diff --git a/.github/workflows/binary.yml b/.github/workflows/binary.yml
index 2f64664..c6f3ece 100644
--- a/.github/workflows/binary.yml
+++ b/.github/workflows/binary.yml
@@ -20,10 +20,10 @@ jobs:
- name: "Build binary"
run: |
sudo apt-get update
- sudo apt-get install -y build-essential libvirt-dev make libguestfs-dev
+ sudo apt-get install -y build-essential libvirt-dev make genisoimage libguestfs-dev libcephfs-dev librbd-dev librados-dev
make
- uses: actions/upload-artifact@v3
with:
name: yavirt-ubuntu
- path: bin
\ No newline at end of file
+ path: bin
diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml
index 4a93af3..a1f2622 100644
--- a/.github/workflows/golangci-lint.yml
+++ b/.github/workflows/golangci-lint.yml
@@ -10,14 +10,27 @@ on:
jobs:
lint:
runs-on: ubuntu-latest
- container: projecteru2/footstone:yavirt-prebuild
steps:
- - uses: actions/checkout@v3
+ - name: checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
- - uses: actions/setup-go@v3
+ - name: "Setup go"
+ uses: actions/setup-go@v5
with:
go-version-file: 'go.mod'
+
+ - name: "Install dependencies"
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y build-essential libvirt-dev make genisoimage libguestfs-dev libcephfs-dev librbd-dev librados-dev
+
+ - name: "Install dependencies"
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y build-essential libvirt-dev make genisoimage libguestfs-dev libcephfs-dev librbd-dev librados-dev
- - uses: golangci/golangci-lint-action@v3
+ - uses: golangci/golangci-lint-action@v6
with:
args: --timeout=8m
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index e64159b..3e3b319 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,14 +11,25 @@ on:
jobs:
unittests:
runs-on: ubuntu-latest
- container: projecteru2/footstone:yavirt-prebuild
-
steps:
- - uses: actions/checkout@v3
+ - name: checkout
+ uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
- - uses: actions/setup-go@v3
+ - name: "Setup go"
+ uses: actions/setup-go@v4
with:
go-version-file: 'go.mod'
+
+ - name: "Install dependencies"
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y build-essential libvirt-dev make genisoimage libguestfs-dev libcephfs-dev librbd-dev librados-dev
+ - name: "Install dependencies"
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y build-essential libvirt-dev make genisoimage libguestfs-dev libcephfs-dev librbd-dev librados-dev
- name: unit tests
run: make test
diff --git a/.gitignore b/.gitignore
index 02e03c6..44d7609 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,5 +3,6 @@ cscope.*
vendor/
dist/
yavirt
-
-.vscode
\ No newline at end of file
+.idea/
+.vscode
+/tmp
diff --git a/.golangci.yml b/.golangci.yml
index d4c89f4..f46b35f 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -1,12 +1,17 @@
run:
timeout: 5m
tests: false
- skip-dirs:
+ modules-download-mode: readonly
+
+issues:
+ exclude-dirs:
- vendor
- tools
- 3rdmocks
- modules-download-mode: readonly
-
+ - thirdpart
+ - tmp
+ - mocks
+
linters-settings:
nakedret:
max-func-lines: 59
@@ -27,7 +32,6 @@ linters-settings:
for-loops: true
errcheck:
check-type-assertions: true
- check-blank: true
gocritic:
disabled-checks:
- captLocal
diff --git a/Dockerfile b/Dockerfile
index a166787..709de07 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,17 +1,30 @@
-FROM projecteru2/footstone:yavirt-prebuild-go1.20 AS BUILD
+FROM ubuntu:jammy AS BUILD
# make binary
# RUN git clone https://github.com/projecteru2/yavirt.git /go/src/github.com/projecteru2/yavirt
COPY . /go/src/github.com/projecteru2/yavirt
WORKDIR /go/src/github.com/projecteru2/yavirt
ARG KEEP_SYMBOL
-RUN make deps && make && ./bin/yavirtd --version
+RUN sed -i 's@//.*archive.ubuntu.com@//mirrors.ustc.edu.cn@g' /etc/apt/sources.list
+RUN apt update
+RUN apt install -y golang-1.20 build-essential libvirt-dev make genisoimage libguestfs-dev libcephfs-dev librbd-dev librados-dev
+RUN apt install -y git
+# RUN snap install go --classic
+ENV PATH="$PATH:/usr/lib/go-1.20/bin/"
-FROM alpine:latest
+RUN go version
+RUN make deps CN=1
+RUN make && ./bin/yavirtd --version
+
+FROM ubuntu:jammy
+
+RUN mkdir /etc/yavirt/ && \
+ sed -i 's@//.*archive.ubuntu.com@//mirrors.ustc.edu.cn@g' /etc/apt/sources.list && \
+ apt update && \
+ apt install -y libvirt-dev libguestfs-dev genisoimage libcephfs-dev librbd-dev librados-dev
-RUN mkdir /etc/yavirt/
LABEL ERU=1
COPY --from=BUILD /go/src/github.com/projecteru2/yavirt/bin/yavirtd /usr/bin/yavirtd
COPY --from=BUILD /go/src/github.com/projecteru2/yavirt/bin/yavirtctl /usr/bin/yavirtctl
-COPY --from=BUILD /go/src/github.com/projecteru2/yavirt/internal/virt/template/disk.xml /etc/yavirt/disk.xml
-COPY --from=BUILD /go/src/github.com/projecteru2/yavirt/internal/virt/template/guest.xml /etc/yavirt/guest.xml
+COPY --from=BUILD /go/src/github.com/projecteru2/yavirt/internal/virt/domain/templates/disk.xml /etc/yavirt/disk.xml
+COPY --from=BUILD /go/src/github.com/projecteru2/yavirt/internal/virt/domain/templates/guest.xml /etc/yavirt/guest.xml
diff --git a/Makefile b/Makefile
index b3aa8b5..b47891c 100644
--- a/Makefile
+++ b/Makefile
@@ -1,12 +1,20 @@
+ifeq ($(CN), 1)
+ENV := GOPROXY=https://goproxy.cn,direct
+endif
+
NS := github.com/projecteru2/yavirt
BUILD := go build -race
-TEST := go test -count=1 -race -cover
+TEST := go test -count=1 -race -cover -gcflags=all=-l
-LDFLAGS += -X "$(NS)/internal/ver.Git=$(shell git rev-parse HEAD)"
-LDFLAGS += -X "$(NS)/internal/ver.Compile=$(shell go version)"
-LDFLAGS += -X "$(NS)/internal/ver.Date=$(shell date +'%F %T %z')"
+REVISION := $(shell git rev-parse HEAD || unknown)
+BUILTAT := $(shell date +%Y-%m-%dT%H:%M:%S)
+VERSION := $(shell git describe --tags $(shell git rev-list --tags --max-count=1))
-PKGS := $$(go list ./... | grep -v -P '$(NS)/third_party|vendor/')
+LDFLAGS += -X "$(NS)/internal/ver.REVISION=$(REVISION)"
+LDFLAGS += -X "$(NS)/internal/ver.BUILTAT=$(BUILTAT)"
+LDFLAGS += -X "$(NS)/internal/ver.VERSION=$(VERSION)"
+
+PKGS := $$(go list ./... | grep -v -P '$(NS)/third_party|vendor/|mocks|ovn')
.PHONY: all test build setup
@@ -20,12 +28,15 @@ build-srv:
build-ctl:
$(BUILD) -ldflags '$(LDFLAGS)' -o bin/yavirtctl cmd/cmd.go
-setup:
- go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
- go install github.com/vektra/mockery/v2@latest
+setup: setup-lint
+ $(ENV) go install github.com/vektra/mockery/v2@latest
+
+setup-lint:
+ $(ENV) go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.59.1
lint: format
- golangci-lint run --skip-dirs-use-default --skip-dirs=thirdparty
+ golangci-lint --version
+ golangci-lint run
format: vet
gofmt -s -w $$(find . -iname '*.go' | grep -v -P '\./third_party|\./vendor/')
@@ -34,7 +45,8 @@ vet:
go vet $(PKGS)
deps:
- go mod tidy
+ $(ENV) go mod tidy
+ $(ENV) go mod vendor
mock: deps
mockery --dir pkg/libvirt --output pkg/libvirt/mocks --all
@@ -43,10 +55,12 @@ mock: deps
mockery --dir pkg/utils --output pkg/utils/mocks --name Locker
mockery --dir internal/virt/agent --output internal/virt/agent/mocks --all
mockery --dir internal/virt/domain --output internal/virt/domain/mocks --name Domain
- mockery --dir internal/virt/guest/manager --output internal/virt/guest/manager/mocks --name Manageable
mockery --dir internal/virt/guest --output internal/virt/guest/mocks --name Bot
mockery --dir internal/virt/guestfs --output internal/virt/guestfs/mocks --name Guestfs
- mockery --dir internal/virt/volume --output internal/virt/volume/mocks --name Bot
+ mockery --dir internal/volume --output internal/volume/mocks --name Volume
+ mockery --dir internal/volume/base --output internal/volume/base/mocks --name SnapshotAPI
+ mockery --dir internal/eru/store --output internal/eru/store/mocks --name Store
+ mockery --dir internal/service --output internal/service/mocks --name Service
clean:
rm -fr bin/*
diff --git a/cmd/cmd.go b/cmd/cmd.go
index 545effd..e3185cb 100644
--- a/cmd/cmd.go
+++ b/cmd/cmd.go
@@ -1,21 +1,24 @@
package main
import (
+ "encoding/json"
"fmt"
"os"
"github.com/urfave/cli/v2"
+ "github.com/cockroachdb/errors"
"github.com/projecteru2/yavirt/cmd/guest"
"github.com/projecteru2/yavirt/cmd/image"
- "github.com/projecteru2/yavirt/cmd/maint"
"github.com/projecteru2/yavirt/cmd/network"
+ "github.com/projecteru2/yavirt/cmd/run"
+ "github.com/projecteru2/yavirt/configs"
+ "github.com/projecteru2/yavirt/internal/service/boar"
"github.com/projecteru2/yavirt/internal/ver"
- "github.com/projecteru2/yavirt/pkg/errors"
)
func main() {
- cli.VersionPrinter = func(c *cli.Context) {
+ cli.VersionPrinter = func(_ *cli.Context) {
fmt.Println(ver.Version())
}
@@ -29,7 +32,7 @@ func main() {
},
&cli.StringFlag{
Name: "log-level",
- Value: "INFO",
+ Value: "",
Usage: "set log level",
EnvVars: []string{"ERU_YAVIRT_LOG_LEVEL"},
},
@@ -57,22 +60,62 @@ func main() {
Usage: "change hostname",
EnvVars: []string{"ERU_HOSTNAME", "HOSTNAME"},
},
- &cli.BoolFlag{
- Name: "skip-setup-host",
- Value: false,
+ &cli.IntFlag{
+ Name: "timeout",
+ Value: 300,
+ Usage: "command timeout",
+ EnvVars: []string{"ERU_YAVIRT_CMD_TIMEOUT"},
},
},
Commands: []*cli.Command{
+ {
+ Name: "info",
+ Action: run.Run(info),
+ },
guest.Command(),
image.Command(),
network.Command(),
- maint.Command(),
},
Version: "v",
}
if err := app.Run(os.Args); err != nil {
- fmt.Println(errors.Stack(err))
+ fmt.Println(errors.GetReportableStackTrace(err))
+ }
+}
+
+func info(c *cli.Context, _ run.Runtime) (err error) {
+ cfg := &configs.Conf
+
+ if err := cfg.Load(c.String("config")); err != nil {
+ return errors.Wrap(err, "")
+ }
+ if err := cfg.Prepare(c); err != nil {
+ return err
+ }
+ // disable eru-related features
+ cfg.Eru.Enable = false
+
+ svc, err := boar.New(c.Context, cfg, nil)
+ if err != nil {
+ return err
+ }
+ info, err := svc.Info()
+ if err != nil {
+ return err
+ }
+ ans := map[string]string{
+ "addr": cfg.Host.Addr,
+ "hostname": cfg.Host.Name,
+ }
+ for name, res := range info.Resources {
+ ans[name] = string(res)
+ }
+ b, err := json.MarshalIndent(ans, "", "\t")
+ if err != nil {
+ return err
}
+ fmt.Printf("%s\n", string(b))
+ return nil
}
diff --git a/cmd/guest/attach.go b/cmd/guest/attach.go
new file mode 100644
index 0000000..659aa5e
--- /dev/null
+++ b/cmd/guest/attach.go
@@ -0,0 +1,157 @@
+package guest
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "io"
+ "os"
+ "sync"
+ "time"
+
+ "github.com/projecteru2/core/log"
+ "github.com/projecteru2/yavirt/cmd/run"
+ intertypes "github.com/projecteru2/yavirt/internal/types"
+ "github.com/projecteru2/yavirt/pkg/utils"
+ "github.com/urfave/cli/v2"
+ "golang.org/x/term"
+)
+
+type buffer struct {
+ sync.Mutex
+ fromQ *utils.BytesQueue
+
+ to chan []byte
+ quit chan struct{}
+}
+
+func (b *buffer) Close() error {
+ close(b.to)
+ close(b.quit)
+ return nil
+}
+
+func (b *buffer) Read(p []byte) (int, error) {
+ return b.fromQ.Read(p)
+}
+
+func (b *buffer) Write(p []byte) (int, error) {
+ b.to <- bytes.Clone(p)
+ return len(p), nil
+}
+
+func (b *buffer) UserRead() ([]byte, error) {
+ bs, ok := <-b.to
+ if !ok {
+ return nil, io.EOF
+ }
+ return bs, nil
+}
+
+func (b *buffer) UserWrite(bs []byte) error {
+ _, err := b.fromQ.Write(bs)
+ return err
+}
+
+func attachGuest(c *cli.Context, runtime run.Runtime) error { //nolint
+ id := c.Args().First()
+ cmds := c.Args().Tail()
+ timeout := c.Int("timeout")
+ force := c.Bool("force")
+ safe := c.Bool("safe")
+ devname := c.String("devname")
+
+ log.Debugf(c.Context, "attaching guest %s timeout %d", id, timeout)
+
+ flags := intertypes.NewOpenConsoleFlags(force, safe, cmds)
+ flags.Devname = devname
+ stream := &buffer{
+ fromQ: utils.NewBytesQueue(),
+ to: make(chan []byte, 10),
+ }
+
+ ctx, cancel := context.WithCancel(context.TODO())
+ var lck sync.Mutex
+ lastActive := time.Now()
+ needExit := func() bool {
+ lck.Lock()
+ defer lck.Unlock()
+
+ now := time.Now()
+ elapse := now.Sub(lastActive)
+ if elapse.Seconds() > float64(timeout) {
+ cancel()
+ return true
+ }
+ lastActive = now
+ return false
+ }
+ go func() {
+ err := runtime.Svc.AttachGuest(ctx, id, stream, flags)
+ if err != nil {
+ log.Errorf(c.Context, err, "attach guest error")
+ }
+ }()
+
+ log.Debugf(c.Context, "start terminal...")
+
+ oldState, err := term.MakeRaw(int(os.Stdin.Fd()))
+ if err != nil {
+ panic(err)
+ }
+ defer term.Restore(int(os.Stdin.Fd()), oldState) //nolint
+
+ done1, done2 := make(chan struct{}), make(chan struct{})
+ go func() {
+ defer close(done1)
+ defer log.Debugf(c.Context, "stdin done\n")
+
+ buf := make([]byte, 100*1024)
+ for {
+ if needExit() {
+ return
+ }
+ n, err := os.Stdin.Read(buf)
+ if err != nil {
+ fmt.Printf("Stdin: %s\n", err)
+ return
+ }
+ bs := bytes.Clone(buf[:n])
+ // find ^]
+ if bytes.Contains(bs, []byte{uint8(29)}) {
+ return
+ }
+ err = stream.UserWrite(bs)
+ if err != nil {
+ fmt.Printf("Stdin(Stream): %s\n", err)
+ return
+ }
+ }
+ }()
+ go func() {
+ defer close(done2)
+ defer fmt.Printf("stdout done\n")
+ for {
+ if needExit() {
+ return
+ }
+ bs, err := stream.UserRead()
+ if err != nil {
+ fmt.Printf("Stdout(Stream): %s\n", err)
+ return
+ }
+ log.Debugf(c.Context, "[Exec:Stdout] got from stream: %v\r\n", bs)
+ _, err = os.Stdout.Write(bs)
+ if err != nil {
+ fmt.Printf("Stdout: %s\n", err)
+ return
+ }
+ }
+ }()
+
+ select {
+ case <-done1:
+ case <-done2:
+ }
+ return nil
+}
diff --git a/cmd/guest/capture.go b/cmd/guest/capture.go
index 0821ff1..d040aba 100644
--- a/cmd/guest/capture.go
+++ b/cmd/guest/capture.go
@@ -5,16 +5,12 @@ import (
"github.com/urfave/cli/v2"
+ "github.com/cockroachdb/errors"
"github.com/projecteru2/yavirt/cmd/run"
- "github.com/projecteru2/yavirt/pkg/errors"
)
func captureFlags() []cli.Flag {
return []cli.Flag{
- &cli.StringFlag{
- Name: "user",
- Required: true,
- },
&cli.StringFlag{
Name: "name",
Required: true,
@@ -31,12 +27,11 @@ func capture(c *cli.Context, runtime run.Runtime) error {
return errors.New("Guest ID is required")
}
- user := c.String("user")
name := c.String("name")
overridden := c.Bool("overridden")
- _, err := runtime.Guest.Capture(runtime.VirtContext(), id, user, name, overridden)
+ _, err := runtime.Svc.CaptureGuest(runtime.Ctx, id, name, overridden)
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
fmt.Printf("%s captured\n", name)
diff --git a/cmd/guest/create.go b/cmd/guest/create.go
index 1c1d6a2..6483845 100644
--- a/cmd/guest/create.go
+++ b/cmd/guest/create.go
@@ -1,17 +1,20 @@
package guest
import (
+ "encoding/json"
"fmt"
"strings"
"github.com/urfave/cli/v2"
+ "github.com/cockroachdb/errors"
"github.com/projecteru2/yavirt/cmd/run"
- "github.com/projecteru2/yavirt/internal/models"
- "github.com/projecteru2/yavirt/internal/virt/types"
- "github.com/projecteru2/yavirt/internal/vnet"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/projecteru2/yavirt/internal/network"
+ "github.com/projecteru2/yavirt/internal/types"
"github.com/projecteru2/yavirt/pkg/utils"
+
+ stotypes "github.com/projecteru2/resource-storage/storage/types"
+ rbdtypes "github.com/yuyang0/resource-rbd/rbd/types"
)
func createFlags() []cli.Flag {
@@ -45,24 +48,27 @@ func createFlags() []cli.Flag {
}
func create(c *cli.Context, runtime run.Runtime) error {
- vols, err := getVols(c.String("storage"))
+ res, err := generateResources(c)
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
+ cnt := c.Int("count")
+ networkMode := c.String("network")
+
+ if networkMode == "" {
+ return errors.New("network can't be empty")
+ }
opts := types.GuestCreateOption{
CPU: c.Int("cpu"),
Mem: c.Int64("memory"),
ImageName: c.Args().First(),
ImageUser: c.String("image-user"),
DmiUUID: c.String("dmi"),
- }
-
- cnt := c.Int("count")
- network := c.String("network")
-
- if len(network) < 1 {
- network = runtime.Host.NetworkMode
+ Labels: map[string]string{
+ network.ModeLabelKey: networkMode,
+ },
+ Resources: res,
}
switch {
@@ -74,14 +80,12 @@ func create(c *cli.Context, runtime run.Runtime) error {
return fmt.Errorf("--memory is required")
case cnt < 1:
return fmt.Errorf("--count must be greater than 0")
- case network != vnet.NetworkCalico && network != vnet.NetworkVlan:
- return fmt.Errorf("--network is invalid: %s", network)
+ case networkMode != network.CalicoMode && networkMode != network.VlanMode:
+ return fmt.Errorf("--network is invalid: %s", networkMode)
}
- runtime.Host.NetworkMode = network
-
for i := 0; i < cnt; i++ {
- g, err := runtime.Guest.Create(runtime.VirtContext(), opts, runtime.Host, vols)
+ g, err := runtime.Svc.CreateGuest(runtime.Ctx, opts)
if err != nil {
return err
}
@@ -92,28 +96,38 @@ func create(c *cli.Context, runtime run.Runtime) error {
return nil
}
-func getVols(mounts string) ([]*models.Volume, error) {
- if len(mounts) < 1 {
- return nil, nil
- }
-
- var vols = []*models.Volume{}
-
- for _, raw := range strings.Split(mounts, ",") {
- mnt, rawCap := utils.PartRight(raw, ":")
-
- volCap, err := utils.Atoi64(rawCap)
+func generateResources(c *cli.Context) (ans map[string][]byte, err error) {
+ ans = map[string][]byte{}
+ // for storage resources
+ {
+ mounts := c.String("storage")
+ if len(mounts) < 1 {
+ return
+ }
+ eParmas := stotypes.EngineParams{
+ Volumes: strings.Split(mounts, ","),
+ }
+ bs, err := json.Marshal(eParmas)
if err != nil {
- return nil, errors.Trace(err)
+ return nil, err
}
+ ans["storage"] = bs
+ }
- vol, err := models.NewDataVolume(mnt, volCap)
+ // for rbd resources
+ {
+ mounts := c.String("rbd")
+ if len(mounts) < 1 {
+ return
+ }
+ eParmas := rbdtypes.EngineParams{
+ Volumes: strings.Split(mounts, ","),
+ }
+ bs, err := json.Marshal(eParmas)
if err != nil {
- return nil, errors.Trace(err)
+ return nil, err
}
-
- vols = append(vols, vol)
+ ans["rbd"] = bs
}
-
- return vols, nil
+ return
}
diff --git a/cmd/guest/exec.go b/cmd/guest/exec.go
new file mode 100644
index 0000000..8b0c15e
--- /dev/null
+++ b/cmd/guest/exec.go
@@ -0,0 +1,59 @@
+package guest
+
+import (
+ "os"
+
+ "github.com/projecteru2/core/log"
+ "github.com/projecteru2/yavirt/cmd/run"
+ "github.com/urfave/cli/v2"
+)
+
+func execFlags() []cli.Flag {
+ return []cli.Flag{
+ &cli.BoolFlag{
+ Name: "i",
+ Value: false,
+ },
+ &cli.StringFlag{
+ Name: "devname",
+ Value: "",
+ },
+ &cli.BoolFlag{
+ Name: "force",
+ Value: false,
+ },
+ &cli.BoolFlag{
+ Name: "safe",
+ Value: false,
+ },
+ }
+}
+
+func exec(c *cli.Context, runtime run.Runtime) (err error) {
+ // defer runtime.CancelFn()
+
+ if c.Bool("i") {
+ return attachGuest(c, runtime)
+ } else { //nolint
+ return execGuest(c, runtime)
+ }
+}
+
+func execGuest(c *cli.Context, runtime run.Runtime) error {
+ id := c.Args().First()
+ cmds := c.Args().Tail()
+
+ log.Debugf(c.Context, "exec guest %s, cmd: %v", id, cmds)
+ msg, err := runtime.Svc.ExecuteGuest(runtime.Ctx, id, cmds)
+ if err != nil {
+ log.Errorf(c.Context, err, "exec guest error")
+ return err
+ }
+ if msg.ExitCode == 0 {
+ os.Stdout.Write(msg.Data)
+ } else {
+ os.Stderr.Write(msg.Data)
+ }
+ log.Debugf(c.Context, "+_+_+_ %s", string(msg.Data))
+ return err
+}
diff --git a/cmd/guest/forward.go b/cmd/guest/forward.go
deleted file mode 100644
index 9a0ac30..0000000
--- a/cmd/guest/forward.go
+++ /dev/null
@@ -1,54 +0,0 @@
-package guest
-
-import (
- "fmt"
-
- "github.com/urfave/cli/v2"
-
- "github.com/projecteru2/yavirt/cmd/run"
- "github.com/projecteru2/yavirt/internal/models"
- "github.com/projecteru2/yavirt/pkg/errors"
-)
-
-func forwardFlags() []cli.Flag {
- return []cli.Flag{
- &cli.StringFlag{
- Name: "status",
- Required: true,
- },
- }
-}
-
-func forward(c *cli.Context, runtime run.Runtime) error {
- validStatus := func(st string) error {
- for _, status := range models.AllStatuses {
- if st == status {
- return nil
- }
- }
- return errors.Errorf("invalid dest. status: %s", st)
- }
-
- st := c.String("status")
- if err := validStatus(st); err != nil {
- return err
- }
-
- id := c.Args().First()
- if len(id) < 1 {
- return errors.New("Guest ID is required")
- }
-
- g, err := runtime.Guest.Load(runtime.VirtContext(), id)
- if err != nil {
- return err
- }
-
- if err := g.ForwardStatus(st, false); err != nil {
- return errors.Trace(err)
- }
-
- fmt.Printf("%s forward to %s\n", id, st)
-
- return nil
-}
diff --git a/cmd/guest/get.go b/cmd/guest/get.go
index aa9d61b..82009d9 100644
--- a/cmd/guest/get.go
+++ b/cmd/guest/get.go
@@ -5,8 +5,8 @@ import (
"github.com/urfave/cli/v2"
+ "github.com/cockroachdb/errors"
"github.com/projecteru2/yavirt/cmd/run"
- "github.com/projecteru2/yavirt/pkg/errors"
)
func get(c *cli.Context, runtime run.Runtime) error {
@@ -15,34 +15,36 @@ func get(c *cli.Context, runtime run.Runtime) error {
return errors.New("Guest ID is required")
}
- g, err := runtime.Guest.Load(runtime.VirtContext(), id)
+ g, err := runtime.Svc.GetGuest(runtime.Ctx, id)
if err != nil {
return err
}
fmt.Printf("guest: %s\n", g.ID)
+ fmt.Printf("Status: %s\n", g.Status)
fmt.Printf("CPU: %d\n", g.CPU)
- fmt.Printf("Memory: %d\n", g.Memory)
+ fmt.Printf("Memory: %d\n", g.Mem)
- fmt.Println("volume:")
- for _, vol := range g.Vols {
- fmt.Printf(" %s\n", vol)
- }
+ // TODO: add more information to guest
+ // fmt.Println("volume:")
+ // for _, vol := range g.Vols {
+ // fmt.Printf(" %s\n", vol)
+ // }
fmt.Println("IP:")
for _, ip := range g.IPs {
- fmt.Printf(" %s, gw: %s\n", ip, ip.GatewayAddr())
+ fmt.Printf(" %s\n", ip)
}
- hc, err := g.HealthCheck()
- if err != nil {
- if errors.Contain(err, errors.ErrKeyNotExists) {
- return nil
- }
- return err
- }
- fmt.Println("HealthCheck:")
- fmt.Printf(" %v\n", hc.TCPEndpoints())
- fmt.Printf(" %v\n", hc.HTTPEndpoints())
+ // hc, err := g.HealthCheck()
+ // if err != nil {
+ // if errors.Contain(err, errors.ErrKeyNotExists) {
+ // return nil
+ // }
+ // return err
+ // }
+ // fmt.Println("HealthCheck:")
+ // fmt.Printf(" %v\n", hc.TCPEndpoints())
+ // fmt.Printf(" %v\n", hc.HTTPEndpoints())
return nil
}
diff --git a/cmd/guest/guest.go b/cmd/guest/guest.go
index 313ff9f..0ca8adb 100644
--- a/cmd/guest/guest.go
+++ b/cmd/guest/guest.go
@@ -4,13 +4,10 @@ import (
"github.com/urfave/cli/v2"
"github.com/projecteru2/yavirt/cmd/run"
- "github.com/projecteru2/yavirt/internal/models"
)
// Command .
func Command() *cli.Command {
- models.Setup()
-
return &cli.Command{
Name: "guest",
Subcommands: []*cli.Command{
@@ -21,7 +18,7 @@ func Command() *cli.Command {
{
Name: "list",
Flags: listFlags(),
- Action: run.Run(list),
+ Action: run.Run(listCmd),
},
{
Name: "create",
@@ -30,6 +27,7 @@ func Command() *cli.Command {
},
{
Name: "start",
+ Flags: controlFlags(),
Action: run.Run(start),
},
{
@@ -42,18 +40,18 @@ func Command() *cli.Command {
},
{
Name: "stop",
- Flags: stopFlags(),
+ Flags: controlFlags(),
Action: run.Run(stop),
},
{
Name: "destroy",
- Flags: destroyFlags(),
+ Flags: controlFlags(),
Action: run.Run(destroy),
},
{
- Name: "forward",
- Flags: forwardFlags(),
- Action: run.Run(forward),
+ Name: "exec",
+ Flags: execFlags(),
+ Action: run.Run(exec),
},
{
Name: "resize",
diff --git a/cmd/guest/list.go b/cmd/guest/list.go
index 92cb62e..3195678 100644
--- a/cmd/guest/list.go
+++ b/cmd/guest/list.go
@@ -5,9 +5,11 @@ import (
"github.com/urfave/cli/v2"
+ "github.com/cockroachdb/errors"
"github.com/projecteru2/yavirt/cmd/run"
"github.com/projecteru2/yavirt/configs"
"github.com/projecteru2/yavirt/internal/models"
+ "github.com/projecteru2/yavirt/pkg/terrors"
)
func listFlags() []cli.Flag {
@@ -21,7 +23,7 @@ func listFlags() []cli.Flag {
}
}
-func list(c *cli.Context, _ run.Runtime) error {
+func listCmd(c *cli.Context, _ run.Runtime) error {
all := c.Bool("all")
var err error
@@ -35,7 +37,7 @@ func list(c *cli.Context, _ run.Runtime) error {
}
guests, err = models.GetNodeGuests(nodename)
}
- if err != nil {
+ if err != nil && !errors.Is(err, terrors.ErrKeyNotExists) {
return err
}
diff --git a/cmd/guest/network.go b/cmd/guest/network.go
index f8faa84..cb88582 100644
--- a/cmd/guest/network.go
+++ b/cmd/guest/network.go
@@ -5,8 +5,8 @@ import (
"github.com/urfave/cli/v2"
+ "github.com/cockroachdb/errors"
"github.com/projecteru2/yavirt/cmd/run"
- "github.com/projecteru2/yavirt/pkg/errors"
)
func connectExtraNetworkFlags() []cli.Flag {
@@ -38,8 +38,8 @@ func disconnectExtraNetwork(c *cli.Context, runtime run.Runtime) error {
network := c.String("network")
- if err := runtime.Guest.DisconnectExtraNetwork(runtime.VirtContext(), id, network); err != nil {
- return errors.Trace(err)
+ if err := runtime.Svc.DisconnectNetwork(runtime.Ctx, id, network); err != nil {
+ return errors.Wrap(err, "")
}
fmt.Printf("guest %s had been disconnected from network %s\n", id, network)
@@ -56,9 +56,9 @@ func connectExtraNetwork(c *cli.Context, runtime run.Runtime) error {
network := c.String("network")
ipv4 := c.String("ipv4")
- dest, err := runtime.Guest.ConnectExtraNetwork(runtime.VirtContext(), id, network, ipv4)
+ dest, err := runtime.Svc.ConnectNetwork(runtime.Ctx, id, network, ipv4)
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
if len(ipv4) < 1 {
diff --git a/cmd/guest/op.go b/cmd/guest/op.go
index 1f901e7..92ea5cc 100644
--- a/cmd/guest/op.go
+++ b/cmd/guest/op.go
@@ -2,25 +2,16 @@ package guest
import (
"fmt"
- "time"
"github.com/urfave/cli/v2"
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/core/log"
+ "github.com/projecteru2/libyavirt/types"
"github.com/projecteru2/yavirt/cmd/run"
- "github.com/projecteru2/yavirt/internal/virt"
- "github.com/projecteru2/yavirt/pkg/errors"
)
-func destroyFlags() []cli.Flag {
- return []cli.Flag{
- &cli.BoolFlag{
- Name: "force",
- Value: false,
- },
- }
-}
-
-func stopFlags() []cli.Flag {
+func controlFlags() []cli.Flag {
return []cli.Flag{
&cli.BoolFlag{
Name: "force",
@@ -30,9 +21,13 @@ func stopFlags() []cli.Flag {
}
func start(c *cli.Context, runtime run.Runtime) error {
- id, err := op(c, runtime, runtime.Guest.Start)
- if err != nil {
- return errors.Trace(err)
+ defer runtime.CancelFn()
+
+ id := c.Args().First()
+ log.Debugf(c.Context, "Starting guest %s", id)
+
+ if err := runtime.Svc.ControlGuest(runtime.Ctx, id, types.OpStart, c.Bool("force")); err != nil {
+ return errors.Wrap(err, "")
}
fmt.Printf("%s started\n", id)
@@ -41,9 +36,12 @@ func start(c *cli.Context, runtime run.Runtime) error {
}
func suspend(c *cli.Context, runtime run.Runtime) error {
- id, err := op(c, runtime, runtime.Guest.Suspend)
- if err != nil {
- return errors.Trace(err)
+ defer runtime.CancelFn()
+
+ id := c.Args().First()
+ log.Debugf(c.Context, "Suspending guest %s", id)
+ if err := runtime.Svc.ControlGuest(runtime.Ctx, id, types.OpSuspend, false); err != nil {
+ return errors.Wrap(err, "")
}
fmt.Printf("%s suspended\n", id)
@@ -52,9 +50,12 @@ func suspend(c *cli.Context, runtime run.Runtime) error {
}
func resume(c *cli.Context, runtime run.Runtime) error {
- id, err := op(c, runtime, runtime.Guest.Resume)
- if err != nil {
- return errors.Trace(err)
+ defer runtime.CancelFn()
+
+ id := c.Args().First()
+ log.Debugf(c.Context, "Resuming guest %s", id)
+ if err := runtime.Svc.ControlGuest(runtime.Ctx, id, types.OpResume, false); err != nil {
+ return errors.Wrap(err, "")
}
fmt.Printf("%s resumed\n", id)
@@ -63,13 +64,12 @@ func resume(c *cli.Context, runtime run.Runtime) error {
}
func stop(c *cli.Context, runtime run.Runtime) error {
- shut := func(ctx virt.Context, id string) error {
- return runtime.Guest.Stop(ctx, id, c.Bool("force"))
- }
+ defer runtime.CancelFn()
- id, err := op(c, runtime, shut)
- if err != nil {
- return errors.Trace(err)
+ id := c.Args().First()
+ log.Debugf(c.Context, "Stopping guest %s", id)
+ if err := runtime.Svc.ControlGuest(runtime.Ctx, id, types.OpStop, c.Bool("force")); err != nil {
+ return errors.Wrap(err, "")
}
fmt.Printf("%s stopped\n", id)
@@ -77,33 +77,18 @@ func stop(c *cli.Context, runtime run.Runtime) error {
return nil
}
-func destroy(c *cli.Context, runtime run.Runtime) error {
- destroy := func(ctx virt.Context, id string) error {
- done, err := runtime.Guest.Destroy(ctx, id, c.Bool("force"))
- if err != nil {
- return errors.Trace(err)
- }
-
- select {
- case err := <-done:
- return err
- case <-time.After(time.Minute):
- return errors.ErrTimeout
- }
- }
+func destroy(c *cli.Context, runtime run.Runtime) (err error) {
+ defer runtime.CancelFn()
+
+ id := c.Args().First()
+ log.Debugf(c.Context, "Destroying guest %s", id)
- id, err := op(c, runtime, destroy)
+ err = runtime.Svc.ControlGuest(runtime.Ctx, id, types.OpDestroy, c.Bool("force"))
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
fmt.Printf("%s destroyed\n", id)
return nil
}
-
-func op(c *cli.Context, runtime run.Runtime, fn func(virt.Context, string) error) (id string, err error) {
- id = c.Args().First()
- err = fn(runtime.VirtContext(), id)
- return
-}
diff --git a/cmd/guest/resize.go b/cmd/guest/resize.go
index 4d6615d..3a04879 100644
--- a/cmd/guest/resize.go
+++ b/cmd/guest/resize.go
@@ -5,9 +5,11 @@ import (
"github.com/urfave/cli/v2"
+ "github.com/cockroachdb/errors"
"github.com/projecteru2/yavirt/cmd/run"
- "github.com/projecteru2/yavirt/pkg/errors"
- "github.com/projecteru2/yavirt/pkg/utils"
+ "github.com/projecteru2/yavirt/internal/types"
+ "github.com/projecteru2/yavirt/internal/volume"
+ "github.com/projecteru2/yavirt/internal/volume/local"
)
func resizeFlags() []cli.Flag {
@@ -25,12 +27,13 @@ func resizeFlags() []cli.Flag {
}
func resize(c *cli.Context, runtime run.Runtime) (err error) {
- vs := map[string]int64{}
+ vs := map[string]volume.Volume{}
for _, raw := range c.StringSlice("volumes") {
- mnt, cap := utils.PartRight(raw, ":") //nolint
- if vs[mnt], err = utils.Atoi64(cap); err != nil {
- return errors.Trace(err)
+ vol, err := local.NewVolumeFromStr(raw)
+ if err != nil {
+ return errors.Wrap(err, "")
}
+ vs[vol.GetMountDir()] = vol
}
id := c.Args().First()
@@ -40,8 +43,14 @@ func resize(c *cli.Context, runtime run.Runtime) (err error) {
cpu := c.Int("cpu")
mem := c.Int64("memory")
- if err = runtime.Guest.Resize(runtime.VirtContext(), id, cpu, mem, vs); err != nil {
- return errors.Trace(err)
+ req := &types.GuestResizeOption{
+ ID: id,
+ CPU: cpu,
+ Mem: mem,
+ //TODO: add resources
+ }
+ if err = runtime.Svc.ResizeGuest(runtime.Ctx, id, req); err != nil {
+ return errors.Wrap(err, "")
}
fmt.Printf("%s resized\n", id)
diff --git a/cmd/guest/snapshot.go b/cmd/guest/snapshot.go
index 1285a31..f878441 100644
--- a/cmd/guest/snapshot.go
+++ b/cmd/guest/snapshot.go
@@ -5,8 +5,9 @@ import (
"github.com/urfave/cli/v2"
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/libyavirt/types"
"github.com/projecteru2/yavirt/cmd/run"
- "github.com/projecteru2/yavirt/pkg/errors"
)
func listSnapshotFlags() []cli.Flag {
@@ -68,18 +69,18 @@ func listSnapshot(c *cli.Context, runtime run.Runtime) error {
}
}
- volSnap, err := runtime.Guest.ListSnapshot(runtime.VirtContext(), id, volID)
+ req := types.ListSnapshotReq{
+ ID: id,
+ VolID: volID,
+ }
+ volSnap, err := runtime.Svc.ListSnapshot(runtime.Ctx, req)
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
- for vol, snaps := range volSnap {
- fmt.Printf("Vol: %s\n", vol)
- fmt.Printf("Total: %d snapshot(s)\n", len(snaps))
- for _, s := range snaps {
- fmt.Printf("%s\n", s)
- }
- fmt.Println()
+ fmt.Printf("Total: %d snapshot(s)\n", len(volSnap))
+ for _, snap := range volSnap {
+ fmt.Printf("%v\n", snap)
}
return nil
@@ -97,7 +98,11 @@ func createSnapshot(c *cli.Context, runtime run.Runtime) error {
return errors.New("Volume ID is required")
}
- return runtime.Guest.CreateSnapshot(runtime.VirtContext(), id, volID)
+ req := types.CreateSnapshotReq{
+ ID: id,
+ VolID: volID,
+ }
+ return runtime.Svc.CreateSnapshot(runtime.Ctx, req)
}
func commitSnapshot(c *cli.Context, runtime run.Runtime) error {
@@ -121,9 +126,14 @@ func commitSnapshot(c *cli.Context, runtime run.Runtime) error {
}
if len(snapID) > 0 {
- return runtime.Guest.CommitSnapshot(runtime.VirtContext(), id, volID, snapID)
+ req := types.CommitSnapshotReq{
+ ID: id,
+ VolID: volID,
+ SnapID: snapID,
+ }
+ return runtime.Svc.CommitSnapshot(runtime.Ctx, req)
}
- return runtime.Guest.CommitSnapshotByDay(runtime.VirtContext(), id, volID, day)
+ return runtime.Svc.CommitSnapshotByDay(runtime.Ctx, id, volID, day)
}
@@ -144,5 +154,10 @@ func restoreSnapshot(c *cli.Context, runtime run.Runtime) error {
return errors.New("Snapshot ID is required")
}
- return runtime.Guest.RestoreSnapshot(runtime.VirtContext(), id, volID, snapID)
+ req := types.RestoreSnapshotReq{
+ ID: id,
+ VolID: volID,
+ SnapID: snapID,
+ }
+ return runtime.Svc.RestoreSnapshot(runtime.Ctx, req)
}
diff --git a/cmd/image/image.go b/cmd/image/image.go
index a042125..cd211a7 100644
--- a/cmd/image/image.go
+++ b/cmd/image/image.go
@@ -1,13 +1,21 @@
package image
import (
+ "context"
"fmt"
+ "io"
+ "os"
+ "time"
+ "github.com/ceph/go-ceph/rados"
+ "github.com/ceph/go-ceph/rbd"
"github.com/urfave/cli/v2"
+ "github.com/cockroachdb/errors"
"github.com/projecteru2/yavirt/cmd/run"
- "github.com/projecteru2/yavirt/internal/models"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/projecteru2/yavirt/configs"
+ "github.com/projecteru2/yavirt/internal/utils"
+ vmiFact "github.com/yuyang0/vmimage/factory"
)
// Command .
@@ -22,12 +30,10 @@ func Command() *cli.Command {
},
{
Name: "get",
- Flags: getFlags(),
Action: run.Run(get),
},
{
Name: "rm",
- Flags: rmFlags(),
Action: run.Run(rm),
},
{
@@ -41,6 +47,12 @@ func Command() *cli.Command {
Flags: digestFlags(),
Action: run.Run(digest),
},
+ {
+ Name: "rbd",
+ Usage: "",
+ Flags: rbdFlags(),
+ Action: run.Run(rbdAction),
+ },
},
}
}
@@ -54,23 +66,6 @@ func listFlags() []cli.Flag {
}
}
-func rmFlags() []cli.Flag {
- return []cli.Flag{
- &cli.StringFlag{
- Name: "user",
- Usage: "the owner of an image",
- },
- }
-}
-
-func getFlags() []cli.Flag {
- return []cli.Flag{
- &cli.StringFlag{
- Name: "user",
- },
- }
-}
-
func addFlags() []cli.Flag {
return []cli.Flag{
&cli.Int64Flag{
@@ -95,14 +90,24 @@ func digestFlags() []cli.Flag {
}
}
+func rbdFlags() []cli.Flag {
+ return []cli.Flag{
+ &cli.BoolFlag{
+ Name: "update",
+ Usage: "update rbd for image",
+ Value: false,
+ },
+ }
+}
+
func list(c *cli.Context, _ run.Runtime) error {
- imgs, err := models.ListImages(c.String("user"))
+ imgs, err := vmiFact.ListLocalImages(c.Context, c.String("user"))
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
for _, img := range imgs {
- fmt.Printf("%s\n", img)
+ fmt.Printf("%s\n", img.Fullname())
}
return nil
@@ -113,13 +118,12 @@ func get(c *cli.Context, _ run.Runtime) error {
if len(name) < 1 {
return errors.New("image name is required")
}
-
- img, err := models.LoadImage(name, c.String("user"))
+ img, err := vmiFact.LoadImage(c.Context, name)
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
- fmt.Printf("image: %s, user: %s, filepath: %s\n", img.GetName(), img.GetUser(), img.Filepath())
+ fmt.Printf("image: %s, filepath: %s\n", img.Fullname(), img.Filepath())
return nil
}
@@ -135,24 +139,31 @@ func add(c *cli.Context, _ run.Runtime) error {
case size < 1:
return errors.New("--size is required")
}
-
- img := models.NewSysImage()
- img.Name = name
- img.Size = size
-
- if err := img.Create(); err != nil {
- return errors.Trace(err)
-
+ img, err := vmiFact.NewImage(name)
+ if err != nil {
+ return err
+ }
+ fmt.Printf("*** Prepare image\n")
+ if rc, err := vmiFact.Prepare(filePath, img); err != nil {
+ return errors.Wrap(err, "")
+ } else { //nolint
+ defer rc.Close()
+ if _, err := io.Copy(os.Stdout, rc); err != nil {
+ return errors.Wrap(err, "")
+ }
}
- fmt.Printf("image %s created\n", img.Name)
-
- if len(filePath) > 0 {
- // TODO: add image with file to check hash
- // TODO: or download hash from image-hub
- return nil
+ fmt.Printf("*** Push image\n")
+ if rc, err := vmiFact.Push(c.Context, img, false); err != nil {
+ return errors.Wrap(err, "")
+ } else { //nolint
+ defer rc.Close()
+ if _, err = io.Copy(os.Stdout, rc); err != nil {
+ return errors.Wrap(err, "")
+ }
}
+ fmt.Printf("image %s created\n", img.Fullname())
return nil
}
@@ -162,17 +173,16 @@ func rm(c *cli.Context, _ run.Runtime) error {
return errors.New("image name is required")
}
- user := c.String("user")
- img, err := models.LoadImage(name, user)
+ img, err := vmiFact.LoadImage(c.Context, name)
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
- if err := img.Delete(); err != nil {
- return errors.Trace(err)
+ if err := vmiFact.RemoveLocal(c.Context, img); err != nil {
+ return errors.Wrap(err, "")
}
- fmt.Printf("%s has been deleted\n", img)
+ fmt.Printf("%s has been deleted\n", img.Fullname())
return nil
}
@@ -188,22 +198,78 @@ func digest(c *cli.Context, _ run.Runtime) error {
return nil
}
- img, err := models.LoadSysImage(name)
+ img, err := vmiFact.LoadImage(c.Context, name)
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
- if len(img.Hash) > 0 {
- fmt.Printf("hash of %s: %s\n", img.Name, img.Hash)
- return nil
+ fmt.Printf("hash of %s: %s\n", img.Fullname(), img.GetDigest())
+
+ return nil
+}
+
+func createAndProtectSnapshot(pool, imgName, snapName string, update bool) error {
+ conn, err := rados.NewConnWithUser(configs.Conf.Storage.Ceph.Username)
+ if err != nil {
+ return err
+ }
+ if err := conn.ReadDefaultConfigFile(); err != nil {
+ return err
+ }
+ if err := conn.Connect(); err != nil {
+ return err
+ }
+ defer conn.Shutdown()
+ ctx, err := conn.OpenIOContext(pool)
+ if err != nil {
+ return err
}
+ defer ctx.Destroy()
- hash, err := img.UpdateHash()
+ rbdImage, err := rbd.OpenImage(ctx, imgName, rbd.NoSnapshot)
if err != nil {
- return errors.Trace(err)
+ return err
+ }
+ if update {
+ // rename snapshot
+ oldSnap := rbdImage.GetSnapshot(snapName)
+ oldName := fmt.Sprintf("%s_%d", snapName, time.Now().UnixNano())
+ if err := oldSnap.Rename(oldName); err != nil {
+ return err
+ }
+ }
+ snapshot, err := rbdImage.CreateSnapshot(snapName)
+ if err != nil {
+ return err
+ }
+ return snapshot.Protect()
+}
+
+func rbdAction(c *cli.Context, _ run.Runtime) error {
+ name := c.Args().First()
+ if len(name) < 1 {
+ return errors.New("image name is required")
}
- fmt.Printf("hash of %s: %s\n", img.Name, hash)
+ img, err := vmiFact.LoadImage(c.Context, name)
+ if err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ rbdDisk := fmt.Sprintf("rbd:eru/%s:id=%s", img.RBDName(), configs.Conf.Storage.Ceph.Username)
+ if c.Bool("update") {
+ if err := utils.ForceWriteBLK(context.TODO(), img.Filepath(), rbdDisk); err != nil {
+ return errors.Wrap(err, "")
+ }
+ } else {
+ if err := utils.WriteBLK(context.TODO(), img.Filepath(), rbdDisk, true); err != nil {
+ return errors.Wrap(err, "")
+ }
+ }
+ if err = createAndProtectSnapshot("eru", img.RBDName(), "latest", c.Bool("update")); err != nil {
+ return errors.Wrap(err, "")
+ }
+ fmt.Printf("write %s to %s successfully", name, rbdDisk)
return nil
}
diff --git a/cmd/maint/fasten.go b/cmd/maint/fasten.go
deleted file mode 100644
index 9cae147..0000000
--- a/cmd/maint/fasten.go
+++ /dev/null
@@ -1,250 +0,0 @@
-package maint
-
-import (
- "context"
- "encoding/xml"
- "fmt"
- "path/filepath"
- "strconv"
- "strings"
-
- "github.com/urfave/cli/v2"
-
- "github.com/projecteru2/yavirt/cmd/run"
- "github.com/projecteru2/yavirt/configs"
- "github.com/projecteru2/yavirt/internal/meta"
- "github.com/projecteru2/yavirt/internal/models"
- "github.com/projecteru2/yavirt/pkg/errors"
- "github.com/projecteru2/yavirt/pkg/libvirt"
- "github.com/projecteru2/yavirt/pkg/netx"
- "github.com/projecteru2/yavirt/pkg/store"
-)
-
-var intIPSubnets = map[int64]int64{}
-
-// fasten all local guests that are dangling.
-func fasten(_ *cli.Context, _ run.Runtime) error {
- virt, err := libvirt.Connect("qemu:///system")
- if err != nil {
- return errors.Trace(err)
- }
- defer virt.Close()
-
- ids, err := virt.ListDomainsNames()
- if err != nil {
- return errors.Trace(err)
- }
-
- prefix := filepath.Join(configs.Conf.EtcdPrefix, "ips", "/")
- data, _, err := store.GetPrefix(context.Background(), prefix, (1<<32)-1) //nolint:gomnd // max value of int32
- if err != nil {
- return errors.Trace(err)
- }
- for key := range data {
- if !strings.Contains(key, "occupied") {
- continue
- }
- key = strings.TrimPrefix(key, configs.Conf.EtcdPrefix)
- key = strings.TrimLeft(key, "/")
- parts := strings.Split(key, "/")
- intSubnet, err := strconv.ParseInt(parts[1], 10, 64)
- if err != nil {
- return errors.Annotatef(err, "parse subnet %s failed", parts[1])
- }
- intIP, err := strconv.ParseInt(parts[3], 10, 64)
- if err != nil {
- return errors.Annotatef(err, "parse subnet %d ip %s failed", intSubnet, parts[3])
- }
- intIPSubnets[intIP] = intSubnet
- }
-
- for _, id := range ids {
- switch _, err := models.LoadGuest(id); {
- case err == nil:
- fmt.Printf("valid guest: %s\n", id)
- continue
-
- case errors.IsKeyNotExistsErr(err):
- if err := fastenDangling(id, virt); err != nil {
- return errors.Trace(err)
- }
-
- default:
- return errors.Trace(err)
- }
- }
-
- return nil
-}
-
-var ips = map[string]string{
- "guest-000104": "10.129.144.1",
- "guest-000160": "10.129.144.24",
- "guest-000172": "10.129.144.28",
- "guest-000145": "10.129.144.15",
- "guest-000189": "10.129.144.39",
- "guest-000128": "10.129.144.11",
- "guest-000156": "10.129.144.21",
- "guest-000175": "10.129.144.30",
- "guest-000157": "10.129.144.22",
- "guest-000174": "10.129.144.32",
- "guest-000155": "10.129.144.20",
- "guest-000173": "10.129.144.31",
- "guest-000144": "10.129.144.16",
- "guest-000188": "10.129.144.38",
- "guest-000164": "10.129.144.26",
- "guest-000184": "10.129.144.36",
- "guest-000150": "10.129.144.18",
- "guest-000152": "10.129.144.19",
- "guest-000183": "10.129.144.34",
- "guest-000168": "10.129.144.27",
- "guest-000177": "10.129.144.35",
- "guest-000140": "10.129.144.14",
- "guest-000186": "10.129.144.37",
- "guest-000158": "10.129.144.23",
- "guest-000171": "10.129.144.29",
- "guest-000114": "10.129.144.4",
- "guest-000162": "10.129.144.25",
- "guest-000180": "10.129.144.33",
- "guest-000138": "10.129.140.16",
- "guest-000190": "10.129.140.36",
- "guest-000170": "10.129.140.28",
- "guest-000130": "10.129.140.13",
- "guest-000154": "10.129.140.20",
- "guest-000181": "10.129.140.32",
- "guest-000167": "10.129.140.26",
- "guest-000169": "10.129.140.27",
- "guest-000166": "10.129.140.25",
- "guest-000179": "10.129.140.31",
- "guest-000117": "10.129.140.7",
- "guest-000187": "10.129.140.35",
- "guest-000165": "10.129.140.24",
- "guest-000182": "10.129.140.33",
- "guest-000163": "10.129.140.23",
- "guest-000195": "10.129.140.37",
- "guest-000129": "10.129.140.12",
- "guest-000159": "10.129.140.21",
- "guest-000185": "10.129.140.34",
- "guest-000151": "10.129.140.18",
- "guest-000176": "10.129.140.30",
- "guest-000141": "10.129.140.17",
- "guest-000153": "10.129.140.19",
- "guest-000178": "10.129.140.29",
- "guest-000142": "10.129.152.13",
- "guest-000107": "10.129.152.2",
- "guest-000136": "10.129.152.6",
- "guest-000192": "10.129.152.15",
- "guest-000143": "10.129.132.10",
- "guest-000194": "10.129.132.13",
- "guest-000137": "10.129.132.8",
- "guest-000191": "10.129.132.11",
- "guest-000139": "10.129.132.9",
- "guest-000193": "10.129.132.12",
-}
-
-func fastenDangling(id string, virt *libvirt.Libvirtee) error {
- dom, err := virt.LookupDomain(id)
- if err != nil {
- return errors.Trace(err)
- }
- defer dom.Free()
-
- guest, err := models.NewGuest(nil, nil)
- if err != nil {
- return errors.Trace(err)
- }
- guest.HostName = configs.Hostname()
- guest.ID = id
- guest.ImageName = "ubuntu1604-sto"
-
- state, err := dom.GetState()
- if err != nil {
- return errors.Trace(err)
- }
- switch state {
- case libvirt.DomainRunning:
- guest.Status = models.StatusRunning
- case libvirt.DomainShutoff:
- guest.Status = models.StatusStopped
- default:
- return errors.Errorf("doesn't support %s", state)
- }
-
- info, err := dom.GetInfo()
- if err != nil {
- return errors.Trace(err)
- }
- guest.CPU = int(info.NrVirtCpu)
- guest.Memory = int64(info.MaxMem) * 1024
-
- var flags libvirt.DomainXMLFlags
- txt, err := dom.GetXMLDesc(flags)
- if err != nil {
- return errors.Trace(err)
- }
- dx := domainXML{}
- if err = xml.Unmarshal([]byte(txt), &dx); err != nil {
- return errors.Trace(err)
- }
-
- for _, disk := range dx.Devices.Disks {
- fn := filepath.Base(disk.Source.File)
- if strings.HasPrefix(fn, "sys-") {
- fn = fn[:len(fn)-4] // to remove '.vol' ext.
- id = fn[4:] // to remove 'sys-' prefix.
- if id = strings.TrimLeft(id, "0"); len(id) <= 3 {
- id = fmt.Sprintf("%06s", id)
- } else {
- id = fmt.Sprintf("%32s", id)
- }
- guest.VolIDs = []string{id}
- }
- }
- if len(guest.VolIDs) < 1 {
- return errors.Errorf("guest %s can't find sys volume", guest.ID)
- }
-
- ip := ips[guest.ID]
- if len(ip) < 1 {
- fmt.Printf("guest %s hasn't IP, skip it\n", guest.ID)
- return nil
- }
- intIP, err := netx.IPv4ToInt(ip)
- if err != nil {
- return errors.Errorf("guest %s has invalid IP: %s", guest.ID, ip)
- }
- intSubnet, ok := intIPSubnets[intIP]
- if !ok {
- return errors.Errorf("guest %s IP %s hasn't subnet", guest.ID, ip)
- }
- guest.IPNets = meta.IPNets{
- &meta.IPNet{
- IntIP: intIP,
- IntSubnet: intSubnet,
- },
- }
-
- res := meta.Resources{guest}
- data, err := res.Encode()
- if err != nil {
- return errors.Trace(err)
- }
-
- if err := store.Create(context.Background(), data); err != nil {
- return errors.Annotatef(err, "create %s failed", data)
- }
-
- fmt.Printf("created %s\n", data)
-
- return nil
-}
-
-type domainXML struct {
- Devices struct {
- Disks []struct {
- Source struct {
- File string `xml:"file,attr"`
- } `xml:"source"`
- } `xml:"disk"`
- } `xml:"devices"`
-}
diff --git a/cmd/maint/maint.go b/cmd/maint/maint.go
deleted file mode 100644
index 5cf7862..0000000
--- a/cmd/maint/maint.go
+++ /dev/null
@@ -1,20 +0,0 @@
-package maint
-
-import (
- "github.com/urfave/cli/v2"
-
- "github.com/projecteru2/yavirt/cmd/run"
-)
-
-// Command .
-func Command() *cli.Command {
- return &cli.Command{
- Name: "maint",
- Subcommands: []*cli.Command{
- {
- Name: "fasten",
- Action: run.Run(fasten),
- },
- },
- }
-}
diff --git a/cmd/network/calico/align.go b/cmd/network/calico/align.go
index b8a9fb7..5d9c79e 100644
--- a/cmd/network/calico/align.go
+++ b/cmd/network/calico/align.go
@@ -9,8 +9,11 @@ import (
libcaliopt "github.com/projectcalico/calico/libcalico-go/lib/options"
"github.com/urfave/cli/v2"
+ "github.com/cockroachdb/errors"
"github.com/projecteru2/yavirt/cmd/run"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/projecteru2/yavirt/internal/network"
+ "github.com/projecteru2/yavirt/internal/network/drivers/calico"
+ networkFactory "github.com/projecteru2/yavirt/internal/network/factory"
)
func alignFlags() []cli.Flag {
@@ -22,23 +25,28 @@ func alignFlags() []cli.Flag {
}
}
-func align(c *cli.Context, runtime run.Runtime) error {
- bound, err := getGatewayBoundIPs(runtime)
+func align(c *cli.Context, _ run.Runtime) error {
+ bound, err := getGatewayBoundIPs()
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
- return alignGatewayIPs(runtime, bound, c.Bool("dry-run"))
+ return alignGatewayIPs(bound, c.Bool("dry-run"))
}
-func getGatewayBoundIPs(runtime run.Runtime) ([]net.IP, error) {
- if err := runtime.CalicoHandler.InitGateway("yavirt-cali-gw"); err != nil {
- return nil, errors.Trace(err)
+func getGatewayBoundIPs() ([]net.IP, error) {
+ drv := networkFactory.GetDriver(network.CalicoMode)
+ if drv == nil {
+ return nil, errors.New("calico driver is not intialized")
+ }
+ cali, _ := drv.(*calico.Driver)
+ if err := cali.InitGateway("yavirt-cali-gw"); err != nil {
+ return nil, errors.Wrap(err, "")
}
- gw := runtime.CalicoHandler.Gateway()
+ gw := cali.Gateway()
addrs, err := gw.ListAddr()
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
ips := make([]net.IP, addrs.Len())
@@ -49,8 +57,13 @@ func getGatewayBoundIPs(runtime run.Runtime) ([]net.IP, error) {
return ips, nil
}
-func alignGatewayIPs(runtime run.Runtime, bound []net.IP, dryRun bool) error {
- wep := runtime.CalicoHandler.GatewayWorkloadEndpoint()
+func alignGatewayIPs(bound []net.IP, dryRun bool) error {
+ drv := networkFactory.GetDriver(network.CalicoMode)
+ if drv == nil {
+ return errors.New("calico driver is not intialized")
+ }
+ cali, _ := drv.(*calico.Driver)
+ wep := cali.GatewayWorkloadEndpoint()
for _, bip := range bound {
ipn := libcalinet.IPNet{
@@ -81,7 +94,12 @@ func alignGatewayIPs(runtime run.Runtime, bound []net.IP, dryRun bool) error {
continue
}
- _, err := runtime.CalicoDriver.WorkloadEndpoint().WorkloadEndpoints().Update(context.Background(), wep, libcaliopt.SetOptions{})
+ drv := networkFactory.GetDriver(network.CalicoMode)
+ if drv == nil {
+ return errors.New("calico driver is not intialized")
+ }
+ cali, _ := drv.(*calico.Driver)
+ _, err := cali.WorkloadEndpoints().Update(context.Background(), wep, libcaliopt.SetOptions{})
if err != nil {
return err
}
diff --git a/cmd/run/run.go b/cmd/run/run.go
index 4b8ec87..fee81e2 100644
--- a/cmd/run/run.go
+++ b/cmd/run/run.go
@@ -2,25 +2,17 @@ package run
import (
"context"
- "os"
- "strings"
"time"
"github.com/urfave/cli/v2"
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/core/log"
+ coretypes "github.com/projecteru2/core/types"
"github.com/projecteru2/yavirt/configs"
- "github.com/projecteru2/yavirt/internal/models"
- "github.com/projecteru2/yavirt/internal/virt"
- "github.com/projecteru2/yavirt/internal/virt/guest/manager"
- "github.com/projecteru2/yavirt/internal/vnet"
- "github.com/projecteru2/yavirt/internal/vnet/calico"
- calinet "github.com/projecteru2/yavirt/internal/vnet/calico"
- "github.com/projecteru2/yavirt/internal/vnet/device"
- calihandler "github.com/projecteru2/yavirt/internal/vnet/handler/calico"
- "github.com/projecteru2/yavirt/pkg/errors"
- "github.com/projecteru2/yavirt/pkg/idgen"
+ "github.com/projecteru2/yavirt/internal/service"
+ "github.com/projecteru2/yavirt/internal/service/boar"
"github.com/projecteru2/yavirt/pkg/netx"
- "github.com/projecteru2/yavirt/pkg/store"
)
var runtime Runtime
@@ -30,17 +22,9 @@ type Runner func(*cli.Context, Runtime) error
// Runtime .
type Runtime struct {
- SkipSetupHost bool
- Host *models.Host
- Device *device.Driver
- CalicoDriver *calinet.Driver
- CalicoHandler *calihandler.Handler
- Guest manager.Manager
-}
-
-// VirtContext .
-func (r Runtime) VirtContext() virt.Context {
- return virt.NewContext(context.Background(), r.CalicoHandler)
+ Ctx context.Context
+ CancelFn context.CancelFunc
+ Svc service.Service
}
// ConvDecimal .
@@ -59,83 +43,35 @@ func (r Runtime) ConvDecimal(ipv4 string) int64 {
// Run .
func Run(fn Runner) cli.ActionFunc {
- return func(c *cli.Context) error {
+ return func(c *cli.Context) (err error) {
cfg := &configs.Conf
- if err := cfg.Load([]string{c.String("config")}); err != nil {
- return errors.Trace(err)
+ if err := cfg.Load(c.String("config")); err != nil {
+ return errors.Wrap(err, "")
}
if err := cfg.Prepare(c); err != nil {
return err
}
- runtime.SkipSetupHost = c.Bool("skip-setup-host")
- runtime.Guest = manager.New()
- // when add host, we need skip host setup
- if c.Command.FullName() == "host add" {
- runtime.SkipSetupHost = true
- }
- if err := setup(); err != nil {
- return errors.Trace(err)
- }
-
- return fn(c, runtime)
- }
-}
-func setup() error {
- if err := store.Setup("etcd"); err != nil {
- return errors.Trace(err)
- }
-
- if runtime.SkipSetupHost {
- return nil
- }
-
- if err := setupHost(); err != nil {
- return errors.Trace(err)
- }
-
- idgen.Setup(runtime.Host.ID, time.Now())
-
- if runtime.Host.NetworkMode == vnet.NetworkCalico {
- if err := setupCalico(); err != nil {
- return errors.Trace(err)
+ // always send log to stdout
+ svcLog := &coretypes.ServerLogConfig{
+ Level: configs.Conf.Log.Level,
+ UseJSON: configs.Conf.Log.UseJSON,
+ Filename: configs.Conf.Log.Filename,
+ MaxSize: configs.Conf.Log.MaxSize,
+ MaxAge: configs.Conf.Log.MaxAge,
+ MaxBackups: configs.Conf.Log.MaxBackups,
}
- }
-
- return nil
-}
-
-func setupHost() (err error) {
- if runtime.Host, err = models.LoadHost(); err != nil {
- return errors.Trace(err)
- }
-
- return nil
-}
-
-func setupCalico() (err error) {
- if endps := os.Getenv("ETCD_ENDPOINTS"); len(endps) < 1 {
- if err = os.Setenv("ETCD_ENDPOINTS", strings.Join(configs.Conf.EtcdEndpoints, ",")); err != nil {
- return
+ if err := log.SetupLog(c.Context, svcLog, configs.Conf.Log.SentryDSN); err != nil {
+ return err
}
- }
-
- if runtime.Device, err = device.New(); err != nil {
- return
- }
- if runtime.CalicoDriver, err = calico.NewDriver(configs.Conf.CalicoConfigFile, configs.Conf.CalicoPoolNames); err != nil {
- return
- }
+ runtime.Ctx, runtime.CancelFn = context.WithTimeout(context.Background(), time.Duration(c.Int("timeout"))*time.Second)
+ runtime.Svc, err = boar.New(c.Context, &configs.Conf, nil)
+ if err != nil {
+ return errors.Wrap(err, "")
+ }
- var outboundIP string
- if outboundIP, err = netx.GetOutboundIP(configs.Conf.Core.Addrs[0]); err != nil {
- return
+ return fn(c, runtime)
}
-
- runtime.CalicoHandler = calihandler.New(runtime.Device, runtime.CalicoDriver, configs.Conf.CalicoPoolNames, outboundIP)
- err = runtime.CalicoHandler.InitGateway(configs.Conf.CalicoGatewayName)
-
- return
}
diff --git a/config.example.toml b/config.example.toml
new file mode 100644
index 0000000..c306c0b
--- /dev/null
+++ b/config.example.toml
@@ -0,0 +1,110 @@
+env = "dev"
+graceful_timeout = "20s"
+virt_timeout = "1h"
+health_check_timeout = "2s"
+qmp_connect_timeout = "8s"
+
+resize_volume_min_ratio = 0.05
+resize_volume_min_size = 10737418240
+
+max_concurrency = 100000 # optional, default 100000 for pool size
+max_snapshots_count = 30
+snapshot_restorable_days = 7
+
+meta_timeout = "1m"
+meta_type = "etcd"
+
+virt_dir = "/opt/yavirtd"
+virt_bridge = "yavirbr0"
+virt_cpu_cache_passthrough = true
+
+ga_disk_timeout = "16m"
+ga_boot_timeout = "30m"
+
+recovery_on = false
+recovery_max_retries = 2
+recovery_retry_interval = "3m"
+recovery_interval = "10m"
+
+cert_path = "/etc/eru/tls" # optional, if you need connect to daemon without https
+
+
+[log]
+level = "info"
+use_json = false
+filename = ""
+
+[resource]
+min_cpu = 1
+max_cpu = 112
+min_memory = 536870912 # 0.5GB
+max_memory = 549755813888 # 512GB
+
+[host]
+id = "unique id for host"
+addr = "{{ inventory_hostname }}"
+name = "{{ node_yavirt_name }}"
+subnet = "127.0.0.1"
+cpu = 0
+memory = ""
+storage = ""
+network = "calico"
+
+[eru]
+addrs = ["127.0.0.1:5001"]
+username = "{{ core_username }}"
+password = "{{ core_password }}"
+status_check_interval = "64s"
+
+[etcd]
+prefix = "/yavirt/v1"
+endpoints = ["127.0.0.1:2379"]
+
+[network]
+modes = ["calico"]
+default_mode = "calico"
+
+[network.calico]
+pools = ["{{ calico_ippool_name }}"]
+
+[network.cni]
+plugin_path = "/usr/bin/yavirt-cni"
+config_path = "/etc/cni/net.d/yavirt-cni.conf"
+
+[network.ovn]
+nb_addr = "{{ ovn_nb_addr }}"
+ovsdb_addr = "{{ ovsdb_addr }}"
+
+[image_hub]
+type = "docker"
+prefix = "{{ image_prefix }}"
+username = "{{ image_hub_username }}"
+password = "{{ image_hub_password }}"
+pull_policy = "{{ image_pull_policy }}"
+
+[auth]
+username = "{{ yavirt_username }}"
+password = "{{ yavirt_password }}"
+
+[storage]
+init_guest_volume = false
+[storage.ceph]
+monitor_addrs = ["127.0.0.1:6789"]
+username = "{{ ceph_username}}"
+secret_uuid = "{{ ceph_secret_uuid }}"
+
+[notify]
+type = "all"
+
+[notify.all]
+types = ["dingding", "mail"]
+
+[notify.dingding]
+token = "{{ dingtalk_token }}"
+
+[notify.mail]
+smtp_host = "smtp.qiye.aliyun.com"
+smtp_port = 465
+sender = "{{ email_sender }}"
+password = "{{ email_password }}"
+receivers = ["user1@xxx.com"]
diff --git a/configs/batch.go b/configs/batch.go
index f67aa19..9217fa7 100644
--- a/configs/batch.go
+++ b/configs/batch.go
@@ -2,18 +2,20 @@ package configs
import (
"strings"
+ "time"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/yavirt/pkg/terrors"
)
// Batch .
type Batch struct {
- Bins []string `toml:"bins"`
- FlagFile string `toml:"flag_file"`
- ForceOK bool `toml:"force_ok"`
- Timeout Duration `toml:"timeout"`
- Retry bool `toml:"retry"`
- Interval Duration `toml:"interval"`
+ Bins []string `toml:"bins"`
+ FlagFile string `toml:"flag_file"`
+ ForceOK bool `toml:"force_ok"`
+ Timeout time.Duration `toml:"timeout"`
+ Retry bool `toml:"retry"`
+ Interval time.Duration `toml:"interval"`
}
// IsRunOnce .
@@ -28,7 +30,7 @@ func (b Batch) GetCommands() (map[string][]string, error) {
for _, bin := range b.Bins {
switch parts := strings.Split(bin, " "); len(parts) {
case 0:
- return nil, errors.Annotatef(errors.ErrInvalidValue, "invalid command: %s", bin)
+ return nil, errors.Wrapf(terrors.ErrInvalidValue, "invalid command: %s", bin)
case 1:
cmds[parts[0]] = nil
default:
diff --git a/configs/check.go b/configs/check.go
index c997cf7..be561c2 100644
--- a/configs/check.go
+++ b/configs/check.go
@@ -6,7 +6,7 @@ import (
"strconv"
"strings"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/cockroachdb/errors"
)
type checker struct { //nolint
@@ -29,15 +29,15 @@ func (c *checker) check() (err error) { //nolint
}
if c.fieldObj, c.val, err = c.getFieldValue(reflect.ValueOf(c.conf), c.field); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
if err := c.checkEnum(); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
if err := c.checkRange(); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
return
diff --git a/configs/codec.go b/configs/codec.go
index 6d40dff..2f7a0f8 100644
--- a/configs/codec.go
+++ b/configs/codec.go
@@ -5,13 +5,13 @@ import (
"github.com/BurntSushi/toml"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/cockroachdb/errors"
)
// Decode .
func Decode(raw string, conf *Config) error {
if _, err := toml.Decode(raw, conf); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
return nil
}
@@ -26,7 +26,7 @@ func Encode(conf *Config, noIndents ...bool) (string, error) {
}
if err := enc.Encode(conf); err != nil {
- return "", errors.Trace(err)
+ return "", errors.Wrap(err, "")
}
return buf.String(), nil
diff --git a/configs/config.go b/configs/config.go
index 48eed27..445c282 100644
--- a/configs/config.go
+++ b/configs/config.go
@@ -1,43 +1,34 @@
package configs
import (
- "crypto/tls"
"os"
"path/filepath"
"strings"
"time"
- _ "embed"
-
- clientv3 "go.etcd.io/etcd/client/v3"
- "go.etcd.io/etcd/pkg/transport"
-
+ "github.com/cockroachdb/errors"
"github.com/dustin/go-humanize"
- "github.com/projecteru2/yavirt/pkg/errors"
- "github.com/projecteru2/yavirt/pkg/log"
+ "github.com/mcuadros/go-defaults"
"github.com/projecteru2/yavirt/pkg/netx"
+ "github.com/projecteru2/yavirt/pkg/notify/bison"
+ "github.com/projecteru2/yavirt/pkg/utils"
"github.com/urfave/cli/v2"
+
+ coretypes "github.com/projecteru2/core/types"
+ vmitypes "github.com/yuyang0/vmimage/types"
)
var (
- //go:embed default-config.toml
- DefaultTemplate string
- Conf = newDefault()
+ Conf = newDefault()
)
type sizeType int64
type subnetType int64
-type CoreConfig struct {
- Addrs []string `toml:"addrs"`
- Username string `toml:"username"`
- Password string `toml:"password"`
- StatusCheckInterval Duration `toml:"status_check_interval"`
- NodeStatusTTL Duration `toml:"nodestatus_ttl"`
- Nodename string `toml:"nodename"`
-}
-
func (a *sizeType) UnmarshalText(text []byte) error {
+ if len(text) == 0 {
+ return nil
+ }
var err error
i, err := humanize.ParseBytes(string(text))
if err != nil {
@@ -60,90 +51,225 @@ func (a *subnetType) UnmarshalText(text []byte) error {
return nil
}
+// HealthCheckConfig contain healthcheck config
+type HealthCheckConfig struct {
+ Interval int `toml:"interval" default:"60"`
+ Timeout int `toml:"timeout" default:"10"`
+ CacheTTL int64 `toml:"cache_ttl" default:"300"`
+ EnableDefaultChecker bool `toml:"enable_default_checker" default:"true"`
+}
+
+// Config contain all configs
+type EruConfig struct {
+ Enable bool `toml:"enable" default:"true"`
+ Addrs []string `toml:"addrs"`
+ Username string `toml:"username"`
+ Password string `toml:"password"`
+ Podname string `toml:"podname" default:"virt"`
+
+ Hostname string `toml:"-"`
+ HeartbeatInterval int `toml:"heartbeat_interval" default:"60"`
+ Labels []string `toml:"labels"` // node labels
+
+ CheckOnlyMine bool `toml:"check_only_mine" default:"false"`
+
+ HealthCheck HealthCheckConfig `toml:"healthcheck"`
+
+ GlobalConnectionTimeout time.Duration `toml:"global_connection_timeout" default:"5s"`
+}
+
+// GetHealthCheckStatusTTL returns the TTL for health check status.
+// Because selfmon is integrated in eru-core, so there returns 0.
+func (config *EruConfig) GetHealthCheckStatusTTL() int64 {
+ return 0
+}
+
type HostConfig struct {
- Name string `json:"name" toml:"name"`
- Addr string `json:"addr" toml:"addr"`
- Type string `json:"type" toml:"type"`
- Subnet subnetType `json:"subnet" toml:"subnet"`
- CPU int `json:"cpu" toml:"cpu"`
- Memory sizeType `json:"memory" toml:"memory"`
- Storage sizeType `json:"storage" toml:"storage"`
- NetworkMode string `json:"network,omitempty" toml:"network"`
+ ID uint32 `json:"id" toml:"id"`
+ Name string `json:"name" toml:"name"`
+ Addr string `json:"addr" toml:"addr"`
+ Type string `json:"type" toml:"type"`
+ Subnet subnetType `json:"subnet" toml:"subnet"`
+ CPU int `json:"cpu" toml:"cpu"`
+ Memory sizeType `json:"memory" toml:"memory"`
+ Storage sizeType `json:"storage" toml:"storage"`
+}
+
+type ETCDConfig struct {
+ Prefix string `toml:"prefix" default:"/yavirt/v1"`
+ Endpoints []string `toml:"endpoints" default:"[http://127.0.0.1:2379]"`
+ Username string `toml:"username"`
+ Password string `toml:"password"`
+ CA string `toml:"ca"`
+ Key string `toml:"key"`
+ Cert string `toml:"cert"`
+}
+
+type CalicoConfig struct {
+ ConfigFile string `toml:"config_file" default:"/etc/calico/calicoctl.cfg"`
+ Nodename string `toml:"nodename"`
+ PoolNames []string `toml:"pools" default:"[clouddev]"`
+ GatewayName string `toml:"gateway" default:"yavirt-cali-gw"`
+ ETCDEnv string `toml:"etcd_env" default:"ETCD_ENDPOINTS"`
+ IFNamePrefix string `toml:"ifname_prefix" default:"cali"`
+}
+
+func (c *CalicoConfig) Check() error {
+ if len(c.ConfigFile) == 0 && len(os.Getenv(c.ETCDEnv)) == 0 {
+ return errors.New("either config_file or etcd_env must be set")
+ }
+ return nil
+}
+
+type CNIConfig struct {
+ PluginPath string `toml:"plugin_path" default:"/usr/bin/yavirt-cni"`
+ ConfigPath string `toml:"config_path" default:"/etc/cni/net.d/yavirt-cni.conf"`
+ IFNamePrefix string `toml:"ifname_prefix" default:"yap"`
+}
+
+func (c *CNIConfig) Check() error {
+ if c.PluginPath == "" || c.ConfigPath == "" {
+ return errors.New("cni config must be set")
+ }
+ return nil
+}
+
+type VlanConfig struct {
+ Subnet subnetType `json:"subnet" toml:"subnet"`
+ IFNamePrefix string `toml:"ifname_prefix" default:"yap"`
+}
+
+func (c *VlanConfig) Check() error {
+ return nil
+}
+
+type OVNConfig struct {
+ NBAddrs []string `toml:"nb_addrs" default:"[tcp:127.0.0.1:6641]"`
+ OVSDBAddr string `toml:"ovsdb_addr" default:"unix:/var/run/openvswitch/db.sock"`
+ IFNamePrefix string `toml:"ifname_prefix" default:"yap"`
+}
+
+func (c *OVNConfig) Check() error {
+ if len(c.NBAddrs) == 0 || c.OVSDBAddr == "" {
+ return errors.New("ovn config must be set")
+ }
+ return nil
+}
+
+type NetworkConfig struct {
+ Modes []string `toml:"modes" default:"[calico]"` // supported network modes
+ DefaultMode string `toml:"default_mode" default:"calico"`
+ Calico CalicoConfig `toml:"calico"`
+ CNI CNIConfig `toml:"cni"`
+ Vlan VlanConfig `toml:"vlan"`
+ OVN OVNConfig `toml:"ovn"`
+}
+
+type CephConfig struct {
+ MonitorAddrs []string `toml:"monitor_addrs"`
+ Username string `toml:"username" default:"eru"`
+ SecretUUID string `toml:"secret_uuid"`
+}
+
+type LocalConfig struct {
+ Dir string `toml:"dir"`
+}
+
+type StorageConfig struct {
+ InitGuestVolume bool `toml:"init_guest_volume"`
+ Ceph CephConfig `toml:"ceph"`
+ Local LocalConfig `toml:"local"`
+}
+
+type ResourceConfig struct {
+ MinCPU int `toml:"min_cpu" default:"1"`
+ MaxCPU int `toml:"max_cpu" default:"112"`
+ MinMemory int64 `toml:"min_memory" default:"536870912"` // default: 512M
+ MaxMemory int64 `toml:"max_memory" default:"549755813888"` // default: 512G
+ ReservedMemory int64 `toml:"reserved_memory" default:"10737418240"` // default: 10GB
+ MinVolumeCap int64 `toml:"min_volume" default:"1073741824"`
+ MaxVolumeCap int64 `toml:"max_volume" default:"1099511627776"`
+ MaxVolumesCount int `toml:"max_volumes_count" default:"8"`
+ Bandwidth int64 `toml:"bandwidth" default:"50000000000"`
+ ExcludePCIs []string `toml:"exclude_pcis"`
+
+ GPUProductMap map[string]string `toml:"gpu_product_map"`
+}
+
+type VMAuthConfig struct {
+ Username string `toml:"username" default:"root"`
+ Password string `toml:"password" default:"root"`
+}
+
+type LogConfig struct {
+ Level string `toml:"level" default:"info"`
+ UseJSON bool `toml:"use_json"`
+ SentryDSN string `toml:"sentry_dsn"`
+ Verbose bool `toml:"verbose"`
+ // for file log
+ Filename string `toml:"filename"`
+ MaxSize int `toml:"maxsize" default:"500"`
+ MaxAge int `toml:"max_age" default:"28"`
+ MaxBackups int `toml:"max_backups" default:"3"`
}
// Config .
type Config struct {
- Env string `toml:"env"`
- // host-related config
- Host HostConfig `toml:"host"`
- Core CoreConfig `toml:"core"`
+ Env string `toml:"env" default:"dev"`
+ CertPath string `toml:"cert_path" default:"/etc/eru/tls"`
- ProfHTTPPort int `toml:"prof_http_port"`
- BindHTTPAddr string `toml:"bind_http_addr"`
- BindGRPCAddr string `toml:"bind_grpc_addr"`
+ MaxConcurrency int `toml:"max_concurrency" default:"100000"`
+ ProfHTTPPort int `toml:"prof_http_port" default:"9999"`
+ BindHTTPAddr string `toml:"bind_http_addr" default:"0.0.0.0:9696"`
+ BindGRPCAddr string `toml:"bind_grpc_addr" default:"0.0.0.0:9697"`
SkipGuestReportRegexps []string `toml:"skip_guest_report_regexps"`
- EnabledCalicoCNI bool `toml:"enabled_calico_cni"`
- CNIPluginPath string `toml:"cni_plugin_path"`
- CNIConfigPath string `toml:"cni_config_path"`
-
- VirtTimeout Duration `toml:"virt_timeout"`
- GracefulTimeout Duration `toml:"graceful_timeout"`
- HealthCheckTimeout Duration `toml:"health_check_timeout"`
- QMPConnectTimeout Duration `toml:"qmp_connect_timeout"`
-
- ImageHubDomain string `toml:"image_hub_domain"`
- ImageHubNamespace string `toml:"image_hub_namespace"`
-
- GADiskTimeout Duration `toml:"ga_disk_timeout"`
- GABootTimeout Duration `toml:"ga_boot_timeout"`
-
- ResizeVolumeMinRatio float64 `toml:"resize_volume_min_ratio"`
- ResizeVolumeMinSize int64 `toml:"resize_volume_min_size"`
-
- MinCPU int `toml:"min_cpu"`
- MaxCPU int `toml:"max_cpu"`
- MinMemory int64 `toml:"min_memory"`
- MaxMemory int64 `toml:"max_memory"`
- MinVolumeCap int64 `toml:"min_volume"`
- MaxVolumeCap int64 `toml:"max_volume"`
- MaxVolumesCount int `toml:"max_volumes_count"`
- MaxSnapshotsCount int `toml:"max_snapshots_count"`
- SnapshotRestorableDay int `toml:"snapshot_restorable_days"`
-
- CalicoConfigFile string `toml:"calico_config_file"`
- CalicoPoolNames []string `toml:"calico_pools"`
- CalicoGatewayName string `toml:"calico_gateway"`
- CalicoETCDEnv string `toml:"calico_etcd_env"`
-
- MetaTimeout Duration `toml:"meta_timeout"`
- MetaType string `toml:"meta_type"`
-
- VirtDir string `toml:"virt_dir"`
+ EnableLibvirtMetrics bool `toml:"enable_libvirt_metrics"`
+
+ VirtTimeout time.Duration `toml:"virt_timeout" default:"60m"`
+ GracefulTimeout time.Duration `toml:"graceful_timeout" default:"20s"`
+ HealthCheckTimeout time.Duration `toml:"health_check_timeout" default:"2s"`
+ QMPConnectTimeout time.Duration `toml:"qmp_connect_timeout" default:"8s"`
+ MemStatsPeriod int `toml:"mem_stats_period" default:"10"` // in seconds
+
+ GADiskTimeout time.Duration `toml:"ga_disk_timeout" default:"16m"`
+ GABootTimeout time.Duration `toml:"ga_boot_timeout" default:"30m"`
+
+ ResizeVolumeMinRatio float64 `toml:"resize_volume_min_ratio" default:"0.001"`
+ ResizeVolumeMinSize int64 `toml:"resize_volume_min_size" default:"1073741824"` // default 1GB
+
+ MaxSnapshotsCount int `toml:"max_snapshots_count" default:"30"`
+ SnapshotRestorableDay int `toml:"snapshot_restorable_days" default:"7"`
+
+ MetaTimeout time.Duration `toml:"meta_timeout" default:"1m"`
+ MetaType string `toml:"meta_type" default:"etcd"`
+
+ VirtDir string `toml:"virt_dir" default:"/opt/yavirtd"`
VirtFlockDir string `toml:"virt_flock_dir"`
VirtTmplDir string `toml:"virt_temp_dir"`
- VirtSockDir string `toml:"virt_sock_dir"`
- VirtBridge string `toml:"virt_bridge"`
- VirtCPUCachePassthrough bool `toml:"virt_cpu_cache_passthrough"`
-
- LogLevel string `toml:"log_level"`
- LogFile string `toml:"log_file"`
- LogSentry string `toml:"log_sentry"`
-
- EtcdPrefix string `toml:"etcd_prefix"`
- EtcdEndpoints []string `toml:"etcd_endpoints"`
- EtcdUsername string `toml:"etcd_username"`
- EtcdPassword string `toml:"etcd_password"`
- EtcdCA string `toml:"etcd_ca"`
- EtcdKey string `toml:"etcd_key"`
- EtcdCert string `toml:"etcd_cert"`
+ VirtCloudInitDir string `toml:"virt_cloud_init_dir"`
+ VirtBridge string `toml:"virt_bridge" default:"yavirbr0"`
+ VirtCPUCachePassthrough bool `toml:"virt_cpu_cache_passthrough" default:"true"`
Batches []*Batch `toml:"batches"`
// system recovery
- RecoveryOn bool `toml:"recovery_on"`
- RecoveryMaxRetries int `toml:"recovery_max_retries"`
- RecoveryRetryInterval Duration `toml:"recovery_retry_interval"`
- RecoveryInterval Duration `toml:"recovery_interval"`
+ RecoveryOn bool `toml:"recovery_on"`
+ RecoveryMaxRetries int `toml:"recovery_max_retries" default:"2"`
+ RecoveryRetryInterval time.Duration `toml:"recovery_retry_interval" default:"3m"`
+ RecoveryInterval time.Duration `toml:"recovery_interval" default:"10m"`
+
+ // host-related config
+ Host HostConfig `toml:"host"`
+ Eru EruConfig `toml:"eru"`
+ Etcd ETCDConfig `toml:"etcd"`
+ Network NetworkConfig `toml:"network"`
+ Storage StorageConfig `toml:"storage"`
+ Resource ResourceConfig `toml:"resource"`
+ ImageHub vmitypes.Config `toml:"image_hub"`
+ Auth coretypes.AuthConfig `toml:"auth"` // grpc auth
+ VMAuth VMAuthConfig `toml:"vm_auth"`
+ Log LogConfig `toml:"log"`
+ Notify bison.Config `toml:"notify"`
}
func Hostname() string {
@@ -151,12 +277,9 @@ func Hostname() string {
}
func newDefault() Config {
- var conf Config
- if err := Decode(DefaultTemplate, &conf); err != nil {
- log.FatalStack(err)
- }
-
- return conf
+ conf := new(Config)
+ defaults.SetDefaults(conf)
+ return *conf
}
// Dump .
@@ -165,10 +288,10 @@ func (cfg *Config) Dump() (string, error) {
}
// Load .
-func (cfg *Config) Load(files []string) error {
+func (cfg *Config) Load(files ...string) error {
for _, path := range files {
if err := DecodeFile(path, cfg); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
}
return nil
@@ -193,24 +316,41 @@ func (cfg *Config) Prepare(c *cli.Context) (err error) {
}
if c.String("log-level") != "" {
- cfg.LogLevel = c.String("log-level")
+ cfg.Log.Level = c.String("log-level")
}
if len(c.StringSlice("core-addrs")) > 0 {
- cfg.Core.Addrs = c.StringSlice("core-addrs")
+ cfg.Eru.Addrs = c.StringSlice("core-addrs")
}
if c.String("core-username") != "" {
- cfg.Core.Username = c.String("core-username")
+ cfg.Eru.Username = c.String("core-username")
}
if c.String("core-password") != "" {
- cfg.Core.Password = c.String("core-password")
+ cfg.Eru.Password = c.String("core-password")
}
// prepare ETCD_ENDPOINTS(Calico needs this environment variable)
- if len(cfg.EtcdEndpoints) > 0 {
- if err = os.Setenv("ETCD_ENDPOINTS", strings.Join(cfg.EtcdEndpoints, ",")); err != nil {
+ if !utils.FileExists(cfg.Network.Calico.ConfigFile) {
+ cfg.Network.Calico.ConfigFile = ""
+ }
+ if cfg.Network.Calico.Nodename == "" {
+ cfg.Network.Calico.Nodename = cfg.Host.Name
+ }
+ if len(cfg.Etcd.Endpoints) > 0 {
+ if err = os.Setenv(cfg.Network.Calico.ETCDEnv, strings.Join(cfg.Etcd.Endpoints, ",")); err != nil {
return err
}
}
+ if cfg.CertPath != "" {
+ if cfg.Etcd.CA == "" {
+ cfg.Etcd.CA = filepath.Join(cfg.CertPath, "etcd", "ca.pem")
+ }
+ if cfg.Etcd.Cert == "" {
+ cfg.Etcd.Cert = filepath.Join(cfg.CertPath, "etcd", "cert.pem")
+ }
+ if cfg.Etcd.Key == "" {
+ cfg.Etcd.Key = filepath.Join(cfg.CertPath, "etcd", "key.pem")
+ }
+ }
if cfg.Host.Addr == "" {
return errors.New("Address must be provided")
@@ -219,19 +359,71 @@ func (cfg *Config) Prepare(c *cli.Context) (err error) {
if cfg.Host.Name == "" {
return errors.New("Hostname must be provided")
}
- if len(cfg.Core.Addrs) == 0 {
+ // Network
+ if err := cfg.checkNetwork(); err != nil {
+ return err
+ }
+ // eru
+ if len(cfg.Eru.Addrs) == 0 {
return errors.New("Core addresses are needed")
}
-
+ cfg.Eru.Hostname = cfg.Host.Name
+ if err := cfg.ImageHub.CheckAndRefine(); err != nil {
+ return err
+ }
return cfg.loadVirtDirs()
}
+func (cfg *Config) checkNetwork() error {
+ if len(cfg.Network.Modes) == 0 {
+ return errors.New("Network modes must be provided")
+ }
+ if cfg.Network.DefaultMode == "" {
+ cfg.Network.DefaultMode = cfg.Network.Modes[0]
+ }
+ var found bool
+ for _, mode := range cfg.Network.Modes {
+ if mode == cfg.Network.DefaultMode {
+ found = true
+ break
+ }
+ switch mode {
+ case "cni":
+ if err := cfg.Network.CNI.Check(); err != nil {
+ return err
+ }
+ case "calico":
+ if err := cfg.Network.Calico.Check(); err != nil {
+ return err
+ }
+ case "ovn":
+ if err := cfg.Network.OVN.Check(); err != nil {
+ return err
+ }
+ case "vlan":
+ if err := cfg.Network.Vlan.Check(); err != nil {
+ return err
+ }
+ default:
+ return errors.New("Invalid network mode")
+ }
+ }
+ if !found {
+ return errors.New("Invalid default network mode")
+ }
+ return nil
+}
+
func (cfg *Config) loadVirtDirs() error {
cfg.VirtFlockDir = filepath.Join(cfg.VirtDir, "flock")
cfg.VirtTmplDir = filepath.Join(cfg.VirtDir, "template")
- cfg.VirtSockDir = filepath.Join(cfg.VirtDir, "sock")
+ cfg.VirtCloudInitDir = filepath.Join(cfg.VirtDir, "cloud-init")
+
// ensure directories
- for _, d := range []string{cfg.VirtFlockDir, cfg.VirtTmplDir, cfg.VirtSockDir} {
+ for _, d := range []string{cfg.VirtFlockDir, cfg.VirtTmplDir, cfg.VirtCloudInitDir} {
+ if err := os.MkdirAll(d, 0755); err != nil && !os.IsExist(err) {
+ return err
+ }
err := os.MkdirAll(d, 0755)
if err != nil && !os.IsExist(err) {
return err
@@ -239,49 +431,3 @@ func (cfg *Config) loadVirtDirs() error {
}
return nil
}
-
-// NewEtcdConfig .
-func (cfg *Config) NewEtcdConfig() (etcdcnf clientv3.Config, err error) {
- etcdcnf.Endpoints = cfg.EtcdEndpoints
- etcdcnf.Username = cfg.EtcdUsername
- etcdcnf.Password = cfg.EtcdPassword
- etcdcnf.TLS, err = cfg.newEtcdTLSConfig()
- return
-}
-
-func (cfg *Config) newEtcdTLSConfig() (*tls.Config, error) {
- if len(cfg.EtcdCA) < 1 || len(cfg.EtcdKey) < 1 || len(cfg.EtcdCert) < 1 {
- return nil, nil //nolint
- }
-
- return transport.TLSInfo{
- TrustedCAFile: cfg.EtcdCA,
- KeyFile: cfg.EtcdKey,
- CertFile: cfg.EtcdCert,
- }.ClientConfig()
-}
-
-// CoreGuestStatusTTL .
-func (cfg *Config) CoreGuestStatusTTL() time.Duration {
- return 3 * cfg.Core.StatusCheckInterval.Duration() //nolint:gomnd // TTL is 3 times the interval
-}
-
-// CoreGuestStatusCheckInterval .
-func (cfg *Config) CoreGuestStatusCheckInterval() time.Duration {
- return cfg.Core.StatusCheckInterval.Duration()
-}
-
-// CoreGRPCTimeout .
-func (cfg *Config) CoreGRPCTimeout() time.Duration {
- return cfg.CoreStatusReportInterval() / 3 //nolint:gomnd // report timeout 3 times per interval
-}
-
-// CoreStatusReportInterval .
-func (cfg *Config) CoreStatusReportInterval() time.Duration {
- return cfg.Core.StatusCheckInterval.Duration() / 3 //nolint:gomnd // report 3 times every check
-}
-
-// HasImageHub indicates whether the config has ImageHub configurations.
-func (cfg *Config) HasImageHub() bool {
- return len(cfg.ImageHubDomain) > 0 && len(cfg.ImageHubNamespace) > 0
-}
diff --git a/configs/config_test.go b/configs/config_test.go
index 282abbc..2437597 100644
--- a/configs/config_test.go
+++ b/configs/config_test.go
@@ -2,6 +2,7 @@ package configs
import (
"testing"
+ "time"
"github.com/BurntSushi/toml"
"github.com/projecteru2/yavirt/pkg/test/assert"
@@ -9,6 +10,10 @@ import (
func TestHostConfig(t *testing.T) {
ss := `
+meta_timeout = "3m"
+ga_disk_timeout = "6m"
+ga_boot_timeout = "10m"
+
[host]
name = "host1"
subnet = "127.0.0.1"
@@ -16,10 +21,91 @@ cpu = 4
memory = "1gib"
storage = "40gi"
network = "calico"
+
+[resource.gpu_product_map]
+"Nvidia 3070" = "nvidia-3070"
+"Nvidia 4090" = "nvidia-4090"
`
cfg := Config{}
_, err := toml.Decode(ss, &cfg)
assert.Nil(t, err)
+ assert.Equal(t, cfg.Host.Subnet, subnetType(2130706433))
assert.Equal(t, cfg.Host.Memory, sizeType(1*1024*1024*1024))
assert.Equal(t, cfg.Host.Storage, sizeType(40*1024*1024*1024))
+ assert.Equal(t, cfg.MetaTimeout, 3*time.Minute)
+ assert.Equal(t, cfg.GADiskTimeout, 6*time.Minute)
+ assert.Equal(t, cfg.GABootTimeout, 10*time.Minute)
+ assert.Equal(t, cfg.Resource.GPUProductMap, map[string]string{
+ "Nvidia 3070": "nvidia-3070",
+ "Nvidia 4090": "nvidia-4090",
+ })
+
+ ss = `
+subnet = ""
+memory = ""
+storage = 0
+ `
+ host := HostConfig{}
+ _, err = toml.Decode(ss, &host)
+ assert.Nil(t, err)
+ assert.Equal(t, host.Memory, sizeType(0))
+ assert.Equal(t, host.Storage, sizeType(0))
+ assert.Equal(t, host.Subnet, subnetType(0))
+
+ ss = `
+memory = 1234
+ `
+ host = HostConfig{}
+ _, err = toml.Decode(ss, &host)
+ assert.Nil(t, err)
+ assert.Equal(t, host.Memory, sizeType(1234))
+}
+
+func TestDefault(t *testing.T) {
+ cfg := newDefault()
+ assert.Equal(t, cfg.BindHTTPAddr, "0.0.0.0:9696")
+ assert.Equal(t, cfg.BindGRPCAddr, "0.0.0.0:9697")
+ assert.Equal(t, cfg.ProfHTTPPort, 9999)
+ assert.Equal(t, cfg.Resource.MinCPU, 1)
+ assert.Equal(t, cfg.Resource.MaxCPU, 112)
+ assert.Equal(t, cfg.MemStatsPeriod, 10)
+ assert.Equal(t, cfg.ImageHub.Type, "docker")
+ assert.Equal(t, cfg.ImageHub.Docker.Endpoint, "unix:///var/run/docker.sock")
+ // assert.Equal(t, cfg.ImageHub.PullPolicy, "always")
+
+ assert.Equal(t, cfg.VirtDir, "/opt/yavirtd")
+ assert.Equal(t, cfg.VirtBridge, "yavirbr0")
+ // eru
+ assert.Equal(t, cfg.Eru.Enable, true)
+ assert.Equal(t, cfg.Eru.GlobalConnectionTimeout, 5*time.Second)
+ assert.Equal(t, cfg.Eru.HeartbeatInterval, 60)
+ assert.Equal(t, cfg.Eru.HealthCheck.Interval, 60)
+ assert.Equal(t, cfg.Eru.HealthCheck.Timeout, 10)
+ assert.Equal(t, cfg.Eru.HealthCheck.CacheTTL, int64(300))
+ // etcd
+ assert.Equal(t, cfg.Etcd.Endpoints, []string{"http://127.0.0.1:2379"})
+ assert.Equal(t, cfg.Etcd.Prefix, "/yavirt/v1")
+
+ assert.Equal(t, cfg.MetaTimeout, time.Minute)
+ assert.Equal(t, cfg.MetaType, "etcd")
+
+ assert.Equal(t, cfg.GADiskTimeout, 16*time.Minute)
+ assert.Equal(t, cfg.GABootTimeout, 30*time.Minute)
+
+ assert.Equal(t, cfg.GracefulTimeout, 20*time.Second)
+ assert.Equal(t, cfg.VirtTimeout, time.Hour)
+ assert.Equal(t, cfg.HealthCheckTimeout, 2*time.Second)
+ assert.Equal(t, cfg.QMPConnectTimeout, 8*time.Second)
+
+ assert.Equal(t, cfg.ResizeVolumeMinRatio, 0.001)
+ assert.Equal(t, cfg.ResizeVolumeMinSize, int64(1073741824))
+
+ assert.Equal(t, cfg.MaxConcurrency, 100000)
+ assert.Equal(t, cfg.MaxSnapshotsCount, 30)
+ assert.Equal(t, cfg.SnapshotRestorableDay, 7)
+
+ assert.False(t, cfg.RecoveryOn)
+ assert.Equal(t, cfg.RecoveryMaxRetries, 2)
+ assert.Equal(t, cfg.RecoveryRetryInterval, 3*time.Minute)
+ assert.Equal(t, cfg.Network.OVN.NBAddrs, []string{"tcp:127.0.0.1:6641"})
}
diff --git a/configs/default-config.toml b/configs/default-config.toml
deleted file mode 100644
index aa64ef4..0000000
--- a/configs/default-config.toml
+++ /dev/null
@@ -1,62 +0,0 @@
-env = "dev"
-prof_http_port = 9999
-bind_http_addr = "0.0.0.0:9696"
-bind_grpc_addr = "0.0.0.0:9697"
-graceful_timeout = "20s"
-virt_timeout = "1h"
-health_check_timeout = "2s"
-qmp_connect_timeout = "8s"
-cni_plugin_path = "/usr/bin/yavirt-cni"
-cni_config_path = "/etc/cni/net.d/yavirt-cni.conf"
-
-resize_volume_min_ratio = 0.05
-resize_volume_min_size = 10737418240
-
-min_cpu = 1
-max_cpu = 64
-min_memory = 1073741824
-max_memory = 68719476736
-min_volume = 1073741824
-max_volume = 1099511627776
-max_volumes_count = 8
-max_snapshots_count = 30
-snapshot_restorable_days = 7
-
-meta_timeout = "1m"
-meta_type = "etcd"
-
-virt_dir = "/tmp/virt"
-virt_bridge = "virbr0"
-virt_cpu_cache_passthrough = true
-
-calico_gateway = "yavirt-cali-gw"
-calico_pools = ["clouddev"]
-calico_etcd_env = "ETCD_ENDPOINTS"
-
-log_level = "info"
-
-etcd_prefix = "/yavirt-dev/v1"
-etcd_endpoints = ["http://127.0.0.1:2379"]
-
-ga_disk_timeout = "16m"
-ga_boot_timeout = "30m"
-
-recovery_on = false
-recovery_max_retries = 2
-recovery_retry_interval = "3m"
-recovery_interval = "10m"
-
-[host]
-name = "host1"
-subnet = "127.0.0.1"
-cpu = 4
-memory = "1g"
-storage = "40g"
-network = "calico"
-
-[core]
-addrs = ["127.0.0.1:5001"]
-username = "admin"
-password = "password"
-status_check_interval = "64s"
-nodestatus_ttl = "16m"
diff --git a/configs/time.go b/configs/time.go
deleted file mode 100644
index 9f293da..0000000
--- a/configs/time.go
+++ /dev/null
@@ -1,49 +0,0 @@
-package configs
-
-import (
- "fmt"
- "time"
-)
-
-// Duration .
-type Duration time.Duration
-
-// Duration .
-func (d Duration) Duration() time.Duration {
- return time.Duration(d)
-}
-
-// UnmarshalText .
-func (d *Duration) UnmarshalText(text []byte) error {
- var dur, err = time.ParseDuration(string(text))
- if err != nil {
- return err
- }
- *d = Duration(dur)
- return nil
-}
-
-// MarshalText .
-func (d Duration) MarshalText() ([]byte, error) {
- if d == 0 {
- return []byte("0"), nil
- }
-
- var dur = time.Duration(d)
- if dur < 0 {
- dur = -dur
- }
-
- switch {
- case dur%time.Hour == 0:
- return []byte(fmt.Sprintf("%dh", dur/time.Hour)), nil
- case dur%time.Minute == 0:
- return []byte(fmt.Sprintf("%dm", dur/time.Minute)), nil
- case dur%time.Second == 0:
- return []byte(fmt.Sprintf("%ds", dur/time.Second)), nil
- case dur%time.Millisecond == 0:
- return []byte(fmt.Sprintf("%dms", dur/time.Millisecond)), nil
- default:
- return []byte(dur.String()), nil
- }
-}
diff --git a/go.mod b/go.mod
index 12eaa08..fda6566 100644
--- a/go.mod
+++ b/go.mod
@@ -1,125 +1,212 @@
module github.com/projecteru2/yavirt
-go 1.20
+go 1.22
+
+toolchain go1.22.3
require (
- github.com/BurntSushi/toml v1.2.1
+ github.com/BurntSushi/toml v1.3.2
+ github.com/Masterminds/sprig/v3 v3.2.3
+ github.com/agiledragon/gomonkey/v2 v2.11.0
+ github.com/alphadose/haxmap v1.3.1
+ github.com/antchfx/xmlquery v1.3.17
+ github.com/blinkbean/dingtalk v0.0.0-20230927120905-796332ac4ba1
+ github.com/cenkalti/backoff/v4 v4.2.1
+ github.com/ceph/go-ceph v0.26.0
+ github.com/cockroachdb/errors v1.11.1
github.com/containernetworking/cni v1.1.2
+ github.com/deckarep/golang-set/v2 v2.3.1
+ github.com/digitalocean/go-libvirt v0.0.0-20221205150000-2939327a8519
github.com/dustin/go-humanize v1.0.1
- github.com/getsentry/sentry-go v0.20.0
- github.com/gin-gonic/gin v1.9.0
- github.com/google/uuid v1.3.0
- github.com/juju/errors v1.0.0
- github.com/libvirt/libvirt-go v7.4.0+incompatible
+ github.com/emirpasic/gods v1.18.1
+ github.com/florianl/go-tc v0.4.2
+ github.com/go-logr/logr v1.4.1
+ github.com/google/uuid v1.6.0
+ github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2
+ github.com/jaypipes/ghw v0.10.0
+ github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible
+ github.com/kdomanski/iso9660 v0.4.0
+ github.com/kr/pretty v0.3.1
+ github.com/mcuadros/go-defaults v1.2.0
+ github.com/mitchellh/mapstructure v1.5.0
+ github.com/ovn-org/libovsdb v0.6.1-0.20230912124059-239822fe891a
+ github.com/panjf2000/ants/v2 v2.9.0
+ github.com/patrickmn/go-cache v2.1.0+incompatible
+ github.com/pkg/errors v0.9.1
github.com/projectcalico/api v0.0.0-20230222223746-44aa60c2201f
github.com/projectcalico/calico v1.11.0-cni-plugin.0.20230510161715-15d193738928
- github.com/projecteru2/core v0.0.0-20230512041401-f4113e25d62c
- github.com/projecteru2/libyavirt v0.0.0-20230524090109-0faf050e0f3b
- github.com/prometheus/client_golang v1.15.0
+ github.com/projecteru2/core v0.0.0-20240613084815-dff459401ad7
+ github.com/projecteru2/libyavirt v0.0.0-20231128023216-96fef06a6ca4
+ github.com/projecteru2/resource-storage v0.0.0-20230206062354-d828802f6b96
+ github.com/prometheus-community/pro-bing v0.4.0
+ github.com/prometheus/client_golang v1.16.0
github.com/robfig/cron/v3 v3.0.1
- github.com/sirupsen/logrus v1.9.0
- github.com/stretchr/testify v1.8.2
- github.com/urfave/cli/v2 v2.25.1
+ github.com/rs/zerolog v1.30.0
+ github.com/russross/blackfriday/v2 v2.1.0
+ github.com/samber/lo v1.39.0
+ github.com/samber/slog-zerolog/v2 v2.3.0
+ github.com/shirou/gopsutil v2.21.11+incompatible
+ github.com/stretchr/testify v1.9.0
+ github.com/urfave/cli/v2 v2.27.1
github.com/vishvananda/netlink v1.2.1-beta.2.0.20230206183746-70ca0345eede
+ github.com/yuyang0/resource-bandwidth v0.0.0-20231102113253-8e47795c92e5
+ github.com/yuyang0/resource-gpu v0.0.0-20231026065700-1577d804efa8
+ github.com/yuyang0/resource-rbd v0.0.2-0.20230701090628-cb86da0f60b9
+ github.com/yuyang0/vmimage v0.0.0-20240628091041-9f45a357a3ae
go.etcd.io/etcd v3.3.27+incompatible
- go.etcd.io/etcd/client/v3 v3.5.8
- golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53
- golang.org/x/sys v0.8.0
- google.golang.org/grpc v1.54.1
+ go.etcd.io/etcd/client/v3 v3.5.12
+ go.etcd.io/etcd/tests/v3 v3.5.12
+ golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df
+ golang.org/x/sys v0.20.0
+ golang.org/x/term v0.20.0
+ golang.org/x/tools v0.21.0
+ google.golang.org/grpc v1.60.1
k8s.io/apimachinery v0.26.3
+ libvirt.org/go/libvirtxml v1.9004.0
)
+replace github.com/ovn-org/libovsdb => github.com/yuyang0/libovsdb v0.0.0-20231222065958-6f259a987799
+
require (
- github.com/alphadose/haxmap v1.2.0 // indirect
+ github.com/Masterminds/goutils v1.1.1 // indirect
+ github.com/Masterminds/semver/v3 v3.2.0 // indirect
+ github.com/Microsoft/go-winio v0.6.1 // indirect
+ github.com/StackExchange/wmi v1.2.1 // indirect
+ github.com/antchfx/xpath v1.2.4 // indirect
+ github.com/benbjohnson/clock v1.3.3 // indirect
github.com/beorn7/perks v1.0.1 // indirect
- github.com/bytedance/sonic v1.8.7 // indirect
+ github.com/cenkalti/hub v1.0.1 // indirect
+ github.com/cenkalti/rpc2 v0.0.0-20210604223624-c1acbc6ec984 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
- github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
- github.com/cockroachdb/errors v1.9.1 // indirect
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
- github.com/cockroachdb/redact v1.1.3 // indirect
+ github.com/cockroachdb/redact v1.1.5 // indirect
+ github.com/containerd/containerd v1.7.11 // indirect
github.com/coreos/etcd v3.3.27+incompatible // indirect
github.com/coreos/go-semver v0.3.1 // indirect
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/coreos/pkg v0.0.0-20230327231512-ba87abf18a23 // indirect
- github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
+ github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/distribution/reference v0.5.0 // indirect
+ github.com/docker/distribution v2.8.3+incompatible // indirect
+ github.com/docker/docker v24.0.9+incompatible // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/emicklei/go-restful/v3 v3.10.2 // indirect
- github.com/gin-contrib/sse v0.1.0 // indirect
- github.com/go-logr/logr v1.2.4 // indirect
- github.com/go-openapi/jsonpointer v0.19.6 // indirect
- github.com/go-openapi/jsonreference v0.20.2 // indirect
- github.com/go-openapi/swag v0.22.3 // indirect
+ github.com/getsentry/sentry-go v0.23.0 // indirect
+ github.com/ghodss/yaml v1.0.0 // indirect
+ github.com/go-logr/stdr v1.2.2 // indirect
+ github.com/go-ole/go-ole v1.2.6 // indirect
+ github.com/go-openapi/jsonpointer v0.21.0 // indirect
+ github.com/go-openapi/jsonreference v0.21.0 // indirect
+ github.com/go-openapi/swag v0.23.0 // indirect
+ github.com/go-ping/ping v1.1.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
- github.com/go-playground/validator/v10 v10.12.0 // indirect
- github.com/goccy/go-json v0.10.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
- github.com/golang/protobuf v1.5.3 // indirect
+ github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
+ github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
+ github.com/golang/protobuf v1.5.4 // indirect
+ github.com/google/btree v1.1.2 // indirect
github.com/google/gnostic v0.6.9 // indirect
- github.com/google/go-cmp v0.5.9 // indirect
+ github.com/google/go-cmp v0.6.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
+ github.com/gorilla/websocket v1.5.0 // indirect
+ github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
+ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
+ github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect
+ github.com/huandu/xstrings v1.3.3 // indirect
github.com/imdario/mergo v0.3.15 // indirect
+ github.com/jaypipes/pcidb v1.0.0 // indirect
github.com/jinzhu/configor v1.2.1 // indirect
+ github.com/jonboulle/clockwork v0.4.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
+ github.com/josharian/native v1.1.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kelseyhightower/envconfig v1.4.0 // indirect
- github.com/klauspost/cpuid/v2 v2.2.4 // indirect
- github.com/kr/pretty v0.3.1 // indirect
+ github.com/klauspost/compress v1.17.2 // indirect
github.com/kr/text v0.2.0 // indirect
- github.com/leodido/go-urn v1.2.3 // indirect
+ github.com/leodido/go-urn v1.4.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
- github.com/mattn/go-isatty v0.0.18 // indirect
+ github.com/mattn/go-isatty v0.0.20 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
- github.com/mitchellh/mapstructure v1.5.0 // indirect
+ github.com/mdlayher/netlink v1.7.2 // indirect
+ github.com/mdlayher/socket v0.4.1 // indirect
+ github.com/mitchellh/copystructure v1.0.0 // indirect
+ github.com/mitchellh/go-homedir v1.1.0 // indirect
+ github.com/mitchellh/reflectwalk v1.0.0 // indirect
+ github.com/moby/patternmatcher v0.6.0 // indirect
+ github.com/moby/sys/sequential v0.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
- github.com/panjf2000/ants/v2 v2.7.3 // indirect
- github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
- github.com/pelletier/go-toml/v2 v2.0.7 // indirect
- github.com/pkg/errors v0.9.1 // indirect
+ github.com/opencontainers/go-digest v1.0.0 // indirect
+ github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b // indirect
+ github.com/opencontainers/runc v1.1.12 // indirect
+ github.com/pierrec/lz4/v4 v4.1.14 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/projectcalico/go-json v0.0.0-20161128004156-6219dc7339ba // indirect
github.com/projectcalico/go-yaml-wrapper v0.0.0-20191112210931-090425220c54 // indirect
+ github.com/projecteru2/vmihub v0.0.0-20240628073228-3417154bf02a // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.42.0 // indirect
- github.com/prometheus/procfs v0.9.0 // indirect
- github.com/rogpeppe/go-internal v1.10.0 // indirect
- github.com/rs/zerolog v1.29.1 // indirect
- github.com/russross/blackfriday/v2 v2.1.0 // indirect
+ github.com/prometheus/procfs v0.10.1 // indirect
+ github.com/rogpeppe/go-internal v1.11.0 // indirect
+ github.com/samber/slog-common v0.16.0 // indirect
+ github.com/shopspring/decimal v1.3.1 // indirect
+ github.com/sirupsen/logrus v1.9.3 // indirect
+ github.com/soheilhy/cmux v0.1.5 // indirect
+ github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
- github.com/stretchr/objx v0.5.0 // indirect
- github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
- github.com/ugorji/go/codec v1.2.11 // indirect
+ github.com/stretchr/objx v0.5.2 // indirect
+ github.com/tklauser/go-sysconf v0.3.13 // indirect
+ github.com/tklauser/numcpus v0.7.0 // indirect
+ github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 // indirect
+ github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect
github.com/vishvananda/netns v0.0.4 // indirect
- github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
- go.etcd.io/etcd/api/v3 v3.5.8 // indirect
- go.etcd.io/etcd/client/pkg/v3 v3.5.8 // indirect
+ github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 // indirect
+ github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect
+ github.com/yusufpapurcu/wmi v1.2.4 // indirect
+ go.etcd.io/bbolt v1.3.8 // indirect
+ go.etcd.io/etcd/api/v3 v3.5.12 // indirect
+ go.etcd.io/etcd/client/pkg/v3 v3.5.12 // indirect
+ go.etcd.io/etcd/client/v2 v2.305.12 // indirect
+ go.etcd.io/etcd/pkg/v3 v3.5.12 // indirect
+ go.etcd.io/etcd/raft/v3 v3.5.12 // indirect
+ go.etcd.io/etcd/server/v3 v3.5.12 // indirect
+ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0 // indirect
+ go.opentelemetry.io/otel v1.20.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.20.0 // indirect
+ go.opentelemetry.io/otel/metric v1.20.0 // indirect
+ go.opentelemetry.io/otel/sdk v1.20.0 // indirect
+ go.opentelemetry.io/otel/trace v1.20.0 // indirect
+ go.opentelemetry.io/proto/otlp v1.0.0 // indirect
go.uber.org/atomic v1.10.0 // indirect
- go.uber.org/goleak v1.2.1 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.24.0 // indirect
- golang.org/x/arch v0.3.0 // indirect
- golang.org/x/crypto v0.8.0 // indirect
- golang.org/x/net v0.10.0 // indirect
- golang.org/x/oauth2 v0.7.0 // indirect
- golang.org/x/sync v0.1.0 // indirect
- golang.org/x/term v0.8.0 // indirect
- golang.org/x/text v0.9.0 // indirect
+ golang.org/x/crypto v0.23.0 // indirect
+ golang.org/x/mod v0.17.0 // indirect
+ golang.org/x/net v0.25.0 // indirect
+ golang.org/x/oauth2 v0.13.0 // indirect
+ golang.org/x/sync v0.7.0 // indirect
+ golang.org/x/text v0.15.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230215201556-9c5414ab4bde // indirect
- google.golang.org/appengine v1.6.7 // indirect
- google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
- google.golang.org/protobuf v1.30.0 // indirect
+ google.golang.org/appengine v1.6.8 // indirect
+ google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 // indirect
+ google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/go-playground/validator.v9 v9.31.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
+ gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
+ howett.net/plist v1.0.0 // indirect
k8s.io/api v0.26.3 // indirect
k8s.io/client-go v0.26.3 // indirect
k8s.io/klog/v2 v2.90.1 // indirect
diff --git a/go.sum b/go.sum
index 7e0b8f4..e32823d 100644
--- a/go.sum
+++ b/go.sum
@@ -1,57 +1,89 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
+cloud.google.com/go v0.110.8 h1:tyNdfIxjzaWctIiLYOTalaLKZ17SI44SKFW26QbOhME=
+cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY=
+cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM=
+cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
+cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
+github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
+github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
+github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
+github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
-github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
-github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno=
-github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo=
-github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
+github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
+github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
+github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
+github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
+github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g=
+github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
+github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
+github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
+github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
+github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
-github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0=
-github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
-github.com/alphadose/haxmap v1.2.0 h1:noGrAmCE+gNheZ4KpW+sYj9W5uMcO1UAjbAq9XBOAfM=
-github.com/alphadose/haxmap v1.2.0/go.mod h1:rjHw1IAqbxm0S3U5tD16GoKsiAd8FWx5BJ2IYqXwgmM=
+github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA=
+github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8=
+github.com/agiledragon/gomonkey/v2 v2.11.0 h1:5oxSgA+tC1xuGsrIorR+sYiziYltmJyEZ9qA25b6l5U=
+github.com/agiledragon/gomonkey/v2 v2.11.0/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY=
+github.com/alphadose/haxmap v1.3.1 h1:KmZh75duO1tC8pt3LmUwoTYiZ9sh4K52FX8p7/yrlqU=
+github.com/alphadose/haxmap v1.3.1/go.mod h1:rjHw1IAqbxm0S3U5tD16GoKsiAd8FWx5BJ2IYqXwgmM=
+github.com/antchfx/xmlquery v1.3.17 h1:d0qWjPp/D+vtRw7ivCwT5ApH/3CkQU8JOeo3245PpTk=
+github.com/antchfx/xmlquery v1.3.17/go.mod h1:Afkq4JIeXut75taLSuI31ISJ/zeq+3jG7TunF7noreA=
+github.com/antchfx/xpath v1.2.4 h1:dW1HB/JxKvGtJ9WyVGJ0sIoEcqftV3SqIstujI+B9XY=
+github.com/antchfx/xpath v1.2.4/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
-github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
-github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
+github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/benbjohnson/clock v1.3.3 h1:g+rSsSaAzhHJYcIQE78hJ3AhyjjtQvleKDjlhdBnIhc=
+github.com/benbjohnson/clock v1.3.3/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/blinkbean/dingtalk v0.0.0-20230927120905-796332ac4ba1 h1:G14RkaB3RRW099aQbfyHm4RFgNxGUOTeHSoN+CZy2YI=
+github.com/blinkbean/dingtalk v0.0.0-20230927120905-796332ac4ba1/go.mod h1:9BaLuGSBqY3vT5hstValh48DbsKO7vaHaJnG9pXwbto=
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
-github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
-github.com/bytedance/sonic v1.8.7 h1:d3sry5vGgVq/OpgozRUNP6xBsSo0mtNdwliApw+SAMQ=
-github.com/bytedance/sonic v1.8.7/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
+github.com/cenk/hub v1.0.1 h1:RBwXNOF4a8KjD8BJ08XqN8KbrqaGiQLDrgvUGJSHuPA=
+github.com/cenk/hub v1.0.1/go.mod h1:rJM1LNAW0ppT8FMMuPK6c2NP/R2nH/UthtuRySSaf6Y=
+github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
+github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
+github.com/cenkalti/hub v1.0.1 h1:UMtjc6dHSaOQTO15SVA50MBIR9zQwvsukQupDrkIRtg=
+github.com/cenkalti/hub v1.0.1/go.mod h1:tcYwtS3a2d9NO/0xDXVJWx3IedurUjYCqFCmpi0lpHs=
+github.com/cenkalti/rpc2 v0.0.0-20210604223624-c1acbc6ec984 h1:CNwZyGS6KpfaOWbh2yLkSy3rSTUh3jub9CzpFpP6PVQ=
+github.com/cenkalti/rpc2 v0.0.0-20210604223624-c1acbc6ec984/go.mod h1:v2npkhrXyk5BCnkNIiPdRI23Uq6uWPUQGL2hnRcRr/M=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/ceph/go-ceph v0.26.0 h1:LZoATo25ZH5aeL5t85BwIbrNLKCDfcDM+e0qV0cmwHY=
+github.com/ceph/go-ceph v0.26.0/go.mod h1:ISxb295GszZwtLPkeWi+L2uLYBVsqbsh0M104jZMOX4=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
-github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
-github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
+github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA=
+github.com/cilium/ebpf v0.8.1/go.mod h1:f5zLIM0FSNuAkSyLAN7X+Hy6yznlF1mNiWUMfxMtrgk=
+github.com/cilium/ebpf v0.9.1 h1:64sn2K3UKw8NbP/blsixRpF3nXuyhz/VjRlRzvlBRu4=
+github.com/cilium/ebpf v0.9.1/go.mod h1:+OhNOIXx/Fnu1IE8bJz2dzOA+VSfyTfdNUVdlQnxUFY=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k=
+github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD93PBm/jA=
github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU=
-github.com/cockroachdb/errors v1.9.1 h1:yFVvsI0VxmRShfawbt/laCIDy/mtTqqnvoNgiy5bEV8=
-github.com/cockroachdb/errors v1.9.1/go.mod h1:2sxOtL2WIc096WSZqZ5h8fa17rdDq9HZOZLBCor4mBk=
-github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs=
+github.com/cockroachdb/errors v1.11.1 h1:xSEW75zKaKCWzR3OfxXUxgrk/NtT4G1MiOv5lWZazG8=
+github.com/cockroachdb/errors v1.11.1/go.mod h1:8MUxA3Gi6b25tYlFEBGLf+D8aISL+M4MIpiWMSNRfxw=
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE=
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs=
-github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ=
-github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
-github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
+github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30=
+github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
+github.com/containerd/containerd v1.7.11 h1:lfGKw3eU35sjV0aG2eYZTiwFEY1pCzxdzicHP3SZILw=
+github.com/containerd/containerd v1.7.11/go.mod h1:5UluHxHTX2rdvYuZ5OJTC5m/KJNs0Zs9wVoJm9zf5ZE=
github.com/containernetworking/cni v1.1.2 h1:wtRGZVv7olUHMOqouPpn3cXJWpJgM6+EUl31EQbXALQ=
github.com/containernetworking/cni v1.1.2/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw=
-github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/bbolt v1.3.7 h1:jwixv2lofx/nLylxXRUufR6Jte5YRzsAgmQfsm64qcs=
+github.com/coreos/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
github.com/coreos/etcd v3.3.27+incompatible h1:QIudLb9KeBsE5zyYxd1mjzRSkzLg9Wf9QlRwFgd6oTA=
github.com/coreos/etcd v3.3.27+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
-github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
-github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU=
@@ -60,90 +92,101 @@ github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/coreos/pkg v0.0.0-20230327231512-ba87abf18a23 h1:SrdboTJZnOqc2r4cT4wQCzQJjGYwkclLwx2sPrDsx7g=
github.com/coreos/pkg v0.0.0-20230327231512-ba87abf18a23/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
-github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
-github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
-github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
+github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
+github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
-github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
+github.com/deckarep/golang-set/v2 v2.3.1 h1:vjmkvJt/IV27WXPyYQpAh4bRyWJc5Y435D17XQ9QU5A=
+github.com/deckarep/golang-set/v2 v2.3.1/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
+github.com/digitalocean/go-libvirt v0.0.0-20221205150000-2939327a8519 h1:OpkN/n40cmKenDQS+IOAeW9DLhYy4DADSeZnouCEV/E=
+github.com/digitalocean/go-libvirt v0.0.0-20221205150000-2939327a8519/go.mod h1:WyJJyfmJ0gWJvjV+ZH4DOgtOYZc1KOvYyBXWCLKxsUU=
+github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
+github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
+github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
+github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
+github.com/docker/docker v24.0.9+incompatible h1:HPGzNmwfLZWdxHqK9/II92pyi1EpYKsAqcl4G0Of9v0=
+github.com/docker/docker v24.0.9+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
-github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
-github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
github.com/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE=
github.com/emicklei/go-restful/v3 v3.10.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
+github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
+github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
-github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
+github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA=
+github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE=
github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84=
-github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
-github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
+github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+github.com/florianl/go-tc v0.4.2 h1:jan5zcOWCLhA9SRBHZhQ0SSAq7cmDUagiRPngAi5AOQ=
+github.com/florianl/go-tc v0.4.2/go.mod h1:2W1jSMFryiYlpQigr4ZpSSpE9XNze+bW7cTsCXWbMwo=
github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0=
+github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
+github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og=
+github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
+github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
-github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
-github.com/getsentry/sentry-go v0.12.0/go.mod h1:NSap0JBYWzHND8oMbyi0+XZhUalc1TBdRL1M71JZW2c=
-github.com/getsentry/sentry-go v0.20.0 h1:bwXW98iMRIWxn+4FgPW7vMrjmbym6HblXALmhjHmQaQ=
-github.com/getsentry/sentry-go v0.20.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY=
+github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
+github.com/getsentry/sentry-go v0.23.0 h1:dn+QRCeJv4pPt9OjVXiMcGIBIefaTJPw/h0bZWO05nE=
+github.com/getsentry/sentry-go v0.23.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY=
+github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
-github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
-github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
-github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
-github.com/gin-gonic/gin v1.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8=
-github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH89961k=
-github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
-github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
+github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
+github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
+github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
-github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
-github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
-github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
-github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
-github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
-github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
-github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
-github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
-github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
-github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
+github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
+github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
+github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
+github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
+github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
+github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
+github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
+github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
+github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
+github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
+github.com/go-ping/ping v1.1.0 h1:3MCGhVX4fyEUuhsfwPrsEdQw6xspHkv5zHsiSoDFZYw=
+github.com/go-ping/ping v1.1.0/go.mod h1:xIFjORFzTxqIV/tDVGO4eDy/bLuSyawEeojSm3GfRGk=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
-github.com/go-playground/validator/v10 v10.12.0 h1:E4gtWgxWxp8YSxExrQFv5BpCahla0PVF2oTTEYaWQGI=
-github.com/go-playground/validator/v10 v10.12.0/go.mod h1:hCAPuzYvKdP33pxWa+2+6AIKXEKqjIUyqsNCtbsSJrA=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
-github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
-github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
-github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
-github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
-github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
-github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
-github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4=
-github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
+github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
-github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM=
-github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
+github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
+github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo=
+github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
@@ -157,9 +200,10 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
-github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
-github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
-github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
+github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
+github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/gnostic v0.6.9 h1:ZK/5VhkoX835RikCHpSUJV9a+S3e1zLh59YnyWeBW+0=
github.com/google/gnostic v0.6.9/go.mod h1:Nm8234We1lq6iB9OmlgNv3nH91XLLVZHCDayfA3xq+E=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -167,61 +211,86 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
-github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
-github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
-github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
+github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI=
+github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
-github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
-github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
-github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE=
+github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4=
+github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM=
github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
-github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
-github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
-github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI=
-github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0=
-github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk=
-github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g=
-github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw=
+github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2 h1:9K06NfxkBh25x56yVhWWlKFE8YpicaSfHwoV8SFbueA=
+github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2/go.mod h1:3A9PQ1cunSDF/1rbTq99Ts4pVnycWg+vlPkfeD2NLFI=
+github.com/jaypipes/ghw v0.10.0 h1:UHu9UX08Py315iPojADFPOkmjTsNzHj4g4adsNKKteY=
+github.com/jaypipes/ghw v0.10.0/go.mod h1:jeJGbkRB2lL3/gxYzNYzEDETV1ZJ56OKr+CSeSEym+g=
+github.com/jaypipes/pcidb v1.0.0 h1:vtZIfkiCUE42oYbJS0TAq9XSfSmcsgo9IdxSm9qzYU8=
+github.com/jaypipes/pcidb v1.0.0/go.mod h1:TnYUvqhPBzCKnH34KrIX22kAeEbDCSRJ9cqLRCuNDfk=
+github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jinzhu/configor v1.2.1 h1:OKk9dsR8i6HPOCZR8BcMtcEImAFjIhbJFZNyn5GCZko=
github.com/jinzhu/configor v1.2.1/go.mod h1:nX89/MOmDba7ZX7GCyU/VIaQ2Ar2aizBl2d3JLF/rDc=
+github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4=
+github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=
+github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible h1:jdpOPRN1zP63Td1hDQbZW73xKmzDvZHzVdNYxhnTMDA=
+github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible/go.mod h1:1c7szIrayyPPB/987hsnvNzLushdWf4o/79s3P08L8A=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
-github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
-github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
+github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
+github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
+github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
+github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
+github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
+github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ=
+github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok=
+github.com/jsimonetti/rtnetlink v0.0.0-20201216134343-bde56ed16391/go.mod h1:cR77jAZG3Y3bsb8hF6fHJbFoyFukLFOkQ98S0pQz3xw=
+github.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943/go.mod h1:z4c53zj6Eex712ROyh8WI0ihysb5j2ROyV42iNogmAs=
+github.com/jsimonetti/rtnetlink v0.0.0-20210122163228-8d122574c736/go.mod h1:ZXpIyOK59ZnN7J0BV99cZUPmsqDRZ3eq5X+st7u/oSA=
+github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b/go.mod h1:8w9Rh8m+aHZIG69YPGGem1i5VzoyRC8nw2kA8B+ik5U=
+github.com/jsimonetti/rtnetlink v0.0.0-20210525051524-4cc836578190/go.mod h1:NmKSdU4VGSiv1bMsdqNALI4RSvvjtz65tTMCnD05qLo=
+github.com/jsimonetti/rtnetlink v0.0.0-20211022192332-93da33804786/go.mod h1:v4hqbTdfQngbVSZJVWUhGE/lbTFf9jb+ygmNUDQMuOs=
+github.com/jsimonetti/rtnetlink v1.3.5 h1:hVlNQNRlLDGZz31gBPicsG7Q53rnlsz1l1Ix/9XlpVA=
+github.com/jsimonetti/rtnetlink v1.3.5/go.mod h1:0LFedyiTkebnd43tE4YAkWGIq9jQphow4CcwxaT2Y00=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
-github.com/juju/errors v1.0.0 h1:yiq7kjCLll1BiaRuNY53MGI0+EQ3rF6GB+wvboZDefM=
-github.com/juju/errors v1.0.0/go.mod h1:B5x9thDqx0wIMH3+aLIMP9HjItInYWObRovoCFM5Qe8=
-github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
-github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8=
-github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE=
-github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE=
-github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro=
-github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8=
+github.com/kdomanski/iso9660 v0.4.0 h1:BPKKdcINz3m0MdjIMwS0wx1nofsOjxOq8TOr45WGHFg=
+github.com/kdomanski/iso9660 v0.4.0/go.mod h1:OxUSupHsO9ceI8lBLPJKWBTphLemjrCQY8LPXM7qSzU=
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
-github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
-github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
-github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
-github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
-github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
+github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
+github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
@@ -232,73 +301,95 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y=
-github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
-github.com/leodido/go-urn v1.2.3 h1:6BE2vPT0lqoz3fmOesHZiaiFh7889ssCo2GMvLCfiuA=
-github.com/leodido/go-urn v1.2.3/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
-github.com/libvirt/libvirt-go v7.4.0+incompatible h1:crnSLkwPqCdXtg6jib/FxBG/hweAc/3Wxth1AehCXL4=
-github.com/libvirt/libvirt-go v7.4.0+incompatible/go.mod h1:34zsnB4iGeOv7Byj6qotuW8Ya4v4Tr43ttjz/F0wjLE=
-github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
+github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
-github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
-github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
-github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
-github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
-github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
-github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
-github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
-github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
-github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
-github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
-github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8=
-github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
+github.com/mcuadros/go-defaults v1.2.0 h1:FODb8WSf0uGaY8elWJAkoLL0Ri6AlZ1bFlenk56oZtc=
+github.com/mcuadros/go-defaults v1.2.0/go.mod h1:WEZtHEVIGYVDqkKSWBdWKUVdRyKlMfulPaGDWIVeCWY=
+github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo=
+github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc=
+github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
+github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
+github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY=
+github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o=
+github.com/mdlayher/netlink v1.2.0/go.mod h1:kwVW1io0AZy9A1E2YYgaD4Cj+C+GPkU6klXCMzIJ9p8=
+github.com/mdlayher/netlink v1.2.1/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU=
+github.com/mdlayher/netlink v1.2.2-0.20210123213345-5cc92139ae3e/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU=
+github.com/mdlayher/netlink v1.3.0/go.mod h1:xK/BssKuwcRXHrtN04UBkwQ6dY9VviGGuriDdoPSWys=
+github.com/mdlayher/netlink v1.4.0/go.mod h1:dRJi5IABcZpBD2A3D0Mv/AiX8I9uDEu5oGkAVrekmf8=
+github.com/mdlayher/netlink v1.4.1/go.mod h1:e4/KuJ+s8UhfUpO9z00/fDZZmhSrs+oxyqAS9cNgn6Q=
+github.com/mdlayher/netlink v1.6.0/go.mod h1:0o3PlBmGst1xve7wQ7j/hwpNaFaH4qCRyWCdcZk8/vA=
+github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
+github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
+github.com/mdlayher/packet v1.1.2 h1:3Up1NG6LZrsgDVn6X4L9Ge/iyRyxFEFD9o6Pr3Q1nQY=
+github.com/mdlayher/packet v1.1.2/go.mod h1:GEu1+n9sG5VtiRE4SydOmX5GTwyyYlteZiFU+x0kew4=
+github.com/mdlayher/socket v0.0.0-20210307095302-262dc9984e00/go.mod h1:GAFlyu4/XV68LkQKYzKhIo/WW7j3Zi0YRAz/BOoanUc=
+github.com/mdlayher/socket v0.1.1/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs=
+github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
+github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
+github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
+github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
+github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
-github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
+github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
+github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
+github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
+github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
+github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
+github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA=
+github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
-github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
+github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
+github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
-github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
-github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
-github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
-github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
+github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
-github.com/onsi/ginkgo/v2 v2.7.1 h1:YgLPk+gpqDtAPeRCWEmfO8oxE6ru3xcVSXAM7wn8w9I=
+github.com/onsi/ginkgo/v2 v2.13.2 h1:Bi2gGVkfn6gQcjNjZJVO8Gf0FHzMPf2phUei9tejVMs=
+github.com/onsi/ginkgo/v2 v2.13.2/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
-github.com/onsi/gomega v1.25.0 h1:Vw7br2PCDYijJHSfBOWhov+8cAnUf8MfMaIOV323l6Y=
-github.com/panjf2000/ants/v2 v2.7.3 h1:rHQ0hH0DQvuNUqqlWIMJtkMcDuL1uQAfpX2mIhQ5/s0=
-github.com/panjf2000/ants/v2 v2.7.3/go.mod h1:KIBmYG9QQX5U2qzFP/yQJaq/nSb6rahS9iEHkrCMgM8=
+github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg=
+github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
+github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
+github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
+github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b h1:YWuSjZCQAPM8UUBLkYUk1e+rZcvWHJmFb6i6rM44Xs8=
+github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ=
+github.com/opencontainers/runc v1.1.12 h1:BOIssBaW1La0/qbNZHXOOa71dZfZEQOzW7dqQf3phss=
+github.com/opencontainers/runc v1.1.12/go.mod h1:S+lQwSfncpBha7XTy/5lBwWgm5+y5Ma/O44Ekby9FK8=
+github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/panjf2000/ants/v2 v2.9.0 h1:SztCLkVxBRigbg+vt0S5QvF5vxAbxbKt09/YfAJ0tEo=
+github.com/panjf2000/ants/v2 v2.9.0/go.mod h1:7ZxyxsqE4vvW0M7LSD8aI3cKwgFhBHbxnlN8mDqHa1I=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
-github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
-github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us=
-github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
+github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE=
+github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
@@ -315,55 +406,71 @@ github.com/projectcalico/go-json v0.0.0-20161128004156-6219dc7339ba h1:aaF2byUCZ
github.com/projectcalico/go-json v0.0.0-20161128004156-6219dc7339ba/go.mod h1:q8EdCgBdMQzgiX/uk4GXLWLk+gIHd1a7mWUAamJKDb4=
github.com/projectcalico/go-yaml-wrapper v0.0.0-20191112210931-090425220c54 h1:Jt2Pic9dxgJisekm8q2WV9FaWxUJhhRfwHSP640drww=
github.com/projectcalico/go-yaml-wrapper v0.0.0-20191112210931-090425220c54/go.mod h1:UgC0aTQ2KMDxlX3lU/stndk7DMUBJqzN40yFiILHgxc=
-github.com/projecteru2/core v0.0.0-20230512041401-f4113e25d62c h1:ovxsd205M4RZfAtPBHiUh34sDmz/ARSktYrgXXdRYRQ=
-github.com/projecteru2/core v0.0.0-20230512041401-f4113e25d62c/go.mod h1:zpMzjZ0hohaoB2jLsbhBsJ0KQlL10WVORpj5/BKqTtw=
-github.com/projecteru2/libyavirt v0.0.0-20230524090109-0faf050e0f3b h1:mXvbNYdr2uh2mhk5HdiBBSc9DhaR2RuulURaXhJaP2I=
-github.com/projecteru2/libyavirt v0.0.0-20230524090109-0faf050e0f3b/go.mod h1:N41KaKmqbailweGs4x/mt2H0O0Y7MizObZQ+igLdzpw=
-github.com/prometheus/client_golang v1.15.0 h1:5fCgGYogn0hFdhyhLbw7hEsWxufKtY9klyvdNfFlFhM=
-github.com/prometheus/client_golang v1.15.0/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk=
+github.com/projectcalico/hcsshim v0.8.9-calico h1:aRrOWouDTzKwaIoRGMV/I1QikR+ikwj1G9T9h3wD090=
+github.com/projectcalico/hcsshim v0.8.9-calico/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8=
+github.com/projecteru2/core v0.0.0-20240613084815-dff459401ad7 h1:VTQ/+U5Qhu7KpqZ3Z3naX7NlOpuMSwBG/uNMlSzprq0=
+github.com/projecteru2/core v0.0.0-20240613084815-dff459401ad7/go.mod h1:JDOLwVw4EdLTk+bqI/LdU4Ix/Wl6BaaHMzaOO5vpU8U=
+github.com/projecteru2/libyavirt v0.0.0-20231128023216-96fef06a6ca4 h1:3a0IhsOtH9J+iSn/DV7v9gpW2lBDGhkp+XEvTaSiK4g=
+github.com/projecteru2/libyavirt v0.0.0-20231128023216-96fef06a6ca4/go.mod h1:+EcdWF8KyTf2u8Zxu3397nSmalCSmpuxvGwcX1g3RL0=
+github.com/projecteru2/resource-storage v0.0.0-20230206062354-d828802f6b96 h1:mt8llWHpuOhPMIe7sOxr5jqYrVk4wE6eZ3cyAkj0+7o=
+github.com/projecteru2/resource-storage v0.0.0-20230206062354-d828802f6b96/go.mod h1:sdXwl7dPfO3UH8PPr7ELvEutJSAjOQOGlmkenfL6DfU=
+github.com/projecteru2/vmihub v0.0.0-20240628073228-3417154bf02a h1:DE3fhCM/OKJs2Z9bkeNKDJCpnU0wubUXNYs4Jhl93AM=
+github.com/projecteru2/vmihub v0.0.0-20240628073228-3417154bf02a/go.mod h1:h8beeiTyKvxMccTOXVcrJkYTrQer5DGi1Ve4p53bX24=
+github.com/prometheus-community/pro-bing v0.4.0 h1:YMbv+i08gQz97OZZBwLyvmmQEEzyfyrrjEaAchdy3R4=
+github.com/prometheus-community/pro-bing v0.4.0/go.mod h1:b7wRYZtCcPmt4Sz319BykUU241rWLe1VFXyiyWK/dH4=
+github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
+github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
-github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
-github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
+github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
+github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
-github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
-github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
-github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
-github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
-github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc=
-github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU=
-github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
+github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
+github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
+github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
+github.com/rs/zerolog v1.30.0 h1:SymVODrcRsaRaSInD9yQtKbtWqwsfoPcRff/oRXLj4c=
+github.com/rs/zerolog v1.30.0/go.mod h1:/tk+P47gFdPXq4QYjvCmT5/Gsug2nagsFWBWhAiSi1w=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
-github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
-github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
-github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
-github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
-github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA=
+github.com/samber/lo v1.39.0/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
+github.com/samber/slog-common v0.16.0 h1:2/t1EcFd1Ru77mh2ab+8B6NBHnEXsBBHtOJc7PSH0aI=
+github.com/samber/slog-common v0.16.0/go.mod h1:Qjrfhwk79XiCIhBj8+jTq1Cr0u9rlWbjawh3dWXzaHk=
+github.com/samber/slog-zerolog/v2 v2.3.0 h1:s1OmSGQaAjQ/9C7lgEG2cro+jqw8Dl+ML05I3dFkJ50=
+github.com/samber/slog-zerolog/v2 v2.3.0/go.mod h1:wppqUvvyAa3OFW+Snn6x4v3Wf+aT1gSwh19T2CraIuE=
+github.com/shirou/gopsutil v2.21.11+incompatible h1:lOGOyCG67a5dv2hq5Z1BLDUqqKp3HkbjPcz5j6XMS0U=
+github.com/shirou/gopsutil v2.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
+github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
+github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
+github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
+github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=
+github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
-github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
-github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
-github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
-github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
-github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
+github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
-github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
-github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
+github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -372,24 +479,19 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
-github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
-github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
-github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
-github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
-github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
-github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
-github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
-github.com/urfave/cli/v2 v2.25.1 h1:zw8dSP7ghX0Gmm8vugrs6q9Ku0wzweqPyshy+syu9Gw=
-github.com/urfave/cli/v2 v2.25.1/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
-github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
-github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
-github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w=
-github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
-github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
-github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4=
+github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0=
+github.com/tklauser/numcpus v0.7.0 h1:yjuerZP127QG9m5Zh/mSO4wqurYil27tHrqwRoRjpr4=
+github.com/tklauser/numcpus v0.7.0/go.mod h1:bb6dMVcj8A42tSE7i32fsIUCbQNllK5iDguyOZRUzAY=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk=
+github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 h1:tHNk7XK9GkmKUR6Gh8gVBKXc2MVSZ4G/NnWLtzw4gNA=
+github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264=
+github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho=
+github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
github.com/vishvananda/netlink v1.2.1-beta.2.0.20230206183746-70ca0345eede h1:S+/0qI1RT0iW4moxdCoopW5JvXWU9pbJXM96IElhDF0=
github.com/vishvananda/netlink v1.2.1-beta.2.0.20230206183746-70ca0345eede/go.mod h1:cAAsePK2e15YDAMJNyOpGYEWNe4sIghTY7gpz4cX/Ik=
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
@@ -398,159 +500,225 @@ github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZla
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
-github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
-github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
-github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
-github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI=
-github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
-github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
-github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc=
+github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 h1:S2dVYn90KE98chqDkyE9Z4N61UnQd+KOfgp5Iu53llk=
+github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe9UDgpxAWQrhbbBXOYJFQDq/dtJw=
+github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk=
github.com/yuin/goldmark v1.1.27/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=
+github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
+github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
+github.com/yuyang0/libovsdb v0.0.0-20231222065958-6f259a987799 h1:pcGwcgtagBxYMRjkae/hJpofMQkMe58yCLWefqxFYsM=
+github.com/yuyang0/libovsdb v0.0.0-20231222065958-6f259a987799/go.mod h1:LC5DOvcY58jOG3HTvDyCVidoMJDurPeu+xlxv5Krd9Q=
+github.com/yuyang0/resource-bandwidth v0.0.0-20231102113253-8e47795c92e5 h1:qLiO9f8EufOBFDRtFfAn6zYndXlhmBJgOijfc9ipViU=
+github.com/yuyang0/resource-bandwidth v0.0.0-20231102113253-8e47795c92e5/go.mod h1:qq6SbQf88tieRqLkMzUgAoANLszQWdcH8H4Ji7xo2sE=
+github.com/yuyang0/resource-gpu v0.0.0-20231026065700-1577d804efa8 h1:U1GBBWRCG0kmo3XG3sI5pz0i4nMwjDsM92uxfOOc/1A=
+github.com/yuyang0/resource-gpu v0.0.0-20231026065700-1577d804efa8/go.mod h1:oggnae33QHkm9k2Xd0J4BFjdIV1VhPdpm4VUujYUvo0=
+github.com/yuyang0/resource-rbd v0.0.2-0.20230701090628-cb86da0f60b9 h1:2La8T7mqVy98jyAkwxIN9gB+Akx3qbLGmVEtleaxND4=
+github.com/yuyang0/resource-rbd v0.0.2-0.20230701090628-cb86da0f60b9/go.mod h1:ANjyr7r+YfKtpWiIsZPzF7+krI55Uf84R9AvbNr5WAg=
+github.com/yuyang0/vmimage v0.0.0-20240628091041-9f45a357a3ae h1:qsuhmk0vb2uNRdWsI+23DaOODto0/fG8tmEnqwHmjCA=
+github.com/yuyang0/vmimage v0.0.0-20240628091041-9f45a357a3ae/go.mod h1:sx0f5ijzfuwsxQnDlU8CpRbEzAoQu6TxpEKN6gozBAw=
go.etcd.io/etcd v3.3.27+incompatible h1:5hMrpf6REqTHV2LW2OclNpRtxI0k9ZplMemJsMSWju0=
go.etcd.io/etcd v3.3.27+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI=
-go.etcd.io/etcd/api/v3 v3.5.8 h1:Zf44zJszoU7zRV0X/nStPenegNXoFDWcB/MwrJbA+L4=
-go.etcd.io/etcd/api/v3 v3.5.8/go.mod h1:uyAal843mC8uUVSLWz6eHa/d971iDGnCRpmKd2Z+X8k=
-go.etcd.io/etcd/client/pkg/v3 v3.5.8 h1:tPp9YRn/UBFAHdhOQUII9eUs7aOK35eulpMhX4YBd+M=
-go.etcd.io/etcd/client/pkg/v3 v3.5.8/go.mod h1:y+CzeSmkMpWN2Jyu1npecjB9BBnABxGM4pN8cGuJeL4=
-go.etcd.io/etcd/client/v3 v3.5.8 h1:B6ngTKZSWWowHEoaucOKHQR/AtZKaoHLiUpWxOLG4l4=
-go.etcd.io/etcd/client/v3 v3.5.8/go.mod h1:idZYIPVkttBJBiRigkB5EM0MmEyx8jcl18zCV3F5noc=
+go.etcd.io/etcd/api/v3 v3.5.12 h1:W4sw5ZoU2Juc9gBWuLk5U6fHfNVyY1WC5g9uiXZio/c=
+go.etcd.io/etcd/api/v3 v3.5.12/go.mod h1:Ot+o0SWSyT6uHhA56al1oCED0JImsRiU9Dc26+C2a+4=
+go.etcd.io/etcd/client/pkg/v3 v3.5.12 h1:EYDL6pWwyOsylrQyLp2w+HkQ46ATiOvoEdMarindU2A=
+go.etcd.io/etcd/client/pkg/v3 v3.5.12/go.mod h1:seTzl2d9APP8R5Y2hFL3NVlD6qC/dOT+3kvrqPyTas4=
+go.etcd.io/etcd/client/v2 v2.305.12 h1:0m4ovXYo1CHaA/Mp3X/Fak5sRNIWf01wk/X1/G3sGKI=
+go.etcd.io/etcd/client/v2 v2.305.12/go.mod h1:aQ/yhsxMu+Oht1FOupSr60oBvcS9cKXHrzBpDsPTf9E=
+go.etcd.io/etcd/client/v3 v3.5.12 h1:v5lCPXn1pf1Uu3M4laUE2hp/geOTc5uPcYYsNe1lDxg=
+go.etcd.io/etcd/client/v3 v3.5.12/go.mod h1:tSbBCakoWmmddL+BKVAJHa9km+O/E+bumDe9mSbPiqw=
+go.etcd.io/etcd/pkg/v3 v3.5.12 h1:OK2fZKI5hX/+BTK76gXSTyZMrbnARyX9S643GenNGb8=
+go.etcd.io/etcd/pkg/v3 v3.5.12/go.mod h1:UVwg/QIMoJncyeb/YxvJBJCE/NEwtHWashqc8A1nj/M=
+go.etcd.io/etcd/raft/v3 v3.5.12 h1:7r22RufdDsq2z3STjoR7Msz6fYH8tmbkdheGfwJNRmU=
+go.etcd.io/etcd/raft/v3 v3.5.12/go.mod h1:ERQuZVe79PI6vcC3DlKBukDCLja/L7YMu29B74Iwj4U=
+go.etcd.io/etcd/server/v3 v3.5.12 h1:EtMjsbfyfkwZuA2JlKOiBfuGkFCekv5H178qjXypbG8=
+go.etcd.io/etcd/server/v3 v3.5.12/go.mod h1:axB0oCjMy+cemo5290/CutIjoxlfA6KVYKD1w0uue10=
+go.etcd.io/etcd/tests/v3 v3.5.12 h1:k1fG7+F87Z7zKp57EcjXu9XgOsW0sfp5USqfzmMTIwM=
+go.etcd.io/etcd/tests/v3 v3.5.12/go.mod h1:CLWdnlr8bWNa8tjkmKFybPz5Ldjh9GuHbYhq1g9vpIo=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0 h1:PzIubN4/sjByhDRHLviCjJuweBXWFZWhghjg7cS28+M=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0/go.mod h1:Ct6zzQEuGK3WpJs2n4dn+wfJYzd/+hNnxMRTWjGn30M=
+go.opentelemetry.io/otel v1.20.0 h1:vsb/ggIY+hUjD/zCAQHpzTmndPqv/ml2ArbsbfBYTAc=
+go.opentelemetry.io/otel v1.20.0/go.mod h1:oUIGj3D77RwJdM6PPZImDpSZGDvkD9fhesHny69JFrs=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0 h1:DeFD0VgTZ+Cj6hxravYYZE2W4GlneVH81iAOPjZkzk8=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0/go.mod h1:GijYcYmNpX1KazD5JmWGsi4P7dDTTTnfv1UbGn84MnU=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.20.0 h1:gvmNvqrPYovvyRmCSygkUDyL8lC5Tl845MLEwqpxhEU=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.20.0/go.mod h1:vNUq47TGFioo+ffTSnKNdob241vePmtNZnAODKapKd0=
+go.opentelemetry.io/otel/metric v1.20.0 h1:ZlrO8Hu9+GAhnepmRGhSU7/VkpjrNowxRN9GyKR4wzA=
+go.opentelemetry.io/otel/metric v1.20.0/go.mod h1:90DRw3nfK4D7Sm/75yQ00gTJxtkBxX+wu6YaNymbpVM=
+go.opentelemetry.io/otel/sdk v1.20.0 h1:5Jf6imeFZlZtKv9Qbo6qt2ZkmWtdWx/wzcCbNUlAWGM=
+go.opentelemetry.io/otel/sdk v1.20.0/go.mod h1:rmkSx1cZCm/tn16iWDn1GQbLtsW/LvsdEEFzCSRM6V0=
+go.opentelemetry.io/otel/trace v1.20.0 h1:+yxVAPZPbQhbC3OfAkeIVTky6iTFpcr4SiY9om7mXSQ=
+go.opentelemetry.io/otel/trace v1.20.0/go.mod h1:HJSK7F/hA5RlzpZ0zKDCHCDHm556LCDtKaAo6JmBFUU=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
+go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
+go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
+go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
-go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
-go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
+go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
+go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
+go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
+go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
+go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
-golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
-golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
-golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
-golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ=
-golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
+golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
+golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
+golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 h1:5llv2sWeaMSnA3w2kS57ouQQ4pudlXrR0dCgw51QK9o=
-golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
+golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME=
+golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
+golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
+golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
-golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
+golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
+golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
+golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g=
-golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4=
+golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY=
+golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
-golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
+golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
+golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201118182958-a01c418693c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220804214406-8e32c043e418/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
-golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
+golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
-golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
+golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
-golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
-golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
+golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
+golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
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=
-golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw=
+golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -559,28 +727,30 @@ golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230215201556-9c5414ab4bde h1:ybF7AMzI
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230215201556-9c5414ab4bde/go.mod h1:mQqgjkW8GQQcJQsbBvK890TKqUK1DfKWkuBGbOkuMHQ=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
-google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
-google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
+google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
-google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
-google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
+google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 h1:SeZZZx0cP0fqUyA+oRzP9k7cSwJlvDFiROO72uwD6i0=
+google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97/go.mod h1:t1VqOqqvce95G3hIDCT5FeO3YUc6Q4Oe24L/+rNMxRk=
+google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97 h1:W18sezcAYs+3tDZX4F80yctqa12jcP1PUS2gQu1zTPU=
+google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97/go.mod h1:iargEX0SFPm3xcfMI0d1domjg0ZF4Aa0p2awqyxhvF0=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 h1:6GQBEOdGkX6MMTLT9V+TjtIRZCw9VPD5Z+yHY9wMgS0=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97/go.mod h1:v7nGkzlmW8P3n/bKmWBn2WpBjpOEx8Q6gMueudAmKfY=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
-google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
-google.golang.org/grpc v1.54.1 h1:zQZQNqQZU9cHv2vLdDhB2mFeDZ2hGpgYM1A0PKjFsSM=
-google.golang.org/grpc v1.54.1/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
+google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU=
+google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -593,26 +763,27 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
-google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
+google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
-gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
gopkg.in/go-playground/validator.v9 v9.31.0 h1:bmXmP2RSNtFES+bn4uYuHT7iJFJv7Vj+an+ZQdDaD1M=
gopkg.in/go-playground/validator.v9 v9.31.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
-gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
-gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
+gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
+gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@@ -620,14 +791,17 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
-gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o=
+gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM=
+howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
k8s.io/api v0.26.3 h1:emf74GIQMTik01Aum9dPP0gAypL8JTLl/lHa4V9RFSU=
k8s.io/api v0.26.3/go.mod h1:PXsqwPMXBSBcL1lJ9CYDKy7kIReUydukS5JiRlxC3qE=
k8s.io/apimachinery v0.26.3 h1:dQx6PNETJ7nODU3XPtrwkfuubs6w7sX0M8n61zHIV/k=
@@ -640,7 +814,8 @@ k8s.io/kube-openapi v0.0.0-20230224204131-30e856af5c3e h1:Zs3X1UrbS0jrEPVOM8Y3xn
k8s.io/kube-openapi v0.0.0-20230224204131-30e856af5c3e/go.mod h1:y5VtZWM9sHHc2ZodIH/6SHzXj+TPU5USoA8lcIeKEKY=
k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk=
k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
-rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
+libvirt.org/go/libvirtxml v1.9004.0 h1:h+nhEZCABCnK4go0GLRN2WZhIhRrLAqsz84t553oiM4=
+libvirt.org/go/libvirtxml v1.9004.0/go.mod h1:7Oq2BLDstLr/XtoQD8Fr3mfDNrzlI3utYKySXF2xkng=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=
diff --git a/internal/debug/debug.go b/internal/debug/debug.go
new file mode 100644
index 0000000..e70c760
--- /dev/null
+++ b/internal/debug/debug.go
@@ -0,0 +1,24 @@
+package debug
+
+import (
+ "encoding/json"
+ "net/http"
+
+ "github.com/projecteru2/yavirt/internal/eru/resources"
+ "github.com/projecteru2/yavirt/internal/vmcache"
+)
+
+func Handler(w http.ResponseWriter, _ *http.Request) {
+ infos := vmcache.FetchDomainsInfo()
+ resp := map[string]any{
+ "infos": infos,
+ "gpu": map[string]any{
+ "capacity": resources.GetManager().FetchGPU(),
+ },
+ "cpumem": resources.GetManager().FetchCPUMem(),
+ }
+ bs, _ := json.Marshal(resp)
+ w.Header().Set("Content-Type", "application/json")
+
+ _, _ = w.Write(bs)
+}
diff --git a/internal/eru/agent/agent.go b/internal/eru/agent/agent.go
new file mode 100644
index 0000000..79c2984
--- /dev/null
+++ b/internal/eru/agent/agent.go
@@ -0,0 +1,156 @@
+package agent
+
+import (
+ "context"
+ "strings"
+ "sync"
+ "testing"
+ "time"
+
+ "github.com/alphadose/haxmap"
+ "github.com/cockroachdb/errors"
+ "github.com/patrickmn/go-cache"
+ "github.com/projecteru2/core/log"
+ corerpc "github.com/projecteru2/core/rpc"
+ "github.com/projecteru2/yavirt/internal/eru/common"
+ "github.com/projecteru2/yavirt/internal/eru/store"
+ corestore "github.com/projecteru2/yavirt/internal/eru/store/core"
+ storemocks "github.com/projecteru2/yavirt/internal/eru/store/mocks"
+ "github.com/projecteru2/yavirt/internal/eru/types"
+ "github.com/projecteru2/yavirt/internal/service"
+ "github.com/projecteru2/yavirt/internal/utils"
+ "google.golang.org/grpc/status"
+)
+
+type Manager struct {
+ svc service.Service
+ store store.Store
+ config *types.Config
+
+ checkWorkloadMutex *sync.Mutex
+ startingWorkloads *haxmap.Map[string, *utils.RetryTask]
+
+ // storeIdentifier indicates which eru this agent belongs to
+ // it can be used to identify the corresponding core
+ // and all containers that belong to this core
+ storeIdentifier string
+ cas *utils.GroupCAS
+ wrkStatusCache *cache.Cache
+
+ mCol *MetricsCollector
+}
+
+func NewManager(
+ ctx context.Context, svc service.Service,
+ config *types.Config, endpoint string,
+ t *testing.T,
+) (*Manager, error) {
+ logger := log.WithFunc("agent.NewManager")
+ interval := time.Duration(2*config.HealthCheck.Interval) * time.Second
+ m := &Manager{
+ config: config,
+ svc: svc,
+ cas: utils.NewGroupCAS(),
+ checkWorkloadMutex: &sync.Mutex{},
+ startingWorkloads: haxmap.New[string, *utils.RetryTask](),
+ wrkStatusCache: cache.New(interval, interval),
+ }
+ m.mCol = &MetricsCollector{
+ wrkStatusCache: m.wrkStatusCache,
+ }
+
+ if t == nil {
+ corestore.Init(ctx, config)
+ if m.store = corestore.Get(); m.store == nil {
+ return nil, common.ErrGetStoreFailed
+ }
+ } else {
+ m.store = storemocks.NewFakeStore()
+ }
+ labels := map[string]string{}
+ for _, label := range config.Labels {
+ parts := strings.Split(label, "=")
+ if len(parts) != 2 {
+ return nil, errors.Newf("invalid label %s", label)
+ }
+ labels[parts[0]] = parts[1]
+ }
+ go func() {
+ // Core need to connect to the local grpc server, so sleep 30s here to wait local grpc server up
+ time.Sleep(30 * time.Second)
+ // try to register current node to eru core
+ if _, err := m.store.AddNode(ctx, &types.AddNodeOpts{
+ Nodename: config.Hostname,
+ Endpoint: endpoint,
+ Podname: config.Podname,
+ Labels: labels,
+ }); err != nil {
+ e, ok := status.FromError(err)
+ if !ok {
+ logger.Error(ctx, err, "failed to add node")
+ return
+ }
+ if e.Code() == corerpc.AddNode && strings.Contains(e.Message(), "node already exists") {
+ logger.Infof(ctx, "node %s already exists", config.Hostname)
+ } else {
+ logger.Errorf(ctx, err, "failed to add node %s", config.Hostname)
+ }
+ }
+ // update node's labels if necessary
+ if len(labels) > 0 {
+ if _, err := m.store.SetNode(ctx, &types.SetNodeOpts{
+ Nodename: config.Hostname,
+ Labels: labels,
+ }); err != nil {
+ logger.Errorf(ctx, err, "failed to update node labels")
+ }
+ }
+ }()
+ m.storeIdentifier = m.store.GetIdentifier(ctx)
+ return m, nil
+}
+
+func (m *Manager) startNodeManager(ctx context.Context) {
+ log.WithFunc("startNodeManager").Info(ctx, "starting node status heartbeat")
+ _ = utils.Pool.Submit(func() { m.heartbeat(ctx) })
+}
+
+func (m *Manager) startWorkloadManager(ctx context.Context) {
+ log.WithFunc("startWorkloadManager").Info(ctx, "starting workload manager")
+ // start status watcher
+ _ = utils.Pool.Submit(func() { m.monitor(ctx) })
+
+ // start health check
+ _ = utils.Pool.Submit(func() { m.healthCheck(ctx) })
+}
+
+// Run runs a node manager
+func (m *Manager) Run(ctx context.Context) error {
+ logger := log.WithFunc("Run")
+
+ m.startNodeManager(ctx)
+ m.startWorkloadManager(ctx)
+
+ <-ctx.Done()
+ logger.Info(ctx, "exiting")
+ return nil
+}
+
+// Exit .
+func (m *Manager) Exit() error {
+ ctx := context.TODO()
+ logger := log.WithFunc("Exit").WithField("hostname", m.config.Hostname)
+ logger.Info(ctx, "remove node status")
+
+ // ctx is now canceled. use a new context.
+ var err error
+ utils.WithTimeout(ctx, m.config.GlobalConnectionTimeout, func(ctx context.Context) {
+ // remove node status
+ err = m.store.SetNodeStatus(ctx, -1)
+ })
+ if err != nil {
+ logger.Error(ctx, err, "failed to remove node status")
+ return err
+ }
+ return nil
+}
diff --git a/internal/eru/agent/agent_test.go b/internal/eru/agent/agent_test.go
new file mode 100644
index 0000000..4e33add
--- /dev/null
+++ b/internal/eru/agent/agent_test.go
@@ -0,0 +1,89 @@
+package agent
+
+import (
+ "context"
+ "sync"
+ "testing"
+ "time"
+
+ storemocks "github.com/projecteru2/yavirt/internal/eru/store/mocks"
+ "github.com/projecteru2/yavirt/internal/eru/types"
+ "github.com/projecteru2/yavirt/internal/service/mocks"
+ interutils "github.com/projecteru2/yavirt/internal/utils"
+ "github.com/projecteru2/yavirt/pkg/test/mock"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func newMockManager(t *testing.T) *Manager {
+ config := &types.Config{
+ Hostname: "fake",
+ HeartbeatInterval: 2,
+ CheckOnlyMine: false,
+ HealthCheck: types.HealthCheckConfig{
+ Interval: 10,
+ Timeout: 5,
+ CacheTTL: 300,
+ },
+ GlobalConnectionTimeout: 5 * time.Second,
+ }
+ svc := &mocks.Service{}
+
+ m, err := NewManager(context.Background(), svc, config, "", t)
+ assert.Nil(t, err)
+ return m
+}
+
+func TestRunNodeManager(t *testing.T) {
+ manager := newMockManager(t)
+ store := manager.store.(*storemocks.MockStore)
+ svc := manager.svc.(*mocks.Service)
+ svc.On("IsHealthy", mock.Anything).Return(true)
+
+ ctx, cancel := context.WithTimeout(context.Background(), time.Duration(manager.config.HeartbeatInterval*3)*time.Second)
+ defer cancel()
+
+ status, err := store.GetNodeStatus(ctx, "fake")
+ assert.Nil(t, err)
+ assert.Equal(t, status.Alive, false)
+
+ var wg sync.WaitGroup
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ time.Sleep(time.Duration(manager.config.HeartbeatInterval*2) * time.Second)
+ status, err := store.GetNodeStatus(ctx, "fake")
+ assert.Nil(t, err)
+ assert.Equal(t, status.Alive, true)
+ }()
+
+ manager.startNodeManager(ctx)
+
+ info, err := store.GetNode(ctx, "fake")
+ assert.Nil(t, err)
+ assert.Equal(t, info.Available, false)
+ wg.Wait()
+}
+
+func TestRunWorklaodManager(t *testing.T) {
+ manager := newMockManager(t)
+
+ watchers := interutils.NewWatchers()
+ wch, err := watchers.Get()
+ assert.Nil(t, err)
+ go watchers.Run(context.Background())
+ defer watchers.Stop()
+
+ store := manager.store.(*storemocks.MockStore)
+ svc := manager.svc.(*mocks.Service)
+ initSVC(svc)
+ // svc.On("VirtContext", mock.Anything).Return(nil)
+ svc.On("WatchGuestEvents", mock.Anything).Return(wch, nil)
+ ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
+ defer cancel()
+ manager.startWorkloadManager(ctx)
+
+ time.Sleep(2 * time.Second)
+
+ assertInitStatus(t, store)
+}
diff --git a/internal/eru/agent/guest.go b/internal/eru/agent/guest.go
new file mode 100644
index 0000000..acd52a7
--- /dev/null
+++ b/internal/eru/agent/guest.go
@@ -0,0 +1,129 @@
+package agent
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "sync"
+ "time"
+
+ "github.com/projecteru2/yavirt/internal/service"
+ "github.com/projecteru2/yavirt/internal/utils"
+
+ "github.com/projecteru2/core/log"
+ coreutils "github.com/projecteru2/core/utils"
+)
+
+// LabelMeta .
+const LabelMeta = "ERU_META"
+
+// HealthCheck .
+type HealthCheck struct {
+ TCPPorts []string
+ HTTPPort string
+ HTTPURL string
+ HTTPCode int
+ Cmds []string
+}
+
+type healthCheckMeta struct {
+ Publish []string
+ HealthCheck *HealthCheck
+}
+
+// Guest yavirt virtual machine
+type Guest struct {
+ ID string
+ Status string
+ TransitStatus string
+ CreateTime int64
+ TransitTime int64
+ UpdateTime int64
+ CPU int
+ Mem int64
+ Storage int64
+ ImageID int64
+ ImageName string
+ ImageUser string
+ Networks map[string]string
+ Labels map[string]string
+ IPs []string
+ Hostname string
+ Running bool
+ HealthCheck *HealthCheck
+
+ once sync.Once
+}
+
+// CheckHealth returns if the guest is healthy
+func (g *Guest) CheckHealth(ctx context.Context, svc service.Service, timeout time.Duration, enableDefaultChecker bool) bool {
+ logger := log.WithFunc("CheckHealth").WithField("ID", g.ID)
+ // init health check bridge
+ g.once.Do(func() {
+ if meta, ok := g.Labels[LabelMeta]; ok {
+ hcm := &healthCheckMeta{}
+ err := json.Unmarshal([]byte(meta), hcm)
+ if err != nil {
+ logger.Error(ctx, err, "invalid json format, guest %v, meta %v", g.ID, meta)
+ return
+ }
+ g.HealthCheck = hcm.HealthCheck
+ }
+ if enableDefaultChecker && g.HealthCheck == nil {
+ // add a default checker if not exist
+ g.HealthCheck = &HealthCheck{
+ Cmds: []string{"whoami"},
+ }
+ }
+ })
+
+ logger.Debugf(ctx, "[eru agent] guest %v\n health check: %v", g, g.HealthCheck)
+ if g.HealthCheck == nil {
+ return true
+ }
+
+ var tcpCheckers []string
+ var httpCheckers []string
+
+ healthCheck := g.HealthCheck
+
+ for _, port := range healthCheck.TCPPorts {
+ for _, ip := range g.IPs {
+ tcpCheckers = append(tcpCheckers, fmt.Sprintf("%s:%s", ip, port))
+ }
+ }
+ if healthCheck.HTTPPort != "" {
+ for _, ip := range g.IPs {
+ httpCheckers = append(httpCheckers, fmt.Sprintf("http://%s:%s%s", ip, healthCheck.HTTPPort, healthCheck.HTTPURL)) //nolint
+ }
+ }
+
+ f1 := utils.CheckHTTP(ctx, g.ID, httpCheckers, healthCheck.HTTPCode, timeout)
+ f2 := utils.CheckTCP(ctx, g.ID, tcpCheckers, timeout)
+ f3 := CheckCMD(ctx, svc, g.ID, healthCheck.Cmds, timeout)
+ return f1 && f2 && f3
+}
+
+func CheckCMD(ctx context.Context, svc service.Service, ID string, cmdList []string, timeout time.Duration) bool {
+ logger := log.WithFunc("CheckCMD").WithField("ID", ID)
+ ctx, cancel := context.WithTimeout(ctx, timeout)
+ defer cancel()
+
+ for _, cmdStr := range cmdList {
+ cmd := coreutils.MakeCommandLineArgs(cmdStr)
+ ans := true
+ utils.WithTimeout(ctx, timeout, func(ctx1 context.Context) {
+ msg, err := svc.ExecuteGuest(ctx1, ID, cmd)
+ if err != nil || msg.ExitCode != 0 {
+ log.Warnf(ctx, "[checkHealth] guest %s execute cmd %s failed (err: %s, msg: %v)", ID, cmdStr, err, msg)
+ ans = false
+ return
+ }
+ logger.Debugf(ctx, "[checkHealth] guest %s execute cmd %s success, output: %v", ID, cmdStr, string(msg.Data))
+ })
+ if !ans {
+ return ans
+ }
+ }
+ return true
+}
diff --git a/internal/eru/agent/metrics.go b/internal/eru/agent/metrics.go
new file mode 100644
index 0000000..ff816b3
--- /dev/null
+++ b/internal/eru/agent/metrics.go
@@ -0,0 +1,83 @@
+package agent
+
+import (
+ "context"
+ "sync/atomic"
+
+ "github.com/patrickmn/go-cache"
+ "github.com/projecteru2/core/log"
+ "github.com/projecteru2/core/utils"
+ virttypes "github.com/projecteru2/libyavirt/types"
+ "github.com/projecteru2/yavirt/configs"
+ "github.com/projecteru2/yavirt/internal/eru/types"
+ "github.com/projecteru2/yavirt/internal/vmcache"
+ "github.com/prometheus/client_golang/prometheus"
+)
+
+var (
+ vmHealthyDesc = prometheus.NewDesc(
+ prometheus.BuildFQName("vm", "", "healthy"),
+ "VM healthy status.",
+ []string{"EruID", "node", "app_id", "app_sid", "appname", "ip"},
+ nil)
+ coreHealthyDesc = prometheus.NewDesc(
+ prometheus.BuildFQName("node", "core", "healthy"),
+ "core healthy status.",
+ []string{"node"},
+ nil)
+)
+
+type MetricsCollector struct {
+ wrkStatusCache *cache.Cache
+ coreHealthy atomic.Bool
+}
+
+func (mgr *Manager) GetMetricsCollector() *MetricsCollector {
+ return mgr.mCol
+}
+
+func (e *MetricsCollector) Describe(ch chan<- *prometheus.Desc) {
+ ch <- vmHealthyDesc
+ ch <- coreHealthyDesc
+}
+
+func (e *MetricsCollector) Collect(ch chan<- prometheus.Metric) {
+ logger := log.WithFunc("agent.MetricsCollector.Collect")
+ for _, v := range e.wrkStatusCache.Items() {
+ wrkStatus, _ := v.Object.(*types.WorkloadStatus)
+ if wrkStatus == nil {
+ logger.Warnf(context.TODO(), "[BUG] wrkStatus can't be nil here")
+ continue
+ }
+ if !wrkStatus.Running {
+ continue
+ }
+ de := vmcache.FetchDomainEntry(wrkStatus.ID)
+ if de == nil {
+ logger.Warnf(context.TODO(), "[eru agent] failed to get domain entry %s", wrkStatus.ID)
+ continue
+ }
+ healthy := 0
+ if wrkStatus.Healthy {
+ healthy = 1
+ }
+ ch <- prometheus.MustNewConstMetric(
+ vmHealthyDesc,
+ prometheus.GaugeValue,
+ float64(healthy),
+ virttypes.EruID(wrkStatus.ID),
+ wrkStatus.Nodename,
+ de.AppID,
+ de.AppSID,
+ de.AppName,
+ de.IP,
+ )
+ }
+
+ ch <- prometheus.MustNewConstMetric(
+ coreHealthyDesc,
+ prometheus.GaugeValue,
+ float64(utils.Bool2Int(e.coreHealthy.Load())),
+ configs.Hostname(),
+ )
+}
diff --git a/internal/eru/agent/monitor.go b/internal/eru/agent/monitor.go
new file mode 100644
index 0000000..cbdba7d
--- /dev/null
+++ b/internal/eru/agent/monitor.go
@@ -0,0 +1,121 @@
+package agent
+
+import (
+ "context"
+ "time"
+
+ "github.com/projecteru2/yavirt/internal/eru/common"
+ intertypes "github.com/projecteru2/yavirt/internal/types"
+ "github.com/projecteru2/yavirt/internal/utils"
+
+ "github.com/projecteru2/core/log"
+)
+
+func (m *Manager) initMonitor(ctx context.Context) (err error) {
+ watcher, err := m.svc.WatchGuestEvents(ctx)
+ if err != nil {
+ return err
+ }
+ logger := log.WithFunc("initMonitor")
+ defer logger.Infof(ctx, "events goroutine has done")
+ defer watcher.Stop()
+
+ for {
+ select {
+ case event := <-watcher.Events():
+ // don't block here
+ _ = utils.Pool.Submit(func() {
+ switch event.Op {
+ case intertypes.StartOp:
+ m.handleWorkloadStart(ctx, event.ID)
+ case intertypes.DieOp:
+ m.handleWorkloadDie(ctx, event.ID)
+ }
+ })
+ case <-watcher.Done():
+ // The watcher already has been stopped.
+ logger.Infof(ctx, "watcher has done")
+ return nil
+
+ case <-ctx.Done():
+ logger.Infof(ctx, "ctx done")
+ return nil
+ }
+ }
+}
+
+// monitor with retry
+func (m *Manager) monitor(ctx context.Context) {
+ logger := log.WithFunc("monitor")
+ for {
+ select {
+ case <-ctx.Done():
+ logger.Info(ctx, "context canceled, stop monitoring")
+ return
+ default:
+ if err := m.initMonitor(ctx); err != nil {
+ logger.Error(ctx, err, "received an err, will retry")
+ }
+ time.Sleep(m.config.GlobalConnectionTimeout)
+ }
+ }
+}
+
+// 检查一个workload,允许重试
+func (m *Manager) checkOneWorkloadWithBackoffRetry(ctx context.Context, ID string) {
+ logger := log.WithFunc("checkOneWorkloadWithBackoffRetry").WithField("ID", ID)
+ logger.Debug(ctx, "check workload")
+
+ m.checkWorkloadMutex.Lock()
+ defer m.checkWorkloadMutex.Unlock()
+
+ if retryTask, ok := m.startingWorkloads.Get(ID); ok {
+ retryTask.Stop(ctx)
+ }
+
+ retryTask := utils.NewRetryTask(ctx, utils.GetMaxAttemptsByTTL(m.config.GetHealthCheckStatusTTL()), func() error {
+ if !m.checkOneWorkload(ctx, ID) {
+ // 这个err就是用来判断要不要继续的,不用打在日志里
+ return common.ErrWorkloadUnhealthy
+ }
+ return nil
+ })
+ m.startingWorkloads.Set(ID, retryTask)
+ _ = utils.Pool.Submit(func() {
+ if err := retryTask.Run(ctx); err != nil {
+ logger.Debug(ctx, "workload still not healthy")
+ }
+ })
+}
+
+func (m *Manager) handleWorkloadStart(ctx context.Context, ID string) {
+ logger := log.WithFunc("handleWorkloadStart").WithField("ID", ID)
+ logger.Debug(ctx, "workload start")
+ workloadStatus, err := m.GetStatus(ctx, ID, true)
+ if err != nil {
+ logger.Warnf(ctx, "faild to get workload status: %s", err)
+ return
+ }
+
+ if workloadStatus.Healthy {
+ if err := m.store.SetWorkloadStatus(ctx, workloadStatus, m.config.GetHealthCheckStatusTTL()); err != nil {
+ logger.Warnf(ctx, "failed to update deploy status: %s", err)
+ }
+ } else {
+ m.checkOneWorkloadWithBackoffRetry(ctx, ID)
+ }
+}
+
+func (m *Manager) handleWorkloadDie(ctx context.Context, ID string) {
+ logger := log.WithFunc("handleWorkloadDie").WithField("ID", ID)
+ logger.Debug(ctx, "wrokload die")
+ workloadStatus, err := m.GetStatus(ctx, ID, true)
+ if err != nil {
+ logger.Warnf(ctx, "faild to get workload status: %s", err)
+ return
+ }
+
+ if err := m.store.SetWorkloadStatus(ctx, workloadStatus, m.config.GetHealthCheckStatusTTL()); err != nil {
+ logger.Warnf(ctx, "failed to update deploy status: %s", err)
+ }
+}
diff --git a/internal/eru/agent/monitor_test.go b/internal/eru/agent/monitor_test.go
new file mode 100644
index 0000000..2b65696
--- /dev/null
+++ b/internal/eru/agent/monitor_test.go
@@ -0,0 +1,101 @@
+package agent
+
+import (
+ "context"
+ "testing"
+ "time"
+
+ virttypes "github.com/projecteru2/libyavirt/types"
+ storemocks "github.com/projecteru2/yavirt/internal/eru/store/mocks"
+ "github.com/projecteru2/yavirt/internal/eru/types"
+ "github.com/projecteru2/yavirt/internal/service/mocks"
+ intertypes "github.com/projecteru2/yavirt/internal/types"
+ interutils "github.com/projecteru2/yavirt/internal/utils"
+ "github.com/projecteru2/yavirt/pkg/test/mock"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestMonitor(t *testing.T) {
+ manager := newMockManager(t)
+
+ watchers := interutils.NewWatchers()
+ wch, err := watchers.Get()
+ assert.Nil(t, err)
+ go watchers.Run(context.Background())
+ defer watchers.Stop()
+
+ store := manager.store.(*storemocks.MockStore)
+ svc := manager.svc.(*mocks.Service)
+
+ svc.On("VirtContext", mock.Anything).Return(nil)
+ svc.On("WatchGuestEvents", mock.Anything).Return(wch, nil).Once()
+
+ assert.Nil(t, store.GetMockWorkloadStatus("00033017009174384208170000000001"))
+ assert.Nil(t, store.GetMockWorkloadStatus("00033017009174384208170000000002"))
+
+ // stop "00033017009174384208170000000001"
+ svc.On("GetGuest", mock.Anything, "00033017009174384208170000000001").Return(&virttypes.Guest{
+ Resource: virttypes.Resource{
+ ID: "00033017009174384208170000000001",
+ },
+ Labels: map[string]string{"ERU": "1"},
+ Running: false,
+ }, nil)
+
+ // svc.On("ExecuteGuest", mock.Anything, mock.Anything, mock.Anything).Return(&virttypes.ExecuteGuestMessage{}, nil)
+ watchers.Watched(intertypes.Event{
+ ID: "00033017009174384208170000000001",
+ Op: "die",
+ })
+
+ // start monitor and wait for a while, then exit
+ ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
+ go manager.initMonitor(ctx)
+ time.Sleep(2 * time.Second)
+ cancel()
+
+ assert.Equal(t, store.GetMockWorkloadStatus("00033017009174384208170000000001"), &types.WorkloadStatus{
+ ID: "00033017009174384208170000000001",
+ Nodename: "fake",
+ Extension: []byte(`{"ERU":"1"}`),
+ Running: false,
+ Healthy: false,
+ })
+
+ // start "00033017009174384208170000000002"
+ wch2, err := watchers.Get()
+ assert.Nil(t, err)
+ svc.On("WatchGuestEvents", mock.Anything).Return(wch2, nil).Once()
+
+ svc.On("GetGuest", mock.Anything, "00033017009174384208170000000002").Return(&virttypes.Guest{
+ Resource: virttypes.Resource{
+ ID: "00033017009174384208170000000002",
+ },
+ Labels: map[string]string{"ERU": "1"},
+ Running: true,
+ }, nil)
+ watchers.Watched(intertypes.Event{
+ ID: "00033017009174384208170000000002",
+ Op: "start",
+ })
+
+ ctx, cancel = context.WithTimeout(context.Background(), time.Second*30)
+ go manager.initMonitor(ctx)
+ time.Sleep(2 * time.Second)
+ cancel()
+
+ assert.Equal(t, store.GetMockWorkloadStatus("00033017009174384208170000000001"), &types.WorkloadStatus{
+ ID: "00033017009174384208170000000001",
+ Nodename: "fake",
+ Extension: []byte(`{"ERU":"1"}`),
+ Running: false,
+ Healthy: false,
+ })
+ time.Sleep(1 * time.Second)
+
+ // initMonotr already stopped watcher and send an empty event,
+ // so watchers got an chance to delete watcher
+ watchers.Watched(intertypes.Event{})
+ time.Sleep(1 * time.Second)
+ assert.Zero(t, watchers.Len())
+}
diff --git a/internal/eru/agent/node.go b/internal/eru/agent/node.go
new file mode 100644
index 0000000..0e3aae5
--- /dev/null
+++ b/internal/eru/agent/node.go
@@ -0,0 +1,62 @@
+package agent
+
+import (
+ "context"
+ "time"
+
+ "github.com/projecteru2/core/log"
+ "github.com/projecteru2/yavirt/internal/utils"
+)
+
+// heartbeat creates a new goroutine to report status every HeartbeatInterval seconds
+// By default HeartbeatInterval is 0, will not do heartbeat.
+func (m *Manager) heartbeat(ctx context.Context) {
+ if m.config.HeartbeatInterval <= 0 {
+ return
+ }
+ _ = utils.Pool.Submit(func() { m.nodeStatusReport(ctx) })
+
+ tick := time.NewTicker(time.Duration(m.config.HeartbeatInterval) * time.Second)
+ defer tick.Stop()
+
+ for {
+ select {
+ case <-tick.C:
+ _ = utils.Pool.Submit(func() { m.nodeStatusReport(ctx) })
+ case <-ctx.Done():
+ return
+ }
+ }
+}
+
+// nodeStatusReport does heartbeat, tells core this node is alive.
+// The TTL is set to double of HeartbeatInterval, by default it will be 360s,
+// which means if a node is not available, subcriber will notice this after at least 360s.
+// HealthCheck.Timeout is used as timeout of requesting core Profile
+func (m *Manager) nodeStatusReport(ctx context.Context) {
+ logger := log.WithFunc("nodeStatusReport").WithField("hostname", m.config.Hostname)
+ logger.Debug(ctx, "report begins")
+ defer logger.Debug(ctx, "report ends")
+ if !m.svc.IsHealthy(ctx) {
+ logger.Warn(ctx, "service is not healthy")
+ return
+ }
+ if err := m.store.CheckHealth(ctx); err != nil {
+ logger.Error(ctx, err, "failed to check health of core")
+ m.mCol.coreHealthy.Store(false)
+ } else {
+ m.mCol.coreHealthy.Store(true)
+ }
+ ttl := int64(m.config.HeartbeatInterval * 3)
+
+ if err := utils.BackoffRetry(ctx, 3, func() (err error) {
+ utils.WithTimeout(ctx, m.config.GlobalConnectionTimeout, func(ctx context.Context) {
+ if err = m.store.SetNodeStatus(ctx, ttl); err != nil {
+ logger.Error(ctx, err, "failed to set node status")
+ }
+ })
+ return err
+ }); err != nil {
+ logger.Error(ctx, err, "failed to set node status for 3 times")
+ }
+}
diff --git a/internal/eru/agent/node_test.go b/internal/eru/agent/node_test.go
new file mode 100644
index 0000000..7d153fc
--- /dev/null
+++ b/internal/eru/agent/node_test.go
@@ -0,0 +1,51 @@
+package agent
+
+import (
+ "context"
+ "testing"
+ "time"
+
+ storemocks "github.com/projecteru2/yavirt/internal/eru/store/mocks"
+ "github.com/projecteru2/yavirt/internal/service/mocks"
+ "github.com/projecteru2/yavirt/pkg/test/mock"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestNodeStatusReport(t *testing.T) {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ manager := newMockManager(t)
+ store := manager.store.(*storemocks.MockStore)
+ svc := manager.svc.(*mocks.Service)
+ svc.On("IsHealthy", mock.Anything).Return(true)
+
+ status, err := store.GetNodeStatus(ctx, "fake")
+ assert.Nil(t, err)
+ assert.Equal(t, status.Alive, false)
+
+ manager.nodeStatusReport(ctx)
+ status, err = store.GetNodeStatus(ctx, "fake")
+ assert.Nil(t, err)
+ assert.Equal(t, status.Alive, true)
+}
+
+func TestHeartbeat(t *testing.T) {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ manager := newMockManager(t)
+ store := manager.store.(*storemocks.MockStore)
+ svc := manager.svc.(*mocks.Service)
+ svc.On("IsHealthy", mock.Anything).Return(true)
+
+ status, err := store.GetNodeStatus(ctx, "fake")
+ assert.Nil(t, err)
+ assert.Equal(t, status.Alive, false)
+
+ go manager.heartbeat(ctx)
+
+ time.Sleep(time.Duration(manager.config.HeartbeatInterval+2) * time.Second)
+ status, err = store.GetNodeStatus(ctx, "fake")
+ assert.Nil(t, err)
+ assert.Equal(t, status.Alive, true)
+}
diff --git a/internal/eru/agent/workload.go b/internal/eru/agent/workload.go
new file mode 100644
index 0000000..a57b26b
--- /dev/null
+++ b/internal/eru/agent/workload.go
@@ -0,0 +1,171 @@
+package agent
+
+import (
+ "context"
+ "encoding/json"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/projecteru2/yavirt/internal/eru/common"
+ "github.com/projecteru2/yavirt/internal/eru/types"
+ "github.com/projecteru2/yavirt/internal/utils"
+
+ "github.com/projecteru2/core/cluster"
+ "github.com/projecteru2/core/log"
+ yavirttypes "github.com/projecteru2/libyavirt/types"
+)
+
+func (m *Manager) ListWorkloadIDs(ctx context.Context) (ids []string, err error) {
+ utils.WithTimeout(ctx, m.config.GlobalConnectionTimeout, func(ctx context.Context) {
+ ids, err = m.svc.GetGuestIDList(ctx)
+ })
+ if err != nil && !strings.Contains(err.Error(), "key not exists") {
+ log.WithFunc("ListWorkloadIDs").Error(ctx, err, "failed to get workload ids")
+ return nil, err
+ }
+ return ids, nil
+}
+
+func (m *Manager) detectWorkload(ctx context.Context, ID string) (*Guest, error) {
+ logger := log.WithFunc("detectWorkload").WithField("ID", ID)
+
+ var guest *yavirttypes.Guest
+ var err error
+
+ utils.WithTimeout(ctx, m.config.GlobalConnectionTimeout, func(ctx context.Context) {
+ guest, err = m.svc.GetGuest(ctx, ID)
+ })
+
+ if err != nil {
+ logger.Error(ctx, err, "failed to detect workload")
+ return nil, err
+ }
+
+ if _, ok := guest.Labels[cluster.ERUMark]; !ok {
+ return nil, common.ErrInvaildVM
+ }
+
+ if m.config.CheckOnlyMine && m.config.Hostname != guest.Hostname {
+ logger.Debugf(ctx, "guest's hostname is %s instead of %s", guest.Hostname, m.config.Hostname)
+ return nil, common.ErrInvaildVM
+ }
+
+ return &Guest{
+ ID: guest.ID,
+ Status: guest.Status,
+ TransitStatus: guest.TransitStatus,
+ CreateTime: guest.CreateTime,
+ TransitTime: guest.TransitTime,
+ UpdateTime: guest.UpdateTime,
+ CPU: guest.CPU,
+ Mem: guest.Mem,
+ Storage: guest.Storage,
+ ImageID: guest.ImageID,
+ ImageName: guest.ImageName,
+ ImageUser: guest.ImageUser,
+ Networks: guest.Networks,
+ Labels: guest.Labels,
+ IPs: guest.IPs,
+ Hostname: guest.Hostname,
+ Running: guest.Running,
+ once: sync.Once{},
+ }, nil
+}
+
+// GetStatus checks workload's status first, then returns workload status
+func (m *Manager) GetStatus(ctx context.Context, ID string, checkHealth bool) (*types.WorkloadStatus, error) {
+ logger := log.WithFunc("GetStatus").WithField("ID", ID)
+ guest, err := m.detectWorkload(ctx, ID)
+ if err != nil {
+ logger.Error(ctx, err, "failed to get guest status")
+ return nil, err
+ }
+
+ bytes, err := json.Marshal(guest.Labels)
+ if err != nil {
+ logger.Error(ctx, err, "failed to marshal labels")
+ return nil, err
+ }
+
+ status := &types.WorkloadStatus{
+ ID: guest.ID,
+ Running: guest.Running,
+ Healthy: guest.Running && guest.HealthCheck == nil,
+ Networks: guest.Networks,
+ Extension: bytes,
+ Nodename: m.config.Hostname,
+ }
+
+ if checkHealth && guest.Running {
+ free, acquired := m.cas.Acquire(guest.ID)
+ if !acquired {
+ return nil, common.ErrGetLockFailed
+ }
+ defer free()
+ timeout := time.Duration(m.config.HealthCheck.Timeout) * time.Second
+ status.Healthy = guest.CheckHealth(ctx, m.svc, timeout, m.config.HealthCheck.EnableDefaultChecker)
+ }
+
+ return status, nil
+}
+
+func (m *Manager) healthCheck(ctx context.Context) {
+ tick := time.NewTicker(time.Duration(m.config.HealthCheck.Interval) * time.Second)
+ defer tick.Stop()
+
+ _ = utils.Pool.Submit(func() { m.checkAllWorkloads(ctx) })
+
+ for {
+ select {
+ case <-tick.C:
+ _ = utils.Pool.Submit(func() { m.checkAllWorkloads(ctx) })
+ case <-ctx.Done():
+ return
+ }
+ }
+}
+
+// 检查全部 label 为ERU=1的workload
+// 这里需要 list all,原因是 monitor 检测到 die 的时候已经标记为 false 了
+// 但是这时候 health check 刚返回 true 回来并写入 core
+// 为了保证最终数据一致性这里也要检测
+func (m *Manager) checkAllWorkloads(ctx context.Context) {
+ logger := log.WithFunc("checkAllWorkloads")
+ logger.Debug(ctx, "health check begin")
+ workloadIDs, err := m.ListWorkloadIDs(ctx)
+ if err != nil {
+ logger.Error(ctx, err, "error when list all workloads with label \"ERU=1\"")
+ return
+ }
+
+ for idx := range workloadIDs {
+ wrkID := workloadIDs[idx]
+ _ = utils.Pool.Submit(func() { m.checkOneWorkload(ctx, wrkID) })
+ }
+}
+
+// 检查并保存一个workload的状态,最后返回workload是否healthy。
+// 返回healthy是为了重试用的,没啥别的意义。
+func (m *Manager) checkOneWorkload(ctx context.Context, ID string) bool {
+ logger := log.WithFunc("checkOneWorkload").WithField("ID", ID)
+ workloadStatus, err := m.GetStatus(ctx, ID, true)
+ if err != nil {
+ logger.Error(ctx, err, "failed to get status of workload")
+ return false
+ }
+
+ m.wrkStatusCache.Set(workloadStatus.ID, workloadStatus, 0)
+
+ if err := m.setWorkloadStatus(ctx, workloadStatus); err != nil {
+ logger.Error(ctx, err, "update workload status failed")
+ }
+ return workloadStatus.Healthy
+}
+
+// 设置workload状态,允许重试,带timeout控制
+func (m *Manager) setWorkloadStatus(ctx context.Context, status *types.WorkloadStatus) error {
+ return utils.BackoffRetry(ctx, 3, func() error {
+ return m.store.SetWorkloadStatus(ctx, status, m.config.GetHealthCheckStatusTTL())
+ })
+}
diff --git a/internal/eru/agent/workload_test.go b/internal/eru/agent/workload_test.go
new file mode 100644
index 0000000..f9fc511
--- /dev/null
+++ b/internal/eru/agent/workload_test.go
@@ -0,0 +1,64 @@
+package agent
+
+import (
+ "context"
+ "testing"
+ "time"
+
+ storemocks "github.com/projecteru2/yavirt/internal/eru/store/mocks"
+ "github.com/projecteru2/yavirt/internal/eru/types"
+ "github.com/projecteru2/yavirt/internal/service/mocks"
+ "github.com/projecteru2/yavirt/pkg/test/mock"
+ "github.com/stretchr/testify/assert"
+
+ virttypes "github.com/projecteru2/libyavirt/types"
+)
+
+func assertInitStatus(t *testing.T, store *storemocks.MockStore) {
+ assert.Equal(t, store.GetMockWorkloadStatus("00033017009174384208170000000001"), &types.WorkloadStatus{
+ ID: "00033017009174384208170000000001",
+ Nodename: "fake",
+ Extension: []byte(`{"ERU":"1"}`),
+ Running: true,
+ Healthy: true,
+ })
+
+ assert.Equal(t, store.GetMockWorkloadStatus("00033017009174384208170000000002"), &types.WorkloadStatus{
+ ID: "00033017009174384208170000000002",
+ Nodename: "fake",
+ Extension: []byte(`{"ERU":"1"}`),
+ Running: false,
+ Healthy: false,
+ })
+}
+
+func initSVC(svc *mocks.Service) {
+ svc.On("VirtContext", mock.Anything).Return(nil)
+ svc.On("GetGuestIDList", mock.Anything).Return([]string{"00033017009174384208170000000001", "00033017009174384208170000000002"}, nil)
+ svc.On("GetGuest", mock.Anything, "00033017009174384208170000000001").Return(&virttypes.Guest{
+ Resource: virttypes.Resource{
+ ID: "00033017009174384208170000000001",
+ },
+ Labels: map[string]string{"ERU": "1"},
+ Running: true,
+ }, nil)
+ svc.On("GetGuest", mock.Anything, "00033017009174384208170000000002").Return(&virttypes.Guest{
+ Resource: virttypes.Resource{
+ ID: "00033017009174384208170000000002",
+ },
+ Labels: map[string]string{"ERU": "1"},
+ Running: false,
+ }, nil)
+}
+func TestHealthCheck(t *testing.T) {
+ manager := newMockManager(t)
+ svc := manager.svc.(*mocks.Service)
+ initSVC(svc)
+
+ ctx := context.Background()
+ manager.checkAllWorkloads(ctx)
+ store := manager.store.(*storemocks.MockStore)
+ time.Sleep(2 * time.Second)
+
+ assertInitStatus(t, store)
+}
diff --git a/internal/eru/common/error.go b/internal/eru/common/error.go
new file mode 100644
index 0000000..1374971
--- /dev/null
+++ b/internal/eru/common/error.go
@@ -0,0 +1,36 @@
+package common
+
+import "github.com/pkg/errors"
+
+// ErrNotImplemented .
+var (
+ ErrNotImplemented = errors.New("not implemented")
+ // ErrConnecting means writer is in connecting status, waiting to be connected
+ ErrConnecting = errors.New("connecting")
+ // ErrInvalidScheme .
+ ErrInvalidScheme = errors.New("invalid scheme")
+ // ErrGetRuntimeFailed .
+ ErrGetRuntimeFailed = errors.New("failed to get runtime client")
+ // ErrInvalidRuntimeType .
+ ErrInvalidRuntimeType = errors.New("unknown runtime type")
+ // ErrGetStoreFailed .
+ ErrGetStoreFailed = errors.New("failed to get store client")
+ // ErrInvalidStoreType .
+ ErrInvalidStoreType = errors.New("unknown store type")
+ // ErrWorkloadUnhealthy .
+ ErrWorkloadUnhealthy = errors.New("not healthy")
+ // ErrClosedSteam .
+ ErrClosedSteam = errors.New("closed")
+ // ErrSyscallFailed .
+ ErrSyscallFailed = errors.New("syscall fail, Not a syscall.Stat_t")
+ // ErrDevNotFound .
+ ErrDevNotFound = errors.New("device not found")
+ // ErrJournalDisable .
+ ErrJournalDisable = errors.New("journal disabled")
+ // ErrInvaildContainer .
+ ErrInvaildContainer = errors.New("invaild container")
+ // ErrGetLockFailed .
+ ErrGetLockFailed = errors.New("get lock failed")
+ // ErrInvaildVM .
+ ErrInvaildVM = errors.New("invaild vm")
+)
diff --git a/internal/eru/recycle/recycle.go b/internal/eru/recycle/recycle.go
new file mode 100644
index 0000000..14a448b
--- /dev/null
+++ b/internal/eru/recycle/recycle.go
@@ -0,0 +1,155 @@
+package recycle
+
+import (
+ "context"
+ "fmt"
+ "strings"
+ "testing"
+ "time"
+
+ "github.com/pkg/errors"
+ "github.com/projecteru2/core/log"
+ corerpc "github.com/projecteru2/core/rpc"
+ virttypes "github.com/projecteru2/libyavirt/types"
+ "github.com/projecteru2/yavirt/configs"
+ "github.com/projecteru2/yavirt/internal/eru/common"
+ "github.com/projecteru2/yavirt/internal/eru/store"
+ corestore "github.com/projecteru2/yavirt/internal/eru/store/core"
+ storemocks "github.com/projecteru2/yavirt/internal/eru/store/mocks"
+ "github.com/projecteru2/yavirt/internal/eru/types"
+ "github.com/projecteru2/yavirt/internal/service"
+ "github.com/projecteru2/yavirt/internal/utils"
+ "github.com/projecteru2/yavirt/pkg/notify/bison"
+ "github.com/samber/lo"
+ "google.golang.org/grpc/status"
+)
+
+var (
+ interval = 1 * time.Minute
+ deleteWait = 15 * time.Second
+ stor store.Store
+)
+
+func fetchWorkloads() ([]string, error) {
+ ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+ defer cancel()
+ wrks, err := stor.ListNodeWorkloads(ctx, configs.Hostname())
+ if err != nil {
+ return nil, err
+ }
+ ids := lo.Map(wrks, func(w *types.Workload, _ int) string {
+ return w.ID
+ })
+ return ids, nil
+}
+
+func deleteGuest(svc service.Service, eruID string) error {
+ logger := log.WithFunc("deleteGuest")
+ // when core delete a workload, it will delete the record in etcd first and then delete the workload
+ // so there is a time window in which the guest is a dangling guest, so we wait for a while and wait the deletion finished
+ // TODO better way to detect if a guest is in deletion
+ time.Sleep(deleteWait)
+
+ ctx, cancel := context.WithTimeout(context.TODO(), 30*time.Second)
+ defer cancel()
+ logger.Infof(ctx, "[recycle] start to remove dangling guest %s", eruID)
+ // since guest deletion is a dangerous operation here,
+ // so we check eru again
+ wrk, err := stor.GetWorkload(ctx, eruID)
+ logger.Infof(ctx, "[recycle] guest %s, wrk: %v, err: %v", eruID, wrk, err)
+ if err == nil {
+ logger.Errorf(ctx, err, "[recycle] BUG: dangling guest %s is still in eru", eruID)
+ return errors.Errorf("BUG: dangling guest %s is still in eru", eruID)
+ }
+
+ e, ok := status.FromError(err)
+ if !ok {
+ return err
+ }
+ if e.Code() == corerpc.GetWorkload && strings.Contains(e.Message(), "entity count invalid") { //nolint
+ logger.Infof(ctx, "[recycle] start to remove local guest %s", eruID)
+ // When creating a guest, the core first creates the workload and then creates a record in ETCD.
+ // Therefore, within the time window between these two operations, we may incorrectly detect dangling guests.
+ // To prevent this situation, we create a creation session locker when creating a guest and check this locker here.
+ flck := utils.NewCreateSessionFlock(utils.VirtID(eruID))
+ if flck.FileExists() {
+ // creation session locker file exists
+ // it means this guest is in creation
+ logger.Warnf(ctx, "[recycle] guest %s in creation", eruID)
+ return fmt.Errorf("guest %s is in creation", eruID)
+ }
+
+ if err := svc.ControlGuest(ctx, utils.VirtID(eruID), virttypes.OpDestroy, true); err != nil {
+ logger.Errorf(ctx, err, "[recycle] failed to remove dangling guest %s", eruID)
+ return err
+ }
+ notifier := bison.GetService()
+ log.Debugf(ctx, "[recycle] notifier: %v", notifier)
+ if notifier != nil {
+ text := fmt.Sprintf(`
+delete dangling guest successfully
+---
+
+- **node:** %s
+- **id:** %s
+ `, configs.Hostname(), eruID)
+ if err := notifier.SendMarkdown(context.TODO(), "delete dangling guest", text); err != nil {
+ logger.Warnf(ctx, "[recycle] failed to send dingtalk message: %v", err)
+ }
+ }
+ return nil
+ }
+
+ return err
+}
+
+func startLoop(ctx context.Context, svc service.Service) {
+ logger := log.WithFunc("startLoop")
+ logger.Info(ctx, "[recycle] starting recycle loop")
+ defer logger.Info(ctx, "[recycle] recycle loop stopped")
+
+ for {
+ select {
+ case <-ctx.Done():
+ return
+ case <-time.After(interval):
+ }
+
+ coreIDs, err := fetchWorkloads()
+ if err != nil {
+ logger.Error(ctx, err, "failed to fetch workloads")
+ continue
+ }
+ localIDs, err := svc.GetGuestIDList(context.Background())
+ if err != nil {
+ continue
+ }
+ coreMap := map[string]struct{}{}
+ for _, id := range coreIDs {
+ coreMap[id] = struct{}{}
+ }
+ for _, id := range localIDs {
+ eruID := virttypes.EruID(id)
+ if _, ok := coreMap[eruID]; ok {
+ continue
+ }
+ go deleteGuest(svc, eruID) //nolint
+ }
+ }
+}
+
+func Setup(ctx context.Context, cfg *configs.Config, t *testing.T) (err error) {
+ if t == nil {
+ corestore.Init(ctx, &cfg.Eru)
+ if stor = corestore.Get(); stor == nil {
+ return common.ErrGetStoreFailed
+ }
+ } else {
+ stor = storemocks.NewFakeStore()
+ }
+ return nil
+}
+
+func Run(ctx context.Context, svc service.Service) {
+ go startLoop(ctx, svc)
+}
diff --git a/internal/eru/recycle/recycle_test.go b/internal/eru/recycle/recycle_test.go
new file mode 100644
index 0000000..0581ee5
--- /dev/null
+++ b/internal/eru/recycle/recycle_test.go
@@ -0,0 +1,76 @@
+package recycle
+
+import (
+ "context"
+ "strings"
+ "testing"
+ "time"
+
+ virttypes "github.com/projecteru2/libyavirt/types"
+ "github.com/projecteru2/yavirt/internal/service/mocks"
+ "github.com/projecteru2/yavirt/pkg/notify/bison"
+ "github.com/projecteru2/yavirt/pkg/test/assert"
+ "github.com/projecteru2/yavirt/pkg/test/mock"
+
+ coretypes "github.com/projecteru2/core/types"
+ storemocks "github.com/projecteru2/yavirt/internal/eru/store/mocks"
+ "github.com/projecteru2/yavirt/internal/eru/types"
+ grpcstatus "google.golang.org/grpc/status"
+)
+
+func TestDeleteGuest(t *testing.T) {
+ bison.Setup(nil, t)
+ deleteWait = 0
+ ctx, cancle := context.WithCancel(context.Background())
+ defer cancle()
+ err := Setup(ctx, nil, t)
+ assert.Nil(t, err)
+
+ svc := &mocks.Service{}
+ mockSto := stor.(*storemocks.MockStore)
+
+ // still in eru
+ mockSto.On("GetWorkload", mock.Anything, mock.Anything).Return(
+ &types.Workload{
+ ID: virttypes.EruID("00033017009174384208170000000001"),
+ }, nil).Once()
+ err = deleteGuest(svc, virttypes.EruID("00033017009174384208170000000001"))
+ assert.Err(t, err)
+ assert.True(t, strings.Contains(err.Error(), "still in eru"))
+
+ // get an other error from eru
+ mockSto.On("GetWorkload", mock.Anything, mock.Anything).Return(nil, grpcstatus.Error(1111, coretypes.ErrInvaildCount.Error())).Once()
+ err = deleteGuest(svc, virttypes.EruID("00033017009174384208170000000001"))
+ assert.Err(t, err)
+
+ mockSto.On("GetWorkload", mock.Anything, mock.Anything).Return(nil, grpcstatus.Error(1051, coretypes.ErrInvaildCount.Error())).Once()
+ svc.On("VirtContext", mock.Anything).Return(nil).Once()
+ svc.On("ControlGuest", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
+ err = deleteGuest(svc, virttypes.EruID("00033017009174384208170000000001"))
+ assert.Nil(t, err)
+
+}
+
+func TestNormal(t *testing.T) {
+ interval = 2 * time.Second
+
+ ctx, cancle := context.WithCancel(context.Background())
+ defer cancle()
+ err := Setup(ctx, nil, t)
+ assert.Nil(t, err)
+
+ svc := &mocks.Service{}
+ svc.On("GetGuestIDList", mock.Anything).Return([]string{"00033017009174384208170000000001", "00033017009174384208170000000002"}, nil)
+ mockSto := stor.(*storemocks.MockStore)
+ mockSto.On("ListNodeWorkloads", mock.Anything, mock.Anything).Return(
+ []*types.Workload{
+ {
+ ID: virttypes.EruID("00033017009174384208170000000001"),
+ },
+ {
+ ID: virttypes.EruID("00033017009174384208170000000002"),
+ },
+ }, nil)
+ Run(ctx, svc)
+ time.Sleep(7 * time.Second)
+}
diff --git a/internal/eru/resources/core.go b/internal/eru/resources/core.go
new file mode 100644
index 0000000..a3d3d41
--- /dev/null
+++ b/internal/eru/resources/core.go
@@ -0,0 +1,234 @@
+package resources
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "sort"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/mitchellh/mapstructure"
+ "github.com/projecteru2/core/log"
+ cpumemtypes "github.com/projecteru2/core/resource/plugins/cpumem/types"
+ resourcetypes "github.com/projecteru2/core/resource/types"
+ stotypes "github.com/projecteru2/resource-storage/storage/types"
+ "github.com/projecteru2/yavirt/configs"
+ "github.com/projecteru2/yavirt/internal/eru/types"
+ intertypes "github.com/projecteru2/yavirt/internal/types"
+ "github.com/projecteru2/yavirt/pkg/notify/bison"
+ gputypes "github.com/yuyang0/resource-gpu/gpu/types"
+)
+
+// CoreResourcesManager used to cache the resources on core
+type CoreResourcesManager struct {
+ mu sync.Mutex
+ cpumem *cpumemtypes.NodeResource
+ gpu *gputypes.NodeResource
+ sto *stotypes.NodeResource
+}
+
+func NewCoreResourcesManager() *CoreResourcesManager {
+ return &CoreResourcesManager{}
+}
+
+func (cm *CoreResourcesManager) fetchResourcesWithLock() {
+ ctx, cancel := context.WithTimeout(context.TODO(), 30*time.Second)
+ defer cancel()
+ logger := log.WithFunc("fetchResources")
+
+ resp, err := cli.GetNodeResource(ctx, configs.Hostname())
+ if err != nil {
+ logger.Errorf(ctx, err, "failed to fetch resource from core")
+ return
+ }
+ capacity := resp.Capacity
+ cm.mu.Lock()
+ defer cm.mu.Unlock()
+ for resName, rawParams := range capacity {
+ switch resName {
+ case intertypes.PluginNameCPUMem:
+ cpumem := cpumemtypes.NodeResource{}
+ if err = mapstructure.Decode(rawParams, &cpumem); err != nil {
+ logger.Errorf(ctx, err, "failed to unmarshal resource cpumem")
+ } else {
+ logger.Debugf(ctx, "[core fetchResources] cpumem: %v", cpumem)
+ cm.cpumem = &cpumem
+ }
+ case intertypes.PluginNameStorage:
+ sto := stotypes.NodeResource{}
+ if err = mapstructure.Decode(rawParams, &sto); err != nil {
+ logger.Errorf(ctx, err, "failed to unmarshal resource storage")
+ } else {
+ logger.Debugf(ctx, "[core fetchResources] storage: %v", sto)
+ cm.sto = &sto
+ }
+ case intertypes.PluginNameGPU:
+ gpu := gputypes.NodeResource{}
+ if err = mapstructure.Decode(rawParams, &gpu); err != nil {
+ logger.Errorf(ctx, err, "failed to unmarshal resource gpu")
+ } else {
+ logger.Debugf(ctx, "[core fetchResources] gpu: %v", gpu)
+ cm.gpu = &gpu
+ }
+ }
+ }
+}
+
+func (cm *CoreResourcesManager) GetCpumem() (ans *cpumemtypes.NodeResource) {
+ cm.mu.Lock()
+ ans = cm.cpumem
+ cm.mu.Unlock()
+ if ans != nil {
+ return
+ }
+ cm.fetchResourcesWithLock()
+ cm.mu.Lock()
+ defer cm.mu.Unlock()
+ return cm.cpumem
+}
+
+func (cm *CoreResourcesManager) GetGPU() (ans *gputypes.NodeResource) {
+ cm.mu.Lock()
+ ans = cm.gpu
+ cm.mu.Unlock()
+ if ans != nil {
+ return
+ }
+ cm.fetchResourcesWithLock()
+ cm.mu.Lock()
+ defer cm.mu.Unlock()
+ return cm.gpu
+}
+
+func (cm *CoreResourcesManager) UpdateGPU(nr *gputypes.NodeResource) {
+ ctx, cancel := context.WithTimeout(context.TODO(), 30*time.Second)
+ defer cancel()
+ logger := log.WithFunc("UpdateGPU")
+
+ remoteNR := cm.GetGPU()
+ if remoteNR == nil {
+ return
+ }
+ if remoteNR.Count() == nr.Count() {
+ remoteNR1 := remoteNR.DeepCopy()
+ remoteNR1.Sub(nr)
+ if remoteNR1.Count() == 0 {
+ logger.Debug(ctx, "remote gpu config is consistent")
+ return
+ }
+ }
+ logger.Infof(ctx, "start to update gpu resource: ", nr, remoteNR)
+ resBS, _ := json.Marshal(nr)
+ opts := &types.SetNodeOpts{
+ Nodename: configs.Hostname(),
+ Delta: false,
+ Resources: map[string][]byte{
+ "gpu": resBS,
+ },
+ }
+ _, err := cli.SetNode(ctx, opts)
+ if err != nil {
+ logger.Errorf(ctx, err, "failed to update core resource")
+ return
+ }
+
+ notifier := bison.GetService()
+ if notifier != nil {
+ text := fmt.Sprintf(`
+update core gpu resource successfully
+
+---
+
+- **node:** %s
+- **gpu:** %v
+ `, configs.Hostname(), nr)
+ _ = notifier.SendMarkdown(ctx, "update core gpu resource successfully", text)
+ }
+
+ cm.mu.Lock()
+ defer cm.mu.Unlock()
+
+ cm.gpu = nr
+}
+
+func (cm *CoreResourcesManager) UpdateCPUMem(nr *cpumemtypes.NodeResource) (err error) {
+ ctx, cancel := context.WithTimeout(context.TODO(), 30*time.Second)
+ defer cancel()
+ logger := log.WithFunc("UpdateCPUMem")
+
+ localNR := nr.DeepCopy()
+ remoteNR := cm.GetCpumem()
+ if remoteNR == nil {
+ return err
+ }
+ if remoteNR.CPU == localNR.CPU && remoteNR.Memory <= localNR.Memory && remoteNR.Memory >= (localNR.Memory*75/100) {
+ logger.Info(ctx, "remote cpumem config is consistent")
+ return err
+ }
+ logger.Infof(ctx, "start to update cpumem resource: ", localNR, remoteNR)
+ // prepare data for SetNode
+ cb, _ := convCpumemBytes(localNR)
+ opts := &types.SetNodeOpts{
+ Nodename: configs.Hostname(),
+ Delta: false,
+ Resources: map[string][]byte{
+ "cpumem": cb,
+ },
+ }
+ if _, err = cli.SetNode(ctx, opts); err != nil {
+ logger.Errorf(ctx, err, "failed to update core resource")
+ return err
+ }
+
+ notifier := bison.GetService()
+ if notifier != nil {
+ text := fmt.Sprintf(`
+update core cpumem resource successfully
+---
+
+- **node:** %s
+- **cpumem:** %+v
+ `, configs.Hostname(), localNR)
+ _ = notifier.SendMarkdown(ctx, "update core cpumem resource successfully", text)
+ }
+
+ cm.mu.Lock()
+ defer cm.mu.Unlock()
+
+ cm.cpumem = localNR
+ return nil
+}
+
+func convCpumemBytes(localNR *cpumemtypes.NodeResource) ([]byte, error) {
+ cpumem := resourcetypes.RawParams{
+ "cpu": localNR.CPU,
+ "memory": localNR.Memory * 80 / 100, // use 80% of memory
+ }
+ // nodeID => cpuID list
+ numaCPUMap := map[string][]string{}
+ for cpuID, numID := range localNR.NUMA {
+ numaCPUMap[numID] = append(numaCPUMap[numID], cpuID)
+ }
+ numaCPUList := make([]string, 0, len(numaCPUMap))
+ for idx := 0; idx < len(numaCPUMap); idx++ {
+ cpuIDList := numaCPUMap[strconv.Itoa(idx)]
+ // sort here, so we can write UT easily
+ sort.Strings(cpuIDList)
+ numaCPUList = append(numaCPUList, strings.Join(cpuIDList, ","))
+ }
+ if len(numaCPUList) > 0 {
+ cpumem["numa-cpu"] = numaCPUList
+ }
+ numaMemList := make([]string, 0, len(localNR.NUMAMemory))
+ for idx := 0; idx < len(localNR.NUMAMemory); idx++ {
+ nodeMem := localNR.NUMAMemory[strconv.Itoa(idx)] * 80 / 100 // use 80% of memory
+ numaMemList = append(numaMemList, strconv.FormatInt(nodeMem, 10))
+ }
+ if len(numaMemList) > 0 {
+ cpumem["numa-memory"] = numaMemList
+ }
+ return json.Marshal(cpumem)
+}
diff --git a/internal/eru/resources/core_test.go b/internal/eru/resources/core_test.go
new file mode 100644
index 0000000..c619f71
--- /dev/null
+++ b/internal/eru/resources/core_test.go
@@ -0,0 +1,42 @@
+package resources
+
+import (
+ "testing"
+
+ cpumemtypes "github.com/projecteru2/core/resource/plugins/cpumem/types"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestConvCpumemBytes(t *testing.T) {
+ testCases := []struct {
+ name string
+ localNR *cpumemtypes.NodeResource
+ expected []byte
+ expectFail bool
+ }{
+ {
+ name: "Valid case",
+ localNR: &cpumemtypes.NodeResource{
+ CPU: 4,
+ Memory: 8192,
+ NUMA: map[string]string{"0": "0", "1": "0", "2": "1", "3": "1"},
+ NUMAMemory: map[string]int64{"0": 1000, "1": 10000},
+ },
+ expected: []byte(`{"cpu":4,"memory":6553,"numa-cpu":["0,1","2,3"],"numa-memory":["800","8000"]}`),
+ expectFail: false,
+ },
+ // Add more test cases as needed
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ result, err := convCpumemBytes(tc.localNR)
+ if tc.expectFail {
+ assert.Error(t, err, "Expected an error but got nil")
+ } else {
+ assert.NoError(t, err, "Expected no error but got %v", err)
+ assert.Equal(t, tc.expected, result, "Result does not match expected")
+ }
+ })
+ }
+}
diff --git a/internal/eru/resources/cpumem.go b/internal/eru/resources/cpumem.go
new file mode 100644
index 0000000..20b47a1
--- /dev/null
+++ b/internal/eru/resources/cpumem.go
@@ -0,0 +1,79 @@
+package resources
+
+import (
+ "context"
+ "fmt"
+ "strconv"
+ "time"
+
+ "github.com/jaypipes/ghw"
+ "github.com/projecteru2/core/log"
+ cpumemtypes "github.com/projecteru2/core/resource/plugins/cpumem/types"
+ "github.com/projecteru2/yavirt/configs"
+)
+
+type CPUMemManager struct {
+ cpumem *cpumemtypes.NodeResource
+ coreMgr *CoreResourcesManager
+}
+
+func NewCPUMemManager(coreMgr *CoreResourcesManager, cfg *configs.Config) (*CPUMemManager, error) {
+ logger := log.WithFunc("NewCPUMemManager")
+ cpumem, err := fetchCPUMemFromHardware(cfg)
+ if err != nil {
+ return nil, err
+ }
+ logger.Infof(context.TODO(), "hardware cpumem info: %+v", cpumem)
+ go func() {
+ // Core need to connect to the local grpc server, so sleep 30s here to wait local grpc server up
+ time.Sleep(45 * time.Second)
+ if err := coreMgr.UpdateCPUMem(cpumem); err != nil {
+ logger.Errorf(context.TODO(), err, "failed to update cpumem")
+ }
+ }()
+ return &CPUMemManager{
+ cpumem: cpumem,
+ coreMgr: coreMgr,
+ }, err
+}
+
+func fetchCPUMemFromHardware(cfg *configs.Config) (*cpumemtypes.NodeResource, error) {
+ numa := cpumemtypes.NUMA{}
+ numaMem := cpumemtypes.NUMAMemory{}
+
+ cpu, err := ghw.CPU()
+ if err != nil {
+ return nil, err
+ }
+ mem, err := ghw.Memory()
+ if err != nil {
+ return nil, err
+ }
+ // 因为core会对memory取0.8,而在我们这个场景中,当机器的内存很大比如500G的时候,取0.8浪费太多
+ // 所以这里默认只保留配置的ReservedMemory给yavirt,os使用。
+ reservedMem := cfg.Resource.ReservedMemory
+ if reservedMem > mem.TotalUsableBytes*20/100 {
+ reservedMem = mem.TotalUsableBytes * 20 / 100
+ }
+ infoMem := (mem.TotalUsableBytes - reservedMem) * 100 / 80
+
+ topology, err := ghw.Topology()
+ if err != nil {
+ return nil, err
+ }
+ numaReservedMem := reservedMem / int64(len(topology.Nodes))
+ for _, node := range topology.Nodes {
+ numaMem[strconv.Itoa(node.ID)] = (node.Memory.TotalUsableBytes - numaReservedMem) * 100 / 80
+ for _, core := range node.Cores {
+ for _, id := range core.LogicalProcessors {
+ numa[strconv.Itoa(id)] = fmt.Sprintf("%d", node.ID)
+ }
+ }
+ }
+ return &cpumemtypes.NodeResource{
+ CPU: float64(cpu.TotalThreads),
+ Memory: infoMem,
+ NUMAMemory: numaMem,
+ NUMA: numa,
+ }, nil
+}
diff --git a/internal/eru/resources/cpumem_test.go b/internal/eru/resources/cpumem_test.go
new file mode 100644
index 0000000..a98e1fb
--- /dev/null
+++ b/internal/eru/resources/cpumem_test.go
@@ -0,0 +1,82 @@
+package resources
+
+import (
+ "testing"
+
+ . "github.com/agiledragon/gomonkey/v2"
+ "github.com/jaypipes/ghw"
+ "github.com/jaypipes/ghw/pkg/cpu"
+ "github.com/jaypipes/ghw/pkg/memory"
+ "github.com/jaypipes/ghw/pkg/topology"
+ "github.com/mcuadros/go-defaults"
+ "github.com/projecteru2/yavirt/configs"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestFetchCPUMem(t *testing.T) {
+ patches := ApplyFuncReturn(ghw.Topology, &topology.Info{
+ Nodes: []*topology.Node{
+ {
+ ID: 0,
+ Cores: []*cpu.ProcessorCore{
+ {
+ ID: 0,
+ LogicalProcessors: []int{
+ 0, 2,
+ },
+ },
+ },
+ Memory: &memory.Area{
+ TotalUsableBytes: 1024,
+ },
+ },
+ {
+ ID: 1,
+ Cores: []*cpu.ProcessorCore{
+ {
+ ID: 1,
+ LogicalProcessors: []int{
+ 1, 3,
+ },
+ },
+ },
+ Memory: &memory.Area{
+ TotalUsableBytes: 1024,
+ },
+ },
+ },
+ }, nil)
+ defer patches.Reset()
+
+ patches = ApplyFuncReturn(ghw.CPU, &cpu.Info{
+ TotalThreads: 4,
+ }, nil)
+ defer patches.Reset()
+
+ patches = ApplyFuncReturn(ghw.Memory, &memory.Info{
+ Area: memory.Area{
+ TotalUsableBytes: 2048,
+ },
+ }, nil)
+ defer patches.Reset()
+ cfg := &configs.Config{}
+ defaults.SetDefaults(cfg)
+
+ res, err := fetchCPUMemFromHardware(cfg)
+ assert.Nil(t, err)
+ assert.Equal(t, res.CPU, float64(4))
+ assert.Equal(t, res.Memory, int64(2048))
+ for core, node := range res.NUMA {
+ switch node {
+ case "0":
+ assert.Truef(t, core == "0" || core == "2", "+++ %v", core)
+ case "1":
+ assert.Truef(t, core == "1" || core == "3", "++++ %v", core)
+ default:
+ assert.False(t, true)
+ }
+ }
+ for _, node := range res.NUMAMemory {
+ assert.Equal(t, node, int64(1025))
+ }
+}
diff --git a/internal/eru/resources/gpu.go b/internal/eru/resources/gpu.go
new file mode 100644
index 0000000..58c0e46
--- /dev/null
+++ b/internal/eru/resources/gpu.go
@@ -0,0 +1,245 @@
+package resources
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "os/exec"
+ "strings"
+ "sync"
+ "time"
+
+ _ "embed"
+
+ "github.com/kr/pretty"
+
+ mapset "github.com/deckarep/golang-set/v2"
+ "github.com/patrickmn/go-cache"
+
+ "github.com/jaypipes/ghw"
+ "github.com/projecteru2/core/log"
+ "github.com/projecteru2/yavirt/configs"
+ "github.com/projecteru2/yavirt/internal/types"
+ "github.com/projecteru2/yavirt/internal/vmcache"
+ gputypes "github.com/yuyang0/resource-gpu/gpu/types"
+)
+
+var execCommand = exec.Command
+
+var (
+ //go:embed gpu_name.json
+ gpuNameJSON string
+ gpuNameMap = map[string]string{}
+)
+
+type SingleTypeGPUs struct {
+ gpuMap map[string]types.GPUInfo
+ addrSet mapset.Set[string]
+}
+
+type GPUManager struct {
+ mu sync.Mutex
+ gpuTypeMap map[string]*SingleTypeGPUs
+ coreMgr *CoreResourcesManager
+ lostGPUCache *cache.Cache
+}
+
+func initGPUNameMap(gpuProdMapCfg map[string]string) error {
+ if len(gpuNameMap) > 0 {
+ return nil
+ }
+ if err := json.Unmarshal([]byte(gpuNameJSON), &gpuNameMap); err != nil {
+ return err
+ }
+ // merge name map from config to gpuNameMap
+ for k, v := range gpuProdMapCfg {
+ gpuNameMap[k] = v
+ }
+ return nil
+}
+
+func NewGPUManager(ctx context.Context, cfg *configs.Config, coreMgr *CoreResourcesManager) (*GPUManager, error) {
+ if err := initGPUNameMap(cfg.Resource.GPUProductMap); err != nil {
+ return nil, err
+ }
+ gpuMap, err := fetchGPUInfoFromHardware()
+ if err != nil {
+ return nil, err
+ }
+ log.WithFunc("NewGPUManager").Infof(ctx, "hardware gpu info: %# v", pretty.Formatter(gpuMap))
+
+ mgr := &GPUManager{
+ gpuTypeMap: gpuMap,
+ coreMgr: coreMgr,
+ lostGPUCache: cache.New(3*time.Minute, 1*time.Minute),
+ }
+ go mgr.monitor(ctx)
+ return mgr, nil
+}
+
+func (g *GPUManager) GetResource() *gputypes.NodeResource {
+ g.mu.Lock()
+ defer g.mu.Unlock()
+
+ res := &gputypes.NodeResource{
+ ProdCountMap: make(gputypes.ProdCountMap),
+ }
+ for prod, gpus := range g.gpuTypeMap {
+ res.ProdCountMap[prod] = len(gpus.gpuMap)
+ }
+ return res
+}
+
+func (g *GPUManager) alloc(req *gputypes.EngineParams, usedAddrsMap mapset.Set[string]) (ans []types.GPUInfo, err error) {
+ totalCount := 0
+ for reqProd, reqCount := range req.ProdCountMap {
+ if reqCount <= 0 {
+ continue
+ }
+ totalCount += reqCount
+ singleTypeGPUs := g.gpuTypeMap[reqProd]
+ available := singleTypeGPUs.addrSet.Difference(usedAddrsMap)
+ if available.Cardinality() < reqCount {
+ return nil, errors.New("no enough GPU")
+ }
+ for addr := range available.Iter() {
+ if reqCount <= 0 {
+ break
+ }
+ info := singleTypeGPUs.gpuMap[addr]
+ ans = append(ans, info)
+ reqCount--
+ }
+ }
+ return ans, nil
+}
+
+func (g *GPUManager) Alloc(req *gputypes.EngineParams) (ans []types.GPUInfo, err error) {
+ g.mu.Lock()
+ defer g.mu.Unlock()
+ usedAddrs := vmcache.FetchGPUAddrs()
+ usedAddrsSet := mapset.NewSet[string](usedAddrs...)
+ return g.alloc(req, usedAddrsSet)
+}
+
+func (g *GPUManager) monitor(ctx context.Context) {
+ for {
+ select {
+ case <-ctx.Done():
+ return
+ case <-time.After(1 * time.Minute):
+ }
+ gpuMap, err := fetchGPUInfoFromHardware()
+ if err != nil {
+ log.WithFunc("GPUManager.monitor").Errorf(ctx, err, "failed to fetch gpu info from hardware")
+ continue
+ }
+
+ totalGPUAddrSet := mapset.NewSet[string]()
+ for _, gpus := range gpuMap {
+ totalGPUAddrSet = totalGPUAddrSet.Union(gpus.addrSet)
+ }
+ // check if used gpu are lost
+ usedAddrs := vmcache.FetchDomainGPUAddrs()
+
+ for domain, addrs := range usedAddrs {
+ addrsSet := mapset.NewSet[string](addrs...)
+ diff := addrsSet.Difference(totalGPUAddrSet)
+ if diff.Cardinality() > 0 {
+ de := vmcache.FetchDomainEntry(domain)
+ if de == nil {
+ continue
+ }
+ lostGPUInfo := map[string]string{
+ "node": configs.Hostname(),
+ "domain": domain,
+ "pci_addrs": strings.Join(diff.ToSlice(), ","),
+ "app_id": de.AppID,
+ "app_sid": de.AppSID,
+ "appname": de.AppName,
+ "ip": de.IP,
+ }
+ g.lostGPUCache.Set(domain, lostGPUInfo, cache.DefaultExpiration)
+ }
+ }
+
+ g.mu.Lock()
+ g.gpuTypeMap = gpuMap
+ // don't use defer here,because the following GetRsource also need acquire locker
+ g.mu.Unlock()
+
+ g.coreMgr.UpdateGPU(g.GetResource())
+ }
+}
+
+func fetchGPUInfoFromHardware() (map[string]*SingleTypeGPUs, error) {
+ pci, err := ghw.PCI()
+ if err != nil {
+ return nil, err
+ }
+
+ cmdOut, err := execCommand("lshw", "-quiet", "-json", "-C", "display").Output()
+ if err != nil {
+ return nil, err
+ }
+ params := []map[string]any{}
+ if err = json.Unmarshal(cmdOut, ¶ms); err != nil {
+ return nil, err
+ }
+ // map format:
+ //
+ // product:
+ // pciaddr: gpu info
+ gpuMap := make(map[string]*SingleTypeGPUs)
+ excludePCIs := map[string]struct{}{}
+ for _, addr := range configs.Conf.Resource.ExcludePCIs {
+ excludePCIs[addr] = struct{}{}
+ }
+ for _, param := range params {
+ var addr string
+ if businfoRaw, ok := param["businfo"]; ok && businfoRaw != nil {
+ addr = strings.Split(businfoRaw.(string), "@")[1]
+ } else if handleRaw, ok := param["handle"]; ok && handleRaw != nil {
+ handle := handleRaw.(string) //nolint
+ idx := strings.Index(handle, ":")
+ addr = handle[idx+1:]
+ }
+ if addr == "" {
+ log.Warnf(context.TODO(), "Can't fetch PCI address from %v", param)
+ continue
+ }
+ if _, ok := excludePCIs[addr]; ok {
+ log.Warnf(context.TODO(), "Exclude PCI address %s", addr)
+ continue
+ }
+ deviceInfo := pci.GetDevice(addr)
+ var numa string
+ if deviceInfo != nil && deviceInfo.Node != nil {
+ numa = fmt.Sprintf("%d", deviceInfo.Node.ID)
+ }
+ info := types.GPUInfo{
+ Address: addr,
+ Product: param["product"].(string),
+ Vendor: param["vendor"].(string),
+ NumaID: numa,
+ }
+ if strings.Contains(info.Vendor, "NVIDIA") || strings.Contains(info.Vendor, "AMD") {
+ prod := gpuNameMap[info.Product]
+ if prod == "" {
+ return nil, fmt.Errorf("unknown GPU product: %s", info.Product)
+ }
+ singleTypeGPUs := gpuMap[prod]
+ if singleTypeGPUs == nil {
+ singleTypeGPUs = &SingleTypeGPUs{
+ gpuMap: make(map[string]types.GPUInfo),
+ addrSet: mapset.NewSet[string](),
+ }
+ }
+ singleTypeGPUs.gpuMap[info.Address] = info
+ singleTypeGPUs.addrSet.Add(info.Address)
+ gpuMap[prod] = singleTypeGPUs
+ }
+ }
+ return gpuMap, nil
+}
diff --git a/internal/eru/resources/gpu_name.json b/internal/eru/resources/gpu_name.json
new file mode 100644
index 0000000..0873ed8
--- /dev/null
+++ b/internal/eru/resources/gpu_name.json
@@ -0,0 +1,8 @@
+{
+ "GA104 [GeForce RTX 3070]": "nvidia-3070",
+ "GA104 [GeForce RTX 3070 Lite Hash Rate]": "nvidia-3070-lhr",
+ "GA102 [GeForce RTX 3090]": "nvidia-3090",
+ "NVIDIA Corporation": "nvidia-4090",
+ "GA104M [GeForce RTX 3070 Mobile / Max-Q]": "nvidia-3070m",
+ "Aldebaran": "amd-mi210"
+}
\ No newline at end of file
diff --git a/internal/eru/resources/gpu_test.go b/internal/eru/resources/gpu_test.go
new file mode 100644
index 0000000..136c4ab
--- /dev/null
+++ b/internal/eru/resources/gpu_test.go
@@ -0,0 +1,274 @@
+package resources
+
+import (
+ "encoding/json"
+ "fmt"
+ "os"
+ "os/exec"
+ "testing"
+
+ "github.com/samber/lo"
+ gputypes "github.com/yuyang0/resource-gpu/gpu/types"
+
+ mapset "github.com/deckarep/golang-set/v2"
+ "github.com/projecteru2/yavirt/internal/types"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestGPUAlloc(t *testing.T) {
+ addrSet1 := mapset.NewSet[string]("0.0.0.0", "0.0.0.1", "0.0.0.2", "0.0.0.3")
+ addrSet2 := mapset.NewSet[string]("0.0.0.4", "0.0.0.5", "0.0.0.6", "0.0.0.7")
+ mgr := &GPUManager{
+ gpuTypeMap: map[string]*SingleTypeGPUs{
+ "nvidia-3090": {
+ gpuMap: map[string]types.GPUInfo{
+ "0.0.0.0": {
+ Address: "0.0.0.0",
+ },
+ "0.0.0.1": {
+ Address: "0.0.0.1",
+ },
+ "0.0.0.2": {
+ Address: "0.0.0.2",
+ },
+ "0.0.0.3": {
+ Address: "0.0.0.3",
+ },
+ },
+ addrSet: addrSet1,
+ },
+ "nvidia-3070": {
+ gpuMap: map[string]types.GPUInfo{
+ "0.0.0.4": {
+ Address: "0.0.0.4",
+ },
+ "0.0.0.5": {
+ Address: "0.0.0.5",
+ },
+
+ "0.0.0.6": {
+ Address: "0.0.0.6",
+ },
+
+ "0.0.0.7": {
+ Address: "0.0.0.7",
+ },
+ },
+ addrSet: addrSet2,
+ },
+ },
+ }
+ // no used addrs
+ req := &gputypes.EngineParams{
+ ProdCountMap: map[string]int{
+ "nvidia-3090": 1,
+ "nvidia-3070": 2,
+ },
+ }
+ usedAddrsSet := mapset.NewSet[string]()
+ ans, err := mgr.alloc(req, usedAddrsSet)
+ assert.Nil(t, err)
+ assert.Len(t, ans, 3)
+
+ allocedAddrs := lo.Map(ans, func(info types.GPUInfo, _ int) string {
+ return info.Address
+ })
+ addrSet := mapset.NewSet[string](allocedAddrs...)
+ diff1 := addrSet.Difference(addrSet2)
+ diff2 := addrSet.Difference(addrSet1)
+ assert.Equal(t, diff1.Cardinality(), 1)
+ assert.Equal(t, diff2.Cardinality(), 2)
+
+ // have used addrs
+ usedAddrsSet = mapset.NewSet[string]("0.0.0.0", "0.0.0.3", "0.0.0.4", "0.0.0.5")
+ ans, err = mgr.alloc(req, usedAddrsSet)
+ assert.Nil(t, err)
+ assert.Len(t, ans, 3)
+ allocedAddrs = lo.Map(ans, func(info types.GPUInfo, _ int) string {
+ return info.Address
+ })
+ addrSet = mapset.NewSet[string](allocedAddrs...)
+ diff1 = addrSet.Difference(addrSet2)
+ diff2 = addrSet.Difference(addrSet1)
+ assert.Equal(t, diff1.Cardinality(), 1)
+ assert.Equal(t, diff2.Cardinality(), 2)
+
+ assert.False(t, diff1.Contains("0.0.0.0"))
+ assert.False(t, diff1.Contains("0.0.0.3"))
+ assert.False(t, diff2.Contains("0.0.0.4"))
+ assert.False(t, diff2.Contains("0.0.0.5"))
+
+ // no enough resource
+ req = &gputypes.EngineParams{
+ ProdCountMap: map[string]int{
+ "nvidia-3090": 1,
+ "nvidia-3070": 3,
+ },
+ }
+ usedAddrsSet = mapset.NewSet[string]("0.0.0.0", "0.0.0.3", "0.0.0.4", "0.0.0.5")
+ ans, err = mgr.alloc(req, usedAddrsSet)
+ assert.Error(t, err)
+ req = &gputypes.EngineParams{
+ ProdCountMap: map[string]int{
+ "nvidia-3090": 2,
+ "nvidia-3070": 3,
+ },
+ }
+ ans, err = mgr.alloc(req, usedAddrsSet)
+ assert.Error(t, err)
+ req = &gputypes.EngineParams{
+ ProdCountMap: map[string]int{
+ "nvidia-3090": 3,
+ "nvidia-3070": 3,
+ },
+ }
+ ans, err = mgr.alloc(req, usedAddrsSet)
+ assert.Error(t, err)
+ req = &gputypes.EngineParams{
+ ProdCountMap: map[string]int{
+ "nvidia-3090": 3,
+ "nvidia-3070": 2,
+ },
+ }
+ ans, err = mgr.alloc(req, usedAddrsSet)
+ assert.Error(t, err)
+ req = &gputypes.EngineParams{
+ ProdCountMap: map[string]int{
+ "nvidia-3090": 2,
+ "nvidia-3070": 2,
+ },
+ }
+ ans, err = mgr.alloc(req, usedAddrsSet)
+ assert.Nil(t, err)
+}
+
+func TestFetchGPU(t *testing.T) {
+ err := initGPUNameMap(nil)
+ assert.Nil(t, err)
+ execCommand = fakeExecCommand
+ defer func() { execCommand = exec.Command }()
+
+ gpuMap, err := fetchGPUInfoFromHardware()
+ assert.Nil(t, err)
+ assert.Len(t, gpuMap, 3)
+ gpus3090, ok := gpuMap["nvidia-3090"]
+ assert.True(t, ok)
+ assert.Equal(t, gpus3090.addrSet.Cardinality(), 1)
+ assert.True(t, gpus3090.addrSet.Contains("0000:3d:00.0"))
+
+ gpus3070, ok := gpuMap["nvidia-3070"]
+ assert.True(t, ok)
+ assert.Equal(t, gpus3070.addrSet.Cardinality(), 1)
+ assert.True(t, gpus3070.addrSet.Contains("0000:3c:00.0"))
+ gpuMapJSON, _ := json.Marshal(gpuMap)
+ t.Logf(string(gpuMapJSON))
+
+ mi210, ok := gpuMap["amd-mi210"]
+ assert.True(t, ok)
+ assert.Equal(t, mi210.addrSet.Cardinality(), 1)
+ assert.True(t, mi210.addrSet.Contains("0000:e3:00.0"))
+}
+
+var fakeExecResult = `[
+ {
+ "id" : "display",
+ "class" : "display",
+ "claimed" : true,
+ "handle" : "PCI:0000:3d:00.0",
+ "description" : "VGA compatible controller",
+ "product" : "GA102 [GeForce RTX 3090]",
+ "vendor" : "NVIDIA Corporation",
+ "physid" : "0",
+ "businfo" : "pci@0000:3d:00.0",
+ "version" : "a1",
+ "width" : 64,
+ "clock" : 33000000,
+ "configuration" : {
+ "driver" : "vfio-pci",
+ "latency" : "0"
+ },
+ "capabilities" : {
+ "pm" : "Power Management",
+ "msi" : "Message Signalled Interrupts",
+ "pciexpress" : "PCI Express",
+ "vga_controller" : true,
+ "bus_master" : "bus mastering",
+ "cap_list" : "PCI capabilities listing",
+ "rom" : "extension ROM"
+ }
+ },
+ {
+ "id" : "display",
+ "class" : "display",
+ "claimed" : true,
+ "handle" : "PCI:0000:3c:00.0",
+ "description" : "VGA compatible controller",
+ "product" : "GA104 [GeForce RTX 3070]",
+ "vendor" : "NVIDIA Corporation",
+ "physid" : "0",
+ "businfo" : "pci@0000:3c:00.0",
+ "version" : "a1",
+ "width" : 64,
+ "clock" : 33000000,
+ "configuration" : {
+ "driver" : "vfio-pci",
+ "latency" : "0"
+ },
+ "capabilities" : {
+ "pm" : "Power Management",
+ "msi" : "Message Signalled Interrupts",
+ "pciexpress" : "PCI Express",
+ "vga_controller" : true,
+ "bus_master" : "bus mastering",
+ "cap_list" : "PCI capabilities listing",
+ "rom" : "extension ROM"
+ }
+ },
+ {
+ "id" : "display",
+ "class" : "display",
+ "claimed" : true,
+ "handle" : "PCI:0000:e3:00.0",
+ "description" : "Display controller",
+ "product" : "Aldebaran",
+ "vendor" : "Advanced Micro Devices, Inc. [AMD/ATI]",
+ "physid" : "0",
+ "businfo" : "pci@0000:e3:00.0",
+ "version" : "02",
+ "width" : 64,
+ "clock" : 33000000,
+ "configuration" : {
+ "driver" : "amdgpu",
+ "latency" : "0"
+ },
+ "capabilities" : {
+ "pm" : "Power Management",
+ "pciexpress" : "PCI Express",
+ "msi" : "Message Signalled Interrupts",
+ "msix" : "MSI-X",
+ "bus_master" : "bus mastering",
+ "cap_list" : "PCI capabilities listing",
+ "rom" : "extension ROM"
+ }
+ }
+]`
+
+func fakeExecCommand(command string, args ...string) *exec.Cmd {
+ cs := []string{"-test.run=TestHelperProcess", "--", command}
+ cs = append(cs, args...)
+ cmd := exec.Command(os.Args[0], cs...)
+ cmd.Env = []string{
+ "GO_WANT_HELPER_PROCESS=1",
+ fmt.Sprintf("GOCOVERDIR=%s", os.TempDir()),
+ }
+ return cmd
+}
+
+func TestHelperProcess(t *testing.T) {
+ if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
+ return
+ }
+ // some code here to check arguments perhaps?
+ fmt.Fprintf(os.Stdout, fakeExecResult)
+ os.Exit(0)
+}
diff --git a/internal/eru/resources/manager.go b/internal/eru/resources/manager.go
new file mode 100644
index 0000000..f920842
--- /dev/null
+++ b/internal/eru/resources/manager.go
@@ -0,0 +1,121 @@
+package resources
+
+import (
+ "context"
+ "encoding/json"
+ "sync"
+ "testing"
+
+ cpumemtypes "github.com/projecteru2/core/resource/plugins/cpumem/types"
+ stotypes "github.com/projecteru2/resource-storage/storage/types"
+ "github.com/projecteru2/yavirt/configs"
+ "github.com/projecteru2/yavirt/internal/eru/common"
+ "github.com/projecteru2/yavirt/internal/eru/store"
+ corestore "github.com/projecteru2/yavirt/internal/eru/store/core"
+ storemocks "github.com/projecteru2/yavirt/internal/eru/store/mocks"
+ intertypes "github.com/projecteru2/yavirt/internal/types"
+ bdtypes "github.com/yuyang0/resource-bandwidth/bandwidth/types"
+ gputypes "github.com/yuyang0/resource-gpu/gpu/types"
+)
+
+var (
+ mgr *Manager
+ cli store.Store
+)
+
+type Manager struct {
+ cfg *configs.Config
+ coreMgr *CoreResourcesManager
+
+ gpu *GPUManager
+ cpumem *CPUMemManager
+ sto *StorageManager
+ gpuLock sync.Mutex
+}
+
+func (mgr *Manager) AllocGPU(req *gputypes.EngineParams) (ans []intertypes.GPUInfo, err error) {
+ return mgr.gpu.Alloc(req)
+}
+
+func (mgr *Manager) LockGPU() {
+ mgr.gpuLock.Lock()
+}
+
+func (mgr *Manager) UnlockGPU() {
+ mgr.gpuLock.Unlock()
+}
+
+func (mgr *Manager) FetchResources() (map[string][]byte, error) {
+ cpumemBytes, err := json.Marshal(mgr.cpumem.cpumem)
+ if err != nil {
+ return nil, err
+ }
+ stoBytes, err := json.Marshal(mgr.sto.sto)
+ if err != nil {
+ return nil, err
+ }
+ gpusBytes, err := json.Marshal(mgr.gpu.GetResource())
+ if err != nil {
+ return nil, err
+ }
+ bd := bdtypes.NodeResource{
+ Bandwidth: mgr.cfg.Resource.Bandwidth,
+ }
+ bdBytes, _ := json.Marshal(bd)
+
+ ans := map[string][]byte{
+ intertypes.PluginNameCPUMem: cpumemBytes,
+ intertypes.PluginNameStorage: stoBytes,
+ intertypes.PluginNameGPU: gpusBytes,
+ intertypes.PluginNameBandwidth: bdBytes,
+ }
+ return ans, nil
+}
+
+func (mgr *Manager) FetchCPUMem() *cpumemtypes.NodeResource {
+ return mgr.cpumem.cpumem
+}
+
+func (mgr *Manager) FetchStorage() *stotypes.NodeResource {
+ return mgr.sto.sto
+}
+
+func (mgr *Manager) FetchGPU() *gputypes.NodeResource {
+ return mgr.gpu.GetResource()
+}
+
+func GetManager() *Manager {
+ return mgr
+}
+
+func Setup(ctx context.Context, cfg *configs.Config, t *testing.T) (*Manager, error) {
+ if t == nil {
+ corestore.Init(ctx, &cfg.Eru)
+ if cli = corestore.Get(); cli == nil {
+ return nil, common.ErrGetStoreFailed
+ }
+ } else {
+ cli = storemocks.NewFakeStore()
+ }
+ coreMgr := NewCoreResourcesManager()
+ gpuMgr, err := NewGPUManager(ctx, cfg, coreMgr)
+ if err != nil {
+ return nil, err
+ }
+ cpumemMgr, err := NewCPUMemManager(coreMgr, cfg)
+ if err != nil {
+ return nil, err
+ }
+ stoMgr, err := newStorageManager()
+ if err != nil {
+ return nil, err
+ }
+ mgr = &Manager{
+ cfg: cfg,
+ gpu: gpuMgr,
+ cpumem: cpumemMgr,
+ sto: stoMgr,
+ coreMgr: coreMgr,
+ }
+ return mgr, nil
+}
diff --git a/internal/eru/resources/metrics.go b/internal/eru/resources/metrics.go
new file mode 100644
index 0000000..a1e0737
--- /dev/null
+++ b/internal/eru/resources/metrics.go
@@ -0,0 +1,44 @@
+package resources
+
+import "github.com/prometheus/client_golang/prometheus"
+
+var (
+ lostGPUDesc = prometheus.NewDesc(
+ prometheus.BuildFQName("vm", "gpu", "lost"),
+ "Lost GPUs.",
+ []string{"node", "domain", "pci_addrs", "app_id", "app_sid", "appname", "ip"},
+ nil)
+)
+
+type MetricsCollector struct {
+ mgr *Manager
+}
+
+func (mgr *Manager) GetMetricsCollector() *MetricsCollector {
+ return &MetricsCollector{
+ mgr: mgr,
+ }
+}
+
+func (e *MetricsCollector) Describe(ch chan<- *prometheus.Desc) {
+ ch <- lostGPUDesc
+}
+
+func (e *MetricsCollector) Collect(ch chan<- prometheus.Metric) {
+ for _, v := range e.mgr.gpu.lostGPUCache.Items() {
+ gpuInfo, _ := v.Object.(map[string]string)
+
+ ch <- prometheus.MustNewConstMetric(
+ lostGPUDesc,
+ prometheus.GaugeValue,
+ 1.0,
+ gpuInfo["node"],
+ gpuInfo["domain"],
+ gpuInfo["pci_addrs"],
+ gpuInfo["app_id"],
+ gpuInfo["app_sid"],
+ gpuInfo["appname"],
+ gpuInfo["ip"],
+ )
+ }
+}
diff --git a/internal/eru/resources/storage.go b/internal/eru/resources/storage.go
new file mode 100644
index 0000000..a6f2818
--- /dev/null
+++ b/internal/eru/resources/storage.go
@@ -0,0 +1,56 @@
+package resources
+
+import (
+ "os/exec"
+ "path"
+ "strings"
+
+ "github.com/dustin/go-humanize"
+ stotypes "github.com/projecteru2/resource-storage/storage/types"
+)
+
+type StorageManager struct {
+ sto *stotypes.NodeResource
+}
+
+func newStorageManager() (*StorageManager, error) {
+ sto, err := FetchStorage()
+ if err != nil {
+ return nil, err
+ }
+ return &StorageManager{
+ sto: sto,
+ }, nil
+}
+
+func FetchStorage() (*stotypes.NodeResource, error) {
+ ans := &stotypes.NodeResource{}
+ total := int64(0)
+ vols := stotypes.Volumes{}
+ // use df to fetch volume information
+
+ cmdOut, err := exec.Command("df", "-h").Output()
+ if err != nil {
+ return nil, err
+ }
+ lines := strings.Split(string(cmdOut), "\n")
+ for _, line := range lines {
+ parts := strings.Fields(line)
+ if len(parts) != 6 {
+ continue
+ }
+ var size uint64
+ size, err = humanize.ParseBytes(parts[1])
+ if err != nil {
+ return nil, err
+ }
+ mountPoint := parts[len(parts)-1]
+ if path.Base(mountPoint) == "eru" {
+ vols[mountPoint] = int64(size)
+ total += int64(size)
+ }
+ }
+ ans.Volumes = vols
+ ans.Storage = total
+ return ans, nil
+}
diff --git a/internal/eru/store/core/client.go b/internal/eru/store/core/client.go
new file mode 100644
index 0000000..0047323
--- /dev/null
+++ b/internal/eru/store/core/client.go
@@ -0,0 +1,71 @@
+package core
+
+import (
+ "context"
+ "sync"
+ "time"
+
+ "github.com/projecteru2/core/client"
+ pb "github.com/projecteru2/core/rpc/gen"
+ coretypes "github.com/projecteru2/core/types"
+ "github.com/projecteru2/yavirt/internal/eru/types"
+
+ "github.com/patrickmn/go-cache"
+ "github.com/projecteru2/core/log"
+)
+
+// Store use core to store meta
+type Store struct {
+ clientPool *client.Pool
+ config *types.Config
+ cache *cache.Cache
+}
+
+var coreStore *Store
+var once sync.Once
+
+// New new a Store
+func New(ctx context.Context, config *types.Config) (*Store, error) {
+ auth := coretypes.AuthConfig{
+ Username: config.Username,
+ Password: config.Password,
+ }
+ clientPoolConfig := &client.PoolConfig{
+ EruAddrs: config.Addrs,
+ Auth: auth,
+ ConnectionTimeout: config.GlobalConnectionTimeout,
+ }
+ clientPool, err := client.NewCoreRPCClientPool(ctx, clientPoolConfig)
+ if err != nil {
+ return nil, err
+ }
+ cache := cache.New(time.Duration(config.HealthCheck.CacheTTL)*time.Second, 24*time.Hour)
+ return &Store{clientPool, config, cache}, nil
+}
+
+// GetClient returns a gRPC client
+func (c *Store) GetClient() pb.CoreRPCClient {
+ return c.clientPool.GetClient()
+}
+
+// Init inits the core store only once
+func Init(ctx context.Context, config *types.Config) {
+ once.Do(func() {
+ var err error
+ coreStore, err = New(ctx, config)
+ if err != nil {
+ log.WithFunc("core.client").Error(ctx, err, "failed to create core store")
+ return
+ }
+ })
+}
+
+// Get returns the core store instance
+func Get() *Store {
+ return coreStore
+}
+
+func (c *Store) CheckHealth(ctx context.Context) error {
+ _, err := c.GetClient().Info(ctx, &pb.Empty{})
+ return err
+}
diff --git a/internal/eru/store/core/identifier.go b/internal/eru/store/core/identifier.go
new file mode 100644
index 0000000..7879114
--- /dev/null
+++ b/internal/eru/store/core/identifier.go
@@ -0,0 +1,21 @@
+package core
+
+import (
+ "context"
+
+ pb "github.com/projecteru2/core/rpc/gen"
+ "github.com/projecteru2/yavirt/internal/utils"
+)
+
+// GetIdentifier returns the identifier of core
+func (c *Store) GetIdentifier(ctx context.Context) string {
+ var resp *pb.CoreInfo
+ var err error
+ utils.WithTimeout(ctx, c.config.GlobalConnectionTimeout, func(ctx context.Context) {
+ resp, err = c.GetClient().Info(ctx, &pb.Empty{})
+ })
+ if err != nil {
+ return ""
+ }
+ return resp.Identifier
+}
diff --git a/internal/eru/store/core/node.go b/internal/eru/store/core/node.go
new file mode 100644
index 0000000..16e1709
--- /dev/null
+++ b/internal/eru/store/core/node.go
@@ -0,0 +1,245 @@
+package core
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "io"
+
+ "github.com/projecteru2/core/log"
+ resourcetypes "github.com/projecteru2/core/resource/types"
+ pb "github.com/projecteru2/core/rpc/gen"
+ "github.com/projecteru2/yavirt/internal/eru/types"
+ "github.com/projecteru2/yavirt/internal/utils"
+ "github.com/samber/lo"
+)
+
+// GetNode return a node by core
+func (c *Store) GetNode(ctx context.Context, nodename string) (*types.Node, error) {
+ var resp *pb.Node
+ var err error
+
+ utils.WithTimeout(ctx, c.config.GlobalConnectionTimeout, func(ctx context.Context) {
+ resp, err = c.GetClient().GetNode(ctx, &pb.GetNodeOptions{Nodename: nodename})
+ })
+
+ if err != nil {
+ return nil, err
+ }
+
+ node := &types.Node{
+ Name: resp.Name,
+ Podname: resp.Podname,
+ Endpoint: resp.Endpoint,
+ Available: resp.Available,
+ }
+ return node, nil
+}
+
+// SetNodeStatus reports the status of node
+// SetNodeStatus always reports alive status,
+// when not alive, TTL will cause expiration of node
+func (c *Store) SetNodeStatus(ctx context.Context, ttl int64) error {
+ opts := &pb.SetNodeStatusOptions{
+ Nodename: c.config.Hostname,
+ Ttl: ttl,
+ }
+ var err error
+ utils.WithTimeout(ctx, c.config.GlobalConnectionTimeout, func(ctx context.Context) {
+ _, err = c.GetClient().SetNodeStatus(ctx, opts)
+ })
+
+ return err
+}
+
+// GetNodeStatus gets the status of node
+func (c *Store) GetNodeStatus(ctx context.Context, nodename string) (*types.NodeStatus, error) {
+ var resp *pb.NodeStatusStreamMessage
+ var err error
+
+ utils.WithTimeout(ctx, c.config.GlobalConnectionTimeout, func(ctx context.Context) {
+ resp, err = c.GetClient().GetNodeStatus(ctx, &pb.GetNodeStatusOptions{Nodename: nodename})
+ })
+
+ if err != nil {
+ return nil, err
+ }
+
+ if resp.Error != "" {
+ err = errors.New(resp.Error)
+ }
+
+ status := &types.NodeStatus{
+ Nodename: resp.Nodename,
+ Podname: resp.Podname,
+ Alive: resp.Alive,
+ Error: err,
+ }
+ return status, nil
+}
+
+// NodeStatusStream watches the changes of node status
+func (c *Store) NodeStatusStream(ctx context.Context) (<-chan *types.NodeStatus, <-chan error) {
+ msgChan := make(chan *types.NodeStatus)
+ errChan := make(chan error)
+
+ _ = utils.Pool.Submit(func() {
+ defer close(msgChan)
+ defer close(errChan)
+
+ client, err := c.GetClient().NodeStatusStream(ctx, &pb.Empty{})
+ if err != nil {
+ errChan <- err
+ return
+ }
+
+ for {
+ message, err := client.Recv()
+ if err != nil {
+ errChan <- err
+ return
+ }
+ nodeStatus := &types.NodeStatus{
+ Nodename: message.Nodename,
+ Podname: message.Podname,
+ Alive: message.Alive,
+ Error: nil,
+ }
+ if message.Error != "" {
+ nodeStatus.Error = errors.New(message.Error)
+ }
+ msgChan <- nodeStatus
+ }
+ })
+
+ return msgChan, errChan
+}
+
+// ListPodNodes list nodes by given conditions, note that not all the fields are filled.
+func (c *Store) ListPodNodes(ctx context.Context, all bool, podname string, labels map[string]string) ([]*types.Node, error) {
+ ch, err := c.listPodeNodes(ctx, &pb.ListNodesOptions{
+ Podname: podname,
+ All: all,
+ Labels: labels,
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ nodes := []*types.Node{}
+ for n := range ch {
+ nodes = append(nodes, &types.Node{
+ Name: n.Name,
+ Endpoint: n.Endpoint,
+ Podname: n.Podname,
+ Labels: n.Labels,
+ })
+ }
+ return nodes, nil
+}
+
+func (c *Store) listPodeNodes(ctx context.Context, opt *pb.ListNodesOptions) (ch chan *pb.Node, err error) {
+ ch = make(chan *pb.Node)
+
+ utils.WithTimeout(ctx, c.config.GlobalConnectionTimeout, func(ctx context.Context) {
+ var stream pb.CoreRPC_ListPodNodesClient
+ if stream, err = c.GetClient().ListPodNodes(ctx, opt); err != nil {
+ return
+ }
+
+ _ = utils.Pool.Submit(func() {
+ defer close(ch)
+ for {
+ node, err := stream.Recv()
+ if err != nil {
+ if err != io.EOF { //nolint:nolintlint
+ log.WithFunc("listPodeNodes").Error(ctx, err, "get node stream failed")
+ }
+ return
+ }
+ ch <- node
+ }
+ })
+ })
+
+ return ch, nil
+}
+
+func (c *Store) ListNodeWorkloads(ctx context.Context, nodename string) ([]*types.Workload, error) {
+ opts := &pb.GetNodeOptions{
+ Nodename: nodename,
+ }
+ wrks, err := c.GetClient().ListNodeWorkloads(ctx, opts)
+ if err != nil {
+ return nil, err
+ }
+ ans := lo.Map(wrks.Workloads, func(w *pb.Workload, _ int) *types.Workload {
+ return &types.Workload{
+ ID: w.Id,
+ }
+ })
+ return ans, nil
+}
+
+func (c *Store) GetNodeResource(ctx context.Context, nodename string) (*types.NodeResource, error) {
+ resp, err := c.GetClient().GetNodeResource(ctx, &pb.GetNodeResourceOptions{
+ Opts: &pb.GetNodeOptions{
+ Nodename: nodename,
+ },
+ })
+ if err != nil {
+ return nil, err
+ }
+ capacity := resourcetypes.Resources{}
+ if err = json.Unmarshal([]byte(resp.ResourceCapacity), &capacity); err != nil {
+ return nil, err
+ }
+ return &types.NodeResource{
+ Capacity: capacity,
+ }, nil
+}
+
+func (c *Store) SetNode(ctx context.Context, opts *types.SetNodeOpts) (*types.Node, error) {
+ resp, err := c.GetClient().SetNode(ctx, &pb.SetNodeOptions{
+ Nodename: opts.Nodename,
+ Endpoint: opts.Endpoint,
+ Ca: opts.Ca,
+ Cert: opts.Cert,
+ Key: opts.Key,
+ Labels: opts.Labels,
+ Resources: opts.Resources,
+ Delta: opts.Delta,
+ WorkloadsDown: opts.WorkloadsDown,
+ })
+ if err != nil {
+ return nil, err
+ }
+ return &types.Node{
+ Name: resp.Name,
+ Podname: resp.Podname,
+ Endpoint: resp.Endpoint,
+ Available: resp.Available,
+ }, nil
+}
+
+func (c *Store) AddNode(ctx context.Context, opts *types.AddNodeOpts) (*types.Node, error) {
+ resp, err := c.GetClient().AddNode(ctx, &pb.AddNodeOptions{
+ Nodename: opts.Nodename,
+ Endpoint: opts.Endpoint,
+ Podname: opts.Podname,
+ Ca: opts.Ca,
+ Cert: opts.Cert,
+ Key: opts.Key,
+ Labels: opts.Labels,
+ Resources: opts.Resources,
+ })
+ if err != nil {
+ return nil, err
+ }
+ return &types.Node{
+ Name: resp.Name,
+ Podname: resp.Podname,
+ Endpoint: resp.Endpoint,
+ Available: resp.Available,
+ }, nil
+}
diff --git a/internal/eru/store/core/workload.go b/internal/eru/store/core/workload.go
new file mode 100644
index 0000000..a089afd
--- /dev/null
+++ b/internal/eru/store/core/workload.go
@@ -0,0 +1,81 @@
+package core
+
+import (
+ "context"
+ "crypto/rand"
+ "fmt"
+ "math/big"
+ "time"
+
+ pb "github.com/projecteru2/core/rpc/gen"
+ virttypes "github.com/projecteru2/libyavirt/types"
+ "github.com/projecteru2/yavirt/internal/eru/types"
+ "github.com/projecteru2/yavirt/internal/utils"
+)
+
+func getCacheTTL(ttl int64) time.Duration {
+ n, _ := rand.Int(rand.Reader, big.NewInt(ttl))
+ delta := n.Int64() / 4
+ ttl = ttl - ttl/8 + delta
+ return time.Duration(ttl) * time.Second
+}
+
+// SetWorkloadStatus deploy containers
+func (c *Store) SetWorkloadStatus(ctx context.Context, status *types.WorkloadStatus, ttl int64) error {
+ workloadStatus := fmt.Sprintf("%+v", status)
+ if ttl == 0 {
+ cached, ok := c.cache.Get(status.ID)
+ if ok {
+ str := cached.(string) //nolint
+ if str == workloadStatus {
+ return nil
+ }
+ }
+ }
+
+ statusPb := &pb.WorkloadStatus{
+ Id: virttypes.EruID(status.ID),
+ Running: status.Running,
+ Healthy: status.Healthy,
+ Networks: status.Networks,
+ Extension: status.Extension,
+ Ttl: ttl,
+
+ Appname: status.Appname,
+ Entrypoint: status.Entrypoint,
+ Nodename: c.config.Hostname,
+ }
+
+ opts := &pb.SetWorkloadsStatusOptions{
+ Status: []*pb.WorkloadStatus{statusPb},
+ }
+
+ var err error
+ utils.WithTimeout(ctx, c.config.GlobalConnectionTimeout, func(ctx context.Context) {
+ _, err = c.GetClient().SetWorkloadsStatus(ctx, opts)
+ })
+
+ if ttl == 0 {
+ if err != nil {
+ c.cache.Delete(status.ID)
+ } else {
+ c.cache.Set(status.ID, workloadStatus, getCacheTTL(c.config.HealthCheck.CacheTTL))
+ }
+ }
+
+ return err
+}
+
+func (c *Store) GetWorkload(ctx context.Context, id string) (*types.Workload, error) {
+ opts := &pb.WorkloadID{
+ Id: virttypes.EruID(id),
+ }
+ wrk, err := c.GetClient().GetWorkload(ctx, opts)
+ if err != nil {
+ return nil, err
+ }
+ ans := &types.Workload{
+ ID: wrk.Id,
+ }
+ return ans, nil
+}
diff --git a/internal/eru/store/mocks/Store.go b/internal/eru/store/mocks/Store.go
new file mode 100644
index 0000000..1b5345e
--- /dev/null
+++ b/internal/eru/store/mocks/Store.go
@@ -0,0 +1,374 @@
+// Code generated by mockery v2.42.0. DO NOT EDIT.
+
+package mocks
+
+import (
+ context "context"
+
+ mock "github.com/stretchr/testify/mock"
+
+ types "github.com/projecteru2/yavirt/internal/eru/types"
+)
+
+// Store is an autogenerated mock type for the Store type
+type Store struct {
+ mock.Mock
+}
+
+// AddNode provides a mock function with given fields: ctx, opts
+func (_m *Store) AddNode(ctx context.Context, opts *types.AddNodeOpts) (*types.Node, error) {
+ ret := _m.Called(ctx, opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for AddNode")
+ }
+
+ var r0 *types.Node
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, *types.AddNodeOpts) (*types.Node, error)); ok {
+ return rf(ctx, opts)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, *types.AddNodeOpts) *types.Node); ok {
+ r0 = rf(ctx, opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Node)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, *types.AddNodeOpts) error); ok {
+ r1 = rf(ctx, opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CheckHealth provides a mock function with given fields: ctx
+func (_m *Store) CheckHealth(ctx context.Context) error {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for CheckHealth")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(context.Context) error); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// GetIdentifier provides a mock function with given fields: ctx
+func (_m *Store) GetIdentifier(ctx context.Context) string {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetIdentifier")
+ }
+
+ var r0 string
+ if rf, ok := ret.Get(0).(func(context.Context) string); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Get(0).(string)
+ }
+
+ return r0
+}
+
+// GetNode provides a mock function with given fields: ctx, nodename
+func (_m *Store) GetNode(ctx context.Context, nodename string) (*types.Node, error) {
+ ret := _m.Called(ctx, nodename)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetNode")
+ }
+
+ var r0 *types.Node
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, string) (*types.Node, error)); ok {
+ return rf(ctx, nodename)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, string) *types.Node); ok {
+ r0 = rf(ctx, nodename)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Node)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
+ r1 = rf(ctx, nodename)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// GetNodeResource provides a mock function with given fields: ctx, nodename
+func (_m *Store) GetNodeResource(ctx context.Context, nodename string) (*types.NodeResource, error) {
+ ret := _m.Called(ctx, nodename)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetNodeResource")
+ }
+
+ var r0 *types.NodeResource
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, string) (*types.NodeResource, error)); ok {
+ return rf(ctx, nodename)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, string) *types.NodeResource); ok {
+ r0 = rf(ctx, nodename)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.NodeResource)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
+ r1 = rf(ctx, nodename)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// GetNodeStatus provides a mock function with given fields: ctx, nodename
+func (_m *Store) GetNodeStatus(ctx context.Context, nodename string) (*types.NodeStatus, error) {
+ ret := _m.Called(ctx, nodename)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetNodeStatus")
+ }
+
+ var r0 *types.NodeStatus
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, string) (*types.NodeStatus, error)); ok {
+ return rf(ctx, nodename)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, string) *types.NodeStatus); ok {
+ r0 = rf(ctx, nodename)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.NodeStatus)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
+ r1 = rf(ctx, nodename)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// GetWorkload provides a mock function with given fields: ctx, id
+func (_m *Store) GetWorkload(ctx context.Context, id string) (*types.Workload, error) {
+ ret := _m.Called(ctx, id)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetWorkload")
+ }
+
+ var r0 *types.Workload
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, string) (*types.Workload, error)); ok {
+ return rf(ctx, id)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, string) *types.Workload); ok {
+ r0 = rf(ctx, id)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Workload)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
+ r1 = rf(ctx, id)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ListNodeWorkloads provides a mock function with given fields: ctx, nodename
+func (_m *Store) ListNodeWorkloads(ctx context.Context, nodename string) ([]*types.Workload, error) {
+ ret := _m.Called(ctx, nodename)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ListNodeWorkloads")
+ }
+
+ var r0 []*types.Workload
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, string) ([]*types.Workload, error)); ok {
+ return rf(ctx, nodename)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, string) []*types.Workload); ok {
+ r0 = rf(ctx, nodename)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]*types.Workload)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
+ r1 = rf(ctx, nodename)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ListPodNodes provides a mock function with given fields: ctx, all, podname, labels
+func (_m *Store) ListPodNodes(ctx context.Context, all bool, podname string, labels map[string]string) ([]*types.Node, error) {
+ ret := _m.Called(ctx, all, podname, labels)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ListPodNodes")
+ }
+
+ var r0 []*types.Node
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, bool, string, map[string]string) ([]*types.Node, error)); ok {
+ return rf(ctx, all, podname, labels)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, bool, string, map[string]string) []*types.Node); ok {
+ r0 = rf(ctx, all, podname, labels)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]*types.Node)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, bool, string, map[string]string) error); ok {
+ r1 = rf(ctx, all, podname, labels)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// NodeStatusStream provides a mock function with given fields: ctx
+func (_m *Store) NodeStatusStream(ctx context.Context) (<-chan *types.NodeStatus, <-chan error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for NodeStatusStream")
+ }
+
+ var r0 <-chan *types.NodeStatus
+ var r1 <-chan error
+ if rf, ok := ret.Get(0).(func(context.Context) (<-chan *types.NodeStatus, <-chan error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) <-chan *types.NodeStatus); ok {
+ r0 = rf(ctx)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(<-chan *types.NodeStatus)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) <-chan error); ok {
+ r1 = rf(ctx)
+ } else {
+ if ret.Get(1) != nil {
+ r1 = ret.Get(1).(<-chan error)
+ }
+ }
+
+ return r0, r1
+}
+
+// SetNode provides a mock function with given fields: ctx, opts
+func (_m *Store) SetNode(ctx context.Context, opts *types.SetNodeOpts) (*types.Node, error) {
+ ret := _m.Called(ctx, opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SetNode")
+ }
+
+ var r0 *types.Node
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, *types.SetNodeOpts) (*types.Node, error)); ok {
+ return rf(ctx, opts)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, *types.SetNodeOpts) *types.Node); ok {
+ r0 = rf(ctx, opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Node)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, *types.SetNodeOpts) error); ok {
+ r1 = rf(ctx, opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// SetNodeStatus provides a mock function with given fields: ctx, ttl
+func (_m *Store) SetNodeStatus(ctx context.Context, ttl int64) error {
+ ret := _m.Called(ctx, ttl)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SetNodeStatus")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok {
+ r0 = rf(ctx, ttl)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// SetWorkloadStatus provides a mock function with given fields: ctx, status, ttl
+func (_m *Store) SetWorkloadStatus(ctx context.Context, status *types.WorkloadStatus, ttl int64) error {
+ ret := _m.Called(ctx, status, ttl)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SetWorkloadStatus")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(context.Context, *types.WorkloadStatus, int64) error); ok {
+ r0 = rf(ctx, status, ttl)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// NewStore creates a new instance of Store. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func NewStore(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *Store {
+ mock := &Store{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/internal/eru/store/mocks/fake.go b/internal/eru/store/mocks/fake.go
new file mode 100644
index 0000000..fdfbd95
--- /dev/null
+++ b/internal/eru/store/mocks/fake.go
@@ -0,0 +1,191 @@
+package mocks
+
+import (
+ "context"
+ "sync"
+
+ "github.com/alphadose/haxmap"
+ "github.com/projecteru2/core/log"
+ "github.com/stretchr/testify/mock"
+
+ resourcetypes "github.com/projecteru2/core/resource/types"
+ virttypes "github.com/projecteru2/libyavirt/types"
+ "github.com/projecteru2/yavirt/internal/eru/common"
+ "github.com/projecteru2/yavirt/internal/eru/store"
+ "github.com/projecteru2/yavirt/internal/eru/types"
+)
+
+// MockStore .
+type MockStore struct {
+ Store
+ sync.Mutex
+ workloads *haxmap.Map[string, *types.Workload]
+ workloadStatus *haxmap.Map[string, *types.WorkloadStatus] // map[string]*types.WorkloadStatus
+ nodeStatus *haxmap.Map[string, *types.NodeStatus] // map[string]*types.NodeStatus
+ nodeInfo *haxmap.Map[string, *types.Node] // map[string]*types.Node
+ msgChan chan *types.NodeStatus
+ errChan chan error
+}
+
+func (m *MockStore) init() {
+ m.workloads = haxmap.New[string, *types.Workload]()
+ m.workloadStatus = haxmap.New[string, *types.WorkloadStatus]()
+ m.nodeStatus = haxmap.New[string, *types.NodeStatus]()
+ m.nodeInfo = haxmap.New[string, *types.Node]()
+ m.msgChan = make(chan *types.NodeStatus)
+ m.errChan = make(chan error)
+
+ m.nodeInfo.Set("fake", &types.Node{
+ Name: "fake",
+ Endpoint: "eva://127.0.0.1:6666",
+ })
+ m.nodeInfo.Set("faker", &types.Node{
+ Name: "faker",
+ Endpoint: "eva://127.0.0.1:6667",
+ })
+}
+
+// NewFakeStore returns a mock store instance created from mock
+func NewFakeStore() store.Store {
+ logger := log.WithFunc("fakestore")
+ m := &MockStore{}
+ m.init()
+ m.On("CheckHealth", mock.Anything).Return(nil)
+ m.On("GetNode", mock.Anything, mock.Anything).Return(func(ctx context.Context, nodename string) *types.Node {
+ m.Lock()
+ defer m.Unlock()
+ node, ok := m.nodeInfo.Get(nodename)
+ if !ok {
+ return nil
+ }
+ return &types.Node{
+ Name: node.Name,
+ Available: node.Available,
+ }
+ }, nil)
+ m.On("SetNodeStatus", mock.Anything, mock.Anything).Return(func(ctx context.Context, ttl int64) error {
+ logger.Info(ctx, "set node status")
+ nodename := "fake"
+ m.Lock()
+ defer m.Unlock()
+ if status, ok := m.nodeStatus.Get(nodename); ok {
+ status.Alive = true
+ } else {
+ m.nodeStatus.Set(nodename, &types.NodeStatus{
+ Nodename: nodename,
+ Alive: true,
+ })
+ }
+ return nil
+ })
+ m.On("GetNodeStatus", mock.Anything, mock.Anything).Return(func(ctx context.Context, nodename string) *types.NodeStatus {
+ m.Lock()
+ defer m.Unlock()
+ if status, ok := m.nodeStatus.Get(nodename); ok {
+ return &types.NodeStatus{
+ Nodename: status.Nodename,
+ Alive: status.Alive,
+ }
+ }
+ return &types.NodeStatus{
+ Nodename: nodename,
+ Alive: false,
+ }
+ }, nil)
+ m.On("AddNode", mock.Anything, mock.Anything).Return(func(ctx context.Context, opts *types.AddNodeOpts) (*types.Node, error) {
+ m.Lock()
+ defer m.Unlock()
+ m.nodeInfo.Set(opts.Nodename, &types.Node{
+ Name: opts.Nodename,
+ Endpoint: opts.Endpoint,
+ })
+ return &types.Node{
+ Name: opts.Nodename,
+ Endpoint: opts.Endpoint,
+ }, nil
+ })
+ m.On("SetNode", mock.Anything, mock.Anything).Return(func(ctx context.Context, opts *types.SetNodeOpts) (*types.Node, error) {
+ m.Lock()
+ defer m.Unlock()
+ m.nodeInfo.Set(opts.Nodename, &types.Node{
+ Name: opts.Nodename,
+ Endpoint: opts.Endpoint,
+ Labels: opts.Labels,
+ })
+ return &types.Node{
+ Name: opts.Nodename,
+ Endpoint: opts.Endpoint,
+ Labels: opts.Labels,
+ }, nil
+ })
+ m.On("SetWorkloadStatus", mock.Anything, mock.Anything, mock.Anything).Return(func(ctx context.Context, status *types.WorkloadStatus, ttl int64) error {
+ logger.Infof(ctx, "set workload status: %+v\n", status)
+ m.workloadStatus.Set(status.ID, status)
+ return nil
+ })
+ m.On("GetIdentifier", mock.Anything).Return("fake-identifier")
+ m.On("NodeStatusStream", mock.Anything).Return(func(ctx context.Context) <-chan *types.NodeStatus {
+ return m.msgChan
+ }, func(ctx context.Context) <-chan error {
+ return m.errChan
+ })
+ m.On("ListPodNodes", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]*types.Node{
+ {
+ Name: "fake",
+ },
+ {
+ Name: "faker",
+ },
+ }, nil)
+
+ m.On("ListNodeWorkloads", mock.Anything, mock.Anything).Return([]*types.Workload{
+ {
+ ID: virttypes.EruID("00033017009174384208170000000001"),
+ },
+ {
+ ID: virttypes.EruID("00033017009174384208170000000002"),
+ },
+ }, nil)
+ // TODO
+ m.On("GetNodeResource", mock.Anything, mock.Anything).Return(&types.NodeResource{
+ Capacity: resourcetypes.Resources{
+ "cpumem": nil,
+ },
+ }, nil)
+ // m.On("GetWorkload", mock.Anything, mock.Anything).Return(func(ctx context.Context, ID string) (*types.Workload, error) {
+ // m.Lock()
+ // defer m.Unlock()
+ // wrk, ok := m.workloads.Get(ID)
+ // if !ok {
+ // return nil, status.Error(1051, "entity count invalid")
+ // }
+ // return wrk, nil
+ // })
+ return m
+}
+
+// GetMockWorkloadStatus returns the mock workload status by ID
+func (m *MockStore) GetMockWorkloadStatus(ID string) *types.WorkloadStatus {
+ status, ok := m.workloadStatus.Get(ID)
+ if !ok {
+ return nil
+ }
+ return status
+}
+
+// StartNodeStatusStream "faker" up, "fake" down.
+func (m *MockStore) StartNodeStatusStream() {
+ m.msgChan <- &types.NodeStatus{
+ Nodename: "faker",
+ Alive: true,
+ }
+ m.msgChan <- &types.NodeStatus{
+ Nodename: "fake",
+ Alive: false,
+ }
+}
+
+// StopNodeStatusStream send an err to errChan.
+func (m *MockStore) StopNodeStatusStream() {
+ m.errChan <- common.ErrClosedSteam
+}
diff --git a/internal/eru/store/store.go b/internal/eru/store/store.go
new file mode 100644
index 0000000..8da416c
--- /dev/null
+++ b/internal/eru/store/store.go
@@ -0,0 +1,24 @@
+package store
+
+import (
+ "context"
+
+ "github.com/projecteru2/yavirt/internal/eru/types"
+)
+
+// Store wrapper of remote calls
+type Store interface { //nolint
+ CheckHealth(ctx context.Context) error
+ GetNode(ctx context.Context, nodename string) (*types.Node, error)
+ SetNodeStatus(ctx context.Context, ttl int64) error
+ GetNodeStatus(ctx context.Context, nodename string) (*types.NodeStatus, error)
+ AddNode(ctx context.Context, opts *types.AddNodeOpts) (*types.Node, error)
+ SetNode(ctx context.Context, opts *types.SetNodeOpts) (*types.Node, error)
+ SetWorkloadStatus(ctx context.Context, status *types.WorkloadStatus, ttl int64) error
+ GetIdentifier(ctx context.Context) string
+ NodeStatusStream(ctx context.Context) (<-chan *types.NodeStatus, <-chan error)
+ ListPodNodes(ctx context.Context, all bool, podname string, labels map[string]string) ([]*types.Node, error)
+ ListNodeWorkloads(ctx context.Context, nodename string) ([]*types.Workload, error)
+ GetNodeResource(ctx context.Context, nodename string) (*types.NodeResource, error)
+ GetWorkload(ctx context.Context, id string) (*types.Workload, error)
+}
diff --git a/internal/eru/types/config.go b/internal/eru/types/config.go
new file mode 100644
index 0000000..008316b
--- /dev/null
+++ b/internal/eru/types/config.go
@@ -0,0 +1,8 @@
+package types
+
+import (
+ "github.com/projecteru2/yavirt/configs"
+)
+
+type Config = configs.EruConfig
+type HealthCheckConfig = configs.HealthCheckConfig
diff --git a/internal/eru/types/log.go b/internal/eru/types/log.go
new file mode 100644
index 0000000..a2a11ce
--- /dev/null
+++ b/internal/eru/types/log.go
@@ -0,0 +1,26 @@
+package types
+
+import (
+ "bufio"
+ "net"
+)
+
+// Log for log
+type Log struct {
+ ID string `json:"id"`
+ Name string `json:"name"`
+ Type string `json:"type"`
+ EntryPoint string `json:"entrypoint"`
+ Ident string `json:"ident"`
+ Data string `json:"data"`
+ Datetime string `json:"datetime"`
+ Extra map[string]string `json:"extra"`
+}
+
+// LogConsumer for log consumer
+type LogConsumer struct {
+ ID string
+ App string
+ Conn net.Conn
+ Buf *bufio.ReadWriter
+}
diff --git a/internal/eru/types/message.go b/internal/eru/types/message.go
new file mode 100644
index 0000000..e52b09d
--- /dev/null
+++ b/internal/eru/types/message.go
@@ -0,0 +1,9 @@
+package types
+
+// WorkloadEventMessage .
+type WorkloadEventMessage struct {
+ ID string
+ Type string
+ Action string
+ TimeNano int64
+}
diff --git a/internal/eru/types/node.go b/internal/eru/types/node.go
new file mode 100644
index 0000000..1d7fae7
--- /dev/null
+++ b/internal/eru/types/node.go
@@ -0,0 +1,53 @@
+package types
+
+import (
+ resourcetypes "github.com/projecteru2/core/resource/types"
+)
+
+// Node .
+type Node struct {
+ Name string
+ Endpoint string
+ Podname string
+ Labels map[string]string
+ Available bool
+}
+
+// NodeStatus .
+type NodeStatus struct {
+ Nodename string
+ Podname string
+ Alive bool
+ Error error
+}
+
+type NodeResource struct {
+ Capacity resourcetypes.Resources
+}
+
+type Workload struct {
+ ID string
+}
+
+type SetNodeOpts struct {
+ Nodename string
+ Endpoint string
+ Ca string
+ Cert string
+ Key string
+ Labels map[string]string
+ Resources map[string][]byte
+ Delta bool
+ WorkloadsDown bool
+}
+
+type AddNodeOpts struct {
+ Nodename string
+ Endpoint string
+ Podname string
+ Ca string
+ Cert string
+ Key string
+ Labels map[string]string
+ Resources map[string][]byte
+}
diff --git a/internal/eru/types/workload.go b/internal/eru/types/workload.go
new file mode 100644
index 0000000..a16ff67
--- /dev/null
+++ b/internal/eru/types/workload.go
@@ -0,0 +1,13 @@
+package types
+
+// WorkloadStatus .
+type WorkloadStatus struct {
+ ID string
+ Running bool
+ Healthy bool
+ Networks map[string]string
+ Extension []byte
+ Appname string
+ Nodename string
+ Entrypoint string
+}
diff --git a/internal/meta/const.go b/internal/meta/const.go
new file mode 100644
index 0000000..98edb8b
--- /dev/null
+++ b/internal/meta/const.go
@@ -0,0 +1,54 @@
+package meta
+
+const (
+ // StatusPending .
+ StatusPending = "pending"
+ // StatusCreating .
+ StatusCreating = "creating"
+ // StatusStarting .
+ StatusStarting = "starting"
+ // StatusRunning .
+ StatusRunning = "running"
+ // StatusStopping .
+ StatusStopping = "stopping"
+ // StatusStopped .
+ StatusStopped = "stopped"
+ // StatusMigrating .
+ StatusMigrating = "migrating"
+ // StatusResizing .
+ StatusResizing = "resizing"
+ // StatusCapturing .
+ StatusCapturing = "capturing"
+ // StatusCaptured .
+ StatusCaptured = "captured"
+ // StatusDestroying .
+ StatusDestroying = "destroying"
+ // StatusDestroyed .
+ StatusDestroyed = "destroyed"
+ // StatusPausing .
+ StatusPausing = "pausing"
+ // StatusPaused .
+ StatusPaused = "paused"
+ // StatusResuming .
+ StatusResuming = "resuming"
+ // StatusFreeze .
+ StatusFreeze = "frozen"
+ // StatusThaw .
+ StatusThaw = "thawed"
+)
+
+// AllStatuses .
+var AllStatuses = []string{
+ StatusPending,
+ StatusCreating,
+ StatusStarting,
+ StatusRunning,
+ StatusStopping,
+ StatusStopped,
+ StatusCapturing,
+ StatusCaptured,
+ StatusMigrating,
+ StatusResizing,
+ StatusDestroying,
+ StatusDestroyed,
+}
diff --git a/internal/models/generic.go b/internal/meta/generic.go
similarity index 59%
rename from internal/models/generic.go
rename to internal/meta/generic.go
index 47046f4..838faa0 100644
--- a/internal/models/generic.go
+++ b/internal/meta/generic.go
@@ -1,46 +1,71 @@
-package models
+package meta
import (
"path/filepath"
"time"
+ "github.com/cockroachdb/errors"
"github.com/projecteru2/yavirt/configs"
- "github.com/projecteru2/yavirt/internal/meta"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/projecteru2/yavirt/pkg/terrors"
)
// Generic .
type Generic struct {
- ID string `json:"id,omitempty"`
- Status string `json:"status"`
- CreatedTime int64 `json:"create_time"`
- UpdatedTime int64 `json:"update_time,omitempty"`
- MigratedTime int64 `json:"migrate_time,omitempty"`
+ ID string `json:"id,omitempty" mapstructure:"id"`
+ Status string `json:"status" mapstructure:"status"`
+ CreatedTime int64 `json:"create_time" mapstructure:"create_time"`
+ UpdatedTime int64 `json:"update_time,omitempty" mapstructure:"update_time"`
+ MigratedTime int64 `json:"migrate_time,omitempty" mapstructure:"migrate_time"`
- *meta.Ver
+ *Ver
}
-func newGeneric() *Generic {
+type GenericInterface interface {
+ Resource
+ GetID() string
+ GetCreatedTime() int64
+ SetStatus(st string, force bool) error
+ GetStatus() string
+}
+
+func NewGeneric() *Generic {
return &Generic{
Status: StatusPending,
CreatedTime: time.Now().Unix(),
- Ver: meta.NewVer(),
+ Ver: NewVer(),
}
}
+func (g *Generic) GetID() string {
+ return g.ID
+}
+
+func (g *Generic) GetCreatedTime() int64 {
+ return g.CreatedTime
+}
+
+// MetaKey .
+func (g *Generic) MetaKey() string {
+ return VolumeKey(g.ID)
+}
+
// JoinVirtPath .
func (g *Generic) JoinVirtPath(elem string) string {
return filepath.Join(configs.Conf.VirtDir, elem)
}
-func (g *Generic) setStatus(st string, force bool) error {
+func (g *Generic) SetStatus(st string, force bool) error {
if !(force || g.checkStatus(st)) {
- return errors.Annotatef(errors.ErrForwardStatus, "%s => %s", g.Status, st)
+ return errors.Wrapf(terrors.ErrForwardStatus, "%s => %s", g.Status, st)
}
g.Status = st
return nil
}
+func (g *Generic) GetStatus() string {
+ return g.Status
+}
+
// CheckForwardStatus .
func (g *Generic) CheckForwardStatus(next string) bool {
return g.checkStatus(next)
@@ -76,7 +101,7 @@ func (g *Generic) checkStatus(next string) bool {
return now == StatusStopped || now == StatusRunning
case StatusRunning:
- return now == StatusStarting || now == StatusResuming
+ return now == StatusStarting || now == StatusResuming || now == StatusRunning
case StatusPaused:
return now == StatusPausing
diff --git a/internal/meta/ip.go b/internal/meta/ip.go
index 18a7e34..e933fee 100644
--- a/internal/meta/ip.go
+++ b/internal/meta/ip.go
@@ -4,7 +4,7 @@ import (
"fmt"
"net"
- "github.com/projecteru2/yavirt/internal/vnet/device"
+ "github.com/projecteru2/yavirt/internal/network/utils/device"
"github.com/projecteru2/yavirt/pkg/netx"
)
@@ -66,6 +66,10 @@ func (ipn IPNet) GatewayIPNet() (*net.IPNet, error) {
return netx.ParseCIDR2(ipn.GatewayCIDR())
}
+func (ipn IPNet) GatewayAddr() string {
+ return netx.IntToIPv4(ipn.IntGateway)
+}
+
// GatewayCIDR .
func (ipn IPNet) GatewayCIDR() string {
return fmt.Sprintf("%s/%d", netx.IntToIPv4(ipn.IntGateway), ipn.GatewayPrefix)
diff --git a/internal/meta/keys.go b/internal/meta/keys.go
index d2d0f5a..567aa78 100644
--- a/internal/meta/keys.go
+++ b/internal/meta/keys.go
@@ -22,7 +22,7 @@ const (
// HostCounterKey //hosts:counter
func HostCounterKey() string {
- return filepath.Join(configs.Conf.EtcdPrefix, fmt.Sprintf("%s:counter", hostPrefix))
+ return filepath.Join(configs.Conf.Etcd.Prefix, fmt.Sprintf("%s:counter", hostPrefix))
}
// HostGuestKey //hosts//
@@ -37,7 +37,7 @@ func HostGuestsPrefix(name string) string {
// HostKey //hosts/
func HostKey(name string) string {
- return filepath.Join(configs.Conf.EtcdPrefix, hostPrefix, name)
+ return filepath.Join(configs.Conf.Etcd.Prefix, hostPrefix, name)
}
// GuestKey //guests/
@@ -47,16 +47,16 @@ func GuestKey(id string) string {
// GuestsPrefix //guests/
func GuestsPrefix() string {
- return fmt.Sprintf("%s/", filepath.Join(configs.Conf.EtcdPrefix, guestPrefix))
+ return fmt.Sprintf("%s/", filepath.Join(configs.Conf.Etcd.Prefix, guestPrefix))
}
// VolumeKey //vols/
func VolumeKey(id string) string {
- return filepath.Join(configs.Conf.EtcdPrefix, volPrefix, id)
+ return filepath.Join(configs.Conf.Etcd.Prefix, volPrefix, id)
}
func SnapshotKey(id string) string {
- return filepath.Join(configs.Conf.EtcdPrefix, snapshotPrefix, id)
+ return filepath.Join(configs.Conf.Etcd.Prefix, snapshotPrefix, id)
}
// UserImageKey //uimgs//
@@ -66,7 +66,7 @@ func UserImageKey(user, name string) string {
// UserImagePrefix //
func UserImagePrefix(user string) string {
- return filepath.Join(configs.Conf.EtcdPrefix, uimgPrefix, user)
+ return filepath.Join(configs.Conf.Etcd.Prefix, uimgPrefix, user)
}
// ImageKey //imgs/
@@ -76,7 +76,7 @@ func SysImageKey(name string) string {
// SysImagePrefix //imgs/
func SysImagePrefix() string {
- return filepath.Join(configs.Conf.EtcdPrefix, imgPrefix)
+ return filepath.Join(configs.Conf.Etcd.Prefix, imgPrefix)
}
// OccupiedIPKey //ips//occupied/
@@ -104,7 +104,7 @@ func IPALocKey(subnet int64) string {
// SubnetKey //ips/
func SubnetKey(subnet int64) string {
var v = strconv.FormatInt(subnet, 10)
- return filepath.Join(configs.Conf.EtcdPrefix, ipPrefix, v)
+ return filepath.Join(configs.Conf.Etcd.Prefix, ipPrefix, v)
}
// IPBlockKey //ippool//blocks/
@@ -129,5 +129,5 @@ func IPPoolKey(name string) string {
// IPPoolsPrefix //ippools/
func IPPoolsPrefix() string {
- return filepath.Join(configs.Conf.EtcdPrefix, ippPrefix)
+ return filepath.Join(configs.Conf.Etcd.Prefix, ippPrefix)
}
diff --git a/internal/meta/meta.go b/internal/meta/meta.go
index 783be4d..c823ebf 100644
--- a/internal/meta/meta.go
+++ b/internal/meta/meta.go
@@ -3,8 +3,8 @@ package meta
import (
"context"
+ "github.com/cockroachdb/errors"
"github.com/projecteru2/yavirt/configs"
- "github.com/projecteru2/yavirt/pkg/errors"
"github.com/projecteru2/yavirt/pkg/store"
)
@@ -12,14 +12,14 @@ import (
func Create(res Resources) error {
var data, err = res.Encode()
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "failed to encode resources")
}
var ctx, cancel = Context(context.Background())
defer cancel()
if err := store.Create(ctx, data); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "failed to create resources")
}
res.IncrVer()
@@ -34,7 +34,7 @@ func Load(res Resource) error {
var ver, err = store.Get(ctx, res.MetaKey(), res)
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "failed to load resource")
}
res.SetVer(ver)
@@ -42,18 +42,30 @@ func Load(res Resource) error {
return nil
}
+func LoadRaw(key string) (map[string]any, int64, error) {
+ var ctx, cancel = Context(context.Background())
+ defer cancel()
+ val := map[string]any{}
+ var ver, err = store.Get(ctx, key, &val)
+ if err != nil {
+ return nil, ver, errors.Wrap(err, "failed to load resource")
+ }
+
+ return val, ver, nil
+}
+
// Save .
func Save(res Resources) error {
var data, err = res.Encode()
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "failed to encode resources")
}
var ctx, cancel = Context(context.Background())
defer cancel()
if err := store.Update(ctx, data, res.Vers()); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "failed to update resources")
}
res.IncrVer()
@@ -63,5 +75,5 @@ func Save(res Resources) error {
// Context .
func Context(ctx context.Context) (context.Context, context.CancelFunc) {
- return context.WithTimeout(ctx, configs.Conf.MetaTimeout.Duration())
+ return context.WithTimeout(ctx, configs.Conf.MetaTimeout)
}
diff --git a/internal/meta/res.go b/internal/meta/res.go
index 3184610..51c4dc2 100644
--- a/internal/meta/res.go
+++ b/internal/meta/res.go
@@ -1,7 +1,7 @@
package meta
import (
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/cockroachdb/errors"
"github.com/projecteru2/yavirt/pkg/utils"
)
@@ -28,7 +28,7 @@ func (res Resources) Encode() (map[string]string, error) {
for _, r := range res {
var enc, err = utils.JSONEncode(r, "\t")
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrapf(err, "encode resource %v failed", r)
}
data[r.MetaKey()] = string(enc)
diff --git a/internal/models/status_test.go b/internal/meta/status_test.go
similarity index 97%
rename from internal/models/status_test.go
rename to internal/meta/status_test.go
index ec3a741..57faa5e 100644
--- a/internal/models/status_test.go
+++ b/internal/meta/status_test.go
@@ -1,4 +1,4 @@
-package models
+package meta
import (
"testing"
@@ -61,7 +61,7 @@ func TestStatusForward(t *testing.T) {
},
}
- var g = newGeneric()
+ var g = NewGeneric()
for _, c := range cases {
var next = c.forward
diff --git a/internal/metrics/libvirt.go b/internal/metrics/libvirt.go
new file mode 100644
index 0000000..d3b4642
--- /dev/null
+++ b/internal/metrics/libvirt.go
@@ -0,0 +1,451 @@
+package metrics
+
+import (
+ "context"
+ "fmt"
+ "strings"
+
+ "github.com/projecteru2/core/log"
+ "github.com/projecteru2/yavirt/internal/vmcache"
+ "github.com/prometheus/client_golang/prometheus"
+
+ "github.com/digitalocean/go-libvirt"
+)
+
+var (
+ libvirtUpDesc = prometheus.NewDesc(
+ prometheus.BuildFQName("libvirt", "", "up"),
+ "Whether scraping libvirt's metrics was successful.",
+ []string{"host"},
+ nil)
+
+ libvirtDomainNumbers = prometheus.NewDesc(
+ prometheus.BuildFQName("libvirt", "", "domains_number"),
+ "Number of the domain",
+ []string{"host"},
+ nil)
+
+ libvirtDomainState = prometheus.NewDesc(
+ prometheus.BuildFQName("libvirt", "", "domain_state_code"),
+ "Code of the domain state",
+ []string{"name", "ip", "eruName", "instanceId", "userName", "userId", "host", "stateDesc"},
+ nil)
+
+ libvirtDomainInfoNrVirtCPUDesc = prometheus.NewDesc(
+ prometheus.BuildFQName("libvirt", "domain_info", "virtual_cpus"),
+ "Number of virtual CPUs for the domain.",
+ []string{"name", "ip", "eruName", "instanceId", "userName", "userId", "host"},
+ nil)
+
+ libvirtDomainInfoMaxMemDesc = prometheus.NewDesc(
+ prometheus.BuildFQName("libvirt", "domain_info", "maximum_memory_bytes"),
+ "Maximum allowed memory of the domain, in bytes.",
+ []string{"name", "ip", "eruName", "instanceId", "userName", "userId", "host"},
+ nil)
+ libvirtDomainInfoMemoryDesc = prometheus.NewDesc(
+ prometheus.BuildFQName("libvirt", "domain_info", "memory_usage_bytes"),
+ "Memory usage of the domain, in bytes.",
+ []string{"name", "ip", "eruName", "instanceId", "userName", "userId", "host"},
+ nil)
+
+ libvirtDomainInfoNrGPUDesc = prometheus.NewDesc(
+ prometheus.BuildFQName("libvirt", "domain_info", "gpus"),
+ "Number of GPUs for the domain.",
+ []string{"name", "ip", "eruName", "instanceId", "userName", "userId", "host"},
+ nil)
+
+ // CPU stats
+ libvirtDomainStatCPUTimeDesc = prometheus.NewDesc(
+ prometheus.BuildFQName("libvirt", "domain_cpu_stats", "time_seconds_total"),
+ "Amount of CPU time used by the domain, in seconds.",
+ []string{"name", "ip", "eruName", "instanceId", "userName", "userId", "host"},
+ nil)
+
+ // memory stats
+ libvirtDomainStatMemorySwapInBytesDesc = prometheus.NewDesc(
+ prometheus.BuildFQName("libvirt", "domain_mem_stats", "swap_in_bytes"),
+ "Memory swap in of domain(the total amount of data read from swap space), in bytes.",
+ []string{"name", "ip", "eruName", "instanceId", "userName", "userId", "host"},
+ nil)
+ libvirtDomainStatMemorySwapOutBytesDesc = prometheus.NewDesc(
+ prometheus.BuildFQName("libvirt", "domain_mem_stats", "swap_out_bytes"),
+ "Memory swap out of the domain(the total amount of memory written out to swap space), in bytes.",
+ []string{"name", "ip", "eruName", "instanceId", "userName", "userId", "host"},
+ nil)
+ libvirtDomainStatMemoryUnusedBytesDesc = prometheus.NewDesc(
+ prometheus.BuildFQName("libvirt", "domain_mem_stats", "unused_bytes"),
+ "Memory unused of the domain, in bytes.",
+ []string{"name", "ip", "eruName", "instanceId", "userName", "userId", "host"},
+ nil)
+ libvirtDomainStatMemoryAvailableInBytesDesc = prometheus.NewDesc(
+ prometheus.BuildFQName("libvirt", "domain_mem_stats", "available_bytes"),
+ "Memory available of the domain, in bytes.",
+ []string{"name", "ip", "eruName", "instanceId", "userName", "userId", "host"},
+ nil)
+ libvirtDomainStatMemoryUsableBytesDesc = prometheus.NewDesc(
+ prometheus.BuildFQName("libvirt", "domain_mem_stats", "usable_bytes"),
+ "Memory usable of the domain(corresponds to 'Available' in /proc/meminfo), in bytes.",
+ []string{"name", "ip", "eruName", "instanceId", "userName", "userId", "host"},
+ nil)
+ libvirtDomainStatMemoryRssBytesDesc = prometheus.NewDesc(
+ prometheus.BuildFQName("libvirt", "domain_mem_stats", "rss_bytes"),
+ "Resident Set Size of the process running the domain, in bytes.",
+ []string{"name", "ip", "eruName", "instanceId", "userName", "userId", "host"},
+ nil)
+
+ libvirtDomainBlockRdBytesDesc = prometheus.NewDesc(
+ prometheus.BuildFQName("libvirt", "domain_block_stats", "read_bytes_total"),
+ "Number of bytes read from a block device, in bytes.",
+ []string{"name", "ip", "eruName", "instanceId", "userName", "userId", "host", "source_file", "target_device"},
+ nil)
+ libvirtDomainBlockRdReqDesc = prometheus.NewDesc(
+ prometheus.BuildFQName("libvirt", "domain_block_stats", "read_requests_total"),
+ "Number of read requests from a block device.",
+ []string{"name", "ip", "eruName", "instanceId", "userName", "userId", "host", "source_file", "target_device"},
+ nil)
+ libvirtDomainBlockWrBytesDesc = prometheus.NewDesc(
+ prometheus.BuildFQName("libvirt", "domain_block_stats", "write_bytes_total"),
+ "Number of bytes written from a block device, in bytes.",
+ []string{"name", "ip", "eruName", "instanceId", "userName", "userId", "host", "source_file", "target_device"},
+ nil)
+ libvirtDomainBlockWrReqDesc = prometheus.NewDesc(
+ prometheus.BuildFQName("libvirt", "domain_block_stats", "write_requests_total"),
+ "Number of write requests from a block device.",
+ []string{"name", "ip", "eruName", "instanceId", "userName", "userId", "host", "source_file", "target_device"},
+ nil)
+
+ // DomainInterface
+ libvirtDomainInterfaceRxBytesDesc = prometheus.NewDesc(
+ prometheus.BuildFQName("libvirt", "domain_interface_stats", "rx_bytes_total"),
+ "Number of bytes received on a network interface, in bytes.",
+ []string{"name", "ip", "eruName", "instanceId", "userName", "userId", "host", "target_device"},
+ nil)
+ libvirtDomainInterfaceRxPacketsDesc = prometheus.NewDesc(
+ prometheus.BuildFQName("libvirt", "domain_interface_stats", "rx_packets_total"),
+ "Number of packets received on a network interface.",
+ []string{"name", "ip", "eruName", "instanceId", "userName", "userId", "host", "target_device"},
+ nil)
+ libvirtDomainInterfaceRxErrsDesc = prometheus.NewDesc(
+ prometheus.BuildFQName("libvirt", "domain_interface_stats", "rx_errors_total"),
+ "Number of packet receive errors on a network interface.",
+ []string{"name", "ip", "eruName", "instanceId", "userName", "userId", "host", "target_device"},
+ nil)
+ libvirtDomainInterfaceRxDropDesc = prometheus.NewDesc(
+ prometheus.BuildFQName("libvirt", "domain_interface_stats", "rx_drops_total"),
+ "Number of packet receive drops on a network interface.",
+ []string{"name", "ip", "eruName", "instanceId", "userName", "userId", "host", "target_device"},
+ nil)
+ libvirtDomainInterfaceTxBytesDesc = prometheus.NewDesc(
+ prometheus.BuildFQName("libvirt", "domain_interface_stats", "tx_bytes_total"),
+ "Number of bytes transmitted on a network interface, in bytes.",
+ []string{"name", "ip", "eruName", "instanceId", "userName", "userId", "host", "target_device"},
+ nil)
+ libvirtDomainInterfaceTxPacketsDesc = prometheus.NewDesc(
+ prometheus.BuildFQName("libvirt", "domain_interface_stats", "tx_packets_total"),
+ "Number of packets transmitted on a network interface.",
+ []string{"name", "ip", "eruName", "instanceId", "userName", "userId", "host", "target_device"},
+ nil)
+ libvirtDomainInterfaceTxErrsDesc = prometheus.NewDesc(
+ prometheus.BuildFQName("libvirt", "domain_interface_stats", "tx_errors_total"),
+ "Number of packet transmit errors on a network interface.",
+ []string{"name", "ip", "eruName", "instanceId", "userName", "userId", "host", "target_device"},
+ nil)
+ libvirtDomainInterfaceTxDropDesc = prometheus.NewDesc(
+ prometheus.BuildFQName("libvirt", "domain_interface_stats", "tx_drops_total"),
+ "Number of packet transmit drops on a network interface.",
+ []string{"name", "ip", "eruName", "instanceId", "userName", "userId", "host", "target_device"},
+ nil)
+
+ domainState = map[libvirt.DomainState]string{
+ libvirt.DomainNostate: "no state",
+ libvirt.DomainRunning: "the domain is running",
+ libvirt.DomainBlocked: "the domain is blocked on resource",
+ libvirt.DomainPaused: "the domain is paused by user",
+ libvirt.DomainShutdown: "the domain is being shut down",
+ libvirt.DomainShutoff: "the domain is shut off",
+ libvirt.DomainCrashed: "the domain is crashed",
+ libvirt.DomainPmsuspended: "the domain is suspended by guest power management",
+ // libvirtgo.DOMAIN_LAST: "this enum value will increase over time as new events are added to the libvirt API",
+ }
+)
+
+type collectFunc func(ch chan<- prometheus.Metric, stats *vmcache.DomainStatsResp, promLabels []string) (err error)
+
+// LibvirtExporter implements a Prometheus exporter for libvirt state.
+type LibvirtExporter struct {
+ host string
+}
+
+// NewLibvirtExporter creates a new Prometheus exporter for libvirt.
+func NewLibvirtExporter(hn string) *LibvirtExporter {
+ return &LibvirtExporter{hn}
+}
+
+// Collect scrapes Prometheus metrics from libvirt.
+func (e *LibvirtExporter) Collect(ch chan<- prometheus.Metric) {
+ ch <- prometheus.MustNewConstMetric(
+ libvirtUpDesc,
+ prometheus.GaugeValue,
+ 1.0,
+ e.host)
+
+ domainMap := vmcache.FetchStats()
+ domainNumber := len(domainMap)
+ ch <- prometheus.MustNewConstMetric(
+ libvirtDomainNumbers,
+ prometheus.GaugeValue,
+ float64(domainNumber),
+ e.host,
+ )
+
+ for name := range domainMap {
+ dom := domainMap[name]
+ if err := e.CollectDomain(ch, &dom); err != nil {
+ log.WithFunc("metrics.Collect").Errorf(context.TODO(), err, "failed to collect domain %s", name)
+ return
+ }
+ }
+}
+
+// CollectDomain extracts Prometheus metrics from a libvirt domain.
+func (e *LibvirtExporter) CollectDomain(ch chan<- prometheus.Metric, stats *vmcache.DomainStatsResp) (err error) {
+ // if stats.State == nil || stats.Balloon == nil || stats.Cpu == nil {
+ // return nil
+ // }
+ var (
+ rState = stats.State
+ rvirCPU, _ = vmcache.ToUint64(stats.Stats["vcpu.maximum"])
+ nrGPUs = len(stats.GPUAddrs)
+ rmaxmem, _ = vmcache.ToUint64(stats.Stats["balloon.maximum"])
+ rmemory, _ = vmcache.ToUint64(stats.Stats["balloon.current"])
+ rcputime, _ = vmcache.ToUint64(stats.Stats["cpu.time"])
+ )
+
+ promLabels := []string{
+ stats.AppName,
+ stats.IP,
+ stats.EruName,
+ stats.UUID,
+ stats.UserName,
+ stats.UserID,
+ e.host}
+
+ ch <- prometheus.MustNewConstMetric(libvirtDomainState, prometheus.GaugeValue, float64(rState), append(promLabels, domainState[rState])...)
+
+ ch <- prometheus.MustNewConstMetric(libvirtDomainInfoMaxMemDesc, prometheus.GaugeValue, float64(rmaxmem)*1024, promLabels...)
+ ch <- prometheus.MustNewConstMetric(libvirtDomainInfoMemoryDesc, prometheus.GaugeValue, float64(rmemory)*1024, promLabels...)
+ ch <- prometheus.MustNewConstMetric(libvirtDomainInfoNrVirtCPUDesc, prometheus.GaugeValue, float64(rvirCPU), promLabels...)
+ ch <- prometheus.MustNewConstMetric(libvirtDomainStatCPUTimeDesc, prometheus.CounterValue, float64(rcputime)/1e9, promLabels...)
+ ch <- prometheus.MustNewConstMetric(libvirtDomainInfoNrGPUDesc, prometheus.GaugeValue, float64(nrGPUs), promLabels...)
+ // var isActive int32
+ // if isActive, err = l.DomainIsActive(domain.libvirtDomain); err != nil {
+ // logger.Error("failed to get active status of domain", zap.String("name", "ip", domain.domainName), zap.Error(err))
+ // return err
+ // }
+ // if isActive != 1 {
+ // logger.Info("domain is not active", zap.String("name", "ip", domain.domainName))
+ // return nil
+ // }
+
+ for _, collectFunc := range []collectFunc{CollectDomainBlockDeviceInfo, CollectDomainNetworkInfo, CollectDomainMemoryStatInfo} {
+ if err = collectFunc(ch, stats, promLabels); err != nil {
+ log.WithFunc("metrics.CollectDomain").Errorf(context.TODO(), err, "failed to collect some domain info")
+ }
+ }
+
+ return nil
+}
+
+func CollectDomainBlockDeviceInfo(ch chan<- prometheus.Metric, stats *vmcache.DomainStatsResp, promLabels []string) (err error) {
+ // Report block device statistics.
+ count, _ := vmcache.ToUint64(stats.Stats["block.count"])
+
+ for i := uint64(0); i < count; i++ {
+ diskName, _ := vmcache.ToString(stats.Stats[fmt.Sprintf("block.%d.name", i)])
+ if !strings.HasPrefix(diskName, "vd") {
+ continue
+ }
+ diskPath, _ := vmcache.ToString(stats.Stats[fmt.Sprintf("block.%d.path", i)])
+ rRdReq, _ := vmcache.ToUint64(stats.Stats[fmt.Sprintf("block.%d.rd.reqs", i)])
+ rRdBytes, _ := vmcache.ToUint64(stats.Stats[fmt.Sprintf("block.%d.rd.bytes", i)])
+ rWrReq, _ := vmcache.ToUint64(stats.Stats[fmt.Sprintf("block.%d.wr.reqs", i)])
+ rWrBytes, _ := vmcache.ToUint64(stats.Stats[fmt.Sprintf("block.%d.wr.bytes", i)])
+
+ promDiskLabels := append(promLabels, diskPath, diskName) //nolint
+ ch <- prometheus.MustNewConstMetric(
+ libvirtDomainBlockRdBytesDesc,
+ prometheus.CounterValue,
+ float64(rRdBytes),
+ promDiskLabels...)
+
+ ch <- prometheus.MustNewConstMetric(
+ libvirtDomainBlockRdReqDesc,
+ prometheus.CounterValue,
+ float64(rRdReq),
+ promDiskLabels...)
+
+ ch <- prometheus.MustNewConstMetric(
+ libvirtDomainBlockWrBytesDesc,
+ prometheus.CounterValue,
+ float64(rWrBytes),
+ promDiskLabels...)
+
+ ch <- prometheus.MustNewConstMetric(
+ libvirtDomainBlockWrReqDesc,
+ prometheus.CounterValue,
+ float64(rWrReq),
+ promDiskLabels...)
+
+ }
+ return
+}
+
+func CollectDomainNetworkInfo(ch chan<- prometheus.Metric, stats *vmcache.DomainStatsResp, promLabels []string) (err error) {
+ // Report network interface statistics.
+ count, _ := vmcache.ToUint64(stats.Stats["net.count"])
+ for idx := uint64(0); idx < count; idx++ {
+ ifaceName, _ := vmcache.ToString(stats.Stats[fmt.Sprintf("net.%d.name", idx)])
+ if ifaceName == "" {
+ continue
+ }
+ rRxBytes, _ := vmcache.ToUint64(stats.Stats[fmt.Sprintf("net.%d.rx.bytes", idx)])
+ rRxPackets, _ := vmcache.ToUint64(stats.Stats[fmt.Sprintf("net.%d.rx.pkts", idx)])
+ rRxErrs, _ := vmcache.ToUint64(stats.Stats[fmt.Sprintf("net.%d.rx.errs", idx)])
+ rRxDrop, _ := vmcache.ToUint64(stats.Stats[fmt.Sprintf("net.%d.rx.drop", idx)])
+ rTxBytes, _ := vmcache.ToUint64(stats.Stats[fmt.Sprintf("net.%d.tx.bytes", idx)])
+ rTxPackets, _ := vmcache.ToUint64(stats.Stats[fmt.Sprintf("net.%d.tx.pkts", idx)])
+ rTxErrs, _ := vmcache.ToUint64(stats.Stats[fmt.Sprintf("net.%d.tx.errs", idx)])
+ rTxDrop, _ := vmcache.ToUint64(stats.Stats[fmt.Sprintf("net.%d.tx.drop", idx)])
+
+ promInterfaceLabels := append(promLabels, ifaceName) //nolint
+ ch <- prometheus.MustNewConstMetric(
+ libvirtDomainInterfaceRxBytesDesc,
+ prometheus.CounterValue,
+ float64(rRxBytes),
+ promInterfaceLabels...)
+
+ ch <- prometheus.MustNewConstMetric(
+ libvirtDomainInterfaceRxPacketsDesc,
+ prometheus.CounterValue,
+ float64(rRxPackets),
+ promInterfaceLabels...)
+
+ ch <- prometheus.MustNewConstMetric(
+ libvirtDomainInterfaceRxErrsDesc,
+ prometheus.CounterValue,
+ float64(rRxErrs),
+ promInterfaceLabels...)
+
+ ch <- prometheus.MustNewConstMetric(
+ libvirtDomainInterfaceRxDropDesc,
+ prometheus.CounterValue,
+ float64(rRxDrop),
+ promInterfaceLabels...)
+
+ ch <- prometheus.MustNewConstMetric(
+ libvirtDomainInterfaceTxBytesDesc,
+ prometheus.CounterValue,
+ float64(rTxBytes),
+ promInterfaceLabels...)
+
+ ch <- prometheus.MustNewConstMetric(
+ libvirtDomainInterfaceTxPacketsDesc,
+ prometheus.CounterValue,
+ float64(rTxPackets),
+ promInterfaceLabels...)
+
+ ch <- prometheus.MustNewConstMetric(
+ libvirtDomainInterfaceTxErrsDesc,
+ prometheus.CounterValue,
+ float64(rTxErrs),
+ promInterfaceLabels...)
+
+ ch <- prometheus.MustNewConstMetric(
+ libvirtDomainInterfaceTxDropDesc,
+ prometheus.CounterValue,
+ float64(rTxDrop),
+ promInterfaceLabels...)
+ }
+ return err
+}
+
+func CollectDomainMemoryStatInfo(ch chan<- prometheus.Metric, stats *vmcache.DomainStatsResp, promLabels []string) (err error) {
+ var (
+ swapIn, _ = vmcache.ToUint64(stats.Stats["balloon.swap_in"])
+ swapOut, _ = vmcache.ToUint64(stats.Stats["balloon.swap_out"])
+ unused, _ = vmcache.ToUint64(stats.Stats["balloon.unused"])
+ available, _ = vmcache.ToUint64(stats.Stats["balloon.available"])
+ usable, _ = vmcache.ToUint64(stats.Stats["balloon.usable"])
+ rss, _ = vmcache.ToUint64(stats.Stats["balloon.rss"])
+ )
+
+ ch <- prometheus.MustNewConstMetric(
+ libvirtDomainStatMemorySwapInBytesDesc,
+ prometheus.GaugeValue,
+ float64(swapIn)*1024,
+ promLabels...)
+ ch <- prometheus.MustNewConstMetric(
+ libvirtDomainStatMemorySwapOutBytesDesc,
+ prometheus.GaugeValue,
+ float64(swapOut)*1024,
+ promLabels...)
+ ch <- prometheus.MustNewConstMetric(
+ libvirtDomainStatMemoryUnusedBytesDesc,
+ prometheus.GaugeValue,
+ float64(unused*1024),
+ promLabels...)
+ ch <- prometheus.MustNewConstMetric(
+ libvirtDomainStatMemoryAvailableInBytesDesc,
+ prometheus.GaugeValue,
+ float64(available*1024),
+ promLabels...)
+ ch <- prometheus.MustNewConstMetric(
+ libvirtDomainStatMemoryUsableBytesDesc,
+ prometheus.GaugeValue,
+ float64(usable*1024),
+ promLabels...)
+ ch <- prometheus.MustNewConstMetric(
+ libvirtDomainStatMemoryRssBytesDesc,
+ prometheus.GaugeValue,
+ float64(rss*1024),
+ promLabels...)
+ return
+}
+
+// Describe returns metadata for all Prometheus metrics that may be exported.
+func (e *LibvirtExporter) Describe(ch chan<- *prometheus.Desc) {
+ ch <- libvirtUpDesc
+ ch <- libvirtDomainNumbers
+
+ // domain info
+ ch <- libvirtDomainState
+ ch <- libvirtDomainInfoMaxMemDesc
+ ch <- libvirtDomainInfoMemoryDesc
+ ch <- libvirtDomainInfoNrVirtCPUDesc
+ ch <- libvirtDomainStatCPUTimeDesc
+ ch <- libvirtDomainInfoNrGPUDesc
+
+ // domain block
+ ch <- libvirtDomainBlockRdBytesDesc
+ ch <- libvirtDomainBlockRdReqDesc
+ ch <- libvirtDomainBlockWrBytesDesc
+ ch <- libvirtDomainBlockWrReqDesc
+
+ // domain interface
+ ch <- libvirtDomainInterfaceRxBytesDesc
+ ch <- libvirtDomainInterfaceRxPacketsDesc
+ ch <- libvirtDomainInterfaceRxErrsDesc
+ ch <- libvirtDomainInterfaceRxDropDesc
+ ch <- libvirtDomainInterfaceTxBytesDesc
+ ch <- libvirtDomainInterfaceTxPacketsDesc
+ ch <- libvirtDomainInterfaceTxErrsDesc
+ ch <- libvirtDomainInterfaceTxDropDesc
+
+ // domain mem stat
+ ch <- libvirtDomainStatMemorySwapInBytesDesc
+ ch <- libvirtDomainStatMemorySwapOutBytesDesc
+ ch <- libvirtDomainStatMemoryUnusedBytesDesc
+ ch <- libvirtDomainStatMemoryAvailableInBytesDesc
+ ch <- libvirtDomainStatMemoryUsableBytesDesc
+ ch <- libvirtDomainStatMemoryRssBytesDesc
+}
diff --git a/internal/metrics/metric.go b/internal/metrics/metric.go
index 192cf29..b389937 100644
--- a/internal/metrics/metric.go
+++ b/internal/metrics/metric.go
@@ -6,8 +6,7 @@ import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
- "github.com/projecteru2/yavirt/configs"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/cockroachdb/errors"
"github.com/projecteru2/yavirt/pkg/utils"
)
@@ -19,31 +18,34 @@ var (
MetricHeartbeatCount = "yavirt_heartbeat_total"
// MetricErrorCount .
MetricErrorCount = "yavirt_error_total"
+ MetricSvcTasks = "yavirt_svc_task_count"
metr *Metrics
)
-func init() {
- hn := configs.Hostname()
-
+func Setup(hn string, cols ...prometheus.Collector) {
metr = New(hn)
metr.RegisterCounter(MetricErrorCount, "yavirt errors", nil) //nolint
metr.RegisterCounter(MetricHeartbeatCount, "yavirt heartbeats", nil) //nolint
+ metr.RegisterGauge(MetricSvcTasks, "yavirt service tasks", nil) //nolint
+ e := NewLibvirtExporter(hn)
+ prometheus.MustRegister(e)
+ if len(cols) > 0 {
+ prometheus.MustRegister(cols...)
+ }
}
// Metrics .
type Metrics struct {
- host string
- counters map[string]*prometheus.CounterVec
- gauges map[string]*prometheus.GaugeVec
+ host string
+ collectors map[string]prometheus.Collector
}
// New .
func New(host string) *Metrics {
return &Metrics{
- host: host,
- counters: map[string]*prometheus.CounterVec{},
- gauges: map[string]*prometheus.GaugeVec{},
+ host: host,
+ collectors: map[string]prometheus.Collector{},
}
}
@@ -58,10 +60,9 @@ func (m *Metrics) RegisterCounter(name, desc string, labels []string) error {
)
if err := prometheus.Register(col); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
-
- m.counters[name] = col
+ m.collectors[name] = col
return nil
}
@@ -77,38 +78,66 @@ func (m *Metrics) RegisterGauge(name, desc string, labels []string) error {
)
if err := prometheus.Register(col); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
- m.gauges[name] = col
+ m.collectors[name] = col
return nil
}
// Incr .
func (m *Metrics) Incr(name string, labels map[string]string) error {
- var col, exists = m.counters[name]
+ var collector, exists = m.collectors[name]
if !exists {
return errors.Errorf("collector %s not found", name)
}
labels = m.appendLabel(labels, "host", m.host)
+ switch col := collector.(type) {
+ case *prometheus.GaugeVec:
+ col.With(labels).Inc()
+ case *prometheus.CounterVec:
+ col.With(labels).Inc()
+ default:
+ return errors.Errorf("collector %s is not counter or gauge", name)
+ }
- col.With(labels).Inc()
+ return nil
+}
+
+// Decr .
+func (m *Metrics) Decr(name string, labels map[string]string) error {
+ var collector, exists = m.collectors[name]
+ if !exists {
+ return errors.Errorf("collector %s not found", name)
+ }
+
+ labels = m.appendLabel(labels, "host", m.host)
+ switch col := collector.(type) {
+ case *prometheus.GaugeVec:
+ col.With(labels).Dec()
+ default:
+ return errors.Errorf("collector %s is not gauge", name)
+ }
return nil
}
// Store .
func (m *Metrics) Store(name string, value float64, labels map[string]string) error {
- var col, exists = m.gauges[name]
+ var collector, exists = m.collectors[name]
if !exists {
return errors.Errorf("collector %s not found", name)
}
labels = m.appendLabel(labels, "host", m.host)
-
- col.With(labels).Set(value)
+ switch col := collector.(type) {
+ case *prometheus.GaugeVec:
+ col.With(labels).Set(value)
+ default:
+ return errors.Errorf("collector %s is not gauge", name)
+ }
return nil
}
@@ -142,6 +171,10 @@ func Incr(name string, labels map[string]string) error {
return metr.Incr(name, labels)
}
+func Decr(name string, labels map[string]string) error {
+ return metr.Decr(name, labels)
+}
+
// Store .
func Store(name string, value float64, labels map[string]string) error {
return metr.Store(name, value, labels)
diff --git a/internal/models/const.go b/internal/models/const.go
index 2b875e8..29ff0ed 100644
--- a/internal/models/const.go
+++ b/internal/models/const.go
@@ -1,66 +1,11 @@
package models
const (
- // StatusPending .
- StatusPending = "pending"
- // StatusCreating .
- StatusCreating = "creating"
- // StatusStarting .
- StatusStarting = "starting"
- // StatusRunning .
- StatusRunning = "running"
- // StatusStopping .
- StatusStopping = "stopping"
- // StatusStopped .
- StatusStopped = "stopped"
- // StatusMigrating .
- StatusMigrating = "migrating"
- // StatusResizing .
- StatusResizing = "resizing"
- // StatusCapturing .
- StatusCapturing = "capturing"
- // StatusCaptured .
- StatusCaptured = "captured"
- // StatusDestroying .
- StatusDestroying = "destroying"
- // StatusDestroyed .
- StatusDestroyed = "destroyed"
- // StatusPausing .
- StatusPausing = "pausing"
- // StatusPaused .
- StatusPaused = "paused"
- // StatusResuming .
- StatusResuming = "resuming"
-
- // VolDataType .
- VolDataType = "dat"
- // VolSysType .
- VolSysType = "sys"
- // VolQcow2Format .
- VolQcow2Format = "qcow2"
-
- // SnapshotFullType .
- SnapshotFullType = "full"
- // SnapshotIncrementalType .
- SnapshotIncrementalType = "incremental"
-
// HostVirtType .
HostVirtType = "virt"
// HostMetaType .
HostMetaType = "meta"
- // DistroUbuntu .
- DistroUbuntu = "ubuntu"
- // DistroCentOS .
- DistroCentOS = "centos"
-
- // UserImagePrefix .
- UserImagePrefix = "uimg"
- // ImageSys indicates the image is a system version.
- ImageSys = "sys"
- // ImageUser indicates the image was captured by user.
- ImageUser = "user"
-
// LabelPublish .
LabelPublish = "Publish"
// LabelHealthCheck .
@@ -83,19 +28,3 @@ const (
// MaxBlockIPCount .
MaxBlockIPCount = 256
)
-
-// AllStatuses .
-var AllStatuses = []string{
- StatusPending,
- StatusCreating,
- StatusStarting,
- StatusRunning,
- StatusStopping,
- StatusStopped,
- StatusCapturing,
- StatusCaptured,
- StatusMigrating,
- StatusResizing,
- StatusDestroying,
- StatusDestroyed,
-}
diff --git a/internal/models/guest.go b/internal/models/guest.go
index 83a1a9e..8bd4428 100644
--- a/internal/models/guest.go
+++ b/internal/models/guest.go
@@ -2,70 +2,80 @@ package models
import (
"context"
- "fmt"
- "path/filepath"
+ "encoding/json"
"strings"
erucluster "github.com/projecteru2/core/cluster"
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/core/log"
"github.com/projecteru2/yavirt/configs"
"github.com/projecteru2/yavirt/internal/meta"
- "github.com/projecteru2/yavirt/internal/virt/types"
- "github.com/projecteru2/yavirt/internal/vnet"
- "github.com/projecteru2/yavirt/internal/vnet/handler"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/projecteru2/yavirt/internal/network"
+ "github.com/projecteru2/yavirt/internal/types"
+ interutils "github.com/projecteru2/yavirt/internal/utils"
+ "github.com/projecteru2/yavirt/internal/volume"
+ volFact "github.com/projecteru2/yavirt/internal/volume/factory"
+ "github.com/projecteru2/yavirt/internal/volume/local"
"github.com/projecteru2/yavirt/pkg/idgen"
+ "github.com/projecteru2/yavirt/pkg/netx"
"github.com/projecteru2/yavirt/pkg/store"
+ "github.com/projecteru2/yavirt/pkg/terrors"
"github.com/projecteru2/yavirt/pkg/utils"
+ bdtypes "github.com/yuyang0/resource-bandwidth/bandwidth/types"
+ gputypes "github.com/yuyang0/resource-gpu/gpu/types"
+ vmiFact "github.com/yuyang0/vmimage/factory"
+ vmitypes "github.com/yuyang0/vmimage/types"
)
// Guest indicates a virtual machine.
type Guest struct {
- *Generic
-
- ImageName string `json:"img"`
- ImageUser string `json:"img_user,omitempty"`
- HostName string `json:"host"`
- CPU int `json:"cpu"`
- Memory int64 `json:"mem"`
- VolIDs []string `json:"vols"`
- IPNets meta.IPNets `json:"ips"`
- ExtraNetworks Networks `json:"extra_networks,omitempty"`
- NetworkMode string `json:"network,omitempty"`
- EnabledCalicoCNI bool `json:"enabled_calico_cni,omitempty"`
- NetworkPair string `json:"network_pair,omitempty"`
- EndpointID string `json:"endpoint,omitempty"`
- MAC string `json:"mac"`
- JSONLabels map[string]string `json:"labels"`
-
- LambdaOption *LambdaOptions `json:"lambda_option,omitempty"`
- LambdaStdin bool `json:"lambda_stdin,omitempty"`
- Host *Host `json:"-"`
- Img Image `json:"-"`
- Vols Volumes `json:"-"`
- IPs IPs `json:"-"`
+ *meta.Generic
+
+ ImageName string `json:"img"`
+ HostName string `json:"host"`
+ CPU int `json:"cpu"`
+ Memory int64 `json:"mem"`
+ VolIDs []string `json:"vols"`
+ GPUEngineParams *gputypes.EngineParams `json:"gpu_engine_params"`
+ BDEngineParams *bdtypes.EngineParams `json:"bandwidth_engine_params"`
+ IPNets meta.IPNets `json:"ips"`
+ ExtraNetworks Networks `json:"extra_networks,omitempty"`
+ NetworkMode string `json:"network,omitempty"`
+ NetworkPair string `json:"network_pair,omitempty"`
+ EndpointID string `json:"endpoint,omitempty"`
+ MAC string `json:"mac"`
+ MTU int `json:"mtu"`
+ JSONLabels map[string]string `json:"labels"`
+
+ LambdaOption *LambdaOptions `json:"lambda_option,omitempty"`
+ LambdaStdin bool `json:"lambda_stdin,omitempty"`
+ Host *Host `json:"-"`
+ Img *vmitypes.Image `json:"-"`
+ Vols volFact.Volumes `json:"-"`
+ IPs IPs `json:"-"`
DmiUUID string `json:"-"`
}
// Check .
func (g *Guest) Check() error {
- if g.CPU < configs.Conf.MinCPU || g.CPU > configs.Conf.MaxCPU {
- return errors.Annotatef(errors.ErrInvalidValue,
+ if g.CPU < configs.Conf.Resource.MinCPU || g.CPU > configs.Conf.Resource.MaxCPU {
+ return errors.Wrapf(terrors.ErrInvalidValue,
"invalid CPU num: %d, it should be [%d, %d]",
- g.CPU, configs.Conf.MinCPU, configs.Conf.MaxCPU)
+ g.CPU, configs.Conf.Resource.MinCPU, configs.Conf.Resource.MaxCPU)
}
- if g.Memory < configs.Conf.MinMemory || g.Memory > configs.Conf.MaxMemory {
- return errors.Annotatef(errors.ErrInvalidValue,
+ if g.Memory < configs.Conf.Resource.MinMemory || g.Memory > configs.Conf.Resource.MaxMemory {
+ return errors.Wrapf(terrors.ErrInvalidValue,
"invalie memory: %d, it shoule be [%d, %d]",
- g.Memory, configs.Conf.MinMemory, configs.Conf.MaxMemory)
+ g.Memory, configs.Conf.Resource.MinMemory, configs.Conf.Resource.MaxMemory)
}
if lab, exists := g.JSONLabels[erucluster.LabelMeta]; exists {
obj := map[string]any{}
if err := utils.JSONDecode([]byte(lab), &obj); err != nil {
- return errors.Annotatef(errors.ErrInvalidValue, "'%s' should be JSON format", lab)
+ return errors.Wrapf(terrors.ErrInvalidValue, "'%s' should be JSON format", lab)
}
}
@@ -79,14 +89,15 @@ func (g *Guest) MetaKey() string {
// Create .
func (g *Guest) Create() error {
- g.Vols.genID()
- g.Vols.setGuestID(g.ID)
- g.VolIDs = g.Vols.ids()
+ g.Vols.GenID()
+ g.Vols.SetDevice()
+ g.Vols.SetGuestID(g.ID)
+ g.VolIDs = g.Vols.IDs()
g.IPs.setGuestID(g.ID)
var res = meta.Resources{g}
- res.Concate(g.Vols.resources())
+ res.Concate(g.Vols.Resources())
res.Concate(meta.Resources{newHostGuest(g.HostName, g.ID)})
return meta.Create(res)
@@ -109,7 +120,7 @@ func (g *Guest) RemoveVol(volID string) {
n := g.Vols.Len()
for i := n - 1; i >= 0; i-- {
- if g.Vols[i].ID != volID {
+ if g.Vols[i].GetID() != volID {
continue
}
@@ -125,53 +136,58 @@ func (g *Guest) RemoveVol(volID string) {
}
// AppendVols .
-func (g *Guest) AppendVols(vols ...*Volume) error {
- if g.Vols.Len()+len(vols) > configs.Conf.MaxVolumesCount {
- return errors.Annotatef(errors.ErrTooManyVolumes, "at most %d", configs.Conf.MaxVolumesCount)
+func (g *Guest) AppendVols(vols ...volume.Volume) error {
+ if g.Vols.Len()+len(vols) > configs.Conf.Resource.MaxVolumesCount {
+ return errors.Wrapf(terrors.ErrTooManyVolumes, "at most %d", configs.Conf.Resource.MaxVolumesCount)
}
- var res = Volumes(vols)
- res.setHostName(g.HostName)
+ var res = volFact.Volumes(vols)
+ res.SetHostName(g.HostName)
- g.Vols.append(vols...)
+ g.Vols = append(g.Vols, vols...)
- g.VolIDs = append(g.VolIDs, res.ids()...)
+ g.VolIDs = append(g.VolIDs, res.IDs()...)
return nil
}
-func (g *Guest) SwitchVol(vol *Volume, idx int) error {
+func (g *Guest) SwitchVol(vol volume.Volume, idx int) error {
if idx < 0 || idx >= g.Vols.Len() {
- return errors.Annotatef(errors.ErrInvalidValue, "must in range 0 to %d", g.Vols.Len()-1)
+ return errors.WithMessagef(terrors.ErrInvalidValue, "must in range 0 to %d", g.Vols.Len()-1)
}
g.Vols[idx] = vol
- g.VolIDs[idx] = vol.ID
+ g.VolIDs[idx] = vol.GetID()
return nil
}
// Load .
-func (g *Guest) Load(host *Host, networkHandler handler.Handler) (err error) {
+func (g *Guest) Load(host *Host, networkHandler network.Driver, opts ...Option) (err error) {
+ logger := log.WithFunc("Guest.Load")
+ op := NewOp(opts...)
g.Host = host
- if g.Img, err = LoadImage(g.ImageName, g.ImageUser); err != nil {
- return errors.Trace(err)
- }
-
- if g.Vols, err = LoadVolumes(g.VolIDs); err != nil {
- return errors.Trace(err)
+ if g.Vols, err = volFact.LoadVolumes(g.VolIDs); err != nil {
+ return errors.WithMessagef(err, "failed to load volumes %v", g.VolIDs)
}
if err = g.LoadIPs(networkHandler); err != nil {
- return errors.Trace(err)
+ return errors.WithMessage(err, "failed to load IPs")
}
+ if g.Img, err = vmiFact.LoadImage(context.TODO(), g.ImageName); err != nil {
+ if op.IgnoreLoadImageErr {
+ logger.Warnf(context.TODO(), "failed to load image %s: %s", g.ImageName, err)
+ } else {
+ return errors.Wrapf(terrors.ErrLoadImage, "failed to load image %s: %s", g.ImageName, err)
+ }
+ }
return nil
}
// LoadIPs .
-func (g *Guest) LoadIPs(networkHandler handler.Handler) (err error) {
+func (g *Guest) LoadIPs(networkHandler network.Driver) (err error) {
for _, ipn := range g.IPNets {
ipn.Assigned = true
}
@@ -195,15 +211,15 @@ func (g *Guest) Save() error {
// Delete .
func (g *Guest) Delete(force bool) error {
- if err := g.setStatus(StatusDestroyed, force); err != nil {
- return errors.Trace(err)
+ if err := g.SetStatus(meta.StatusDestroyed, force); err != nil {
+ return errors.WithMessagef(err, "Delete: failed to set status to %s", meta.StatusDestroyed)
}
var keys = []string{
g.MetaKey(),
newHostGuest(g.HostName, g.ID).MetaKey(),
}
- keys = append(keys, g.Vols.deleteKeys()...)
+ keys = append(keys, g.Vols.MetaKeys()...)
var vers = map[string]int64{g.MetaKey(): g.GetVer()}
for _, vol := range g.Vols {
@@ -217,20 +233,20 @@ func (g *Guest) Delete(force bool) error {
}
// SysVolume .
-func (g *Guest) SysVolume() (*Volume, error) {
+func (g *Guest) SysVolume() (volume.Volume, error) {
for _, vol := range g.Vols {
if vol.IsSys() {
return vol, nil
}
}
- return nil, errors.ErrSysVolumeNotExists
+ return nil, terrors.ErrSysVolumeNotExists
}
// HealthCheck .
func (g *Guest) HealthCheck() (HealthCheck, error) {
hcb, err := g.healthCheckBridge()
if err != nil {
- return HealthCheck{}, errors.Trace(err)
+ return HealthCheck{}, errors.Wrap(err, "")
}
return hcb.healthCheck(g)
}
@@ -239,7 +255,7 @@ func (g *Guest) HealthCheck() (HealthCheck, error) {
func (g *Guest) PublishPorts() ([]int, error) {
hcb, err := g.healthCheckBridge()
if err != nil {
- return []int{}, errors.Trace(err)
+ return []int{}, errors.Wrap(err, "")
}
return hcb.publishPorts()
}
@@ -258,16 +274,10 @@ func (g *Guest) MemoryInMiB() int64 {
return utils.ConvToMB(g.Memory)
}
-// SocketFilepath shows the socket filepath of the guest on the host.
-func (g *Guest) SocketFilepath() string {
- var fn = fmt.Sprintf("%s.sock", g.ID)
- return filepath.Join(configs.Conf.VirtSockDir, fn)
-}
-
// NetworkPairName .
func (g *Guest) NetworkPairName() string {
switch {
- case g.NetworkMode == vnet.NetworkCalico:
+ case g.NetworkMode == network.CalicoMode:
fallthrough
case len(g.NetworkPair) > 0:
return g.NetworkPair
@@ -277,65 +287,83 @@ func (g *Guest) NetworkPairName() string {
}
}
+// Generate cloud-init config from guest.
+func (g *Guest) GenCloudInit() (*types.CloudInitConfig, error) {
+ cidr := g.IPNets[0].CIDR()
+ gwAddr := g.IPNets[0].GatewayAddr()
+ inSubnet := netx.InSubnet(gwAddr, cidr)
+ obj := &types.CloudInitConfig{
+ IFName: "ens5",
+ CIDR: cidr,
+ MAC: g.MAC,
+ MTU: g.MTU,
+ DefaultGW: types.CloudInitGateway{
+ IP: gwAddr,
+ OnLink: !inSubnet,
+ },
+ }
+ if bs, ok := g.JSONLabels["instance/cloud-init"]; ok {
+ if err := json.Unmarshal([]byte(bs), &obj); err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ } else {
+ obj.Username = configs.Conf.VMAuth.Username
+ obj.Password = configs.Conf.VMAuth.Password
+ }
+ if obj.Hostname == "" {
+ obj.Hostname = interutils.RandomString(10)
+ }
+ if obj.InstanceID == "" {
+ obj.InstanceID = obj.Hostname
+ }
+ return obj, nil
+}
+
func newGuest() *Guest {
return &Guest{
- Generic: newGeneric(),
- Vols: Volumes{},
+ Generic: meta.NewGeneric(),
+ Vols: volFact.Volumes{},
IPs: IPs{},
}
}
// LoadGuest .
func LoadGuest(id string) (*Guest, error) {
- return manager.LoadGuest(id)
-}
-
-// CreateGuest .
-func CreateGuest(opts types.GuestCreateOption, host *Host, vols []*Volume) (*Guest, error) {
- return manager.CreateGuest(opts, host, vols)
-}
-
-// NewGuest creates a new guest.
-func NewGuest(host *Host, img Image) (*Guest, error) {
- return manager.NewGuest(host, img)
-}
-
-// GetNodeGuests gets all guests which belong to the node.
-func GetNodeGuests(nodename string) ([]*Guest, error) {
- return manager.GetNodeGuests(nodename)
-}
-
-// GetAllGuests .
-func GetAllGuests() ([]*Guest, error) {
- return manager.GetAllGuests()
-}
-
-// LoadGuest .
-func (m *Manager) LoadGuest(id string) (*Guest, error) {
- g, err := m.NewGuest(nil, nil)
- if err != nil {
- return nil, errors.Trace(err)
- }
-
+ g := newGuest()
g.ID = id
if err := meta.Load(g); err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.WithMessagef(err, "load guest %s", id)
}
return g, nil
}
// CreateGuest .
-func (m *Manager) CreateGuest(opts types.GuestCreateOption, host *Host, vols []*Volume) (*Guest, error) {
- img, err := LoadImage(opts.ImageName, opts.ImageUser)
+func CreateGuest(opts types.GuestCreateOption, host *Host, vols []volume.Volume) (*Guest, error) {
+ img, err := vmiFact.LoadImage(context.TODO(), opts.ImageName)
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrapf(err, "failed to load image %s", opts.ImageName)
}
- guest, err := m.NewGuest(host, img)
- if err != nil {
- return nil, errors.Trace(err)
+ var guest = newGuest()
+ guest.Host = host
+ guest.HostName = guest.Host.Name
+ guest.NetworkMode = opts.Labels[network.ModeLabelKey]
+ if guest.NetworkMode == "" {
+ guest.NetworkMode = host.DefaultNetworkMode
+ opts.Labels[network.ModeLabelKey] = guest.NetworkMode
+ }
+ guest.MTU = 1500
+
+ guest.Img = img
+ guest.ImageName = img.Fullname()
+ // Create sys volume when user doesn't specify one
+ if len(vols) == 0 || (!vols[0].IsSys()) {
+ sysVol := local.NewSysVolume(img.VirtualSize, img.Fullname())
+ if err := guest.AppendVols(sysVol); err != nil {
+ return nil, errors.WithMessagef(err, "Create: failed to append volume %s", sysVol)
+ }
}
guest.ID = idgen.Next()
@@ -344,48 +372,60 @@ func (m *Manager) CreateGuest(opts types.GuestCreateOption, host *Host, vols []*
guest.DmiUUID = opts.DmiUUID
guest.JSONLabels = opts.Labels
- if guest.NetworkMode == vnet.NetworkCalico {
- guest.EnabledCalicoCNI = configs.Conf.EnabledCalicoCNI
- }
-
if opts.Lambda {
guest.LambdaOption = &LambdaOptions{
Cmd: opts.Cmd,
CmdOutput: nil,
}
}
+ log.Debugf(context.TODO(), "Resources: %v", opts.Resources)
+ if bs, ok := opts.Resources["gpu"]; ok {
+ var eParams gputypes.EngineParams
+ if err := json.Unmarshal(bs, &eParams); err != nil {
+ return nil, errors.Wrapf(err, "failed to unmarshal gpu params")
+ }
+ guest.GPUEngineParams = &eParams
+ }
+ if bs, ok := opts.Resources["bandwidth"]; ok {
+ var eParams bdtypes.EngineParams
+ if err := json.Unmarshal(bs, &eParams); err != nil {
+ return nil, errors.Wrapf(err, "failed to unmarshal bandwidth params")
+ }
+ guest.BDEngineParams = &eParams
+ }
if err := guest.AppendVols(vols...); err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.WithMessagef(err, "CreateGuest: failed to append volumes %v", vols)
}
if err := guest.Check(); err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.WithMessagef(err, "CreateGuest: failed to check guest %v", guest)
}
if err := guest.Create(); err != nil {
- return nil, errors.Trace(err)
+ return nil, err
}
return guest, nil
}
// NewGuest creates a new guest.
-func (m *Manager) NewGuest(host *Host, img Image) (*Guest, error) {
+func NewGuest(host *Host, img *vmitypes.Image) (*Guest, error) {
var guest = newGuest()
if host != nil {
guest.Host = host
guest.HostName = guest.Host.Name
- guest.NetworkMode = guest.Host.NetworkMode
+ guest.NetworkMode = guest.Host.DefaultNetworkMode
}
if img != nil {
guest.Img = img
- guest.ImageName = guest.Img.GetName()
- guest.ImageUser = guest.Img.GetUser()
- if err := guest.AppendVols(guest.Img.NewSysVolume()); err != nil {
- return nil, errors.Trace(err)
+ guest.ImageName = img.Fullname()
+
+ sysVol := local.NewSysVolume(img.VirtualSize, img.Fullname())
+ if err := guest.AppendVols(sysVol); err != nil {
+ return nil, errors.WithMessagef(err, "NewGuest: failed to append volume %s", sysVol)
}
}
@@ -393,13 +433,13 @@ func (m *Manager) NewGuest(host *Host, img Image) (*Guest, error) {
}
// GetNodeGuests gets all guests which belong to the node.
-func (m *Manager) GetNodeGuests(nodename string) ([]*Guest, error) {
+func GetNodeGuests(nodename string) ([]*Guest, error) {
ctx, cancel := meta.Context(context.Background())
defer cancel()
data, _, err := store.GetPrefix(ctx, meta.HostGuestsPrefix(nodename), 0)
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "failed to get prefix")
}
guests := []*Guest{}
@@ -410,9 +450,9 @@ func (m *Manager) GetNodeGuests(nodename string) ([]*Guest, error) {
continue
}
- g, err := m.LoadGuest(gid)
+ g, err := LoadGuest(gid)
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.WithMessagef(err, "GetNodeGuests: failed to load guest %s", gid)
}
guests = append(guests, g)
@@ -422,13 +462,13 @@ func (m *Manager) GetNodeGuests(nodename string) ([]*Guest, error) {
}
// GetAllGuests .
-func (m *Manager) GetAllGuests() ([]*Guest, error) {
+func GetAllGuests() ([]*Guest, error) {
var ctx, cancel = meta.Context(context.Background())
defer cancel()
var data, vers, err = store.GetPrefix(ctx, meta.GuestsPrefix(), 0)
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.WithMessagef(err, "GetAllGuests: failed to get prefix")
}
var guests = []*Guest{}
@@ -436,12 +476,12 @@ func (m *Manager) GetAllGuests() ([]*Guest, error) {
for key, val := range data {
var ver, exists = vers[key]
if !exists {
- return nil, errors.Annotatef(errors.ErrKeyBadVersion, key)
+ return nil, errors.Wrapf(terrors.ErrKeyBadVersion, key)
}
var g = newGuest()
if err := utils.JSONDecode(val, g); err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrapf(err, "GetAllGuests: failed to decode guest %s", key)
}
g.SetVer(ver)
diff --git a/internal/models/guest_status.go b/internal/models/guest_status.go
index d3367f3..e28dce1 100644
--- a/internal/models/guest_status.go
+++ b/internal/models/guest_status.go
@@ -1,87 +1,87 @@
package models
import (
+ "github.com/cockroachdb/errors"
"github.com/projecteru2/yavirt/internal/meta"
- "github.com/projecteru2/yavirt/pkg/errors"
)
// ForwardCreating .
func (g *Guest) ForwardCreating() error {
- return g.ForwardStatus(StatusCreating, false)
+ return g.ForwardStatus(meta.StatusCreating, false)
}
// ForwardStarting .
-func (g *Guest) ForwardStarting() error {
- return g.ForwardStatus(StatusStarting, false)
+func (g *Guest) ForwardStarting(force bool) error {
+ return g.ForwardStatus(meta.StatusStarting, force)
}
// ForwardStopped .
func (g *Guest) ForwardStopped(force bool) error {
- return g.ForwardStatus(StatusStopped, force)
+ return g.ForwardStatus(meta.StatusStopped, force)
}
// ForwardStopping .
func (g *Guest) ForwardStopping() error {
- return g.ForwardStatus(StatusStopping, false)
+ return g.ForwardStatus(meta.StatusStopping, false)
}
// ForwardCaptured .
func (g *Guest) ForwardCaptured() error {
- return g.ForwardStatus(StatusCaptured, false)
+ return g.ForwardStatus(meta.StatusCaptured, false)
}
// ForwardCapturing .
func (g *Guest) ForwardCapturing() error {
- return g.ForwardStatus(StatusCapturing, false)
+ return g.ForwardStatus(meta.StatusCapturing, false)
}
// ForwardDestroying .
func (g *Guest) ForwardDestroying(force bool) error {
- return g.ForwardStatus(StatusDestroying, force)
+ return g.ForwardStatus(meta.StatusDestroying, force)
}
// ForwardRunning .
func (g *Guest) ForwardRunning() error {
- return g.ForwardStatus(StatusRunning, false)
+ return g.ForwardStatus(meta.StatusRunning, false)
}
// ForwardPaused .
func (g *Guest) ForwardPaused() error {
- return g.ForwardStatus(StatusPaused, false)
+ return g.ForwardStatus(meta.StatusPaused, false)
}
// ForwardPausing .
func (g *Guest) ForwardPausing() error {
- return g.ForwardStatus(StatusPausing, false)
+ return g.ForwardStatus(meta.StatusPausing, false)
}
// ForwardResuming .
func (g *Guest) ForwardResuming() error {
- return g.ForwardStatus(StatusResuming, false)
+ return g.ForwardStatus(meta.StatusResuming, false)
}
// ForwardResizing .
func (g *Guest) ForwardResizing() error {
- return g.ForwardStatus(StatusResizing, false)
+ return g.ForwardStatus(meta.StatusResizing, false)
}
// ForwardMigrating .
func (g *Guest) ForwardMigrating() error {
- return g.ForwardStatus(StatusMigrating, false)
+ return g.ForwardStatus(meta.StatusMigrating, false)
}
// ForwardStatus .
func (g *Guest) ForwardStatus(st string, force bool) error {
- if err := g.setStatus(st, force); err != nil {
- return errors.Trace(err)
+ if err := g.SetStatus(st, force); err != nil {
+ return errors.WithMessagef(err, "ForwardStatus: failed to set guest status to %s", st)
}
- if err := g.Vols.setStatus(st, force); err != nil {
- return errors.Trace(err)
+ if err := g.Vols.SetStatus(st, force); err != nil {
+ return errors.WithMessagef(err, "ForwardStatus: failed to set volumes status to %s", st)
}
var res = meta.Resources{g}
- res.Concate(g.Vols.resources())
+ res.Concate(g.Vols.Resources())
return meta.Save(res)
}
diff --git a/internal/models/guest_test.go b/internal/models/guest_test.go
index 0b1ae5c..be40b6b 100644
--- a/internal/models/guest_test.go
+++ b/internal/models/guest_test.go
@@ -2,8 +2,6 @@ package models
import (
"context"
- "fmt"
- "strconv"
"testing"
erucluster "github.com/projecteru2/core/cluster"
@@ -11,7 +9,6 @@ import (
eruutils "github.com/projecteru2/core/utils"
"github.com/projecteru2/yavirt/pkg/test/assert"
- "github.com/projecteru2/yavirt/pkg/utils"
)
func TestEmptyLabels(t *testing.T) {
@@ -51,120 +48,120 @@ func TestValidLabels(t *testing.T) {
assert.Equal(t, 200, hc.HTTPCode)
}
-func TestRemoveVol(t *testing.T) {
- testcases := []struct {
- orig []int
- rm int
- ids []int
- }{
- // removes the first item.
- {
- []int{0},
- 0,
- []int{},
- },
- {
- []int{0, 1},
- 0,
- []int{1},
- },
- {
- []int{0, 1, 2},
- 0,
- []int{2, 1},
- },
- {
- []int{0, 1, 2, 3},
- 0,
- []int{3, 1, 2},
- },
- // removes the last item.
- {
- []int{0, 1},
- 1,
- []int{0},
- },
- {
- []int{0, 1, 2},
- 2,
- []int{0, 1},
- },
- {
- []int{0, 1, 2, 3},
- 3,
- []int{0, 1, 2},
- },
- // removes the medium item.
- {
- []int{0, 1, 2},
- 1,
- []int{0, 2},
- },
- {
- []int{0, 1, 2, 3},
- 2,
- []int{0, 1, 3},
- },
- {
- []int{0, 1, 2, 3},
- 1,
- []int{0, 3, 2},
- },
- // duplicated
- {
- []int{0, 0, 0},
- 0,
- []int{},
- },
- {
- []int{0, 0, 1},
- 0,
- []int{1},
- },
- {
- []int{0, 1, 1},
- 1,
- []int{0},
- },
- {
- []int{0, 1, 0, 1},
- 0,
- []int{1, 1},
- },
- {
- []int{0, 1, 0, 1},
- 1,
- []int{0, 0},
- },
- {
- []int{0, 1, 1, 0},
- 0,
- []int{1, 1},
- },
- {
- []int{0, 1, 1, 0},
- 1,
- []int{0, 0},
- },
- }
+// func TestRemoveVol(t *testing.T) {
+// testcases := []struct {
+// orig []int
+// rm int
+// ids []int
+// }{
+// // removes the first item.
+// {
+// []int{0},
+// 0,
+// []int{},
+// },
+// {
+// []int{0, 1},
+// 0,
+// []int{1},
+// },
+// {
+// []int{0, 1, 2},
+// 0,
+// []int{2, 1},
+// },
+// {
+// []int{0, 1, 2, 3},
+// 0,
+// []int{3, 1, 2},
+// },
+// // removes the last item.
+// {
+// []int{0, 1},
+// 1,
+// []int{0},
+// },
+// {
+// []int{0, 1, 2},
+// 2,
+// []int{0, 1},
+// },
+// {
+// []int{0, 1, 2, 3},
+// 3,
+// []int{0, 1, 2},
+// },
+// // removes the medium item.
+// {
+// []int{0, 1, 2},
+// 1,
+// []int{0, 2},
+// },
+// {
+// []int{0, 1, 2, 3},
+// 2,
+// []int{0, 1, 3},
+// },
+// {
+// []int{0, 1, 2, 3},
+// 1,
+// []int{0, 3, 2},
+// },
+// // duplicated
+// {
+// []int{0, 0, 0},
+// 0,
+// []int{},
+// },
+// {
+// []int{0, 0, 1},
+// 0,
+// []int{1},
+// },
+// {
+// []int{0, 1, 1},
+// 1,
+// []int{0},
+// },
+// {
+// []int{0, 1, 0, 1},
+// 0,
+// []int{1, 1},
+// },
+// {
+// []int{0, 1, 0, 1},
+// 1,
+// []int{0, 0},
+// },
+// {
+// []int{0, 1, 1, 0},
+// 0,
+// []int{1, 1},
+// },
+// {
+// []int{0, 1, 1, 0},
+// 1,
+// []int{0, 0},
+// },
+// }
- for _, tc := range testcases {
- g := newGuest()
- for _, id := range tc.orig {
- vol, err := NewDataVolume(fmt.Sprintf("/data%d", id), utils.GB)
- assert.NilErr(t, err)
+// for _, tc := range testcases {
+// g := newGuest()
+// for _, id := range tc.orig {
+// vol, err := NewDataVolume(fmt.Sprintf("/data%d", id), utils.GB, "")
+// assert.NilErr(t, err)
- vol.ID = strconv.Itoa(id)
- assert.NilErr(t, g.AppendVols(vol))
- }
+// vol.ID = strconv.Itoa(id)
+// assert.NilErr(t, g.AppendVols(vol))
+// }
- g.RemoveVol(strconv.Itoa(tc.rm))
- assert.Equal(t, len(tc.ids), g.Vols.Len())
- assert.Equal(t, len(tc.ids), len(g.VolIDs))
+// g.RemoveVol(strconv.Itoa(tc.rm))
+// assert.Equal(t, len(tc.ids), g.Vols.Len())
+// assert.Equal(t, len(tc.ids), len(g.VolIDs))
- for i, id := range tc.ids {
- assert.Equal(t, strconv.Itoa(id), g.Vols[i].ID)
- assert.Equal(t, strconv.Itoa(id), g.VolIDs[i])
- }
- }
-}
+// for i, id := range tc.ids {
+// assert.Equal(t, strconv.Itoa(id), g.Vols[i].GetID())
+// assert.Equal(t, strconv.Itoa(id), g.VolIDs[i])
+// }
+// }
+// }
diff --git a/internal/models/health_check.go b/internal/models/health_check.go
index c1082b8..2dc2ff5 100644
--- a/internal/models/health_check.go
+++ b/internal/models/health_check.go
@@ -8,15 +8,16 @@ import (
erucluster "github.com/projecteru2/core/cluster"
+ "github.com/cockroachdb/errors"
"github.com/projecteru2/yavirt/internal/meta"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/projecteru2/yavirt/pkg/terrors"
"github.com/projecteru2/yavirt/pkg/utils"
)
func (g *Guest) healthCheckBridge() (*HealthCheckBridge, error) {
raw, exists := g.JSONLabels[erucluster.LabelMeta]
if !exists {
- return nil, errors.Annotatef(errors.ErrKeyNotExists, "no such label: %s", erucluster.LabelMeta)
+ return nil, errors.Wrapf(terrors.ErrKeyNotExists, "no such label: %s", erucluster.LabelMeta)
}
hcb := &HealthCheckBridge{}
diff --git a/internal/models/host.go b/internal/models/host.go
index 47886a6..e5b286d 100644
--- a/internal/models/host.go
+++ b/internal/models/host.go
@@ -4,8 +4,8 @@ import (
"fmt"
"github.com/projecteru2/yavirt/configs"
+ "github.com/projecteru2/yavirt/internal/eru/resources"
"github.com/projecteru2/yavirt/internal/meta"
- "github.com/projecteru2/yavirt/pkg/netx"
)
// Host .
@@ -14,42 +14,56 @@ import (
// /hosts:counter
// /hosts/
type Host struct {
- *Generic
+ *meta.Generic
- ID uint32 `json:"id"`
- Name string `json:"name"`
- Type string `json:"type"`
- Subnet int64 `json:"subnet"`
- CPU int `json:"cpu"`
- Memory int64 `json:"mem"`
- Storage int64 `json:"storage"`
- NetworkMode string `json:"network,omitempty"`
+ ID uint32 `json:"id"`
+ Name string `json:"name"`
+ Type string `json:"type"`
+ Subnet int64 `json:"subnet"`
+ CPU int `json:"cpu"`
+ Memory int64 `json:"mem"`
+ Storage int64 `json:"storage"`
+ NetworkModes []string `json:"network,omitempty"`
+ DefaultNetworkMode string `json:"default_network,omitempty"`
}
// LoadHost .
func LoadHost() (*Host, error) {
- host := &Host{
- Generic: newGeneric(),
- Name: configs.Conf.Host.Name,
- Type: HostVirtType,
- Subnet: int64(configs.Conf.Host.Subnet),
- CPU: configs.Conf.Host.CPU,
- Memory: int64(configs.Conf.Host.Memory),
- Storage: int64(configs.Conf.Host.Storage),
- NetworkMode: configs.Conf.Host.NetworkMode,
+ cfg := &configs.Conf
+ cpu, mem, sto := cfg.Host.CPU, int64(cfg.Host.Memory), int64(cfg.Host.Storage)
+ // update cpu, memory, storage using hardware information
+ if cpu == 0 || mem == 0 {
+ cpumem := resources.GetManager().FetchCPUMem()
+ if cpu == 0 {
+ cpu = int(cpumem.CPU)
+ }
+ if mem == 0 {
+ mem = cpumem.Memory
+ }
}
- dec, err := netx.IPv4ToInt(configs.Conf.Host.Addr)
- if err != nil {
- return nil, err
+ if sto == 0 {
+ storage := resources.GetManager().FetchStorage()
+ sto = storage.Storage
}
- host.ID = uint32(dec)
+ host := &Host{
+ Generic: meta.NewGeneric(),
+ ID: cfg.Host.ID,
+ Name: cfg.Host.Name,
+ Type: HostVirtType,
+ Subnet: int64(cfg.Host.Subnet),
+ CPU: cpu,
+ Memory: mem,
+ Storage: sto,
+ NetworkModes: cfg.Network.Modes,
+ DefaultNetworkMode: cfg.Network.DefaultMode,
+ }
return host, nil
}
// NewHost .
func NewHost() *Host {
- return &Host{Generic: newGeneric()}
+ return &Host{Generic: meta.NewGeneric()}
}
// MetaKey .
diff --git a/internal/models/host_test.go b/internal/models/host_test.go
index e18a307..1c29ea2 100644
--- a/internal/models/host_test.go
+++ b/internal/models/host_test.go
@@ -1,11 +1,9 @@
package models
import (
- "time"
-
"github.com/projecteru2/yavirt/pkg/idgen"
)
func init() {
- idgen.Setup(0, time.Now())
+ idgen.Setup(0)
}
diff --git a/internal/models/image.go b/internal/models/image.go
deleted file mode 100644
index 7555a00..0000000
--- a/internal/models/image.go
+++ /dev/null
@@ -1,53 +0,0 @@
-package models
-
-import (
- "os"
-
- "github.com/projecteru2/yavirt/pkg/errors"
-)
-
-// Image wraps a few methods about Image.
-type Image interface { //nolint
- GetName() string
- GetUser() string
- GetDistro() string
- GetID() string
- GetType() string
- GetHash() string
- UpdateHash() (string, error)
-
- NewSysVolume() *Volume
- Delete() error
-
- String() string
- Filepath() string
- Filename() string
-}
-
-// LoadImage loads an Image.
-func LoadImage(name, user string) (Image, error) {
- if len(user) > 0 {
- return LoadUserImage(user, name)
- }
- return LoadSysImage(name)
-}
-
-// ListImages lists all images which belong to a specific user, or system-wide type.
-func ListImages(user string) ([]Image, error) {
- if len(user) > 0 {
- return ListUserImages(user)
- }
- return ListSysImages()
-}
-
-// ImageExists whether the image file exists.
-func ImageExists(img Image) (bool, error) {
- switch _, err := os.Stat(img.Filepath()); {
- case err == nil:
- return true, nil
- case os.IsNotExist(err):
- return false, nil
- default:
- return false, errors.Trace(err)
- }
-}
diff --git a/internal/models/ipblock.go b/internal/models/ipblock.go
index 5730cf4..abb8d71 100644
--- a/internal/models/ipblock.go
+++ b/internal/models/ipblock.go
@@ -3,9 +3,10 @@ package models
import (
"net"
+ "github.com/cockroachdb/errors"
"github.com/projecteru2/yavirt/internal/meta"
- "github.com/projecteru2/yavirt/pkg/errors"
"github.com/projecteru2/yavirt/pkg/netx"
+ "github.com/projecteru2/yavirt/pkg/terrors"
"github.com/projecteru2/yavirt/pkg/utils"
)
@@ -22,7 +23,7 @@ func (bs *IPBlocks) Append(block ...*IPBlock) {
// IPBlock .
type IPBlock struct {
- *Generic
+ *meta.Generic
IPs *utils.Bitmap32 `json:"ips"`
@@ -32,12 +33,12 @@ type IPBlock struct {
func newIPBlock(ipp *IPPool, ipn *net.IPNet) *IPBlock {
block := &IPBlock{
- Generic: newGeneric(),
+ Generic: meta.NewGeneric(),
ippool: ipp,
ipnet: ipn,
}
- block.Status = StatusRunning
+ block.Status = meta.StatusRunning
block.IPs = utils.NewBitmap32(block.ipCount())
return block
@@ -46,17 +47,17 @@ func newIPBlock(ipp *IPPool, ipn *net.IPNet) *IPBlock {
// Release .
func (b *IPBlock) Release(ipn *net.IPNet) error {
if !b.ippool.Contains(ipn) {
- return errors.Annotatef(errors.ErrInsufficientIP, "IP %s not found", ipn.IP)
+ return errors.Wrapf(terrors.ErrInsufficientIP, "IP %s not found", ipn.IP)
}
offset := b.getIPIndex(ipn.IP)
if err := b.IPs.Unset(offset); err != nil {
- return errors.Annotatef(err, "release %d IP %s failed", offset, ipn)
+ return errors.Wrapf(err, "release %d IP %s failed", offset, ipn)
}
if err := b.save(); err != nil {
b.IPs.Set(offset) //nolint
- return errors.Trace(err)
+ return errors.Wrapf(err, "release %d IP %s failed", offset, ipn)
}
return nil
@@ -90,7 +91,7 @@ func (b *IPBlock) Assign() (ipn *net.IPNet, err error) {
})
if err == nil && ipn == nil {
- err = errors.Annotatef(errors.ErrInsufficientIP,
+ err = errors.Wrapf(terrors.ErrInsufficientIP,
"block %s hasn't free IP", b.ipnet)
}
@@ -104,12 +105,12 @@ func (b *IPBlock) assign(offset int) (*net.IPNet, error) {
}
if err := b.IPs.Set(offset); err != nil {
- return nil, errors.Annotatef(err, "assign %d IP %s failed", offset, ipn)
+ return nil, errors.Wrapf(err, "assign %d IP %s failed", offset, ipn)
}
if err := b.save(); err != nil {
b.IPs.Unset(offset) //nolint
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
return ipn, nil
diff --git a/internal/models/ippool.go b/internal/models/ippool.go
index 4016748..fe2996a 100644
--- a/internal/models/ippool.go
+++ b/internal/models/ippool.go
@@ -7,16 +7,17 @@ import (
clientv3 "go.etcd.io/etcd/client/v3"
+ "github.com/cockroachdb/errors"
"github.com/projecteru2/yavirt/internal/meta"
- "github.com/projecteru2/yavirt/pkg/errors"
"github.com/projecteru2/yavirt/pkg/netx"
"github.com/projecteru2/yavirt/pkg/store"
+ "github.com/projecteru2/yavirt/pkg/terrors"
"github.com/projecteru2/yavirt/pkg/utils"
)
// IPPool .
type IPPool struct {
- *Generic
+ *meta.Generic
Name string `json:"name"`
Raw string `json:"raw"`
@@ -34,7 +35,7 @@ func LoadIPPool(name string) (*IPPool, error) {
ipp := newIPPool(name)
if err := meta.Load(ipp); err != nil {
- return nil, errors.Annotatef(err, "load IPPool %s failed", name)
+ return nil, errors.WithMessagef(err, "load IPPool %s failed", name)
}
return ipp, ipp.parse()
@@ -52,27 +53,27 @@ func NewIPPool(name, cidr string) (ipp *IPPool, err error) {
func newIPPool(name string) *IPPool {
ipp := &IPPool{
- Generic: newGeneric(),
+ Generic: meta.NewGeneric(),
Name: name,
blocks: IPBlocks{},
sync: true,
}
- ipp.Status = StatusRunning
+ ipp.Status = meta.StatusRunning
return ipp
}
func (ipp *IPPool) parse() (err error) {
if _, ipp.ipnet, err = netx.ParseCIDR(ipp.Raw); err != nil {
- return errors.Annotatef(err, "parse CIDR %s failed", ipp.Raw)
+ return errors.Wrapf(err, "parse CIDR %s failed", ipp.Raw)
}
switch {
case ipp.MaskBits() > MaxMaskBits:
- return errors.Annotatef(errors.ErrTooLargeMaskBits, "at most", MaxMaskBits)
+ return errors.Wrapf(terrors.ErrTooLargeMaskBits, "at most", MaxMaskBits)
case ipp.MaskBits() < MinMaskBits:
- return errors.Annotatef(errors.ErrTooSmallMaskBits, "at least", MinMaskBits)
+ return errors.Wrapf(terrors.ErrTooSmallMaskBits, "at least", MinMaskBits)
}
ipp.CIDR = fmt.Sprintf("%s/%d", ipp.Subnet().String(), ipp.MaskBits())
@@ -89,7 +90,7 @@ func (ipp *IPPool) Assign() (ipn *net.IPNet, err error) {
}
defer func() {
if ue := unlock(context.Background()); ue != nil {
- err = errors.Wrap(err, ue)
+ err = errors.CombineErrors(err, ue)
}
}()
@@ -125,7 +126,7 @@ func (ipp *IPPool) getAvailBlock() (block *IPBlock, err error) {
// there's no any available block.
if err == nil && block == nil {
- err = errors.Annotatef(errors.ErrInsufficientIP,
+ err = errors.Wrapf(terrors.ErrInsufficientIP,
"%s CIDR %s hasn't free IP", ipp.Name, ipp.ipnet)
}
@@ -135,7 +136,7 @@ func (ipp *IPPool) getAvailBlock() (block *IPBlock, err error) {
// Release .
func (ipp *IPPool) Release(ipn *net.IPNet) (err error) {
if !ipp.Contains(ipn) {
- return errors.Annotatef(errors.ErrInvalidValue, "%s doesn't contain %s", ipp.Name, ipn)
+ return errors.Wrapf(terrors.ErrInvalidValue, "%s doesn't contain %s", ipp.Name, ipn)
}
var unlock utils.Unlocker
@@ -144,7 +145,7 @@ func (ipp *IPPool) Release(ipn *net.IPNet) (err error) {
}
defer func() {
if ue := unlock(context.Background()); ue != nil {
- err = errors.Wrap(err, ue)
+ err = errors.CombineErrors(err, ue)
}
}()
@@ -165,7 +166,7 @@ func (ipp *IPPool) Release(ipn *net.IPNet) (err error) {
// IsAssigned .
func (ipp *IPPool) IsAssigned(ipn *net.IPNet) (assigned bool, err error) {
if !ipp.Contains(ipn) {
- return false, errors.Annotatef(errors.ErrInvalidValue, "%s doesn't contain %s", ipp.Name, ipn)
+ return false, errors.Wrapf(terrors.ErrInvalidValue, "%s doesn't contain %s", ipp.Name, ipn)
}
var unlock utils.Unlocker
@@ -174,7 +175,7 @@ func (ipp *IPPool) IsAssigned(ipn *net.IPNet) (assigned bool, err error) {
}
defer func() {
if ue := unlock(context.Background()); ue != nil {
- err = errors.Wrap(err, ue)
+ err = errors.CombineErrors(err, ue)
}
}()
@@ -194,7 +195,7 @@ func (ipp *IPPool) getBlock(ipn *net.IPNet) (*IPBlock, error) {
i := ipp.getBlockIndex(ipn.IP)
if int64(ipp.blocks.Len()) <= i {
- return nil, errors.Annotatef(errors.ErrInsufficientBlocks,
+ return nil, errors.Wrapf(terrors.ErrInsufficientBlocks,
"block %s not found", netx.Int2ip(ipp.intSubnet()+i))
}
@@ -222,7 +223,7 @@ func (ipp *IPPool) Contains(ipn *net.IPNet) bool {
func (ipp *IPPool) spawnBlock(offset int) (block *IPBlock, err error) {
if err = ipp.Flags.Set(offset); err != nil {
- return nil, errors.Annotatef(err, "spawn %d block %s failed",
+ return nil, errors.Wrapf(err, "spawn %d block %s failed",
offset, netx.Int2ip(ipp.intSubnet()+int64(offset)))
}
@@ -240,7 +241,7 @@ func (ipp *IPPool) spawnBlock(offset int) (block *IPBlock, err error) {
func (ipp *IPPool) reload() error {
newOne := newIPPool(ipp.Name)
if err := meta.Load(newOne); err != nil {
- return errors.Annotatef(err, "load IPPool %s failed", ipp.Name)
+ return errors.Wrapf(err, "load IPPool %s failed", ipp.Name)
}
ipp.Flags = newOne.Flags
@@ -257,11 +258,11 @@ func (ipp *IPPool) reloadBlocks() error {
data, vers, err := store.GetPrefix(ctx, prefix, int64(ipp.blockCount()))
if err != nil {
// there's no any block yet.
- if errors.Contain(err, errors.ErrKeyNotExists) {
+ if errors.Is(err, terrors.ErrKeyNotExists) {
return nil
}
- return errors.Annotatef(err, "get IPPool %s all blocks failed", ipp.Name)
+ return errors.Wrapf(err, "get IPPool %s all blocks failed", ipp.Name)
}
delete(data, prefix)
@@ -275,31 +276,31 @@ func (ipp *IPPool) parseBlocksBytes(data map[string][]byte, vers map[string]int6
for key, bytes := range data {
ver, exists := vers[key]
if !exists {
- return errors.Annotatef(errors.ErrKeyBadVersion, key)
+ return errors.Wrapf(terrors.ErrKeyBadVersion, key)
}
ipn, err := ipp.parseBlockMetaKey(key)
if err != nil {
- return errors.Annotatef(err, "parse block key %s failed", key)
+ return errors.Wrapf(err, "parse block key %s failed", key)
}
block := newIPBlock(ipp, ipn)
if err := utils.JSONDecode(bytes, block); err != nil {
- return errors.Annotatef(err, "decode IPBlock bytes %s failed", bytes)
+ return errors.Wrapf(err, "decode IPBlock bytes %s failed", bytes)
}
block.SetVer(ver)
i := ipp.getBlockIndex(block.BlockIP())
if int64(blocks.Len()) <= i {
- return errors.Annotatef(errors.ErrInsufficientBlocks, "%d block %s not found", i, ipn)
+ return errors.Wrapf(terrors.ErrInsufficientBlocks, "%d block %s not found", i, ipn)
}
blocks[i] = block
}
if err := ipp.checkBlocks(blocks); err != nil {
- return errors.Trace(err)
+ return errors.WithMessagef(err, "parse blocks %s failed", blocks)
}
ipp.blocks = blocks
@@ -318,7 +319,7 @@ func (ipp *IPPool) checkBlocks(blocks IPBlocks) (err error) {
return true
}
- err = errors.Annotatef(errors.ErrInvalidValue,
+ err = errors.Wrapf(terrors.ErrInvalidValue,
"IPPool %s %d block %s should be spawned (%t) but not",
ipp.ipnet, offset, ipp.getBlockIPNet(offset), set)
@@ -346,12 +347,12 @@ func (ipp *IPPool) save(block *IPBlock) error {
ippBytes, err := ipp.Marshal()
if err != nil {
- return errors.Trace(err)
+ return errors.Wrapf(err, "failed to marshal %s", ipp)
}
blockBytes, err := block.Marshal()
if err != nil {
- return errors.Trace(err)
+ return errors.Wrapf(err, "failed to marshal %s", block)
}
ops := []clientv3.Op{
@@ -364,9 +365,9 @@ func (ipp *IPPool) save(block *IPBlock) error {
switch succ, err := store.BatchOperate(ctx, ops); {
case err != nil:
- return errors.Trace(err)
+ return errors.Wrap(err, "failed to batch operate")
case !succ:
- return errors.Annotatef(errors.ErrBatchOperate,
+ return errors.Wrapf(terrors.ErrBatchOperate,
"put: %s / %s", ipp.MetaKey(), block.MetaKey())
}
diff --git a/internal/models/mocks/Manageable.go b/internal/models/mocks/Manageable.go
deleted file mode 100644
index 192e1ed..0000000
--- a/internal/models/mocks/Manageable.go
+++ /dev/null
@@ -1,130 +0,0 @@
-// Code generated by mockery v1.0.0. DO NOT EDIT.
-
-package mocks
-
-import (
- models "github.com/projecteru2/yavirt/internal/models"
- mock "github.com/stretchr/testify/mock"
-
- types "github.com/projecteru2/yavirt/internal/virt/types"
-)
-
-// Manageable is an autogenerated mock type for the Manageable type
-type Manageable struct {
- mock.Mock
-}
-
-// CreateGuest provides a mock function with given fields: opts, host, vols
-func (_m *Manageable) CreateGuest(opts types.GuestCreateOption, host *models.Host, vols []*models.Volume) (*models.Guest, error) {
- ret := _m.Called(opts, host, vols)
-
- var r0 *models.Guest
- if rf, ok := ret.Get(0).(func(types.GuestCreateOption, *models.Host, []*models.Volume) *models.Guest); ok {
- r0 = rf(opts, host, vols)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(*models.Guest)
- }
- }
-
- var r1 error
- if rf, ok := ret.Get(1).(func(types.GuestCreateOption, *models.Host, []*models.Volume) error); ok {
- r1 = rf(opts, host, vols)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// GetAllGuests provides a mock function with given fields:
-func (_m *Manageable) GetAllGuests() ([]*models.Guest, error) {
- ret := _m.Called()
-
- var r0 []*models.Guest
- if rf, ok := ret.Get(0).(func() []*models.Guest); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]*models.Guest)
- }
- }
-
- var r1 error
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// GetNodeGuests provides a mock function with given fields: nodename
-func (_m *Manageable) GetNodeGuests(nodename string) ([]*models.Guest, error) {
- ret := _m.Called(nodename)
-
- var r0 []*models.Guest
- if rf, ok := ret.Get(0).(func(string) []*models.Guest); ok {
- r0 = rf(nodename)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]*models.Guest)
- }
- }
-
- var r1 error
- if rf, ok := ret.Get(1).(func(string) error); ok {
- r1 = rf(nodename)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// LoadGuest provides a mock function with given fields: id
-func (_m *Manageable) LoadGuest(id string) (*models.Guest, error) {
- ret := _m.Called(id)
-
- var r0 *models.Guest
- if rf, ok := ret.Get(0).(func(string) *models.Guest); ok {
- r0 = rf(id)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(*models.Guest)
- }
- }
-
- var r1 error
- if rf, ok := ret.Get(1).(func(string) error); ok {
- r1 = rf(id)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// NewGuest provides a mock function with given fields: host, img
-func (_m *Manageable) NewGuest(host *models.Host, img models.Image) (*models.Guest, error) {
- ret := _m.Called(host, img)
-
- var r0 *models.Guest
- if rf, ok := ret.Get(0).(func(*models.Host, models.Image) *models.Guest); ok {
- r0 = rf(host, img)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(*models.Guest)
- }
- }
-
- var r1 error
- if rf, ok := ret.Get(1).(func(*models.Host, models.Image) error); ok {
- r1 = rf(host, img)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
diff --git a/internal/models/mocks/mock.go b/internal/models/mocks/mock.go
deleted file mode 100644
index d1d7baf..0000000
--- a/internal/models/mocks/mock.go
+++ /dev/null
@@ -1,10 +0,0 @@
-package mocks
-
-import "github.com/projecteru2/yavirt/internal/models"
-
-func Mock() (*Manageable, func()) {
- var origManager = models.GetManager()
- var mockManager = &Manageable{}
- models.SetManager(mockManager)
- return mockManager, func() { models.SetManager(origManager) }
-}
diff --git a/internal/models/model.go b/internal/models/model.go
deleted file mode 100644
index a7c4709..0000000
--- a/internal/models/model.go
+++ /dev/null
@@ -1,27 +0,0 @@
-package models
-
-import "github.com/projecteru2/yavirt/internal/virt/types"
-
-type Manageable interface {
- GetAllGuests() ([]*Guest, error)
- GetNodeGuests(nodename string) ([]*Guest, error)
- LoadGuest(id string) (*Guest, error)
- CreateGuest(opts types.GuestCreateOption, host *Host, vols []*Volume) (*Guest, error)
- NewGuest(host *Host, img Image) (*Guest, error)
-}
-
-type Manager struct{}
-
-var manager Manageable
-
-func Setup() {
- manager = &Manager{}
-}
-
-func GetManager() Manageable {
- return manager
-}
-
-func SetManager(m Manageable) {
- manager = m
-}
diff --git a/internal/models/option.go b/internal/models/option.go
new file mode 100644
index 0000000..c3fd227
--- /dev/null
+++ b/internal/models/option.go
@@ -0,0 +1,21 @@
+package models
+
+type Op struct {
+ IgnoreLoadImageErr bool
+}
+
+type Option func(*Op)
+
+func IgnoreLoadImageErrOption() Option {
+ return func(op *Op) {
+ op.IgnoreLoadImageErr = true
+ }
+}
+
+func NewOp(opts ...Option) *Op {
+ op := &Op{}
+ for _, opt := range opts {
+ opt(op)
+ }
+ return op
+}
diff --git a/internal/models/sys_image.go b/internal/models/sys_image.go
deleted file mode 100644
index 122b0ea..0000000
--- a/internal/models/sys_image.go
+++ /dev/null
@@ -1,185 +0,0 @@
-package models
-
-import (
- "context"
- "crypto/sha256"
- "fmt"
- "io"
- "math"
- "os"
-
- "github.com/projecteru2/yavirt/internal/meta"
- "github.com/projecteru2/yavirt/pkg/errors"
- "github.com/projecteru2/yavirt/pkg/store"
- "github.com/projecteru2/yavirt/pkg/utils"
-)
-
-// SysImage indicates a system image
-type SysImage struct {
- *Generic
- ParentName string `json:"parent,omitempty"`
- Name string `json:"name"`
- Size int64 `json:"size"`
- Hash string `json:"sha256"`
-}
-
-// NewSysImage creates a new system-wide image.
-func NewSysImage() *SysImage {
- return &SysImage{Generic: newGeneric()}
-}
-
-// ListSysImages lists all system-wide images.
-func ListSysImages() ([]Image, error) {
- ctx, cancel := meta.Context(context.TODO())
- defer cancel()
-
- prefix := meta.SysImagePrefix()
- data, vers, err := store.GetPrefix(ctx, prefix, math.MaxInt64)
- if err != nil {
- if errors.Contain(err, errors.ErrKeyNotExists) {
- return nil, nil
- }
- return nil, errors.Annotatef(err, "get sys images failed")
- }
-
- delete(data, prefix)
-
- return parseSysImages(data, vers)
-}
-
-func parseSysImages(data map[string][]byte, vers map[string]int64) ([]Image, error) {
- imgs := make([]Image, 0, len(data))
-
- for key, bytes := range data {
- ver, exists := vers[key]
- if !exists {
- return nil, errors.Annotatef(errors.ErrKeyBadVersion, key)
- }
-
- img := NewSysImage()
- if err := utils.JSONDecode(bytes, img); err != nil {
- return nil, errors.Annotatef(err, "decode SysImage bytes %s failed", bytes)
- }
-
- img.SetVer(ver)
-
- imgs = append(imgs, img)
- }
-
- return imgs, nil
-}
-
-// LoadSysImage loads a system-wide image.
-func LoadSysImage(name string) (*SysImage, error) {
- img := NewSysImage()
- img.Name = name
- if err := meta.Load(img); err != nil {
- return nil, errors.Trace(err)
- }
- return img, nil
-}
-
-// String .
-func (img *SysImage) String() string {
- return fmt.Sprintf("sys-image: %s", img.GetName())
-}
-
-// GetType gets the image's type.
-func (img *SysImage) GetType() string {
- return ImageSys
-}
-
-// GetHash gets the image's hash.
-func (img *SysImage) GetHash() string {
- return img.Hash
-}
-
-// UpdateHash update and return the image's hash .
-func (img *SysImage) UpdateHash() (string, error) {
- exists, err := ImageExists(img)
- if err != nil {
- return "", err
- }
- if !exists {
- // TODO: Pull image?
- return "", errors.ErrImageFileNotExists
- }
-
- f, err := os.Open(img.Filepath())
- if err != nil {
- return "", err
- }
- defer f.Close()
-
- hash := sha256.New()
- if _, err := io.Copy(hash, f); err != nil {
- return "", err
- }
-
- img.Hash = fmt.Sprintf("%x", hash.Sum(nil))
-
- return img.Hash, img.Save()
-}
-
-// Save updated metadata.
-func (img *SysImage) Save() error {
- return meta.Save(meta.Resources{img})
-}
-
-// GetID gets the image's ID which will be uploaded to image hub.
-func (img *SysImage) GetID() string {
- return img.Name
-}
-
-// GetName gets image's name
-func (img *SysImage) GetName() string {
- return img.Name
-}
-
-// GetUser gets the system-wide image's owner name
-func (img *SysImage) GetUser() string {
- return ""
-}
-
-// Create .
-func (img *SysImage) Create() error {
- img.Status = StatusRunning
- return meta.Create(meta.Resources{img})
-}
-
-// Delete removes the system-wide image.
-func (img *SysImage) Delete() error {
- ctx, cancel := meta.Context(context.TODO())
- defer cancel()
-
- return store.Delete(
- ctx,
- []string{img.MetaKey()},
- map[string]int64{img.MetaKey(): img.GetVer()},
- )
-}
-
-// MetaKey .
-func (img *SysImage) MetaKey() string {
- return meta.SysImageKey(img.Name)
-}
-
-// NewSysVolume generates a new volume for OS' system disk.
-func (img *SysImage) NewSysVolume() *Volume {
- return NewSysVolume(img.Size, img.Name)
-}
-
-// Filepath gets a system-wide image's absolute filepath.
-func (img *SysImage) Filepath() string {
- return img.JoinVirtPath(img.Filename())
-}
-
-// Filename generates a system-wide image's filename without any path info.
-func (img *SysImage) Filename() string {
- return fmt.Sprintf("%s.img", img.Name)
-}
-
-// GetDistro gets the system-wide image's distro.
-func (img *SysImage) GetDistro() string {
- return img.Name[:6]
-}
diff --git a/internal/models/user_image.go b/internal/models/user_image.go
deleted file mode 100644
index c856166..0000000
--- a/internal/models/user_image.go
+++ /dev/null
@@ -1,146 +0,0 @@
-package models
-
-import (
- "context"
- "fmt"
- "math"
-
- "github.com/projecteru2/yavirt/internal/meta"
- "github.com/projecteru2/yavirt/pkg/errors"
- "github.com/projecteru2/yavirt/pkg/store"
- "github.com/projecteru2/yavirt/pkg/utils"
-)
-
-// UserImage .
-type UserImage struct {
- *SysImage
- User string `json:"user"`
- Distro string `json:"distro"`
- Version int64 `json:"version"`
-}
-
-// NewUserImage creates a new user captured image.
-func NewUserImage(user, name string, size int64) *UserImage {
- img := &UserImage{SysImage: NewSysImage()}
- img.Name = name
- img.Size = size
- img.User = user
- return img
-}
-
-// ListUserImages list all images which belongs to the user.
-func ListUserImages(user string) ([]Image, error) {
- ctx, cancel := meta.Context(context.TODO())
- defer cancel()
-
- prefix := meta.UserImagePrefix(user)
- data, vers, err := store.GetPrefix(ctx, prefix, math.MaxInt64)
- if err != nil {
- if errors.Contain(err, errors.ErrKeyNotExists) {
- return nil, nil
- }
- return nil, errors.Annotatef(err, "get sys images failed")
- }
-
- delete(data, prefix)
-
- return parseUserImages(data, vers)
-}
-
-func parseUserImages(data map[string][]byte, vers map[string]int64) ([]Image, error) {
- imgs := make([]Image, 0, len(data))
-
- for key, bytes := range data {
- ver, exists := vers[key]
- if !exists {
- return nil, errors.Annotatef(errors.ErrKeyBadVersion, key)
- }
-
- img := &UserImage{SysImage: NewSysImage()}
- if err := utils.JSONDecode(bytes, img); err != nil {
- return nil, errors.Annotatef(err, "decode SysImage bytes %s failed", bytes)
- }
-
- img.SetVer(ver)
-
- imgs = append(imgs, img)
- }
-
- return imgs, nil
-}
-
-// LoadUserImage loads a user captured image.
-func LoadUserImage(user, name string) (*UserImage, error) {
- i := NewUserImage(user, name, 0)
- return i, meta.Load(i)
-}
-
-// String .
-func (i UserImage) String() string {
- return fmt.Sprintf("usr-image: %s, distro: %s, owner: %s", i.GetName(), i.GetDistro(), i.GetUser())
-}
-
-// GetType gets the image's type.
-func (i UserImage) GetType() string {
- return ImageUser
-}
-
-// GetID gets the user captured image's ID which will be pushed to image hub.
-func (i UserImage) GetID() string {
- return fmt.Sprintf("%s_%s", i.User, i.Name)
-}
-
-// GetUser gets the user captured image's owner name.
-func (i UserImage) GetUser() string {
- return i.User
-}
-
-// Filepath gets a user captured image's absolute filepath.
-func (i UserImage) Filepath() string {
- return i.JoinVirtPath(i.Filename())
-}
-
-// Filename generates a user captured image's filename without any path info.
-func (i UserImage) Filename() string {
- return fmt.Sprintf("%s-%s-%s-%d.uimg", i.Distro, i.User, i.Name, i.Version)
-}
-
-// Delete removes the system-wide image
-func (i UserImage) Delete() error {
- ctx, cancel := meta.Context(context.TODO())
- defer cancel()
-
- return store.Delete(
- ctx,
- []string{i.MetaKey()},
- map[string]int64{i.MetaKey(): i.GetVer()},
- )
-}
-
-// NextVersion .
-func (i *UserImage) NextVersion() error {
- // TODO
- // it should be distributed calculation/update, which means unique in global.
- return nil
-}
-
-// Save updates metadata.
-func (i *UserImage) Save() error {
- return meta.Save(meta.Resources{i})
-}
-
-// Create creates a new user image to metadata.
-func (i *UserImage) Create() error {
- i.Status = StatusRunning
- return meta.Create(meta.Resources{i})
-}
-
-// MetaKey .
-func (i *UserImage) MetaKey() string {
- return meta.UserImageKey(i.User, i.Name)
-}
-
-// GetDistro gets the user captured image's distro.
-func (i UserImage) GetDistro() string {
- return i.Distro
-}
diff --git a/internal/models/volume.go b/internal/models/volume.go
deleted file mode 100644
index 099d647..0000000
--- a/internal/models/volume.go
+++ /dev/null
@@ -1,380 +0,0 @@
-package models
-
-import (
- "context"
- "fmt"
- "path/filepath"
- "strings"
-
- "github.com/projecteru2/yavirt/configs"
- "github.com/projecteru2/yavirt/internal/meta"
- "github.com/projecteru2/yavirt/pkg/errors"
- "github.com/projecteru2/yavirt/pkg/idgen"
- "github.com/projecteru2/yavirt/pkg/store"
- "github.com/projecteru2/yavirt/pkg/utils"
-)
-
-// Volume .
-// etcd keys:
-//
-// /vols/
-type Volume struct {
- *Generic
- Type string `json:"type"`
- MountDir string `json:"mount,omitempty"`
- HostDir string `json:"host_dir,omitempty"`
- Capacity int64 `json:"capacity"`
- Format string `json:"format"`
- HostName string `json:"host"`
- GuestID string `json:"guest"`
- ImageName string `json:"image,omitempty"`
- SnapIDs []string `json:"snaps"`
- BaseSnapshotID string `json:"base_snapshot_id"`
-
- Snaps Snapshots `json:"-"`
-}
-
-// LoadVolume .
-func LoadVolume(id string) (*Volume, error) {
- var vol = newVolume()
- vol.ID = id
-
- if err := meta.Load(vol); err != nil {
- return nil, err
- }
-
- return vol, vol.Load()
-}
-
-// NewDataVolume .
-func NewDataVolume(mnt string, cap int64) (*Volume, error) {
- mnt = strings.TrimSpace(mnt)
-
- src, dest := utils.PartRight(mnt, ":")
- src = strings.TrimSpace(src)
- dest = filepath.Join("/", strings.TrimSpace(dest))
-
- if len(src) > 0 {
- src = filepath.Join("/", src)
- }
-
- var vol = NewVolume(VolDataType, cap)
- vol.HostDir = src
- vol.MountDir = dest
-
- return vol, vol.Check()
-}
-
-// NewSysVolume .
-func NewSysVolume(cap int64, imageName string) *Volume {
- vol := NewVolume(VolSysType, cap)
- vol.ImageName = imageName
- return vol
-}
-
-// NewVolume .
-func NewVolume(vtype string, cap int64) *Volume {
- var vol = newVolume()
- vol.Type = vtype
- vol.Capacity = cap
- return vol
-}
-
-func newVolume() *Volume {
- return &Volume{Generic: newGeneric(), Format: VolQcow2Format}
-}
-
-// Load .
-func (v *Volume) Load() (err error) {
- if v.Snaps, err = LoadSnapshots(v.SnapIDs); err != nil {
- return errors.Trace(err)
- }
-
- return nil
-}
-
-// Delete .
-func (v *Volume) Delete(force bool) error {
- if err := v.setStatus(StatusDestroyed, force); err != nil {
- return errors.Trace(err)
- }
-
- keys := []string{v.MetaKey()}
- vers := map[string]int64{v.MetaKey(): v.GetVer()}
-
- ctx, cancel := meta.Context(context.Background())
- defer cancel()
-
- return store.Delete(ctx, keys, vers)
-}
-
-// Amplify .
-func (v *Volume) Amplify(cap int64) error {
- v.Capacity = cap
- return v.Save()
-}
-
-// AppendSnaps .
-func (v *Volume) AppendSnaps(snaps ...*Snapshot) error {
- if v.Snaps.Len()+len(snaps) > configs.Conf.MaxSnapshotsCount {
- return errors.Annotatef(errors.ErrTooManyVolumes, "at most %d", configs.Conf.MaxSnapshotsCount)
- }
-
- res := Snapshots(snaps)
-
- v.Snaps.append(snaps...)
-
- v.SnapIDs = append(v.SnapIDs, res.ids()...)
-
- return nil
-}
-
-// RemoveSnaps Remove snapshots meta by preserving the order.
-func (v *Volume) RemoveSnap(snapID string) {
- keep := 0
-
- for i := 0; i < v.Snaps.Len(); i++ {
- if v.Snaps[i].ID == snapID {
- continue
- }
-
- v.Snaps[keep] = v.Snaps[i]
- v.SnapIDs[keep] = v.SnapIDs[i]
- keep++
- }
-
- v.Snaps = v.Snaps[:keep]
- v.SnapIDs = v.SnapIDs[:keep]
-}
-
-// Save updates metadata to persistence store.
-func (v *Volume) Save() error {
- return meta.Save(meta.Resources{v})
-}
-
-// MetaKey .
-func (v *Volume) MetaKey() string {
- return meta.VolumeKey(v.ID)
-}
-
-// GenerateID .
-func (v *Volume) GenerateID() {
- v.genID()
-}
-
-func (v *Volume) genID() {
- v.ID = idgen.Next()
-}
-
-// GetDevicePathBySerialNumber .
-func (v *Volume) GetDevicePathBySerialNumber(sn int) string {
- return v.GetDevicePathByName(v.GetDeviceName(sn))
-}
-
-// GetDevicePathByName .
-func (v *Volume) GetDevicePathByName(name string) string {
- return GetDevicePathByName(name)
-}
-
-// GetDeviceName .
-func (v *Volume) GetDeviceName(sn int) string {
- return GetDeviceName(sn)
-}
-
-// GetDevicePathByName .
-func GetDevicePathByName(name string) string {
- return filepath.Join("/dev", name)
-}
-
-// GetDeviceName .
-func GetDeviceName(sn int) string {
- return fmt.Sprintf("vd%s", string(utils.LowerLetters[sn]))
-}
-
-func (v *Volume) GetMountDir() string {
- if len(v.MountDir) > 0 {
- return v.MountDir
- }
- return "/"
-}
-
-func (v *Volume) String() string {
- var mnt = "/"
- if len(v.MountDir) > 0 {
- mnt = v.MountDir
- }
- return fmt.Sprintf("%s, %s, %s:%s, size: %d", v.Filepath(), v.Status, v.GuestID, mnt, v.Capacity)
-}
-
-// Filepath .
-func (v *Volume) Filepath() string {
- if len(v.HostDir) > 0 {
- return filepath.Join(v.HostDir, v.Name())
- }
- return v.JoinVirtPath(v.Name())
-}
-
-// Name .
-func (v *Volume) Name() string {
- return fmt.Sprintf("%s-%s.vol", v.Type, v.ID)
-}
-
-// Check .
-func (v *Volume) Check() error {
- switch {
- case v.Capacity < configs.Conf.MinVolumeCap || v.Capacity > configs.Conf.MaxVolumeCap:
- return errors.Annotatef(errors.ErrInvalidValue, "capacity: %d", v.Capacity)
- case v.HostDir == "/":
- return errors.Annotatef(errors.ErrInvalidValue, "host dir: %s", v.HostDir)
- case v.MountDir == "/":
- return errors.Annotatef(errors.ErrInvalidValue, "mount dir: %s", v.MountDir)
- default:
- return nil
- }
-}
-
-// IsSys .
-func (v *Volume) IsSys() bool {
- return v.Type == VolSysType
-}
-
-// LoadVolumes .
-func LoadVolumes(ids []string) (vols Volumes, err error) {
- vols = make(Volumes, len(ids))
-
- for i, id := range ids {
- if vols[i], err = LoadVolume(id); err != nil {
- return nil, errors.Trace(err)
- }
- }
-
- return vols, nil
-}
-
-// Volumes .
-type Volumes []*Volume
-
-// Check .
-func (vols Volumes) Check() error {
- for _, v := range vols {
- if v == nil {
- return errors.Annotatef(errors.ErrInvalidValue, "nil *Volume")
- }
- if err := v.Check(); err != nil {
- return errors.Trace(err)
- }
- }
- return nil
-}
-
-// Find .
-func (vols Volumes) Find(volID string) (*Volume, error) {
- for _, v := range vols {
- if v.ID == volID {
- return v, nil
- }
- }
-
- return nil, errors.Annotatef(errors.ErrInvalidValue, "volID %s not exists", volID)
-}
-
-func (vols Volumes) resources() meta.Resources {
- var r = make(meta.Resources, len(vols))
- for i, v := range vols {
- r[i] = v
- }
- return r
-}
-
-func (vols *Volumes) append(vol ...*Volume) {
- *vols = append(*vols, vol...)
-}
-
-func (vols Volumes) setGuestID(id string) {
- for _, vol := range vols {
- vol.GuestID = id
- }
-}
-
-func (vols Volumes) setHostName(name string) {
- for _, vol := range vols {
- vol.HostName = name
- }
-}
-
-func (vols Volumes) ids() []string {
- var v = make([]string, len(vols))
- for i, vol := range vols {
- v[i] = vol.ID
- }
- return v
-}
-
-func (vols Volumes) genID() {
- for _, vol := range vols {
- vol.genID()
- }
-}
-
-func (vols Volumes) setStatus(st string, force bool) error {
- for _, vol := range vols {
- if err := vol.setStatus(st, force); err != nil {
- return errors.Trace(err)
- }
- }
- return nil
-}
-
-func (vols Volumes) deleteKeys() []string {
- var keys = make([]string, len(vols))
- for i, vol := range vols {
- keys[i] = vol.MetaKey()
- }
- return keys
-}
-
-// Exists checks the volume if exists, in which mounted the directory.
-func (vols Volumes) Exists(mnt string) bool {
- for _, vol := range vols {
- switch {
- case vol.IsSys():
- continue
- case vol.MountDir == mnt:
- return true
- }
- }
- return false
-}
-
-// Len .
-func (vols Volumes) Len() int {
- return len(vols)
-}
-
-// GetMntVol return the vol of a path if exists .
-func (vols Volumes) GetMntVol(path string) (*Volume, error) {
- path = filepath.Dir(path)
- if path[0] != '/' {
- return nil, errors.ErrDestinationInvalid
- }
-
- var sys, maxVol *Volume
- maxLen := -1
- for _, vol := range vols {
- if vol.IsSys() {
- sys = vol
- continue
- }
-
- mntDirLen := len(vol.MountDir)
- if mntDirLen > maxLen && strings.Index(path, vol.MountDir) == 0 {
- maxLen = mntDirLen
- maxVol = vol
- }
- }
-
- if maxLen < 1 {
- return sys, nil
- }
- return maxVol, nil
-}
diff --git a/internal/network/const.go b/internal/network/const.go
new file mode 100644
index 0000000..bdb987a
--- /dev/null
+++ b/internal/network/const.go
@@ -0,0 +1,18 @@
+package network
+
+const (
+ // CalicoMode .
+ CalicoMode = "calico"
+ // Network CalicoCNI
+ CalicoCNIMode = "calico-cni"
+ // VlanMode .
+ VlanMode = "vlan"
+ // OVNMode
+ OVNMode = "ovn"
+ // FakeMode
+ FakeMode = "fake"
+
+ ModeLabelKey = "network/mode"
+ CalicoLabelKey = "network/calico"
+ OVNLabelKey = "network/ovn"
+)
diff --git a/internal/network/drivers/calico/const.go b/internal/network/drivers/calico/const.go
new file mode 100644
index 0000000..1737648
--- /dev/null
+++ b/internal/network/drivers/calico/const.go
@@ -0,0 +1,14 @@
+package calico
+
+import "net"
+
+const (
+ // OrchestratorID .
+ OrchestratorID = "yavirt"
+
+ // CalicoIPv4Version .
+ CalicoIPv4Version = 4
+)
+
+// AllonesMask .
+var AllonesMask = net.CIDRMask(32, net.IPv4len*8)
diff --git a/internal/network/drivers/calico/dhcp.go b/internal/network/drivers/calico/dhcp.go
new file mode 100644
index 0000000..94e3910
--- /dev/null
+++ b/internal/network/drivers/calico/dhcp.go
@@ -0,0 +1,120 @@
+package calico
+
+import (
+ "context"
+ "net"
+
+ "github.com/alphadose/haxmap"
+ "github.com/cockroachdb/errors"
+ "github.com/insomniacslk/dhcp/dhcpv4"
+ "github.com/insomniacslk/dhcp/dhcpv4/server4"
+ "github.com/projecteru2/core/log"
+)
+
+type singleServer struct {
+ *server4.Server
+ Iface string
+ IP net.IP
+}
+
+type DHCPServer struct {
+ Servers haxmap.Map[string, *singleServer]
+ Port int
+ gwIP net.IP
+}
+
+func NewDHCPServer(gw net.IP) *DHCPServer {
+ return &DHCPServer{
+ Port: 67,
+ gwIP: gw,
+ }
+}
+
+func (srv *DHCPServer) AddInterface(iface string, ip net.IP, ipNet *net.IPNet) error {
+ logger := log.WithFunc("DHCPServer.AddInterface")
+ laddr := net.UDPAddr{
+ IP: net.ParseIP("0.0.0.0"),
+ Port: srv.Port,
+ }
+ dhcpSrv, err := server4.NewServer(iface, &laddr, srv.NewHandler(ip, ipNet))
+ if err != nil {
+ return errors.Wrapf(err, "fialed to create dhcpv4 server")
+ }
+ if oldSrv, exists := srv.Servers.Get(iface); exists {
+ logger.Infof(context.TODO(), "Stop old dhcp server for interface %s", iface)
+ oldSrv.Close()
+ }
+ srv.Servers.Set(iface, &singleServer{
+ Server: dhcpSrv,
+ Iface: iface,
+ IP: ip,
+ })
+ go func() {
+ defer logger.Infof(context.TODO(), "dhcp server for %s: %s exits", iface, ip.String())
+ logger.Infof(context.TODO(), "starting dhcp server for %s: %s", iface, ip.String())
+ _ = dhcpSrv.Serve()
+ }()
+ return nil
+}
+
+func (srv *DHCPServer) RemoveInterface(iface string) {
+ ssrv, exists := srv.Servers.GetAndDel(iface)
+ if !exists {
+ return
+ }
+ ssrv.Close()
+}
+
+func (srv *DHCPServer) NewHandler(ip net.IP, ipNet *net.IPNet) server4.Handler {
+ return func(conn net.PacketConn, peer net.Addr, m *dhcpv4.DHCPv4) {
+ // Process DHCP requests (DISCOVER, OFFER, REQUEST, DECLINE, RELEASE)
+ logger := log.WithFunc("dhcp.handler")
+ logger.Debugf(context.TODO(), m.Summary())
+ leaseTime := uint32(3600)
+
+ switch m.MessageType() {
+ case dhcpv4.MessageTypeDiscover:
+ // Offer an IP address from the subnet based on server IP
+ offer, err := dhcpv4.NewReplyFromRequest(
+ m,
+ dhcpv4.WithMessageType(dhcpv4.MessageTypeOffer),
+ dhcpv4.WithYourIP(ip),
+ dhcpv4.WithClientIP(m.ClientIPAddr),
+ dhcpv4.WithLeaseTime(leaseTime),
+ dhcpv4.WithNetmask(ipNet.Mask),
+ dhcpv4.WithGatewayIP(srv.gwIP),
+ )
+ if err != nil {
+ logger.Errorf(context.TODO(), err, "Failed to create DHCP offer")
+ return
+ }
+ if _, err := conn.WriteTo(offer.ToBytes(), peer); err != nil {
+ logger.Error(context.TODO(), err, "failed to write offer packet.")
+ }
+ case dhcpv4.MessageTypeRequest:
+ // Check if requested IP is within our range and send ACK
+ if m.YourIPAddr.Equal(ip) {
+ ack, err := dhcpv4.NewReplyFromRequest(
+ m,
+ dhcpv4.WithMessageType(dhcpv4.MessageTypeAck),
+ dhcpv4.WithYourIP(ip),
+ dhcpv4.WithClientIP(m.ClientIPAddr),
+ // dhcpv4.WithServerIP(ip),
+ dhcpv4.WithLeaseTime(leaseTime),
+ dhcpv4.WithNetmask(ipNet.Mask),
+ dhcpv4.WithGatewayIP(srv.gwIP),
+ )
+ if err != nil {
+ logger.Errorf(context.TODO(), err, "Failed to create DHCP ACK")
+ }
+ if _, err := conn.WriteTo(ack.ToBytes(), peer); err != nil {
+ logger.Errorf(context.TODO(), err, "failed to write ACK package.")
+ }
+ } else {
+ logger.Warnf(context.TODO(), "Invalid IP request from %s for %s", peer, m.YourIPAddr)
+ }
+ default:
+ logger.Warnf(context.TODO(), "Unhandled DHCP message type: %d", m.MessageType())
+ }
+ }
+}
diff --git a/internal/network/drivers/calico/driver.go b/internal/network/drivers/calico/driver.go
new file mode 100644
index 0000000..40bbd03
--- /dev/null
+++ b/internal/network/drivers/calico/driver.go
@@ -0,0 +1,160 @@
+package calico
+
+import (
+ "context"
+ "net"
+ "strings"
+ "sync"
+
+ calitype "github.com/projectcalico/api/pkg/apis/projectcalico/v3"
+ "github.com/projectcalico/calico/libcalico-go/lib/apiconfig"
+ libcaliapi "github.com/projectcalico/calico/libcalico-go/lib/apis/v3"
+ "github.com/projectcalico/calico/libcalico-go/lib/clientv3"
+ "github.com/projectcalico/calico/libcalico-go/lib/options"
+ "github.com/projecteru2/core/log"
+ "github.com/projecteru2/yavirt/configs"
+ "github.com/projecteru2/yavirt/internal/network/utils/device"
+ "github.com/projecteru2/yavirt/pkg/netx"
+ "github.com/projecteru2/yavirt/pkg/terrors"
+
+ "github.com/cockroachdb/errors"
+)
+
+// Driver .
+type Driver struct {
+ sync.Mutex
+
+ clientv3.Interface
+
+ mCol *MetricsCollector
+ dev *device.Driver
+
+ gateway *device.Dummy
+ gatewayWorkloadEndpoint *libcaliapi.WorkloadEndpoint
+
+ nodename string
+ hostIP string
+ poolNames map[string]struct{}
+ dhcp *DHCPServer
+}
+
+// NewDriver .
+func NewDriver(cfg *configs.CalicoConfig) (*Driver, error) {
+ configFile, poolNames := cfg.ConfigFile, cfg.PoolNames
+ dev, err := device.New()
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+
+ hostIP, err := netx.GetOutboundIP("8.8.8.8:53")
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+
+ caliConf, err := apiconfig.LoadClientConfig(configFile)
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+
+ cali, err := clientv3.New(*caliConf)
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+
+ var driver = &Driver{
+ Interface: cali,
+ mCol: &MetricsCollector{},
+ nodename: cfg.Nodename,
+ dev: dev,
+ hostIP: hostIP,
+ poolNames: map[string]struct{}{},
+ }
+
+ for _, pn := range poolNames {
+ driver.poolNames[pn] = struct{}{}
+ }
+
+ return driver, nil
+}
+
+func (d *Driver) CheckHealth(ctx context.Context) (err error) {
+ defer func() {
+ if err != nil {
+ d.mCol.healthy.Store(false)
+ } else {
+ d.mCol.healthy.Store(true)
+ }
+ }()
+ n, err := d.Nodes().Get(ctx, d.nodename, options.GetOptions{})
+ if err != nil {
+ return err
+ }
+ if n == nil {
+ return errors.Newf("calico node %s not found", d.nodename)
+ }
+ if err := CheckNodeStatus(); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (d *Driver) InitDHCP() error {
+ logger := log.WithFunc("calico.initDHCP")
+ gwIP := net.ParseIP("169.254.1.1")
+ dhcpSrv := NewDHCPServer(gwIP)
+ weps, err := d.ListWEP()
+ if err != nil {
+ return err
+ }
+ for _, wep := range weps {
+ iface := wep.Spec.InterfaceName
+ if len(wep.Spec.IPNetworks) == 0 {
+ continue
+ }
+ ip, ipNet, err := net.ParseCIDR(wep.Spec.IPNetworks[0])
+ if err != nil {
+ logger.Errorf(context.TODO(), err, "failed to parse cidr: %s", wep.Spec.IPNetworks[0])
+ continue
+ }
+ if err := dhcpSrv.AddInterface(iface, ip, ipNet); err != nil {
+ logger.Errorf(context.TODO(), err, "failed to add interface to dhcp.")
+ }
+ }
+ d.dhcp = dhcpSrv
+ return nil
+}
+
+func (d *Driver) getIPPool(poolName string) (pool *calitype.IPPool, err error) {
+ if poolName != "" {
+ return d.IPPools().Get(context.Background(), poolName, options.GetOptions{})
+ }
+ pools, err := d.IPPools().List(context.Background(), options.ListOptions{})
+ switch {
+ case err != nil:
+ return pool, errors.Wrap(err, "")
+ case len(pools.Items) < 1:
+ return pool, errors.Wrap(terrors.ErrCalicoPoolNotExists, "")
+ }
+
+ if len(d.poolNames) < 1 {
+ return &pools.Items[0], nil
+ }
+
+ for _, p := range pools.Items {
+ if _, exists := d.poolNames[p.Name]; exists {
+ return &p, nil
+ }
+ }
+
+ return pool, errors.Wrapf(terrors.ErrCalicoPoolNotExists, "no such pool names: %s", d.poolNamesStr())
+}
+
+func (d *Driver) poolNamesStr() string {
+ names := d.PoolNames()
+ return strings.Join(names, ", ")
+}
+
+// Ipam .
+func (d *Driver) Ipam() *Ipam {
+ return newIpam(d)
+}
diff --git a/internal/network/drivers/calico/driver_test.go b/internal/network/drivers/calico/driver_test.go
new file mode 100644
index 0000000..e0c0841
--- /dev/null
+++ b/internal/network/drivers/calico/driver_test.go
@@ -0,0 +1,20 @@
+package calico
+
+import (
+ "strings"
+ "testing"
+
+ mapset "github.com/deckarep/golang-set/v2"
+ "github.com/projecteru2/yavirt/pkg/test/assert"
+)
+
+func TestPoolNameStr(t *testing.T) {
+ d := &Driver{
+ poolNames: map[string]struct{}{"a": {}, "b": {}, "c": {}},
+ }
+ ss := d.poolNamesStr()
+ l := strings.Split(ss, ", ")
+ s1 := mapset.NewSet[string](l...)
+ diff := s1.Difference(mapset.NewSet("a", "b", "c"))
+ assert.Equal(t, diff.Cardinality(), 0)
+}
diff --git a/internal/network/drivers/calico/endpoint.go b/internal/network/drivers/calico/endpoint.go
new file mode 100644
index 0000000..e5bb803
--- /dev/null
+++ b/internal/network/drivers/calico/endpoint.go
@@ -0,0 +1,137 @@
+package calico
+
+import (
+ "context"
+ "fmt"
+ "strings"
+
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/core/log"
+ "github.com/projecteru2/yavirt/internal/network/types"
+ "github.com/projecteru2/yavirt/internal/network/utils/device"
+ "github.com/projecteru2/yavirt/pkg/terrors"
+ "github.com/projecteru2/yavirt/pkg/utils"
+)
+
+const (
+ calicoMTU = 1500
+)
+
+// CreateEndpointNetwork .
+func (h *Driver) CreateEndpointNetwork(args types.EndpointArgs) (types.EndpointArgs, func() error, error) {
+ // Create network policy if necessary
+ // TODO: maybe we can create network policy when create new user.
+ if err := h.CreateNetworkPolicy(args.Calico.Namespace); err != nil {
+ return args, nil, errors.Wrapf(err, "failed to create network policy")
+ }
+
+ h.Lock()
+ defer h.Unlock()
+
+ // alloc an ip for this endpoint
+ ip, err := h.assignIP(&args)
+ if err != nil {
+ return args, nil, errors.Wrap(err, "")
+ }
+ rollbackIP := func() error {
+ return h.releaseIPs(ip)
+ }
+
+ args.IPs = append(args.IPs, ip)
+
+ if args.EndpointID, err = h.generateEndpointID(); err != nil {
+ return args, rollbackIP, errors.Wrap(err, "")
+ }
+
+ dev, err := h.createTap()
+ if err != nil {
+ return args, rollbackIP, errors.Wrap(err, "")
+ }
+ args.DevName = dev.Name()
+ if err = dev.Up(); err != nil {
+ return args, rollbackIP, errors.Wrap(err, "")
+ }
+
+ // qemu will create TAP device when start, so we can delete it here
+ defer func() {
+ // try to delete tap device, we ignore the error
+ err = h.deleteTap(dev)
+ log.Debugf(context.TODO(), "After delete tap device(%v): %v", dev.Name(), err)
+ }()
+
+ if _, err = h.createWEP(args); err != nil {
+ return args, rollbackIP, err
+ }
+ rollback := func() error {
+ err1 := rollbackIP()
+ err2 := h.DeleteEndpointNetwork(args)
+ return errors.CombineErrors(err1, err2)
+ }
+ args.MTU = calicoMTU
+ return args, rollback, err
+}
+
+// JoinEndpointNetwork .
+func (h *Driver) JoinEndpointNetwork(args types.EndpointArgs) (func() error, error) {
+ if err := args.Check(); err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+
+ h.Lock()
+ defer h.Unlock()
+
+ devDriver, err := device.New()
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ dev, err := devDriver.ShowLink(args.DevName)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to get link")
+ }
+
+ for _, ip := range args.IPs {
+ ip.BindDevice(dev)
+
+ if err := dev.AddRoute(ip.IPAddr(), h.hostIP); err != nil {
+ if !terrors.IsVirtLinkRouteExistsErr(err) {
+ return nil, errors.Wrap(err, "")
+ }
+ }
+ }
+
+ if h.dhcp != nil && len(args.IPs) > 0 {
+ ip := args.IPs[0]
+ if err := h.dhcp.AddInterface(dev.Name(), ip.NetIP(), ip.IPNetwork()); err != nil {
+ return nil, errors.Wrap(err, "Failed to add interface to dhcp server")
+ }
+ }
+ rollback := func() error {
+ var err error
+ for _, ip := range args.IPs {
+ cidr := fmt.Sprintf("%s/32", ip.IPAddr())
+ if err1 := dev.DeleteRoute(cidr); err1 != nil {
+ err = errors.CombineErrors(err, err1)
+ }
+ }
+ return err
+ }
+
+ return rollback, nil
+}
+
+// DeleteEndpointNetwork .
+func (h *Driver) DeleteEndpointNetwork(args types.EndpointArgs) error {
+ h.Lock()
+ defer h.Unlock()
+ err1 := h.releaseIPs(args.IPs...)
+ err2 := h.deleteWEP(&args)
+ return errors.CombineErrors(err1, err2)
+}
+
+func (h *Driver) generateEndpointID() (string, error) {
+ var uuid, err = utils.UUIDStr()
+ if err != nil {
+ return "", errors.Wrap(err, "")
+ }
+ return strings.ReplaceAll(uuid, "-", ""), nil
+}
diff --git a/internal/network/drivers/calico/gateway.go b/internal/network/drivers/calico/gateway.go
new file mode 100644
index 0000000..3f01898
--- /dev/null
+++ b/internal/network/drivers/calico/gateway.go
@@ -0,0 +1,163 @@
+package calico
+
+import (
+ "net"
+
+ libcaliapi "github.com/projectcalico/calico/libcalico-go/lib/apis/v3"
+
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/yavirt/configs"
+ "github.com/projecteru2/yavirt/internal/meta"
+ "github.com/projecteru2/yavirt/internal/network/types"
+ "github.com/projecteru2/yavirt/internal/network/utils/device"
+ "github.com/projecteru2/yavirt/pkg/terrors"
+)
+
+// InitGateway .
+func (h *Driver) InitGateway(gwName string) error {
+ dev, err := device.New()
+ if err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ h.Lock()
+ defer h.Unlock()
+
+ gw, err := dev.ShowLink(gwName)
+ if err != nil {
+ if terrors.IsVirtLinkNotExistsErr(err) {
+ gw, err = dev.AddLink(device.LinkTypeDummy, gwName)
+ }
+
+ if err != nil {
+ return errors.Wrap(err, "")
+ }
+ }
+
+ var ok bool
+ if h.gateway, ok = gw.(*device.Dummy); !ok {
+ return errors.Wrapf(terrors.ErrInvalidValue, "expect *device.Dummy, but %v", gw)
+ }
+
+ if err := h.gateway.Up(); err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ if err := h.loadGateway(); err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ gwIPs, err := h.gatewayIPs()
+ if err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ return h.bindGatewayIPs(gwIPs...)
+}
+
+// Gateway .
+func (h *Driver) Gateway() *device.Dummy {
+ h.Lock()
+ defer h.Unlock()
+ return h.gateway
+}
+
+// GatewayWorkloadEndpoint .
+func (h *Driver) GatewayWorkloadEndpoint() *libcaliapi.WorkloadEndpoint {
+ h.Lock()
+ defer h.Unlock()
+ return h.gatewayWorkloadEndpoint
+}
+
+func (h *Driver) bindGatewayIPs(ips ...meta.IP) error {
+ for _, ip := range ips {
+ var addr, err = h.dev.ParseCIDR(ip.CIDR())
+ if err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ addr.IPNet = &net.IPNet{
+ IP: addr.IPNet.IP,
+ Mask: AllonesMask,
+ }
+
+ if err := h.gateway.BindAddr(addr); err != nil && !terrors.IsVirtLinkAddrExistsErr(err) {
+ return errors.Wrap(err, "")
+ }
+
+ if err := h.gateway.ClearRoutes(); err != nil {
+ return errors.Wrap(err, "")
+ }
+ }
+
+ return nil
+}
+
+// RefreshGateway refreshes gateway data.
+func (h *Driver) RefreshGateway() error {
+ h.Lock()
+ defer h.Unlock()
+ return h.loadGateway()
+}
+
+func (h *Driver) loadGateway() error {
+ hn := configs.Hostname()
+
+ var args types.EndpointArgs
+ args.Hostname = hn
+ //TODO: better way to set namespace here
+ args.Calico.Namespace = hn
+ args.EndpointID = configs.Conf.Network.Calico.GatewayName
+
+ wep, err := h.getWEP(args)
+ if err != nil {
+ if terrors.IsCalicoEndpointNotExistsErr(err) {
+ return nil
+ }
+ return errors.Wrap(err, "")
+ }
+
+ h.gatewayWorkloadEndpoint = wep
+
+ return nil
+}
+
+// GetGatewayIP gets a gateway IP which could serve the ip.
+func (h *Driver) GetGatewayIP(ip meta.IP) (meta.IP, error) {
+ h.Lock()
+ defer h.Unlock()
+ return h.getGatewayIP(ip)
+}
+
+func (h *Driver) getGatewayIP(ip meta.IP) (meta.IP, error) {
+ if h.gatewayWorkloadEndpoint == nil {
+ return nil, errors.Wrapf(terrors.ErrCalicoGatewayIPNotExists, "no such gateway WorkloadEndpoint")
+ }
+
+ for _, cidr := range h.gatewayWorkloadEndpoint.Spec.IPNetworks {
+ var gwIP, err = ParseCIDR(cidr)
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+
+ if h.isUnderGateway(gwIP, ip) {
+ return gwIP, nil
+ }
+ }
+
+ return nil, errors.Wrapf(terrors.ErrCalicoGatewayIPNotExists, "for %s", ip)
+}
+
+func (h *Driver) isUnderGateway(gatewayIP, ip meta.IP) bool {
+ var ipn = &net.IPNet{}
+ ipn.IP = gatewayIP.NetIP()
+ ipn.Mask = net.CIDRMask(ip.Prefix(), net.IPv4len*8)
+ return ipn.Contains(ip.NetIP())
+}
+
+func (h *Driver) gatewayIPs() (ips []meta.IP, err error) {
+ if h.gatewayWorkloadEndpoint != nil {
+ ips, err = ConvIPs(h.gatewayWorkloadEndpoint)
+ }
+ return
+}
diff --git a/internal/network/drivers/calico/health.go b/internal/network/drivers/calico/health.go
new file mode 100644
index 0000000..730a221
--- /dev/null
+++ b/internal/network/drivers/calico/health.go
@@ -0,0 +1,275 @@
+// Copyright (c) 2016 Tigera, Inc. All rights reserved.
+
+// 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 calico
+
+import (
+ "bufio"
+ "context"
+ "fmt"
+ "net"
+ "regexp"
+ "strings"
+ "time"
+
+ "reflect"
+
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/core/log"
+ "github.com/projecteru2/yavirt/internal/utils"
+ "github.com/samber/lo"
+ "github.com/shirou/gopsutil/process"
+)
+
+// CheckNodeStatus prints status of the node and returns error (if any)
+func CheckNodeStatus() error {
+ // Go through running processes and check if `calico-felix` processes is not running
+ processes, err := process.Processes()
+ if err != nil {
+ return err
+ }
+
+ // For older versions of calico/node, the process was called `calico-felix`. Newer ones use `calico-node -felix`.
+ if !utils.PSContains([]string{"calico-felix"}, processes) && !utils.PSContains([]string{"calico-node", "-felix"}, processes) {
+ // Return and print message if calico-node is not running
+ return errors.New("calico process is not running")
+ }
+
+ if !utils.PSContains([]string{"bird"}, processes) {
+ return errors.New("BIRDv4 process: 'bird' is not running")
+ }
+ peers, err := getBIRDPeers("4")
+ if err != nil {
+ return err
+ }
+ if checkActivePeers(peers) != nil {
+ return errors.New("No active IPV4 peers")
+ }
+ // // Check if birdv6 process is running, print the BGP peer table if it is, else print a warning
+ // if psContains([]string{"bird6"}, processes) {
+ // if peers, err := getBIRDPeers("6"); err != nil {
+ // return err
+ // }
+ // } else {
+ // fmt.Printf("\nINFO: BIRDv6 process: 'bird6' is not running.\n")
+ // }
+
+ return nil
+}
+
+// Check for Word_ where every octate is separated by "_", regardless of IP protocols
+// Example match: "Mesh_192_168_56_101" or "Mesh_fd80_24e2_f998_72d7__2"
+var bgpPeerRegex = regexp.MustCompile(`^(Global|Node|Mesh)_(.+)$`)
+
+// Mapping the BIRD/GoBGP type extracted from the peer name to the display type.
+var bgpTypeMap = map[string]string{
+ "Global": "global",
+ "Mesh": "node-to-node mesh",
+ "Node": "node specific",
+}
+
+// Timeout for querying BIRD
+var birdTimeOut = 2 * time.Second
+
+// Expected BIRD protocol table columns
+var birdExpectedHeadings = []string{"name", "proto", "table", "state", "since", "info"}
+
+// bgpPeer is a structure containing details about a BGP peer.
+type bgpPeer struct {
+ PeerIP string
+ PeerType string
+ State string
+ Since string
+ BGPState string
+ Info string
+}
+
+// Unmarshal a peer from a line in the BIRD protocol output. Returns true if
+// successful, false otherwise.
+func (b *bgpPeer) unmarshalBIRD(line, ipSep string) bool {
+ // Split into fields. We expect at least 6 columns:
+ // name, proto, table, state, since and info.
+ // The info column contains the BGP state plus possibly some additional
+ // info (which will be columns > 6).
+ //
+ // Peer names will be of the format described by bgpPeerRegex.
+ log.Debugf(context.TODO(), "Parsing line: %s", line)
+ columns := strings.Fields(line)
+ if len(columns) < 6 {
+ log.Debug(context.TODO(), "Not a valid line: fewer than 6 columns")
+ return false
+ }
+ if columns[1] != "BGP" {
+ log.Debug(context.TODO(), "Not a valid line: protocol is not BGP")
+ return false
+ }
+
+ // Check the name of the peer is of the correct format. This regex
+ // returns two components:
+ // - A type (Global|Node|Mesh) which we can map to a display type
+ // - An IP address (with _ separating the octets)
+ sm := bgpPeerRegex.FindStringSubmatch(columns[0])
+ if len(sm) != 3 {
+ log.Debugf(context.TODO(), "Not a valid line: peer name '%s' is not correct format", columns[0])
+ return false
+ }
+ var ok bool
+ b.PeerIP = strings.ReplaceAll(sm[2], "_", ipSep)
+ if b.PeerType, ok = bgpTypeMap[sm[1]]; !ok {
+ log.Debugf(context.TODO(), "Not a valid line: peer type '%s' is not recognized", sm[1])
+ return false
+ }
+
+ // Store remaining columns (piecing back together the info string)
+ b.State = columns[3]
+ b.Since = columns[4]
+ b.BGPState = columns[5]
+ if len(columns) > 6 {
+ b.Info = strings.Join(columns[6:], " ")
+ }
+
+ return true
+}
+
+// getBIRDPeers queries BIRD and displays the local peers in table format.
+func getBIRDPeers(ipv string) ([]bgpPeer, error) {
+ log.Debugf(context.TODO(), "Print BIRD peers for IPv%s", ipv)
+ birdSuffix := ""
+ if ipv == "6" {
+ birdSuffix = "6"
+ }
+
+ log.Debugf(context.TODO(), "IPv%s BGP status", ipv)
+
+ // Try connecting to the bird socket in `/var/run/calico/` first to get the data
+ c, err := net.Dial("unix", fmt.Sprintf("/var/run/calico/bird%s.ctl", birdSuffix))
+ if err != nil {
+ // If that fails, try connecting to bird socket in `/var/run/bird` (which is the
+ // default socket location for bird install) for non-containerized installs
+ log.Debug(context.TODO(), "Failed to connect to BIRD socket in /var/run/calic, trying /var/run/bird \n")
+ c, err = net.Dial("unix", fmt.Sprintf("/var/run/bird/bird%s.ctl", birdSuffix))
+ if err != nil {
+ return nil, errors.Wrapf(err, "Error querying BIRD: unable to connect to BIRDv%s socket: %v", ipv, err)
+ }
+ }
+ defer c.Close()
+
+ // To query the current state of the BGP peers, we connect to the BIRD
+ // socket and send a "show protocols" message. BIRD responds with
+ // peer data in a table format.
+ //
+ // Send the request.
+ _, err = c.Write([]byte("show protocols\n"))
+ if err != nil {
+ return nil, errors.Wrapf(err, "Error executing command: unable to write to BIRD socket")
+ }
+
+ // Scan the output and collect parsed BGP peers
+ log.Debug(context.TODO(), "Reading output from BIRD\n")
+ peers, err := scanBIRDPeers(ipv, c)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Error executing command")
+ }
+
+ return peers, nil
+}
+
+// scanBIRDPeers scans through BIRD output to return a slice of bgpPeer
+// structs.
+//
+// We split this out from the main printBIRDPeers() function to allow us to
+// test this processing in isolation.
+func scanBIRDPeers(ipv string, conn net.Conn) ([]bgpPeer, error) {
+ // Determine the separator to use for an IP address, based on the
+ // IP version.
+ ipSep := "."
+ if ipv == "6" {
+ ipSep = ":"
+ }
+
+ // The following is sample output from BIRD
+ //
+ // 0001 BIRD 1.5.0 ready.
+ // 2002-name proto table state since info
+ // 1002-kernel1 Kernel master up 2016-11-21
+ // device1 Device master up 2016-11-21
+ // direct1 Direct master up 2016-11-21
+ // Mesh_172_17_8_102 BGP master up 2016-11-21 Established
+ // 0000
+ scanner := bufio.NewScanner(conn)
+ peers := []bgpPeer{}
+
+ // Set a time-out for reading from the socket connection.
+ err := conn.SetReadDeadline(time.Now().Add(birdTimeOut))
+ if err != nil {
+ return nil, errors.New("failed to set time-out")
+ }
+
+ for scanner.Scan() {
+ // Process the next line that has been read by the scanner.
+ str := scanner.Text()
+ log.Debugf(context.TODO(), "Read: %s\n", str)
+
+ if strings.HasPrefix(str, "0000") { //nolint
+ // "0000" means end of data
+ break
+ } else if strings.HasPrefix(str, "0001") { //nolint
+ // "0001" code means BIRD is ready.
+ } else if strings.HasPrefix(str, "2002") {
+ // "2002" code means start of headings
+ f := strings.Fields(str[5:])
+ if !reflect.DeepEqual(f, birdExpectedHeadings) {
+ return nil, errors.New("unknown BIRD table output format")
+ }
+ } else if strings.HasPrefix(str, "1002") {
+ // "1002" code means first row of data.
+ peer := bgpPeer{}
+ if peer.unmarshalBIRD(str[5:], ipSep) {
+ peers = append(peers, peer)
+ }
+ } else if strings.HasPrefix(str, " ") {
+ // Row starting with a " " is another row of data.
+ peer := bgpPeer{}
+ if peer.unmarshalBIRD(str[1:], ipSep) {
+ peers = append(peers, peer)
+ }
+ } else {
+ // Format of row is unexpected.
+ return nil, errors.New("unexpected output line from BIRD")
+ }
+
+ // Before reading the next line, adjust the time-out for
+ // reading from the socket connection.
+ err = conn.SetReadDeadline(time.Now().Add(birdTimeOut))
+ if err != nil {
+ return nil, errors.New("failed to adjust time-out")
+ }
+ }
+
+ return peers, scanner.Err()
+}
+
+func checkActivePeers(peers []bgpPeer) error {
+ activePeers := lo.Reduce(peers, func(agg int, peer bgpPeer, _ int) int {
+ // log.Infof(context.TODO(), "+++++++++ %v, %s", peer, peer.State)
+ if peer.State == "up" {
+ agg++
+ }
+ return agg
+ }, 0)
+ if activePeers <= 0 {
+ return errors.New("no active peers")
+ }
+ return nil
+}
diff --git a/internal/vnet/calico/ip.go b/internal/network/drivers/calico/ip.go
similarity index 88%
rename from internal/vnet/calico/ip.go
rename to internal/network/drivers/calico/ip.go
index c5d6aca..3ff1cc3 100644
--- a/internal/vnet/calico/ip.go
+++ b/internal/network/drivers/calico/ip.go
@@ -7,10 +7,10 @@ import (
calinet "github.com/projectcalico/calico/libcalico-go/lib/net"
+ "github.com/cockroachdb/errors"
"github.com/projecteru2/yavirt/internal/meta"
- "github.com/projecteru2/yavirt/internal/vnet"
- "github.com/projecteru2/yavirt/internal/vnet/device"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/projecteru2/yavirt/internal/network"
+ "github.com/projecteru2/yavirt/internal/network/utils/device"
"github.com/projecteru2/yavirt/pkg/netx"
)
@@ -31,7 +31,7 @@ type IP struct {
func ParseCIDR(cidr string) (*IP, error) {
var _, ipn, err = parseCIDR(cidr)
if err != nil {
- return nil, errors.Annotatef(err, cidr)
+ return nil, errors.Wrap(err, cidr)
}
return NewIP(ipn), nil
}
@@ -68,7 +68,7 @@ func (ip *IP) BindGuestID(guestID string) {
// IntIP .
func (ip *IP) IntIP() (v int64) {
- v, _ = netx.IPv4ToInt(ip.IP.String()) //nolint
+ v, _ = netx.IPv4ToInt(ip.IP.String())
return
}
@@ -91,7 +91,7 @@ func (ip *IP) String() string {
func (ip *IP) AutoRouteCIDR() (string, error) {
var _, ipn, err = netx.ParseCIDR(ip.CIDR())
if err != nil {
- return "", errors.Trace(err)
+ return "", errors.Wrap(err, "")
}
return ipn.String(), nil
}
@@ -134,7 +134,7 @@ func (ip *IP) SubnetAddr() string {
// IntGateway .
func (ip *IP) IntGateway() (v int64) {
- v, _ = netx.IPv4ToInt(ip.GatewayAddr()) //nolint
+ v, _ = netx.IPv4ToInt(ip.GatewayAddr())
return v
}
@@ -162,7 +162,7 @@ func (ip *IP) MetaKey() string {
// NetworkMode .
func (ip *IP) NetworkMode() string {
- return vnet.NetworkCalico
+ return network.CalicoMode
}
// NetworkName .
diff --git a/internal/network/drivers/calico/ipam.go b/internal/network/drivers/calico/ipam.go
new file mode 100644
index 0000000..d8a8087
--- /dev/null
+++ b/internal/network/drivers/calico/ipam.go
@@ -0,0 +1,224 @@
+package calico
+
+import (
+ "context"
+ "net"
+ "sync"
+
+ libcaliipam "github.com/projectcalico/calico/libcalico-go/lib/ipam"
+ libcalinet "github.com/projectcalico/calico/libcalico-go/lib/net"
+
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/core/log"
+ "github.com/projecteru2/yavirt/configs"
+ "github.com/projecteru2/yavirt/internal/meta"
+ "github.com/projecteru2/yavirt/internal/network"
+ "github.com/projecteru2/yavirt/internal/network/types"
+ "github.com/projecteru2/yavirt/pkg/netx"
+ "github.com/projecteru2/yavirt/pkg/store/etcd"
+ "github.com/projecteru2/yavirt/pkg/terrors"
+)
+
+// Ipam .
+type Ipam struct {
+ *Driver
+ lck sync.Mutex
+}
+
+func newIpam(driver *Driver) *Ipam {
+ return &Ipam{Driver: driver}
+}
+
+// Assign .
+func (ipam *Ipam) Assign(_ context.Context, args *types.EndpointArgs) (meta.IP, error) {
+ hn := configs.Hostname()
+
+ ipam.lck.Lock()
+ defer ipam.lck.Unlock()
+
+ ipn, err := ipam.getIPv4Net(args.Calico.IPPool)
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+
+ caliArgs := libcaliipam.AutoAssignArgs{
+ Num4: 1,
+ Hostname: hn,
+ IPv4Pools: []libcalinet.IPNet{*ipn},
+ IntendedUse: "Workload",
+ }
+
+ return ipam.assign(caliArgs)
+}
+
+func (ipam *Ipam) assign(args libcaliipam.AutoAssignArgs) (meta.IP, error) {
+ var ipv4s, err = ipam.autoAssign(args)
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+
+ if len(ipv4s.IPs) < 1 {
+ return nil, errors.Wrap(terrors.ErrInsufficientIP, "")
+ }
+
+ var ip = ipv4s.IPs[0]
+ var ones, _ = ip.Mask.Size()
+ if ones >= 30 {
+ return nil, errors.Wrapf(terrors.ErrCalicoTooSmallSubnet, "/%d", ones)
+ }
+
+ if err := netx.CheckIPv4(ip.IP, ip.Mask); err != nil {
+ if !terrors.IsIPv4IsNetworkNumberErr(err) && !terrors.IsIPv4IsBroadcastErr(err) {
+ return nil, errors.Wrap(err, "")
+ }
+
+ // Occupies the network no. and broadcast addr.,
+ // doesn't release them to Calico unallocated pool.
+ // and then retry to assign.
+ log.Warnf(context.TODO(), "occupy %s as it's a network no. or broadcast addr.", ip)
+ return ipam.assign(args)
+ }
+
+ return NewIP(&ip), nil
+}
+
+func (ipam *Ipam) autoAssign(args libcaliipam.AutoAssignArgs) (ipv4s *libcaliipam.IPAMAssignments, err error) {
+ etcd.RetryTimedOut(func() error { //nolint
+ ipv4s, _, err = ipam.IPAM().AutoAssign(context.Background(), args)
+ return err
+ }, 3) //nolint:gomnd // try 3 times
+ return
+}
+
+func (ipam *Ipam) getIPv4Net(poolName string) (*libcalinet.IPNet, error) {
+ pool, err := ipam.getIPPool(poolName)
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+
+ _, ipn, err := libcalinet.ParseCIDR(pool.Spec.CIDR)
+
+ switch {
+ case err != nil:
+ return nil, errors.Wrap(err, pool.Spec.CIDR)
+
+ case ipn.Version() != CalicoIPv4Version:
+ return nil, errors.Wrapf(terrors.ErrCalicoIPv4Only, "%d", ipn.Version())
+ }
+
+ return ipn, err
+}
+
+// Release .
+func (ipam *Ipam) Release(ctx context.Context, ips ...meta.IP) error {
+ ipam.lck.Lock()
+ defer ipam.lck.Unlock()
+
+ var releaseOpts = make([]libcaliipam.ReleaseOptions, len(ips))
+ for i := range ips {
+ var ip, ok = ips[i].(*IP)
+ if !ok {
+ return errors.Wrapf(terrors.ErrInvalidValue, "expect *IP, but %v", ips[i])
+ }
+
+ releaseOpts[i] = libcaliipam.ReleaseOptions{Address: ip.IP.String()}
+ }
+
+ return etcd.RetryTimedOut(func() error {
+ var _, err = ipam.IPAM().ReleaseIPs(ctx, releaseOpts...)
+ return err
+ }, 3) //nolint:gomnd // try 3 times
+}
+
+// Query .
+func (ipam *Ipam) Query(ctx context.Context, args meta.IPNets) ([]meta.IP, error) {
+ ipam.lck.Lock()
+ defer ipam.lck.Unlock()
+
+ var ips = make([]meta.IP, len(args))
+ var err error
+
+ for i := range args {
+ if ips[i], err = ipam.load(ctx, args[i]); err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ }
+
+ return ips, nil
+}
+
+func (ipam *Ipam) load(_ context.Context, arg *meta.IPNet) (*IP, error) {
+ var ip, err = ParseCIDR(arg.CIDR())
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+
+ gwIPNet, err := ipam.getGatewayIPNet(arg)
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+
+ ip.BindGatewayIPNet(gwIPNet)
+
+ return ip, nil
+}
+
+func (ipam *Ipam) getGatewayIPNet(arg *meta.IPNet) (*net.IPNet, error) {
+ return netx.ParseCIDR2(arg.GatewayCIDR())
+}
+
+// NewIP .
+func (h *Driver) NewIP(_, cidr string) (meta.IP, error) {
+ return ParseCIDR(cidr)
+}
+
+// AssignIP .
+func (h *Driver) AssignIP(args *types.EndpointArgs) (ip meta.IP, err error) {
+ h.Lock()
+ defer h.Unlock()
+ return h.assignIP(args)
+}
+
+func (h *Driver) assignIP(args *types.EndpointArgs) (ip meta.IP, err error) {
+ if ip, err = h.ipam().Assign(context.TODO(), args); err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+
+ var roll = ip
+ defer func() {
+ if err != nil && roll != nil {
+ if re := h.releaseIPs(roll); re != nil {
+ err = errors.CombineErrors(err, re)
+ }
+ }
+ }()
+
+ _, gwIPNet, err := net.ParseCIDR("169.254.1.1/32")
+ ip.BindGatewayIPNet(gwIPNet)
+ return ip, err
+}
+
+// ReleaseIPs .
+func (h *Driver) ReleaseIPs(ips ...meta.IP) error {
+ h.Lock()
+ defer h.Unlock()
+ return h.releaseIPs(ips...)
+}
+
+func (h *Driver) releaseIPs(ips ...meta.IP) error {
+ return h.ipam().Release(context.Background(), ips...)
+}
+
+// QueryIPs .
+func (h *Driver) QueryIPs(ipns meta.IPNets) ([]meta.IP, error) {
+ return h.ipam().Query(context.Background(), ipns)
+}
+
+func (h *Driver) ipam() network.Ipam {
+ return h.Ipam()
+}
+
+// QueryIPv4 .
+func (h *Driver) QueryIPv4(_ string) (meta.IP, error) {
+ return nil, errors.Wrap(terrors.ErrNotImplemented, "QueryIPv4 error")
+}
diff --git a/internal/network/drivers/calico/ippool.go b/internal/network/drivers/calico/ippool.go
new file mode 100644
index 0000000..750d70b
--- /dev/null
+++ b/internal/network/drivers/calico/ippool.go
@@ -0,0 +1,24 @@
+package calico
+
+import (
+ "context"
+
+ "github.com/projectcalico/calico/libcalico-go/lib/options"
+)
+
+// PoolNames .
+func (h *Driver) PoolNames() (ans []string) {
+ for name := range h.poolNames {
+ ans = append(ans, name)
+ }
+ return
+}
+
+// GetIPPoolCidr .
+func (h *Driver) GetIPPoolCidr(ctx context.Context, name string) (string, error) {
+ ipPool, err := h.IPPools().Get(ctx, name, options.GetOptions{})
+ if err != nil {
+ return "", err
+ }
+ return ipPool.Spec.CIDR, nil
+}
diff --git a/internal/network/drivers/calico/metrics.go b/internal/network/drivers/calico/metrics.go
new file mode 100644
index 0000000..ddd3130
--- /dev/null
+++ b/internal/network/drivers/calico/metrics.go
@@ -0,0 +1,39 @@
+package calico
+
+import (
+ "sync/atomic"
+
+ "github.com/projecteru2/core/utils"
+ "github.com/projecteru2/yavirt/configs"
+ "github.com/prometheus/client_golang/prometheus"
+)
+
+var (
+ calicoHealthyDesc = prometheus.NewDesc(
+ prometheus.BuildFQName("node", "calico", "healthy"),
+ "calico healthy status.",
+ []string{"node"},
+ nil)
+)
+
+type MetricsCollector struct {
+ healthy atomic.Bool
+}
+
+func (d *Driver) GetMetricsCollector() prometheus.Collector {
+ return d.mCol
+}
+
+func (e *MetricsCollector) Describe(ch chan<- *prometheus.Desc) {
+ ch <- calicoHealthyDesc
+}
+
+func (e *MetricsCollector) Collect(ch chan<- prometheus.Metric) {
+ healthy := utils.Bool2Int(e.healthy.Load())
+ ch <- prometheus.MustNewConstMetric(
+ calicoHealthyDesc,
+ prometheus.GaugeValue,
+ float64(healthy),
+ configs.Hostname(),
+ )
+}
diff --git a/internal/network/drivers/calico/policy.go b/internal/network/drivers/calico/policy.go
new file mode 100644
index 0000000..219f7f4
--- /dev/null
+++ b/internal/network/drivers/calico/policy.go
@@ -0,0 +1,147 @@
+package calico
+
+import (
+ "context"
+ "fmt"
+
+ apiv3 "github.com/projectcalico/api/pkg/apis/projectcalico/v3"
+ libcalierr "github.com/projectcalico/calico/libcalico-go/lib/errors"
+ libcaliopt "github.com/projectcalico/calico/libcalico-go/lib/options"
+
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/yavirt/pkg/store/etcd"
+ "github.com/projecteru2/yavirt/pkg/terrors"
+)
+
+const (
+ policyName = "deny-namespaces"
+)
+
+func (d *Driver) CreateNetworkPolicy(ns string) (err error) {
+ d.Lock()
+ defer d.Unlock()
+
+ cwe := genCalicoNetworkPolicy(ns)
+ err = etcd.RetryTimedOut(func() error {
+ var created, ce = d.NetworkPolicies().Create(context.Background(), cwe, libcaliopt.SetOptions{})
+ if ce != nil {
+ if _, ok := ce.(libcalierr.ErrorResourceAlreadyExists); !ok {
+ return ce
+ }
+ }
+
+ cwe = created
+
+ return nil
+ }, 3)
+
+ return
+}
+
+func (d *Driver) DeleteNetworkPolicy(ns string) (err error) {
+ d.Lock()
+ defer d.Unlock()
+
+ return etcd.RetryTimedOut(func() error {
+ _, err := d.NetworkPolicies().Delete(
+ context.Background(),
+ ns,
+ policyName,
+ libcaliopt.DeleteOptions{},
+ )
+ if err != nil {
+ if _, ok := err.(libcalierr.ErrorResourceDoesNotExist); !ok {
+ return err
+ }
+ }
+ return nil
+ }, 3)
+}
+
+func (d *Driver) GetNetworkPolicy(ns string) (cwe *apiv3.NetworkPolicy, err error) {
+ d.Lock()
+ defer d.Unlock()
+
+ etcd.RetryTimedOut(func() error { //nolint
+ cwe, err = d.NetworkPolicies().Get(context.Background(), ns, policyName, libcaliopt.GetOptions{})
+ if err != nil {
+ if _, ok := err.(libcalierr.ErrorResourceDoesNotExist); ok { //nolint
+ err = errors.Wrapf(terrors.ErrCalicoEndpointNotExists, "%s on %s", ns, policyName)
+ }
+ }
+
+ return err
+ }, 3)
+ return
+}
+
+// apiVersion: projectcalico.org/v3
+// kind: NetworkPolicy
+// metadata:
+//
+// name: allow-pool2
+// namespace: testpool2
+//
+// spec:
+//
+// types:
+// - Ingress
+// - Egress
+// ingress:
+// - action: Allow
+// source:
+// selector: projectcalico.org/namespace == 'testpool2'
+// - action: Allow
+// source:
+// notNets:
+// - '10.0.0.0/8'
+// egress:
+// - action: Allow
+// destination:
+// selector: projectcalico.org/namespace == 'testpool2'
+// - action: Allow
+// destination:
+// notNets:
+// - '10.0.0.0/8'
+func genCalicoNetworkPolicy(ns string) *apiv3.NetworkPolicy {
+ p := apiv3.NewNetworkPolicy()
+ p.Name = policyName
+
+ p.ObjectMeta.Namespace = ns
+ p.Spec.Types = []apiv3.PolicyType{apiv3.PolicyTypeIngress, apiv3.PolicyTypeEgress}
+ p.Spec.Ingress = []apiv3.Rule{
+ {
+ Action: apiv3.Allow,
+ Source: apiv3.EntityRule{
+ Selector: fmt.Sprintf("projectcalico.org/namespace == '%s'", ns),
+ },
+ },
+ {
+ Action: apiv3.Allow,
+ Source: apiv3.EntityRule{
+ NotNets: []string{
+ "10.0.0.0/8",
+ "192.168.0.0/16",
+ },
+ },
+ },
+ }
+ p.Spec.Egress = []apiv3.Rule{
+ {
+ Action: apiv3.Allow,
+ Destination: apiv3.EntityRule{
+ Selector: fmt.Sprintf("projectcalico.org/namespace == '%s'", ns),
+ },
+ },
+ {
+ Action: apiv3.Allow,
+ Destination: apiv3.EntityRule{
+ NotNets: []string{
+ "10.0.0.0/8",
+ "192.168.0.0/16",
+ },
+ },
+ },
+ }
+ return p
+}
diff --git a/internal/network/drivers/calico/tap.go b/internal/network/drivers/calico/tap.go
new file mode 100644
index 0000000..f1e1724
--- /dev/null
+++ b/internal/network/drivers/calico/tap.go
@@ -0,0 +1,46 @@
+package calico
+
+import (
+ "fmt"
+
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/yavirt/configs"
+ "github.com/projecteru2/yavirt/internal/network/utils/device"
+ "github.com/projecteru2/yavirt/pkg/terrors"
+ "github.com/projecteru2/yavirt/pkg/utils"
+)
+
+func (d *Driver) createTap() (device.VirtLink, error) {
+ var name, err = d.randTapName()
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+
+ for {
+ var tap, err = d.dev.AddLink(device.LinkTypeTuntap, name)
+ if err != nil {
+ if errors.Is(err, terrors.ErrVirtLinkExists) {
+ continue
+ }
+
+ return nil, errors.Wrap(err, "")
+ }
+
+ return tap, nil
+ }
+}
+
+func (d *Driver) deleteTap(dev device.VirtLink) error {
+ return d.dev.DeleteLink(dev.Name())
+}
+
+func (d *Driver) randTapName() (string, error) {
+ var endpID, err = d.generateEndpointID()
+ if err != nil {
+ return "", errors.Wrap(err, "")
+ }
+
+ var name = fmt.Sprintf("%s%s", configs.Conf.Network.Calico.IFNamePrefix, endpID[:utils.Min(12, len(endpID))])
+
+ return name, nil
+}
diff --git a/internal/network/drivers/calico/workload_endpoint.go b/internal/network/drivers/calico/workload_endpoint.go
new file mode 100644
index 0000000..28f1978
--- /dev/null
+++ b/internal/network/drivers/calico/workload_endpoint.go
@@ -0,0 +1,246 @@
+package calico
+
+import (
+ "context"
+ "net"
+ "time"
+
+ libcaliapi "github.com/projectcalico/calico/libcalico-go/lib/apis/v3"
+ libcalierr "github.com/projectcalico/calico/libcalico-go/lib/errors"
+ libcalinames "github.com/projectcalico/calico/libcalico-go/lib/names"
+ libcalinet "github.com/projectcalico/calico/libcalico-go/lib/net"
+ libcaliopt "github.com/projectcalico/calico/libcalico-go/lib/options"
+ k8smeta "k8s.io/apimachinery/pkg/apis/meta/v1"
+ k8stypes "k8s.io/apimachinery/pkg/types"
+
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/yavirt/internal/meta"
+ "github.com/projecteru2/yavirt/internal/network/types"
+ "github.com/projecteru2/yavirt/pkg/netx"
+ "github.com/projecteru2/yavirt/pkg/store/etcd"
+ "github.com/projecteru2/yavirt/pkg/terrors"
+)
+
+// Get .
+func (d *Driver) GetWEP(args types.EndpointArgs) (*libcaliapi.WorkloadEndpoint, error) {
+ d.Lock()
+ defer d.Unlock()
+ return d.getWEP(args)
+}
+
+func (d *Driver) getWEP(args types.EndpointArgs) (cwe *libcaliapi.WorkloadEndpoint, err error) {
+ var endpName string
+ if endpName, err = d.generateEndpointName(args.Hostname, args.EndpointID); err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+
+ etcd.RetryTimedOut(func() error { //nolint
+ cwe, err = d.WorkloadEndpoints().Get(context.Background(), args.Calico.Namespace, endpName, libcaliopt.GetOptions{})
+ if err != nil {
+ if _, ok := err.(libcalierr.ErrorResourceDoesNotExist); ok { //nolint
+ err = errors.Wrapf(terrors.ErrCalicoEndpointNotExists, "%s on %s", endpName, args.Hostname)
+ }
+ }
+
+ return err
+ }, 3)
+
+ return
+}
+
+// Create .
+func (d *Driver) CreateWEP(args types.EndpointArgs) (cwe *libcaliapi.WorkloadEndpoint, err error) {
+ d.Lock()
+ defer d.Unlock()
+
+ return d.createWEP(args)
+}
+
+func (d *Driver) createWEP(args types.EndpointArgs) (cwe *libcaliapi.WorkloadEndpoint, err error) {
+ if cwe, err = d.getCalicoWorkloadEndpoint(args); err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+
+ err = etcd.RetryTimedOut(func() error {
+ var created, ce = d.WorkloadEndpoints().Create(context.Background(), cwe, libcaliopt.SetOptions{})
+ if ce != nil {
+ if _, ok := ce.(libcalierr.ErrorResourceAlreadyExists); !ok {
+ return ce
+ }
+ }
+
+ cwe = created
+
+ return nil
+ }, 3)
+
+ return
+}
+
+// Update .
+func (d *Driver) UpdateWEP(args types.EndpointArgs) (cwe *libcaliapi.WorkloadEndpoint, err error) {
+ d.Lock()
+ defer d.Unlock()
+ return d.updateWEP(args)
+}
+
+func (d *Driver) updateWEP(args types.EndpointArgs) (cwe *libcaliapi.WorkloadEndpoint, err error) {
+ cwe, err = d.getCalicoWorkloadEndpoint(args)
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+
+ cwe.ObjectMeta.UID = k8stypes.UID(args.Calico.UID)
+ cwe.ObjectMeta.CreationTimestamp = k8smeta.NewTime(time.Now().UTC())
+
+ err = etcd.RetryTimedOut(func() error {
+ var updated, ue = d.WorkloadEndpoints().Update(context.Background(), cwe, libcaliopt.SetOptions{})
+ if ue != nil {
+ return ue
+ }
+
+ cwe = updated
+
+ return nil
+ }, 3)
+
+ return
+}
+
+// Delete .
+func (d *Driver) DeleteWEP(args types.EndpointArgs) error {
+ d.Lock()
+ defer d.Unlock()
+ return d.deleteWEP(&args)
+}
+
+// func (we *Driver) delete(endpName, namespace string) (err error) {
+func (d *Driver) deleteWEP(args *types.EndpointArgs) (err error) {
+ endpName, err := d.generateEndpointName(args.Hostname, args.EndpointID)
+ if err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ return etcd.RetryTimedOut(func() error {
+ _, err := d.WorkloadEndpoints().Delete(
+ context.TODO(),
+ args.Calico.Namespace,
+ endpName,
+ libcaliopt.DeleteOptions{},
+ )
+ if _, ok := err.(libcalierr.ErrorResourceDoesNotExist); !ok {
+ return err
+ }
+ return nil
+ }, 3)
+}
+
+func (d *Driver) ListWEP() ([]libcaliapi.WorkloadEndpoint, error) {
+ var ident = libcalinames.WorkloadEndpointIdentifiers{
+ Node: d.nodename,
+ }
+ namePrefix, _ := ident.CalculateWorkloadEndpointName(true)
+ ans, err := d.WorkloadEndpoints().List(context.TODO(), libcaliopt.ListOptions{
+ Name: namePrefix,
+ Prefix: true,
+ })
+ if err != nil {
+ return nil, err
+ }
+ return ans.Items, nil
+}
+
+func (d *Driver) getCalicoWorkloadEndpoint(args types.EndpointArgs) (*libcaliapi.WorkloadEndpoint, error) {
+ endpName, err := d.generateEndpointName(args.Hostname, args.EndpointID)
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+
+ ipNets, err := d.convCalicoIPNetworks(args.IPs)
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+
+ profile, err := d.getProfile(args.Calico.IPPool)
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+
+ wep := libcaliapi.NewWorkloadEndpoint()
+ wep.Name = endpName
+ wep.ObjectMeta.Namespace = args.Calico.Namespace
+ wep.ObjectMeta.ResourceVersion = args.Calico.ResourceVersion
+ wep.Spec.Endpoint = args.EndpointID
+ wep.Spec.Node = args.Hostname
+ wep.Spec.Orchestrator = OrchestratorID
+ wep.Spec.Workload = OrchestratorID
+ wep.Spec.InterfaceName = args.DevName
+ wep.Spec.MAC = args.MAC
+ wep.Spec.IPNetworks = append(wep.Spec.IPNetworks, ipNets...)
+ wep.Spec.Profiles = d.mergeProfile(args.Calico.Profiles, profile)
+
+ return wep, nil
+}
+
+func (d *Driver) mergeProfile(profiles []string, other string) []string {
+ if len(profiles) < 1 {
+ return []string{other}
+ }
+
+ for _, p := range profiles {
+ if p == other {
+ return profiles
+ }
+ }
+
+ return append(profiles, other)
+}
+
+func (d *Driver) generateEndpointName(hostname, endpointID string) (string, error) {
+ var ident = libcalinames.WorkloadEndpointIdentifiers{
+ Node: hostname,
+ Orchestrator: OrchestratorID,
+ Workload: OrchestratorID,
+ Endpoint: endpointID,
+ }
+ return ident.CalculateWorkloadEndpointName(false)
+}
+
+func (d *Driver) convCalicoIPNetworks(ips []meta.IP) ([]string, error) {
+ var ipNets = make([]string, len(ips))
+
+ for i, ip := range ips {
+ ipv4, _, err := netx.ParseCIDR(ip.CIDR())
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+
+ ipNets[i] = libcalinet.IPNet{IPNet: net.IPNet{
+ IP: ipv4,
+ Mask: net.CIDRMask(net.IPv4len*8, net.IPv4len*8),
+ }}.String()
+ }
+
+ return ipNets, nil
+}
+
+func (d *Driver) getProfile(poolName string) (string, error) {
+ var pool, err = d.getIPPool(poolName)
+ if err != nil {
+ return "", errors.Wrap(err, "")
+ }
+ return pool.ObjectMeta.Name, nil
+}
+
+// ConvIPs .
+func ConvIPs(cwe *libcaliapi.WorkloadEndpoint) (ips []meta.IP, err error) {
+ ips = make([]meta.IP, len(cwe.Spec.IPNetworks))
+
+ for i, cidr := range cwe.Spec.IPNetworks {
+ if ips[i], err = ParseCIDR(cidr); err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ }
+
+ return ips, nil
+}
diff --git a/internal/network/drivers/cni/calico/network.go b/internal/network/drivers/cni/calico/network.go
new file mode 100644
index 0000000..cf4da90
--- /dev/null
+++ b/internal/network/drivers/cni/calico/network.go
@@ -0,0 +1,181 @@
+package calico
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "io"
+ "os"
+ "path/filepath"
+ "time"
+
+ "github.com/cockroachdb/errors"
+ current "github.com/containernetworking/cni/pkg/types/100"
+ "github.com/projecteru2/core/log"
+ "github.com/projecteru2/yavirt/configs"
+ "github.com/projecteru2/yavirt/internal/meta"
+ calihandler "github.com/projecteru2/yavirt/internal/network/drivers/calico"
+ "github.com/projecteru2/yavirt/internal/network/types"
+ netutils "github.com/projecteru2/yavirt/internal/network/utils"
+ "github.com/projecteru2/yavirt/pkg/sh"
+ "github.com/projecteru2/yavirt/pkg/terrors"
+ "github.com/projecteru2/yavirt/pkg/utils"
+)
+
+const (
+ cniCmdAdd = "ADD"
+ cniCmdDel = "DEL"
+ calicoIPPoolLabelKey = "calico/ippool"
+ calicoNSLabelKey = "calico/namespace"
+)
+
+type Driver struct {
+ *calihandler.Driver
+ cfg *configs.CNIConfig
+}
+
+func NewDriver(cfg *configs.CNIConfig, cali *calihandler.Driver) (*Driver, error) {
+ return &Driver{
+ Driver: cali,
+ cfg: cfg,
+ }, nil
+}
+
+func (d *Driver) QueryIPs(meta.IPNets) ([]meta.IP, error) {
+ return nil, nil
+}
+
+func (d *Driver) CreateEndpointNetwork(args types.EndpointArgs) (types.EndpointArgs, func() error, error) {
+ var err error
+ if args.EndpointID, err = netutils.GenEndpointID(); err != nil {
+ return args, nil, errors.Wrap(err, "")
+ }
+
+ stdout, execDel, err := d.calicoCNIAdd(&args, true)
+ if err != nil {
+ return args, nil, errors.Wrap(err, "")
+ }
+
+ if err := d.populateIPFromAddResult(stdout, &args); err != nil {
+ if de := execDel(); de != nil {
+ return args, nil, errors.CombineErrors(err, de)
+ }
+ }
+
+ return args, execDel, nil
+}
+
+func (d *Driver) JoinEndpointNetwork(args types.EndpointArgs) (func() error, error) {
+ _, _, err := d.calicoCNIAdd(&args, false)
+ return nil, errors.Wrap(err, "")
+}
+
+func (d *Driver) DeleteEndpointNetwork(args types.EndpointArgs) error {
+ return d.calicoCNIDel(&args)
+}
+
+func (d *Driver) calicoCNIDel(args *types.EndpointArgs) error {
+ env := d.makeCNIEnv(args)
+ env["CNI_COMMAND"] = cniCmdDel
+
+ dat, err := d.readCNIConfig()
+ if err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ _, err = execCNIPlugin(env, bytes.NewBuffer(dat), d.cfg.PluginPath)
+ return err
+}
+
+func (d *Driver) calicoCNIAdd(args *types.EndpointArgs, needRollback bool) (stdout []byte, rollback func() error, err error) {
+ env := d.makeCNIEnv(args)
+ env["CNI_COMMAND"] = cniCmdAdd
+
+ var dat []byte
+ if dat, err = d.readCNIConfig(); err != nil {
+ return nil, nil, errors.Wrap(err, "")
+ }
+
+ if stdout, err = execCNIPlugin(env, bytes.NewBuffer(dat), d.cfg.PluginPath); err != nil {
+ return nil, nil, errors.Wrap(err, "")
+ }
+
+ execDel := func() error {
+ env["CNI_COMMAND"] = cniCmdDel
+ _, err := execCNIPlugin(env, bytes.NewBuffer(dat), d.cfg.PluginPath)
+ return err
+ }
+
+ defer func() {
+ if err != nil && needRollback {
+ if de := execDel(); de != nil {
+ err = errors.CombineErrors(err, de)
+ }
+ execDel = nil
+ }
+ }()
+
+ // Refreshes gateway for non-Calico-CNI operations.
+ if err = d.RefreshGateway(); err != nil {
+ return nil, nil, errors.Wrap(err, "")
+ }
+
+ return stdout, execDel, nil
+}
+
+func (d *Driver) populateIPFromAddResult(dat []byte, args *types.EndpointArgs) error {
+ var result current.Result
+ if err := json.Unmarshal(dat, &result); err != nil {
+ return errors.Wrap(err, "")
+ }
+ if len(result.IPs) < 1 {
+ return errors.Wrap(terrors.ErrIPIsnotAssigned, "")
+ }
+
+ for _, ipConf := range result.IPs {
+ ip, err := calihandler.ParseCIDR(ipConf.Address.String())
+ if err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ gwip, err := d.GetGatewayIP(ip)
+ if err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ ip.BindGatewayIPNet(gwip.IPNetwork())
+ args.IPs = append(args.IPs, ip)
+ }
+
+ return nil
+}
+
+func (d *Driver) readCNIConfig() ([]byte, error) {
+ // TODO: follows the CNI policy, rather than hard code absolute path here.
+ return os.ReadFile(d.cfg.ConfigPath)
+}
+
+func (d *Driver) makeCNIEnv(args *types.EndpointArgs) map[string]string {
+ networkPair := d.cfg.IFNamePrefix + args.EndpointID[:utils.Min(12, len(args.EndpointID))]
+ return map[string]string{
+ "CNI_CONTAINERID": args.GuestID,
+ "CNI_ARGS": "IgnoreUnknown=1;MAC=" + args.MAC,
+ "CNI_IFNAME": networkPair,
+ "CNI_PATH": filepath.Dir(d.cfg.PluginPath),
+ "CNI_NETNS": "yap",
+ }
+}
+
+func execCNIPlugin(env map[string]string, stdin io.Reader, plugin string) ([]byte, error) {
+ ctx, cancel := context.WithTimeout(context.Background(), time.Minute*8)
+ defer cancel()
+
+ log.Debugf(context.TODO(), "CNI Plugin env: %v", env)
+ so, se, err := sh.ExecInOut(ctx, env, stdin, plugin)
+
+ if err != nil {
+ err = errors.Wrapf(err, "Failed to exec %s with %v: %s: %s", plugin, string(so), string(se))
+ }
+
+ return so, err
+}
diff --git a/internal/network/drivers/fake/fake.go b/internal/network/drivers/fake/fake.go
new file mode 100644
index 0000000..6caf083
--- /dev/null
+++ b/internal/network/drivers/fake/fake.go
@@ -0,0 +1,41 @@
+package fake
+
+import (
+ "context"
+
+ "github.com/projecteru2/yavirt/internal/meta"
+ "github.com/projecteru2/yavirt/internal/network/types"
+ "github.com/projecteru2/yavirt/internal/network/utils/device"
+ "github.com/prometheus/client_golang/prometheus"
+)
+
+type Driver struct{}
+
+func (d *Driver) CheckHealth(_ context.Context) error {
+ return nil
+}
+func (d *Driver) GetMetricsCollector() prometheus.Collector {
+ return nil
+}
+
+func (d *Driver) QueryIPs(meta.IPNets) ([]meta.IP, error) {
+ return nil, nil
+}
+func (d *Driver) CreateEndpointNetwork(types.EndpointArgs) (types.EndpointArgs, func() error, error) {
+ return types.EndpointArgs{}, nil, nil
+}
+func (d *Driver) JoinEndpointNetwork(types.EndpointArgs) (func() error, error) {
+ return nil, nil //nolint:nilnil
+}
+func (d *Driver) DeleteEndpointNetwork(types.EndpointArgs) error {
+ return nil
+}
+func (d *Driver) GetEndpointDevice(string) (device.VirtLink, error) {
+ return nil, nil //nolint
+}
+func (d *Driver) CreateNetworkPolicy(string) error {
+ return nil
+}
+func (d *Driver) DeleteNetworkPolicy(string) error {
+ return nil
+}
diff --git a/internal/network/drivers/ovn/ip.go b/internal/network/drivers/ovn/ip.go
new file mode 100644
index 0000000..55beff7
--- /dev/null
+++ b/internal/network/drivers/ovn/ip.go
@@ -0,0 +1,173 @@
+package ovn
+
+import (
+ "fmt"
+ "net"
+ "strings"
+
+ "github.com/pkg/errors"
+ "github.com/projecteru2/yavirt/internal/meta"
+ "github.com/projecteru2/yavirt/internal/network"
+ "github.com/projecteru2/yavirt/internal/network/utils/device"
+ "github.com/projecteru2/yavirt/pkg/netx"
+)
+
+// IP .
+// etcd keys:
+//
+// /ips//free/
+// /ips//occupied/
+type IP struct {
+ IPNet *net.IPNet
+ IP net.IP
+ Device device.VirtLink
+ GatewayIPNet *net.IPNet
+ GuestID string `json:"guest"`
+ *meta.Ver // just for fulfilling meta.IP, it doesn't be referred.
+}
+
+// NewIP .
+func NewIP(ipStr, subnet string) (*IP, error) {
+ ip, ipnet, err := net.ParseCIDR(subnet)
+ if err != nil {
+ return nil, err
+ }
+ if ipStr != "" {
+ ip = net.ParseIP(ipStr)
+ }
+ gwIP, err := netx.DefaultGatewayIP(ipnet)
+ if err != nil {
+ return nil, err
+ }
+ gwIPNet := &net.IPNet{
+ IP: gwIP,
+ Mask: ipnet.Mask,
+ }
+ ans := &IP{
+ IPNet: ipnet,
+ IP: ip,
+ GatewayIPNet: gwIPNet,
+ }
+ return ans, nil
+}
+
+// BindGatewayIPNet .
+func (ip *IP) BindGatewayIPNet(ipn *net.IPNet) {
+ ip.GatewayIPNet = ipn
+}
+
+// BindDevice .
+func (ip *IP) BindDevice(dev device.VirtLink) {
+ ip.Device = dev
+}
+
+// BindGuestID .
+func (ip *IP) BindGuestID(guestID string) {
+ ip.GuestID = guestID
+}
+
+// IntIP .
+func (ip *IP) IntIP() (v int64) {
+ v, _ = netx.IPv4ToInt(ip.IP.String())
+ return
+}
+
+// IntSubnet .
+func (ip *IP) IntSubnet() int64 {
+ return 0
+}
+
+// Prefix .
+func (ip *IP) Prefix() int {
+ var prefix, _ = ip.IPNet.Mask.Size()
+ return prefix
+}
+
+func (ip *IP) String() string {
+ return ip.CIDR()
+}
+
+// AutoRouteCIDR .
+func (ip *IP) AutoRouteCIDR() (string, error) {
+ var _, ipn, err = netx.ParseCIDR(ip.CIDR())
+ if err != nil {
+ return "", errors.Wrap(err, "")
+ }
+ return ipn.String(), nil
+}
+
+// CIDR .
+func (ip *IP) CIDR() string {
+ return ip.IPNet.String()
+}
+
+// NetIP .
+func (ip *IP) NetIP() net.IP {
+ return ip.IP
+}
+
+// IPNetwork .
+func (ip *IP) IPNetwork() *net.IPNet {
+ return ip.IPNet
+}
+
+// Netmask .
+func (ip *IP) Netmask() string {
+ mask := ip.IPNet.Mask
+ var s = make([]string, len(mask))
+
+ for i, byte := range mask {
+ s[i] = fmt.Sprintf("%d", byte)
+ }
+
+ return strings.Join(s, ".")
+}
+
+// IPAddr .
+func (ip *IP) IPAddr() string {
+ return ip.IP.String()
+}
+
+// SubnetAddr .
+func (ip *IP) SubnetAddr() string {
+ return ""
+}
+
+// IntGateway .
+func (ip *IP) IntGateway() (v int64) {
+ v, _ = netx.IPv4ToInt(ip.GatewayAddr())
+ return v
+}
+
+// GatewayPrefix .
+func (ip *IP) GatewayPrefix() int {
+ var prefix, _ = ip.IPNet.Mask.Size()
+ return prefix
+}
+
+// GatewayAddr .
+func (ip *IP) GatewayAddr() string {
+ return ip.GatewayIPNet.IP.String()
+}
+
+// IsAssigned always returns true,
+// the unassigned IPs're only stored in Calico itself.
+func (ip *IP) IsAssigned() bool {
+ return true
+}
+
+// MetaKey .
+func (ip *IP) MetaKey() string {
+ // DOES NOT STORE
+ return ""
+}
+
+// NetworkMode .
+func (ip *IP) NetworkMode() string {
+ return network.OVNMode
+}
+
+// NetworkName .
+func (ip *IP) NetworkName() (s string) {
+ return
+}
diff --git a/internal/network/drivers/ovn/metrics.go b/internal/network/drivers/ovn/metrics.go
new file mode 100644
index 0000000..27dbfa6
--- /dev/null
+++ b/internal/network/drivers/ovn/metrics.go
@@ -0,0 +1,39 @@
+package ovn
+
+import (
+ "sync/atomic"
+
+ "github.com/projecteru2/core/utils"
+ "github.com/projecteru2/yavirt/configs"
+ "github.com/prometheus/client_golang/prometheus"
+)
+
+var (
+ ovnHealthyDesc = prometheus.NewDesc(
+ prometheus.BuildFQName("node", "ovn", "healthy"),
+ "ovn healthy status.",
+ []string{"node"},
+ nil)
+)
+
+type MetricsCollector struct {
+ healthy atomic.Bool
+}
+
+func (d *Driver) GetMetricsCollector() prometheus.Collector {
+ return d.mCol
+}
+
+func (e *MetricsCollector) Describe(ch chan<- *prometheus.Desc) {
+ ch <- ovnHealthyDesc
+}
+
+func (e *MetricsCollector) Collect(ch chan<- prometheus.Metric) {
+ healthy := utils.Bool2Int(e.healthy.Load())
+ ch <- prometheus.MustNewConstMetric(
+ ovnHealthyDesc,
+ prometheus.GaugeValue,
+ float64(healthy),
+ configs.Hostname(),
+ )
+}
diff --git a/internal/network/drivers/ovn/models.go b/internal/network/drivers/ovn/models.go
new file mode 100644
index 0000000..7c37f67
--- /dev/null
+++ b/internal/network/drivers/ovn/models.go
@@ -0,0 +1,35 @@
+package ovn
+
+type LogicalSwitch struct {
+ UUID string `ovsdb:"_uuid"` // _uuid tag is mandatory
+ Name string `ovsdb:"name"`
+ Ports []string `ovsdb:"ports"`
+ Config map[string]string `ovsdb:"other_config"`
+}
+
+type LogicalSwitchPort struct {
+ UUID string `ovsdb:"_uuid"`
+ Name string `ovsdb:"name"`
+ Type string `ovsdb:"type"`
+ ExternalIDs map[string]string `ovsdb:"external_ids"`
+ Options map[string]string `ovsdb:"options"`
+ Addresses []string `ovsdb:"addresses"`
+ PortSecurity []string `ovsdb:"port_security"`
+ DynamicAddresses *string `ovsdb:"dynamic_addresses"`
+ ParentName *string `ovsdb:"parent_name"`
+ Tag *int `ovsdb:"tag"`
+ TagRequest *int `ovsdb:"tag_request"`
+ Up *bool `ovsdb:"up"`
+}
+
+type Interface struct {
+ UUID string `ovsdb:"_uuid"`
+ Name string `ovsdb:"name"`
+ Type string `ovsdb:"type"`
+ Error *string `ovsdb:"error"`
+ ExternalIDs map[string]string `ovsdb:"external_ids"`
+ Statistics map[string]int `ovsdb:"statistics"`
+ Config map[string]string `ovsdb:"other_config"`
+ AdminState *string `ovsdb:"admin_state"`
+ LinkState *string `ovsdb:"link_state"`
+}
diff --git a/internal/network/drivers/ovn/ovn.go b/internal/network/drivers/ovn/ovn.go
new file mode 100644
index 0000000..fbd74cc
--- /dev/null
+++ b/internal/network/drivers/ovn/ovn.go
@@ -0,0 +1,163 @@
+package ovn
+
+import (
+ "context"
+ "fmt"
+ "strings"
+ "sync"
+
+ "github.com/cockroachdb/errors"
+ "github.com/ovn-org/libovsdb/client"
+ "github.com/ovn-org/libovsdb/model"
+ "github.com/projecteru2/yavirt/configs"
+ "github.com/projecteru2/yavirt/internal/meta"
+ "github.com/projecteru2/yavirt/internal/network/types"
+ netutils "github.com/projecteru2/yavirt/internal/network/utils"
+ "github.com/projecteru2/yavirt/internal/utils"
+ "github.com/shirou/gopsutil/process"
+)
+
+const (
+ ovnMTU = 1442
+)
+
+type Driver struct {
+ sync.Mutex
+ mCol *MetricsCollector
+ cfg *configs.OVNConfig
+ nbClientDBModel model.ClientDBModel
+ nbCli client.Client
+ ovsClientDBModel model.ClientDBModel
+ ovsCli client.Client
+}
+
+func NewDriver(cfg *configs.OVNConfig) (*Driver, error) {
+ return &Driver{cfg: cfg, mCol: &MetricsCollector{}}, nil
+}
+
+func (d *Driver) CheckHealth(_ context.Context) (err error) {
+ defer func() {
+ if err != nil {
+ d.mCol.healthy.Store(false)
+ } else {
+ d.mCol.healthy.Store(true)
+ }
+ }()
+ processes, err := process.Processes()
+ if err != nil {
+ return err
+ }
+ binaries := []string{
+ "ovn-controller",
+ "ovsdb-server",
+ "ovs-vswitchd",
+ }
+ for _, name := range binaries {
+ if !utils.PSContains([]string{name}, processes) {
+ return errors.Newf("%s is not running", name)
+ }
+ }
+
+ return nil
+}
+
+func (d *Driver) QueryIPs(args meta.IPNets) ([]meta.IP, error) {
+ if len(args) == 0 {
+ return nil, nil
+ }
+ ans := make([]meta.IP, 0, len(args))
+ for _, ipn := range args {
+ ip, err := NewIP("", ipn.CIDR())
+ if err != nil {
+ return nil, err
+ }
+ ans = append(ans, ip)
+ }
+ return ans, nil
+}
+
+func (d *Driver) CreateEndpointNetwork(args types.EndpointArgs) (types.EndpointArgs, func() error, error) {
+ var (
+ err error
+ ls *LogicalSwitch
+ lsp *LogicalSwitchPort
+ )
+
+ if args.DevName, err = netutils.GenDevName(configs.Conf.Network.OVN.IFNamePrefix); err != nil {
+ return types.EndpointArgs{}, nil, err
+ }
+ // get LogicalSwitch
+ if args.OVN.LogicalSwitchUUID != "" {
+ if ls, err = d.getLogicalSwitch(args.OVN.LogicalSwitchUUID); err != nil {
+ return types.EndpointArgs{}, nil, err
+ }
+ } else {
+ lsList, err := d.getLogicalSwitchByName(args.OVN.LogicalSwitchName)
+ if err != nil {
+ return types.EndpointArgs{}, nil, err
+ }
+ switch len(lsList) {
+ case 1:
+ ls = lsList[0]
+ case 0:
+ return types.EndpointArgs{}, nil, fmt.Errorf("logical switch %s not found", args.OVN.LogicalSwitchName)
+ default:
+ return types.EndpointArgs{}, nil, fmt.Errorf("multiple logical switch %s found", args.OVN.LogicalSwitchName)
+ }
+ }
+ // create LogicalSwitchPort if necessary and then get it
+ if args.OVN.LogicalSwitchPortName != "" {
+ if lsp, err = d.getLogicalSwitchPortByName(args.OVN.LogicalSwitchPortName); err != nil {
+ return types.EndpointArgs{}, nil, err
+ }
+ } else {
+ lspUUID, err := d.createLogicalSwitchPort(&args)
+ if err != nil {
+ return types.EndpointArgs{}, nil, err
+ }
+ if lsp, err = d.getLogicalSwitchPort(lspUUID); err != nil {
+ return types.EndpointArgs{}, nil, err
+ }
+ }
+ subnet := ls.Config["subnet"]
+ addrs := strings.Split(*lsp.DynamicAddresses, " ")
+ mac := addrs[0]
+ ipv4 := addrs[1]
+ args.MAC = mac
+ args.MTU = ovnMTU
+ ip, err := NewIP(ipv4, subnet)
+ if err != nil {
+ return types.EndpointArgs{}, nil, err
+ }
+ args.IPs = append(args.IPs, ip)
+ return args, nil, nil
+}
+
+func (d *Driver) JoinEndpointNetwork(args types.EndpointArgs) (func() error, error) {
+ lspName := args.OVN.LogicalSwitchPortName
+ if lspName == "" {
+ lspName = LSPName(args.GuestID)
+ }
+ err := d.setExternalID(args.DevName, "iface-id", lspName)
+ return nil, err
+}
+
+func (d *Driver) DeleteEndpointNetwork(args types.EndpointArgs) error {
+ // lsp is provided by other component, so we ignore deleting lsp here
+ if args.OVN.LogicalSwitchPortName != "" {
+ return nil
+ }
+ return d.deleteLogicalSwitchPort(&args)
+}
+
+func (d *Driver) CreateNetworkPolicy(string) error {
+ return nil
+}
+
+func (d *Driver) DeleteNetworkPolicy(string) error {
+ return nil
+}
+
+func LSPName(guestID string) string {
+ return fmt.Sprintf("lsp-%s", guestID)
+}
diff --git a/internal/network/drivers/ovn/ovn_api.go b/internal/network/drivers/ovn/ovn_api.go
new file mode 100644
index 0000000..625e031
--- /dev/null
+++ b/internal/network/drivers/ovn/ovn_api.go
@@ -0,0 +1,402 @@
+package ovn
+
+import (
+ "context"
+ "fmt"
+ "log/slog"
+ "strings"
+ "time"
+
+ "github.com/cenkalti/backoff/v4"
+ "github.com/cockroachdb/errors"
+ "github.com/go-logr/logr"
+ "github.com/ovn-org/libovsdb/client"
+ "github.com/ovn-org/libovsdb/model"
+ "github.com/ovn-org/libovsdb/ovsdb"
+ "github.com/projecteru2/core/log"
+ "github.com/projecteru2/yavirt/internal/network/types"
+ "github.com/samber/lo"
+ slogzerolog "github.com/samber/slog-zerolog/v2"
+)
+
+func normalizeAddr(addr string) string {
+ if !(strings.HasPrefix(addr, "tcp:") || strings.HasPrefix(addr, "unix:")) {
+ if strings.HasPrefix(addr, "/") {
+ addr = "unix:" + addr
+ } else {
+ addr = "tcp:" + addr
+ }
+ }
+ return addr
+}
+
+func getCli(addrs []string, dbModelReq *model.ClientDBModel, monitor bool) (client.Client, error) {
+ opts := make([]client.Option, 0, len(addrs)+3)
+ for _, addr := range addrs {
+ addr = normalizeAddr(addr)
+ opts = append(opts, client.WithEndpoint(addr))
+ }
+
+ zlogger := log.GetGlobalLogger()
+ slogHandler := slogzerolog.Option{Level: slog.LevelDebug, Logger: zlogger}.NewZerologHandler()
+ ovsLogger := logr.FromSlogHandler(slogHandler)
+ opts = append(opts, []client.Option{
+ client.WithReconnect(15*time.Second, backoff.NewExponentialBackOff()),
+ // client.WithInactivityCheck(1*time.Minute, 10*time.Second, backoff.NewExponentialBackOff()),
+ client.WithLogger(&ovsLogger),
+ }...)
+ cli, err := client.NewOVSDBClient(*dbModelReq, opts...)
+ if err != nil {
+ return nil, err
+ }
+ if err = cli.Connect(context.TODO()); err != nil {
+ return nil, err
+ }
+ if monitor {
+ _, err = cli.MonitorAll(context.TODO())
+ }
+ return cli, err
+}
+
+func (d *Driver) getNBCli() (cli client.Client, err error) {
+ if d.nbCli == nil {
+ d.nbClientDBModel, _ = model.NewClientDBModel("OVN_Northbound", map[string]model.Model{
+ "Logical_Switch": &LogicalSwitch{},
+ "Logical_Switch_Port": &LogicalSwitchPort{},
+ })
+ // dbModelReq.SetIndexes(map[string][]model.ClientIndex{
+ // "Logical_Switch": {
+ // {
+ // Columns: []model.ColumnKey{
+ // {
+ // Column: "name",
+ // },
+ // },
+ // },
+ // },
+ // })
+ d.nbCli, err = getCli(d.cfg.NBAddrs, &d.nbClientDBModel, false)
+ }
+ return d.nbCli, err
+}
+
+func (d *Driver) getOVSDBCli() (cli client.Client, err error) {
+ if d.ovsCli == nil {
+ d.ovsClientDBModel, _ = model.NewClientDBModel("Open_vSwitch", map[string]model.Model{
+ "Interface": &Interface{},
+ })
+ d.ovsCli, err = getCli([]string{d.cfg.OVSDBAddr}, &d.ovsClientDBModel, true)
+ }
+ return d.ovsCli, err
+}
+
+func (d *Driver) setExternalID(ifaceName, key, value string) error {
+ iface := &Interface{
+ Name: ifaceName,
+ }
+ cli, err := d.getOVSDBCli()
+ if err != nil {
+ return err
+ }
+
+ err = cli.Get(context.TODO(), iface)
+ if err != nil {
+ return errors.Wrapf(err, "failed to get interface %s", ifaceName)
+ }
+ iface.ExternalIDs[key] = value
+
+ ops, err := cli.Where(iface).Update(iface)
+ if err != nil {
+ return errors.Wrapf(err, "failed to set external_id %s", key)
+ }
+ _, err = cli.Transact(context.TODO(), ops...)
+ if err != nil {
+ return errors.Wrapf(err, "failed to set external_id %s", key)
+ }
+ return nil
+}
+
+func (d *Driver) createLogicalSwitch(name string, subnet string) (string, error) { //nolint:unused
+ cli, err := d.getNBCli()
+ if err != nil {
+ return "", err
+ }
+ obj := &LogicalSwitch{
+ Name: name,
+ }
+ if subnet != "" {
+ obj.Config = map[string]string{
+ "subnet": subnet,
+ }
+ }
+ ops, err := cli.Create(obj)
+ if err != nil {
+ return "", errors.Wrapf(err, "failed to create logical switch %s", name)
+ }
+ opsRes, err := cli.Transact(context.TODO(), ops...)
+ if err != nil {
+ return "", errors.Wrapf(err, "failed to create logical switch %s", name)
+ }
+ var ansUUID string
+ if len(opsRes) > 0 {
+ ansUUID = opsRes[0].UUID.GoUUID
+ }
+ return ansUUID, nil
+}
+
+func (d *Driver) getLogicalSwitch(uuid string) (*LogicalSwitch, error) {
+ cli, err := d.getNBCli()
+ if err != nil {
+ return nil, err
+ }
+ obj := &LogicalSwitch{
+ UUID: uuid,
+ }
+ v, err := selectHelper(cli, "Logical_Switch", &d.nbClientDBModel, obj)
+ if err != nil {
+ return nil, err
+ }
+ if ans, ok := v.(*LogicalSwitch); !ok {
+ return nil, errors.New("failed to convert to LogicalSwitch")
+ } else { //nolint
+ return ans, nil
+ }
+}
+
+func (d *Driver) getLogicalSwitchByName(name string) ([]*LogicalSwitch, error) {
+ cli, err := d.getNBCli()
+ if err != nil {
+ return nil, err
+ }
+ obj := &LogicalSwitch{
+ Name: name,
+ }
+ ans, err := selectHelper(cli, "Logical_Switch", &d.nbClientDBModel, obj)
+ if err != nil {
+ return nil, err
+ }
+ if ans == nil {
+ return nil, nil
+ }
+ switch v := ans.(type) {
+ case *LogicalSwitch:
+ return []*LogicalSwitch{v}, nil
+ case []*LogicalSwitch:
+ return v, nil
+ default:
+ return nil, errors.New("failed to convert to LogicalSwitch")
+ }
+}
+
+func (d *Driver) getOneLogicalSwitchByName(name string) (*LogicalSwitch, error) {
+ lsList, err := d.getLogicalSwitchByName(name)
+ if err != nil {
+ return nil, err
+ }
+ switch len(lsList) {
+ case 1:
+ return lsList[0], nil
+ case 0:
+ return nil, fmt.Errorf("logical switch %s not found", name)
+ default:
+ return nil, fmt.Errorf("multiple logical switch %s found", name)
+ }
+}
+
+func (d *Driver) deleteLogicalSwitch(name string) error { //nolint:unused
+ cli, err := d.getNBCli()
+ if err != nil {
+ return err
+ }
+ ops, err := cli.Where(&LogicalSwitch{
+ Name: name,
+ }).Delete()
+ if err != nil {
+ return errors.Wrapf(err, "failed to delete logical switch %s", name)
+ }
+ _, err = cli.Transact(context.TODO(), ops...)
+ return errors.Wrapf(err, "failed to delete logical switch %s", name)
+}
+
+func (d *Driver) createLogicalSwitchPort(args *types.EndpointArgs) (string, error) {
+ cli, err := d.getNBCli()
+ if err != nil {
+ return "", err
+ }
+ namedUUID, err := newRowUUID()
+ if err != nil {
+ return "", err
+ }
+ obj := &LogicalSwitchPort{
+ UUID: namedUUID,
+ Name: LSPName(args.GuestID),
+ // Type: "internal",
+ Addresses: []string{
+ fmt.Sprintf("%s dynamic", args.MAC),
+ },
+ PortSecurity: []string{
+ args.MAC,
+ },
+ }
+ ops, err := cli.Create(obj)
+ if err != nil {
+ return "", errors.Wrapf(err, "failed to create logical switch port %s", LSPName(args.GuestID))
+ }
+
+ ls := &LogicalSwitch{
+ UUID: args.OVN.LogicalSwitchUUID,
+ }
+ if ls.UUID == "" {
+ ls, err = d.getOneLogicalSwitchByName(args.OVN.LogicalSwitchName)
+ if err != nil {
+ return "", err
+ }
+ }
+ lsOps, err := cli.Where(ls).Mutate(ls, model.Mutation{
+ Field: &ls.Ports,
+ Mutator: ovsdb.MutateOperationInsert,
+ Value: []string{namedUUID},
+ })
+ if err != nil {
+ return "", errors.Wrapf(err, "failed to create logical switch port %s", LSPName(args.GuestID))
+ }
+ ops = append(ops, lsOps...)
+
+ opsRes, err := cli.Transact(context.TODO(), ops...)
+ if err != nil {
+ return "", errors.Wrapf(err, "failed to create logical switch port %s", LSPName(args.GuestID))
+ }
+ err = lo.Reduce(opsRes, func(r error, op ovsdb.OperationResult, _ int) error {
+ if op.Error != "" {
+ return errors.CombineErrors(r, errors.Newf("%s: %s", op.Error, op.Details))
+ }
+ return r
+ }, nil)
+ if err != nil {
+ return "", err
+ }
+ var ansUUID string
+ if len(opsRes) > 0 {
+ ansUUID = opsRes[0].UUID.GoUUID
+ }
+ return ansUUID, nil
+}
+
+func (d *Driver) deleteLogicalSwitchPort(args *types.EndpointArgs) error {
+ cli, err := d.getNBCli()
+ if err != nil {
+ return err
+ }
+ lsUUID := args.OVN.LogicalSwitchUUID
+ if lsUUID == "" {
+ ls, err := d.getOneLogicalSwitchByName(args.OVN.LogicalSwitchName)
+ if err != nil {
+ return err
+ }
+ lsUUID = ls.UUID
+ }
+ ls := &LogicalSwitch{
+ UUID: lsUUID,
+ }
+ lsp, err := d.getLogicalSwitchPortByName(LSPName(args.GuestID))
+ if err != nil {
+ return err
+ }
+ uuid := lsp.UUID
+ ops, err := cli.Where(ls).Mutate(ls, model.Mutation{
+ Field: &ls.Ports,
+ Mutator: ovsdb.MutateOperationDelete,
+ Value: []string{uuid},
+ })
+ if err != nil {
+ return err
+ }
+ _, err = cli.Transact(context.TODO(), ops...)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func selectHelper(cli client.Client, table string, cModel *model.ClientDBModel, obj any) (any, error) {
+ ops, err := cli.Select(obj)
+ if err != nil {
+ return nil, err
+ }
+ opsRes, err := cli.Transact(context.TODO(), ops...)
+ if err != nil {
+ return nil, errors.Wrapf(err, "failed to run transaction for selection")
+ }
+ if opsRes[0].Error != "" {
+ return nil, errors.Newf("%s:%s", opsRes[0].Error, opsRes[0].Details)
+ }
+ if len(opsRes[0].Rows) == 0 {
+ return nil, nil //nolint:nilnil
+ }
+ dbModel, errList := model.NewDatabaseModel(cli.Schema(), *cModel)
+ err = lo.Reduce(errList, func(r error, e error, _ int) error {
+ return errors.CombineErrors(r, e)
+ }, nil)
+ if err != nil {
+ return nil, err
+ }
+
+ ans := make([]any, 0, len(opsRes[0].Rows))
+ for idx := range opsRes[0].Rows {
+ row := opsRes[0].Rows[idx]
+ var uuid string
+ if v, ok := row["_uuid"]; ok {
+ uuid = v.(ovsdb.UUID).GoUUID
+ }
+ mod, err := model.CreateModel(dbModel, table, &row, uuid)
+ if err != nil {
+ return nil, err
+ }
+ ans = append(ans, mod)
+ }
+ if len(ans) == 1 {
+ return ans[0], nil
+ }
+ return ans, nil
+}
+
+func (d *Driver) getLogicalSwitchPort(uuid string) (*LogicalSwitchPort, error) {
+ cli, err := d.getNBCli()
+ if err != nil {
+ return nil, err
+ }
+ obj := &LogicalSwitchPort{
+ UUID: uuid,
+ }
+ v, err := selectHelper(cli, "Logical_Switch_Port", &d.nbClientDBModel, obj)
+ if err != nil {
+ return nil, err
+ }
+ if v == nil {
+ return nil, nil //nolint:nilnil
+ }
+ if ans, ok := v.(*LogicalSwitchPort); !ok {
+ return nil, errors.New("failed to convert to LogicalSwitchPort")
+ } else { //nolint
+ return ans, nil
+ }
+}
+
+func (d *Driver) getLogicalSwitchPortByName(name string) (*LogicalSwitchPort, error) {
+ cli, err := d.getNBCli()
+ if err != nil {
+ return nil, err
+ }
+ obj := &LogicalSwitchPort{
+ Name: name,
+ }
+ v, err := selectHelper(cli, "Logical_Switch_Port", &d.nbClientDBModel, obj)
+ if err != nil {
+ return nil, err
+ }
+ if ans, ok := v.(*LogicalSwitchPort); !ok {
+ return nil, errors.New("failed to convert to LogicalSwitchPort")
+ } else { //nolint
+ return ans, nil
+ }
+}
diff --git a/internal/network/drivers/ovn/ovn_api_test.go b/internal/network/drivers/ovn/ovn_api_test.go
new file mode 100644
index 0000000..882d472
--- /dev/null
+++ b/internal/network/drivers/ovn/ovn_api_test.go
@@ -0,0 +1,95 @@
+package ovn
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/projecteru2/yavirt/configs"
+ "github.com/projecteru2/yavirt/internal/network/types"
+ "github.com/projecteru2/yavirt/pkg/test/assert"
+)
+
+func TestLS(t *testing.T) {
+ cfg := &configs.OVNConfig{
+ NBAddrs: []string{
+ "tcp:192.168.160.25:6641",
+ },
+ }
+ d, err := NewDriver(cfg)
+ assert.Nil(t, err)
+ // err = d.createLogicalSwitch("ut-test", "192.168.111.0/24")
+ // err = d.createLogicalSwitch("ut-test", "")
+ // assert.Nil(t, err)
+ newLS, err := d.getLogicalSwitch("c343cbde-67b4-4b86-9cc1-9452b270f6f6")
+ assert.Nil(t, err)
+ fmt.Printf("+++++++ new ls: %v\n", newLS)
+}
+
+func TestLSP(t *testing.T) {
+ cfg := &configs.OVNConfig{
+ NBAddrs: []string{
+ "tcp:192.168.160.25:6641",
+ },
+ }
+ d, err := NewDriver(cfg)
+ assert.Nil(t, err)
+ lsUUID, err := d.createLogicalSwitch("ut-test", "192.168.111.0/24")
+ assert.Nil(t, err)
+ // defer d.deleteLogicalSwitch("ut-test")
+ // lsUUID := "8c896d59-20d7-4b5f-9690-5b75ae03f787"
+ args := &types.EndpointArgs{
+ GuestID: "00052017027003203659270000000003",
+ MAC: "00:55:00:00:00:03",
+ OVN: types.OVNArgs{
+ LogicalSwitchUUID: lsUUID,
+ },
+ }
+ uuid, err := d.createLogicalSwitchPort(args)
+ assert.Nil(t, err)
+ fmt.Printf("++++++++ uuid: %s\n", uuid)
+ // time.Sleep(time.Millisecond)
+ // d.nbCli = nil
+ lsp, err := d.getLogicalSwitchPort(uuid)
+ assert.Nil(t, err)
+ fmt.Printf("++++++++ lsp: %v\n", lsp)
+ assert.NotNil(t, lsp.DynamicAddresses)
+ lsp1, err := d.getLogicalSwitchPortByName(LSPName(args.GuestID))
+ assert.Nil(t, err)
+ fmt.Printf("++++++++ lsp1: %v\n", lsp1)
+}
+
+func TestDeleteLSP(t *testing.T) {
+ // lsUUID := "46333352-cfbb-45e2-a172-c0076b985718"
+ guestID := "00009017034928197341160000000001"
+ cfg := &configs.OVNConfig{
+ NBAddrs: []string{
+ "tcp:192.168.160.25:6641",
+ },
+ }
+ d, err := NewDriver(cfg)
+ assert.Nil(t, err)
+ ls, err := d.getLogicalSwitchPortByName(LSPName(guestID))
+ assert.Nil(t, err)
+ fmt.Printf("+++++++++++ %v\n", ls)
+ err = d.deleteLogicalSwitchPort(&types.EndpointArgs{
+ GuestID: guestID,
+ // OVNLogicSwitchUUID: lsUUID,
+ OVN: types.OVNArgs{
+ LogicalSwitchName: "ut-test",
+ },
+ })
+ assert.Nil(t, err)
+}
+
+func TestSetExternalIDs(t *testing.T) {
+ cfg := &configs.OVNConfig{
+ NBAddrs: []string{
+ "tcp:192.168.160.25:6641",
+ },
+ OVSDBAddr: "tcp:192.168.160.26:6640",
+ }
+ d, err := NewDriver(cfg)
+ assert.Nil(t, err)
+ err = d.setExternalID("vm2", "iface-id", "vm2222222")
+ assert.Nil(t, err)
+}
diff --git a/internal/network/drivers/ovn/ovn_test.go b/internal/network/drivers/ovn/ovn_test.go
new file mode 100644
index 0000000..6a7d89f
--- /dev/null
+++ b/internal/network/drivers/ovn/ovn_test.go
@@ -0,0 +1,67 @@
+package ovn
+
+import (
+ "testing"
+
+ . "github.com/agiledragon/gomonkey/v2"
+ "github.com/projecteru2/yavirt/configs"
+ "github.com/projecteru2/yavirt/internal/network/types"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestCreateEndpointNetwork(t *testing.T) {
+ inputArgs := types.EndpointArgs{
+ GuestID: "00052017027003203659270000000003",
+ MAC: "00:55:00:00:00:03",
+ OVN: types.OVNArgs{
+ LogicalSwitchUUID: "haha-kaka",
+ },
+ }
+ lspUUID := "kaka-123456"
+ cfg := &configs.OVNConfig{
+ NBAddrs: []string{
+ "tcp:127.0.0.1:6641",
+ },
+ }
+ d, err := NewDriver(cfg)
+ assert.Nil(t, err)
+ assert.NotNil(t, d)
+ patches := ApplyPrivateMethod(d, "createLogicalSwitchPort", func(_ *Driver, args *types.EndpointArgs) (string, error) {
+ assert.Equal(t, inputArgs.OVN.LogicalSwitchUUID, args.OVN.LogicalSwitchUUID)
+ return lspUUID, nil
+ })
+ defer patches.Reset()
+
+ ls := &LogicalSwitch{
+ UUID: "haha-kaka",
+ Name: "test-ls",
+ Config: map[string]string{
+ "subnet": "192.168.110.1/24",
+ },
+ }
+ patches = ApplyPrivateMethod(d, "getLogicalSwitch", func(_ *Driver, uuid string) (*LogicalSwitch, error) {
+ assert.Equal(t, inputArgs.OVN.LogicalSwitchUUID, uuid)
+ return ls, nil
+ })
+ defer patches.Reset()
+
+ addr := "00:11:22:33:44:55 192.168.110.3"
+ lsp := &LogicalSwitchPort{
+ UUID: "haha-kaka",
+ Name: "test-lsp",
+ Addresses: []string{
+ "00:11:22:33:44:55 dynamic",
+ },
+ DynamicAddresses: &addr,
+ }
+ patches = ApplyPrivateMethod(d, "getLogicalSwitchPort", func(d *Driver, uuid string) (*LogicalSwitchPort, error) {
+ assert.Equal(t, lspUUID, uuid)
+ return lsp, nil
+ })
+ defer patches.Reset()
+ args, rollback, err := d.CreateEndpointNetwork(inputArgs)
+ assert.Nil(t, err)
+ assert.Nil(t, rollback)
+ assert.Len(t, args.IPs, 1)
+ assert.Equal(t, args.IPs[0].IPAddr(), "192.168.110.3")
+}
diff --git a/internal/network/drivers/ovn/utils.go b/internal/network/drivers/ovn/utils.go
new file mode 100644
index 0000000..cf31410
--- /dev/null
+++ b/internal/network/drivers/ovn/utils.go
@@ -0,0 +1,30 @@
+package ovn
+
+import (
+ "encoding/hex"
+
+ "github.com/google/uuid"
+)
+
+func encodeHex(dst []byte, id uuid.UUID) {
+ hex.Encode(dst, id[:4])
+ dst[8] = '_'
+ hex.Encode(dst[9:13], id[4:6])
+ dst[13] = '_'
+ hex.Encode(dst[14:18], id[6:8])
+ dst[18] = '_'
+ hex.Encode(dst[19:23], id[8:10])
+ dst[23] = '_'
+ hex.Encode(dst[24:], id[10:])
+}
+
+func newRowUUID() (string, error) {
+ id, err := uuid.NewRandom()
+ if err != nil {
+ return "", err
+ }
+ var buf [36 + 3]byte
+ copy(buf[:], "row")
+ encodeHex(buf[3:], id)
+ return string(buf[:]), nil
+}
diff --git a/internal/vnet/vlan/ip.go b/internal/network/drivers/vlan/ip.go
similarity index 92%
rename from internal/vnet/vlan/ip.go
rename to internal/network/drivers/vlan/ip.go
index ca61e04..bb13cab 100644
--- a/internal/vnet/vlan/ip.go
+++ b/internal/network/drivers/vlan/ip.go
@@ -6,8 +6,8 @@ import (
"net"
"github.com/projecteru2/yavirt/internal/meta"
- "github.com/projecteru2/yavirt/internal/vnet"
- "github.com/projecteru2/yavirt/internal/vnet/device"
+ "github.com/projecteru2/yavirt/internal/network"
+ "github.com/projecteru2/yavirt/internal/network/utils/device"
"github.com/projecteru2/yavirt/pkg/netx"
)
@@ -69,7 +69,7 @@ func (ip *IP) BindGuestID(guestID string) {
// Create .
func (ip *IP) Create() error {
- var ipam = NewIpam("", ip.Subnet.IntSubnet())
+ var ipam = NewIpam(ip.Subnet.IntSubnet())
var ctx, cancel = meta.Context(context.Background())
defer cancel()
@@ -126,7 +126,7 @@ func (ip *IP) equal(b *IP) bool { //nolint
// NetworkMode .
func (ip *IP) NetworkMode() string {
- return vnet.NetworkVlan
+ return network.VlanMode
}
// NetworkName .
diff --git a/internal/vnet/vlan/ipam.go b/internal/network/drivers/vlan/ipam.go
similarity index 74%
rename from internal/vnet/vlan/ipam.go
rename to internal/network/drivers/vlan/ipam.go
index 358c5af..c27f1c8 100644
--- a/internal/vnet/vlan/ipam.go
+++ b/internal/network/drivers/vlan/ipam.go
@@ -5,40 +5,40 @@ import (
clientv3 "go.etcd.io/etcd/client/v3"
+ "github.com/cockroachdb/errors"
"github.com/projecteru2/yavirt/internal/meta"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/projecteru2/yavirt/internal/network/types"
"github.com/projecteru2/yavirt/pkg/store"
+ "github.com/projecteru2/yavirt/pkg/terrors"
"github.com/projecteru2/yavirt/pkg/utils"
)
// Ipam .
type Ipam struct {
- subnet int64
- guestID string
+ subnet int64
}
// NewIpam .
-func NewIpam(guestID string, subnet int64) *Ipam {
+func NewIpam(subnet int64) *Ipam {
return &Ipam{
- subnet: subnet,
- guestID: guestID,
+ subnet: subnet,
}
}
// Assign .
-func (ipam *Ipam) Assign(ctx context.Context) (ip meta.IP, err error) {
+func (ipam *Ipam) Assign(ctx context.Context, args *types.EndpointArgs) (ip meta.IP, err error) {
var unlock utils.Unlocker
if unlock, err = ipam.Lock(ctx); err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
defer func() {
- if ue := unlock(context.Background()); ue != nil {
- err = errors.Wrap(err, ue)
+ if ue := unlock(context.TODO()); ue != nil {
+ err = errors.CombineErrors(err, ue)
}
}()
- return ipam.assign(ctx, ipam.guestID)
+ return ipam.assign(ctx, args.GuestID)
}
// Release .
@@ -49,12 +49,12 @@ func (ipam *Ipam) Release(ctx context.Context, ips ...meta.IP) (err error) {
var unlock utils.Unlocker
if unlock, err = ipam.Lock(ctx); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
defer func() {
if ue := unlock(context.Background()); ue != nil {
- err = errors.Wrap(err, ue)
+ err = errors.CombineErrors(err, ue)
}
}()
@@ -69,21 +69,21 @@ func (ipam *Ipam) Insert(ctx context.Context, ip *IP) (err error) {
var unlock utils.Unlocker
if unlock, err = ipam.Lock(ctx); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
defer func() {
if ue := unlock(context.Background()); ue != nil {
- err = errors.Wrap(err, ue)
+ err = errors.CombineErrors(err, ue)
}
}()
var exists bool
switch exists, err = ipam.exists(ctx, ip); {
case err != nil:
- return errors.Trace(err)
+ return errors.Wrap(err, "")
case exists:
- return errors.Annotatef(errors.ErrKeyExists, ip.CIDR())
+ return errors.Wrapf(terrors.ErrKeyExists, ip.CIDR())
}
return ipam.insert(ip)
@@ -96,7 +96,7 @@ func (ipam *Ipam) Query(ctx context.Context, args meta.IPNets) ([]meta.IP, error
for i := range args {
if ips[i], err = ipam.load(ctx, args[i]); err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
}
@@ -106,7 +106,7 @@ func (ipam *Ipam) Query(ctx context.Context, args meta.IPNets) ([]meta.IP, error
func (ipam *Ipam) load(_ context.Context, arg *meta.IPNet) (*IP, error) {
subn, err := LoadSubnet(arg.IntSubnet)
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
var ip = NewIP()
@@ -115,7 +115,7 @@ func (ipam *Ipam) load(_ context.Context, arg *meta.IPNet) (*IP, error) {
ip.occupied = arg.Assigned
if err := meta.Load(ip); err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
return ip, nil
@@ -128,7 +128,7 @@ func (ipam *Ipam) insert(ip *IP) error {
func (ipam *Ipam) check(ips ...meta.IP) error {
for _, ip := range ips {
if ip.IntSubnet() != ipam.subnet {
- return errors.Annotatef(errors.ErrInvalidValue, "invalid subnet: %s", ip.SubnetAddr())
+ return errors.Wrapf(terrors.ErrInvalidValue, "invalid subnet: %s", ip.SubnetAddr())
}
}
return nil
@@ -138,7 +138,7 @@ func (ipam *Ipam) exists(ctx context.Context, ip *IP) (bool, error) {
var keys = []string{ip.freeKey(), ip.occupiedKey()}
var exists, err = store.Exists(ctx, keys)
if err != nil {
- return false, errors.Trace(err)
+ return false, errors.Wrap(err, "")
}
for _, v := range exists {
@@ -159,7 +159,7 @@ func (ipam *Ipam) release(ctx context.Context, ips ...meta.IP) error {
ip.BindGuestID("")
if err := ipam.doop(ctx, ip, putkey, delkey); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
}
@@ -169,12 +169,12 @@ func (ipam *Ipam) release(ctx context.Context, ips ...meta.IP) error {
func (ipam *Ipam) assign(ctx context.Context, guestID string) (*IP, error) {
var ip, err = ipam.pickup(ctx)
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
ip.GuestID = guestID
if err := ipam.occupy(ctx, ip); err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
return ip, nil
@@ -189,7 +189,7 @@ func (ipam *Ipam) occupy(ctx context.Context, ip *IP) error {
func (ipam *Ipam) doop(ctx context.Context, ip meta.IP, putkey, delkey string) error {
var enc, err = utils.JSONEncode(ip, "\t")
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
var ops = []clientv3.Op{
@@ -199,9 +199,9 @@ func (ipam *Ipam) doop(ctx context.Context, ip meta.IP, putkey, delkey string) e
switch succ, err := store.BatchOperate(ctx, ops); {
case err != nil:
- return errors.Trace(err)
+ return errors.Wrap(err, "")
case !succ:
- return errors.Annotatef(errors.ErrOperateIP, "put: %s, del: %s", putkey, delkey)
+ return errors.Wrapf(terrors.ErrOperateIP, "put: %s, del: %s", putkey, delkey)
}
return nil
@@ -210,12 +210,12 @@ func (ipam *Ipam) doop(ctx context.Context, ip meta.IP, putkey, delkey string) e
func (ipam *Ipam) pickup(ctx context.Context) (*IP, error) {
var subnet = NewSubnet(ipam.subnet)
if err := meta.Load(subnet); err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
var data, vers, err = store.GetPrefix(ctx, meta.FreeIPPrefix(ipam.subnet), 1)
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
var ip = NewIP()
@@ -224,11 +224,11 @@ func (ipam *Ipam) pickup(ctx context.Context) (*IP, error) {
for key, val := range data {
var ver, exists = vers[key]
if !exists {
- return nil, errors.Annotatef(errors.ErrKeyBadVersion, key)
+ return nil, errors.Wrapf(terrors.ErrKeyBadVersion, key)
}
if err := utils.JSONDecode(val, ip); err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
ip.SetVer(ver)
diff --git a/internal/network/drivers/vlan/metrics.go b/internal/network/drivers/vlan/metrics.go
new file mode 100644
index 0000000..7449a05
--- /dev/null
+++ b/internal/network/drivers/vlan/metrics.go
@@ -0,0 +1,39 @@
+package vlan
+
+import (
+ "sync/atomic"
+
+ "github.com/projecteru2/core/utils"
+ "github.com/projecteru2/yavirt/configs"
+ "github.com/prometheus/client_golang/prometheus"
+)
+
+var (
+ vlanHealthyDesc = prometheus.NewDesc(
+ prometheus.BuildFQName("network", "vlan", "healthy"),
+ "vlan healthy status.",
+ []string{"node"},
+ nil)
+)
+
+type MetricsCollector struct {
+ healthy atomic.Bool
+}
+
+func (d *Handler) GetMetricsCollector() prometheus.Collector {
+ return d.mCol
+}
+
+func (e *MetricsCollector) Describe(ch chan<- *prometheus.Desc) {
+ ch <- vlanHealthyDesc
+}
+
+func (e *MetricsCollector) Collect(ch chan<- prometheus.Metric) {
+ healthy := utils.Bool2Int(e.healthy.Load())
+ ch <- prometheus.MustNewConstMetric(
+ vlanHealthyDesc,
+ prometheus.GaugeValue,
+ float64(healthy),
+ configs.Hostname(),
+ )
+}
diff --git a/internal/vnet/vlan/subnet.go b/internal/network/drivers/vlan/subnet.go
similarity index 100%
rename from internal/vnet/vlan/subnet.go
rename to internal/network/drivers/vlan/subnet.go
diff --git a/internal/network/drivers/vlan/vlan.go b/internal/network/drivers/vlan/vlan.go
new file mode 100644
index 0000000..5f348d2
--- /dev/null
+++ b/internal/network/drivers/vlan/vlan.go
@@ -0,0 +1,84 @@
+package vlan
+
+import (
+ "context"
+
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/yavirt/internal/meta"
+ "github.com/projecteru2/yavirt/internal/network"
+ "github.com/projecteru2/yavirt/internal/network/types"
+ "github.com/projecteru2/yavirt/pkg/terrors"
+)
+
+// Handler .
+type Handler struct {
+ mCol *MetricsCollector
+ subnet int64
+}
+
+// New .
+func New(subnet int64) *Handler {
+ return &Handler{subnet: subnet, mCol: &MetricsCollector{}}
+}
+
+func (h *Handler) CheckHealth(_ context.Context) error {
+ return nil
+}
+
+// NewIP .
+func (h *Handler) NewIP(_, _ string) (meta.IP, error) {
+ return nil, errors.Wrap(terrors.ErrNotImplemented, "NewIP error")
+}
+
+// QueryIPs .
+func (h *Handler) QueryIPs(ipns meta.IPNets) ([]meta.IP, error) {
+ return h.ipam().Query(context.TODO(), ipns)
+}
+
+func (h *Handler) ipam() network.Ipam {
+ return NewIpam(h.subnet)
+}
+
+// CreateEndpointNetwork .
+func (h *Handler) CreateEndpointNetwork(args types.EndpointArgs) (resp types.EndpointArgs, rollback func() error, err error) {
+ ip, err := h.ipam().Assign(context.TODO(), &args)
+ if err != nil {
+ return
+ }
+ resp = args
+ resp.IPs = append(resp.IPs, ip)
+ rollback = func() error {
+ return h.ipam().Release(context.Background(), ip)
+ }
+ return
+}
+
+// JoinEndpointNetwork .
+func (h *Handler) JoinEndpointNetwork(types.EndpointArgs) (rollback func() error, err error) {
+ // DO NOTHING
+ return
+}
+
+// DeleteEndpointNetwork .
+func (h *Handler) DeleteEndpointNetwork(args types.EndpointArgs) error {
+ return h.ipam().Release(context.Background(), args.IPs...)
+}
+
+// QueryIPv4 .
+func (h *Handler) QueryIPv4(string) (meta.IP, error) {
+ return nil, errors.Wrapf(terrors.ErrNotImplemented, "QueryIPv4 error")
+}
+
+// GetCidr .
+func (h *Handler) GetCidr() string {
+ ip := IP{Value: h.subnet, Subnet: &Subnet{SubnetPrefix: 0}}
+ return ip.CIDR()
+}
+
+func (h *Handler) CreateNetworkPolicy(string) error {
+ return nil
+}
+
+func (h *Handler) DeleteNetworkPolicy(string) error {
+ return nil
+}
diff --git a/internal/network/factory/factory.go b/internal/network/factory/factory.go
new file mode 100644
index 0000000..12c01dd
--- /dev/null
+++ b/internal/network/factory/factory.go
@@ -0,0 +1,135 @@
+package factory
+
+import (
+ "context"
+
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/yavirt/configs"
+ "github.com/projecteru2/yavirt/internal/network"
+ "github.com/projecteru2/yavirt/internal/network/drivers/calico"
+ cniCalico "github.com/projecteru2/yavirt/internal/network/drivers/cni/calico"
+ "github.com/projecteru2/yavirt/internal/network/drivers/fake"
+ "github.com/projecteru2/yavirt/internal/network/drivers/ovn"
+ "github.com/projecteru2/yavirt/internal/network/drivers/vlan"
+ "github.com/prometheus/client_golang/prometheus"
+)
+
+var (
+ gF *Factory
+)
+
+type Factory struct {
+ Config *configs.NetworkConfig
+ networkHandlers map[string]network.Driver
+}
+
+func Setup(cfg *configs.NetworkConfig) (err error) {
+ gF, err = New(cfg)
+ return err
+}
+
+func CheckHealth(ctx context.Context) error {
+ for _, d := range gF.networkHandlers {
+ if err := d.CheckHealth(ctx); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func GetMetricsCollectors() (ans []prometheus.Collector) {
+ for _, d := range gF.networkHandlers {
+ col := d.GetMetricsCollector()
+ if col == nil {
+ continue
+ }
+ ans = append(ans, col)
+ }
+ return ans
+}
+
+func GetDriver(mode string) network.Driver {
+ return gF.networkHandlers[mode]
+}
+
+func ListDrivers() map[string]network.Driver {
+ return gF.networkHandlers
+}
+
+func New(cfg *configs.NetworkConfig) (*Factory, error) {
+ f := &Factory{
+ Config: cfg,
+ networkHandlers: map[string]network.Driver{
+ network.FakeMode: &fake.Driver{},
+ },
+ }
+ err := f.setupDrivers()
+ return f, err
+}
+
+func (f *Factory) setupDrivers() error {
+ cfg := f.Config
+ for _, mode := range cfg.Modes {
+ switch mode {
+ case network.CalicoMode:
+ if err := f.setupCalico(); err != nil {
+ return errors.Wrap(err, "")
+ }
+ case network.CalicoCNIMode:
+ if err := f.setupCalicoCNI(); err != nil {
+ return errors.Wrap(err, "")
+ }
+ case network.VlanMode:
+ if err := f.setupVlan(); err != nil {
+ return errors.Wrap(err, "")
+ }
+ case network.OVNMode:
+ if err := f.setupOVN(); err != nil {
+ return errors.Wrap(err, "")
+ }
+ default:
+ return errors.Newf("invalid network mode: %s", mode)
+ }
+ }
+ return nil
+}
+
+func (f *Factory) setupCalicoCNI() error {
+ cali, err := calico.NewDriver(&f.Config.Calico)
+ if err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ driver, err := cniCalico.NewDriver(&f.Config.CNI, cali)
+ if err != nil {
+ return errors.Wrap(err, "")
+ }
+ f.networkHandlers[network.CalicoCNIMode] = driver
+ return nil
+}
+
+func (f *Factory) setupVlan() error { //nolint
+ cfg := f.Config.Vlan
+ f.networkHandlers[network.VlanMode] = vlan.New(int64(cfg.Subnet))
+ return nil
+}
+
+func (f *Factory) setupOVN() (err error) {
+ cfg := &f.Config.OVN
+ f.networkHandlers[network.OVNMode], err = ovn.NewDriver(cfg)
+ return
+}
+
+func (f *Factory) setupCalico() error {
+ cali, err := calico.NewDriver(&f.Config.Calico)
+ if err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ // if err := svc.caliHandler.InitGateway(f.Config.Calico.GatewayName); err != nil {
+ // return errors.Wrap(err, "")
+ // }
+
+ f.networkHandlers[network.CalicoMode] = cali
+ return nil
+}
diff --git a/internal/network/network.go b/internal/network/network.go
new file mode 100644
index 0000000..f7eb42e
--- /dev/null
+++ b/internal/network/network.go
@@ -0,0 +1,32 @@
+package network
+
+import (
+ "context"
+
+ "github.com/projecteru2/yavirt/internal/meta"
+ "github.com/projecteru2/yavirt/internal/network/types"
+ "github.com/prometheus/client_golang/prometheus"
+)
+
+type Driver interface {
+ // Prepare(ctx context.Context) error
+
+ CheckHealth(ctx context.Context) error
+ QueryIPs(meta.IPNets) ([]meta.IP, error)
+
+ CreateEndpointNetwork(types.EndpointArgs) (types.EndpointArgs, func() error, error)
+ JoinEndpointNetwork(types.EndpointArgs) (func() error, error)
+ DeleteEndpointNetwork(types.EndpointArgs) error
+
+ CreateNetworkPolicy(string) error
+ DeleteNetworkPolicy(string) error
+
+ GetMetricsCollector() prometheus.Collector
+}
+
+// Ipam .
+type Ipam interface {
+ Assign(ctx context.Context, args *types.EndpointArgs) (meta.IP, error)
+ Release(context.Context, ...meta.IP) error
+ Query(context.Context, meta.IPNets) ([]meta.IP, error)
+}
diff --git a/internal/network/types/types.go b/internal/network/types/types.go
new file mode 100644
index 0000000..d8f7add
--- /dev/null
+++ b/internal/network/types/types.go
@@ -0,0 +1,68 @@
+package types
+
+import (
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/yavirt/internal/meta"
+ "github.com/projecteru2/yavirt/pkg/terrors"
+)
+
+type CalicoArgs struct {
+ IPPool string `json:"ippool"`
+ Namespace string `json:"namespace"`
+
+ ResourceVersion string
+ UID string
+ Profiles []string
+}
+
+type OVNArgs struct {
+ LogicalSwitchUUID string `json:"logical_switch_uuid"`
+ LogicalSwitchName string `json:"logical_switch_name"`
+ LogicalSwitchPortName string `json:"logical_switch_port_name"`
+}
+
+type VlanArgs struct {
+ // TODO
+}
+
+type CNIArgs struct {
+}
+
+// EndpointArgs .
+type EndpointArgs struct {
+ GuestID string
+ EndpointID string
+ IPs []meta.IP
+ DevName string
+ MAC string
+ MTU int
+ Hostname string
+
+ Calico CalicoArgs
+ OVN OVNArgs
+ Vlan VlanArgs
+ CNI CNIArgs
+}
+
+// Check .
+func (a EndpointArgs) Check() error {
+ switch {
+ case len(a.EndpointID) < 1:
+ return errors.Wrapf(terrors.ErrInvalidValue, "EndpointID is empty")
+
+ case len(a.IPs) < 1:
+ return errors.Wrapf(terrors.ErrInvalidValue, "IPs is empty")
+
+ case a.DevName == "":
+ return errors.Wrapf(terrors.ErrInvalidValue, "Device is nil")
+
+ case len(a.MAC) < 1:
+ return errors.Wrapf(terrors.ErrInvalidValue, "MAC is empty")
+
+ case len(a.Hostname) < 1:
+ return errors.Wrapf(terrors.ErrInvalidValue, "Hostname is empty")
+
+ default:
+ return nil
+ }
+}
diff --git a/internal/vnet/device/addr.go b/internal/network/utils/device/addr.go
similarity index 87%
rename from internal/vnet/device/addr.go
rename to internal/network/utils/device/addr.go
index d007f89..5a1a818 100644
--- a/internal/vnet/device/addr.go
+++ b/internal/network/utils/device/addr.go
@@ -5,7 +5,7 @@ import (
"github.com/vishvananda/netlink"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/cockroachdb/errors"
)
// Addr .
@@ -49,12 +49,12 @@ func (a Addrs) Len() int {
func (d *Driver) BindAddr(cidr, linkName string) error {
addr, err := d.ParseCIDR(cidr)
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
link, err := d.ShowLink(linkName)
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
return link.BindAddr(addr)
@@ -64,7 +64,7 @@ func (d *Driver) BindAddr(cidr, linkName string) error {
func (d *Driver) ParseCIDR(cidr string) (*Addr, error) {
var raw, err = netlink.ParseAddr(cidr)
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
return &Addr{Addr: raw}, nil
@@ -74,7 +74,7 @@ func (d *Driver) ParseCIDR(cidr string) (*Addr, error) {
func (d *Driver) ListAddrs(linkName string, _ int) (Addrs, error) {
link, err := d.ShowLink(linkName)
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
return link.ListAddr()
diff --git a/internal/vnet/device/attr.go b/internal/network/utils/device/attr.go
similarity index 79%
rename from internal/vnet/device/attr.go
rename to internal/network/utils/device/attr.go
index dd04d0a..9d3a2dd 100644
--- a/internal/vnet/device/attr.go
+++ b/internal/network/utils/device/attr.go
@@ -6,7 +6,8 @@ import (
"github.com/vishvananda/netlink"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/yavirt/pkg/terrors"
"github.com/projecteru2/yavirt/pkg/utils"
)
@@ -34,11 +35,11 @@ func newHardwareAddr(linkType string) (net.HardwareAddr, error) {
mac, err = newTuntapMAC()
default:
- err = errors.Annotatef(errors.ErrInvalidValue, "unexpected link type: %s", linkType)
+ err = errors.Wrapf(terrors.ErrInvalidValue, "unexpected link type: %s", linkType)
}
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
return net.ParseMAC(mac)
@@ -47,7 +48,7 @@ func newHardwareAddr(linkType string) (net.HardwareAddr, error) {
func newTuntapMAC() (string, error) {
var buf, err = utils.RandBuf(3)
if err != nil {
- return "", errors.Trace(err)
+ return "", errors.Wrap(err, "")
}
return fmt.Sprintf("fe:54:00:%02x:%02x:%02x", buf[0], buf[1], buf[2]), nil
}
diff --git a/internal/vnet/device/const.go b/internal/network/utils/device/const.go
similarity index 100%
rename from internal/vnet/device/const.go
rename to internal/network/utils/device/const.go
diff --git a/internal/vnet/device/driver.go b/internal/network/utils/device/driver.go
similarity index 82%
rename from internal/vnet/device/driver.go
rename to internal/network/utils/device/driver.go
index 0ddc9db..2c4be70 100644
--- a/internal/vnet/device/driver.go
+++ b/internal/network/utils/device/driver.go
@@ -5,7 +5,7 @@ import (
"github.com/vishvananda/netlink"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/cockroachdb/errors"
)
// Driver .
@@ -19,7 +19,7 @@ type Driver struct {
func New() (*Driver, error) {
var handle, err = netlink.NewHandle()
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
return &Driver{Handle: handle}, nil
diff --git a/internal/vnet/device/dummy.go b/internal/network/utils/device/dummy.go
similarity index 100%
rename from internal/vnet/device/dummy.go
rename to internal/network/utils/device/dummy.go
diff --git a/internal/vnet/device/generic.go b/internal/network/utils/device/generic.go
similarity index 86%
rename from internal/vnet/device/generic.go
rename to internal/network/utils/device/generic.go
index 4a91868..b80d0b1 100644
--- a/internal/vnet/device/generic.go
+++ b/internal/network/utils/device/generic.go
@@ -4,9 +4,10 @@ import (
"fmt"
"net"
+ "github.com/projecteru2/yavirt/pkg/terrors"
"github.com/vishvananda/netlink"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/cockroachdb/errors"
)
type genericLink struct {
@@ -28,7 +29,7 @@ func (g *genericLink) BindAddr(addr *Addr) error {
var err = g.AddrAdd(g, addr.Addr)
if err != nil && isFileExistsErr(err) {
- return errors.Annotatef(errors.ErrVirtLinkAddrExists, "%s", addr)
+ return errors.Wrapf(terrors.ErrVirtLinkAddrExists, "%s", addr)
}
return err
@@ -37,7 +38,7 @@ func (g *genericLink) BindAddr(addr *Addr) error {
func (g *genericLink) ListAddr() (Addrs, error) {
var raw, err = g.AddrList(g, FamilyIPv4)
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
return newAddrs(raw), nil
}
@@ -47,7 +48,7 @@ func (g *genericLink) Add() error {
defer g.Unlock()
if _, err := g.showLink(g.Name()); err == nil {
- return errors.Annotatef(errors.ErrVirtLinkExists, g.Name())
+ return errors.Wrapf(terrors.ErrVirtLinkExists, g.Name())
}
return g.LinkAdd(g.Link)
@@ -77,12 +78,12 @@ func (g *genericLink) ClearRoutes() error {
var raw, err = g.RouteList(g, FamilyIPv4)
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
for _, r := range raw {
if err := g.deleteRoute(r.Dst); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
}
@@ -95,7 +96,7 @@ func (g *genericLink) DeleteRoute(cidr string) error {
var raw, err = g.RouteList(g, FamilyIPv4)
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
for _, r := range raw {
diff --git a/internal/vnet/device/link.go b/internal/network/utils/device/link.go
similarity index 73%
rename from internal/vnet/device/link.go
rename to internal/network/utils/device/link.go
index a8c6988..da2fbf8 100644
--- a/internal/vnet/device/link.go
+++ b/internal/network/utils/device/link.go
@@ -3,9 +3,10 @@ package device
import (
"strings"
+ "github.com/projecteru2/yavirt/pkg/terrors"
"github.com/vishvananda/netlink"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/cockroachdb/errors"
)
// VirtLink .
@@ -31,7 +32,7 @@ type VirtLink interface { //nolint
func createVirtLink(linkType, name string, d *Driver) (VirtLink, error) {
var hwAddr, err = newHardwareAddr(linkType)
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
var attrs = NewAttrs(name, hwAddr)
@@ -44,7 +45,7 @@ func createVirtLink(linkType, name string, d *Driver) (VirtLink, error) {
return createTuntap(attrs, d), nil
default:
- return nil, errors.Annotatef(errors.ErrInvalidValue, "unexpected link type: %s", linkType)
+ return nil, errors.Wrapf(terrors.ErrInvalidValue, "unexpected link type: %s", linkType)
}
}
@@ -59,7 +60,7 @@ func newVirtLink(raw netlink.Link, d *Driver) (VirtLink, error) {
return newTuntap(raw, d), nil
default:
- return nil, errors.Annotatef(errors.ErrInvalidValue, "unexpected link type: %s", raw.Type())
+ return nil, errors.Wrapf(terrors.ErrInvalidValue, "unexpected link type: %s", raw.Type())
}
}
@@ -70,7 +71,7 @@ func (d *Driver) ShowLinkByIndex(index int) (VirtLink, error) {
var raw, err = d.LinkByIndex(index)
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
return newVirtLink(raw, d)
@@ -87,10 +88,10 @@ func (d *Driver) showLink(name string) (VirtLink, error) {
var raw, err = d.LinkByName(name)
if err != nil {
if err.Error() == "Link not found" {
- err = errors.Trace(errors.ErrVirtLinkNotExists)
+ err = errors.Wrapf(terrors.ErrVirtLinkNotExists, "failed to get link %s", name)
}
- return nil, errors.Annotatef(err, name)
+ return nil, errors.Wrap(err, name)
}
return newVirtLink(raw, d)
@@ -103,14 +104,14 @@ func (d *Driver) ListLinks() (VirtLinks, error) {
var raws, err = d.LinkList()
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
var links = make(VirtLinks, len(raws))
for i, raw := range raws {
if links[i], err = newVirtLink(raw, d); err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
}
@@ -121,16 +122,28 @@ func (d *Driver) ListLinks() (VirtLinks, error) {
func (d *Driver) AddLink(linkType, name string) (VirtLink, error) {
var link, err = createVirtLink(linkType, name, d)
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
if err := link.Add(); err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
return link, nil
}
+// delete link by name
+func (d *Driver) DeleteLink(name string) error {
+ var raw, err = d.LinkByName(name)
+ if err != nil {
+ if err.Error() == "Link not found" {
+ err = errors.Wrapf(terrors.ErrVirtLinkNotExists, "failed to delete link %s", name)
+ }
+ return err
+ }
+ return d.LinkDel(raw)
+}
+
// CheckLinkType .
func (d *Driver) CheckLinkType(linkType string) bool {
return linkType == LinkTypeDummy ||
diff --git a/internal/vnet/device/link_test.go b/internal/network/utils/device/link_test.go
similarity index 100%
rename from internal/vnet/device/link_test.go
rename to internal/network/utils/device/link_test.go
diff --git a/internal/vnet/device/route.go b/internal/network/utils/device/route.go
similarity index 86%
rename from internal/vnet/device/route.go
rename to internal/network/utils/device/route.go
index c34f24e..5cfc189 100644
--- a/internal/vnet/device/route.go
+++ b/internal/network/utils/device/route.go
@@ -7,8 +7,9 @@ import (
"github.com/vishvananda/netlink"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/cockroachdb/errors"
"github.com/projecteru2/yavirt/pkg/netx"
+ "github.com/projecteru2/yavirt/pkg/terrors"
)
// Route .
@@ -38,7 +39,7 @@ func (r *Route) add() error {
var err = r.RouteAdd(r.Route)
if err != nil && isFileExistsErr(err) {
- return errors.Trace(errors.ErrVirtLinkRouteExists)
+ return errors.Wrap(terrors.ErrVirtLinkRouteExists, "failed to add route")
}
return err
@@ -49,7 +50,7 @@ func (r *Route) delete() error {
}
func (r *Route) String() string {
- var linkName, _ = r.linkName() //nolint
+ var linkName, _ = r.linkName()
if r.isGw() {
return fmt.Sprintf("default via %s dev %s", r.Gw, linkName)
@@ -67,7 +68,7 @@ func (r *Route) linkName() (string, error) {
var name = "UNKNOWN"
var link, err = r.Link()
if err != nil {
- return name, errors.Trace(err)
+ return name, errors.Wrap(err, "")
}
return link.Name(), nil
}
@@ -83,7 +84,7 @@ type Routes []*Route
func newRoutes(raw []netlink.Route, d *Driver) Routes {
var routes = make(Routes, len(raw))
for i, r := range raw {
- routes[i] = newRoute(&r, d) //nolint
+ routes[i] = newRoute(&r, d)
}
return routes
}
@@ -108,12 +109,12 @@ func (d *Driver) ListRoute(dest string) (Routes, error) {
var ipn, err = netx.ParseCIDROrIP(dest)
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
raw, err := d.RouteGet(ipn.IP)
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
return newRoutes(raw, d), nil
@@ -123,7 +124,7 @@ func (d *Driver) ListRoute(dest string) (Routes, error) {
func (d *Driver) ClearRoutes(linkName string) error {
var link, err = d.ShowLink(linkName)
if err != nil {
- return errors.Annotatef(err, linkName)
+ return errors.Wrap(err, linkName)
}
return link.ClearRoutes()
}
@@ -132,7 +133,7 @@ func (d *Driver) ClearRoutes(linkName string) error {
func (d *Driver) DeleteRoute(dest string) error {
var ipn, err = netx.ParseCIDROrIP(dest)
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
d.Lock()
@@ -153,7 +154,7 @@ func (d *Driver) AddRoute(dest, src, linkName string) error {
link, err := d.showLink(linkName)
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
return d.addRoute(dest, src, link)
@@ -162,7 +163,7 @@ func (d *Driver) AddRoute(dest, src, linkName string) error {
func (d *Driver) addRoute(dest, src string, link VirtLink) error {
ipn, err := netx.ParseCIDROrIP(dest)
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
var route = newDefaultRoute(d, ipn)
diff --git a/internal/vnet/device/route_test.go b/internal/network/utils/device/route_test.go
similarity index 100%
rename from internal/vnet/device/route_test.go
rename to internal/network/utils/device/route_test.go
diff --git a/internal/vnet/device/tuntap.go b/internal/network/utils/device/tuntap.go
similarity index 100%
rename from internal/vnet/device/tuntap.go
rename to internal/network/utils/device/tuntap.go
diff --git a/internal/network/utils/utils.go b/internal/network/utils/utils.go
new file mode 100644
index 0000000..232a83c
--- /dev/null
+++ b/internal/network/utils/utils.go
@@ -0,0 +1,27 @@
+package utils
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/pkg/errors"
+ pkgutils "github.com/projecteru2/yavirt/pkg/utils"
+)
+
+func GenEndpointID() (string, error) {
+ var uuid, err = pkgutils.UUIDStr()
+ if err != nil {
+ return "", errors.Wrap(err, "")
+ }
+ return strings.ReplaceAll(uuid, "-", ""), nil
+}
+
+func GenDevName(prefix string) (string, error) {
+ var endpID, err = GenEndpointID()
+ if err != nil {
+ return "", errors.Wrap(err, "")
+ }
+ var name = fmt.Sprintf("%s%s", prefix, endpID[:pkgutils.Min(12, len(endpID))])
+ return name, nil
+
+}
diff --git a/internal/server/grpc/grpc_app.go b/internal/rpc/grpc_app.go
similarity index 58%
rename from internal/server/grpc/grpc_app.go
rename to internal/rpc/grpc_app.go
index f18dcf8..739e8c0 100644
--- a/internal/server/grpc/grpc_app.go
+++ b/internal/rpc/grpc_app.go
@@ -9,17 +9,20 @@ import (
pb "github.com/projecteru2/libyavirt/grpc/gen"
"github.com/projecteru2/libyavirt/types"
-
- virtypes "github.com/projecteru2/yavirt/internal/virt/types"
- "github.com/projecteru2/yavirt/pkg/errors"
- "github.com/projecteru2/yavirt/pkg/log"
-
- "github.com/projecteru2/yavirt/internal/server"
+ "github.com/samber/lo"
+
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/core/log"
+ "github.com/projecteru2/yavirt/configs"
+ "github.com/projecteru2/yavirt/internal/service"
+ intertypes "github.com/projecteru2/yavirt/internal/types"
+ "github.com/projecteru2/yavirt/internal/utils"
+ vmiFact "github.com/yuyang0/vmimage/factory"
)
// GRPCYavirtd .
type GRPCYavirtd struct {
- service *server.Service
+ service service.Service
}
// Ping .
@@ -29,9 +32,14 @@ func (y *GRPCYavirtd) Ping(_ context.Context, _ *pb.Empty) (*pb.PingMessage, err
}
// GetInfo .
-func (y *GRPCYavirtd) GetInfo(_ context.Context, _ *pb.Empty) (*pb.InfoMessage, error) {
- log.Infof("[grpcserver] get host info")
- info := y.service.Info()
+func (y *GRPCYavirtd) GetInfo(ctx context.Context, _ *pb.Empty) (*pb.InfoMessage, error) {
+ if configs.Conf.Log.Verbose {
+ log.Debug(ctx, "[grpcserver] get host info")
+ }
+ info, err := y.service.Info()
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
return &pb.InfoMessage{
Id: info.ID,
Cpu: int64(info.CPU),
@@ -43,14 +51,14 @@ func (y *GRPCYavirtd) GetInfo(_ context.Context, _ *pb.Empty) (*pb.InfoMessage,
// GetGuest .
func (y *GRPCYavirtd) GetGuest(ctx context.Context, opts *pb.GetGuestOptions) (*pb.GetGuestMessage, error) {
- log.Infof("[grpcserver] get guest: %s", opts.Id)
+ log.Infof(ctx, "[grpcserver] get guest: %s", opts.Id)
guestReq := types.GuestReq{ID: opts.Id}
- guest, err := y.service.GetGuest(y.service.VirtContext(ctx), guestReq.VirtID())
+ guest, err := y.service.GetGuest(ctx, guestReq.VirtID())
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
return &pb.GetGuestMessage{
- Id: guest.ID,
+ Id: types.EruID(guest.ID),
Status: guest.Status,
TransitStatus: guest.TransitStatus,
CreateTime: guest.CreateTime,
@@ -62,26 +70,34 @@ func (y *GRPCYavirtd) GetGuest(ctx context.Context, opts *pb.GetGuestOptions) (*
ImageId: guest.ImageID,
ImageName: guest.ImageName,
Networks: guest.Networks,
+ Ips: guest.IPs,
+ Labels: guest.Labels,
+ Hostname: guest.Hostname,
+ Running: guest.Running,
}, nil
}
// GetGuestIDList gets all local vms' domain names regardless of their metadata validility.
func (y *GRPCYavirtd) GetGuestIDList(ctx context.Context, _ *pb.GetGuestIDListOptions) (*pb.GetGuestIDListMessage, error) {
- log.Infof("[grpcserver] get guest id list")
- ids, err := y.service.GetGuestIDList(y.service.VirtContext(ctx))
+ log.Info(ctx, "[grpcserver] get guest id list")
+ ids, err := y.service.GetGuestIDList(ctx)
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
- return &pb.GetGuestIDListMessage{Ids: ids}, nil
+ eruIDs := lo.Map(ids, func(id string, _ int) string {
+ return types.EruID(id)
+ })
+ return &pb.GetGuestIDListMessage{Ids: eruIDs}, nil
}
// Events
func (y *GRPCYavirtd) Events(_ *pb.EventsOptions, server pb.YavirtdRPC_EventsServer) error {
- log.Infof("[grpcserver] events method calling")
- defer log.Infof("[grpcserver] events method completed")
-
ctx := server.Context()
- watcher, err := y.service.WatchGuestEvents(y.service.VirtContext(ctx))
+
+ log.Info(ctx, "[grpcserver] events method calling")
+ defer log.Info(ctx, "[grpcserver] events method completed")
+
+ watcher, err := y.service.WatchGuestEvents(ctx)
if err != nil {
return err
}
@@ -91,25 +107,25 @@ func (y *GRPCYavirtd) Events(_ *pb.EventsOptions, server pb.YavirtdRPC_EventsSer
wg.Add(1)
go func() {
+ defer log.Info(ctx, "[grpcserver] events goroutine has done")
defer wg.Done()
- defer log.Infof("[grpcserver] events goroutine has done")
defer watcher.Stop()
for {
select {
case event := <-watcher.Events():
if err := server.Send(parseEvent(event)); err != nil {
- log.ErrorStack(err)
+ log.Error(ctx, err)
return
}
case <-watcher.Done():
// The watcher already has been stopped.
- log.Infof("[grpcserver] watcher has done")
+ log.Info(ctx, "[grpcserver] watcher has done")
return
case <-ctx.Done():
- log.Infof("[grpcserver] ctx done")
+ log.Info(ctx, "[grpcserver] ctx done")
return
}
}
@@ -118,23 +134,23 @@ func (y *GRPCYavirtd) Events(_ *pb.EventsOptions, server pb.YavirtdRPC_EventsSer
return nil
}
-func parseEvent(event virtypes.Event) *pb.EventMessage {
+func parseEvent(event intertypes.Event) *pb.EventMessage {
return &pb.EventMessage{
Id: types.EruID(event.ID),
Type: event.Type,
- Action: event.Action,
+ Action: string(event.Op),
TimeNano: event.Time.UnixNano(),
}
}
// GetGuestUUID .
func (y *GRPCYavirtd) GetGuestUUID(ctx context.Context, opts *pb.GetGuestOptions) (*pb.GetGuestUUIDMessage, error) {
- log.Infof("[grpcserver] get guest UUID: %s", opts.Id)
+ log.Infof(ctx, "[grpcserver] get guest UUID: %s", opts.Id)
guestReq := types.GuestReq{ID: opts.Id}
- uuid, err := y.service.GetGuestUUID(y.service.VirtContext(ctx), guestReq.VirtID())
+ uuid, err := y.service.GetGuestUUID(ctx, guestReq.VirtID())
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
return &pb.GetGuestUUIDMessage{Uuid: uuid}, nil
@@ -142,13 +158,13 @@ func (y *GRPCYavirtd) GetGuestUUID(ctx context.Context, opts *pb.GetGuestOptions
// CreateGuest .
func (y *GRPCYavirtd) CreateGuest(ctx context.Context, opts *pb.CreateGuestOptions) (*pb.CreateGuestMessage, error) {
- log.Infof("[grpcserver] create guest: %q", opts)
- guest, err := y.service.CreateGuest(y.service.VirtContext(ctx), virtypes.ConvertGRPCCreateOptions(opts))
+ log.Infof(ctx, "[grpcserver] create guest: %q", opts)
+ guest, err := y.service.CreateGuest(ctx, intertypes.ConvertGRPCCreateOptions(opts))
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
return &pb.CreateGuestMessage{
- Id: guest.ID,
+ Id: types.EruID(guest.ID),
Status: guest.Status,
TransitStatus: guest.TransitStatus,
CreateTime: guest.CreateTime,
@@ -166,52 +182,29 @@ func (y *GRPCYavirtd) CreateGuest(ctx context.Context, opts *pb.CreateGuestOptio
// CaptureGuest .
func (y *GRPCYavirtd) CaptureGuest(ctx context.Context, opts *pb.CaptureGuestOptions) (*pb.UserImageMessage, error) {
- log.Infof("[grpcserver] capture guest: %q", opts)
-
- req := types.CaptureGuestReq{
- Name: opts.Name,
- User: opts.User,
- Overridden: opts.Overridden,
- }
- req.ID = opts.Id
-
- virtCtx := y.service.VirtContext(ctx)
+ log.Infof(ctx, "[grpcserver] capture guest: %q", opts)
- uimg, err := y.service.CaptureGuest(virtCtx, req)
+ imgName := vmiFact.NewImageName(opts.User, opts.Name)
+ uimg, err := y.service.CaptureGuest(ctx, utils.VirtID(opts.Id), imgName, opts.Overridden)
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
return &pb.UserImageMessage{
- Id: uimg.GetID(),
- Name: uimg.Name,
- Distro: uimg.Distro,
- LatestVersion: uimg.Version,
- Size: uimg.Size,
+ Name: uimg.Fullname(),
+ Distro: uimg.OS.Distrib,
+ Size: uimg.VirtualSize,
}, nil
}
// ResizeGuest .
func (y *GRPCYavirtd) ResizeGuest(ctx context.Context, opts *pb.ResizeGuestOptions) (*pb.ControlGuestMessage, error) {
- log.Infof("[grpcserver] resize guest: %q", opts)
+ log.Infof(ctx, "[grpcserver] resize guest: %q", opts)
msg := &pb.ControlGuestMessage{Msg: "ok"}
- virtCtx := y.service.VirtContext(ctx)
-
- req := types.ResizeGuestReq{
- CPU: int(opts.Cpu),
- Mem: opts.Memory,
- Resources: opts.Resources,
- }
- req.Volumes = make([]types.Volume, len(opts.Volumes))
- for i, vol := range opts.Volumes {
- req.Volumes[i].Mount = vol.Mount
- req.Volumes[i].Capacity = vol.Capacity
- req.Volumes[i].IO = vol.Io
- }
- req.ID = opts.Id
- err := y.service.ResizeGuest(virtCtx, req)
+ req := intertypes.ConvertGRPCResizeOptions(opts)
+ err := y.service.ResizeGuest(ctx, utils.VirtID(opts.Id), req)
if err != nil {
msg.Msg = fmt.Sprintf("%s", err)
}
@@ -221,50 +214,45 @@ func (y *GRPCYavirtd) ResizeGuest(ctx context.Context, opts *pb.ResizeGuestOptio
// ControlGuest .
func (y *GRPCYavirtd) ControlGuest(ctx context.Context, opts *pb.ControlGuestOptions) (_ *pb.ControlGuestMessage, err error) {
- log.Infof("[grpcserver] control guest: %q", opts)
- req := types.GuestReq{ID: opts.Id}
- virtCtx := y.service.VirtContext(ctx)
- err = y.service.ControlGuest(virtCtx, req.VirtID(), opts.Operation, opts.Force)
+ log.Infof(ctx, "[grpcserver] control guest: %q", opts)
+ err = y.service.ControlGuest(ctx, utils.VirtID(opts.Id), opts.Operation, opts.Force)
msg := "ok"
if err != nil {
msg = fmt.Sprintf("%s", err)
}
- return &pb.ControlGuestMessage{Msg: msg}, errors.Trace(err)
+ return &pb.ControlGuestMessage{Msg: msg}, errors.Wrap(err, "")
}
// AttachGuest .
func (y *GRPCYavirtd) AttachGuest(server pb.YavirtdRPC_AttachGuestServer) (err error) {
- defer log.Infof("[grpcserver] attach guest complete")
- log.Infof("[grpcserver] attach guest start")
+ ctx := server.Context()
+ defer log.Info(ctx, "[grpcserver] attach guest complete")
opts, err := server.Recv()
if err != nil {
return
}
+ log.Infof(ctx, "[grpcserver] attach guest start: %v", opts)
- virtCtx := y.service.VirtContext(server.Context())
- req := types.GuestReq{ID: opts.Id}
serverStream := &ExecuteGuestServerStream{
ID: opts.Id,
server: server,
}
- flags := virtypes.OpenConsoleFlags{Force: opts.Force, Safe: opts.Safe, Commands: opts.Commands}
- return y.service.AttachGuest(virtCtx, req.VirtID(), serverStream, flags)
+ flags := intertypes.NewOpenConsoleFlags(opts.Force, opts.Safe, opts.Commands)
+ return y.service.AttachGuest(ctx, utils.VirtID(opts.Id), serverStream, flags)
}
// ResizeConsoleWindow .
func (y *GRPCYavirtd) ResizeConsoleWindow(ctx context.Context, opts *pb.ResizeWindowOptions) (*pb.Empty, error) {
req := types.GuestReq{ID: opts.Id}
- virtCtx := y.service.VirtContext(ctx)
- return nil, y.service.ResizeConsoleWindow(virtCtx, req.VirtID(), uint(opts.Height), uint(opts.Width))
+ return nil, y.service.ResizeConsoleWindow(ctx, req.VirtID(), uint(opts.Height), uint(opts.Width))
}
// ExecuteGuest .
func (y *GRPCYavirtd) ExecuteGuest(ctx context.Context, opts *pb.ExecuteGuestOptions) (msg *pb.ExecuteGuestMessage, err error) {
- log.Infof("[grpcserver] execute guest start")
+ log.Infof(ctx, "[grpcserver] execute guest start")
req := types.GuestReq{ID: opts.Id}
- virtCtx := y.service.VirtContext(ctx)
- m, err := y.service.ExecuteGuest(virtCtx, req.VirtID(), opts.Commands)
+ m, err := y.service.ExecuteGuest(ctx, req.VirtID(), opts.Commands)
if err != nil {
return
}
@@ -275,9 +263,9 @@ func (y *GRPCYavirtd) ExecuteGuest(ctx context.Context, opts *pb.ExecuteGuestOpt
}, nil
}
-func (y *GRPCYavirtd) ExecExitCode(_ context.Context, opts *pb.ExecExitCodeOptions) (msg *pb.ExecExitCodeMessage, err error) {
- log.Infof("[grpcserver] get exit code start")
- defer log.Infof("[grpcserver] get exit code done")
+func (y *GRPCYavirtd) ExecExitCode(ctx context.Context, opts *pb.ExecExitCodeOptions) (msg *pb.ExecExitCodeMessage, err error) {
+ log.Infof(ctx, "[grpcserver] get exit code start %q", opts)
+ defer log.Infof(ctx, "[grpcserver] get exit code done")
req := types.GuestReq{ID: opts.Id}
@@ -290,7 +278,7 @@ func (y *GRPCYavirtd) ExecExitCode(_ context.Context, opts *pb.ExecExitCodeOptio
// ConnectNetwork .
func (y *GRPCYavirtd) ConnectNetwork(ctx context.Context, opts *pb.ConnectNetworkOptions) (*pb.ConnectNetworkMessage, error) {
- log.Infof("[grpcserver] connect network start")
+ log.Infof(ctx, "[grpcserver] connect network start %q", opts)
req := types.ConnectNetworkReq{
Network: opts.Network,
@@ -298,10 +286,9 @@ func (y *GRPCYavirtd) ConnectNetwork(ctx context.Context, opts *pb.ConnectNetwor
}
req.ID = opts.Id
- virtCtx := y.service.VirtContext(ctx)
- cidr, err := y.service.ConnectNetwork(virtCtx, req.VirtID(), req.Network, req.IPv4)
+ cidr, err := y.service.ConnectNetwork(ctx, req.VirtID(), req.Network, req.IPv4)
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
return &pb.ConnectNetworkMessage{Cidr: cidr}, nil
@@ -309,15 +296,14 @@ func (y *GRPCYavirtd) ConnectNetwork(ctx context.Context, opts *pb.ConnectNetwor
// DisconnectNetwork .
func (y *GRPCYavirtd) DisconnectNetwork(ctx context.Context, opts *pb.DisconnectNetworkOptions) (*pb.DisconnectNetworkMessage, error) {
- log.Infof("[grpcserver] disconnect network start")
+ log.Infof(ctx, "[grpcserver] disconnect network start")
var req types.DisconnectNetworkReq
req.ID = opts.Id
req.Network = opts.Network
- virtCtx := y.service.VirtContext(ctx)
- if err := y.service.DisconnectNetwork(virtCtx, req.VirtID(), req.Network); err != nil {
- return nil, errors.Trace(err)
+ if err := y.service.DisconnectNetwork(ctx, req.VirtID(), req.Network); err != nil {
+ return nil, errors.Wrap(err, "")
}
return &pb.DisconnectNetworkMessage{Msg: "ok"}, nil
@@ -325,20 +311,19 @@ func (y *GRPCYavirtd) DisconnectNetwork(ctx context.Context, opts *pb.Disconnect
// NetworkList .
func (y *GRPCYavirtd) NetworkList(ctx context.Context, opts *pb.NetworkListOptions) (*pb.NetworkListMessage, error) {
- log.Infof("[grpcserver] list network start")
- defer log.Infof("[grpcserver] list network completed %v", opts)
+ log.Infof(ctx, "[grpcserver] list network start")
+ defer log.Infof(ctx, "[grpcserver] list network completed %v", opts)
- virtCtx := y.service.VirtContext(ctx)
- networks, err := y.service.NetworkList(virtCtx, opts.Drivers)
+ networks, err := y.service.NetworkList(ctx, opts.Drivers)
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
msg := &pb.NetworkListMessage{Networks: make(map[string][]byte)}
for _, network := range networks {
content, err := json.Marshal(network.Subnets)
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
msg.Networks[network.Name] = content
}
@@ -348,10 +333,10 @@ func (y *GRPCYavirtd) NetworkList(ctx context.Context, opts *pb.NetworkListOptio
// Cat .
func (y *GRPCYavirtd) Cat(opts *pb.CatOptions, srv pb.YavirtdRPC_CatServer) error {
- log.Infof("[grpcserver] cat %v", opts)
- defer log.Infof("[grpcserver] cat %v completed", opts)
+ ctx := srv.Context()
+ log.Infof(ctx, "[grpcserver] cat %v", opts)
+ defer log.Infof(ctx, "[grpcserver] cat %v completed", opts)
- ctx := y.service.VirtContext(srv.Context())
req := types.GuestReq{ID: opts.Id}
wc := &CatWriteCloser{srv: srv}
@@ -362,8 +347,9 @@ func (y *GRPCYavirtd) Cat(opts *pb.CatOptions, srv pb.YavirtdRPC_CatServer) erro
// CopyToGuest .
func (y *GRPCYavirtd) CopyToGuest(server pb.YavirtdRPC_CopyToGuestServer) (err error) {
- defer log.Infof("[grpcserver] copy file to guest complete")
- log.Infof("[grpcserver] copy file to guest start")
+ ctx := server.Context()
+ defer log.Infof(ctx, "[grpcserver] copy file to guest complete")
+ log.Infof(ctx, "[grpcserver] copy file to guest start")
var opts *pb.CopyOptions
byteChan := make(chan []byte, 4*types.BufferSize)
@@ -396,7 +382,6 @@ func (y *GRPCYavirtd) CopyToGuest(server pb.YavirtdRPC_CopyToGuestServer) (err e
}
}()
- ctx := y.service.VirtContext(server.Context())
if err := y.service.CopyToGuest(ctx, req.VirtID(), dest, byteChan, override); err != nil {
<-end
return server.SendAndClose(&pb.CopyMessage{Msg: "copy failed: " + err.Error(), Failed: true})
@@ -410,30 +395,29 @@ func (y *GRPCYavirtd) CopyToGuest(server pb.YavirtdRPC_CopyToGuestServer) (err e
// Log .
func (y *GRPCYavirtd) Log(opts *pb.LogOptions, srv pb.YavirtdRPC_LogServer) error {
- log.Infof("[grpcserver] log start")
- defer log.Infof("[grpcserver] log completed")
+ ctx := srv.Context()
+ log.Infof(ctx, "[grpcserver] log start")
+ defer log.Infof(ctx, "[grpcserver] log completed")
- virtCtx := y.service.VirtContext(srv.Context())
req := types.GuestReq{ID: opts.Id}
wc := &LogWriteCloser{srv: srv}
defer wc.Close()
- return y.service.Log(virtCtx, req.VirtID(), "/var/log/syslog", int(opts.N), wc)
+ return y.service.Log(ctx, req.VirtID(), "/var/log/syslog", int(opts.N), wc)
}
// WaitGuest .
func (y *GRPCYavirtd) WaitGuest(ctx context.Context, opts *pb.WaitGuestOptions) (*pb.WaitGuestMessage, error) {
- log.Infof("[grpcserver] wait guest")
- defer log.Infof("[grpcserver] wait complete")
+ log.Infof(ctx, "[grpcserver] wait guest")
+ defer log.Infof(ctx, "[grpcserver] wait complete")
req := types.GuestReq{ID: opts.Id}
- virtCtx := y.service.VirtContext(ctx)
- msg, code, err := y.service.Wait(virtCtx, req.VirtID(), true)
+ msg, code, err := y.service.Wait(ctx, req.VirtID(), true)
if err != nil {
return &pb.WaitGuestMessage{
- Msg: errors.Trace(err).Error(),
+ Msg: errors.Wrap(err, "").Error(),
Code: -1,
- }, errors.Trace(err)
+ }, errors.Wrap(err, "")
}
return &pb.WaitGuestMessage{Msg: msg, Code: int64(code)}, nil
@@ -441,76 +425,83 @@ func (y *GRPCYavirtd) WaitGuest(ctx context.Context, opts *pb.WaitGuestOptions)
// PushImage .
func (y *GRPCYavirtd) PushImage(ctx context.Context, opts *pb.PushImageOptions) (*pb.PushImageMessage, error) {
- log.Infof("[grpcserver] PushImage %v", opts)
- defer log.Infof("[grpcserver] Push %v completed", opts)
+ log.Infof(ctx, "[grpcserver] PushImage %v", opts)
+ defer log.Infof(ctx, "[grpcserver] Push %v completed", opts)
- virtCtx := y.service.VirtContext(ctx)
msg := &pb.PushImageMessage{}
- if err := y.service.PushImage(virtCtx, opts.ImgName, opts.User); err != nil {
+ // TODO add force to opts
+ force := false
+ imgName := vmiFact.NewImageName(opts.User, opts.ImgName)
+ rc, err := y.service.PushImage(ctx, imgName, force)
+ if err != nil {
msg.Err = err.Error()
return msg, err
}
+ defer utils.EnsureReaderClosed(rc)
return msg, nil
}
// RemoveImage .
func (y *GRPCYavirtd) RemoveImage(ctx context.Context, opts *pb.RemoveImageOptions) (*pb.RemoveImageMessage, error) {
- log.Infof("[grpcserver] RemoveImage %v", opts)
- defer log.Infof("[grpcserver] Remove %v completed", opts)
+ log.Infof(ctx, "[grpcserver] RemoveImage %v", opts)
+ defer log.Infof(ctx, "[grpcserver] Remove %v completed", opts)
- virtCtx := y.service.VirtContext(ctx)
msg := &pb.RemoveImageMessage{}
var err error
- msg.Removed, err = y.service.RemoveImage(virtCtx, opts.Image, opts.User, opts.Force, opts.Prune)
+ imgName := vmiFact.NewImageName(opts.User, opts.Image)
+ msg.Removed, err = y.service.RemoveImage(ctx, imgName, opts.Force, opts.Prune)
return msg, err
}
// ListImage .
func (y *GRPCYavirtd) ListImage(ctx context.Context, opts *pb.ListImageOptions) (*pb.ListImageMessage, error) {
- log.Infof("[grpcserver] ListImage %v", opts)
- defer log.Infof("[grpcserver] ListImage %v completed", opts)
-
- virtCtx := y.service.VirtContext(ctx)
+ log.Infof(ctx, "[grpcserver] ListImage %v", opts)
+ defer log.Infof(ctx, "[grpcserver] ListImage %v completed", opts)
- imgs, err := y.service.ListImage(virtCtx, opts.Filter)
+ imgs, err := y.service.ListImage(ctx, opts.Filter)
if err != nil {
return nil, err
}
-
+ // TODO: remove User in pb
msg := &pb.ListImageMessage{Images: []*pb.ImageItem{}}
for _, img := range imgs {
- msg.Images = append(msg.Images, types.ToGRPCImageItem(img))
+ msg.Images = append(msg.Images, &pb.ImageItem{
+ Name: img.Fullname(),
+ Distro: img.OS.Distrib,
+ })
}
return msg, nil
}
func (y *GRPCYavirtd) PullImage(ctx context.Context, opts *pb.PullImageOptions) (*pb.PullImageMessage, error) {
- log.Infof("[grpcserver] PullImage %v", opts)
- defer log.Infof("[grpcserver] PullImage %v completed", opts)
-
- virtCtx := y.service.VirtContext(ctx)
+ log.Infof(ctx, "[grpcserver] PullImage %v", opts)
+ defer log.Infof(ctx, "[grpcserver] PullImage %v completed", opts)
- msg, err := y.service.PullImage(virtCtx, opts.Name, opts.All)
+ img, rc, err := y.service.PullImage(ctx, opts.Name)
if err != nil {
return nil, err
}
+ defer utils.EnsureReaderClosed(rc)
- return &pb.PullImageMessage{Result: msg}, nil
+ // TODO change pb to return image
+ msg, err := json.Marshal(img)
+ if err != nil {
+ return nil, err
+ }
+ return &pb.PullImageMessage{Result: string(msg)}, nil
}
// DigestImage .
func (y *GRPCYavirtd) DigestImage(ctx context.Context, opts *pb.DigestImageOptions) (*pb.DigestImageMessage, error) {
- log.Infof("[grpcserver] DigestImage %v", opts)
- defer log.Infof("[grpcserver] DigestImage %v completed", opts)
+ log.Infof(ctx, "[grpcserver] DigestImage %v", opts)
+ defer log.Infof(ctx, "[grpcserver] DigestImage %v completed", opts)
- virtCtx := y.service.VirtContext(ctx)
-
- digests, err := y.service.DigestImage(virtCtx, opts.ImageName, opts.Local)
+ digests, err := y.service.DigestImage(ctx, opts.ImageName, opts.Local)
if err != nil {
return nil, err
}
@@ -520,18 +511,16 @@ func (y *GRPCYavirtd) DigestImage(ctx context.Context, opts *pb.DigestImageOptio
// ListSnapshot .
func (y *GRPCYavirtd) ListSnapshot(ctx context.Context, opts *pb.ListSnapshotOptions) (*pb.ListSnapshotMessage, error) {
- log.Infof("[grpcserver] list snapshot: %q", opts)
-
- virtCtx := y.service.VirtContext(ctx)
+ log.Infof(ctx, "[grpcserver] list snapshot: %q", opts)
req := types.ListSnapshotReq{
ID: opts.Id,
VolID: opts.VolId,
}
- snaps, err := y.service.ListSnapshot(virtCtx, req)
+ snaps, err := y.service.ListSnapshot(ctx, req)
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
snapshots := []*pb.ListSnapshotMessageItem{}
@@ -551,17 +540,16 @@ func (y *GRPCYavirtd) ListSnapshot(ctx context.Context, opts *pb.ListSnapshotOpt
// CreateSnapshot .
func (y *GRPCYavirtd) CreateSnapshot(ctx context.Context, opts *pb.CreateSnapshotOptions) (*pb.CreateSnapshotMessage, error) {
- log.Infof("[grpcserver] create snapshot: %q", opts)
+ log.Infof(ctx, "[grpcserver] create snapshot: %q", opts)
msg := &pb.CreateSnapshotMessage{Msg: "ok"}
- virtCtx := y.service.VirtContext(ctx)
req := types.CreateSnapshotReq{
ID: opts.Id,
VolID: opts.VolId,
}
- err := y.service.CreateSnapshot(virtCtx, req)
+ err := y.service.CreateSnapshot(ctx, req)
if err != nil {
msg.Msg = fmt.Sprintf("%s", err)
}
@@ -571,10 +559,9 @@ func (y *GRPCYavirtd) CreateSnapshot(ctx context.Context, opts *pb.CreateSnapsho
// CommitSnapshot .
func (y *GRPCYavirtd) CommitSnapshot(ctx context.Context, opts *pb.CommitSnapshotOptions) (*pb.CommitSnapshotMessage, error) {
- log.Infof("[grpcserver] commit snapshot: %q", opts)
+ log.Infof(ctx, "[grpcserver] commit snapshot: %q", opts)
msg := &pb.CommitSnapshotMessage{Msg: "ok"}
- virtCtx := y.service.VirtContext(ctx)
req := types.CommitSnapshotReq{
ID: opts.Id,
@@ -582,7 +569,7 @@ func (y *GRPCYavirtd) CommitSnapshot(ctx context.Context, opts *pb.CommitSnapsho
SnapID: opts.SnapId,
}
- err := y.service.CommitSnapshot(virtCtx, req)
+ err := y.service.CommitSnapshot(ctx, req)
if err != nil {
msg.Msg = fmt.Sprintf("%s", err)
}
@@ -592,10 +579,9 @@ func (y *GRPCYavirtd) CommitSnapshot(ctx context.Context, opts *pb.CommitSnapsho
// RestoreSnapshot .
func (y *GRPCYavirtd) RestoreSnapshot(ctx context.Context, opts *pb.RestoreSnapshotOptions) (*pb.RestoreSnapshotMessage, error) {
- log.Infof("[grpcserver] restore snapshot: %q", opts)
+ log.Infof(ctx, "[grpcserver] restore snapshot: %q", opts)
msg := &pb.RestoreSnapshotMessage{Msg: "ok"}
- virtCtx := y.service.VirtContext(ctx)
req := types.RestoreSnapshotReq{
ID: opts.Id,
@@ -603,10 +589,29 @@ func (y *GRPCYavirtd) RestoreSnapshot(ctx context.Context, opts *pb.RestoreSnaps
SnapID: opts.SnapId,
}
- err := y.service.RestoreSnapshot(virtCtx, req)
+ err := y.service.RestoreSnapshot(ctx, req)
if err != nil {
msg.Msg = fmt.Sprintf("%s", err)
}
return msg, err
}
+
+// ExecuteGuest .
+func (y *GRPCYavirtd) RawEngine(ctx context.Context, opts *pb.RawEngineOptions) (msg *pb.RawEngineMessage, err error) {
+ logger := log.WithFunc("RawEngine").WithField("id", opts.Id).WithField("op", opts.Op)
+ logger.Infof(ctx, "[grpcserver] raw engine operation, params: %s", string(opts.Params))
+ req := types.RawEngineReq{
+ ID: opts.Id,
+ Op: opts.Op,
+ Params: opts.Params,
+ }
+ m, err := y.service.RawEngine(ctx, utils.VirtID(opts.Id), req)
+ if err != nil {
+ return
+ }
+ return &pb.RawEngineMessage{
+ Id: opts.Id,
+ Data: m.Data,
+ }, nil
+}
diff --git a/internal/rpc/grpc_server.go b/internal/rpc/grpc_server.go
new file mode 100644
index 0000000..d026f42
--- /dev/null
+++ b/internal/rpc/grpc_server.go
@@ -0,0 +1,117 @@
+package grpcserver
+
+import (
+ "context"
+ "crypto/tls"
+ "net"
+ "path/filepath"
+ "time"
+
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/credentials"
+ "google.golang.org/grpc/reflection"
+
+ "github.com/projecteru2/core/auth"
+ "github.com/projecteru2/core/log"
+ pb "github.com/projecteru2/libyavirt/grpc/gen"
+ "github.com/projecteru2/yavirt/configs"
+ "github.com/projecteru2/yavirt/internal/service"
+ "github.com/projecteru2/yavirt/pkg/utils"
+)
+
+// GRPCServer .
+type GRPCServer struct {
+ server *grpc.Server
+ app pb.YavirtdRPCServer
+ quit chan struct{}
+}
+
+func loadTLSCredentials(dir string) (credentials.TransportCredentials, error) {
+ // Load server's certificate and private key
+ certFile := filepath.Join(dir, "server-cert.pem")
+ keyFile := filepath.Join(dir, "server-key.pem")
+ if (!utils.FileExists(certFile)) || (!utils.FileExists(keyFile)) {
+ return nil, nil //nolint
+ }
+ serverCert, err := tls.LoadX509KeyPair(certFile, keyFile)
+ if err != nil {
+ return nil, err
+ }
+
+ // Create the credentials and return it
+ config := &tls.Config{
+ MinVersion: tls.VersionTLS12,
+ Certificates: []tls.Certificate{serverCert},
+ ClientAuth: tls.NoClientCert,
+ }
+
+ return credentials.NewTLS(config), nil
+}
+
+func New(cfg *configs.Config, svc service.Service, quit chan struct{}) (*GRPCServer, error) {
+ logger := log.WithFunc("rpc.New")
+ opts := []grpc.ServerOption{}
+ certDir := filepath.Join(cfg.CertPath, "yavirt")
+ tlsCredentials, err := loadTLSCredentials(certDir)
+ if err != nil {
+ return nil, err
+ }
+ if tlsCredentials != nil {
+ logger.Infof(context.TODO(), "grpc server tls enable.")
+ opts = append(opts, grpc.Creds(tlsCredentials))
+ }
+ if cfg.Auth.Username != "" {
+ logger.Infof(context.TODO(), "grpc server auth enable.")
+ auth := auth.NewAuth(cfg.Auth)
+ opts = append(opts, grpc.StreamInterceptor(auth.StreamInterceptor))
+ opts = append(opts, grpc.UnaryInterceptor(auth.UnaryInterceptor))
+ logger.Infof(context.TODO(), "username %s password %s", cfg.Auth.Username, cfg.Auth.Password)
+ }
+ srv := &GRPCServer{
+ server: grpc.NewServer(opts...),
+ app: &GRPCYavirtd{service: svc},
+ quit: quit,
+ }
+ reflection.Register(srv.server)
+
+ return srv, nil
+}
+
+// Serve .
+func (s *GRPCServer) Serve() error {
+ defer func() {
+ log.WithFunc("rpc.Serve").Warnf(context.TODO(), "[grpcserver] main loop %p exit", s)
+ }()
+ lis, err := net.Listen("tcp", configs.Conf.BindGRPCAddr)
+ if err != nil {
+ return err
+ }
+ pb.RegisterYavirtdRPCServer(s.server, s.app)
+
+ return s.server.Serve(lis)
+}
+
+// Close .
+func (s *GRPCServer) Stop(force bool) {
+ logger := log.WithFunc("rpc.Close")
+ if force {
+ logger.Warnf(context.TODO(), "[grpcserver] terminate grpc server forcefully")
+ s.server.Stop()
+ return
+ }
+
+ gracefulDone := make(chan struct{})
+ go func() {
+ defer close(gracefulDone)
+ s.server.GracefulStop()
+ }()
+
+ gracefulTimer := time.NewTimer(configs.Conf.GracefulTimeout)
+ select {
+ case <-gracefulDone:
+ logger.Infof(context.TODO(), "[grpcserver] terminate grpc server gracefully")
+ case <-gracefulTimer.C:
+ logger.Warnf(context.TODO(), "[grpcserver] terminate grpc server forcefully")
+ s.server.Stop()
+ }
+}
diff --git a/internal/server/grpc/types.go b/internal/rpc/types.go
similarity index 100%
rename from internal/server/grpc/types.go
rename to internal/rpc/types.go
diff --git a/internal/server/calico.go b/internal/server/calico.go
deleted file mode 100644
index 59c89b9..0000000
--- a/internal/server/calico.go
+++ /dev/null
@@ -1,58 +0,0 @@
-package server
-
-import (
- "os"
-
- "github.com/projecteru2/yavirt/configs"
- "github.com/projecteru2/yavirt/internal/vnet"
- "github.com/projecteru2/yavirt/internal/vnet/calico"
- "github.com/projecteru2/yavirt/internal/vnet/device"
- calihandler "github.com/projecteru2/yavirt/internal/vnet/handler/calico"
- "github.com/projecteru2/yavirt/pkg/errors"
- "github.com/projecteru2/yavirt/pkg/netx"
-)
-
-func (svc *Service) setupCalico() error {
- if !svc.couldSetupCalico() {
- if svc.Host.NetworkMode == vnet.NetworkCalico {
- return errors.Annotatef(errors.ErrInvalidValue, "invalid Calico config")
- }
- return nil
- }
-
- if err := svc.setupCalicoHandler(); err != nil {
- return errors.Trace(err)
- }
-
- if err := svc.caliHandler.InitGateway(configs.Conf.CalicoGatewayName); err != nil {
- return errors.Trace(err)
- }
-
- return nil
-}
-
-func (svc *Service) setupCalicoHandler() error {
- cali, err := calico.NewDriver(configs.Conf.CalicoConfigFile, configs.Conf.CalicoPoolNames)
- if err != nil {
- return errors.Trace(err)
- }
-
- dev, err := device.New()
- if err != nil {
- return errors.Trace(err)
- }
-
- outboundIP, err := netx.GetOutboundIP(configs.Conf.Core.Addrs[0])
- if err != nil {
- return errors.Trace(err)
- }
-
- svc.caliHandler = calihandler.New(dev, cali, configs.Conf.CalicoPoolNames, outboundIP)
-
- return nil
-}
-
-func (svc *Service) couldSetupCalico() bool {
- var env = configs.Conf.CalicoETCDEnv
- return len(configs.Conf.CalicoConfigFile) > 0 || len(os.Getenv(env)) > 0
-}
diff --git a/internal/server/conv.go b/internal/server/conv.go
deleted file mode 100644
index 9efdfc4..0000000
--- a/internal/server/conv.go
+++ /dev/null
@@ -1,62 +0,0 @@
-package server
-
-import (
- "strings"
-
- pb "github.com/projecteru2/core/rpc/gen"
-
- "github.com/projecteru2/libyavirt/types"
- "github.com/projecteru2/yavirt/internal/models"
-)
-
-func convGuestIDsResp(localIDs []string) []string {
- eruIDs := make([]string, len(localIDs))
- for i, id := range localIDs {
- eruIDs[i] = types.EruID(id)
- }
- return eruIDs
-}
-
-func convGuestResp(g *models.Guest) (resp *types.Guest) {
- resp = &types.Guest{}
- resp.ID = types.EruID(g.ID)
- resp.Status = g.Status
- resp.CreateTime = g.CreatedTime
- resp.UpdateTime = g.UpdatedTime
- resp.ImageName = g.ImageName
- resp.ImageUser = g.ImageUser
- resp.CPU = g.CPU
- resp.Mem = g.Memory
-
- if len(g.IPs) > 0 {
- var ips = make([]string, len(g.IPs))
- for i, ip := range g.IPs {
- ips[i] = ip.IPAddr()
- }
- resp.Networks = map[string]string{"IP": strings.Join(ips, ", ")}
- }
-
- return
-}
-
-// ConvSetWorkloadsStatusOptions .
-func ConvSetWorkloadsStatusOptions(gss []types.EruGuestStatus) *pb.SetWorkloadsStatusOptions {
- css := make([]*pb.WorkloadStatus, len(gss))
- for i, gs := range gss {
- css[i] = convWorkloadStatus(gs)
- }
-
- return &pb.SetWorkloadsStatusOptions{
- Status: css,
- }
-}
-
-func convWorkloadStatus(gs types.EruGuestStatus) *pb.WorkloadStatus {
- return &pb.WorkloadStatus{
- Id: gs.EruGuestID,
- Running: gs.Running,
- Healthy: gs.Healthy,
- Ttl: int64(gs.TTL.Seconds()),
- Networks: map[string]string{"IP": gs.GetIPAddrs()},
- }
-}
diff --git a/internal/server/grpc/grpc_server.go b/internal/server/grpc/grpc_server.go
deleted file mode 100644
index f42bfbc..0000000
--- a/internal/server/grpc/grpc_server.go
+++ /dev/null
@@ -1,77 +0,0 @@
-package grpcserver
-
-import (
- "time"
-
- "google.golang.org/grpc"
-
- pb "github.com/projecteru2/libyavirt/grpc/gen"
- "github.com/projecteru2/yavirt/configs"
- "github.com/projecteru2/yavirt/internal/server"
- "github.com/projecteru2/yavirt/pkg/log"
-)
-
-// GRPCServer .
-type GRPCServer struct {
- *server.Server
-
- server *grpc.Server
- app pb.YavirtdRPCServer
-}
-
-// Listen .
-func Listen(svc *server.Service) (srv *GRPCServer, err error) {
- srv = &GRPCServer{}
- if srv.Server, err = server.Listen(configs.Conf.BindGRPCAddr, svc); err != nil {
- return
- }
-
- srv.server = grpc.NewServer()
- srv.app = &GRPCYavirtd{service: svc}
-
- return
-}
-
-// Reload .
-func (s *GRPCServer) Reload() error {
- return nil
-}
-
-// Serve .
-func (s *GRPCServer) Serve() error {
- defer func() {
- log.Warnf("[grpcserver] main loop %p exit", s)
- s.Close()
- }()
-
- pb.RegisterYavirtdRPCServer(s.server, s.app)
-
- return s.server.Serve(s.Listener)
-}
-
-// Close .
-func (s *GRPCServer) Close() {
- s.Exit.Do(func() {
- close(s.Exit.Ch)
-
- gracefulDone := make(chan struct{})
- go func() {
- defer close(gracefulDone)
- s.server.GracefulStop()
- }()
-
- gracefulTimer := time.NewTimer(configs.Conf.GracefulTimeout.Duration())
- select {
- case <-gracefulDone:
- log.Infof("[grpcserver] terminate grpc server gracefully")
- case <-gracefulTimer.C:
- log.Warnf("[grpcserver] terminate grpc server forcefully")
- s.server.Stop()
- }
- })
-}
-
-// ExitCh .
-func (s *GRPCServer) ExitCh() chan struct{} {
- return s.Exit.Ch
-}
diff --git a/internal/server/http/apiserver.go b/internal/server/http/apiserver.go
deleted file mode 100644
index db12499..0000000
--- a/internal/server/http/apiserver.go
+++ /dev/null
@@ -1,120 +0,0 @@
-package httpserver
-
-import (
- "context"
- "net/http"
-
- "github.com/gin-gonic/gin"
-
- "github.com/projecteru2/libyavirt/types"
- "github.com/projecteru2/yavirt/internal/models"
- "github.com/projecteru2/yavirt/internal/server"
- "github.com/projecteru2/yavirt/internal/virt"
- "github.com/projecteru2/yavirt/pkg/errors"
-)
-
-func newAPIHandler(svc *server.Service) http.Handler {
- gin.SetMode(gin.ReleaseMode)
-
- var api = &apiServer{service: svc}
- var router = gin.Default()
-
- var v1 = router.Group("/v1")
- {
- v1.GET("/ping", api.Ping)
- v1.GET("/info", api.Info)
- v1.GET("/guests/:id", api.GetGuest)
- v1.GET("/guests/:id/uuid", api.GetGuestUUID)
- v1.POST("/guests", api.CreateGuest)
- v1.POST("/guests/stop", api.StopGuest)
- v1.POST("/guests/start", api.StartGuest)
- v1.POST("/guests/destroy", api.DestroyGuest)
- v1.POST("/guests/execute", api.ExecuteGuest)
- v1.POST("/guests/resize", api.ResizeGuest)
- v1.POST("/guests/capture", api.CaptureGuest)
- v1.POST("/guests/connect", api.ConnectNetwork)
- v1.POST("/guests/resize_window", api.ResizeConsoleWindow)
- // v1.POST("/guests/snapshot/list", api.ListSnapshot)
- v1.POST("/guests/snapshot/create", api.CreateSnapshot)
- v1.POST("/guests/snapshot/commit", api.CommitSnapshot)
- v1.POST("/guests/snapshot/restore", api.RestoreSnapshot)
- }
-
- return router
-}
-
-type apiServer struct {
- service *server.Service
-}
-
-func (s *apiServer) host() *models.Host { //nolint
- return s.service.Host
-}
-
-func (s *apiServer) Info(c *gin.Context) {
- s.renderOK(c, s.service.Info())
-}
-
-func (s *apiServer) Ping(c *gin.Context) {
- c.JSON(http.StatusOK, s.service.Ping())
-}
-
-func (s *apiServer) dispatchMsg(c *gin.Context, req any, fn func(virt.Context) error) {
- s.dispatch(c, req, func(ctx virt.Context) (any, error) {
- return nil, fn(ctx)
- })
-}
-
-type operate func(virt.Context) (any, error)
-
-func (s *apiServer) dispatch(c *gin.Context, req any, fn operate) {
- if req != nil {
- if err := s.bind(c, req); err != nil {
- s.renderErr(c, err)
- return
- }
- }
-
- var resp, err = fn(s.virtContext())
- if err != nil {
- s.renderErr(c, err)
- return
- }
-
- if resp == nil {
- s.renderOKMsg(c)
- } else {
- s.renderOK(c, resp)
- }
-}
-
-func (s *apiServer) bind(c *gin.Context, req any) error {
- switch c.Request.Method {
- case http.MethodGet:
- return c.ShouldBindUri(req)
-
- case http.MethodPost:
- return c.ShouldBind(req)
-
- default:
- return errors.Errorf("invalid HTTP method: %s", c.Request.Method)
- }
-}
-
-var okMsg = types.NewMsg("ok")
-
-func (s *apiServer) renderOKMsg(c *gin.Context) {
- s.renderOK(c, okMsg)
-}
-
-func (s *apiServer) renderOK(c *gin.Context, resp any) {
- c.JSON(http.StatusOK, resp)
-}
-
-func (s *apiServer) renderErr(c *gin.Context, err error) {
- c.JSON(http.StatusInternalServerError, err.Error())
-}
-
-func (s *apiServer) virtContext() virt.Context {
- return s.service.VirtContext(context.Background())
-}
diff --git a/internal/server/http/guest.go b/internal/server/http/guest.go
deleted file mode 100644
index 9144d31..0000000
--- a/internal/server/http/guest.go
+++ /dev/null
@@ -1,133 +0,0 @@
-package httpserver
-
-import (
- "github.com/gin-gonic/gin"
-
- "github.com/projecteru2/libyavirt/types"
-
- "github.com/projecteru2/yavirt/internal/virt"
- virtypes "github.com/projecteru2/yavirt/internal/virt/types"
-)
-
-func (s *apiServer) GetGuest(c *gin.Context) {
- var req types.GuestReq
- s.dispatch(c, &req, func(ctx virt.Context) (any, error) {
- return s.service.GetGuest(ctx, req.VirtID())
- })
-}
-
-func (s *apiServer) GetGuestIDList(c *gin.Context) {
- s.dispatch(c, nil, func(ctx virt.Context) (any, error) {
- return s.service.GetGuestIDList(ctx)
- })
-}
-
-func (s *apiServer) GetGuestUUID(c *gin.Context) {
- var req types.GuestReq
- s.dispatch(c, &req, func(ctx virt.Context) (any, error) {
- return s.service.GetGuestUUID(ctx, req.VirtID())
- })
-}
-
-func (s *apiServer) CaptureGuest(c *gin.Context) {
- var req types.CaptureGuestReq
- s.dispatch(c, &req, func(ctx virt.Context) (any, error) {
- return s.service.CaptureGuest(ctx, req)
- })
-}
-
-func (s *apiServer) ResizeGuest(c *gin.Context) {
- var req types.ResizeGuestReq
- s.dispatchMsg(c, &req, func(ctx virt.Context) error {
- return s.service.ResizeGuest(ctx, req)
- })
-}
-
-func (s *apiServer) DestroyGuest(c *gin.Context) {
- var req types.GuestReq
- s.dispatchMsg(c, &req, func(ctx virt.Context) error {
- return s.service.ControlGuest(ctx, req.VirtID(), types.OpDestroy, req.Force)
- })
-}
-
-func (s *apiServer) StopGuest(c *gin.Context) {
- var req types.GuestReq
- s.dispatchMsg(c, &req, func(ctx virt.Context) error {
- return s.service.ControlGuest(ctx, req.VirtID(), types.OpStop, req.Force)
- })
-}
-
-func (s *apiServer) StartGuest(c *gin.Context) {
- var req types.GuestReq
- s.dispatchMsg(c, &req, func(ctx virt.Context) error {
- return s.service.ControlGuest(ctx, req.VirtID(), types.OpStart, false)
- })
-}
-
-func (s *apiServer) CreateGuest(c *gin.Context) {
- var req types.CreateGuestReq
-
- s.dispatch(c, &req, func(ctx virt.Context) (any, error) {
- return s.service.CreateGuest(
- ctx,
- virtypes.GuestCreateOption{
- CPU: req.CPU,
- Mem: req.Mem,
- ImageName: req.ImageName,
- Volumes: req.Volumes,
- DmiUUID: req.DmiUUID,
- Labels: req.Labels,
- ImageUser: req.ImageUser,
- },
- )
- })
-}
-
-func (s *apiServer) ExecuteGuest(c *gin.Context) {
- var req types.ExecuteGuestReq
- s.dispatch(c, &req, func(ctx virt.Context) (any, error) {
- return s.service.ExecuteGuest(ctx, req.VirtID(), req.Commands)
- })
-}
-
-func (s *apiServer) ConnectNetwork(c *gin.Context) {
- var req types.ConnectNetworkReq
- s.dispatch(c, &req, func(ctx virt.Context) (any, error) {
- return s.service.ConnectNetwork(ctx, req.VirtID(), req.Network, req.IPv4)
- })
-}
-
-func (s *apiServer) ResizeConsoleWindow(c *gin.Context) {
- var req types.ResizeConsoleWindowReq
- s.dispatch(c, &req, func(ctx virt.Context) (any, error) {
- return nil, s.service.ResizeConsoleWindow(ctx, req.VirtID(), req.Height, req.Width)
- })
-}
-
-func (s *apiServer) ListSnapshot(c *gin.Context) {
- var req types.ListSnapshotReq
- s.dispatch(c, &req, func(ctx virt.Context) (any, error) {
- return s.service.ListSnapshot(ctx, req)
- })
-}
-
-func (s *apiServer) CreateSnapshot(c *gin.Context) {
- var req types.CreateSnapshotReq
- s.dispatchMsg(c, &req, func(ctx virt.Context) error {
- return s.service.CreateSnapshot(ctx, req)
- })
-}
-
-func (s *apiServer) CommitSnapshot(c *gin.Context) {
- var req types.CommitSnapshotReq
- s.dispatchMsg(c, &req, func(ctx virt.Context) error {
- return s.service.CommitSnapshot(ctx, req)
- })
-}
-
-func (s *apiServer) RestoreSnapshot(c *gin.Context) {
- var req types.RestoreSnapshotReq
- s.dispatchMsg(c, &req, func(ctx virt.Context) error {
- return s.service.RestoreSnapshot(ctx, req)
- })
-}
diff --git a/internal/server/http/http_server.go b/internal/server/http/http_server.go
deleted file mode 100644
index 50be34e..0000000
--- a/internal/server/http/http_server.go
+++ /dev/null
@@ -1,93 +0,0 @@
-package httpserver
-
-import (
- "context"
- "net/http"
-
- "github.com/projecteru2/yavirt/configs"
- "github.com/projecteru2/yavirt/internal/metrics"
- "github.com/projecteru2/yavirt/internal/server"
- "github.com/projecteru2/yavirt/pkg/errors"
- "github.com/projecteru2/yavirt/pkg/log"
-)
-
-// HTTPServer .
-type HTTPServer struct {
- *server.Server
-
- httpServer *http.Server
-}
-
-// Listen .
-func Listen(svc *server.Service) (srv *HTTPServer, err error) {
- srv = &HTTPServer{}
- if srv.Server, err = server.Listen(configs.Conf.BindHTTPAddr, svc); err != nil {
- return
- }
-
- srv.httpServer = srv.newHTTPServer()
-
- return srv, nil
-}
-
-func (s *HTTPServer) newHTTPServer() *http.Server {
- var mux = http.NewServeMux()
- mux.Handle("/metrics", metrics.Handler())
- mux.Handle("/", newAPIHandler(s.Service))
- return &http.Server{Handler: mux} //nolint
-}
-
-// Reload .
-func (s *HTTPServer) Reload() error {
- return nil
-}
-
-// Serve .
-func (s *HTTPServer) Serve() (err error) {
- defer func() {
- log.Warnf("[httpserver] main loop %p exit", s)
- s.Close()
- }()
-
- var errCh = make(chan error, 1)
- go func() {
- defer func() {
- log.Warnf("[httpserver] HTTP server %p exit", s.httpServer)
- }()
- errCh <- s.httpServer.Serve(s.Listener)
- }()
-
- select {
- case <-s.Exit.Ch:
- return nil
- case err = <-errCh:
- return errors.Trace(err)
- }
-}
-
-// Close .
-func (s *HTTPServer) Close() {
- s.Exit.Do(func() {
- close(s.Exit.Ch)
-
- var err error
- defer func() {
- if err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
- }
- }()
-
- var ctx, cancel = context.WithTimeout(context.Background(), configs.Conf.GracefulTimeout.Duration())
- defer cancel()
-
- if err = s.httpServer.Shutdown(ctx); err != nil {
- return
- }
- })
-}
-
-// ExitCh .
-func (s *HTTPServer) ExitCh() chan struct{} {
- return s.Exit.Ch
-}
diff --git a/internal/server/server.go b/internal/server/server.go
deleted file mode 100644
index 26a9962..0000000
--- a/internal/server/server.go
+++ /dev/null
@@ -1,50 +0,0 @@
-package server
-
-import (
- "net"
- "sync"
-
- "github.com/projecteru2/yavirt/configs"
- "github.com/projecteru2/yavirt/pkg/netx"
-)
-
-// Server .
-type Serverable interface {
- Reload() error
- Serve() error
- Close()
- ExitCh() chan struct{}
-}
-
-// Server .
-type Server struct {
- Addr string
- Listener net.Listener
- Service *Service
- Exit struct {
- sync.Once
- Ch chan struct{}
- }
-}
-
-// Listen .
-func Listen(addr string, svc *Service) (srv *Server, err error) {
- srv = &Server{Service: svc}
- srv.Exit.Ch = make(chan struct{}, 1)
- srv.Listener, srv.Addr, err = srv.Listen(addr)
- return
-}
-
-// Listen .
-func (s *Server) Listen(addr string) (lis net.Listener, ip string, err error) {
- var network = "tcp"
- if lis, err = net.Listen(network, addr); err != nil {
- return
- }
-
- if ip, err = netx.GetOutboundIP(configs.Conf.Core.Addrs[0]); err != nil {
- return
- }
-
- return
-}
diff --git a/internal/server/service.go b/internal/server/service.go
deleted file mode 100644
index 9e133da..0000000
--- a/internal/server/service.go
+++ /dev/null
@@ -1,517 +0,0 @@
-package server
-
-import (
- "context"
- "fmt"
- "io"
-
- "github.com/projecteru2/libyavirt/types"
-
- "github.com/robfig/cron/v3"
-
- "github.com/projecteru2/yavirt/configs"
- "github.com/projecteru2/yavirt/internal/metrics"
- "github.com/projecteru2/yavirt/internal/models"
- "github.com/projecteru2/yavirt/internal/ver"
- "github.com/projecteru2/yavirt/internal/virt"
- "github.com/projecteru2/yavirt/internal/virt/guest/manager"
- virtypes "github.com/projecteru2/yavirt/internal/virt/types"
- "github.com/projecteru2/yavirt/internal/vnet"
- calihandler "github.com/projecteru2/yavirt/internal/vnet/handler/calico"
- vlanhandler "github.com/projecteru2/yavirt/internal/vnet/handler/vlan"
- "github.com/projecteru2/yavirt/pkg/errors"
- "github.com/projecteru2/yavirt/pkg/log"
- "github.com/projecteru2/yavirt/pkg/utils"
-)
-
-// Service .
-type Service struct {
- Host *models.Host
- BootGuestCh chan<- string
- caliHandler *calihandler.Handler
- guest manager.Manageable
-
- pid2ExitCode *utils.ExitCodeMap
- RecoverGuestCh chan<- string
-}
-
-// SetupYavirtdService .
-func SetupYavirtdService() (*Service, error) {
- svc := &Service{
- guest: manager.New(),
- pid2ExitCode: utils.NewSyncMap(),
- }
-
- return svc, svc.setup()
-}
-
-func (svc *Service) setup() (err error) {
- if svc.Host, err = models.LoadHost(); err != nil {
- return errors.Trace(err)
- }
-
- if err := svc.setupCalico(); err != nil {
- return errors.Trace(err)
- }
-
- // Start watching all local guests' changes.
- svc.guest.StartWatch()
-
- /*
- if err := svc.ScheduleSnapshotCreate(); err != nil {
- return errors.Trace(err)
- }
- */
-
- return nil
-}
-
-// TODO: Decide time
-func (svc *Service) ScheduleSnapshotCreate() error {
- c := cron.New()
-
- // Everyday 3am
- if _, err := c.AddFunc("0 3 * * *", svc.batchCreateSnapshot); err != nil {
- return errors.Trace(err)
- }
-
- // Every Sunday 1am
- if _, err := c.AddFunc("0 1 * * SUN", svc.batchCommitSnapshot); err != nil {
- return errors.Trace(err)
- }
-
- // Start job asynchronously
- c.Start()
-
- return nil
-}
-
-func (svc *Service) batchCreateSnapshot() {
- guests, err := models.GetAllGuests()
- if err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
- return
- }
-
- for _, g := range guests {
- for _, volID := range g.VolIDs {
- req := types.CreateSnapshotReq{
- ID: g.ID,
- VolID: volID,
- }
-
- if err := svc.CreateSnapshot(
- virt.NewContext(context.Background(), svc.caliHandler), req,
- ); err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
- }
- }
- }
-}
-
-func (svc *Service) batchCommitSnapshot() {
- guests, err := models.GetAllGuests()
- if err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
- return
- }
-
- for _, g := range guests {
- for _, volID := range g.VolIDs {
- if err := svc.CommitSnapshotByDay(
- virt.NewContext(context.Background(), svc.caliHandler),
- g.ID,
- volID,
- configs.Conf.SnapshotRestorableDay,
- ); err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
- }
- }
- }
-}
-
-// VirtContext .
-func (svc *Service) VirtContext(ctx context.Context) virt.Context {
- return virt.NewContext(ctx, svc.caliHandler)
-}
-
-// Ping .
-func (svc *Service) Ping() map[string]string {
- return map[string]string{"version": ver.Version()}
-}
-
-// Info .
-func (svc *Service) Info() types.HostInfo {
- return types.HostInfo{
- ID: fmt.Sprintf("%d", svc.Host.ID),
- CPU: svc.Host.CPU,
- Mem: svc.Host.Memory,
- Storage: svc.Host.Storage,
- Resources: map[string][]byte{},
- }
-}
-
-// GetGuest .
-func (svc *Service) GetGuest(ctx virt.Context, id string) (*types.Guest, error) {
- vg, err := svc.guest.Load(ctx, id)
- if err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
- return nil, err
- }
- return convGuestResp(vg.Guest), nil
-}
-
-// GetGuestIDList .
-func (svc *Service) GetGuestIDList(ctx virt.Context) ([]string, error) {
- ids, err := svc.guest.ListLocalIDs(ctx)
- if err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
- return nil, err
- }
- return convGuestIDsResp(ids), err
-}
-
-// GetGuestUUID .
-func (svc *Service) GetGuestUUID(ctx virt.Context, id string) (string, error) {
- uuid, err := svc.guest.LoadUUID(ctx, id)
- if err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
- return "", err
- }
- return uuid, nil
-}
-
-// CreateGuest .
-func (svc *Service) CreateGuest(ctx virt.Context, opts virtypes.GuestCreateOption) (*types.Guest, error) {
- vols := []*models.Volume{}
- for _, v := range opts.Volumes {
- vol, err := models.NewDataVolume(v.Mount, v.Capacity)
- if err != nil {
- return nil, errors.Trace(err)
- }
- vols = append(vols, vol)
- }
-
- if opts.CPU == 0 {
- opts.CPU = utils.Min(svc.Host.CPU, configs.Conf.MaxCPU)
- }
- if opts.Mem == 0 {
- opts.Mem = utils.Min(svc.Host.Memory, configs.Conf.MaxMemory)
- }
-
- g, err := svc.guest.Create(ctx, opts, svc.Host, vols)
- if err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
- return nil, err
- }
-
- go func() {
- svc.BootGuestCh <- g.ID
- }()
-
- return convGuestResp(g.Guest), nil
-}
-
-// CaptureGuest .
-func (svc *Service) CaptureGuest(ctx virt.Context, req types.CaptureGuestReq) (uimg *models.UserImage, err error) {
- if uimg, err = svc.guest.Capture(ctx, req.VirtID(), req.User, req.Name, req.Overridden); err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
- }
- return
-}
-
-// ResizeGuest .
-func (svc *Service) ResizeGuest(ctx virt.Context, req types.ResizeGuestReq) (err error) {
- vols := map[string]int64{}
- for _, vol := range req.Volumes {
- vols[vol.Mount] = vol.Capacity
- }
- if err = svc.guest.Resize(ctx, req.VirtID(), req.CPU, req.Mem, vols); err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
- }
- return
-}
-
-// ControlGuest .
-func (svc *Service) ControlGuest(ctx virt.Context, id, operation string, force bool) (err error) {
- switch operation {
- case types.OpStart:
- err = svc.guest.Start(ctx, id)
- case types.OpStop:
- err = svc.guest.Stop(ctx, id, force)
- case types.OpDestroy:
- _, err = svc.guest.Destroy(ctx, id, force)
- }
-
- if err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
- return errors.Trace(err)
- }
-
- return nil
-}
-
-// ListSnapshot .
-func (svc *Service) ListSnapshot(ctx virt.Context, req types.ListSnapshotReq) (snaps types.Snapshots, err error) {
- volSnap, err := svc.guest.ListSnapshot(ctx, req.ID, req.VolID)
- if err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
- }
-
- for vol, s := range volSnap {
- for _, snap := range s {
- snaps = append(snaps, &types.Snapshot{
- VolID: vol.ID,
- VolMountDir: vol.GetMountDir(),
- SnapID: snap.ID,
- CreatedTime: snap.CreatedTime,
- })
- }
- }
-
- return
-}
-
-// CreateSnapshot .
-func (svc *Service) CreateSnapshot(ctx virt.Context, req types.CreateSnapshotReq) (err error) {
- if err = svc.guest.CreateSnapshot(ctx, req.ID, req.VolID); err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
- }
- return
-}
-
-// CommitSnapshot .
-func (svc *Service) CommitSnapshot(ctx virt.Context, req types.CommitSnapshotReq) (err error) {
- if err = svc.guest.CommitSnapshot(ctx, req.ID, req.VolID, req.SnapID); err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
- }
- return
-}
-
-// CommitSnapshotByDay .
-func (svc *Service) CommitSnapshotByDay(ctx virt.Context, id, volID string, day int) (err error) {
- if err = svc.guest.CommitSnapshotByDay(ctx, id, volID, day); err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
- }
- return
-}
-
-// RestoreSnapshot .
-func (svc *Service) RestoreSnapshot(ctx virt.Context, req types.RestoreSnapshotReq) (err error) {
- if err = svc.guest.RestoreSnapshot(ctx, req.ID, req.VolID, req.SnapID); err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
- }
- return
-}
-
-// ConnectNetwork .
-func (svc *Service) ConnectNetwork(ctx virt.Context, id, network, ipv4 string) (cidr string, err error) {
- if cidr, err = svc.guest.ConnectExtraNetwork(ctx, id, network, ipv4); err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
- }
- return
-}
-
-// DisconnectNetwork .
-func (svc *Service) DisconnectNetwork(ctx virt.Context, id, network string) (err error) {
- if err = svc.guest.DisconnectExtraNetwork(ctx, id, network); err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
- }
- return
-}
-
-// NetworkList .
-func (svc *Service) NetworkList(ctx virt.Context, drivers []string) ([]*types.Network, error) {
- drv := map[string]struct{}{}
- for _, driver := range drivers {
- drv[driver] = struct{}{}
- }
-
- networks := []*types.Network{}
- switch svc.Host.NetworkMode {
- case vnet.NetworkCalico:
- if _, ok := drv[vnet.NetworkCalico]; svc.caliHandler == nil || !ok {
- break
- }
- for _, poolName := range svc.caliHandler.PoolNames() {
- subnet, err := svc.caliHandler.GetIPPoolCidr(ctx.Context, poolName)
- if err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
- return nil, err
- }
-
- networks = append(networks, &types.Network{
- Name: poolName,
- Subnets: []string{subnet},
- })
- }
- return networks, nil
- case vnet.NetworkVlan: // vlan
- if _, ok := drv[vnet.NetworkVlan]; !ok {
- break
- }
- handler := vlanhandler.New("", svc.Host.Subnet)
- networks = append(networks, &types.Network{
- Name: "vlan",
- Subnets: []string{handler.GetCidr()},
- })
- }
-
- return networks, nil
-}
-
-// AttachGuest .
-func (svc *Service) AttachGuest(ctx virt.Context, id string, stream io.ReadWriteCloser, flags virtypes.OpenConsoleFlags) (err error) {
- if err = svc.guest.AttachConsole(ctx, id, stream, flags); err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
- }
- return
-}
-
-// ResizeConsoleWindow .
-func (svc *Service) ResizeConsoleWindow(ctx virt.Context, id string, height, width uint) (err error) {
- if err = svc.guest.ResizeConsoleWindow(ctx, id, height, width); err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
- }
- return
-}
-
-// ExecuteGuest .
-func (svc *Service) ExecuteGuest(ctx virt.Context, id string, commands []string) (*types.ExecuteGuestMessage, error) {
- stdout, exitCode, pid, err := svc.guest.ExecuteCommand(ctx, id, commands)
- if err != nil {
- log.WarnStack(err)
- metrics.IncrError()
- }
- svc.pid2ExitCode.Put(id, pid, exitCode)
- return &types.ExecuteGuestMessage{
- Pid: pid,
- Data: stdout,
- ExitCode: exitCode,
- }, err
-}
-
-// ExecExitCode .
-func (svc *Service) ExecExitCode(id string, pid int) (int, error) {
- exitCode, err := svc.pid2ExitCode.Get(id, pid)
- if err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
- return 0, err
- }
- return exitCode, nil
-}
-
-// Cat .
-func (svc *Service) Cat(ctx virt.Context, id, path string, dest io.WriteCloser) (err error) {
- if err = svc.guest.Cat(ctx, id, path, dest); err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
- }
- return
-}
-
-// CopyToGuest .
-func (svc *Service) CopyToGuest(ctx virt.Context, id, dest string, content chan []byte, override bool) (err error) {
- if err = svc.guest.CopyToGuest(ctx, id, dest, content, override); err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
- }
- return
-}
-
-// Log .
-func (svc *Service) Log(ctx virt.Context, id, logPath string, n int, dest io.WriteCloser) (err error) {
- if err = svc.guest.Log(ctx, id, logPath, n, dest); err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
- }
- return
-}
-
-// Wait .
-func (svc *Service) Wait(ctx virt.Context, id string, block bool) (msg string, code int, err error) {
- err = svc.guest.Stop(ctx, id, !block)
- if err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
- return "stop error", -1, err
- }
- if msg, code, err = svc.guest.Wait(ctx, id, block); err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
- }
- return
-}
-
-func (svc *Service) PushImage(_ virt.Context, _, _ string) (err error) {
- // todo
- return
-}
-
-func (svc *Service) RemoveImage(ctx virt.Context, imageName, user string, force, prune bool) (removed []string, err error) {
- if removed, err = svc.guest.RemoveImage(ctx, imageName, user, force, prune); err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
- }
- return
-}
-
-func (svc *Service) ListImage(ctx virt.Context, filter string) ([]types.SysImage, error) {
- imgs, err := svc.guest.ListImage(ctx, filter)
- if err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
- }
-
- images := []types.SysImage{}
- for _, img := range imgs {
- images = append(images, types.SysImage{
- Name: img.GetName(),
- User: img.GetUser(),
- Distro: img.GetDistro(),
- ID: img.GetID(),
- Type: img.GetType(),
- })
- }
-
- return images, err
-}
-
-func (svc *Service) PullImage(virt.Context, string, bool) (msg string, err error) {
- // todo
- return
-}
-
-func (svc *Service) DigestImage(ctx virt.Context, imageName string, local bool) (digest []string, err error) {
- if digest, err = svc.guest.DigestImage(ctx, imageName, local); err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
- }
- return
-}
-
-func (svc *Service) WatchGuestEvents(virt.Context) (*manager.Watcher, error) {
- return svc.guest.NewWatcher()
-}
diff --git a/internal/server/service_test.go b/internal/server/service_test.go
deleted file mode 100644
index fa940cb..0000000
--- a/internal/server/service_test.go
+++ /dev/null
@@ -1,104 +0,0 @@
-package server
-
-import (
- "context"
- "testing"
-
- "github.com/projecteru2/libyavirt/types"
- "github.com/projecteru2/yavirt/internal/models"
- "github.com/projecteru2/yavirt/internal/virt"
- vg "github.com/projecteru2/yavirt/internal/virt/guest"
- managerocks "github.com/projecteru2/yavirt/internal/virt/guest/manager/mocks"
- virtypes "github.com/projecteru2/yavirt/internal/virt/types"
- "github.com/projecteru2/yavirt/pkg/test/assert"
- "github.com/projecteru2/yavirt/pkg/test/mock"
- "github.com/projecteru2/yavirt/pkg/utils"
-)
-
-func init() {
- models.Setup()
-}
-
-func TestCreateGuest(t *testing.T) {
- svc := testService(t)
-
- svc.guest.(*managerocks.Manageable).On("Create",
- mock.Anything, // ctx
- mock.Anything, // cpu
- mock.Anything, // memory
- mock.Anything, // vols
- mock.Anything, // imgName
- mock.Anything, // imgUser
- mock.Anything, // host
- mock.Anything, // dmiUUID
- mock.Anything, // labels
- ).Return(testVirtGuest(t), nil)
- _, err := svc.CreateGuest(testVirtContext(t), virtypes.GuestCreateOption{
- CPU: 1,
- Mem: utils.GB,
- ImageName: "ubuntu",
- ImageUser: "anrs",
- Volumes: nil,
- DmiUUID: "uuid",
- Labels: nil,
- })
- assert.NilErr(t, err)
-}
-
-func TestGetGuest(t *testing.T) {
- svc := testService(t)
- svc.guest.(*managerocks.Manageable).On("Load", mock.Anything, mock.Anything).Return(testVirtGuest(t), nil)
- _, err := svc.GetGuest(testVirtContext(t), "id")
- assert.NilErr(t, err)
-}
-
-func TestGetGuestIDList(t *testing.T) {
- localIDs := []string{"ya0", "ya1", "ya2"}
- svc := testService(t)
- svc.guest.(*managerocks.Manageable).On("ListLocalIDs", mock.Anything, mock.Anything).Return(localIDs, nil).Once()
-
- ids, err := svc.GetGuestIDList(testVirtContext(t))
- assert.NilErr(t, err)
-
- eruIDs := []string{types.EruID("ya0"), types.EruID("ya1"), types.EruID("ya2")}
- assert.Equal(t, eruIDs, ids)
-}
-
-func TestGetGuestUUID(t *testing.T) {
- svc := testService(t)
- svc.guest.(*managerocks.Manageable).On("LoadUUID", mock.Anything, mock.Anything).Return("uuid", nil)
- _, err := svc.GetGuestUUID(testVirtContext(t), "id")
- assert.NilErr(t, err)
-}
-
-func TestCopyToGuest(t *testing.T) {
- svc := testService(t)
- svc.guest.(*managerocks.Manageable).On("CopyToGuest",
- mock.Anything, // ctx
- mock.Anything, // id
- mock.Anything, // dest
- mock.Anything, // content
- mock.Anything, // override
- ).Return(nil)
- err := svc.CopyToGuest(testVirtContext(t), "id", "dest", nil, true)
- assert.NilErr(t, err)
-}
-
-func testVirtGuest(t *testing.T) *vg.Guest {
- mg, err := models.NewGuest(nil, nil)
- assert.NilErr(t, err)
- assert.NotNil(t, mg)
- return vg.New(testVirtContext(t), mg)
-}
-
-func testVirtContext(t *testing.T) virt.Context {
- return virt.NewContext(context.Background(), nil)
-}
-
-func testService(t *testing.T) *Service {
- return &Service{
- Host: &models.Host{},
- guest: &managerocks.Manageable{},
- BootGuestCh: make(chan string, 1),
- }
-}
diff --git a/internal/service/boar/boar.go b/internal/service/boar/boar.go
new file mode 100644
index 0000000..fda3212
--- /dev/null
+++ b/internal/service/boar/boar.go
@@ -0,0 +1,415 @@
+package boar
+
+import (
+ "context"
+ "fmt"
+ "net"
+ "strings"
+ "sync"
+ "testing"
+ "time"
+
+ "github.com/projecteru2/libyavirt/types"
+ "github.com/prometheus/client_golang/prometheus"
+
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/core/log"
+ "github.com/projecteru2/yavirt/configs"
+ "github.com/projecteru2/yavirt/internal/eru/agent"
+ "github.com/projecteru2/yavirt/internal/eru/recycle"
+ "github.com/projecteru2/yavirt/internal/eru/resources"
+ "github.com/projecteru2/yavirt/internal/meta"
+ "github.com/projecteru2/yavirt/internal/metrics"
+ "github.com/projecteru2/yavirt/internal/models"
+ networkFactory "github.com/projecteru2/yavirt/internal/network/factory"
+ intertypes "github.com/projecteru2/yavirt/internal/types"
+ interutils "github.com/projecteru2/yavirt/internal/utils"
+ "github.com/projecteru2/yavirt/internal/ver"
+ "github.com/projecteru2/yavirt/internal/virt/guest"
+ "github.com/projecteru2/yavirt/internal/vmcache"
+ "github.com/projecteru2/yavirt/pkg/idgen"
+ "github.com/projecteru2/yavirt/pkg/notify/bison"
+ "github.com/projecteru2/yavirt/pkg/store"
+ "github.com/projecteru2/yavirt/pkg/utils"
+ vmiFact "github.com/yuyang0/vmimage/factory"
+ vmitypes "github.com/yuyang0/vmimage/types"
+)
+
+// Boar .
+type Boar struct {
+ Host *models.Host
+ cfg *configs.Config
+ pool *taskPool
+ BootGuestCh chan<- string
+
+ pid2ExitCode *utils.ExitCodeMap
+ RecoverGuestCh chan<- string
+
+ watchers *interutils.Watchers
+
+ imageMutex sync.Mutex
+ agt *agent.Manager
+ mCol *MetricsCollector
+}
+
+func New(ctx context.Context, cfg *configs.Config, t *testing.T) (br *Boar, err error) {
+ var cols []prometheus.Collector
+
+ br = &Boar{
+ cfg: cfg,
+ mCol: &MetricsCollector{},
+ pid2ExitCode: utils.NewSyncMap(),
+ watchers: interutils.NewWatchers(),
+ }
+ // setup notify
+ if err := bison.Setup(&cfg.Notify, t); err != nil {
+ return br, errors.Wrap(err, "failed to setup notify")
+ }
+
+ resMgr, err := resources.Setup(ctx, cfg, t)
+ if err != nil {
+ return nil, err
+ }
+ cols = append(cols, resMgr.GetMetricsCollector())
+
+ br.Host, err = models.LoadHost()
+ if err != nil {
+ return nil, err
+ }
+ br.pool, err = newTaskPool(cfg.MaxConcurrency)
+ if err != nil {
+ return nil, err
+ }
+ if err := idgen.Setup(br.Host.ID); err != nil {
+ return nil, err
+ }
+
+ if err = store.Setup(configs.Conf, t); err != nil {
+ return nil, err
+ }
+ go br.watchers.Run(ctx)
+ if err := vmcache.Setup(ctx, cfg, br.watchers); err != nil {
+ return br, errors.Wrap(err, "failed to setup vmcache")
+ }
+ if err := vmiFact.Setup(&cfg.ImageHub); err != nil {
+ return br, errors.Wrap(err, "failed to setup vmimage")
+ }
+ if err := networkFactory.Setup(&cfg.Network); err != nil {
+ return br, errors.Wrap(err, "failed to setup calico")
+ }
+ cols = append(cols, networkFactory.GetMetricsCollectors()...)
+
+ if cfg.Eru.Enable {
+ if err = recycle.Setup(ctx, &configs.Conf, t); err != nil {
+ return br, errors.Wrap(err, "failed to setup recycle")
+ }
+ recycle.Run(ctx, br)
+
+ parts := strings.Split(cfg.BindGRPCAddr, ":")
+ if len(parts) != 2 {
+ return br, errors.Newf("invalid bind addr %s", cfg.BindGRPCAddr)
+ }
+ grpcPort := parts[1]
+ endpoint := fmt.Sprintf( //nolint
+ "virt-grpc://%s:%s@%s:%s",
+ cfg.Auth.Username, cfg.Auth.Password, cfg.Host.Addr, grpcPort,
+ )
+ br.agt, err = agent.NewManager(ctx, br, &cfg.Eru, endpoint, t)
+ if err != nil {
+ return br, errors.Wrap(err, "failed to setup agent")
+ }
+ go br.agt.Run(ctx) //nolint
+ cols = append(cols, br.agt.GetMetricsCollector())
+ }
+ cols = append(cols, br.GetMetricsCollector())
+ metrics.Setup(cfg.Host.Name, cols...)
+ /*
+ if err := svc.ScheduleSnapshotCreate(); err != nil {
+ return errors.Wrap(err, "")
+ }
+ */
+
+ return br, nil
+}
+
+func (svc *Boar) Close() {
+ _ = svc.agt.Exit()
+ svc.pool.Release()
+ store.Close()
+}
+
+// Ping .
+func (svc *Boar) Ping() map[string]string {
+ return map[string]string{"version": ver.Version()}
+}
+
+// Info .
+func (svc *Boar) Info() (*types.HostInfo, error) {
+ res, err := resources.GetManager().FetchResources()
+ if err != nil {
+ return nil, err
+ }
+ return &types.HostInfo{
+ ID: fmt.Sprintf("%d", svc.Host.ID),
+ CPU: svc.Host.CPU,
+ Mem: svc.Host.Memory,
+ Storage: svc.Host.Storage,
+ Resources: res,
+ }, nil
+}
+
+func (svc *Boar) IsHealthy(ctx context.Context) (ans bool) {
+ logger := log.WithFunc("boar.Healthy")
+ var err error
+ // check image service
+ if err1 := vmiFact.CheckHealth(ctx); err1 != nil {
+ svc.mCol.imageHealthy.Store(false)
+ err = errors.CombineErrors(err, errors.WithMessagef(err1, "failed to check image hub"))
+ } else {
+ svc.mCol.imageHealthy.Store(true)
+ }
+ // check libvirt health
+ if err1 := checkLibvirtSocket(); err1 != nil {
+ svc.mCol.libvirtHealthy.Store(false)
+ err = errors.CombineErrors(err, errors.WithMessagef(err1, "failed to check libvirt socket"))
+ } else {
+ svc.mCol.libvirtHealthy.Store(true)
+ }
+ // check network drivers, including clico, ovn etc
+ if err1 := networkFactory.CheckHealth(ctx); err1 != nil {
+ err = errors.CombineErrors(err, errors.WithMessagef(err1, "failed to check network drivers"))
+ }
+ //TODO:Check more things
+
+ if err != nil {
+ logger.Errorf(ctx, err, "failed to check health")
+ return false
+ }
+ return true
+}
+
+// GetGuest .
+func (svc *Boar) GetGuest(ctx context.Context, id string) (*types.Guest, error) {
+ vg, err := svc.loadGuest(ctx, id)
+ if err != nil {
+ log.WithFunc("boar.GetGuest").Error(ctx, err)
+ metrics.IncrError()
+ return nil, err
+ }
+ resp := convGuestResp(vg.Guest)
+ return resp, nil
+}
+
+// GetGuestIDList .
+func (svc *Boar) GetGuestIDList(ctx context.Context) ([]string, error) {
+ ids, err := svc.ListLocalIDs(ctx, true)
+ if err != nil {
+ log.WithFunc("boar.GetGuestIDList").Error(ctx, err)
+ metrics.IncrError()
+ return nil, err
+ }
+ return ids, nil
+}
+
+// GetGuestUUID .
+func (svc *Boar) GetGuestUUID(ctx context.Context, id string) (string, error) {
+ uuid, err := svc.LoadUUID(ctx, id)
+ if err != nil {
+ log.WithFunc("boar.GetGuestUUID").Error(ctx, err)
+ metrics.IncrError()
+ return "", err
+ }
+ return uuid, nil
+}
+
+// CaptureGuest .
+func (svc *Boar) CaptureGuest(ctx context.Context, id string, imgName string, overridden bool) (uimg *vmitypes.Image, err error) {
+ defer logErr(err)
+
+ g, err := svc.loadGuest(ctx, id)
+ if err != nil {
+ return nil, err
+ }
+ uImg, err := g.Capture(imgName, overridden)
+ if err != nil {
+ return nil, err
+ }
+ return uImg, nil
+}
+
+// ResizeGuest re-allocates spec or volumes.
+func (svc *Boar) ResizeGuest(ctx context.Context, id string, opts *intertypes.GuestResizeOption) (err error) {
+ defer logErr(err)
+
+ vols, err := extractVols(opts.Resources)
+ if err != nil {
+ return err
+ }
+ cpumem, err := extractCPUMem(opts.Resources)
+ if err != nil {
+ return err
+ }
+ gpu, err := extractGPU(opts.Resources)
+ if err != nil {
+ return err
+ }
+ g, err := svc.loadGuest(ctx, id)
+ if err != nil {
+ return err
+ }
+ do := func(_ context.Context) (any, error) {
+ return nil, g.Resize(cpumem, gpu, vols)
+ }
+ _, err = svc.do(ctx, id, intertypes.ResizeOp, do, nil)
+ return
+}
+
+// Wait .
+func (svc *Boar) Wait(ctx context.Context, id string, block bool) (msg string, code int, err error) {
+ defer logErr(err)
+
+ err = svc.stopGuest(ctx, id, !block)
+ if err != nil {
+ return "stop error", -1, err
+ }
+
+ err = svc.ctrl(ctx, id, intertypes.MiscOp, func(g *guest.Guest) error {
+ if err = g.Wait(meta.StatusStopped, block); err != nil {
+ return err
+ }
+
+ if g.LambdaOption != nil {
+ msg = string(g.LambdaOption.CmdOutput)
+ code = g.LambdaOption.ExitCode
+ }
+
+ return nil
+ }, nil)
+ return msg, code, err
+}
+
+// ListLocals lists all local guests.
+func (svc *Boar) ListLocalIDs(ctx context.Context, onlyERU bool) ([]string, error) {
+ ids, err := guest.ListLocalIDs(ctx)
+ if err != nil {
+ return nil, err
+ }
+ if !onlyERU {
+ return ids, nil
+ }
+ var ans []string
+ for _, id := range ids {
+ if idgen.CheckID(id) {
+ ans = append(ans, id)
+ }
+ }
+ return ans, nil
+}
+
+// LoadUUID read a guest's UUID.
+func (svc *Boar) LoadUUID(ctx context.Context, id string) (string, error) {
+ g, err := svc.loadGuest(ctx, id)
+ if err != nil {
+ return "", err
+ }
+ return g.GetUUID()
+}
+
+// loadGuest read a guest from metadata.
+func (svc *Boar) loadGuest(ctx context.Context, id string, opts ...models.Option) (*guest.Guest, error) {
+ g, err := models.LoadGuest(id)
+ if err != nil {
+ return nil, err
+ }
+
+ var vg = guest.New(ctx, g)
+ if err := vg.Load(opts...); err != nil {
+ return nil, err
+ }
+ if err = vg.UpdateStateIfNecessary(); err != nil {
+ log.WithFunc("boar.loadGuest").Warnf(ctx, "update state error: %s", err)
+ }
+ return vg, nil
+}
+
+func (svc *Boar) WatchGuestEvents(context.Context) (*interutils.Watcher, error) {
+ return svc.watchers.Get()
+}
+
+func logErr(err error) {
+ if err != nil {
+ log.Error(context.TODO(), err)
+ metrics.IncrError()
+ }
+}
+
+type ctrlFunc func(*guest.Guest) error
+type rollbackFunc func()
+
+func (svc *Boar) ctrl(ctx context.Context, id string, op intertypes.Operator, fn ctrlFunc, rollback rollbackFunc) error { //nolint
+ do := func(ctx context.Context) (any, error) {
+ g, err := svc.loadGuest(ctx, id)
+ if err != nil {
+ return nil, err
+ }
+ return nil, fn(g)
+ }
+ _, err := svc.do(ctx, id, op, do, rollback)
+ return err
+}
+
+type doFunc func(context.Context) (any, error)
+
+func (svc *Boar) do(ctx context.Context, id string, op intertypes.Operator, fn doFunc, rollback rollbackFunc) (result any, err error) {
+ defer func() {
+ if err != nil && rollback != nil {
+ rollback()
+ }
+ }()
+
+ // add a max timeout
+ ctx1, cancel := context.WithTimeout(ctx, configs.Conf.VirtTimeout)
+ defer cancel()
+
+ t := newTask(ctx1, id, op, fn)
+
+ if err := svc.pool.SubmitTask(t); err != nil {
+ return nil, err
+ }
+
+ metrics.Incr(metrics.MetricSvcTasks, nil) //nolint:errcheck
+ defer metrics.Decr(metrics.MetricSvcTasks, nil) //nolint:errcheck
+
+ select {
+ case <-t.Done():
+ result, err = t.result()
+ case <-ctx1.Done():
+ err = ctx1.Err()
+ }
+ if err != nil {
+ metrics.IncrError()
+ return
+ }
+
+ svc.watchers.Watched(intertypes.Event{
+ ID: id,
+ Type: guestEventType,
+ Op: op,
+ Time: time.Now().UTC(),
+ })
+
+ return
+}
+
+const guestEventType = "guest"
+
+func checkLibvirtSocket() error {
+ socketPath := "/var/run/libvirt/libvirt-sock"
+ // Dial the Unix domain socket
+ conn, err := net.DialTimeout("unix", socketPath, 3*time.Second)
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+ return nil
+}
diff --git a/internal/service/boar/boar_test.go b/internal/service/boar/boar_test.go
new file mode 100644
index 0000000..1c6071a
--- /dev/null
+++ b/internal/service/boar/boar_test.go
@@ -0,0 +1,85 @@
+package boar
+
+// func TestCreateGuest(t *testing.T) {
+// svc := testService(t)
+
+// svc.guest.(*managerocks.Manageable).On("Create",
+// mock.Anything, // ctx
+// mock.Anything, // cpu
+// mock.Anything, // memory
+// mock.Anything, // vols
+// mock.Anything, // imgName
+// mock.Anything, // imgUser
+// mock.Anything, // host
+// mock.Anything, // dmiUUID
+// mock.Anything, // labels
+// ).Return(testVirtGuest(t), nil)
+// _, err := svc.CreateGuest(testVirtContext(t), virtypes.GuestCreateOption{
+// CPU: 1,
+// Mem: utils.GB,
+// ImageName: "ubuntu",
+// ImageUser: "anrs",
+// Volumes: nil,
+// DmiUUID: "uuid",
+// Labels: nil,
+// })
+// assert.NilErr(t, err)
+// }
+
+// func TestGetGuest(t *testing.T) {
+// svc := testService(t)
+// svc.guest.(*managerocks.Manageable).On("Load", mock.Anything, mock.Anything).Return(testVirtGuest(t), nil)
+// _, err := svc.GetGuest(testVirtContext(t), "id")
+// assert.NilErr(t, err)
+// }
+
+// func TestGetGuestIDList(t *testing.T) {
+// localIDs := []string{"ya0", "ya1", "ya2"}
+// svc := testService(t)
+// svc.guest.(*managerocks.Manageable).On("ListLocalIDs", mock.Anything, mock.Anything).Return(localIDs, nil).Once()
+
+// ids, err := svc.GetGuestIDList(testVirtContext(t))
+// assert.NilErr(t, err)
+
+// eruIDs := []string{types.EruID("ya0"), types.EruID("ya1"), types.EruID("ya2")}
+// assert.Equal(t, eruIDs, ids)
+// }
+
+// func TestGetGuestUUID(t *testing.T) {
+// svc := testService(t)
+// svc.guest.(*managerocks.Manageable).On("LoadUUID", mock.Anything, mock.Anything).Return("uuid", nil)
+// _, err := svc.GetGuestUUID(testVirtContext(t), "id")
+// assert.NilErr(t, err)
+// }
+
+// func TestCopyToGuest(t *testing.T) {
+// svc := testService(t)
+// svc.guest.(*managerocks.Manageable).On("CopyToGuest",
+// mock.Anything, // ctx
+// mock.Anything, // id
+// mock.Anything, // dest
+// mock.Anything, // content
+// mock.Anything, // override
+// ).Return(nil)
+// err := svc.CopyToGuest(testVirtContext(t), "id", "dest", nil, true)
+// assert.NilErr(t, err)
+// }
+
+// func testVirtGuest(t *testing.T) *vg.Guest {
+// mg, err := models.NewGuest(nil, nil)
+// assert.NilErr(t, err)
+// assert.NotNil(t, mg)
+// return vg.New(testVirtContext(t), mg)
+// }
+
+// func testVirtContext(t *testing.T) context.Context {
+// return util.SetCalicoHandler(context.Background(), nil)
+// }
+
+// func testService(t *testing.T) *Boar {
+// return &Boar{
+// Host: &models.Host{},
+// guest: &managerocks.Manageable{},
+// BootGuestCh: make(chan string, 1),
+// }
+// }
diff --git a/internal/service/boar/console.go b/internal/service/boar/console.go
new file mode 100644
index 0000000..ab2d1e3
--- /dev/null
+++ b/internal/service/boar/console.go
@@ -0,0 +1,29 @@
+package boar
+
+import (
+ "context"
+ "io"
+
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/yavirt/internal/meta"
+ intertypes "github.com/projecteru2/yavirt/internal/types"
+)
+
+// AttachGuest .
+func (svc *Boar) AttachGuest(ctx context.Context, id string, stream io.ReadWriteCloser, flags intertypes.OpenConsoleFlags) (err error) {
+ defer logErr(err)
+
+ g, err := svc.loadGuest(ctx, id)
+ if err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ if g.LambdaOption != nil {
+ if err = g.Wait(meta.StatusRunning, false); err != nil {
+ return errors.Wrap(err, "")
+ }
+ flags.Commands = g.LambdaOption.Cmd
+ }
+
+ return g.AttachConsole(ctx, stream, flags)
+}
diff --git a/internal/service/boar/control.go b/internal/service/boar/control.go
new file mode 100644
index 0000000..d1d55d5
--- /dev/null
+++ b/internal/service/boar/control.go
@@ -0,0 +1,165 @@
+package boar
+
+import (
+ "context"
+ "time"
+
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/core/log"
+ "github.com/projecteru2/libyavirt/types"
+ "github.com/projecteru2/yavirt/internal/metrics"
+ "github.com/projecteru2/yavirt/internal/models"
+ intertypes "github.com/projecteru2/yavirt/internal/types"
+ "github.com/projecteru2/yavirt/internal/utils"
+)
+
+// ControlGuest .
+func (svc *Boar) ControlGuest(ctx context.Context, id, operation string, force bool) (err error) {
+ var errCh <-chan error
+ switch operation {
+ case types.OpStart:
+ err = svc.startGuest(ctx, id, force)
+ case types.OpStop:
+ err = svc.stopGuest(ctx, id, force)
+ case types.OpDestroy:
+ errCh, err = svc.destroyGuest(ctx, id, force)
+ if err != nil {
+ break
+ }
+ select {
+ case <-ctx.Done():
+ err = ctx.Err()
+ case err = <-errCh:
+ }
+ case types.OpSuspend:
+ err = svc.suspendGuest(ctx, id)
+ case types.OpResume:
+ err = svc.resumeGuest(ctx, id)
+ }
+
+ if err != nil {
+ log.WithFunc("boar.ControlGuest").Error(ctx, err)
+ metrics.IncrError()
+ return errors.Wrap(err, "")
+ }
+
+ return nil
+}
+
+// destroyGuest destroys a guest.
+func (svc *Boar) destroyGuest(ctx context.Context, id string, force bool) (<-chan error, error) {
+ var done <-chan error
+ do := func(ctx context.Context) (any, error) {
+ g, err := svc.loadGuest(ctx, id, models.IgnoreLoadImageErrOption())
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ if done, err = g.Destroy(ctx, force); err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+
+ return nil, nil //nolint
+ }
+ _, err := svc.do(ctx, id, intertypes.DestroyOp, do, nil)
+ return done, err
+}
+
+// stopGuest stops a guest.
+func (svc *Boar) stopGuest(ctx context.Context, id string, force bool) error {
+ do := func(ctx context.Context) (any, error) {
+ g, err := svc.loadGuest(ctx, id, models.IgnoreLoadImageErrOption())
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ if err := g.Stop(ctx, force); err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+
+ return nil, nil //nolint
+ }
+ _, err := svc.do(ctx, id, intertypes.StopOp, do, nil)
+
+ // eru agent only track start and die event,
+ // so also send a die event here
+ if err == nil {
+ svc.watchers.Watched(intertypes.Event{
+ ID: id,
+ Type: guestEventType,
+ Op: intertypes.DieOp,
+ Time: time.Now().UTC(),
+ })
+ }
+ return err
+}
+
+// startGuest boots a guest.
+func (svc *Boar) startGuest(ctx context.Context, id string, force bool) error {
+ logger := log.WithFunc("boar.startGuest")
+ do := func(ctx context.Context) (any, error) {
+ g, err := svc.loadGuest(ctx, id, models.IgnoreLoadImageErrOption())
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ // we need to release the creation session locker here
+ lck := utils.NewCreateSessionFlock(g.ID)
+ defer func() {
+ logger.Debugf(ctx, "[session unlocker] %s", g.ID)
+ if err := lck.RemoveFile(); err != nil {
+ logger.Warnf(ctx, "failed to remove session locker file %s", err)
+ }
+ }()
+
+ if err := g.Start(ctx, force); err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ if g.LambdaOption != nil && !g.LambdaStdin {
+ output, exitCode, pid, err := g.ExecuteCommand(ctx, g.LambdaOption.Cmd)
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ g.LambdaOption.CmdOutput = output
+ g.LambdaOption.ExitCode = exitCode
+ g.LambdaOption.Pid = pid
+
+ if err = g.Save(); err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ }
+ return nil, nil //nolint
+ }
+ defer logger.Debugf(ctx, "exit startGuest")
+ _, err := svc.do(ctx, id, intertypes.StartOp, do, nil)
+ return err
+}
+
+// suspendGuest suspends a guest.
+func (svc *Boar) suspendGuest(ctx context.Context, id string) error {
+ do := func(ctx context.Context) (any, error) {
+ g, err := svc.loadGuest(ctx, id, models.IgnoreLoadImageErrOption())
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ if err := g.Suspend(); err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ return nil, nil //nolint
+ }
+ _, err := svc.do(ctx, id, intertypes.SuspendOp, do, nil)
+ return err
+}
+
+// resumeGuest resumes a suspended guest.
+func (svc *Boar) resumeGuest(ctx context.Context, id string) error {
+ do := func(ctx context.Context) (any, error) {
+ g, err := svc.loadGuest(ctx, id, models.IgnoreLoadImageErrOption())
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ if err := g.Resume(); err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ return nil, nil //nolint
+ }
+ _, err := svc.do(ctx, id, intertypes.ResumeOp, do, nil)
+ return err
+}
diff --git a/internal/service/boar/create.go b/internal/service/boar/create.go
new file mode 100644
index 0000000..e7430d7
--- /dev/null
+++ b/internal/service/boar/create.go
@@ -0,0 +1,114 @@
+package boar
+
+import (
+ "context"
+
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/core/log"
+ "github.com/projecteru2/libyavirt/types"
+ "github.com/projecteru2/yavirt/configs"
+ "github.com/projecteru2/yavirt/internal/metrics"
+ "github.com/projecteru2/yavirt/internal/models"
+ interutils "github.com/projecteru2/yavirt/internal/utils"
+ "github.com/projecteru2/yavirt/pkg/utils"
+
+ intertypes "github.com/projecteru2/yavirt/internal/types"
+ "github.com/projecteru2/yavirt/internal/virt/guest"
+)
+
+// CreateGuest .
+func (svc *Boar) CreateGuest(ctx context.Context, opts intertypes.GuestCreateOption) (*types.Guest, error) {
+ logger := log.WithFunc("boar.CreateGuest")
+ if opts.CPU == 0 {
+ opts.CPU = utils.Min(svc.Host.CPU, configs.Conf.Resource.MaxCPU)
+ }
+ if opts.Mem == 0 {
+ opts.Mem = utils.Min(svc.Host.Memory, configs.Conf.Resource.MaxMemory)
+ }
+ ctx = interutils.NewRollbackListContext(ctx)
+ g, err := svc.Create(ctx, opts, svc.Host)
+ if err != nil {
+ logger.Error(ctx, err)
+ metrics.IncrError()
+ rl := interutils.GetRollbackListFromContext(ctx)
+ for {
+ fn, msg := rl.Pop()
+ if fn == nil {
+ break
+ }
+ logger.Infof(ctx, "start to rollback<%s>", msg)
+ if err := fn(); err != nil {
+ log.Errorf(ctx, err, "failed to rollback<%s>", msg)
+ }
+ }
+ return nil, err
+ }
+
+ go func() {
+ svc.BootGuestCh <- g.ID
+ }()
+
+ return convGuestResp(g.Guest), nil
+}
+
+// Create creates a new guest.
+func (svc *Boar) Create(ctx context.Context, opts intertypes.GuestCreateOption, host *models.Host) (*guest.Guest, error) {
+ logger := log.WithFunc("boar.Create")
+ vols, err := extractVols(opts.Resources)
+ if err != nil {
+ return nil, err
+ }
+
+ // Creates metadata.
+ g, err := models.CreateGuest(opts, host, vols)
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ rl := interutils.GetRollbackListFromContext(ctx)
+
+ // session locker is locked here and is released in start
+ lck := interutils.NewCreateSessionFlock(g.ID)
+ if err := lck.Trylock(); err != nil {
+ logger.Warnf(ctx, "failed to lock create seesion id<%s> %s", g.ID, err)
+ } else {
+ rl.Append(func() error { return lck.RemoveFile() }, "release creation session locker")
+ }
+
+ rl.Append(func() error { return g.Delete(true) }, "Delete guest model")
+
+ logger.Debugf(ctx, "Guest Created: %+v", g)
+ // Destroys resource and delete metadata while rolling back.
+ vg := guest.New(ctx, g)
+
+ // Creates the resource.
+ create := func(ctx context.Context) (any, error) {
+ err := svc.create(ctx, vg)
+ return nil, err
+ }
+
+ _, err = svc.do(ctx, g.ID, intertypes.CreateOp, create, nil)
+ return vg, err
+}
+
+func (svc *Boar) create(ctx context.Context, vg *guest.Guest) (err error) {
+ logger := log.WithFunc("Boar.create").WithField("guest", vg.ID)
+ logger.Debugf(ctx, "starting to cache image")
+ if err := vg.CacheImage(&svc.imageMutex); err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ logger.Debug(ctx, "creating network")
+ if err = vg.CreateNetwork(ctx); err != nil {
+ return err
+ }
+ logger.Debug(ctx, "preparing volumes")
+ if err = vg.PrepareVolumesForCreate(ctx); err != nil {
+ return err
+ }
+ logger.Debug(ctx, "defining guest")
+ if err = vg.DefineGuestForCreate(ctx); err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ return nil
+}
diff --git a/internal/service/boar/image.go b/internal/service/boar/image.go
new file mode 100644
index 0000000..1e9f2f9
--- /dev/null
+++ b/internal/service/boar/image.go
@@ -0,0 +1,109 @@
+package boar
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "regexp"
+ "strings"
+
+ "github.com/cockroachdb/errors"
+ vmiFact "github.com/yuyang0/vmimage/factory"
+ vmitypes "github.com/yuyang0/vmimage/types"
+)
+
+func (svc *Boar) PushImage(ctx context.Context, imgName string, force bool) (rc io.ReadCloser, err error) {
+ svc.imageMutex.Lock()
+ defer svc.imageMutex.Unlock()
+
+ img, err := vmiFact.NewImage(imgName)
+ if err != nil {
+ return nil, err
+ }
+ if rc, err = vmiFact.Push(ctx, img, force); err != nil {
+ err = errors.Wrap(err, "")
+ return
+ }
+ return
+}
+
+func (svc *Boar) RemoveImage(ctx context.Context, imageName string, force, prune bool) (removed []string, err error) { //nolint
+ defer logErr(err)
+
+ img, err := vmiFact.LoadImage(ctx, imageName)
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+
+ svc.imageMutex.Lock()
+ defer svc.imageMutex.Unlock()
+
+ if err = vmiFact.RemoveLocal(ctx, img); err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+
+ return []string{img.Fullname()}, nil
+}
+
+func (svc *Boar) ListImage(ctx context.Context, filter string) (ans []*vmitypes.Image, err error) {
+ defer logErr(err)
+
+ imgs, err := vmiFact.ListLocalImages(ctx, "")
+ if err != nil {
+ return nil, err
+ }
+
+ images := []*vmitypes.Image{}
+ if len(filter) < 1 {
+ images = imgs
+ } else {
+ var regExp *regexp.Regexp
+ filter = strings.ReplaceAll(filter, "*", ".*")
+ if regExp, err = regexp.Compile(fmt.Sprintf("%s%s%s", "^", filter, "$")); err != nil {
+ return nil, err
+ }
+
+ for _, img := range imgs {
+ if regExp.MatchString(img.Fullname()) {
+ images = append(images, img)
+ }
+ }
+ }
+
+ return images, err
+}
+
+func (svc *Boar) PullImage(ctx context.Context, imgName string) (img *vmitypes.Image, rc io.ReadCloser, err error) {
+ svc.imageMutex.Lock()
+ defer svc.imageMutex.Unlock()
+
+ img, err = vmiFact.NewImage(imgName)
+ if err != nil {
+ err = errors.Wrap(err, "")
+ return
+ }
+ if rc, err = vmiFact.Pull(ctx, img, vmitypes.PullPolicyAlways); err != nil {
+ err = errors.Wrap(err, "")
+ return
+ }
+ return
+}
+
+func (svc *Boar) DigestImage(ctx context.Context, imageName string, local bool) (digest []string, err error) {
+ defer logErr(err)
+
+ if !local {
+ // TODO: wait for image-hub implementation and calico update
+ return []string{""}, nil
+ }
+
+ // If not exists return error
+ // If exists return digests
+
+ img, err := vmiFact.LoadImage(ctx, imageName)
+ if err != nil {
+ return nil, err
+ }
+
+ return []string{img.GetDigest()}, nil
+}
diff --git a/internal/service/boar/metrics.go b/internal/service/boar/metrics.go
new file mode 100644
index 0000000..e020fee
--- /dev/null
+++ b/internal/service/boar/metrics.go
@@ -0,0 +1,51 @@
+package boar
+
+import (
+ "sync/atomic"
+
+ "github.com/projecteru2/core/utils"
+ "github.com/projecteru2/yavirt/configs"
+ "github.com/prometheus/client_golang/prometheus"
+)
+
+var (
+ imageHubHealthyDesc = prometheus.NewDesc(
+ prometheus.BuildFQName("node", "image_hub", "healthy"),
+ "image hub healthy status.",
+ []string{"node"},
+ nil)
+ libvirtHealthyDesc = prometheus.NewDesc(
+ prometheus.BuildFQName("node", "libvirt", "healthy"),
+ "libvirt healthy status.",
+ []string{"node"},
+ nil)
+)
+
+type MetricsCollector struct {
+ imageHealthy atomic.Bool
+ libvirtHealthy atomic.Bool
+}
+
+func (d *Boar) GetMetricsCollector() prometheus.Collector {
+ return d.mCol
+}
+
+func (e *MetricsCollector) Describe(ch chan<- *prometheus.Desc) {
+ ch <- imageHubHealthyDesc
+ ch <- libvirtHealthyDesc
+}
+
+func (e *MetricsCollector) Collect(ch chan<- prometheus.Metric) {
+ ch <- prometheus.MustNewConstMetric(
+ imageHubHealthyDesc,
+ prometheus.GaugeValue,
+ float64(utils.Bool2Int(e.imageHealthy.Load())),
+ configs.Hostname(),
+ )
+ ch <- prometheus.MustNewConstMetric(
+ libvirtHealthyDesc,
+ prometheus.GaugeValue,
+ float64(utils.Bool2Int(e.libvirtHealthy.Load())),
+ configs.Hostname(),
+ )
+}
diff --git a/internal/service/boar/network.go b/internal/service/boar/network.go
new file mode 100644
index 0000000..f821f04
--- /dev/null
+++ b/internal/service/boar/network.go
@@ -0,0 +1,92 @@
+package boar
+
+import (
+ "context"
+
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/core/log"
+ "github.com/projecteru2/libyavirt/types"
+ "github.com/projecteru2/yavirt/internal/meta"
+ "github.com/projecteru2/yavirt/internal/metrics"
+ "github.com/projecteru2/yavirt/internal/network"
+ networkFactory "github.com/projecteru2/yavirt/internal/network/factory"
+ intertypes "github.com/projecteru2/yavirt/internal/types"
+ "github.com/projecteru2/yavirt/internal/virt/guest"
+
+ calihandler "github.com/projecteru2/yavirt/internal/network/drivers/calico"
+ vlanhandler "github.com/projecteru2/yavirt/internal/network/drivers/vlan"
+)
+
+// ConnectNetwork .
+func (svc *Boar) ConnectNetwork(ctx context.Context, id, network, ipv4 string) (cidr string, err error) {
+ var ip meta.IP
+
+ if err := svc.ctrl(ctx, id, intertypes.MiscOp, func(g *guest.Guest) (ce error) {
+ ip, ce = g.ConnectExtraNetwork(network, ipv4)
+ return ce
+ }, nil); err != nil {
+ log.WithFunc("boar.ConnectNetwork").Error(ctx, err)
+ metrics.IncrError()
+ return "", errors.Wrap(err, "")
+ }
+
+ return ip.CIDR(), nil
+}
+
+// DisconnectNetwork .
+func (svc *Boar) DisconnectNetwork(ctx context.Context, id, network string) (err error) {
+ err = svc.ctrl(ctx, id, intertypes.MiscOp, func(g *guest.Guest) error {
+ return g.DisconnectExtraNetwork(network)
+ }, nil)
+ if err != nil {
+ log.WithFunc("DisconnectNetwork").Error(ctx, err)
+ metrics.IncrError()
+ }
+ return
+}
+
+// NetworkList .
+func (svc *Boar) NetworkList(ctx context.Context, drivers []string) ([]*types.Network, error) {
+ drv := map[string]struct{}{}
+ for _, driver := range drivers {
+ drv[driver] = struct{}{}
+ }
+
+ networks := []*types.Network{}
+ for mode, hand := range networkFactory.ListDrivers() {
+ switch mode {
+ case network.CalicoMode:
+ if _, ok := drv[network.CalicoMode]; !ok {
+ break
+ }
+ caliHandler, ok := hand.(*calihandler.Driver)
+ if !ok {
+ break
+ }
+ for _, poolName := range caliHandler.PoolNames() {
+ subnet, err := caliHandler.GetIPPoolCidr(ctx, poolName)
+ if err != nil {
+ log.WithFunc("NetworkList").Error(ctx, err)
+ metrics.IncrError()
+ return nil, err
+ }
+
+ networks = append(networks, &types.Network{
+ Name: poolName,
+ Subnets: []string{subnet},
+ })
+ }
+ return networks, nil
+ case network.VlanMode: // vlan
+ if _, ok := drv[network.VlanMode]; !ok {
+ break
+ }
+ handler := vlanhandler.New(svc.Host.Subnet)
+ networks = append(networks, &types.Network{
+ Name: "vlan",
+ Subnets: []string{handler.GetCidr()},
+ })
+ }
+ }
+ return networks, nil
+}
diff --git a/internal/service/boar/operation.go b/internal/service/boar/operation.go
new file mode 100644
index 0000000..f0409a2
--- /dev/null
+++ b/internal/service/boar/operation.go
@@ -0,0 +1,108 @@
+package boar
+
+import (
+ "context"
+ "io"
+
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/core/log"
+ "github.com/projecteru2/libyavirt/types"
+ "github.com/projecteru2/yavirt/internal/metrics"
+ intertypes "github.com/projecteru2/yavirt/internal/types"
+ "github.com/projecteru2/yavirt/internal/virt/guest"
+ "github.com/projecteru2/yavirt/pkg/terrors"
+)
+
+// ResizeConsoleWindow .
+func (svc *Boar) ResizeConsoleWindow(ctx context.Context, id string, height, width uint) (err error) {
+ defer logErr(err)
+
+ g, err := svc.loadGuest(ctx, id)
+ if err != nil {
+ return errors.Wrap(err, "")
+ }
+ return g.ResizeConsoleWindow(ctx, height, width)
+}
+
+type executeResult struct {
+ output []byte
+ exitCode int
+ pid int
+}
+
+// ExecuteGuest .
+func (svc *Boar) ExecuteGuest(ctx context.Context, id string, commands []string) (_ *types.ExecuteGuestMessage, err error) {
+ defer logErr(err)
+
+ exec := func(ctx context.Context) (any, error) {
+ g, err := svc.loadGuest(ctx, id)
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ output, exitCode, pid, err := g.ExecuteCommand(ctx, commands)
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ return &executeResult{output: output, exitCode: exitCode, pid: pid}, nil
+ }
+
+ res, err := svc.do(ctx, id, intertypes.ExecuteOp, exec, nil)
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+
+ er, ok := res.(*executeResult)
+ if !ok {
+ return nil, errors.Wrapf(terrors.ErrInvalidValue, "expect *executeResult but it's %v", res)
+ }
+ svc.pid2ExitCode.Put(id, er.pid, er.exitCode)
+ return &types.ExecuteGuestMessage{
+ Pid: er.pid,
+ Data: er.output,
+ ExitCode: er.exitCode,
+ }, err
+}
+
+// ExecExitCode .
+func (svc *Boar) ExecExitCode(id string, pid int) (int, error) {
+ exitCode, err := svc.pid2ExitCode.Get(id, pid)
+ if err != nil {
+ log.WithFunc("ExecExitCode").Error(context.TODO(), err)
+ metrics.IncrError()
+ return 0, err
+ }
+ return exitCode, nil
+}
+
+// Cat .
+func (svc *Boar) Cat(ctx context.Context, id, path string, dest io.WriteCloser) (err error) {
+ defer logErr(err)
+
+ return svc.ctrl(ctx, id, intertypes.MiscOp, func(g *guest.Guest) error {
+ return g.Cat(ctx, path, dest)
+ }, nil)
+}
+
+// CopyToGuest .
+func (svc *Boar) CopyToGuest(ctx context.Context, id, dest string, content chan []byte, override bool) (err error) {
+ defer logErr(err)
+
+ return svc.ctrl(ctx, id, intertypes.MiscOp, func(g *guest.Guest) error {
+ return g.CopyToGuest(ctx, dest, content, override)
+ }, nil)
+}
+
+// Log .
+func (svc *Boar) Log(ctx context.Context, id, logPath string, n int, dest io.WriteCloser) (err error) {
+ defer logErr(err)
+
+ return svc.ctrl(ctx, id, intertypes.MiscOp, func(g *guest.Guest) error {
+ if g.LambdaOption == nil {
+ return g.Log(ctx, n, logPath, dest)
+ }
+
+ defer dest.Close()
+ _, err := dest.Write(g.LambdaOption.CmdOutput)
+ return err
+ }, nil)
+}
diff --git a/internal/service/boar/raw_engine.go b/internal/service/boar/raw_engine.go
new file mode 100644
index 0000000..e170131
--- /dev/null
+++ b/internal/service/boar/raw_engine.go
@@ -0,0 +1,201 @@
+package boar
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/core/log"
+ "github.com/projecteru2/libyavirt/types"
+ "github.com/projecteru2/yavirt/internal/meta"
+ intertypes "github.com/projecteru2/yavirt/internal/types"
+ "github.com/projecteru2/yavirt/internal/vmcache"
+ volFact "github.com/projecteru2/yavirt/internal/volume/factory"
+ vmiFact "github.com/yuyang0/vmimage/factory"
+)
+
+type VMParams struct {
+ DeviceName string `json:"device_name"`
+}
+
+func (svc *Boar) RawEngine(ctx context.Context, id string, req types.RawEngineReq) (types.RawEngineResp, error) {
+ switch req.Op {
+ case "vm-get-vnc-port":
+ return svc.getVNCPort(ctx, id)
+ case "vm-init-sys-disk":
+ return svc.InitSysDisk(ctx, id, req.Params)
+ case "vm-fs-freeze-all":
+ return svc.fsFreezeAll(ctx, id)
+ case "vm-fs-thaw-all":
+ return svc.fsThawAll(ctx, id)
+ case "vm-list-vols", "vm-list-vol", "vm-list-volume", "vm-list-volumes":
+ return svc.listVolumes(ctx, id)
+ case "vm-fs-freeze-status":
+ return svc.fsFreezeStatus(ctx, id)
+ default:
+ return types.RawEngineResp{}, errors.Errorf("invalid operation %s", req.Op)
+ }
+}
+
+func (svc *Boar) getVNCPort(_ context.Context, id string) (types.RawEngineResp, error) {
+ entry := vmcache.FetchDomainEntry(id)
+ var port int
+ if entry != nil {
+ port = entry.VNCPort
+ }
+ obj := map[string]int{
+ "port": port,
+ }
+ bs, _ := json.Marshal(obj)
+ resp := types.RawEngineResp{
+ Data: bs,
+ }
+ return resp, nil
+}
+
+type VolItem struct {
+ Name string `json:"name"`
+ Size int64 `json:"size"`
+ Device string `json:"device"`
+}
+
+func guestVolumes2VolItemList(vols volFact.Volumes) []VolItem {
+ if len(vols) == 0 {
+ return nil
+ }
+ volItemList := make([]VolItem, 0)
+ for _, item := range vols {
+ volItem := VolItem{
+ Name: item.Name(),
+ Size: item.GetSize(),
+ Device: item.GetDevice(),
+ }
+ volItemList = append(volItemList, volItem)
+ }
+ return volItemList
+}
+
+func (svc *Boar) listVolumes(ctx context.Context, id string) (types.RawEngineResp, error) {
+ g, err := svc.loadGuest(ctx, id)
+ if err != nil {
+ return types.RawEngineResp{}, errors.Wrap(err, "")
+ }
+
+ volItemList := guestVolumes2VolItemList(g.Vols)
+ if volItemList == nil {
+ return types.RawEngineResp{}, nil
+ }
+
+ bs, _ := json.Marshal(volItemList)
+ resp := types.RawEngineResp{
+ Data: bs,
+ }
+ return resp, nil
+}
+
+func (svc *Boar) fsFreezeAll(ctx context.Context, id string) (types.RawEngineResp, error) {
+ do := func(ctx context.Context) (any, error) {
+ g, err := svc.loadGuest(ctx, id)
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ if nFS, err := g.FSFreezeAll(ctx); err != nil {
+ return nil, errors.Wrap(err, "")
+ } else { //nolint
+ return nFS, nil
+ }
+ }
+ nFSRaw, err := svc.do(ctx, id, intertypes.FSThawOP, do, nil)
+ if err != nil {
+ return types.RawEngineResp{}, errors.Wrap(err, "")
+ }
+ nFS, _ := nFSRaw.(int)
+ return types.RawEngineResp{
+ Data: []byte(fmt.Sprintf(`{"fs_count": %d}`, nFS)),
+ }, nil
+}
+
+func (svc *Boar) fsThawAll(ctx context.Context, id string) (types.RawEngineResp, error) {
+ do := func(ctx context.Context) (any, error) {
+ g, err := svc.loadGuest(ctx, id)
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ if nFS, err := g.FSThawAll(ctx); err != nil {
+ return nil, errors.Wrap(err, "")
+ } else { //nolint
+ return nFS, nil
+ }
+ }
+ nFSRaw, err := svc.do(ctx, id, intertypes.FSThawOP, do, nil)
+ if err != nil {
+ return types.RawEngineResp{}, errors.Wrap(err, "")
+ }
+ nFS, _ := nFSRaw.(int)
+ return types.RawEngineResp{
+ Data: []byte(fmt.Sprintf(`{"fs_count": %d}`, nFS)),
+ }, nil
+}
+
+func (svc *Boar) fsFreezeStatus(ctx context.Context, id string) (types.RawEngineResp, error) {
+ g, err := svc.loadGuest(ctx, id)
+ if err != nil {
+ return types.RawEngineResp{}, errors.Wrap(err, "")
+ }
+ status, err := g.FSFreezeStatus(ctx)
+ if err != nil {
+ return types.RawEngineResp{}, errors.Wrap(err, "")
+ }
+ return types.RawEngineResp{
+ Data: []byte(fmt.Sprintf(`{"status": "%s"}`, status)),
+ }, nil
+}
+
+func (svc *Boar) InitSysDisk(ctx context.Context, id string, rawParams []byte) (types.RawEngineResp, error) {
+ logger := log.WithFunc("boar.InitSysDisk")
+ args := &intertypes.InitSysDiskArgs{}
+ if err := json.Unmarshal(rawParams, args); err != nil {
+ return types.RawEngineResp{}, errors.Wrapf(err, "failed to unmarshal params")
+ }
+ logger.Infof(ctx, "[InitSysDisk] params: %v", args)
+ // prepare image
+ img, err := vmiFact.LoadImage(ctx, args.Image)
+ if err != nil {
+ return types.RawEngineResp{}, errors.Wrapf(err, "failed to load image %s", args.Image)
+ }
+ vols, err := extractVols(args.Resources)
+ if err != nil {
+ return types.RawEngineResp{}, errors.Wrapf(err, "failed to extract new sys volume")
+ }
+ if len(vols) != 1 || (!vols[0].IsSys()) {
+ return types.RawEngineResp{}, errors.Wrapf(err, "need a new sys volume, but gives %v", vols[0])
+ }
+ newSysVol := vols[0]
+ do := func(ctx context.Context) (any, error) {
+ g, err := svc.loadGuest(ctx, id)
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ if g.Status != meta.StatusStopped {
+ return nil, errors.Newf("guest should in stopped state")
+ }
+
+ if err := g.InitSysDisk(ctx, img, args, newSysVol); err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ if err := g.Start(ctx, true); err != nil {
+ return nil, errors.Wrapf(err, "failed to start guest %s", g.ID)
+ }
+
+ return nil, nil //nolint
+ }
+ if _, err := svc.do(ctx, id, intertypes.StopOp, do, nil); err != nil {
+ return types.RawEngineResp{}, errors.Wrap(err, "")
+ }
+ msg := `{"success":true}`
+ resp := types.RawEngineResp{
+ Data: []byte(msg),
+ }
+ return resp, nil
+}
diff --git a/internal/service/boar/snapshot.go b/internal/service/boar/snapshot.go
new file mode 100644
index 0000000..5dab545
--- /dev/null
+++ b/internal/service/boar/snapshot.go
@@ -0,0 +1,224 @@
+package boar
+
+import (
+ "context"
+
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/core/log"
+ "github.com/projecteru2/libyavirt/types"
+ "github.com/projecteru2/yavirt/configs"
+ "github.com/projecteru2/yavirt/internal/meta"
+ "github.com/projecteru2/yavirt/internal/metrics"
+ "github.com/projecteru2/yavirt/internal/models"
+ intertypes "github.com/projecteru2/yavirt/internal/types"
+ "github.com/projecteru2/yavirt/internal/virt/guest"
+ "github.com/robfig/cron/v3"
+)
+
+// ListSnapshot .
+func (svc *Boar) ListSnapshot(ctx context.Context, req types.ListSnapshotReq) (snaps types.Snapshots, err error) {
+ defer logErr(err)
+
+ g, err := svc.loadGuest(ctx, req.ID)
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+
+ volSnap, err := g.ListSnapshot(req.VolID)
+
+ for vol, s := range volSnap {
+ for _, snap := range s {
+ snaps = append(snaps, &types.Snapshot{
+ VolID: vol.GetID(),
+ VolMountDir: vol.GetMountDir(),
+ SnapID: snap.GetID(),
+ CreatedTime: snap.GetCreatedTime(),
+ })
+ }
+ }
+
+ return
+}
+
+// CreateSnapshot .
+func (svc *Boar) CreateSnapshot(ctx context.Context, req types.CreateSnapshotReq) (err error) {
+ defer logErr(err)
+ volID := req.VolID
+
+ return svc.ctrl(ctx, req.ID, intertypes.CreateSnapshotOp, func(g *guest.Guest) error {
+ suspended := false
+ stopped := false
+ if g.Status == meta.StatusRunning {
+ if err := g.Suspend(); err != nil {
+ return err
+ }
+ suspended = true
+ }
+
+ if err := g.CreateSnapshot(volID); err != nil {
+ return err
+ }
+
+ if err := g.CheckVolume(volID); err != nil {
+
+ if suspended {
+ if err := g.Stop(ctx, true); err != nil {
+ return err
+ }
+ suspended = false
+ stopped = true
+ }
+
+ if err := g.RepairVolume(volID); err != nil {
+ return err
+ }
+ }
+
+ if suspended {
+ return g.Resume()
+ } else if stopped {
+ return g.Start(ctx, false)
+ }
+ return nil
+ }, nil)
+}
+
+// CommitSnapshot .
+func (svc *Boar) CommitSnapshot(ctx context.Context, req types.CommitSnapshotReq) (err error) {
+ defer logErr(err)
+
+ return svc.ctrl(ctx, req.ID, intertypes.CommitSnapshotOp, func(g *guest.Guest) error {
+ stopped := false
+ if g.Status == meta.StatusRunning {
+ if err := g.Stop(ctx, true); err != nil {
+ return err
+ }
+ stopped = true
+ }
+
+ if err := g.CommitSnapshot(req.VolID, req.SnapID); err != nil {
+ return err
+ }
+
+ if stopped {
+ return g.Start(ctx, false)
+ }
+ return nil
+ }, nil)
+}
+
+// CommitSnapshotByDay .
+func (svc *Boar) CommitSnapshotByDay(ctx context.Context, id, volID string, day int) (err error) {
+ defer logErr(err)
+
+ return svc.ctrl(ctx, id, intertypes.CommitSnapshotOp, func(g *guest.Guest) error {
+ stopped := false
+ if g.Status == meta.StatusRunning {
+ if err := g.Stop(ctx, true); err != nil {
+ return err
+ }
+ stopped = true
+ }
+
+ if err := g.CommitSnapshotByDay(volID, day); err != nil {
+ return err
+ }
+
+ if stopped {
+ return g.Start(ctx, false)
+ }
+ return nil
+ }, nil)
+}
+
+// RestoreSnapshot .
+func (svc *Boar) RestoreSnapshot(ctx context.Context, req types.RestoreSnapshotReq) (err error) {
+ defer logErr(err)
+
+ return svc.ctrl(ctx, req.ID, intertypes.RestoreSnapshotOp, func(g *guest.Guest) error {
+ stopped := false
+ if g.Status == meta.StatusRunning {
+ if err := g.Stop(ctx, true); err != nil {
+ return err
+ }
+ stopped = true
+ }
+
+ if err := g.RestoreSnapshot(req.VolID, req.SnapID); err != nil {
+ return err
+ }
+
+ if stopped {
+ return g.Start(ctx, false)
+ }
+ return nil
+ }, nil)
+}
+
+// TODO: Decide time
+func (svc *Boar) ScheduleSnapshotCreate() error {
+ c := cron.New()
+
+ // Everyday 3am
+ if _, err := c.AddFunc("0 3 * * *", svc.batchCreateSnapshot); err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ // Every Sunday 1am
+ if _, err := c.AddFunc("0 1 * * SUN", svc.batchCommitSnapshot); err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ // Start job asynchronously
+ c.Start()
+
+ return nil
+}
+
+func (svc *Boar) batchCreateSnapshot() {
+ logger := log.WithFunc("Boar.batchCreateSnapshot")
+ guests, err := models.GetAllGuests()
+ if err != nil {
+ logger.Error(context.TODO(), err)
+ metrics.IncrError()
+ return
+ }
+
+ for _, g := range guests {
+ for _, volID := range g.VolIDs {
+ req := types.CreateSnapshotReq{
+ ID: g.ID,
+ VolID: volID,
+ }
+
+ if err := svc.CreateSnapshot(context.TODO(), req); err != nil {
+ logger.Error(context.TODO(), err)
+ metrics.IncrError()
+ }
+ }
+ }
+}
+
+func (svc *Boar) batchCommitSnapshot() {
+ logger := log.WithFunc("Boar.batchCommitSnapshot")
+ guests, err := models.GetAllGuests()
+ if err != nil {
+ logger.Error(context.TODO(), err)
+ metrics.IncrError()
+ return
+ }
+
+ for _, g := range guests {
+ for _, volID := range g.VolIDs {
+ if err := svc.CommitSnapshotByDay(
+ context.TODO(),
+ g.ID,
+ volID,
+ configs.Conf.SnapshotRestorableDay,
+ ); err != nil {
+ logger.Error(context.TODO(), err)
+ metrics.IncrError()
+ }
+ }
+ }
+}
diff --git a/internal/service/boar/task.go b/internal/service/boar/task.go
new file mode 100644
index 0000000..7354e4a
--- /dev/null
+++ b/internal/service/boar/task.go
@@ -0,0 +1,215 @@
+package boar
+
+import (
+ "context"
+ "fmt"
+ "sync"
+
+ llq "github.com/emirpasic/gods/queues/linkedlistqueue"
+ "github.com/panjf2000/ants/v2"
+ "github.com/projecteru2/core/log"
+ "github.com/projecteru2/yavirt/internal/types"
+)
+
+type taskNotifier struct {
+ id string
+ err error
+}
+
+type task struct {
+ mu sync.Mutex
+
+ id string
+ op types.Operator
+ ctx context.Context
+ do func(context.Context) (any, error)
+ res any
+ err error
+ done struct {
+ once sync.Once
+ c chan struct{}
+ }
+}
+
+func newTask(ctx context.Context, id string, op types.Operator, fn doFunc) *task {
+ t := &task{
+ id: id,
+ op: op,
+ ctx: ctx,
+ do: fn,
+ }
+ t.done.c = make(chan struct{})
+ return t
+}
+
+// String .
+func (t *task) String() string {
+ return fmt.Sprintf("%s <%s>", t.id, t.op)
+}
+
+func (t *task) Done() <-chan struct{} {
+ return t.done.c
+}
+
+func (t *task) run(ctx context.Context) error {
+ defer t.finish()
+
+ var (
+ res any
+ err error
+ )
+
+ select {
+ case <-ctx.Done():
+ err = ctx.Err()
+ default:
+ res, err = t.do(ctx)
+ }
+ t.setResult(res, err)
+ return err
+}
+
+func (t *task) finish() {
+ t.done.once.Do(func() {
+ close(t.done.c)
+ })
+}
+
+func (t *task) result() (any, error) {
+ t.mu.Lock()
+ defer t.mu.Unlock()
+ return t.res, t.err
+}
+
+func (t *task) setResult(res any, err error) {
+ t.mu.Lock()
+ defer t.mu.Unlock()
+
+ t.res, t.err = res, err
+}
+
+// all tasks in a task queue have same guest id.
+type taskQueue struct {
+ *llq.Queue
+ id string
+}
+
+func newTaskQueue(id string) *taskQueue {
+ return &taskQueue{
+ Queue: llq.New(),
+ id: id,
+ }
+}
+
+func (tq *taskQueue) revertAll(err error) {
+ for {
+ obj, ok := tq.Dequeue()
+ if !ok {
+ break
+ }
+ t, _ := obj.(*task)
+ t.finish()
+ t.setResult(nil, err)
+
+ }
+}
+
+type taskPool struct {
+ mu sync.Mutex
+ // pool size
+ size int
+ // key is guest id
+ mgr map[string]*taskQueue
+ pool *ants.Pool
+ notifier chan taskNotifier
+}
+
+func newTaskPool(max int) (*taskPool, error) {
+ p, err := ants.NewPool(max, ants.WithNonblocking(true))
+ if err != nil {
+ return nil, err
+ }
+ tp := &taskPool{
+ size: max,
+ pool: p,
+ mgr: make(map[string]*taskQueue),
+ notifier: make(chan taskNotifier, 10),
+ }
+ go tp.loop()
+ return tp, nil
+}
+
+func (p *taskPool) SubmitTask(t *task) (err error) {
+ needNotify := false
+ err = p.withLocker(func() error {
+ if _, ok := p.mgr[t.id]; !ok {
+ if p.size > 0 && len(p.mgr) >= p.size {
+ return fmt.Errorf("task pool is full")
+ }
+ p.mgr[t.id] = newTaskQueue(t.id)
+ needNotify = true
+ }
+ p.mgr[t.id].Enqueue(t)
+ return nil
+ })
+ if err != nil {
+ return err
+ }
+ if needNotify {
+ p.notifier <- taskNotifier{
+ id: t.id,
+ err: nil,
+ }
+ }
+ return
+}
+
+func (p *taskPool) loop() {
+ logger := log.WithFunc("taskPool.loop")
+ for v := range p.notifier {
+ var t *task
+ _ = p.withLocker(func() error {
+ if v.err != nil {
+ // when error, revert all tasks in the same queue
+ tq := p.mgr[v.id]
+ tq.revertAll(v.err)
+ }
+ tq := p.mgr[v.id]
+ if tq.Empty() {
+ delete(p.mgr, v.id)
+ return nil
+ }
+ obj, _ := tq.Dequeue()
+ t, _ = obj.(*task)
+ return nil
+ })
+
+ if t == nil {
+ continue
+ }
+ err := p.pool.Submit(func() {
+ if err := t.run(t.ctx); err != nil {
+ logger.Error(context.TODO(), err)
+ }
+ _, err := t.result()
+ p.notifier <- taskNotifier{
+ id: t.id,
+ err: err,
+ }
+ })
+ if err != nil {
+ // the pool is full, it never happens, because when submitting task, the size is already checked
+ logger.Errorf(context.TODO(), err, "BUG: failed to submit task<%s> %s", t.id, err)
+ }
+ }
+}
+
+func (p *taskPool) withLocker(f func() error) error {
+ p.mu.Lock()
+ defer p.mu.Unlock()
+ return f()
+}
+
+func (p *taskPool) Release() {
+ p.pool.Release()
+}
diff --git a/internal/service/boar/task_test.go b/internal/service/boar/task_test.go
new file mode 100644
index 0000000..741873b
--- /dev/null
+++ b/internal/service/boar/task_test.go
@@ -0,0 +1,183 @@
+package boar
+
+import (
+ "context"
+ "fmt"
+ "sync/atomic"
+ "testing"
+ "time"
+
+ "github.com/projecteru2/libyavirt/types"
+ "github.com/projecteru2/yavirt/pkg/test/assert"
+)
+
+func TestTask(t *testing.T) {
+ var counter int32
+ timeout := 3 * time.Second
+ start := time.Now()
+ p, err := newTaskPool(100)
+ assert.Nil(t, err)
+ tsk := newTask(context.Background(), "test", types.OpStart, func(ctx context.Context) (any, error) {
+ atomic.AddInt32(&counter, 1)
+ time.Sleep(timeout)
+ return nil, nil
+ })
+ p.SubmitTask(tsk)
+ <-tsk.Done()
+ assert.Equal(t, int32(1), atomic.LoadInt32(&counter))
+ assert.True(t, time.Since(start) > timeout)
+ assert.True(t, time.Since(start) < timeout+3*time.Second)
+}
+
+func TestSingleTypeTask(t *testing.T) {
+ var counter int32
+ timeout := 3 * time.Second
+ nTasks := 4
+ tasks := make([]*task, nTasks)
+ start := time.Now()
+ p, err := newTaskPool(100)
+ assert.Nil(t, err)
+
+ for i := 0; i < nTasks; i++ {
+ tsk := newTask(context.Background(), "test", types.OpStart, func(ctx context.Context) (any, error) {
+ atomic.AddInt32(&counter, 1)
+ time.Sleep(timeout)
+ return nil, nil
+ })
+ p.SubmitTask(tsk)
+ tasks[i] = tsk
+ }
+ for i := 0; i < nTasks; i++ {
+ <-tasks[i].Done()
+ }
+ assert.Equal(t, int32(nTasks), atomic.LoadInt32(&counter))
+ assert.True(t, time.Since(start) > timeout*time.Duration(nTasks))
+ assert.True(t, time.Since(start) < timeout*time.Duration(nTasks)+3*time.Second)
+}
+
+func TestSingleTypeTaskSeq(t *testing.T) {
+ var counter int32
+ timeout := 3 * time.Second
+ nTasks := 4
+ tasks := make([]*task, nTasks)
+ start := time.Now()
+ p, err := newTaskPool(100)
+ assert.Nil(t, err)
+
+ for i := 0; i < nTasks; i++ {
+ tsk := newTask(context.Background(), "test", types.OpStart, func(ctx context.Context) (any, error) {
+ atomic.AddInt32(&counter, 1)
+ time.Sleep(timeout)
+ return nil, nil
+ })
+ p.SubmitTask(tsk)
+ tasks[i] = tsk
+ <-tasks[i].Done()
+ }
+ assert.Equal(t, int32(nTasks), atomic.LoadInt32(&counter))
+ assert.True(t, time.Since(start) > timeout*time.Duration(nTasks))
+ assert.True(t, time.Since(start) < timeout*time.Duration(nTasks)+3*time.Second)
+}
+
+func TestSingleTypeFailedTask(t *testing.T) {
+ var counter int32
+ timeout := 3 * time.Second
+ nTasks := 3
+ nFailed := 4
+ tasks := make([]*task, nTasks+nFailed)
+ start := time.Now()
+ p, err := newTaskPool(100)
+ assert.Nil(t, err)
+
+ for i := 0; i < nTasks; i++ {
+ tsk := newTask(context.Background(), "test", types.OpStart, func(ctx context.Context) (any, error) {
+ atomic.AddInt32(&counter, 1)
+ time.Sleep(timeout)
+ return nil, nil
+ })
+ p.SubmitTask(tsk)
+ tasks[i] = tsk
+ }
+
+ for i := 0; i < nFailed; i++ {
+ tsk := newTask(context.Background(), "test", types.OpStart, func(ctx context.Context) (any, error) {
+ atomic.AddInt32(&counter, 1)
+ return nil, fmt.Errorf("failed")
+ })
+ p.SubmitTask(tsk)
+ tasks[i+nTasks] = tsk
+ }
+ for i := 0; i < len(tasks); i++ {
+ <-tasks[i].Done()
+ _, err := tasks[i].result()
+ if i < nTasks {
+ assert.Nil(t, err)
+ } else {
+ assert.NotNil(t, err)
+ }
+ }
+ assert.Equal(t, int32(nTasks+1), atomic.LoadInt32(&counter))
+ assert.True(t, time.Since(start) > timeout*time.Duration(nTasks))
+ assert.True(t, time.Since(start) < timeout*time.Duration(nTasks)+3*time.Second)
+}
+
+func TestMultiTypeTask(t *testing.T) {
+ var counter int32
+ timeout := 3 * time.Second
+ nTasks := 4
+ tasks := make([]*task, nTasks)
+ start := time.Now()
+ p, err := newTaskPool(100)
+ assert.Nil(t, err)
+
+ for i := 0; i < nTasks; i++ {
+ id := fmt.Sprintf("test%d", i)
+ tsk := newTask(context.Background(), id, types.OpStart, func(ctx context.Context) (any, error) {
+ atomic.AddInt32(&counter, 1)
+ time.Sleep(timeout)
+ return nil, nil
+ })
+ p.SubmitTask(tsk)
+ tasks[i] = tsk
+ }
+ for i := 0; i < nTasks; i++ {
+ <-tasks[i].Done()
+ }
+ assert.Equal(t, int32(nTasks), atomic.LoadInt32(&counter))
+ assert.True(t, time.Since(start) > timeout)
+ assert.True(t, time.Since(start) < timeout+3*time.Second)
+}
+
+func TestSmallPool(t *testing.T) {
+ var counter int32
+ poolSize := 2
+ timeout := 3 * time.Second
+ nTasks := 4
+ tasks := make([]*task, nTasks)
+ start := time.Now()
+ p, err := newTaskPool(poolSize)
+ assert.Nil(t, err)
+
+ for i := 0; i < nTasks; i++ {
+ id := fmt.Sprintf("test%d", i)
+ tsk := newTask(context.Background(), id, types.OpStart, func(ctx context.Context) (any, error) {
+ atomic.AddInt32(&counter, 1)
+ time.Sleep(timeout)
+ return nil, nil
+ })
+ err := p.SubmitTask(tsk)
+ if i < poolSize {
+ assert.Nil(t, err)
+ } else {
+ assert.NotNil(t, err)
+ tsk.finish()
+ }
+ tasks[i] = tsk
+ }
+ for i := 0; i < nTasks; i++ {
+ <-tasks[i].Done()
+ }
+ assert.Equal(t, int32(poolSize), atomic.LoadInt32(&counter))
+ assert.True(t, time.Since(start) > timeout)
+ assert.True(t, time.Since(start) < timeout+3*time.Second)
+}
diff --git a/internal/service/boar/util.go b/internal/service/boar/util.go
new file mode 100644
index 0000000..d5d3f57
--- /dev/null
+++ b/internal/service/boar/util.go
@@ -0,0 +1,145 @@
+package boar
+
+import (
+ "encoding/json"
+
+ "strings"
+
+ pb "github.com/projecteru2/core/rpc/gen"
+
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/libyavirt/types"
+ "github.com/projecteru2/yavirt/internal/meta"
+ "github.com/projecteru2/yavirt/internal/models"
+ intertypes "github.com/projecteru2/yavirt/internal/types"
+ "github.com/projecteru2/yavirt/internal/volume"
+ "github.com/projecteru2/yavirt/internal/volume/local"
+ "github.com/projecteru2/yavirt/internal/volume/rbd"
+
+ cpumemtypes "github.com/projecteru2/core/resource/plugins/cpumem/types"
+ stotypes "github.com/projecteru2/resource-storage/storage/types"
+ gputypes "github.com/yuyang0/resource-gpu/gpu/types"
+ rbdtypes "github.com/yuyang0/resource-rbd/rbd/types"
+)
+
+func extractCPUMem(resources map[string][]byte) (eParams *cpumemtypes.EngineParams, err error) {
+ cpumemRaw, ok := resources[intertypes.PluginNameCPUMem]
+ if !ok {
+ return nil, nil //nolint
+ }
+ var ans cpumemtypes.EngineParams
+ err = json.Unmarshal(cpumemRaw, &ans)
+ return &ans, err
+}
+
+func extractGPU(resources map[string][]byte) (eParams *gputypes.EngineParams, err error) {
+ gpuRaw, ok := resources[intertypes.PluginNameGPU]
+ if !ok {
+ return nil, nil //nolint
+ }
+ var ans gputypes.EngineParams
+ err = json.Unmarshal(gpuRaw, &ans)
+ return &ans, err
+}
+
+func extractVols(resources map[string][]byte) ([]volume.Volume, error) {
+ var sysVol volume.Volume
+ vols := make([]volume.Volume, 1) // first place is for sys volume
+ appendVol := func(vol volume.Volume) error {
+ if vol.IsSys() {
+ if sysVol != nil {
+ return errors.New("multiple sys volume")
+ }
+ sysVol = vol
+ return nil
+ }
+ vols = append(vols, vol) //nolint
+ return nil
+ }
+
+ stoResRaw, ok := resources[intertypes.PluginNameStorage]
+ if ok {
+ eParams := &stotypes.EngineParams{}
+ if err := json.Unmarshal(stoResRaw, eParams); err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ for _, part := range eParams.Volumes {
+ vol, err := local.NewVolumeFromStr(part)
+ if err != nil {
+ return nil, err
+ }
+ if err := appendVol(vol); err != nil {
+ return nil, err
+ }
+ }
+ }
+ rbdResRaw, ok := resources[intertypes.PluginNameRBD]
+ if ok {
+ eParams := &rbdtypes.EngineParams{}
+ if err := json.Unmarshal(rbdResRaw, eParams); err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ for _, part := range eParams.Volumes {
+ vol, err := rbd.NewFromStr(part)
+ if err != nil {
+ return nil, err
+ }
+ if err := appendVol(vol); err != nil {
+ return nil, err
+ }
+ }
+ }
+ if sysVol != nil {
+ vols[0] = sysVol
+ } else {
+ vols = vols[1:]
+ }
+ return vols, nil
+}
+
+func convGuestResp(g *models.Guest) (resp *types.Guest) {
+ resp = &types.Guest{}
+ resp.ID = g.ID
+ resp.Hostname = g.HostName
+ resp.Status = g.Status
+ resp.CreateTime = g.CreatedTime
+ resp.UpdateTime = g.UpdatedTime
+ resp.ImageName = g.ImageName
+ resp.CPU = g.CPU
+ resp.Mem = g.Memory
+ resp.Labels = g.JSONLabels
+ resp.Running = (g.Status == meta.StatusRunning)
+
+ if len(g.IPs) > 0 {
+ var ips = make([]string, len(g.IPs))
+ for i, ip := range g.IPs {
+ ips[i] = ip.IPAddr()
+ }
+ resp.IPs = ips
+ resp.Networks = map[string]string{"IP": strings.Join(ips, ", ")}
+ }
+
+ return
+}
+
+// ConvSetWorkloadsStatusOptions .
+func ConvSetWorkloadsStatusOptions(gss []types.EruGuestStatus) *pb.SetWorkloadsStatusOptions {
+ css := make([]*pb.WorkloadStatus, len(gss))
+ for i, gs := range gss {
+ css[i] = convWorkloadStatus(gs)
+ }
+
+ return &pb.SetWorkloadsStatusOptions{
+ Status: css,
+ }
+}
+
+func convWorkloadStatus(gs types.EruGuestStatus) *pb.WorkloadStatus {
+ return &pb.WorkloadStatus{
+ Id: gs.EruGuestID,
+ Running: gs.Running,
+ Healthy: gs.Healthy,
+ Ttl: int64(gs.TTL.Seconds()),
+ Networks: map[string]string{"IP": gs.GetIPAddrs()},
+ }
+}
diff --git a/internal/service/mocks/Service.go b/internal/service/mocks/Service.go
new file mode 100644
index 0000000..fc55029
--- /dev/null
+++ b/internal/service/mocks/Service.go
@@ -0,0 +1,866 @@
+// Code generated by mockery v2.42.0. DO NOT EDIT.
+
+package mocks
+
+import (
+ context "context"
+ io "io"
+
+ libyavirttypes "github.com/projecteru2/libyavirt/types"
+ mock "github.com/stretchr/testify/mock"
+
+ types "github.com/projecteru2/yavirt/internal/types"
+
+ utils "github.com/projecteru2/yavirt/internal/utils"
+
+ vmimagetypes "github.com/yuyang0/vmimage/types"
+)
+
+// Service is an autogenerated mock type for the Service type
+type Service struct {
+ mock.Mock
+}
+
+// AttachGuest provides a mock function with given fields: ctx, id, stream, flags
+func (_m *Service) AttachGuest(ctx context.Context, id string, stream io.ReadWriteCloser, flags types.OpenConsoleFlags) error {
+ ret := _m.Called(ctx, id, stream, flags)
+
+ if len(ret) == 0 {
+ panic("no return value specified for AttachGuest")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(context.Context, string, io.ReadWriteCloser, types.OpenConsoleFlags) error); ok {
+ r0 = rf(ctx, id, stream, flags)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// CaptureGuest provides a mock function with given fields: ctx, id, imgName, overridden
+func (_m *Service) CaptureGuest(ctx context.Context, id string, imgName string, overridden bool) (*vmimagetypes.Image, error) {
+ ret := _m.Called(ctx, id, imgName, overridden)
+
+ if len(ret) == 0 {
+ panic("no return value specified for CaptureGuest")
+ }
+
+ var r0 *vmimagetypes.Image
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, string, string, bool) (*vmimagetypes.Image, error)); ok {
+ return rf(ctx, id, imgName, overridden)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, string, string, bool) *vmimagetypes.Image); ok {
+ r0 = rf(ctx, id, imgName, overridden)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*vmimagetypes.Image)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, string, string, bool) error); ok {
+ r1 = rf(ctx, id, imgName, overridden)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// Cat provides a mock function with given fields: ctx, id, path, dest
+func (_m *Service) Cat(ctx context.Context, id string, path string, dest io.WriteCloser) error {
+ ret := _m.Called(ctx, id, path, dest)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Cat")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(context.Context, string, string, io.WriteCloser) error); ok {
+ r0 = rf(ctx, id, path, dest)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// CommitSnapshot provides a mock function with given fields: ctx, req
+func (_m *Service) CommitSnapshot(ctx context.Context, req libyavirttypes.CommitSnapshotReq) error {
+ ret := _m.Called(ctx, req)
+
+ if len(ret) == 0 {
+ panic("no return value specified for CommitSnapshot")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(context.Context, libyavirttypes.CommitSnapshotReq) error); ok {
+ r0 = rf(ctx, req)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// CommitSnapshotByDay provides a mock function with given fields: ctx, id, volID, day
+func (_m *Service) CommitSnapshotByDay(ctx context.Context, id string, volID string, day int) error {
+ ret := _m.Called(ctx, id, volID, day)
+
+ if len(ret) == 0 {
+ panic("no return value specified for CommitSnapshotByDay")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(context.Context, string, string, int) error); ok {
+ r0 = rf(ctx, id, volID, day)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// ConnectNetwork provides a mock function with given fields: ctx, id, network, ipv4
+func (_m *Service) ConnectNetwork(ctx context.Context, id string, network string, ipv4 string) (string, error) {
+ ret := _m.Called(ctx, id, network, ipv4)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ConnectNetwork")
+ }
+
+ var r0 string
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, string, string, string) (string, error)); ok {
+ return rf(ctx, id, network, ipv4)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, string, string, string) string); ok {
+ r0 = rf(ctx, id, network, ipv4)
+ } else {
+ r0 = ret.Get(0).(string)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, string, string, string) error); ok {
+ r1 = rf(ctx, id, network, ipv4)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ControlGuest provides a mock function with given fields: ctx, id, operation, force
+func (_m *Service) ControlGuest(ctx context.Context, id string, operation string, force bool) error {
+ ret := _m.Called(ctx, id, operation, force)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ControlGuest")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(context.Context, string, string, bool) error); ok {
+ r0 = rf(ctx, id, operation, force)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// CopyToGuest provides a mock function with given fields: ctx, id, dest, content, override
+func (_m *Service) CopyToGuest(ctx context.Context, id string, dest string, content chan []byte, override bool) error {
+ ret := _m.Called(ctx, id, dest, content, override)
+
+ if len(ret) == 0 {
+ panic("no return value specified for CopyToGuest")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(context.Context, string, string, chan []byte, bool) error); ok {
+ r0 = rf(ctx, id, dest, content, override)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// CreateGuest provides a mock function with given fields: ctx, opts
+func (_m *Service) CreateGuest(ctx context.Context, opts types.GuestCreateOption) (*libyavirttypes.Guest, error) {
+ ret := _m.Called(ctx, opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for CreateGuest")
+ }
+
+ var r0 *libyavirttypes.Guest
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, types.GuestCreateOption) (*libyavirttypes.Guest, error)); ok {
+ return rf(ctx, opts)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, types.GuestCreateOption) *libyavirttypes.Guest); ok {
+ r0 = rf(ctx, opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*libyavirttypes.Guest)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, types.GuestCreateOption) error); ok {
+ r1 = rf(ctx, opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CreateSnapshot provides a mock function with given fields: ctx, req
+func (_m *Service) CreateSnapshot(ctx context.Context, req libyavirttypes.CreateSnapshotReq) error {
+ ret := _m.Called(ctx, req)
+
+ if len(ret) == 0 {
+ panic("no return value specified for CreateSnapshot")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(context.Context, libyavirttypes.CreateSnapshotReq) error); ok {
+ r0 = rf(ctx, req)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// DigestImage provides a mock function with given fields: ctx, imageName, local
+func (_m *Service) DigestImage(ctx context.Context, imageName string, local bool) ([]string, error) {
+ ret := _m.Called(ctx, imageName, local)
+
+ if len(ret) == 0 {
+ panic("no return value specified for DigestImage")
+ }
+
+ var r0 []string
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, string, bool) ([]string, error)); ok {
+ return rf(ctx, imageName, local)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, string, bool) []string); ok {
+ r0 = rf(ctx, imageName, local)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]string)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, string, bool) error); ok {
+ r1 = rf(ctx, imageName, local)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// DisconnectNetwork provides a mock function with given fields: ctx, id, network
+func (_m *Service) DisconnectNetwork(ctx context.Context, id string, network string) error {
+ ret := _m.Called(ctx, id, network)
+
+ if len(ret) == 0 {
+ panic("no return value specified for DisconnectNetwork")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok {
+ r0 = rf(ctx, id, network)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// ExecExitCode provides a mock function with given fields: id, pid
+func (_m *Service) ExecExitCode(id string, pid int) (int, error) {
+ ret := _m.Called(id, pid)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ExecExitCode")
+ }
+
+ var r0 int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(string, int) (int, error)); ok {
+ return rf(id, pid)
+ }
+ if rf, ok := ret.Get(0).(func(string, int) int); ok {
+ r0 = rf(id, pid)
+ } else {
+ r0 = ret.Get(0).(int)
+ }
+
+ if rf, ok := ret.Get(1).(func(string, int) error); ok {
+ r1 = rf(id, pid)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ExecuteGuest provides a mock function with given fields: ctx, id, commands
+func (_m *Service) ExecuteGuest(ctx context.Context, id string, commands []string) (*libyavirttypes.ExecuteGuestMessage, error) {
+ ret := _m.Called(ctx, id, commands)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ExecuteGuest")
+ }
+
+ var r0 *libyavirttypes.ExecuteGuestMessage
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, string, []string) (*libyavirttypes.ExecuteGuestMessage, error)); ok {
+ return rf(ctx, id, commands)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, string, []string) *libyavirttypes.ExecuteGuestMessage); ok {
+ r0 = rf(ctx, id, commands)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*libyavirttypes.ExecuteGuestMessage)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, string, []string) error); ok {
+ r1 = rf(ctx, id, commands)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// GetGuest provides a mock function with given fields: ctx, id
+func (_m *Service) GetGuest(ctx context.Context, id string) (*libyavirttypes.Guest, error) {
+ ret := _m.Called(ctx, id)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetGuest")
+ }
+
+ var r0 *libyavirttypes.Guest
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, string) (*libyavirttypes.Guest, error)); ok {
+ return rf(ctx, id)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, string) *libyavirttypes.Guest); ok {
+ r0 = rf(ctx, id)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*libyavirttypes.Guest)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
+ r1 = rf(ctx, id)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// GetGuestIDList provides a mock function with given fields: ctx
+func (_m *Service) GetGuestIDList(ctx context.Context) ([]string, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetGuestIDList")
+ }
+
+ var r0 []string
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) ([]string, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) []string); ok {
+ r0 = rf(ctx)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]string)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// GetGuestUUID provides a mock function with given fields: ctx, id
+func (_m *Service) GetGuestUUID(ctx context.Context, id string) (string, error) {
+ ret := _m.Called(ctx, id)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetGuestUUID")
+ }
+
+ var r0 string
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, string) (string, error)); ok {
+ return rf(ctx, id)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, string) string); ok {
+ r0 = rf(ctx, id)
+ } else {
+ r0 = ret.Get(0).(string)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
+ r1 = rf(ctx, id)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// Info provides a mock function with given fields:
+func (_m *Service) Info() (*libyavirttypes.HostInfo, error) {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Info")
+ }
+
+ var r0 *libyavirttypes.HostInfo
+ var r1 error
+ if rf, ok := ret.Get(0).(func() (*libyavirttypes.HostInfo, error)); ok {
+ return rf()
+ }
+ if rf, ok := ret.Get(0).(func() *libyavirttypes.HostInfo); ok {
+ r0 = rf()
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*libyavirttypes.HostInfo)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func() error); ok {
+ r1 = rf()
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// IsHealthy provides a mock function with given fields: ctx
+func (_m *Service) IsHealthy(ctx context.Context) bool {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for IsHealthy")
+ }
+
+ var r0 bool
+ if rf, ok := ret.Get(0).(func(context.Context) bool); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Get(0).(bool)
+ }
+
+ return r0
+}
+
+// ListImage provides a mock function with given fields: ctx, filter
+func (_m *Service) ListImage(ctx context.Context, filter string) ([]*vmimagetypes.Image, error) {
+ ret := _m.Called(ctx, filter)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ListImage")
+ }
+
+ var r0 []*vmimagetypes.Image
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, string) ([]*vmimagetypes.Image, error)); ok {
+ return rf(ctx, filter)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, string) []*vmimagetypes.Image); ok {
+ r0 = rf(ctx, filter)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]*vmimagetypes.Image)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
+ r1 = rf(ctx, filter)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ListSnapshot provides a mock function with given fields: ctx, req
+func (_m *Service) ListSnapshot(ctx context.Context, req libyavirttypes.ListSnapshotReq) (libyavirttypes.Snapshots, error) {
+ ret := _m.Called(ctx, req)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ListSnapshot")
+ }
+
+ var r0 libyavirttypes.Snapshots
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, libyavirttypes.ListSnapshotReq) (libyavirttypes.Snapshots, error)); ok {
+ return rf(ctx, req)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, libyavirttypes.ListSnapshotReq) libyavirttypes.Snapshots); ok {
+ r0 = rf(ctx, req)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(libyavirttypes.Snapshots)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, libyavirttypes.ListSnapshotReq) error); ok {
+ r1 = rf(ctx, req)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// Log provides a mock function with given fields: ctx, id, logPath, n, dest
+func (_m *Service) Log(ctx context.Context, id string, logPath string, n int, dest io.WriteCloser) error {
+ ret := _m.Called(ctx, id, logPath, n, dest)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Log")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(context.Context, string, string, int, io.WriteCloser) error); ok {
+ r0 = rf(ctx, id, logPath, n, dest)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// NetworkList provides a mock function with given fields: ctx, drivers
+func (_m *Service) NetworkList(ctx context.Context, drivers []string) ([]*libyavirttypes.Network, error) {
+ ret := _m.Called(ctx, drivers)
+
+ if len(ret) == 0 {
+ panic("no return value specified for NetworkList")
+ }
+
+ var r0 []*libyavirttypes.Network
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, []string) ([]*libyavirttypes.Network, error)); ok {
+ return rf(ctx, drivers)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, []string) []*libyavirttypes.Network); ok {
+ r0 = rf(ctx, drivers)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]*libyavirttypes.Network)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, []string) error); ok {
+ r1 = rf(ctx, drivers)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// Ping provides a mock function with given fields:
+func (_m *Service) Ping() map[string]string {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Ping")
+ }
+
+ var r0 map[string]string
+ if rf, ok := ret.Get(0).(func() map[string]string); ok {
+ r0 = rf()
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(map[string]string)
+ }
+ }
+
+ return r0
+}
+
+// PullImage provides a mock function with given fields: ctx, imgName
+func (_m *Service) PullImage(ctx context.Context, imgName string) (*vmimagetypes.Image, io.ReadCloser, error) {
+ ret := _m.Called(ctx, imgName)
+
+ if len(ret) == 0 {
+ panic("no return value specified for PullImage")
+ }
+
+ var r0 *vmimagetypes.Image
+ var r1 io.ReadCloser
+ var r2 error
+ if rf, ok := ret.Get(0).(func(context.Context, string) (*vmimagetypes.Image, io.ReadCloser, error)); ok {
+ return rf(ctx, imgName)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, string) *vmimagetypes.Image); ok {
+ r0 = rf(ctx, imgName)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*vmimagetypes.Image)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, string) io.ReadCloser); ok {
+ r1 = rf(ctx, imgName)
+ } else {
+ if ret.Get(1) != nil {
+ r1 = ret.Get(1).(io.ReadCloser)
+ }
+ }
+
+ if rf, ok := ret.Get(2).(func(context.Context, string) error); ok {
+ r2 = rf(ctx, imgName)
+ } else {
+ r2 = ret.Error(2)
+ }
+
+ return r0, r1, r2
+}
+
+// PushImage provides a mock function with given fields: ctx, imgName, force
+func (_m *Service) PushImage(ctx context.Context, imgName string, force bool) (io.ReadCloser, error) {
+ ret := _m.Called(ctx, imgName, force)
+
+ if len(ret) == 0 {
+ panic("no return value specified for PushImage")
+ }
+
+ var r0 io.ReadCloser
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, string, bool) (io.ReadCloser, error)); ok {
+ return rf(ctx, imgName, force)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, string, bool) io.ReadCloser); ok {
+ r0 = rf(ctx, imgName, force)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(io.ReadCloser)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, string, bool) error); ok {
+ r1 = rf(ctx, imgName, force)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// RawEngine provides a mock function with given fields: ctx, id, req
+func (_m *Service) RawEngine(ctx context.Context, id string, req libyavirttypes.RawEngineReq) (libyavirttypes.RawEngineResp, error) {
+ ret := _m.Called(ctx, id, req)
+
+ if len(ret) == 0 {
+ panic("no return value specified for RawEngine")
+ }
+
+ var r0 libyavirttypes.RawEngineResp
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, string, libyavirttypes.RawEngineReq) (libyavirttypes.RawEngineResp, error)); ok {
+ return rf(ctx, id, req)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, string, libyavirttypes.RawEngineReq) libyavirttypes.RawEngineResp); ok {
+ r0 = rf(ctx, id, req)
+ } else {
+ r0 = ret.Get(0).(libyavirttypes.RawEngineResp)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, string, libyavirttypes.RawEngineReq) error); ok {
+ r1 = rf(ctx, id, req)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// RemoveImage provides a mock function with given fields: ctx, imageName, force, prune
+func (_m *Service) RemoveImage(ctx context.Context, imageName string, force bool, prune bool) ([]string, error) {
+ ret := _m.Called(ctx, imageName, force, prune)
+
+ if len(ret) == 0 {
+ panic("no return value specified for RemoveImage")
+ }
+
+ var r0 []string
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, string, bool, bool) ([]string, error)); ok {
+ return rf(ctx, imageName, force, prune)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, string, bool, bool) []string); ok {
+ r0 = rf(ctx, imageName, force, prune)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]string)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, string, bool, bool) error); ok {
+ r1 = rf(ctx, imageName, force, prune)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ResizeConsoleWindow provides a mock function with given fields: ctx, id, height, width
+func (_m *Service) ResizeConsoleWindow(ctx context.Context, id string, height uint, width uint) error {
+ ret := _m.Called(ctx, id, height, width)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ResizeConsoleWindow")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(context.Context, string, uint, uint) error); ok {
+ r0 = rf(ctx, id, height, width)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// ResizeGuest provides a mock function with given fields: ctx, id, opts
+func (_m *Service) ResizeGuest(ctx context.Context, id string, opts *types.GuestResizeOption) error {
+ ret := _m.Called(ctx, id, opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ResizeGuest")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(context.Context, string, *types.GuestResizeOption) error); ok {
+ r0 = rf(ctx, id, opts)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// RestoreSnapshot provides a mock function with given fields: ctx, req
+func (_m *Service) RestoreSnapshot(ctx context.Context, req libyavirttypes.RestoreSnapshotReq) error {
+ ret := _m.Called(ctx, req)
+
+ if len(ret) == 0 {
+ panic("no return value specified for RestoreSnapshot")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(context.Context, libyavirttypes.RestoreSnapshotReq) error); ok {
+ r0 = rf(ctx, req)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// Wait provides a mock function with given fields: ctx, id, block
+func (_m *Service) Wait(ctx context.Context, id string, block bool) (string, int, error) {
+ ret := _m.Called(ctx, id, block)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Wait")
+ }
+
+ var r0 string
+ var r1 int
+ var r2 error
+ if rf, ok := ret.Get(0).(func(context.Context, string, bool) (string, int, error)); ok {
+ return rf(ctx, id, block)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, string, bool) string); ok {
+ r0 = rf(ctx, id, block)
+ } else {
+ r0 = ret.Get(0).(string)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, string, bool) int); ok {
+ r1 = rf(ctx, id, block)
+ } else {
+ r1 = ret.Get(1).(int)
+ }
+
+ if rf, ok := ret.Get(2).(func(context.Context, string, bool) error); ok {
+ r2 = rf(ctx, id, block)
+ } else {
+ r2 = ret.Error(2)
+ }
+
+ return r0, r1, r2
+}
+
+// WatchGuestEvents provides a mock function with given fields: _a0
+func (_m *Service) WatchGuestEvents(_a0 context.Context) (*utils.Watcher, error) {
+ ret := _m.Called(_a0)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchGuestEvents")
+ }
+
+ var r0 *utils.Watcher
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (*utils.Watcher, error)); ok {
+ return rf(_a0)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) *utils.Watcher); ok {
+ r0 = rf(_a0)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*utils.Watcher)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(_a0)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// NewService creates a new instance of Service. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func NewService(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *Service {
+ mock := &Service{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/internal/service/service.go b/internal/service/service.go
new file mode 100644
index 0000000..83f85f1
--- /dev/null
+++ b/internal/service/service.go
@@ -0,0 +1,60 @@
+package service
+
+import (
+ "context"
+ "io"
+
+ "github.com/projecteru2/libyavirt/types"
+ intertypes "github.com/projecteru2/yavirt/internal/types"
+ "github.com/projecteru2/yavirt/internal/utils"
+ vmitypes "github.com/yuyang0/vmimage/types"
+)
+
+// Service interface
+// Note: all ids passed to this interface and returned by this interface don't contains maigc prefix
+type Service interface { //nolint:interfacebloat
+ Ping() map[string]string
+ Info() (*types.HostInfo, error)
+ IsHealthy(ctx context.Context) (ans bool)
+
+ // Guest related functions
+ GetGuest(ctx context.Context, id string) (*types.Guest, error)
+ GetGuestIDList(ctx context.Context) ([]string, error)
+ GetGuestUUID(ctx context.Context, id string) (string, error)
+ CreateGuest(ctx context.Context, opts intertypes.GuestCreateOption) (*types.Guest, error)
+ CaptureGuest(ctx context.Context, id string, imgName string, overridden bool) (uimg *vmitypes.Image, err error)
+ ResizeGuest(ctx context.Context, id string, opts *intertypes.GuestResizeOption) (err error)
+ ControlGuest(ctx context.Context, id, operation string, force bool) (err error)
+ AttachGuest(ctx context.Context, id string, stream io.ReadWriteCloser, flags intertypes.OpenConsoleFlags) (err error)
+ ResizeConsoleWindow(ctx context.Context, id string, height, width uint) (err error)
+ Wait(ctx context.Context, id string, block bool) (msg string, code int, err error)
+ WatchGuestEvents(context.Context) (*utils.Watcher, error)
+
+ // Guest utilities
+ ExecuteGuest(ctx context.Context, id string, commands []string) (*types.ExecuteGuestMessage, error)
+ ExecExitCode(id string, pid int) (int, error)
+ Cat(ctx context.Context, id, path string, dest io.WriteCloser) (err error)
+ CopyToGuest(ctx context.Context, id, dest string, content chan []byte, override bool) (err error)
+ Log(ctx context.Context, id, logPath string, n int, dest io.WriteCloser) (err error)
+
+ // Snapshot
+ ListSnapshot(ctx context.Context, req types.ListSnapshotReq) (snaps types.Snapshots, err error)
+ CreateSnapshot(ctx context.Context, req types.CreateSnapshotReq) (err error)
+ CommitSnapshot(ctx context.Context, req types.CommitSnapshotReq) (err error)
+ CommitSnapshotByDay(ctx context.Context, id, volID string, day int) (err error)
+ RestoreSnapshot(ctx context.Context, req types.RestoreSnapshotReq) (err error)
+
+ // Network
+ NetworkList(ctx context.Context, drivers []string) ([]*types.Network, error)
+ ConnectNetwork(ctx context.Context, id, network, ipv4 string) (cidr string, err error)
+ DisconnectNetwork(ctx context.Context, id, network string) (err error)
+
+ // Image
+ PushImage(ctx context.Context, imgName string, force bool) (rc io.ReadCloser, err error)
+ RemoveImage(ctx context.Context, imageName string, force, prune bool) (removed []string, err error)
+ ListImage(ctx context.Context, filter string) ([]*vmitypes.Image, error)
+ PullImage(ctx context.Context, imgName string) (img *vmitypes.Image, rc io.ReadCloser, err error)
+ DigestImage(ctx context.Context, imageName string, local bool) (digest []string, err error)
+
+ RawEngine(ctx context.Context, id string, req types.RawEngineReq) (types.RawEngineResp, error)
+}
diff --git a/internal/types/cloud_init.go b/internal/types/cloud_init.go
new file mode 100644
index 0000000..73506d6
--- /dev/null
+++ b/internal/types/cloud_init.go
@@ -0,0 +1,204 @@
+package types
+
+import (
+ "bytes"
+ _ "embed"
+ "encoding/base64"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "text/template"
+
+ "github.com/Masterminds/sprig/v3"
+
+ "github.com/kdomanski/iso9660/util"
+
+ "github.com/cockroachdb/errors"
+)
+
+var (
+ //go:embed templates/user-data.yaml
+ userData string
+ //go:embed templates/meta-data.yaml
+ metaData string
+ //go:embed templates/network-config.yaml
+ networkData string
+
+ userDataTpl *template.Template
+ metaDataTpl *template.Template
+ networkTpl *template.Template
+)
+
+type CloudInitGateway struct {
+ IP string `json:"ip"`
+ OnLink bool `json:"on_link"`
+}
+
+type CloudInitConfig struct {
+ // use remote server to fetch cloud-init config
+ URL string `json:"url"`
+
+ // use local iso to fetch cloud-init config
+ Username string `json:"username"`
+ Password string `json:"password"`
+ SSHPubKey string `json:"ssh_pub_key"`
+ Hostname string `json:"hostname"`
+ InstanceID string `json:"instance_id"`
+ Files map[string][]byte `json:"files"`
+ Commands []string `json:"commands"`
+
+ MAC string `json:"-"`
+ CIDR string `json:"-"`
+ MTU int `json:"-"`
+ IFName string `json:"-"`
+ DefaultGW CloudInitGateway `json:"-"`
+}
+
+func initTpls() (err error) {
+ if userDataTpl == nil {
+ if userDataTpl, err = template.New("userdata").Funcs(sprig.TxtFuncMap()).Parse(userData); err != nil {
+ return
+ }
+ }
+ if metaDataTpl == nil {
+ if metaDataTpl, err = template.New("metadata").Funcs(sprig.TxtFuncMap()).Parse(metaData); err != nil {
+ return
+ }
+ }
+ if networkTpl == nil {
+ if networkTpl, err = template.New("network").Funcs(sprig.TxtFuncMap()).Parse(networkData); err != nil {
+ return
+ }
+ }
+ return
+}
+
+func (ciCfg *CloudInitConfig) GenFilesContent() (string, string, string, error) {
+ if err := initTpls(); err != nil {
+ return "", "", "", err
+ }
+ d1 := map[string]any{
+ "username": ciCfg.Username,
+ "password": ciCfg.Password,
+ "sshPubKey": ciCfg.SSHPubKey,
+ "mac": ciCfg.MAC,
+ "cidr": ciCfg.CIDR,
+ "mtu": ciCfg.MTU,
+ "ifname": ciCfg.IFName,
+ "defaultGW": map[string]any{
+ "ip": ciCfg.DefaultGW.IP,
+ "onLink": ciCfg.DefaultGW.OnLink,
+ },
+ "commands": ciCfg.Commands,
+ "files": []map[string]any{},
+ }
+ for k, v := range ciCfg.Files {
+ d1["files"] = append(d1["files"].([]map[string]any), map[string]any{
+ "path": k,
+ "content": base64.StdEncoding.EncodeToString(v),
+ })
+ }
+ var userDataBs bytes.Buffer
+ if err := userDataTpl.Execute(&userDataBs, d1); err != nil {
+ return "", "", "", err
+ }
+
+ d2 := map[string]string{
+ "instanceID": ciCfg.InstanceID,
+ "hostname": ciCfg.Hostname,
+ }
+ var metaDataBs bytes.Buffer
+ if err := metaDataTpl.Execute(&metaDataBs, d2); err != nil {
+ return "", "", "", err
+ }
+ var networkBs bytes.Buffer
+ if err := networkTpl.Execute(&networkBs, d1); err != nil {
+ return "", "", "", err
+ }
+ return userDataBs.String(), metaDataBs.String(), networkBs.String(), nil
+}
+
+func (ciCfg *CloudInitConfig) GenerateISO(fname string) (err error) {
+ dir, err := os.MkdirTemp("/tmp", "cloud-init")
+ if err != nil {
+ return
+ }
+ defer os.RemoveAll(dir)
+ udataFname := filepath.Join(dir, "user-data")
+ mdataFname := filepath.Join(dir, "meta-data")
+ networkFname := filepath.Join(dir, "network-config")
+
+ udata, mdata, ndata, err := ciCfg.GenFilesContent()
+ if err != nil {
+ return
+ }
+ if err := os.WriteFile(udataFname, []byte(udata), 0600); err != nil {
+ return errors.Wrap(err, "")
+ }
+ if err := os.WriteFile(mdataFname, []byte(mdata), 0600); err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ if err := os.WriteFile(networkFname, []byte(ndata), 0600); err != nil {
+ return errors.Wrap(err, "")
+ }
+ // args := []string{
+ // "genisoimage", "-output", fname, "-V", "cidata", "-r", "-J", "user-data", "meta-data",
+ // }
+ args := []string{
+ "cloud-localds", "--network-config=network-config", fname, "user-data", "meta-data",
+ }
+ cmd := exec.Command(args[0], args[1:]...) //nolint
+ cmd.Dir = dir
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ return errors.Wrapf(err, "failed to exec genisoimage %s", out)
+ }
+ return
+}
+
+func extractISO(isoPath, outputDir string) error {
+ isoFile, err := os.Open(isoPath)
+ if err != nil {
+ return err
+ }
+ defer isoFile.Close()
+
+ return util.ExtractImageToDirectory(isoFile, outputDir)
+}
+
+func (ciCfg *CloudInitConfig) ReplaceUserData(fname string) (err error) {
+ if ciCfg.Username == "" || ciCfg.Password == "" {
+ return
+ }
+ // if the iso file doesn't exist, it means the cloud-init DataSource is not NoCloud-local
+ _, err = os.Stat(fname)
+ if os.IsNotExist(err) {
+ return nil
+ }
+
+ dir, err := os.MkdirTemp("/tmp", "cloud-init")
+ if err != nil {
+ return
+ }
+ defer os.RemoveAll(dir)
+ if err := extractISO(fname, dir); err != nil {
+ return err
+ }
+ udataFname := filepath.Join(dir, "user-data")
+
+ udata, _, _, err := ciCfg.GenFilesContent()
+ if err := os.WriteFile(udataFname, []byte(udata), 0600); err != nil {
+ return errors.Wrap(err, "")
+ }
+ args := []string{
+ "cloud-localds", "--network-config=network-config", fname, "user-data", "meta-data",
+ }
+ cmd := exec.Command(args[0], args[1:]...) //nolint
+ cmd.Dir = dir
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ return errors.Wrapf(err, "failed to exec genisoimage %s", out)
+ }
+ return
+}
diff --git a/internal/types/cloud_init_test.go b/internal/types/cloud_init_test.go
new file mode 100644
index 0000000..2fea7b0
--- /dev/null
+++ b/internal/types/cloud_init_test.go
@@ -0,0 +1,53 @@
+package types
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strings"
+ "testing"
+
+ "github.com/projecteru2/yavirt/pkg/test/assert"
+)
+
+func TestGenContent(t *testing.T) {
+ cfg := &CloudInitConfig{
+ Username: "root",
+ Password: "passwd",
+ }
+ user, _, _, err := cfg.GenFilesContent()
+ assert.Nil(t, err)
+ // it is ugly here, but using yaml lib is too complex here
+ assert.True(t, strings.Contains(user, "name: \"root\""))
+ assert.True(t, strings.Contains(user, "plain_text_passwd: \"passwd\""))
+ assert.False(t, strings.Contains(user, "- echo hello"))
+ assert.False(t, strings.Contains(user, "- path: foo"))
+ assert.False(t, strings.Contains(user, "content: "))
+
+ cfg.Commands = []string{"echo hello"}
+ cfg.Files = map[string][]byte{
+ "foo": []byte("bar\nbar1"),
+ }
+ user, _, _, err = cfg.GenFilesContent()
+ assert.Nil(t, err)
+ assert.True(t, strings.Contains(user, "name: \"root\""))
+ assert.True(t, strings.Contains(user, "plain_text_passwd: \"passwd\""))
+ assert.True(t, strings.Contains(user, "- echo hello"))
+ assert.True(t, strings.Contains(user, "- path: foo"))
+ assert.True(t, strings.Contains(user, fmt.Sprintf("content: %s", base64.StdEncoding.EncodeToString([]byte("bar\nbar1")))))
+}
+
+func TestNetwork(t *testing.T) {
+ cfg := &CloudInitConfig{
+ CIDR: "10.10.10.1/24",
+ DefaultGW: CloudInitGateway{
+ IP: "10.10.10.111",
+ OnLink: true,
+ },
+ }
+ _, _, network, err := cfg.GenFilesContent()
+ assert.Nil(t, err)
+ // fmt.Printf("%s\n", network)
+ assert.True(t, strings.Contains(network, "10.10.10.1/24"))
+ assert.True(t, strings.Contains(network, "via: 10.10.10.111"))
+ assert.True(t, strings.Contains(network, "on-link: true"))
+}
diff --git a/internal/types/console.go b/internal/types/console.go
new file mode 100644
index 0000000..534d007
--- /dev/null
+++ b/internal/types/console.go
@@ -0,0 +1,30 @@
+package types
+
+import (
+ "io"
+
+ "github.com/projecteru2/yavirt/pkg/libvirt"
+)
+
+type Console interface {
+ io.ReadWriteCloser
+ Fd() int // need fd for epoll event
+}
+
+// OpenConsoleFlags .
+type OpenConsoleFlags struct {
+ libvirt.ConsoleFlags
+ Devname string
+ Commands []string
+}
+
+// NewOpenConsoleFlags .
+func NewOpenConsoleFlags(force, safe bool, cmds []string) OpenConsoleFlags {
+ return OpenConsoleFlags{
+ ConsoleFlags: libvirt.ConsoleFlags{
+ Force: force,
+ Safe: safe,
+ },
+ Commands: cmds,
+ }
+}
diff --git a/internal/types/const.go b/internal/types/const.go
new file mode 100644
index 0000000..2975d56
--- /dev/null
+++ b/internal/types/const.go
@@ -0,0 +1,9 @@
+package types
+
+const (
+ PluginNameCPUMem = "cpumem"
+ PluginNameGPU = "gpu"
+ PluginNameRBD = "rbd"
+ PluginNameStorage = "storage"
+ PluginNameBandwidth = "bandwidth"
+)
diff --git a/internal/virt/types/distro.go b/internal/types/distro.go
similarity index 100%
rename from internal/virt/types/distro.go
rename to internal/types/distro.go
diff --git a/internal/types/domain.go b/internal/types/domain.go
new file mode 100644
index 0000000..8d4f8f1
--- /dev/null
+++ b/internal/types/domain.go
@@ -0,0 +1,40 @@
+package types
+
+import "encoding/xml"
+
+type CustomDomainMetadata struct {
+ XMLName xml.Name `xml:"metadata"`
+ App App `xml:"app"`
+}
+
+type App struct {
+ XMLName xml.Name `xml:"app"`
+ NS string `xml:"xmlns,attr"`
+ From string `xml:"from,attr"`
+ Owner AppOwner `xml:"owner"`
+ Name AppName `xml:"name"`
+ IP AppIP `xml:"ip"`
+ ID AppID `xml:"id"`
+}
+
+type AppOwner struct {
+ XMLName xml.Name `xml:"owner"`
+ UserID string `xml:"id,attr"`
+ UserName string `xml:",chardata"`
+}
+
+type AppName struct {
+ XMLName xml.Name `xml:"name"`
+ Name string `xml:",chardata"`
+}
+
+type AppIP struct {
+ XMLName xml.Name `xml:"ip"`
+ IP string `xml:",chardata"`
+}
+
+type AppID struct {
+ XMLName xml.Name `xml:"id"`
+ SID string `xml:"sid,attr"`
+ ID string `xml:",chardata"`
+}
diff --git a/internal/virt/types/error.go b/internal/types/error.go
similarity index 100%
rename from internal/virt/types/error.go
rename to internal/types/error.go
diff --git a/internal/types/event.go b/internal/types/event.go
new file mode 100644
index 0000000..7f56d8f
--- /dev/null
+++ b/internal/types/event.go
@@ -0,0 +1,39 @@
+package types
+
+import "time"
+
+const (
+ DestroyOp Operator = "destroy"
+ DieOp Operator = "die"
+ StopOp Operator = "stop"
+ StartOp Operator = "start"
+ SuspendOp Operator = "suspend"
+ ResumeOp Operator = "resume"
+ CreateOp Operator = "create"
+ ExecuteOp Operator = "execute"
+ ResizeOp Operator = "resize"
+ ResetSysDiskOp Operator = "reset-sys-disk"
+ FSFreezeOP Operator = "fs-freeze"
+ FSThawOP Operator = "fs-thaw"
+ MiscOp Operator = "misc"
+ CreateSnapshotOp Operator = "create-snapshot"
+ CommitSnapshotOp Operator = "commit-snapshot"
+ RestoreSnapshotOp Operator = "restore-snapshot"
+)
+
+const (
+ EventTypeGuest = "guest"
+)
+
+type Operator string
+
+func (op Operator) String() string {
+ return string(op)
+}
+
+type Event struct {
+ ID string
+ Type string
+ Op Operator
+ Time time.Time
+}
diff --git a/internal/types/gpu.go b/internal/types/gpu.go
new file mode 100644
index 0000000..6725146
--- /dev/null
+++ b/internal/types/gpu.go
@@ -0,0 +1,20 @@
+package types
+
+type GPUInfo struct {
+ Address string `json:"address" mapstructure:"address"`
+ Index int `json:"index" mapstructure:"index"`
+ // example value: "NVIDIA Corporation"
+ Vendor string `json:"vendor" mapstructure:"vendor"`
+ // example value: "GA104 [GeForce RTX 3070]"
+ Product string `json:"product" mapstructure:"product"`
+
+ // NUMA NUMAInfo
+ NumaID string `json:"numa_id" mapstructure:"numa_id"`
+
+ // Cores int `json:"cores" mapstructure:"cores"`
+ GMemory int64 `json:"gmemory" mapstructure:"gmemory"`
+}
+
+type GPUEngineParams struct {
+ Addrs []string `json:"addrs" mapstructure:"addrs"`
+}
diff --git a/internal/virt/types/guest.go b/internal/types/guest.go
similarity index 55%
rename from internal/virt/types/guest.go
rename to internal/types/guest.go
index d84c735..3e9fbf0 100644
--- a/internal/virt/types/guest.go
+++ b/internal/types/guest.go
@@ -40,3 +40,34 @@ func ConvertGRPCCreateOptions(opts *pb.CreateGuestOptions) GuestCreateOption {
}
return ret
}
+
+type GuestResizeOption struct {
+ ID string
+ CPU int
+ Mem int64
+ Volumes []virttypes.Volume
+ Resources map[string][]byte
+}
+
+func ConvertGRPCResizeOptions(opts *pb.ResizeGuestOptions) *GuestResizeOption {
+ ret := &GuestResizeOption{
+ ID: opts.Id,
+ CPU: int(opts.Cpu),
+ Mem: opts.Memory,
+ Resources: opts.Resources,
+ }
+ ret.Volumes = make([]virttypes.Volume, len(opts.Volumes))
+ for i, vol := range opts.Volumes {
+ ret.Volumes[i].Mount = vol.Mount
+ ret.Volumes[i].Capacity = vol.Capacity
+ ret.Volumes[i].IO = vol.Io
+ }
+ return ret
+}
+
+type InitSysDiskArgs struct {
+ Image string `json:"image"`
+ Username string `json:"username"`
+ Password string `json:"password"`
+ Resources map[string][]byte `json:"resources"`
+}
diff --git a/internal/virt/types/guestfs.go b/internal/types/guestfs.go
similarity index 100%
rename from internal/virt/types/guestfs.go
rename to internal/types/guestfs.go
diff --git a/internal/types/templates/meta-data.yaml b/internal/types/templates/meta-data.yaml
new file mode 100644
index 0000000..5ddf70e
--- /dev/null
+++ b/internal/types/templates/meta-data.yaml
@@ -0,0 +1,3 @@
+dsmode: local
+instance-id: {{ .instanceID }}
+local-hostname: {{ .hostname }}
\ No newline at end of file
diff --git a/internal/types/templates/network-config.yaml b/internal/types/templates/network-config.yaml
new file mode 100644
index 0000000..ea92997
--- /dev/null
+++ b/internal/types/templates/network-config.yaml
@@ -0,0 +1,22 @@
+version: 2
+ethernets:
+ eth0:
+ # cloud-init has BUG, On ubuntu if set-name is set, the network config will not take effect and we must run `netplan apply` manually
+ # set-name: eth0
+ match:
+ name: en*
+ # dhcp4: false
+ # dhcp6: false
+ macaddress: {{ .mac }}
+ addresses:
+ - {{ .cidr }}
+ mtu: {{ .mtu }}
+ # gateway4: 169.254.1.1
+ nameservers:
+ addresses:
+ - 8.8.8.8
+ - 8.8.4.4
+ routes:
+ - to: 0.0.0.0/0
+ via: {{index .defaultGW "ip" }}
+ on-link: {{index .defaultGW "onLink" }}
\ No newline at end of file
diff --git a/internal/types/templates/user-data.yaml b/internal/types/templates/user-data.yaml
new file mode 100644
index 0000000..2c13555
--- /dev/null
+++ b/internal/types/templates/user-data.yaml
@@ -0,0 +1,49 @@
+#cloud-config
+
+{{if gt (len .files) 0}}
+write_files:
+ {{ range .files }}
+ - path: {{ .path }}
+ encoding: b64
+ content: {{ .content }}
+ {{ end }}
+{{ end }}
+
+packages:
+ - qemu-guest-agent
+
+{{ if eq .username "root" }}
+bootcmd:
+ - sed -i '/^\s*PermitRootLogin.*$/d' /etc/ssh/sshd_config
+ - echo "PermitRootLogin yes" >> /etc/ssh/sshd_config
+{{ end }}
+
+runcmd:
+ - systemctl restart ssh
+ - systemctl start qemu-guest-agent
+{{ range .commands }}
+ - {{ . }}
+{{ end }}
+
+users:
+ - name: "{{ .username }}"
+ plain_text_passwd: "{{ .password }}"
+ lock_passwd: false
+ sudo: ALL=(ALL) NOPASSWD:ALL
+ groups: sudo
+ shell: /bin/bash
+
+{{ if ne .sshPubKey "" }}
+ ssh_authorized_keys:
+ - {{ .sshPubKey }}
+{{ end }}
+
+{{ if eq .sshPubKey "" }}
+ssh_pwauth: true
+{{ end }}
+
+{{ if eq .username "root" }}
+disable_root: false
+{{ else }}
+disable_root: true
+{{ end }}
\ No newline at end of file
diff --git a/internal/utils/check.go b/internal/utils/check.go
new file mode 100644
index 0000000..9cfcc7f
--- /dev/null
+++ b/internal/utils/check.go
@@ -0,0 +1,85 @@
+package utils
+
+import (
+ "context"
+ "net"
+ "net/http"
+ "time"
+
+ "github.com/projecteru2/core/log"
+)
+
+// CheckHTTP 检查一个workload的所有URL
+// CheckHTTP 事实上一般也就一个
+func CheckHTTP(ctx context.Context, ID string, backends []string, code int, timeout time.Duration) bool {
+ logger := log.WithFunc("CheckHTTP").WithField("ID", ID).WithField("backends", backends).WithField("code", code)
+ for _, backend := range backends {
+ logger.Debug(ctx, "Check health via http")
+ if !checkOneURL(ctx, backend, code, timeout) {
+ logger.Info(ctx, "Check health failed via http")
+ return false
+ }
+ }
+ return true
+}
+
+// CheckTCP 检查一个TCP
+// 这里不支持ctx?
+func CheckTCP(ctx context.Context, ID string, backends []string, timeout time.Duration) bool {
+ logger := log.WithFunc("CheckTCP").WithField("ID", ID).WithField("backends", backends)
+ for _, backend := range backends {
+ logger.Debug(ctx, "Check health via tcp")
+ conn, err := net.DialTimeout("tcp", backend, timeout)
+ if err != nil {
+ logger.Debug(ctx, "Check health failed via tcp")
+ return false
+ }
+ conn.Close()
+ }
+ return true
+}
+
+// 偷来的函数
+// 谁要官方的context没有收录他 ¬ ¬
+func get(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
+ if client == nil {
+ client = http.DefaultClient
+ }
+
+ req, err := http.NewRequest(http.MethodGet, url, nil)
+ if err != nil {
+ return nil, err
+ }
+
+ resp, err := client.Do(req.WithContext(ctx))
+ if err != nil {
+ select {
+ case <-ctx.Done():
+ err = ctx.Err()
+ default:
+ }
+ }
+ return resp, err
+}
+
+// 就先定义 [200, 500) 这个区间的 code 都算是成功吧
+func checkOneURL(ctx context.Context, url string, expectedCode int, timeout time.Duration) bool {
+ logger := log.WithFunc("checkOneURL").WithField("url", url)
+ var resp *http.Response
+ var err error
+ WithTimeout(ctx, timeout, func(ctx context.Context) {
+ resp, err = get(ctx, nil, url) //nolint
+ })
+ if err != nil {
+ logger.Error(ctx, err, "Error when checking")
+ return false
+ }
+ defer resp.Body.Close()
+ if expectedCode == 0 {
+ return resp.StatusCode < 500 && resp.StatusCode >= 200
+ }
+ if resp.StatusCode != expectedCode {
+ logger.Warnf(ctx, "Error when checking, expect %d, got %d", expectedCode, resp.StatusCode)
+ }
+ return resp.StatusCode == expectedCode
+}
diff --git a/internal/utils/check_test.go b/internal/utils/check_test.go
new file mode 100644
index 0000000..47caf63
--- /dev/null
+++ b/internal/utils/check_test.go
@@ -0,0 +1,26 @@
+package utils
+
+import (
+ "context"
+ "net/http"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestCheck(t *testing.T) {
+ go http.ListenAndServe(":12306", http.NotFoundHandler())
+ time.Sleep(time.Second)
+ ctx, cancel := context.WithCancel(context.Background())
+ assert.Equal(t, CheckHTTP(ctx, "", []string{"http://127.0.0.1:12306"}, 404, time.Second), true)
+ assert.Equal(t, CheckHTTP(ctx, "", []string{"http://127.0.0.1:12306"}, 0, time.Second), true)
+ assert.Equal(t, CheckHTTP(ctx, "", []string{"http://127.0.0.1:12306"}, 200, time.Second), false)
+ assert.Equal(t, CheckHTTP(ctx, "", []string{"http://127.0.0.1:12307"}, 200, time.Second), false)
+
+ cancel()
+ assert.Equal(t, CheckHTTP(ctx, "", []string{"http://127.0.0.1:12306"}, 404, time.Second), false)
+
+ assert.Equal(t, CheckTCP(ctx, "", []string{"127.0.0.1:12306"}, time.Second), true)
+ assert.Equal(t, CheckTCP(ctx, "", []string{"127.0.0.1:12307"}, time.Second), false)
+}
diff --git a/internal/utils/pool.go b/internal/utils/pool.go
new file mode 100644
index 0000000..fd40d95
--- /dev/null
+++ b/internal/utils/pool.go
@@ -0,0 +1,15 @@
+package utils
+
+import (
+ "github.com/panjf2000/ants/v2"
+)
+
+// TODO configurableu
+const size = 10000
+
+// Pool .
+var Pool *ants.Pool
+
+func init() {
+ Pool, _ = ants.NewPool(size, ants.WithNonblocking(true))
+}
diff --git a/internal/utils/retry.go b/internal/utils/retry.go
new file mode 100644
index 0000000..65ade1e
--- /dev/null
+++ b/internal/utils/retry.go
@@ -0,0 +1,72 @@
+package utils
+
+import (
+ "context"
+ "time"
+
+ "github.com/projecteru2/core/log"
+)
+
+// RetryTask .
+type RetryTask struct {
+ ctx context.Context
+ cancel context.CancelFunc
+ Func func() error
+ MaxAttempts int
+}
+
+// NewRetryTask .
+func NewRetryTask(ctx context.Context, maxAttempts int, f func() error) *RetryTask {
+ // make sure to execute at least once
+ if maxAttempts < 1 {
+ maxAttempts = 1
+ }
+ ctx, cancel := context.WithCancel(ctx)
+ return &RetryTask{
+ ctx: ctx,
+ cancel: cancel,
+ MaxAttempts: maxAttempts,
+ Func: f,
+ }
+}
+
+// Run start running retry task
+func (r *RetryTask) Run(ctx context.Context) error {
+ logger := log.WithFunc("Run")
+ logger.Debug(ctx, "start")
+ defer r.Stop(ctx)
+
+ var err error
+ interval := 1
+ timer := time.NewTimer(0)
+ defer timer.Stop()
+
+ for i := 0; i < r.MaxAttempts; i++ {
+ select {
+ case <-r.ctx.Done():
+ logger.Debug(ctx, "abort")
+ return r.ctx.Err()
+ case <-timer.C:
+ err = r.Func()
+ if err == nil {
+ return nil
+ }
+ logger.Debugf(ctx, "will retry after %v seconds", interval)
+ timer.Reset(time.Duration(interval) * time.Second)
+ interval *= 2
+ }
+ }
+ return err
+}
+
+// Stop stops running task
+func (r *RetryTask) Stop(context.Context) {
+ r.cancel()
+}
+
+// BackoffRetry retries up to `maxAttempts` times, and the interval will grow exponentially
+func BackoffRetry(ctx context.Context, maxAttempts int, f func() error) error {
+ retryTask := NewRetryTask(ctx, maxAttempts, f)
+ defer retryTask.Stop(ctx)
+ return retryTask.Run(ctx)
+}
diff --git a/internal/utils/retry_test.go b/internal/utils/retry_test.go
new file mode 100644
index 0000000..4a000df
--- /dev/null
+++ b/internal/utils/retry_test.go
@@ -0,0 +1,45 @@
+package utils
+
+import (
+ "context"
+ "errors"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestBackoffRetry(t *testing.T) {
+ var errNotSuccess = errors.New("not success")
+ i := 0
+ f := func() error {
+ i++
+ if i < 4 {
+ return errNotSuccess
+ }
+ return nil
+ }
+ assert.Nil(t, BackoffRetry(context.Background(), 10, f))
+ assert.Equal(t, 4, i)
+
+ i = 0
+ assert.Equal(t, errNotSuccess, BackoffRetry(context.Background(), 0, f))
+ assert.Equal(t, 1, i)
+}
+
+func TestBackoffRetryWithCancel(t *testing.T) {
+ ctx, cancel := context.WithTimeout(context.Background(), time.Second)
+ defer cancel()
+
+ var errNotSuccess = errors.New("not success")
+ i := 0
+ f := func() error {
+ i++
+ if i < 4 {
+ return errNotSuccess
+ }
+ return nil
+ }
+ assert.Equal(t, context.DeadlineExceeded, BackoffRetry(ctx, 10, f))
+ assert.NotEqual(t, 4, i)
+}
diff --git a/internal/utils/rollback.go b/internal/utils/rollback.go
new file mode 100644
index 0000000..2af686c
--- /dev/null
+++ b/internal/utils/rollback.go
@@ -0,0 +1,57 @@
+package utils
+
+import (
+ "context"
+ "sync"
+)
+
+type RollbackFunc func() error
+
+type rollbackListEntry struct {
+ fn RollbackFunc
+ msg string
+}
+
+type RollbackList struct {
+ mu sync.Mutex
+ List []rollbackListEntry
+}
+
+type ctxType string
+
+const (
+ rbKey ctxType = "rollbackList"
+)
+
+func NewRollbackListContext(ctx context.Context) context.Context {
+ return context.WithValue(ctx, rbKey, &RollbackList{})
+}
+
+func GetRollbackListFromContext(ctx context.Context) *RollbackList {
+ v := ctx.Value(rbKey)
+ if v != nil {
+ return v.(*RollbackList)
+ }
+ return nil
+}
+
+func (rl *RollbackList) Append(fn RollbackFunc, msg string) {
+ rl.mu.Lock()
+ defer rl.mu.Unlock()
+ rl.List = append(rl.List, rollbackListEntry{
+ fn: fn,
+ msg: msg,
+ })
+}
+
+func (rl *RollbackList) Pop() (fn RollbackFunc, msg string) {
+ rl.mu.Lock()
+ defer rl.mu.Unlock()
+ n := len(rl.List)
+ if n > 0 {
+ entry := rl.List[n-1]
+ fn, msg = entry.fn, entry.msg
+ rl.List = rl.List[:n-1]
+ }
+ return
+}
diff --git a/internal/utils/rollback_test.go b/internal/utils/rollback_test.go
new file mode 100644
index 0000000..4147827
--- /dev/null
+++ b/internal/utils/rollback_test.go
@@ -0,0 +1,22 @@
+package utils
+
+import (
+ "context"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestRollbacklList(t *testing.T) {
+ ctx := NewRollbackListContext(context.Background())
+ rl := GetRollbackListFromContext(ctx)
+ rl.Append(func() error { return nil }, "1")
+ rl.Append(func() error { return nil }, "2")
+ rl2 := GetRollbackListFromContext(ctx)
+ fn, msg := rl2.Pop()
+ assert.Equal(t, msg, "2")
+ assert.Nil(t, fn())
+ fn, msg = rl2.Pop()
+ assert.Equal(t, msg, "1")
+ assert.Nil(t, fn())
+}
diff --git a/internal/utils/sh.go b/internal/utils/sh.go
new file mode 100644
index 0000000..579057e
--- /dev/null
+++ b/internal/utils/sh.go
@@ -0,0 +1,81 @@
+package utils
+
+import (
+ "context"
+ "fmt"
+ "strconv"
+ "strings"
+
+ "github.com/projecteru2/yavirt/pkg/sh"
+)
+
+// CreateImage .
+func CreateImage(ctx context.Context, fmt, path string, cap int64) error {
+ return sh.ExecContext(ctx, "qemu-img", "create", "-q", "-f", fmt, path, strconv.FormatInt(cap, 10))
+}
+
+func ResizeImage(ctx context.Context, path string, cap int64) error {
+ return sh.ExecContext(ctx, "qemu-img", "resize", path, strconv.FormatInt(cap, 10))
+}
+
+// AmplifyImage .
+func AmplifyImage(ctx context.Context, path string, delta int64) error {
+ flag := fmt.Sprintf("%+d", delta)
+ return sh.ExecContext(ctx, "qemu-img", "resize", path, flag)
+}
+
+// CommitImage .
+func CommitImage(ctx context.Context, path string) error {
+ return sh.ExecContext(ctx, "qemu-img", "commit", path)
+}
+
+// CreateSnapshot .
+func CreateSnapshot(ctx context.Context, volPath string, newVolPath string) error {
+ return sh.ExecContext(ctx, "qemu-img", "create", "-f", "qcow2", "-F", "qcow2", newVolPath, "-b", volPath)
+}
+
+// RebaseImage .
+func RebaseImage(ctx context.Context, volPath string, backingVolPath string) error {
+ return sh.ExecContext(ctx, "qemu-img", "rebase", "-b", backingVolPath, volPath)
+}
+
+// Check .
+func Check(ctx context.Context, volPath string) error {
+ return sh.ExecContext(ctx, "qemu-img", "check", volPath)
+}
+
+// Repair .
+func Repair(ctx context.Context, volPath string) error {
+ return sh.ExecContext(ctx, "qemu-img", "check", "-r", "all", volPath)
+}
+
+// Write an image to a block device
+func WriteBLK(ctx context.Context, imgPath string, device string, ignoreExist bool) error {
+ // two methods
+ // qemu-img convert -f qcow2 -O raw my-qcow2.img /dev/sdb
+ // qemu-img dd -f qcow2 -O raw bs=4M if=/vm-images/image.qcow2 of=/dev/sdd1
+ //
+ // for Ceph RBD, use following command:
+ // qemu-img convert -f qcow2 -O raw debian_squeeze.qcow2 rbd:data/squeeze
+ err := sh.ExecContext(ctx, "qemu-img", "convert", "-f", "qcow2", "-O", "raw", imgPath, device)
+ if err == nil || (ignoreExist && strings.Contains(err.Error(), "error rbd create: File exists")) {
+ return nil
+ }
+ return err
+}
+
+func DumpBLK(ctx context.Context, device string, imgPath string) error {
+ return sh.ExecContext(ctx, "qemu-img", "convert", "-f", "raw", "-O", "qcow2", device, imgPath)
+}
+
+func ForceWriteBLK(ctx context.Context, imgPath string, device string) error {
+ // two methods
+ // qemu-img convert -f qcow2 -O raw my-qcow2.img /dev/sdb
+ // qemu-img dd -f qcow2 -O raw bs=4M if=/vm-images/image.qcow2 of=/dev/sdd1
+ //
+ // for Ceph RBD, use following command:
+ // qemu-img convert -f qcow2 -O raw debian_squeeze.qcow2 rbd:data/squeeze
+ cmdStr := fmt.Sprintf("qemu-img dd -f qcow2 -O raw bs=4M if=%s of=%s --skip-create", imgPath, device)
+ cmds := strings.Split(cmdStr, " ")
+ return sh.ExecContext(ctx, cmds[0], cmds[1:]...)
+}
diff --git a/internal/utils/sync.go b/internal/utils/sync.go
new file mode 100644
index 0000000..fe7900b
--- /dev/null
+++ b/internal/utils/sync.go
@@ -0,0 +1,36 @@
+package utils
+
+import (
+ "sync"
+)
+
+// GroupCAS indicates cas locks which are grouped by keys.
+type GroupCAS struct {
+ sync.Mutex
+ locks map[string]struct{}
+}
+
+// NewGroupCAS .
+func NewGroupCAS() *GroupCAS {
+ return &GroupCAS{
+ locks: map[string]struct{}{},
+ }
+}
+
+// Acquire tries to acquire a cas lock.
+func (g *GroupCAS) Acquire(key string) (free func(), acquired bool) {
+ g.Lock()
+ defer g.Unlock()
+ if _, ok := g.locks[key]; ok {
+ return nil, false
+ }
+
+ g.locks[key] = struct{}{}
+ free = func() {
+ g.Lock()
+ defer g.Unlock()
+ delete(g.locks, key)
+ }
+
+ return free, true
+}
diff --git a/internal/utils/sync_test.go b/internal/utils/sync_test.go
new file mode 100644
index 0000000..df1b406
--- /dev/null
+++ b/internal/utils/sync_test.go
@@ -0,0 +1,62 @@
+package utils
+
+import (
+ "fmt"
+ "sync"
+ "sync/atomic"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func TestCAS(t *testing.T) {
+ key := "key"
+ cas := NewGroupCAS()
+
+ free, acquired := cas.Acquire(key)
+ require.True(t, acquired)
+ require.NotNil(t, free)
+
+ free1, acquired1 := cas.Acquire(key)
+ require.False(t, acquired1)
+ require.Nil(t, free1)
+
+ free()
+ free1, acquired1 = cas.Acquire(key)
+ require.True(t, acquired1)
+ require.NotNil(t, free1)
+}
+
+func TestCASConccurently(t *testing.T) {
+ var wg sync.WaitGroup
+ cas := NewGroupCAS()
+
+ n := 5000
+ key := "key"
+ var sum int32
+ wg.Add(n)
+
+ for i := 0; i < n; i++ {
+ go func(idx int) {
+ defer wg.Done()
+
+ _, acq := cas.Acquire(fmt.Sprintf("%d", idx))
+ require.True(t, acq)
+
+ free, acquired := cas.Acquire(key)
+ t.Logf("idx: %d, acquired: %t", idx, acquired)
+ if !acquired {
+ return
+ }
+
+ // makes sure that there're only one thread has been acquired.
+ require.Truef(t, atomic.CompareAndSwapInt32(&sum, 0, 1), "idx: %d, sum: %d", idx, atomic.LoadInt32(&sum))
+ // marks there's no thread is acquired in advance.
+ require.True(t, atomic.CompareAndSwapInt32(&sum, 1, 0))
+
+ free()
+ }(i)
+ }
+
+ wg.Wait()
+}
diff --git a/internal/utils/system.go b/internal/utils/system.go
new file mode 100644
index 0000000..acb50e4
--- /dev/null
+++ b/internal/utils/system.go
@@ -0,0 +1,45 @@
+package utils
+
+import (
+ "context"
+ "fmt"
+ "os"
+
+ "github.com/projecteru2/core/log"
+ "github.com/shirou/gopsutil/process"
+)
+
+func EnforceRoot() {
+ // Make sure the command is run with super user priviladges
+ if os.Getuid() != 0 {
+ fmt.Println("Need super user privileges: Operation not permitted")
+ os.Exit(1)
+ }
+}
+func PSContains(proc []string, procList []*process.Process) bool {
+ logger := log.WithFunc("psContains")
+ for _, p := range procList {
+ cmds, err := p.CmdlineSlice()
+ if err != nil {
+ // Failed to get CLI arguments for this process.
+ // Maybe it doesn't exist any more - move on to the next one.
+ logger.Debugf(context.TODO(), "Error getting CLI arguments: %s", err)
+ continue
+ }
+ var match bool
+ for i, p := range proc {
+ if i >= len(cmds) {
+ break
+ } else if cmds[i] == p {
+ match = true
+ }
+ }
+
+ // If we got a match, return true. Otherwise, try the next
+ // process in the list.
+ if match {
+ return true
+ }
+ }
+ return false
+}
diff --git a/internal/utils/util.go b/internal/utils/util.go
new file mode 100644
index 0000000..23b1c6a
--- /dev/null
+++ b/internal/utils/util.go
@@ -0,0 +1,61 @@
+package utils
+
+import (
+ "context"
+ "crypto/rand"
+ "fmt"
+ "io"
+ "math"
+ "path/filepath"
+ "time"
+
+ "github.com/projecteru2/core/log"
+ "github.com/projecteru2/libyavirt/types"
+ "github.com/projecteru2/yavirt/configs"
+ "github.com/projecteru2/yavirt/pkg/utils"
+)
+
+func VirtID(id string) string {
+ req := types.GuestReq{ID: id}
+ return req.VirtID()
+}
+
+func NewCreateSessionFlock(id string) *utils.Flock {
+ var fn = fmt.Sprintf("guest_create_session_%s.flock", id)
+ var fpth = filepath.Join(configs.Conf.VirtFlockDir, fn)
+ return utils.NewFlock(fpth)
+}
+
+// EnsureReaderClosed As the name says,
+// blocks until the stream is empty, until we meet EOF
+func EnsureReaderClosed(stream io.ReadCloser) {
+ if stream == nil {
+ return
+ }
+ if _, err := io.Copy(io.Discard, stream); err != nil {
+ log.Errorf(context.TODO(), err, "Empty stream failed")
+ }
+ _ = stream.Close()
+}
+
+func RandomString(length int) string {
+ b := make([]byte, length+2)
+ _, _ = rand.Read(b)
+ return fmt.Sprintf("%x", b)[2 : length+2]
+}
+
+// WithTimeout runs a function with given timeout
+func WithTimeout(ctx context.Context, timeout time.Duration, f func(ctx2 context.Context)) {
+ ctx, cancel := context.WithTimeout(ctx, timeout)
+ defer cancel()
+ f(ctx)
+}
+
+// GetMaxAttemptsByTTL .
+func GetMaxAttemptsByTTL(ttl int64) int {
+ // if selfmon is enabled, retry 5 times
+ if ttl < 1 {
+ return 5
+ }
+ return int(math.Floor(math.Log2(float64(ttl)+1))) + 1
+}
diff --git a/internal/virt/guest/manager/watcher.go b/internal/utils/watcher.go
similarity index 63%
rename from internal/virt/guest/manager/watcher.go
rename to internal/utils/watcher.go
index 84315f8..9d18d06 100644
--- a/internal/virt/guest/manager/watcher.go
+++ b/internal/utils/watcher.go
@@ -1,21 +1,21 @@
-package manager
+package utils
import (
+ "context"
"sync"
- "github.com/projecteru2/yavirt/internal/virt/types"
- "github.com/projecteru2/yavirt/pkg/errors"
- "github.com/projecteru2/yavirt/pkg/log"
+ "github.com/alphadose/haxmap"
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/core/log"
+ "github.com/projecteru2/yavirt/internal/types"
"github.com/projecteru2/yavirt/pkg/utils"
)
var ErrTooManyWatchers = errors.New("too many watchers")
type Watchers struct {
- sync.Mutex
-
index utils.AtomicInt64
- ws map[int64]*Watcher
+ wchMap *haxmap.Map[int64, *Watcher]
events chan types.Event
done struct {
@@ -27,35 +27,38 @@ type Watchers struct {
func NewWatchers() *Watchers {
ws := &Watchers{
events: make(chan types.Event),
- ws: map[int64]*Watcher{},
+ wchMap: haxmap.New[int64, *Watcher](),
}
ws.done.C = make(chan struct{})
return ws
}
+func (ws *Watchers) Len() int {
+ return int(ws.wchMap.Len())
+}
+
func (ws *Watchers) Stop() {
defer ws.done.Do(func() {
close(ws.done.C)
})
- ws.Lock()
- defer ws.Unlock()
-
- for _, w := range ws.ws {
- w.Stop()
- }
+ ws.wchMap.ForEach(func(_ int64, v *Watcher) bool {
+ v.Stop()
+ return true
+ })
}
-func (ws *Watchers) Run() {
- defer log.Infof("watchers loop has done")
+func (ws *Watchers) Run(ctx context.Context) {
+ defer log.Infof(ctx, "watchers loop has done")
for {
select {
case event := <-ws.events:
ws.Notify(event)
-
case <-ws.Done():
return
+ case <-ctx.Done():
+ return
}
}
}
@@ -63,39 +66,37 @@ func (ws *Watchers) Run() {
func (ws *Watchers) Watched(event types.Event) {
select {
case ws.events <- event:
- log.Infof("marks the event %v as watched", event)
+ log.Infof(context.TODO(), "marks the event %v as watched", event)
case <-ws.Done():
- log.Infof("marks the event %v failed as the Watchers has done", event)
+ log.Infof(context.TODO(), "marks the event %v failed as the Watchers has done", event)
}
}
func (ws *Watchers) Notify(event types.Event) {
- defer log.Infof("watchers notification has done")
+ defer log.Infof(context.TODO(), "watchers notification has done")
stopped := []int64{}
- ws.Lock()
- defer ws.Unlock()
-
- for _, w := range ws.ws {
+ ws.wchMap.ForEach(func(_ int64, wch *Watcher) bool {
select {
- case w.events <- event:
+ case wch.events <- event:
// notified successfully.
case <-ws.Done():
// It's really rare as there isn't an explicitly ws.Stop() calling now.
- stopped = append(stopped, w.id)
+ stopped = append(stopped, wch.id)
- case <-w.Done():
+ case <-wch.Done():
// The Watcher has been stopped.
- stopped = append(stopped, w.id)
+ stopped = append(stopped, wch.id)
}
- }
+ return true
+ })
// Reaps the watchers which have been stopped.
for _, k := range stopped {
- delete(ws.ws, k)
+ ws.wchMap.Del(k)
}
}
@@ -104,13 +105,10 @@ func (ws *Watchers) Done() <-chan struct{} {
}
func (ws *Watchers) Get() (*Watcher, error) {
- ws.Lock()
- defer ws.Unlock()
-
w := NewWatcher()
w.id = ws.index.Incr()
- ws.ws[w.id] = w
+ ws.wchMap.Set(w.id, w)
return w, nil
}
diff --git a/internal/virt/guest/manager/watcher_test.go b/internal/utils/watcher_test.go
similarity index 92%
rename from internal/virt/guest/manager/watcher_test.go
rename to internal/utils/watcher_test.go
index 1be7bb7..9f0162f 100644
--- a/internal/virt/guest/manager/watcher_test.go
+++ b/internal/utils/watcher_test.go
@@ -1,12 +1,13 @@
-package manager
+package utils
import (
+ "context"
"strconv"
"sync"
"testing"
"time"
- "github.com/projecteru2/yavirt/internal/virt/types"
+ "github.com/projecteru2/yavirt/internal/types"
"github.com/projecteru2/yavirt/pkg/test/assert"
"github.com/projecteru2/yavirt/pkg/utils"
)
@@ -15,7 +16,7 @@ func TestWatchers_StopSingleOne(t *testing.T) {
ws := NewWatchers()
defer ws.Stop()
- go ws.Run()
+ go ws.Run(context.Background())
var wg sync.WaitGroup
defer wg.Wait()
@@ -49,7 +50,7 @@ func TestWatchers_StopAll(t *testing.T) {
wg.Add(1)
go func() {
defer wg.Done()
- ws.Run()
+ ws.Run(context.Background())
}()
var sum utils.AtomicInt64
@@ -102,7 +103,7 @@ func TestWatchers_WatchedEvent(t *testing.T) {
wg.Add(1)
go func() {
defer wg.Done()
- ws.Run()
+ ws.Run(context.Background())
}()
var sum, recv utils.AtomicInt64
@@ -131,7 +132,7 @@ func TestWatchers_WatchedEvent(t *testing.T) {
for {
select {
case event := <-watcher.Events():
- v, err := strconv.Atoi(event.Action)
+ v, err := strconv.Atoi(event.Op.String())
assert.NilErr(t, err)
recv.Add(int64(v))
@@ -158,7 +159,7 @@ func TestWatchers_WatchedEvent(t *testing.T) {
go func(action string) {
defer nwg.Done()
ws.Watched(types.Event{
- Action: action,
+ Op: types.Operator(action),
})
}(strconv.Itoa(i))
}
diff --git a/internal/ver/ver.go b/internal/ver/ver.go
index 601b2e4..0ee4966 100644
--- a/internal/ver/ver.go
+++ b/internal/ver/ver.go
@@ -1,19 +1,28 @@
package ver
-import "fmt"
+import (
+ "fmt"
+ "runtime"
+)
var (
- // Git commit
- Git string
- // Compile info. of golang itself.
- Compile string
- // Date of compiled
- Date string
+ // NAME .
+ NAME = "Eru-agent"
+ // VERSION .
+ VERSION = "unknown"
+ // REVISION .
+ REVISION = "HEAD"
+ // BUILTAT .
+ BUILTAT = "now"
)
-// Version .
+// String .
func Version() string {
- return fmt.Sprintf(`Git: %s
-Compile: %s
-Built: %s`, Git, Compile, Date)
+ version := ""
+ version += fmt.Sprintf("Version: %s\n", VERSION)
+ version += fmt.Sprintf("Git hash: %s\n", REVISION)
+ version += fmt.Sprintf("Built: %s\n", BUILTAT)
+ version += fmt.Sprintf("Golang version: %s\n", runtime.Version())
+ version += fmt.Sprintf("OS/Arch: %s/%s\n", runtime.GOOS, runtime.GOARCH)
+ return version
}
diff --git a/internal/virt/agent/agent.go b/internal/virt/agent/agent.go
index 1e8242d..e30436f 100644
--- a/internal/virt/agent/agent.go
+++ b/internal/virt/agent/agent.go
@@ -6,6 +6,7 @@ import (
"github.com/projecteru2/yavirt/configs"
"github.com/projecteru2/yavirt/internal/virt/agent/types"
+ "github.com/projecteru2/yavirt/pkg/libvirt"
)
// Interface .
@@ -20,15 +21,18 @@ type Interface interface { //nolint
IsFolder(ctx context.Context, path string) (bool, error)
RemoveAll(ctx context.Context, path string) error
Grep(ctx context.Context, keyword, filepath string) (bool, error)
- OpenFile(path, mode string) (handle int, err error)
- CloseFile(handle int) error
- FlushFile(handle int) error
- ReadFile(handle int, p []byte) (int, bool, error)
- WriteFile(handle int, buf []byte) error
- SeekFile(handle int, offset int, whence int) (position int, eof bool, err error)
- AppendLine(filepath string, p []byte) error
+ OpenFile(ctx context.Context, path, mode string) (handle int, err error)
+ CloseFile(ctx context.Context, handle int) error
+ FlushFile(ctx context.Context, handle int) error
+ ReadFile(ctx context.Context, handle int, p []byte) (int, bool, error)
+ WriteFile(ctx context.Context, handle int, buf []byte) error
+ SeekFile(ctx context.Context, handle int, offset int, whence int) (position int, eof bool, err error)
+ AppendLine(ctx context.Context, filepath string, p []byte) error
Blkid(ctx context.Context, dev string) (string, error)
GetDiskfree(ctx context.Context, mnt string) (*types.Diskfree, error)
+ FSFreezeAll(ctx context.Context) (int, error)
+ FSThawAll(ctx context.Context) (int, error)
+ FSFreezeStatus(ctx context.Context) (string, error)
}
// Agent .
@@ -37,9 +41,9 @@ type Agent struct {
}
// New .
-func New(sockfile string) *Agent {
+func New(name string, virt libvirt.Libvirt) *Agent {
return &Agent{
- qmp: newQmp(sockfile, true),
+ qmp: newQmp(name, virt, true),
}
}
diff --git a/internal/virt/agent/agent_test.go b/internal/virt/agent/agent_test.go
index 8c2434e..fd80dae 100644
--- a/internal/virt/agent/agent_test.go
+++ b/internal/virt/agent/agent_test.go
@@ -6,6 +6,7 @@ import (
"encoding/json"
"os"
"testing"
+ "time"
"github.com/projecteru2/yavirt/internal/virt/agent/mocks"
"github.com/projecteru2/yavirt/internal/virt/agent/types"
@@ -14,7 +15,7 @@ import (
)
func TestAgent(t *testing.T) {
- var agent = New("/tmp/virt/sock/guest-000001.sock")
+ var agent = New("00000000001", nil)
var in = "ping"
var out = []byte("pong")
@@ -28,8 +29,8 @@ func TestAgent(t *testing.T) {
var qmp = &mocks.Qmp{}
defer qmp.AssertExpectations(t)
- qmp.On("Exec", mock.Anything, mock.Anything, mock.Anything).Return([]byte(`{"pid":6735}`), nil).Once()
- qmp.On("ExecStatus", 6735).Return(enc, nil).Once()
+ qmp.On("Exec", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]byte(`{"pid":6735}`), nil).Once()
+ qmp.On("ExecStatus", mock.Anything, 6735).Return(enc, nil).Once()
agent.qmp = qmp
var st = <-agent.ExecOutput(context.Background(), in)
@@ -48,24 +49,26 @@ func TestFileReader(t *testing.T) {
return
}
- var agent = New("/opt/yavirtd/sock/00000000010160627254733565100003.sock")
- rd, err := OpenFile(agent, "/tmp/snmpss.cache", "r")
+ ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
+ defer cancel()
+ var agent = New("000000001", nil)
+ rd, err := OpenFile(ctx, agent, "/tmp/snmpss.cache", "r")
assert.NilErr(t, err)
- defer rd.Close()
+ defer rd.Close(ctx)
p := make([]byte, 10)
- n, err := rd.Read(p)
+ n, err := rd.Read(ctx, p)
assert.NilErr(t, err)
assert.Equal(t, 10, n)
t.Logf(" read /tmp/snmpss.cache: %s ", string(p))
- n, err = rd.Read(p)
+ n, err = rd.Read(ctx, p)
assert.NilErr(t, err)
assert.Equal(t, 10, n)
t.Logf(" read /tmp/snmpss.cache: %s ", string(p))
- n, err = rd.Read(p)
+ n, err = rd.Read(ctx, p)
assert.NilErr(t, err)
assert.Equal(t, 9, n)
t.Logf(" read /tmp/snmpss.cache: %s ", string(p))
diff --git a/internal/virt/agent/blk.go b/internal/virt/agent/blk.go
index ea335fa..b5ea267 100644
--- a/internal/virt/agent/blk.go
+++ b/internal/virt/agent/blk.go
@@ -4,7 +4,8 @@ import (
"context"
"regexp"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/yavirt/pkg/terrors"
)
var blkidRegex = regexp.MustCompile(`(?i)uuid="([-a-f0-9]{36})"`)
@@ -14,12 +15,12 @@ func (a *Agent) Blkid(ctx context.Context, dev string) (string, error) {
var st = <-a.ExecOutput(ctx, "blkid", dev)
so, _, err := st.Stdio()
if err != nil {
- return "", errors.Trace(err)
+ return "", errors.Wrap(err, "")
}
var mat = blkidRegex.FindSubmatch(so)
if mat == nil {
- return "", errors.Annotatef(errors.ErrInvalidValue, "invalid blkid: %s", so)
+ return "", errors.Wrapf(terrors.ErrInvalidValue, "invalid blkid: %s", so)
}
return string(mat[1]), nil
diff --git a/internal/virt/agent/df.go b/internal/virt/agent/df.go
index e7dfcc0..5722c3c 100644
--- a/internal/virt/agent/df.go
+++ b/internal/virt/agent/df.go
@@ -6,8 +6,9 @@ import (
"strconv"
"strings"
+ "github.com/cockroachdb/errors"
"github.com/projecteru2/yavirt/internal/virt/agent/types"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/projecteru2/yavirt/pkg/terrors"
"github.com/projecteru2/yavirt/pkg/utils"
)
@@ -19,7 +20,7 @@ func (a *Agent) GetDiskfree(ctx context.Context, mnt string) (*types.Diskfree, e
st := <-a.ExecOutput(ctx, "df", "-k", mnt)
so, _, err := st.Stdio()
if err != nil {
- return nil, errors.Annotatef(err, "df %s failed", mnt)
+ return nil, errors.Wrapf(err, "df %s failed", mnt)
}
return a.parseDiskfree(string(so))
}
@@ -30,7 +31,7 @@ func (a *Agent) parseDiskfree(so string) (*types.Diskfree, error) {
fields := dfRegex.FindStringSubmatch(line)
if len(fields) != 7 {
- return nil, errors.Annotatef(errors.ErrInvalidValue, "invalid df: %s", so)
+ return nil, errors.Wrapf(terrors.ErrInvalidValue, "invalid df: %s", so)
}
df := &types.Diskfree{
@@ -38,10 +39,10 @@ func (a *Agent) parseDiskfree(so string) (*types.Diskfree, error) {
Filesystem: fields[1],
Mount: fields[6],
}
- df.Blocks, _ = utils.Atoi64(fields[2]) //nolint
- df.UsedBlocks, _ = utils.Atoi64(fields[3]) //nolint
- df.AvailableBlocks, _ = utils.Atoi64(fields[4]) //nolint
- df.UsedPercent, _ = strconv.Atoi(fields[5]) //nolint
+ df.Blocks, _ = utils.Atoi64(fields[2])
+ df.UsedBlocks, _ = utils.Atoi64(fields[3])
+ df.AvailableBlocks, _ = utils.Atoi64(fields[4])
+ df.UsedPercent, _ = strconv.Atoi(fields[5])
return df, nil
}
diff --git a/internal/virt/agent/exec.go b/internal/virt/agent/exec.go
index eaa7810..53d55d4 100644
--- a/internal/virt/agent/exec.go
+++ b/internal/virt/agent/exec.go
@@ -4,10 +4,10 @@ import (
"context"
"time"
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/core/log"
"github.com/projecteru2/yavirt/configs"
"github.com/projecteru2/yavirt/internal/virt/agent/types"
- "github.com/projecteru2/yavirt/pkg/errors"
- "github.com/projecteru2/yavirt/pkg/log"
)
// Grep .
@@ -54,7 +54,8 @@ func (a *Agent) touch(ctx context.Context, filepath string) error {
// Ping .
func (a *Agent) Ping(ctx context.Context) error {
- var st = <-a.exec(ctx, "echo", nil, true)
+ // linux and windows both have whoami.
+ var st = <-a.exec(ctx, "whoami", nil, true)
return st.Error()
}
@@ -62,7 +63,7 @@ func (a *Agent) Ping(ctx context.Context) error {
func (a *Agent) ExecBatch(bat *configs.Batch) error {
var ctx = context.Background()
var cancel context.CancelFunc
- if timeout := bat.Timeout.Duration(); timeout > 0 {
+ if timeout := bat.Timeout; timeout > 0 {
ctx, cancel = context.WithTimeout(ctx, timeout)
defer cancel()
}
@@ -71,7 +72,7 @@ func (a *Agent) ExecBatch(bat *configs.Batch) error {
if runOnce {
switch ran, err := a.isFile(ctx, bat.FlagFile); {
case err != nil:
- return errors.Trace(err)
+ return errors.Wrap(err, "")
case ran:
return nil
}
@@ -79,7 +80,7 @@ func (a *Agent) ExecBatch(bat *configs.Batch) error {
switch err := a.execBatch(ctx, bat); {
case err != nil:
- return errors.Trace(err)
+ return errors.Wrap(err, "")
case runOnce:
return a.touch(ctx, bat.FlagFile)
default:
@@ -100,12 +101,12 @@ func (a *Agent) isFolder(ctx context.Context, path string) (bool, error) {
func (a *Agent) execBatch(ctx context.Context, bat *configs.Batch) error {
var cmds, err = bat.GetCommands()
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
for prog, args := range cmds {
if err := a.execRetry(ctx, prog, args, bat); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
}
@@ -123,16 +124,16 @@ func (a *Agent) execRetry(ctx context.Context, prog string, args []string, bat *
select {
case <-ctx.Done():
- return errors.Annotatef(err, "run %s %s timeout", prog, args)
+ return errors.Wrapf(err, "run %s %s timeout", prog, args)
default:
}
if !bat.Retry {
- return errors.Annotatef(err, "run %s %s error", prog, args)
+ return errors.Wrapf(err, "run %s %s error", prog, args)
}
- log.ErrorStackf(err, "run %s %s error, retry it", prog, args)
- time.Sleep(bat.Interval.Duration())
+ log.WithFunc("execRetry").Errorf(ctx, err, "run %s %s error, retry it", prog, args)
+ time.Sleep(bat.Interval)
}
}
@@ -151,7 +152,7 @@ func (a *Agent) exec(ctx context.Context, prog string, args []string, stdio bool
var st types.ExecStatus
var data []byte
- data, st.Err = a.qmp.Exec(prog, args, stdio)
+ data, st.Err = a.qmp.Exec(ctx, prog, args, stdio)
if st.Err != nil {
done <- st
return done
@@ -180,11 +181,11 @@ func (a *Agent) exec(ctx context.Context, prog string, args []string, stdio bool
select {
case <-ctx.Done():
- st.Err = errors.Annotatef(ctx.Err(), "exec %s error", prog)
+ st.Err = errors.Wrapf(ctx.Err(), "exec %s error", prog)
return
case <-next.C:
- if st = a.execStatus(ret.Pid, stdio); st.Err != nil || st.Exited {
+ if st = a.execStatus(ctx, ret.Pid, stdio); st.Err != nil || st.Exited {
return
}
}
@@ -194,15 +195,15 @@ func (a *Agent) exec(ctx context.Context, prog string, args []string, stdio bool
return done
}
-func (a *Agent) execStatus(pid int, _ bool) (st types.ExecStatus) {
- var data, err = a.qmp.ExecStatus(pid)
+func (a *Agent) execStatus(ctx context.Context, pid int, _ bool) (st types.ExecStatus) {
+ var data, err = a.qmp.ExecStatus(ctx, pid)
if err != nil {
- st.Err = errors.Trace(err)
+ st.Err = errors.Wrap(err, "")
return
}
if err := a.decode(data, &st); err != nil {
- st.Err = errors.Trace(err)
+ st.Err = errors.Wrap(err, "")
}
st.Pid = pid
diff --git a/internal/virt/agent/file.go b/internal/virt/agent/file.go
index 55e1636..7ca76df 100644
--- a/internal/virt/agent/file.go
+++ b/internal/virt/agent/file.go
@@ -2,16 +2,18 @@ package agent
import (
"bytes"
+ "context"
"io"
- "github.com/juju/errors"
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/core/log"
)
// OpenFile .
-func (a *Agent) OpenFile(path, mode string) (handle int, err error) {
- buf, err := a.qmp.OpenFile(path, mode)
+func (a *Agent) OpenFile(ctx context.Context, path, mode string) (handle int, err error) {
+ buf, err := a.qmp.OpenFile(ctx, path, mode)
if err != nil {
- return 0, errors.Trace(err)
+ return 0, errors.Wrap(err, "")
}
err = a.decode(buf, &handle)
@@ -20,55 +22,56 @@ func (a *Agent) OpenFile(path, mode string) (handle int, err error) {
}
// CloseFile .
-func (a *Agent) CloseFile(handle int) error {
- return a.qmp.CloseFile(handle)
+func (a *Agent) CloseFile(ctx context.Context, handle int) error {
+ return a.qmp.CloseFile(ctx, handle)
}
// FlushFile .
-func (a *Agent) FlushFile(handle int) error {
- return a.qmp.FlushFile(handle)
+func (a *Agent) FlushFile(ctx context.Context, handle int) error {
+ return a.qmp.FlushFile(ctx, handle)
}
// ReadFile .
-func (a *Agent) ReadFile(handle int, p []byte) (int, bool, error) {
- return a.qmp.ReadFile(handle, p)
+func (a *Agent) ReadFile(ctx context.Context, handle int, p []byte) (int, bool, error) {
+ return a.qmp.ReadFile(ctx, handle, p)
}
// SeekFile .
-func (a *Agent) SeekFile(handle int, offset int, whence int) (position int, eof bool, err error) {
- return a.qmp.SeekFile(handle, offset, whence)
+func (a *Agent) SeekFile(ctx context.Context, handle int, offset int, whence int) (position int, eof bool, err error) {
+ return a.qmp.SeekFile(ctx, handle, offset, whence)
}
// WriteFile .
-func (a *Agent) WriteFile(handle int, buf []byte) error {
- return a.qmp.WriteFile(handle, buf)
+func (a *Agent) WriteFile(ctx context.Context, handle int, buf []byte) error {
+ return a.qmp.WriteFile(ctx, handle, buf)
}
// AppendLine .
-func (a *Agent) AppendLine(filepath string, p []byte) error {
- file, err := OpenFile(a, filepath, "a")
+func (a *Agent) AppendLine(ctx context.Context, filepath string, p []byte) error {
+ file, err := OpenFile(ctx, a, filepath, "a")
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
- defer file.Close()
+ defer file.Close(ctx)
- if _, err := file.WriteLine(p); err != nil {
- return errors.Trace(err)
+ if _, err := file.WriteLine(ctx, p); err != nil {
+ return errors.Wrap(err, "")
}
- return file.Flush()
+ return file.Flush(ctx)
}
type File interface {
- Open() (err error)
- Flush() error
- Close() error
- Read(p []byte) (n int, err error)
- WriteLine(p []byte) (int, error)
- Write(p []byte) (n int, err error)
- Seek(offset, whence int) (pos int, err error)
- ReadAt(dest []byte, pos int) (n int, err error)
- Tail(n int) ([]byte, error)
+ Open(ctx context.Context) (err error)
+ Flush(ctx context.Context) error
+ Close(ctx context.Context) error
+ Read(ctx context.Context, p []byte) (n int, err error)
+ WriteLine(ctx context.Context, p []byte) (int, error)
+ Write(ctx context.Context, p []byte) (n int, err error)
+ Seek(ctx context.Context, offset, whence int) (pos int, err error)
+ ReadAt(ctx context.Context, dest []byte, pos int) (n int, err error)
+ Tail(ctx context.Context, n int) ([]byte, error)
+ CopyTo(ctx context.Context, dst io.Writer) (int, error)
}
// file .
@@ -81,73 +84,73 @@ type file struct {
}
// OpenFile .
-func OpenFile(agent *Agent, path, mode string) (File, error) {
+func OpenFile(ctx context.Context, agent *Agent, path, mode string) (File, error) {
var wr = &file{
agent: agent,
path: path,
mode: mode,
}
- if err := wr.Open(); err != nil {
- return nil, errors.Trace(err)
+ if err := wr.Open(ctx); err != nil {
+ return nil, errors.Wrap(err, "")
}
return wr, nil
}
// Open .
-func (w *file) Open() (err error) {
- w.handle, err = w.agent.OpenFile(w.path, w.mode)
+func (w *file) Open(ctx context.Context) (err error) {
+ w.handle, err = w.agent.OpenFile(ctx, w.path, w.mode)
return
}
// Flush .
-func (w *file) Flush() error {
- return w.agent.FlushFile(w.handle)
+func (w *file) Flush(ctx context.Context) error {
+ return w.agent.FlushFile(ctx, w.handle)
}
// Close .
-func (w *file) Close() error {
- return w.agent.CloseFile(w.handle)
+func (w *file) Close(ctx context.Context) error {
+ return w.agent.CloseFile(ctx, w.handle)
}
// Read .
-func (w *file) Read(p []byte) (n int, err error) {
+func (w *file) Read(ctx context.Context, p []byte) (n int, err error) {
if w.eof {
return 0, io.EOF
}
- n, w.eof, err = w.agent.ReadFile(w.handle, p)
+ n, w.eof, err = w.agent.ReadFile(ctx, w.handle, p)
return
}
// WriteLine .
-func (w *file) WriteLine(p []byte) (int, error) {
- return w.Write(append(p, '\n'))
+func (w *file) WriteLine(ctx context.Context, p []byte) (int, error) {
+ return w.Write(ctx, append(p, '\n'))
}
-func (w *file) Write(p []byte) (n int, err error) {
+func (w *file) Write(ctx context.Context, p []byte) (n int, err error) {
if len(p) < 1 {
return
}
- if err := w.agent.WriteFile(w.handle, p); err != nil {
- return 0, errors.Trace(err)
+ if err := w.agent.WriteFile(ctx, w.handle, p); err != nil {
+ return 0, errors.Wrap(err, "")
}
return
}
// Seek .
-func (w *file) Seek(offset, whence int) (pos int, err error) {
- pos, w.eof, err = w.agent.SeekFile(w.handle, offset, whence)
+func (w *file) Seek(ctx context.Context, offset, whence int) (pos int, err error) {
+ pos, w.eof, err = w.agent.SeekFile(ctx, w.handle, offset, whence)
return
}
// ReadAt .
-func (w *file) ReadAt(dest []byte, pos int) (n int, err error) {
- _, err = w.Seek(pos, io.SeekStart)
+func (w *file) ReadAt(ctx context.Context, dest []byte, pos int) (n int, err error) {
+ _, err = w.Seek(ctx, pos, io.SeekStart)
if err != nil {
return
}
@@ -155,23 +158,23 @@ func (w *file) ReadAt(dest []byte, pos int) (n int, err error) {
return 0, io.EOF
}
- return w.Read(dest)
+ return w.Read(ctx, dest)
}
// Tail .
-func (w *file) Tail(n int) ([]byte, error) {
+func (w *file) Tail(ctx context.Context, n int) ([]byte, error) {
if n < 1 {
return nil, errors.New("not valid tail")
}
- size, err := w.Seek(0, io.SeekEnd)
+ size, err := w.Seek(ctx, 0, io.SeekEnd)
if err != nil {
return nil, err
}
if size == 1 {
tmp := make([]byte, 1)
- _, err = w.Read(tmp)
+ _, err = w.Read(ctx, tmp)
return tmp, err
}
@@ -181,7 +184,7 @@ func (w *file) Tail(n int) ([]byte, error) {
lineEnd := size
cursor := make([]byte, 1)
for i := size - 2; i >= 0; i-- {
- if _, err = w.ReadAt(cursor, i); err != nil {
+ if _, err = w.ReadAt(ctx, cursor, i); err != nil {
return nil, err
}
@@ -199,12 +202,12 @@ func (w *file) Tail(n int) ([]byte, error) {
lineStart = 0
}
- if _, err = w.Seek(lineStart, io.SeekStart); err != nil {
+ if _, err = w.Seek(ctx, lineStart, io.SeekStart); err != nil {
return nil, err
}
newLine := make([]byte, lineEnd-lineStart)
- if _, err = w.Read(newLine); err != nil {
+ if _, err = w.Read(ctx, newLine); err != nil {
return nil, err
}
tmp = append(tmp, newLine)
@@ -220,3 +223,30 @@ func (w *file) Tail(n int) ([]byte, error) {
return buff.Bytes(), nil
}
+
+func (w *file) CopyTo(ctx context.Context, dst io.Writer) (int, error) {
+ var total int
+ for {
+ buf := make([]byte, 65536)
+ nRead, err := w.Read(ctx, buf)
+
+ if err != nil && err != io.EOF {
+ return total, errors.Wrap(err, "")
+ }
+ if nRead > 0 {
+ if bytes.Contains(buf[:nRead], []byte("^]")) {
+ log.WithFunc("CopyTo").Warnf(ctx, "[io.Scan] reader exited: %v", w)
+ return total, errors.New("[CopyTo] reader got ^]")
+ }
+ nWrite, err := dst.Write(buf[:nRead])
+ if err != nil {
+ return total, errors.Wrap(err, "")
+ }
+ total += nWrite
+ }
+ if err == io.EOF {
+ break
+ }
+ }
+ return total, nil
+}
diff --git a/internal/virt/agent/freeze.go b/internal/virt/agent/freeze.go
new file mode 100644
index 0000000..d66de11
--- /dev/null
+++ b/internal/virt/agent/freeze.go
@@ -0,0 +1,31 @@
+package agent
+
+import (
+ "context"
+
+ "github.com/cockroachdb/errors"
+)
+
+func (a *Agent) FSFreezeAll(ctx context.Context) (int, error) {
+ nFS, err := a.qmp.FSFreezeAll(ctx)
+ if err != nil {
+ return 0, errors.Wrap(err, "")
+ }
+ return nFS, nil
+}
+
+func (a *Agent) FSThawAll(ctx context.Context) (int, error) {
+ nFS, err := a.qmp.FSThawAll(ctx)
+ if err != nil {
+ return 0, errors.Wrap(err, "")
+ }
+ return nFS, nil
+}
+
+func (a *Agent) FSFreezeStatus(ctx context.Context) (string, error) {
+ status, err := a.qmp.FSFreezeStatus(ctx)
+ if err != nil {
+ return "", errors.Wrap(err, "")
+ }
+ return status, nil
+}
diff --git a/internal/virt/agent/freeze_test.go b/internal/virt/agent/freeze_test.go
new file mode 100644
index 0000000..eccb6e8
--- /dev/null
+++ b/internal/virt/agent/freeze_test.go
@@ -0,0 +1,31 @@
+package agent
+
+import (
+ "context"
+ "testing"
+
+ "github.com/projecteru2/yavirt/internal/virt/agent/mocks"
+ "github.com/projecteru2/yavirt/pkg/test/assert"
+)
+
+func TestFreeze(t *testing.T) {
+ mockQmp := mocks.NewQmp(t)
+ ag := Agent{
+ qmp: mockQmp,
+ }
+
+ mockQmp.On("FSFreezeAll", context.Background()).Return(1, nil).Once()
+ nFS, err := ag.FSFreezeAll(context.Background())
+ assert.Nil(t, err)
+ assert.Equal(t, 1, nFS)
+
+ mockQmp.On("FSThawAll", context.Background()).Return(1, nil).Once()
+ nFS, err = ag.FSThawAll(context.Background())
+ assert.Nil(t, err)
+ assert.Equal(t, 1, nFS)
+
+ mockQmp.On("FSFreezeStatus", context.Background()).Return("freezed", nil).Once()
+ status, err := ag.FSFreezeStatus(context.Background())
+ assert.Nil(t, err)
+ assert.Equal(t, "freezed", status)
+}
diff --git a/internal/virt/agent/mocks/File.go b/internal/virt/agent/mocks/File.go
index c806f67..d9b643e 100644
--- a/internal/virt/agent/mocks/File.go
+++ b/internal/virt/agent/mocks/File.go
@@ -1,21 +1,26 @@
-// Code generated by mockery v2.26.1. DO NOT EDIT.
+// Code generated by mockery v2.33.2. DO NOT EDIT.
package mocks
-import mock "github.com/stretchr/testify/mock"
+import (
+ context "context"
+ io "io"
+
+ mock "github.com/stretchr/testify/mock"
+)
// File is an autogenerated mock type for the File type
type File struct {
mock.Mock
}
-// Close provides a mock function with given fields:
-func (_m *File) Close() error {
- ret := _m.Called()
+// Close provides a mock function with given fields: ctx
+func (_m *File) Close(ctx context.Context) error {
+ ret := _m.Called(ctx)
var r0 error
- if rf, ok := ret.Get(0).(func() error); ok {
- r0 = rf()
+ if rf, ok := ret.Get(0).(func(context.Context) error); ok {
+ r0 = rf(ctx)
} else {
r0 = ret.Error(0)
}
@@ -23,13 +28,37 @@ func (_m *File) Close() error {
return r0
}
-// Flush provides a mock function with given fields:
-func (_m *File) Flush() error {
- ret := _m.Called()
+// CopyTo provides a mock function with given fields: ctx, dst
+func (_m *File) CopyTo(ctx context.Context, dst io.Writer) (int, error) {
+ ret := _m.Called(ctx, dst)
+
+ var r0 int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, io.Writer) (int, error)); ok {
+ return rf(ctx, dst)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, io.Writer) int); ok {
+ r0 = rf(ctx, dst)
+ } else {
+ r0 = ret.Get(0).(int)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, io.Writer) error); ok {
+ r1 = rf(ctx, dst)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// Flush provides a mock function with given fields: ctx
+func (_m *File) Flush(ctx context.Context) error {
+ ret := _m.Called(ctx)
var r0 error
- if rf, ok := ret.Get(0).(func() error); ok {
- r0 = rf()
+ if rf, ok := ret.Get(0).(func(context.Context) error); ok {
+ r0 = rf(ctx)
} else {
r0 = ret.Error(0)
}
@@ -37,13 +66,13 @@ func (_m *File) Flush() error {
return r0
}
-// Open provides a mock function with given fields:
-func (_m *File) Open() error {
- ret := _m.Called()
+// Open provides a mock function with given fields: ctx
+func (_m *File) Open(ctx context.Context) error {
+ ret := _m.Called(ctx)
var r0 error
- if rf, ok := ret.Get(0).(func() error); ok {
- r0 = rf()
+ if rf, ok := ret.Get(0).(func(context.Context) error); ok {
+ r0 = rf(ctx)
} else {
r0 = ret.Error(0)
}
@@ -51,23 +80,23 @@ func (_m *File) Open() error {
return r0
}
-// Read provides a mock function with given fields: p
-func (_m *File) Read(p []byte) (int, error) {
- ret := _m.Called(p)
+// Read provides a mock function with given fields: ctx, p
+func (_m *File) Read(ctx context.Context, p []byte) (int, error) {
+ ret := _m.Called(ctx, p)
var r0 int
var r1 error
- if rf, ok := ret.Get(0).(func([]byte) (int, error)); ok {
- return rf(p)
+ if rf, ok := ret.Get(0).(func(context.Context, []byte) (int, error)); ok {
+ return rf(ctx, p)
}
- if rf, ok := ret.Get(0).(func([]byte) int); ok {
- r0 = rf(p)
+ if rf, ok := ret.Get(0).(func(context.Context, []byte) int); ok {
+ r0 = rf(ctx, p)
} else {
r0 = ret.Get(0).(int)
}
- if rf, ok := ret.Get(1).(func([]byte) error); ok {
- r1 = rf(p)
+ if rf, ok := ret.Get(1).(func(context.Context, []byte) error); ok {
+ r1 = rf(ctx, p)
} else {
r1 = ret.Error(1)
}
@@ -75,23 +104,23 @@ func (_m *File) Read(p []byte) (int, error) {
return r0, r1
}
-// ReadAt provides a mock function with given fields: dest, pos
-func (_m *File) ReadAt(dest []byte, pos int) (int, error) {
- ret := _m.Called(dest, pos)
+// ReadAt provides a mock function with given fields: ctx, dest, pos
+func (_m *File) ReadAt(ctx context.Context, dest []byte, pos int) (int, error) {
+ ret := _m.Called(ctx, dest, pos)
var r0 int
var r1 error
- if rf, ok := ret.Get(0).(func([]byte, int) (int, error)); ok {
- return rf(dest, pos)
+ if rf, ok := ret.Get(0).(func(context.Context, []byte, int) (int, error)); ok {
+ return rf(ctx, dest, pos)
}
- if rf, ok := ret.Get(0).(func([]byte, int) int); ok {
- r0 = rf(dest, pos)
+ if rf, ok := ret.Get(0).(func(context.Context, []byte, int) int); ok {
+ r0 = rf(ctx, dest, pos)
} else {
r0 = ret.Get(0).(int)
}
- if rf, ok := ret.Get(1).(func([]byte, int) error); ok {
- r1 = rf(dest, pos)
+ if rf, ok := ret.Get(1).(func(context.Context, []byte, int) error); ok {
+ r1 = rf(ctx, dest, pos)
} else {
r1 = ret.Error(1)
}
@@ -99,23 +128,23 @@ func (_m *File) ReadAt(dest []byte, pos int) (int, error) {
return r0, r1
}
-// Seek provides a mock function with given fields: offset, whence
-func (_m *File) Seek(offset int, whence int) (int, error) {
- ret := _m.Called(offset, whence)
+// Seek provides a mock function with given fields: ctx, offset, whence
+func (_m *File) Seek(ctx context.Context, offset int, whence int) (int, error) {
+ ret := _m.Called(ctx, offset, whence)
var r0 int
var r1 error
- if rf, ok := ret.Get(0).(func(int, int) (int, error)); ok {
- return rf(offset, whence)
+ if rf, ok := ret.Get(0).(func(context.Context, int, int) (int, error)); ok {
+ return rf(ctx, offset, whence)
}
- if rf, ok := ret.Get(0).(func(int, int) int); ok {
- r0 = rf(offset, whence)
+ if rf, ok := ret.Get(0).(func(context.Context, int, int) int); ok {
+ r0 = rf(ctx, offset, whence)
} else {
r0 = ret.Get(0).(int)
}
- if rf, ok := ret.Get(1).(func(int, int) error); ok {
- r1 = rf(offset, whence)
+ if rf, ok := ret.Get(1).(func(context.Context, int, int) error); ok {
+ r1 = rf(ctx, offset, whence)
} else {
r1 = ret.Error(1)
}
@@ -123,25 +152,25 @@ func (_m *File) Seek(offset int, whence int) (int, error) {
return r0, r1
}
-// Tail provides a mock function with given fields: n
-func (_m *File) Tail(n int) ([]byte, error) {
- ret := _m.Called(n)
+// Tail provides a mock function with given fields: ctx, n
+func (_m *File) Tail(ctx context.Context, n int) ([]byte, error) {
+ ret := _m.Called(ctx, n)
var r0 []byte
var r1 error
- if rf, ok := ret.Get(0).(func(int) ([]byte, error)); ok {
- return rf(n)
+ if rf, ok := ret.Get(0).(func(context.Context, int) ([]byte, error)); ok {
+ return rf(ctx, n)
}
- if rf, ok := ret.Get(0).(func(int) []byte); ok {
- r0 = rf(n)
+ if rf, ok := ret.Get(0).(func(context.Context, int) []byte); ok {
+ r0 = rf(ctx, n)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]byte)
}
}
- if rf, ok := ret.Get(1).(func(int) error); ok {
- r1 = rf(n)
+ if rf, ok := ret.Get(1).(func(context.Context, int) error); ok {
+ r1 = rf(ctx, n)
} else {
r1 = ret.Error(1)
}
@@ -149,23 +178,23 @@ func (_m *File) Tail(n int) ([]byte, error) {
return r0, r1
}
-// Write provides a mock function with given fields: p
-func (_m *File) Write(p []byte) (int, error) {
- ret := _m.Called(p)
+// Write provides a mock function with given fields: ctx, p
+func (_m *File) Write(ctx context.Context, p []byte) (int, error) {
+ ret := _m.Called(ctx, p)
var r0 int
var r1 error
- if rf, ok := ret.Get(0).(func([]byte) (int, error)); ok {
- return rf(p)
+ if rf, ok := ret.Get(0).(func(context.Context, []byte) (int, error)); ok {
+ return rf(ctx, p)
}
- if rf, ok := ret.Get(0).(func([]byte) int); ok {
- r0 = rf(p)
+ if rf, ok := ret.Get(0).(func(context.Context, []byte) int); ok {
+ r0 = rf(ctx, p)
} else {
r0 = ret.Get(0).(int)
}
- if rf, ok := ret.Get(1).(func([]byte) error); ok {
- r1 = rf(p)
+ if rf, ok := ret.Get(1).(func(context.Context, []byte) error); ok {
+ r1 = rf(ctx, p)
} else {
r1 = ret.Error(1)
}
@@ -173,23 +202,23 @@ func (_m *File) Write(p []byte) (int, error) {
return r0, r1
}
-// WriteLine provides a mock function with given fields: p
-func (_m *File) WriteLine(p []byte) (int, error) {
- ret := _m.Called(p)
+// WriteLine provides a mock function with given fields: ctx, p
+func (_m *File) WriteLine(ctx context.Context, p []byte) (int, error) {
+ ret := _m.Called(ctx, p)
var r0 int
var r1 error
- if rf, ok := ret.Get(0).(func([]byte) (int, error)); ok {
- return rf(p)
+ if rf, ok := ret.Get(0).(func(context.Context, []byte) (int, error)); ok {
+ return rf(ctx, p)
}
- if rf, ok := ret.Get(0).(func([]byte) int); ok {
- r0 = rf(p)
+ if rf, ok := ret.Get(0).(func(context.Context, []byte) int); ok {
+ r0 = rf(ctx, p)
} else {
r0 = ret.Get(0).(int)
}
- if rf, ok := ret.Get(1).(func([]byte) error); ok {
- r1 = rf(p)
+ if rf, ok := ret.Get(1).(func(context.Context, []byte) error); ok {
+ r1 = rf(ctx, p)
} else {
r1 = ret.Error(1)
}
@@ -197,13 +226,12 @@ func (_m *File) WriteLine(p []byte) (int, error) {
return r0, r1
}
-type mockConstructorTestingTNewFile interface {
+// NewFile creates a new instance of File. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func NewFile(t interface {
mock.TestingT
Cleanup(func())
-}
-
-// NewFile creates a new instance of File. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-func NewFile(t mockConstructorTestingTNewFile) *File {
+}) *File {
mock := &File{}
mock.Mock.Test(t)
diff --git a/internal/virt/agent/mocks/Interface.go b/internal/virt/agent/mocks/Interface.go
index 41e3766..a4e670c 100644
--- a/internal/virt/agent/mocks/Interface.go
+++ b/internal/virt/agent/mocks/Interface.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.26.1. DO NOT EDIT.
+// Code generated by mockery v2.33.2. DO NOT EDIT.
package mocks
@@ -17,13 +17,13 @@ type Interface struct {
mock.Mock
}
-// AppendLine provides a mock function with given fields: filepath, p
-func (_m *Interface) AppendLine(filepath string, p []byte) error {
- ret := _m.Called(filepath, p)
+// AppendLine provides a mock function with given fields: ctx, filepath, p
+func (_m *Interface) AppendLine(ctx context.Context, filepath string, p []byte) error {
+ ret := _m.Called(ctx, filepath, p)
var r0 error
- if rf, ok := ret.Get(0).(func(string, []byte) error); ok {
- r0 = rf(filepath, p)
+ if rf, ok := ret.Get(0).(func(context.Context, string, []byte) error); ok {
+ r0 = rf(ctx, filepath, p)
} else {
r0 = ret.Error(0)
}
@@ -69,13 +69,13 @@ func (_m *Interface) Close() error {
return r0
}
-// CloseFile provides a mock function with given fields: handle
-func (_m *Interface) CloseFile(handle int) error {
- ret := _m.Called(handle)
+// CloseFile provides a mock function with given fields: ctx, handle
+func (_m *Interface) CloseFile(ctx context.Context, handle int) error {
+ ret := _m.Called(ctx, handle)
var r0 error
- if rf, ok := ret.Get(0).(func(int) error); ok {
- r0 = rf(handle)
+ if rf, ok := ret.Get(0).(func(context.Context, int) error); ok {
+ r0 = rf(ctx, handle)
} else {
r0 = ret.Error(0)
}
@@ -143,13 +143,85 @@ func (_m *Interface) ExecOutput(ctx context.Context, prog string, args ...string
return r0
}
-// FlushFile provides a mock function with given fields: handle
-func (_m *Interface) FlushFile(handle int) error {
- ret := _m.Called(handle)
+// FSFreezeAll provides a mock function with given fields: ctx
+func (_m *Interface) FSFreezeAll(ctx context.Context) (int, error) {
+ ret := _m.Called(ctx)
+
+ var r0 int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (int, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) int); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Get(0).(int)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// FSFreezeStatus provides a mock function with given fields: ctx
+func (_m *Interface) FSFreezeStatus(ctx context.Context) (string, error) {
+ ret := _m.Called(ctx)
+
+ var r0 string
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (string, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) string); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Get(0).(string)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// FSThawAll provides a mock function with given fields: ctx
+func (_m *Interface) FSThawAll(ctx context.Context) (int, error) {
+ ret := _m.Called(ctx)
+
+ var r0 int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (int, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) int); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Get(0).(int)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// FlushFile provides a mock function with given fields: ctx, handle
+func (_m *Interface) FlushFile(ctx context.Context, handle int) error {
+ ret := _m.Called(ctx, handle)
var r0 error
- if rf, ok := ret.Get(0).(func(int) error); ok {
- r0 = rf(handle)
+ if rf, ok := ret.Get(0).(func(context.Context, int) error); ok {
+ r0 = rf(ctx, handle)
} else {
r0 = ret.Error(0)
}
@@ -255,23 +327,23 @@ func (_m *Interface) IsFolder(ctx context.Context, path string) (bool, error) {
return r0, r1
}
-// OpenFile provides a mock function with given fields: path, mode
-func (_m *Interface) OpenFile(path string, mode string) (int, error) {
- ret := _m.Called(path, mode)
+// OpenFile provides a mock function with given fields: ctx, path, mode
+func (_m *Interface) OpenFile(ctx context.Context, path string, mode string) (int, error) {
+ ret := _m.Called(ctx, path, mode)
var r0 int
var r1 error
- if rf, ok := ret.Get(0).(func(string, string) (int, error)); ok {
- return rf(path, mode)
+ if rf, ok := ret.Get(0).(func(context.Context, string, string) (int, error)); ok {
+ return rf(ctx, path, mode)
}
- if rf, ok := ret.Get(0).(func(string, string) int); ok {
- r0 = rf(path, mode)
+ if rf, ok := ret.Get(0).(func(context.Context, string, string) int); ok {
+ r0 = rf(ctx, path, mode)
} else {
r0 = ret.Get(0).(int)
}
- if rf, ok := ret.Get(1).(func(string, string) error); ok {
- r1 = rf(path, mode)
+ if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok {
+ r1 = rf(ctx, path, mode)
} else {
r1 = ret.Error(1)
}
@@ -293,30 +365,30 @@ func (_m *Interface) Ping(ctx context.Context) error {
return r0
}
-// ReadFile provides a mock function with given fields: handle, p
-func (_m *Interface) ReadFile(handle int, p []byte) (int, bool, error) {
- ret := _m.Called(handle, p)
+// ReadFile provides a mock function with given fields: ctx, handle, p
+func (_m *Interface) ReadFile(ctx context.Context, handle int, p []byte) (int, bool, error) {
+ ret := _m.Called(ctx, handle, p)
var r0 int
var r1 bool
var r2 error
- if rf, ok := ret.Get(0).(func(int, []byte) (int, bool, error)); ok {
- return rf(handle, p)
+ if rf, ok := ret.Get(0).(func(context.Context, int, []byte) (int, bool, error)); ok {
+ return rf(ctx, handle, p)
}
- if rf, ok := ret.Get(0).(func(int, []byte) int); ok {
- r0 = rf(handle, p)
+ if rf, ok := ret.Get(0).(func(context.Context, int, []byte) int); ok {
+ r0 = rf(ctx, handle, p)
} else {
r0 = ret.Get(0).(int)
}
- if rf, ok := ret.Get(1).(func(int, []byte) bool); ok {
- r1 = rf(handle, p)
+ if rf, ok := ret.Get(1).(func(context.Context, int, []byte) bool); ok {
+ r1 = rf(ctx, handle, p)
} else {
r1 = ret.Get(1).(bool)
}
- if rf, ok := ret.Get(2).(func(int, []byte) error); ok {
- r2 = rf(handle, p)
+ if rf, ok := ret.Get(2).(func(context.Context, int, []byte) error); ok {
+ r2 = rf(ctx, handle, p)
} else {
r2 = ret.Error(2)
}
@@ -338,30 +410,30 @@ func (_m *Interface) RemoveAll(ctx context.Context, path string) error {
return r0
}
-// SeekFile provides a mock function with given fields: handle, offset, whence
-func (_m *Interface) SeekFile(handle int, offset int, whence int) (int, bool, error) {
- ret := _m.Called(handle, offset, whence)
+// SeekFile provides a mock function with given fields: ctx, handle, offset, whence
+func (_m *Interface) SeekFile(ctx context.Context, handle int, offset int, whence int) (int, bool, error) {
+ ret := _m.Called(ctx, handle, offset, whence)
var r0 int
var r1 bool
var r2 error
- if rf, ok := ret.Get(0).(func(int, int, int) (int, bool, error)); ok {
- return rf(handle, offset, whence)
+ if rf, ok := ret.Get(0).(func(context.Context, int, int, int) (int, bool, error)); ok {
+ return rf(ctx, handle, offset, whence)
}
- if rf, ok := ret.Get(0).(func(int, int, int) int); ok {
- r0 = rf(handle, offset, whence)
+ if rf, ok := ret.Get(0).(func(context.Context, int, int, int) int); ok {
+ r0 = rf(ctx, handle, offset, whence)
} else {
r0 = ret.Get(0).(int)
}
- if rf, ok := ret.Get(1).(func(int, int, int) bool); ok {
- r1 = rf(handle, offset, whence)
+ if rf, ok := ret.Get(1).(func(context.Context, int, int, int) bool); ok {
+ r1 = rf(ctx, handle, offset, whence)
} else {
r1 = ret.Get(1).(bool)
}
- if rf, ok := ret.Get(2).(func(int, int, int) error); ok {
- r2 = rf(handle, offset, whence)
+ if rf, ok := ret.Get(2).(func(context.Context, int, int, int) error); ok {
+ r2 = rf(ctx, handle, offset, whence)
} else {
r2 = ret.Error(2)
}
@@ -383,13 +455,13 @@ func (_m *Interface) Touch(ctx context.Context, filepath string) error {
return r0
}
-// WriteFile provides a mock function with given fields: handle, buf
-func (_m *Interface) WriteFile(handle int, buf []byte) error {
- ret := _m.Called(handle, buf)
+// WriteFile provides a mock function with given fields: ctx, handle, buf
+func (_m *Interface) WriteFile(ctx context.Context, handle int, buf []byte) error {
+ ret := _m.Called(ctx, handle, buf)
var r0 error
- if rf, ok := ret.Get(0).(func(int, []byte) error); ok {
- r0 = rf(handle, buf)
+ if rf, ok := ret.Get(0).(func(context.Context, int, []byte) error); ok {
+ r0 = rf(ctx, handle, buf)
} else {
r0 = ret.Error(0)
}
@@ -397,13 +469,12 @@ func (_m *Interface) WriteFile(handle int, buf []byte) error {
return r0
}
-type mockConstructorTestingTNewInterface interface {
+// NewInterface creates a new instance of Interface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func NewInterface(t interface {
mock.TestingT
Cleanup(func())
-}
-
-// NewInterface creates a new instance of Interface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-func NewInterface(t mockConstructorTestingTNewInterface) *Interface {
+}) *Interface {
mock := &Interface{}
mock.Mock.Test(t)
diff --git a/internal/virt/agent/mocks/Qmp.go b/internal/virt/agent/mocks/Qmp.go
index cdb8bce..47447cd 100644
--- a/internal/virt/agent/mocks/Qmp.go
+++ b/internal/virt/agent/mocks/Qmp.go
@@ -1,8 +1,12 @@
-// Code generated by mockery v2.26.1. DO NOT EDIT.
+// Code generated by mockery v2.33.2. DO NOT EDIT.
package mocks
-import mock "github.com/stretchr/testify/mock"
+import (
+ context "context"
+
+ mock "github.com/stretchr/testify/mock"
+)
// Qmp is an autogenerated mock type for the Qmp type
type Qmp struct {
@@ -23,13 +27,13 @@ func (_m *Qmp) Close() error {
return r0
}
-// CloseFile provides a mock function with given fields: handle
-func (_m *Qmp) CloseFile(handle int) error {
- ret := _m.Called(handle)
+// CloseFile provides a mock function with given fields: ctx, handle
+func (_m *Qmp) CloseFile(ctx context.Context, handle int) error {
+ ret := _m.Called(ctx, handle)
var r0 error
- if rf, ok := ret.Get(0).(func(int) error); ok {
- r0 = rf(handle)
+ if rf, ok := ret.Get(0).(func(context.Context, int) error); ok {
+ r0 = rf(ctx, handle)
} else {
r0 = ret.Error(0)
}
@@ -37,25 +41,25 @@ func (_m *Qmp) CloseFile(handle int) error {
return r0
}
-// Exec provides a mock function with given fields: cmd, args, stdio
-func (_m *Qmp) Exec(cmd string, args []string, stdio bool) ([]byte, error) {
- ret := _m.Called(cmd, args, stdio)
+// Exec provides a mock function with given fields: ctx, cmd, args, stdio
+func (_m *Qmp) Exec(ctx context.Context, cmd string, args []string, stdio bool) ([]byte, error) {
+ ret := _m.Called(ctx, cmd, args, stdio)
var r0 []byte
var r1 error
- if rf, ok := ret.Get(0).(func(string, []string, bool) ([]byte, error)); ok {
- return rf(cmd, args, stdio)
+ if rf, ok := ret.Get(0).(func(context.Context, string, []string, bool) ([]byte, error)); ok {
+ return rf(ctx, cmd, args, stdio)
}
- if rf, ok := ret.Get(0).(func(string, []string, bool) []byte); ok {
- r0 = rf(cmd, args, stdio)
+ if rf, ok := ret.Get(0).(func(context.Context, string, []string, bool) []byte); ok {
+ r0 = rf(ctx, cmd, args, stdio)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]byte)
}
}
- if rf, ok := ret.Get(1).(func(string, []string, bool) error); ok {
- r1 = rf(cmd, args, stdio)
+ if rf, ok := ret.Get(1).(func(context.Context, string, []string, bool) error); ok {
+ r1 = rf(ctx, cmd, args, stdio)
} else {
r1 = ret.Error(1)
}
@@ -63,25 +67,121 @@ func (_m *Qmp) Exec(cmd string, args []string, stdio bool) ([]byte, error) {
return r0, r1
}
-// ExecStatus provides a mock function with given fields: pid
-func (_m *Qmp) ExecStatus(pid int) ([]byte, error) {
- ret := _m.Called(pid)
+// ExecStatus provides a mock function with given fields: ctx, pid
+func (_m *Qmp) ExecStatus(ctx context.Context, pid int) ([]byte, error) {
+ ret := _m.Called(ctx, pid)
var r0 []byte
var r1 error
- if rf, ok := ret.Get(0).(func(int) ([]byte, error)); ok {
- return rf(pid)
+ if rf, ok := ret.Get(0).(func(context.Context, int) ([]byte, error)); ok {
+ return rf(ctx, pid)
}
- if rf, ok := ret.Get(0).(func(int) []byte); ok {
- r0 = rf(pid)
+ if rf, ok := ret.Get(0).(func(context.Context, int) []byte); ok {
+ r0 = rf(ctx, pid)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]byte)
}
}
- if rf, ok := ret.Get(1).(func(int) error); ok {
- r1 = rf(pid)
+ if rf, ok := ret.Get(1).(func(context.Context, int) error); ok {
+ r1 = rf(ctx, pid)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// FSFreezeAll provides a mock function with given fields: ctx
+func (_m *Qmp) FSFreezeAll(ctx context.Context) (int, error) {
+ ret := _m.Called(ctx)
+
+ var r0 int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (int, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) int); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Get(0).(int)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// FSFreezeList provides a mock function with given fields: ctx, mountpoints
+func (_m *Qmp) FSFreezeList(ctx context.Context, mountpoints []string) (int, error) {
+ ret := _m.Called(ctx, mountpoints)
+
+ var r0 int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, []string) (int, error)); ok {
+ return rf(ctx, mountpoints)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, []string) int); ok {
+ r0 = rf(ctx, mountpoints)
+ } else {
+ r0 = ret.Get(0).(int)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, []string) error); ok {
+ r1 = rf(ctx, mountpoints)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// FSFreezeStatus provides a mock function with given fields: ctx
+func (_m *Qmp) FSFreezeStatus(ctx context.Context) (string, error) {
+ ret := _m.Called(ctx)
+
+ var r0 string
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (string, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) string); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Get(0).(string)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// FSThawAll provides a mock function with given fields: ctx
+func (_m *Qmp) FSThawAll(ctx context.Context) (int, error) {
+ ret := _m.Called(ctx)
+
+ var r0 int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (int, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) int); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Get(0).(int)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
} else {
r1 = ret.Error(1)
}
@@ -89,13 +189,13 @@ func (_m *Qmp) ExecStatus(pid int) ([]byte, error) {
return r0, r1
}
-// FlushFile provides a mock function with given fields: handle
-func (_m *Qmp) FlushFile(handle int) error {
- ret := _m.Called(handle)
+// FlushFile provides a mock function with given fields: ctx, handle
+func (_m *Qmp) FlushFile(ctx context.Context, handle int) error {
+ ret := _m.Called(ctx, handle)
var r0 error
- if rf, ok := ret.Get(0).(func(int) error); ok {
- r0 = rf(handle)
+ if rf, ok := ret.Get(0).(func(context.Context, int) error); ok {
+ r0 = rf(ctx, handle)
} else {
r0 = ret.Error(0)
}
@@ -103,25 +203,39 @@ func (_m *Qmp) FlushFile(handle int) error {
return r0
}
-// OpenFile provides a mock function with given fields: path, mode
-func (_m *Qmp) OpenFile(path string, mode string) ([]byte, error) {
- ret := _m.Called(path, mode)
+// GetName provides a mock function with given fields:
+func (_m *Qmp) GetName() string {
+ ret := _m.Called()
+
+ var r0 string
+ if rf, ok := ret.Get(0).(func() string); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Get(0).(string)
+ }
+
+ return r0
+}
+
+// OpenFile provides a mock function with given fields: ctx, path, mode
+func (_m *Qmp) OpenFile(ctx context.Context, path string, mode string) ([]byte, error) {
+ ret := _m.Called(ctx, path, mode)
var r0 []byte
var r1 error
- if rf, ok := ret.Get(0).(func(string, string) ([]byte, error)); ok {
- return rf(path, mode)
+ if rf, ok := ret.Get(0).(func(context.Context, string, string) ([]byte, error)); ok {
+ return rf(ctx, path, mode)
}
- if rf, ok := ret.Get(0).(func(string, string) []byte); ok {
- r0 = rf(path, mode)
+ if rf, ok := ret.Get(0).(func(context.Context, string, string) []byte); ok {
+ r0 = rf(ctx, path, mode)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]byte)
}
}
- if rf, ok := ret.Get(1).(func(string, string) error); ok {
- r1 = rf(path, mode)
+ if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok {
+ r1 = rf(ctx, path, mode)
} else {
r1 = ret.Error(1)
}
@@ -129,30 +243,30 @@ func (_m *Qmp) OpenFile(path string, mode string) ([]byte, error) {
return r0, r1
}
-// ReadFile provides a mock function with given fields: handle, p
-func (_m *Qmp) ReadFile(handle int, p []byte) (int, bool, error) {
- ret := _m.Called(handle, p)
+// ReadFile provides a mock function with given fields: ctx, handle, p
+func (_m *Qmp) ReadFile(ctx context.Context, handle int, p []byte) (int, bool, error) {
+ ret := _m.Called(ctx, handle, p)
var r0 int
var r1 bool
var r2 error
- if rf, ok := ret.Get(0).(func(int, []byte) (int, bool, error)); ok {
- return rf(handle, p)
+ if rf, ok := ret.Get(0).(func(context.Context, int, []byte) (int, bool, error)); ok {
+ return rf(ctx, handle, p)
}
- if rf, ok := ret.Get(0).(func(int, []byte) int); ok {
- r0 = rf(handle, p)
+ if rf, ok := ret.Get(0).(func(context.Context, int, []byte) int); ok {
+ r0 = rf(ctx, handle, p)
} else {
r0 = ret.Get(0).(int)
}
- if rf, ok := ret.Get(1).(func(int, []byte) bool); ok {
- r1 = rf(handle, p)
+ if rf, ok := ret.Get(1).(func(context.Context, int, []byte) bool); ok {
+ r1 = rf(ctx, handle, p)
} else {
r1 = ret.Get(1).(bool)
}
- if rf, ok := ret.Get(2).(func(int, []byte) error); ok {
- r2 = rf(handle, p)
+ if rf, ok := ret.Get(2).(func(context.Context, int, []byte) error); ok {
+ r2 = rf(ctx, handle, p)
} else {
r2 = ret.Error(2)
}
@@ -160,30 +274,30 @@ func (_m *Qmp) ReadFile(handle int, p []byte) (int, bool, error) {
return r0, r1, r2
}
-// SeekFile provides a mock function with given fields: handle, offset, whence
-func (_m *Qmp) SeekFile(handle int, offset int, whence int) (int, bool, error) {
- ret := _m.Called(handle, offset, whence)
+// SeekFile provides a mock function with given fields: ctx, handle, offset, whence
+func (_m *Qmp) SeekFile(ctx context.Context, handle int, offset int, whence int) (int, bool, error) {
+ ret := _m.Called(ctx, handle, offset, whence)
var r0 int
var r1 bool
var r2 error
- if rf, ok := ret.Get(0).(func(int, int, int) (int, bool, error)); ok {
- return rf(handle, offset, whence)
+ if rf, ok := ret.Get(0).(func(context.Context, int, int, int) (int, bool, error)); ok {
+ return rf(ctx, handle, offset, whence)
}
- if rf, ok := ret.Get(0).(func(int, int, int) int); ok {
- r0 = rf(handle, offset, whence)
+ if rf, ok := ret.Get(0).(func(context.Context, int, int, int) int); ok {
+ r0 = rf(ctx, handle, offset, whence)
} else {
r0 = ret.Get(0).(int)
}
- if rf, ok := ret.Get(1).(func(int, int, int) bool); ok {
- r1 = rf(handle, offset, whence)
+ if rf, ok := ret.Get(1).(func(context.Context, int, int, int) bool); ok {
+ r1 = rf(ctx, handle, offset, whence)
} else {
r1 = ret.Get(1).(bool)
}
- if rf, ok := ret.Get(2).(func(int, int, int) error); ok {
- r2 = rf(handle, offset, whence)
+ if rf, ok := ret.Get(2).(func(context.Context, int, int, int) error); ok {
+ r2 = rf(ctx, handle, offset, whence)
} else {
r2 = ret.Error(2)
}
@@ -191,13 +305,13 @@ func (_m *Qmp) SeekFile(handle int, offset int, whence int) (int, bool, error) {
return r0, r1, r2
}
-// WriteFile provides a mock function with given fields: handle, buf
-func (_m *Qmp) WriteFile(handle int, buf []byte) error {
- ret := _m.Called(handle, buf)
+// WriteFile provides a mock function with given fields: ctx, handle, buf
+func (_m *Qmp) WriteFile(ctx context.Context, handle int, buf []byte) error {
+ ret := _m.Called(ctx, handle, buf)
var r0 error
- if rf, ok := ret.Get(0).(func(int, []byte) error); ok {
- r0 = rf(handle, buf)
+ if rf, ok := ret.Get(0).(func(context.Context, int, []byte) error); ok {
+ r0 = rf(ctx, handle, buf)
} else {
r0 = ret.Error(0)
}
@@ -205,13 +319,12 @@ func (_m *Qmp) WriteFile(handle int, buf []byte) error {
return r0
}
-type mockConstructorTestingTNewQmp interface {
+// NewQmp creates a new instance of Qmp. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func NewQmp(t interface {
mock.TestingT
Cleanup(func())
-}
-
-// NewQmp creates a new instance of Qmp. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-func NewQmp(t mockConstructorTestingTNewQmp) *Qmp {
+}) *Qmp {
mock := &Qmp{}
mock.Mock.Test(t)
diff --git a/internal/virt/agent/parted.go b/internal/virt/agent/parted.go
index a257af8..3bcc3d4 100644
--- a/internal/virt/agent/parted.go
+++ b/internal/virt/agent/parted.go
@@ -4,7 +4,8 @@ import (
"context"
"regexp"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/yavirt/pkg/terrors"
"github.com/projecteru2/yavirt/pkg/utils"
)
@@ -30,7 +31,7 @@ func (p Parted) GetSize(ctx context.Context) (int64, error) {
st := <-p.ga.ExecOutput(ctx, "parted", "-s", p.dev, "unit", "B", "p")
so, _, err := st.Stdio()
if err != nil {
- return 0, errors.Annotatef(err, "parted %s print failed", p.dev)
+ return 0, errors.Wrapf(err, "parted %s print failed", p.dev)
}
return p.getSize(string(so))
}
@@ -38,7 +39,7 @@ func (p Parted) GetSize(ctx context.Context) (int64, error) {
func (p Parted) getSize(so string) (int64, error) {
mat := printSizeRegex.FindStringSubmatch(so)
if len(mat) != 2 {
- return 0, errors.Annotatef(errors.ErrInvalidValue, "invalid parted: %s", so)
+ return 0, errors.Wrapf(terrors.ErrInvalidValue, "invalid parted: %s", so)
}
return utils.Atoi64(mat[1])
diff --git a/internal/virt/agent/qmp.go b/internal/virt/agent/qmp.go
index f815bfb..cb40fff 100644
--- a/internal/virt/agent/qmp.go
+++ b/internal/virt/agent/qmp.go
@@ -1,34 +1,41 @@
package agent
import (
- "bufio"
+ "context"
"encoding/base64"
"encoding/json"
"fmt"
"net"
+ "strconv"
"sync"
- "github.com/projecteru2/yavirt/configs"
- "github.com/projecteru2/yavirt/pkg/errors"
- "github.com/projecteru2/yavirt/pkg/log"
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/core/log"
"github.com/projecteru2/yavirt/pkg/utils"
+
+ "github.com/projecteru2/yavirt/pkg/libvirt"
)
const maxBytesPerRead = 32 * utils.MB // ref https://www.qemu.org/docs/master/interop/qemu-ga-ref.html
// Qmp .
-type Qmp interface {
+type Qmp interface { //nolint:interfacebloat
Close() error
- Exec(cmd string, args []string, stdio bool) ([]byte, error)
- ExecStatus(pid int) ([]byte, error)
-
- OpenFile(path, mode string) ([]byte, error)
- FlushFile(handle int) error
- WriteFile(handle int, buf []byte) error
- ReadFile(handle int, p []byte) (read int, eof bool, err error)
- CloseFile(handle int) error
- SeekFile(handle int, offset int, whence int) (position int, eof bool, err error)
+ Exec(ctx context.Context, cmd string, args []string, stdio bool) ([]byte, error)
+ ExecStatus(ctx context.Context, pid int) ([]byte, error)
+
+ OpenFile(ctx context.Context, path, mode string) ([]byte, error)
+ FlushFile(ctx context.Context, handle int) error
+ WriteFile(ctx context.Context, handle int, buf []byte) error
+ ReadFile(ctx context.Context, handle int, p []byte) (read int, eof bool, err error)
+ CloseFile(ctx context.Context, handle int) error
+ SeekFile(ctx context.Context, handle int, offset int, whence int) (position int, eof bool, err error)
+ FSFreezeAll(ctx context.Context) (nFS int, err error)
+ FSFreezeList(ctx context.Context, mountpoints []string) (nFS int, err error)
+ FSThawAll(ctx context.Context) (nFS int, err error)
+ FSFreezeStatus(ctx context.Context) (status string, err error)
+ GetName() string
}
type qmp struct {
@@ -38,12 +45,11 @@ type qmp struct {
// the false value indicates virsh qemu-monitor-command.
ga bool
- sockfile string
- sock net.Conn
- reader *bufio.Reader
- writer *bufio.Writer
-
- greeting *json.RawMessage
+ // sockfile string
+ name string
+ sock net.Conn
+ virt libvirt.Libvirt
+ dom libvirt.Domain
}
type qmpResp struct {
@@ -62,14 +68,27 @@ func (e *qmpError) Error() string {
return fmt.Sprintf("QMP error %s: %s", e.Class, e.Desc)
}
-func newQmp(sockfile string, ga bool) *qmp {
+func newQmp(name string, virt libvirt.Libvirt, ga bool) *qmp {
return &qmp{
- sockfile: sockfile,
- ga: ga,
+ name: name,
+ virt: virt,
+ ga: ga,
}
}
-func (q *qmp) Exec(path string, args []string, output bool) ([]byte, error) {
+func (q *qmp) initIfNecessary() error {
+ if q.dom != nil {
+ return nil
+ }
+ dom, err := q.virt.LookupDomain(q.name)
+ if err != nil {
+ return err
+ }
+ q.dom = dom
+ return nil
+}
+
+func (q *qmp) Exec(ctx context.Context, path string, args []string, output bool) ([]byte, error) {
q.Lock()
defer q.Unlock()
@@ -81,39 +100,39 @@ func (q *qmp) Exec(path string, args []string, output bool) ([]byte, error) {
exArg["arg"] = args
}
- log.Debugf("exec %s with %v", path, args)
+ log.WithFunc("qmp.Exec").Debugf(ctx, "exec %s with %v", path, args)
- return q.exec("guest-exec", exArg)
+ return q.exec(ctx, "guest-exec", exArg)
}
-func (q *qmp) ExecStatus(pid int) ([]byte, error) {
+func (q *qmp) ExecStatus(ctx context.Context, pid int) ([]byte, error) {
q.Lock()
defer q.Unlock()
- return q.exec("guest-exec-status", map[string]any{"pid": pid})
+ return q.exec(ctx, "guest-exec-status", map[string]any{"pid": pid})
}
-func (q *qmp) OpenFile(path, mode string) ([]byte, error) {
+func (q *qmp) OpenFile(ctx context.Context, path, mode string) ([]byte, error) {
q.Lock()
defer q.Unlock()
- return q.exec("guest-file-open", map[string]any{"path": path, "mode": mode})
+ return q.exec(ctx, "guest-file-open", map[string]any{"path": path, "mode": mode})
}
-func (q *qmp) CloseFile(handle int) (err error) {
+func (q *qmp) CloseFile(ctx context.Context, handle int) (err error) {
q.Lock()
defer q.Unlock()
- _, err = q.exec("guest-file-close", map[string]any{"handle": handle})
+ _, err = q.exec(ctx, "guest-file-close", map[string]any{"handle": handle})
return
}
-func (q *qmp) FlushFile(handle int) (err error) {
+func (q *qmp) FlushFile(ctx context.Context, handle int) (err error) {
q.Lock()
defer q.Unlock()
- _, err = q.exec("guest-file-flush", map[string]any{"handle": handle})
+ _, err = q.exec(ctx, "guest-file-flush", map[string]any{"handle": handle})
return
}
// ReadFile .
-func (q *qmp) ReadFile(handle int, p []byte) (read int, eof bool, err error) {
+func (q *qmp) ReadFile(ctx context.Context, handle int, p []byte) (read int, eof bool, err error) {
pcap := int64(cap(p))
args := map[string]any{
"handle": handle,
@@ -125,7 +144,7 @@ func (q *qmp) ReadFile(handle int, p []byte) (read int, eof bool, err error) {
for {
var buf []byte
- if buf, err = q.exec("guest-file-read", args); err != nil {
+ if buf, err = q.exec(ctx, "guest-file-read", args); err != nil {
return
}
@@ -157,32 +176,83 @@ func (q *qmp) ReadFile(handle int, p []byte) (read int, eof bool, err error) {
}
}
-func (q *qmp) WriteFile(handle int, buf []byte) (err error) {
+func (q *qmp) WriteFile(ctx context.Context, handle int, buf []byte) (err error) {
q.Lock()
defer q.Unlock()
var b64 = base64.StdEncoding.EncodeToString(buf)
- _, err = q.exec("guest-file-write", map[string]any{"handle": handle, "buf-b64": b64})
+ _, err = q.exec(ctx, "guest-file-write", map[string]any{"handle": handle, "buf-b64": b64})
return
}
-func (q *qmp) exec(cmd string, args map[string]any) ([]byte, error) {
- var buf, err = newQmpCmd(cmd, args).bytes()
- if err != nil {
- return nil, errors.Trace(err)
+func (q *qmp) FSFreezeAll(ctx context.Context) (nFS int, err error) {
+ q.Lock()
+ defer q.Unlock()
+
+ var bs []byte
+ if bs, err = q.exec(ctx, "guest-fsfreeze-freeze", nil); err != nil {
+ return
}
+ nFS, err = strconv.Atoi(string(bs))
- if err := q.connect(); err != nil {
- return nil, errors.Trace(err)
+ return
+}
+func (q *qmp) FSFreezeList(ctx context.Context, mountpoints []string) (nFS int, err error) {
+ q.Lock()
+ defer q.Unlock()
+ var args map[string]any
+ if len(mountpoints) > 0 {
+ args = map[string]any{"mountpoints": mountpoints}
}
+ var bs []byte
+ if bs, err = q.exec(ctx, "guest-fsfreeze-freeze-list", args); err != nil {
+ return
+ }
+ nFS, err = strconv.Atoi(string(bs))
+ return
+}
- switch resp, err := q.req(buf); {
+func (q *qmp) FSThawAll(ctx context.Context) (nFS int, err error) {
+ q.Lock()
+ defer q.Unlock()
+
+ var bs []byte
+ if bs, err = q.exec(ctx, "guest-fsfreeze-thaw", nil); err != nil {
+ return
+ }
+ nFS, err = strconv.Atoi(string(bs))
+ return
+}
+
+func (q *qmp) FSFreezeStatus(ctx context.Context) (status string, err error) {
+ q.Lock()
+ defer q.Unlock()
+
+ var bs []byte
+ if bs, err = q.exec(ctx, "guest-fsfreeze-status", nil); err != nil {
+ return
+ }
+ status = string(bs[1 : len(bs)-1])
+ return
+}
+
+func (q *qmp) exec(ctx context.Context, cmd string, args map[string]any) ([]byte, error) {
+ if err := q.initIfNecessary(); err != nil {
+ return nil, err
+ }
+
+ var buf, err = newQmpCmd(cmd, args).bytes()
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+
+ switch resp, err := q.req(ctx, buf); {
case err != nil:
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
case resp.Error != nil:
- return nil, errors.Trace(resp.Error)
+ return nil, errors.Wrapf(resp.Error, "failed to exec %s", cmd)
default:
return []byte(*resp.Return), nil
@@ -190,7 +260,7 @@ func (q *qmp) exec(cmd string, args map[string]any) ([]byte, error) {
}
// SeekFile .
-func (q *qmp) SeekFile(handle int, offset int, whence int) (position int, eof bool, err error) {
+func (q *qmp) SeekFile(ctx context.Context, handle int, offset int, whence int) (position int, eof bool, err error) {
args := map[string]any{
"handle": handle,
"offset": offset,
@@ -201,7 +271,7 @@ func (q *qmp) SeekFile(handle int, offset int, whence int) (position int, eof bo
defer q.Unlock()
var buf []byte
- if buf, err = q.exec("guest-file-seek", args); err != nil {
+ if buf, err = q.exec(ctx, "guest-file-seek", args); err != nil {
return
}
@@ -216,75 +286,6 @@ func (q *qmp) SeekFile(handle int, offset int, whence int) (position int, eof bo
return resp.Position, resp.EOF, nil
}
-func (q *qmp) connect() error {
- if q.sock != nil {
- return nil
- }
-
- var sock, err = net.DialTimeout("unix", q.sockfile, configs.Conf.QMPConnectTimeout.Duration())
- if err != nil {
- return errors.Trace(err)
- }
-
- q.sock = sock
- q.reader = bufio.NewReader(q.sock)
- q.writer = bufio.NewWriter(q.sock)
-
- if !q.ga {
- if err := q.handshake(); err != nil {
- q.Close()
- return errors.Trace(err)
- }
- }
-
- return nil
-}
-
-func (q *qmp) handshake() error {
- return utils.Invoke([]func() error{
- q.greet,
- q.capabilities,
- })
-}
-
-func (q *qmp) capabilities() error {
- var cmd, err = newQmpCmd("qmp_capabilities", nil).bytes()
- if err != nil {
- return errors.Trace(err)
- }
-
- switch resp, err := q.req(cmd); {
- case err != nil:
- return errors.Trace(err)
-
- case resp.Return == nil:
- return errors.Errorf("QMP negotiation error")
-
- default:
- return nil
- }
-}
-
-func (q *qmp) greet() error {
- var buf, err = q.read()
- if err != nil {
- return errors.Trace(err)
- }
-
- var resp qmpResp
-
- switch err := json.Unmarshal(buf, &resp.Greeting); {
- case err != nil:
- return errors.Trace(err)
- case resp.Greeting == nil:
- return errors.Errorf("QMP greeting error")
- }
-
- q.greeting = resp.Greeting
-
- return nil
-}
-
func (q *qmp) Close() (err error) {
if q.sock != nil {
err = q.sock.Close()
@@ -292,56 +293,23 @@ func (q *qmp) Close() (err error) {
return
}
-func (q *qmp) req(cmd []byte) (qmpResp, error) {
+func (q *qmp) req(ctx context.Context, cmd []byte) (qmpResp, error) {
var resp qmpResp
- if err := q.write(cmd); err != nil {
- return resp, errors.Trace(err)
- }
-
- var buf, err = q.read()
+ rs, err := q.dom.QemuAgentCommand(ctx, string(cmd))
if err != nil {
- return resp, errors.Trace(err)
+ return resp, errors.Wrap(err, "")
}
- if err := json.Unmarshal(buf, &resp); err != nil {
- return resp, errors.Trace(err)
+ if err := json.Unmarshal([]byte(rs), &resp); err != nil {
+ return resp, errors.Wrap(err, "")
}
return resp, nil
}
-func (q *qmp) write(buf []byte) error {
- if _, err := q.writer.Write(append(buf, '\x0a')); err != nil {
- return errors.Trace(err)
- }
-
- if err := q.writer.Flush(); err != nil {
- return errors.Trace(err)
- }
-
- return nil
-}
-
-func (q *qmp) read() ([]byte, error) {
- for {
- var buf, err = q.reader.ReadBytes('\n')
- if err != nil {
- return nil, errors.Trace(err)
- }
-
- var resp qmpResp
- if err := json.Unmarshal(buf, &resp); err != nil {
- return nil, errors.Trace(err)
- }
-
- if resp.Event != nil {
- log.Infof("recv event: %v", resp.Event)
- continue
- }
-
- return buf, nil
- }
+func (q *qmp) GetName() string {
+ return q.name
}
type qmpCmd struct {
diff --git a/internal/virt/agent/qmp_test.go b/internal/virt/agent/qmp_test.go
new file mode 100644
index 0000000..66cd418
--- /dev/null
+++ b/internal/virt/agent/qmp_test.go
@@ -0,0 +1,55 @@
+package agent
+
+import (
+ "context"
+ "testing"
+
+ "github.com/projecteru2/yavirt/pkg/libvirt/mocks"
+ "github.com/projecteru2/yavirt/pkg/test/assert"
+)
+
+func newMockQmp(dom *mocks.Domain) *qmp {
+ return &qmp{
+ name: "mock",
+ virt: nil,
+ ga: true,
+ dom: dom,
+ }
+}
+
+func TestFsFreezeAll(t *testing.T) {
+ dom := &mocks.Domain{}
+ q := newMockQmp(dom)
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ cmd := `{"execute":"guest-fsfreeze-freeze"}`
+ dom.On("QemuAgentCommand", ctx, cmd).Return(`{"return": 3}`, nil)
+ nFs, err := q.FSFreezeAll(ctx)
+ assert.Nil(t, err)
+ assert.Equal(t, 3, nFs)
+}
+
+func TestFSThawAll(t *testing.T) {
+ dom := &mocks.Domain{}
+ q := newMockQmp(dom)
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ cmd := `{"execute":"guest-fsfreeze-thaw"}`
+ dom.On("QemuAgentCommand", ctx, cmd).Return(`{"return": 3}`, nil)
+ nFs, err := q.FSThawAll(ctx)
+ assert.Nil(t, err)
+ assert.Equal(t, 3, nFs)
+}
+
+func TestFsFreezeStatus(t *testing.T) {
+ dom := &mocks.Domain{}
+ q := newMockQmp(dom)
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ cmd := `{"execute":"guest-fsfreeze-status"}`
+ dom.On("QemuAgentCommand", ctx, cmd).Return(`{"return": "freezed"}`, nil)
+ status, err := q.FSFreezeStatus(ctx)
+ assert.Nil(t, err)
+ assert.Equal(t, "freezed", status)
+}
diff --git a/internal/virt/agent/types/types.go b/internal/virt/agent/types/types.go
index 1edd131..f281a13 100644
--- a/internal/virt/agent/types/types.go
+++ b/internal/virt/agent/types/types.go
@@ -3,7 +3,8 @@ package types
import (
"encoding/base64"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/yavirt/pkg/terrors"
)
// Diskfree .
@@ -50,11 +51,11 @@ func (s ExecStatus) Stdio() (so, se []byte, err error) {
var xe error
if so, xe = s.stdout(); xe != nil {
- return nil, nil, errors.Wrap(err, xe)
+ return nil, nil, errors.CombineErrors(err, xe)
}
if se, xe = s.stderr(); xe != nil {
- return nil, nil, errors.Wrap(err, xe)
+ return nil, nil, errors.CombineErrors(err, xe)
}
return
@@ -70,8 +71,8 @@ func (s ExecStatus) stderr() ([]byte, error) {
// CheckReturnCode .
func (s ExecStatus) CheckReturnCode() (bool, error) {
- if err := s.Error(); err != nil && !errors.Contain(err, errors.ErrExecNonZeroReturn) {
- return false, errors.Trace(err)
+ if err := s.Error(); err != nil && !errors.Is(err, terrors.ErrExecNonZeroReturn) {
+ return false, errors.Wrap(err, "")
}
return s.Code == 0, nil
}
@@ -79,13 +80,13 @@ func (s ExecStatus) CheckReturnCode() (bool, error) {
func (s ExecStatus) Error() error {
switch {
case s.Err != nil:
- return errors.Trace(s.Err)
+ return errors.Wrap(s.Err, "")
case !s.Exited:
- return errors.ErrExecIsRunning
+ return terrors.ErrExecIsRunning
case s.Code != 0:
- return errors.Annotatef(errors.ErrExecNonZeroReturn,
+ return errors.Wrapf(terrors.ErrExecNonZeroReturn,
"return %d; stdout: %s; stderr: %s",
s.Code, decodeToString(s.Base64Out), decodeToString(s.Base64Err))
diff --git a/internal/virt/ctx.go b/internal/virt/ctx.go
deleted file mode 100644
index e591716..0000000
--- a/internal/virt/ctx.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package virt
-
-import (
- "context"
-
- calihandler "github.com/projecteru2/yavirt/internal/vnet/handler/calico"
- "github.com/projecteru2/yavirt/pkg/errors"
-)
-
-type key string
-
-const calicoHandlerKey key = "CalicoHandler"
-
-// Context .
-type Context struct {
- context.Context
-}
-
-// NewContext .
-func NewContext(ctx context.Context, caliHandler *calihandler.Handler) Context {
- ctx = context.WithValue(ctx, calicoHandlerKey, caliHandler)
- return Context{Context: ctx}
-}
-
-// CalicoHandler .
-func (c Context) CalicoHandler() (*calihandler.Handler, error) {
- switch hand, ok := c.Value(calicoHandlerKey).(*calihandler.Handler); {
- case !ok:
- fallthrough
- case hand == nil:
- return nil, errors.Annotatef(errors.ErrInvalidValue, "nil *calihandler.Handler")
-
- default:
- return hand, nil
- }
-}
diff --git a/internal/virt/domain/domain.go b/internal/virt/domain/domain.go
index b275cfc..6f1f761 100644
--- a/internal/virt/domain/domain.go
+++ b/internal/virt/domain/domain.go
@@ -1,18 +1,33 @@
package domain
import (
+ "context"
+ "encoding/json"
"encoding/xml"
+ "fmt"
"path/filepath"
+ "strings"
"time"
+ _ "embed"
+
+ "github.com/antchfx/xmlquery"
+ "github.com/cockroachdb/errors"
+ pciaddr "github.com/jaypipes/ghw/pkg/pci/address"
+ "github.com/projecteru2/core/log"
"github.com/projecteru2/yavirt/configs"
+ "github.com/projecteru2/yavirt/internal/eru/resources"
"github.com/projecteru2/yavirt/internal/models"
+ "github.com/projecteru2/yavirt/internal/network"
+ "github.com/projecteru2/yavirt/internal/types"
"github.com/projecteru2/yavirt/internal/virt/template"
- "github.com/projecteru2/yavirt/internal/virt/types"
- "github.com/projecteru2/yavirt/internal/vnet"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/projecteru2/yavirt/internal/vmcache"
"github.com/projecteru2/yavirt/pkg/libvirt"
+ "github.com/projecteru2/yavirt/pkg/terrors"
"github.com/projecteru2/yavirt/pkg/utils"
+ "github.com/samber/lo"
+ gputypes "github.com/yuyang0/resource-gpu/gpu/types"
+ "libvirt.org/go/libvirtxml"
)
const (
@@ -22,17 +37,31 @@ const (
InterfaceBridge = "bridge"
)
+var (
+ //go:embed templates/guest.xml
+ guestXML string
+ //go:embed templates/hostdev.xml
+ hostdevXML string
+)
+
// Domain .
type Domain interface { //nolint
+ Lookup() (libvirt.Domain, error)
CheckShutoff() error
+ CheckRunning() error
GetUUID() (string, error)
GetConsoleTtyname() (string, error)
- AttachVolume(filepath, devName string) (st libvirt.DomainState, err error)
+ OpenConsole(devname string, flages types.OpenConsoleFlags) (*libvirt.Console, error)
+ ReplaceSysVolume(diskXML string) error
+ AttachVolume(buf []byte) (st libvirt.DomainState, err error)
+ DetachVolume(dev string) (st libvirt.DomainState, err error)
+ AttachGPU(prod string, count int) (st libvirt.DomainState, err error)
+ DetachGPU(prod string, count int) (st libvirt.DomainState, err error)
AmplifyVolume(filepath string, cap uint64) error
Define() error
Undefine() error
- Shutdown(force bool) error
- Boot() error
+ Shutdown(ctx context.Context, force bool) error
+ Boot(ctx context.Context) error
Suspend() error
Resume() error
SetSpec(cpu int, mem int64) error
@@ -53,37 +82,45 @@ func New(guest *models.Guest, virt libvirt.Libvirt) *VirtDomain {
}
}
-// XML .
-type XML struct {
- Name string `xml:"name"`
- Devices struct {
- Channel []struct {
- Source struct {
- Path string `xml:"path,attr"`
- } `xml:"source"`
- Alias struct {
- Name string `xml:"name,attr"`
- } `xml:"alias"`
- } `xml:"channel"`
- } `xml:"devices"`
-}
-
// Define .
func (d *VirtDomain) Define() error {
+ ctx := context.TODO()
+ logger := log.WithFunc("VirtDomain.Define").WithField("guest", d.guest.ID)
+
+ logger.Debugf(ctx, "GPU engine params: %v", d.guest.GPUEngineParams)
+ // if gpu resource is needed, we need to lock gpu resources here
+ // and unlock after the domain is defined
+ if d.guest.GPUEngineParams.Count() > 0 {
+ resources.GetManager().LockGPU()
+ defer resources.GetManager().UnlockGPU()
+
+ // Updating the domain cache is necessary in this context. Consider the following scenario:
+ // We do not update the vmcache here because the event-driven update of vmcache may experience delays.
+ // Consequently, after unlocking the GPU locker, the vmcache may not have been updated.
+ // In such cases, the next GPU allocation may inadvertently select GPUs that are already in use by this VM.
+ // While this scenario is rare, it can occur.
+ defer func() {
+ logger.Debugf(ctx, " -------------- %s GPU addresses: %v", d.guest.ID, vmcache.FetchGPUAddrs())
+ if err := vmcache.UpdateDomain(d.guest.ID); err != nil {
+ log.Errorf(ctx, err, "[Define] failed to update domain cache")
+ }
+ logger.Debugf(ctx, " +++++++++++++ %s GPU addresses: %v", d.guest.ID, vmcache.FetchGPUAddrs())
+ }()
+ }
+
buf, err := d.render()
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
dom, err := d.virt.DefineDomain(string(buf))
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
- defer dom.Free()
switch st, err := dom.GetState(); {
case err != nil:
- return errors.Trace(err)
+ return errors.Wrap(err, "")
case st == libvirt.DomainShutoff:
return nil
default:
@@ -92,45 +129,57 @@ func (d *VirtDomain) Define() error {
}
// Boot .
-func (d *VirtDomain) Boot() error {
- dom, err := d.lookup()
+func (d *VirtDomain) Boot(ctx context.Context) error {
+ logger := log.WithFunc("VirtDomain.Boot")
+ dom, err := d.Lookup()
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
- defer dom.Free()
+ defer func() {
+ _ = dom.SetAutostart(true)
+ if err := dom.SetMemoryStatsPeriod(configs.Conf.MemStatsPeriod, false, false); err != nil {
+ logger.Warnf(ctx, "failed to set memory stats period: %v", err)
+ }
+ }()
+ domName, _ := dom.GetName()
var expState = libvirt.DomainShutoff
for i := 0; ; i++ {
- time.Sleep(time.Second * time.Duration(i))
- i %= 5
-
- switch st, err := dom.GetState(); {
- case err != nil:
- return errors.Trace(err)
-
- case st == libvirt.DomainRunning:
- return nil
-
- case st == expState:
- // Actually, dom.Create() means launch a defined domain.
- if err := dom.Create(); err != nil {
- return errors.Trace(err)
+ timeout := time.Duration(i%5) * time.Second
+
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ case <-time.After(timeout):
+ switch st, err := dom.GetState(); {
+ case err != nil:
+ return errors.Wrap(err, "")
+
+ case st == libvirt.DomainRunning:
+ return nil
+
+ case st == expState:
+ // Actually, dom.Create() means launch a defined domain.
+ if err := dom.Create(); err != nil {
+ logger.Debugf(ctx, "create domain failed,dom name : %s , err: %s", domName, err.Error())
+ return errors.Wrap(err, "")
+ }
+ logger.Infof(ctx, "create domain success, dom name : %s", domName)
+ continue
+
+ default:
+ return types.NewDomainStatesErr(st, expState)
}
- continue
-
- default:
- return types.NewDomainStatesErr(st, expState)
}
}
}
// Shutdown .
-func (d *VirtDomain) Shutdown(force bool) error {
- dom, err := d.lookup()
+func (d *VirtDomain) Shutdown(ctx context.Context, force bool) error {
+ dom, err := d.Lookup()
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
- defer dom.Free()
var expState = libvirt.DomainRunning
@@ -140,36 +189,41 @@ func (d *VirtDomain) Shutdown(force bool) error {
}
for i := 0; ; i++ {
- time.Sleep(time.Second * time.Duration(i))
- i %= 5
-
- switch st, err := dom.GetState(); {
- case err != nil:
- return errors.Trace(err)
-
- case st == libvirt.DomainShutoff:
- return nil
-
- case st == libvirt.DomainShutting:
- // It's shutting now, waiting to be shutoff.
- continue
-
- case st == libvirt.DomainPaused:
- fallthrough
- case st == expState:
- if err := shut(dom); err != nil {
- return errors.Trace(err)
- }
- continue
-
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
default:
- return types.NewDomainStatesErr(st, expState)
+ time.Sleep(time.Second * time.Duration(i))
+ i %= 5
+
+ switch st, err := dom.GetState(); {
+ case err != nil:
+ return errors.Wrap(err, "")
+
+ case st == libvirt.DomainShutoff:
+ return nil
+
+ case st == libvirt.DomainShutting:
+ // It's shutting now, waiting to be shutoff.
+ continue
+
+ case st == libvirt.DomainPaused:
+ fallthrough
+ case st == expState:
+ if err := shut(dom); err != nil {
+ return errors.Wrap(err, "")
+ }
+ continue
+
+ default:
+ return types.NewDomainStatesErr(st, expState)
+ }
}
}
}
func (d *VirtDomain) graceShutdown(dom libvirt.Domain) error {
- return dom.ShutdownFlags(libvirt.DomainShutdownDefault)
+ return dom.ShutdownFlags(libvirt.DomainShutdownFlags(libvirt.DomainShutdownDefault))
}
func (d *VirtDomain) forceShutdown(dom libvirt.Domain) error {
@@ -178,15 +232,14 @@ func (d *VirtDomain) forceShutdown(dom libvirt.Domain) error {
// CheckShutoff .
func (d *VirtDomain) CheckShutoff() error {
- dom, err := d.lookup()
+ dom, err := d.Lookup()
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
- defer dom.Free()
switch st, err := dom.GetState(); {
case err != nil:
- return errors.Trace(err)
+ return errors.Wrap(err, "")
case st != libvirt.DomainShutoff:
return types.NewDomainStatesErr(st, libvirt.DomainShutoff)
default:
@@ -194,13 +247,29 @@ func (d *VirtDomain) CheckShutoff() error {
}
}
+// CheckRunning .
+func (d *VirtDomain) CheckRunning() error {
+ dom, err := d.Lookup()
+ if err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ switch st, err := dom.GetState(); {
+ case err != nil:
+ return errors.Wrap(err, "")
+ case st != libvirt.DomainRunning:
+ return types.NewDomainStatesErr(st, libvirt.DomainRunning)
+ default:
+ return nil
+ }
+}
+
// Suspend .
func (d *VirtDomain) Suspend() error {
- dom, err := d.lookup()
+ dom, err := d.Lookup()
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
- defer dom.Free()
var expState = libvirt.DomainRunning
for i := 0; ; i++ {
@@ -209,14 +278,14 @@ func (d *VirtDomain) Suspend() error {
switch st, err := dom.GetState(); {
case err != nil:
- return errors.Trace(err)
+ return errors.Wrap(err, "")
case st == libvirt.DomainPaused:
return nil
case st == expState:
if err := dom.Suspend(); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
continue
@@ -228,11 +297,10 @@ func (d *VirtDomain) Suspend() error {
// Resume .
func (d *VirtDomain) Resume() error {
- dom, err := d.lookup()
+ dom, err := d.Lookup()
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
- defer dom.Free()
var expState = libvirt.DomainPaused
for i := 0; ; i++ {
@@ -241,14 +309,14 @@ func (d *VirtDomain) Resume() error {
switch st, err := dom.GetState(); {
case err != nil:
- return errors.Trace(err)
+ return errors.Wrap(err, "")
case st == libvirt.DomainRunning:
return nil
case st == expState:
if err := dom.Resume(); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
continue
@@ -260,22 +328,21 @@ func (d *VirtDomain) Resume() error {
// Undefine .
func (d *VirtDomain) Undefine() error {
- dom, err := d.lookup()
+ dom, err := d.Lookup()
if err != nil {
- if errors.IsDomainNotExistsErr(err) {
+ if terrors.IsDomainNotExistsErr(err) {
return nil
}
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
- defer dom.Free()
var expState = libvirt.DomainShutoff
switch st, err := dom.GetState(); {
case err != nil:
- if errors.IsDomainNotExistsErr(err) {
+ if terrors.IsDomainNotExistsErr(err) {
return nil
}
- return errors.Trace(err)
+ return errors.Wrap(err, "")
case st == libvirt.DomainPaused:
fallthrough
@@ -289,40 +356,144 @@ func (d *VirtDomain) Undefine() error {
// GetUUID .
func (d *VirtDomain) GetUUID() (string, error) {
- dom, err := d.lookup()
+ dom, err := d.Lookup()
if err != nil {
- return "", errors.Trace(err)
+ return "", errors.Wrap(err, "")
}
- defer dom.Free()
return dom.GetUUIDString()
}
func (d *VirtDomain) render() ([]byte, error) {
uuid, err := d.checkUUID(d.guest.DmiUUID)
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
sysVol, err := d.guest.SysVolume()
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
+ }
+
+ sysVolXML, err := sysVol.GenerateXML()
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ dataVols, err := d.dataVols()
+ if err != nil {
+ return nil, err
+ }
+ metadataXML, err := d.metadataXML()
+ if err != nil {
+ return nil, err
+ }
+ ciXML, cdromSrcXML, err := d.cloudInitXML()
+ if err != nil {
+ return nil, err
+ }
+ vncXML, err := d.vncConfig()
+ if err != nil {
+ return nil, err
}
+ var gpus []map[string]string
+ if d.guest.GPUEngineParams.Count() > 0 {
+ gpus, err = d.gpus()
+ if err != nil {
+ return nil, err
+ }
+ }
var args = map[string]any{
"name": d.guest.ID,
"uuid": uuid,
"memory": d.guest.MemoryInMiB(),
"cpu": d.guest.CPU,
- "sysvol": sysVol.Filepath(),
- "gasock": d.guest.SocketFilepath(),
- "datavols": d.dataVols(d.guest.Vols),
+ "gpus": gpus,
+ "sysvol": string(sysVolXML),
+ "datavols": dataVols,
"interface": d.getInterfaceType(),
"pair": d.guest.NetworkPairName(),
"mac": d.guest.MAC,
+ "bandwidth": d.networkBandwidth(),
"cache_passthrough": configs.Conf.VirtCPUCachePassthrough,
+ "metadata_xml": metadataXML,
+ "cloud_init_xml": ciXML,
+ "cdrom_src_xml": cdromSrcXML,
+ "vnc": vncXML,
+ }
+
+ return template.Render(d.guestTemplateFilepath(), guestXML, args)
+}
+
+type AppMetadata struct {
+ ID int64 `json:"id"`
+ SID string `json:"sid"`
+ Name string `json:"name"`
+ From string `json:"from"`
+ UserID int64 `json:"user_id"`
+ UserName string `json:"user_name"`
+}
+
+func (d *VirtDomain) metadataXML() (string, error) {
+ bs, ok := d.guest.JSONLabels["instance/metadata"]
+ if !ok {
+ return "", nil
+ }
+ obj := AppMetadata{}
+ if err := json.Unmarshal([]byte(bs), &obj); err != nil {
+ return "", errors.Wrap(err, "")
+ }
+ meta := types.CustomDomainMetadata{
+ App: types.App{
+ NS: "https://eru.org/v1",
+ From: obj.From,
+ Owner: types.AppOwner{
+ UserID: fmt.Sprintf("%d", obj.UserID),
+ UserName: obj.UserName,
+ },
+ Name: types.AppName{
+ Name: obj.Name,
+ },
+ ID: types.AppID{
+ SID: obj.SID,
+ ID: fmt.Sprintf("%d", obj.ID),
+ },
+ },
+ }
+ if len(d.guest.IPNets) > 0 {
+ meta.App.IP.IP = d.guest.IPNets[0].IPv4()
+ }
+ xmlBS, err := xml.Marshal(meta)
+ if err != nil {
+ return "", errors.Wrap(err, "")
}
+ return string(xmlBS), nil
+}
- return template.Render(d.guestTemplateFilepath(), args)
+func (d *VirtDomain) cloudInitXML() (string, string, error) {
+ // for network
+ obj, err := d.guest.GenCloudInit()
+ if err != nil {
+ return "", "", errors.Wrap(err, "")
+ }
+ log.Debugf(context.TODO(), "cloud-init: %v", obj)
+ var (
+ ciXML string
+ cdromSrcXML string
+ )
+ switch {
+ case obj.URL != "":
+ ciXML = fmt.Sprintf("ds=nocloud-net;s=%s", obj.URL)
+ case obj.Username != "" || obj.Password != "":
+ output := filepath.Join(configs.Conf.VirtCloudInitDir, fmt.Sprintf("%s.iso", d.guest.ID))
+ if err := obj.GenerateISO(output); err != nil {
+ return "", "", err
+ }
+ ciXML = "ds=nocloud"
+ cdromSrcXML = fmt.Sprintf("", output)
+ default:
+ return "", "", errors.New("invalid cloud-init config")
+ }
+ return ciXML, cdromSrcXML, nil
}
func (d *VirtDomain) checkUUID(raw string) (string, error) {
@@ -331,7 +502,7 @@ func (d *VirtDomain) checkUUID(raw string) (string, error) {
}
if err := utils.CheckUUID(raw); err != nil {
- return "", errors.Trace(err)
+ return "", errors.Wrap(err, "")
}
return raw, nil
@@ -339,37 +510,112 @@ func (d *VirtDomain) checkUUID(raw string) (string, error) {
func (d *VirtDomain) getInterfaceType() string {
switch d.guest.NetworkMode {
- case vnet.NetworkCalico:
+ case network.CalicoMode:
return InterfaceEthernet
default:
return InterfaceBridge
}
}
-func (d *VirtDomain) dataVols(vols models.Volumes) []map[string]string {
- var dat = []map[string]string{}
+func (d *VirtDomain) dataVols() ([]string, error) {
+ vols := d.guest.Vols
+ var dat = []string{}
- for i, v := range vols {
+ for _, v := range vols {
if v.IsSys() {
continue
}
+ buf, err := v.GenerateXML()
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ dat = append(dat, string(buf))
+ }
+ return dat, nil
+}
+
+func allocGPUs(eParams *gputypes.EngineParams) ([]map[string]string, error) {
+ infos, err := resources.GetManager().AllocGPU(eParams)
+ if err != nil {
+ return nil, err
+ }
+ res := lo.Map(infos, func(info types.GPUInfo, _ int) map[string]string {
+ addr := pciaddr.FromString(info.Address)
+ r := map[string]string{
+ "domain": addr.Domain,
+ "bus": addr.Bus,
+ "slot": addr.Device,
+ "function": addr.Function,
+ }
+ return r
+ })
+ return res, nil
+}
+func (d *VirtDomain) gpus() ([]map[string]string, error) {
+ return allocGPUs(d.guest.GPUEngineParams)
+}
- dat = append(dat, map[string]string{
- "path": v.Filepath(),
- "dev": v.GetDeviceName(i),
- })
+type vncConfig struct {
+ Port int `json:"port"`
+ Password string `json:"password"`
+}
+
+func (d *VirtDomain) vncConfig() (string, error) {
+ bs, ok := d.guest.JSONLabels["instance/vnc"]
+ if !ok {
+ return "", nil
+ }
+ obj := vncConfig{}
+ if err := json.Unmarshal([]byte(bs), &obj); err != nil {
+ return "", errors.Wrap(err, "")
+ }
+ portCfg := "port='-1' autoport='yes'"
+ if obj.Port > 0 {
+ portCfg = fmt.Sprintf("port='%d'", obj.Port)
+ }
+ passwdCfg := ""
+ if obj.Password != "" {
+ passwdCfg = fmt.Sprintf("passwd='%s'", obj.Password)
+ }
+ vncXML := fmt.Sprintf(``, portCfg, passwdCfg)
+ return vncXML, nil
+}
+
+func (d *VirtDomain) networkBandwidth() map[string]string {
+ // the Unit of libvirt is kbyte/s
+ // the default settings is avg: 2Gbps, peak: 3Gbps
+ // 1Gbps=1000Mbps=1000000Kbps=1000000000bit
+ ans := map[string]string{
+ "average": fmt.Sprintf("%d", 2000000/8),
+ "peak": fmt.Sprintf("%d", 3000000/8),
+ }
+ ss, ok := d.guest.JSONLabels["instance/nic-bandwidth"]
+ if !ok {
+ return ans
}
- return dat
+ bandwidth := map[string]int64{}
+ err := json.Unmarshal([]byte(ss), &bandwidth)
+ if err != nil {
+ // just print log and use default values.
+ log.Warnf(context.TODO(), "Invalid bandwidth label: %s", ss)
+ } else {
+ if v, ok := bandwidth["average"]; ok {
+ ans["average"] = fmt.Sprintf("%d", v/8000)
+ }
+ if v, ok := bandwidth["peak"]; ok {
+ ans["peak"] = fmt.Sprintf("%d", v/8000)
+ }
+ }
+ return ans
}
// GetXMLString .
func (d *VirtDomain) GetXMLString() (xml string, err error) {
- dom, err := d.lookup()
+ dom, err := d.Lookup()
if err != nil {
return
}
- defer dom.Free()
var flags libvirt.DomainXMLFlags
return dom.GetXMLDesc(flags)
@@ -377,47 +623,38 @@ func (d *VirtDomain) GetXMLString() (xml string, err error) {
// GetConsoleTtyname .
func (d *VirtDomain) GetConsoleTtyname() (devname string, err error) {
- var dom libvirt.Domain
- if dom, err = d.lookup(); err != nil {
- return
- }
- defer dom.Free()
-
- expState := libvirt.DomainRunning
- switch st, err := dom.GetState(); {
- case err != nil:
- return "", errors.Trace(err)
-
- case st != expState:
- return "", types.NewDomainStatesErr(st, expState)
- }
-
x, err := d.GetXMLString()
if err != nil {
return
}
- domainXML := &XML{}
- if err = xml.Unmarshal([]byte(x), domainXML); err != nil {
+ doc, err := xmlquery.Parse(strings.NewReader(x))
+ if err != nil {
return
}
- for _, c := range domainXML.Devices.Channel {
- if c.Alias.Name == "channel0" {
- return c.Source.Path, nil
- }
+ aliasNode := xmlquery.FindOne(doc, "//devices/console[2]/alias")
+ if aliasNode != nil {
+ return aliasNode.SelectAttr("name"), nil
+ }
+ return "", nil
+}
+
+func (d *VirtDomain) OpenConsole(devname string, flags types.OpenConsoleFlags) (*libvirt.Console, error) {
+ dom, err := d.Lookup()
+ if err != nil {
+ return nil, err
}
- return "", errors.Errorf("channel0 not found")
+ return dom.OpenConsole(devname, &flags.ConsoleFlags)
}
// SetSpec .
func (d *VirtDomain) SetSpec(cpu int, mem int64) error {
- dom, err := d.lookup()
+ dom, err := d.Lookup()
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
- defer dom.Free()
if err := d.setCPU(cpu, dom); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
return d.setMemory(mem, dom)
@@ -426,7 +663,7 @@ func (d *VirtDomain) SetSpec(cpu int, mem int64) error {
func (d *VirtDomain) setCPU(cpu int, dom libvirt.Domain) error {
switch {
case cpu < 0:
- return errors.Annotatef(errors.ErrInvalidValue, "invalid CPU num: %d", cpu)
+ return errors.Wrapf(terrors.ErrInvalidValue, "invalid CPU num: %d", cpu)
case cpu == 0:
return nil
}
@@ -434,16 +671,16 @@ func (d *VirtDomain) setCPU(cpu int, dom libvirt.Domain) error {
flag := libvirt.DomainVcpuConfig
// Doesn't set with both Maximum and Current simultaneously.
if err := dom.SetVcpusFlags(uint(cpu), flag|libvirt.DomainVcpuMaximum); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
return dom.SetVcpusFlags(uint(cpu), flag|libvirt.DomainVcpuCurrent)
}
func (d *VirtDomain) setMemory(mem int64, dom libvirt.Domain) error {
- if mem < configs.Conf.MinMemory || mem > configs.Conf.MaxMemory {
- return errors.Annotatef(errors.ErrInvalidValue,
+ if mem < configs.Conf.Resource.MinMemory || mem > configs.Conf.Resource.MaxMemory {
+ return errors.Wrapf(terrors.ErrInvalidValue,
"invalid memory: %d, it shoule be [%d, %d]",
- mem, configs.Conf.MinMemory, configs.Conf.MaxMemory)
+ mem, configs.Conf.Resource.MinMemory, configs.Conf.Resource.MaxMemory)
}
// converts bytes unit to kilobytes
@@ -451,73 +688,212 @@ func (d *VirtDomain) setMemory(mem int64, dom libvirt.Domain) error {
flag := libvirt.DomainMemConfig
if err := dom.SetMemoryFlags(uint64(mem), flag|libvirt.DomainMemMaximum); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
return dom.SetMemoryFlags(uint64(mem), flag|libvirt.DomainMemCurrent)
}
+func (d *VirtDomain) ReplaceSysVolume(diskXML string) error {
+ xmldoc, err := d.GetXMLString()
+ if err != nil {
+ return errors.Wrapf(err, "failed to get domain xml of guest %s", d.guest.ID)
+ }
+ domcfg := &libvirtxml.Domain{}
+ if err = domcfg.Unmarshal(xmldoc); err != nil {
+ return errors.Wrapf(err, "failed to unmarshal domain xml of guest %s", d.guest.ID)
+ }
+ sysDisk := &libvirtxml.DomainDisk{}
+ if err := sysDisk.Unmarshal(diskXML); err != nil {
+ return errors.Wrapf(err, "faied to unmarshal disk xml")
+ }
+ domcfg.Devices.Disks[0] = *sysDisk
+ newXMLDoc, err := domcfg.Marshal()
+ if err != nil {
+ return errors.Wrapf(err, "failed to marshal new domain xml for guest %s", d.guest.ID)
+ }
+ if _, err := d.virt.DefineDomain(newXMLDoc); err != nil {
+ return errors.Wrapf(err, "failed define domain for guest %s", d.guest.ID)
+ }
+
+ return nil
+}
+
// AttachVolume .
-func (d *VirtDomain) AttachVolume(filepath, devName string) (st libvirt.DomainState, err error) {
+func (d *VirtDomain) AttachVolume(buf []byte) (st libvirt.DomainState, err error) {
var dom libvirt.Domain
- if dom, err = d.lookup(); err != nil {
+ if dom, err = d.Lookup(); err != nil {
return
}
- defer dom.Free()
+ return dom.AttachDevice(string(buf))
+}
- var buf []byte
- if buf, err = d.renderAttachVolumeXML(filepath, devName); err != nil {
+func (d *VirtDomain) DetachVolume(devPath string) (st libvirt.DomainState, err error) {
+ x, err := d.GetXMLString()
+ if err != nil {
+ return
+ }
+ dev := filepath.Base(devPath)
+ doc, err := xmlquery.Parse(strings.NewReader(x))
+ if err != nil {
+ return
+ }
+ node := xmlquery.FindOne(doc, fmt.Sprintf("//devices/disk[target[@dev='%s']]", dev))
+ if node == nil {
+ err = errors.New("can't find device")
return
}
- return dom.AttachVolume(string(buf))
+ xml := node.OutputXML(true)
+ log.Infof(context.TODO(), "Detach volume, device(%s) xml: %s", devPath, xml)
+ var dom libvirt.Domain
+ if dom, err = d.Lookup(); err != nil {
+ return
+ }
+ return dom.DetachDevice(xml)
+}
+
+// AttachGPU attaches new GPUs to guest.
+func (d *VirtDomain) AttachGPU(prod string, count int) (st libvirt.DomainState, err error) {
+ logger := log.WithFunc("AttachGPU")
+ var dom libvirt.Domain
+ if dom, err = d.Lookup(); err != nil {
+ return
+ }
+
+ resources.GetManager().LockGPU()
+ defer resources.GetManager().UnlockGPU()
+
+ // Updating the domain cache is necessary in this context. Consider the following scenario:
+ // We do not update the vmcache here because the event-driven update of vmcache may experience delays.
+ // Consequently, after unlocking the GPU locker, the vmcache may not have been updated.
+ // In such cases, the next GPU allocation may inadvertently select GPUs that are already in use by this VM.
+ // While this scenario is rare, it can occur.
+ defer func() {
+ if err := vmcache.UpdateDomain(d.guest.ID); err != nil {
+ logger.Errorf(context.TODO(), err, "failed to update domain cache")
+ }
+ }()
+ eParams := &gputypes.EngineParams{
+ ProdCountMap: map[string]int{
+ prod: count,
+ },
+ }
+ infos, err := allocGPUs(eParams)
+ if err != nil {
+ return
+ }
+ var buf []byte
+ for _, info := range infos {
+ buf, err = template.Render(d.hostdevTemplateFilepath(), hostdevXML, info)
+ if err != nil {
+ return 0, err
+ }
+
+ if st, err = dom.AttachDevice(string(buf)); err != nil {
+ return st, err
+ }
+ }
+ return
}
-func (d *VirtDomain) renderAttachVolumeXML(filepath, devName string) ([]byte, error) {
- args := map[string]any{
- "path": filepath,
- "dev": devName,
+func extractHostdevXML(doc *xmlquery.Node, gaddr string) (string, error) {
+ ctx := context.TODO()
+ logger := log.WithFunc("extractHostdevXML")
+
+ addr := pciaddr.FromString(gaddr)
+ xpathFmt := "//devices/hostdev[source[address[@domain='0x%s' and @bus='0x%s' and @slot='0x%s' and @function='0x%s']]]"
+ node := xmlquery.FindOne(doc, fmt.Sprintf(xpathFmt, addr.Domain, addr.Bus, addr.Device, addr.Function))
+ if node == nil {
+ return "", errors.Errorf("can't find device, pciaddr: %s", gaddr)
}
- return template.Render(d.diskTemplateFilepath(), args)
+ logger.Debugf(ctx, "Detach gpu, device(%s) xml: %s", gaddr, node.OutputXML(true))
+
+ xml := node.OutputXML(true)
+ logger.Infof(ctx, "Detach gpu, device(%s) xml: %s", gaddr, xml)
+ return xml, nil
+}
+
+//
+//
+//
+//
+//
+func (d *VirtDomain) DetachGPU(_ string, count int) (st libvirt.DomainState, err error) {
+ defer func() {
+ if err := vmcache.UpdateDomain(d.guest.ID); err != nil {
+ log.Errorf(context.TODO(), err, "[DetachGPU] failed to update domain cache")
+ }
+ }()
+ var dom libvirt.Domain
+ if dom, err = d.Lookup(); err != nil {
+ return
+ }
+
+ var flags libvirt.DomainXMLFlags
+ x, err := dom.GetXMLDesc(flags)
+
+ if err != nil {
+ return
+ }
+ doc, err := xmlquery.Parse(strings.NewReader(x))
+ if err != nil {
+ return
+ }
+ entry := vmcache.FetchDomainEntry(d.guest.ID)
+ if count > len(entry.GPUAddrs) {
+ count = len(entry.GPUAddrs)
+ }
+ for i := 0; i < count; i++ {
+ gaddr := entry.GPUAddrs[i]
+ // TODO check if the gaddr's product is equal to the product
+ xml, err := extractHostdevXML(doc, gaddr)
+ if err != nil {
+ return 0, err
+ }
+ if st, err = dom.DetachDevice(xml); err != nil {
+ return st, err
+ }
+ }
+ return
}
// GetState .
func (d *VirtDomain) GetState() (libvirt.DomainState, error) {
- dom, err := d.lookup()
+ dom, err := d.Lookup()
if err != nil {
- return libvirt.DomainNoState, errors.Trace(err)
+ return libvirt.DomainNoState, errors.Wrap(err, "")
}
- defer dom.Free()
return dom.GetState()
}
// AmplifyVolume .
func (d *VirtDomain) AmplifyVolume(filepath string, cap uint64) error {
- dom, err := d.lookup()
+ dom, err := d.Lookup()
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
- defer dom.Free()
return dom.AmplifyVolume(filepath, cap)
}
-func (d *VirtDomain) lookup() (libvirt.Domain, error) {
+func (d *VirtDomain) Lookup() (libvirt.Domain, error) {
return d.virt.LookupDomain(d.guest.ID)
}
-func (d *VirtDomain) diskTemplateFilepath() string {
- return filepath.Join(configs.Conf.VirtTmplDir, "disk.xml")
-}
-
func (d *VirtDomain) guestTemplateFilepath() string {
return filepath.Join(configs.Conf.VirtTmplDir, "guest.xml")
}
+func (d *VirtDomain) hostdevTemplateFilepath() string {
+ return filepath.Join(configs.Conf.VirtTmplDir, "hostdev.xml")
+}
+
// GetState .
func GetState(name string, virt libvirt.Libvirt) (libvirt.DomainState, error) {
dom, err := virt.LookupDomain(name)
if err != nil {
- return libvirt.DomainNoState, errors.Trace(err)
+ return libvirt.DomainNoState, errors.Wrap(err, "")
}
- defer dom.Free()
return dom.GetState()
}
diff --git a/internal/virt/domain/domain_test.go b/internal/virt/domain/domain_test.go
index 7cc4072..efd3054 100644
--- a/internal/virt/domain/domain_test.go
+++ b/internal/virt/domain/domain_test.go
@@ -1,8 +1,11 @@
package domain
import (
+ "fmt"
+ "strings"
"testing"
+ "github.com/antchfx/xmlquery"
"github.com/projecteru2/yavirt/internal/models"
"github.com/projecteru2/yavirt/pkg/libvirt"
libmocks "github.com/projecteru2/yavirt/pkg/libvirt/mocks"
@@ -11,10 +14,6 @@ import (
"github.com/projecteru2/yavirt/pkg/utils"
)
-func init() {
- models.Setup()
-}
-
func TestSetSpec(t *testing.T) {
libdom := &libmocks.Domain{}
defer libdom.AssertExpectations(t)
@@ -23,7 +22,6 @@ func TestSetSpec(t *testing.T) {
dom.virt.(*libmocks.Libvirt).On("LookupDomain", mock.Anything).Return(libdom, nil).Once()
defer func() { dom.virt.(*libmocks.Libvirt).AssertExpectations(t) }()
- libdom.On("Free").Return().Once()
libdom.On("SetVcpusFlags", uint(1), libvirt.DomainVcpuConfig|libvirt.DomainVcpuMaximum).Return(nil).Once()
libdom.On("SetVcpusFlags", uint(1), libvirt.DomainVcpuConfig|libvirt.DomainVcpuCurrent).Return(nil).Once()
libdom.On("SetMemoryFlags", uint64(utils.GB>>10), libvirt.DomainMemConfig|libvirt.DomainMemMaximum).Return(nil).Once()
@@ -32,6 +30,63 @@ func TestSetSpec(t *testing.T) {
assert.NilErr(t, dom.SetSpec(1, utils.GB))
}
+// func TestAttachGPU(t *testing.T) {
+// libdom := &libmocks.Domain{}
+// defer libdom.AssertExpectations(t)
+
+// dom := newMockedDomain(t)
+// dom.virt.(*libmocks.Libvirt).On("LookupDomain", mock.Anything).Return(libdom, nil).Once()
+// defer func() { dom.virt.(*libmocks.Libvirt).AssertExpectations(t) }()
+// libdom.On("GetXMLDesc", mock.Anything).Return("", nil).Once()
+// }
+
+func TestExtractHostdevXML(t *testing.T) {
+ x := `
+
+ haha
+ bbb
+
+
+ YAVIRT
+
+
+
+ hvm
+
+
+
+
+
+
+ destroy
+ restart
+ restart
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `
+ doc, err := xmlquery.Parse(strings.NewReader(x))
+ assert.Nil(t, err)
+ xml, err := extractHostdevXML(doc, "0000:81:00.0")
+ assert.Nil(t, err)
+ assert.Equal(t, ``, xml, "xml is incorrect")
+ fmt.Printf("%s\n", xml)
+}
func newMockedDomain(t *testing.T) *VirtDomain {
gmod, err := models.NewGuest(nil, nil)
assert.NilErr(t, err)
diff --git a/internal/virt/domain/mocks/Domain.go b/internal/virt/domain/mocks/Domain.go
index e8a6e28..0a68aba 100644
--- a/internal/virt/domain/mocks/Domain.go
+++ b/internal/virt/domain/mocks/Domain.go
@@ -1,10 +1,17 @@
-// Code generated by mockery v2.26.1. DO NOT EDIT.
+// Code generated by mockery v2.42.0. DO NOT EDIT.
package mocks
import (
- libvirt "github.com/libvirt/libvirt-go"
+ context "context"
+
+ libvirt "github.com/projecteru2/yavirt/third_party/libvirt"
+
mock "github.com/stretchr/testify/mock"
+
+ pkglibvirt "github.com/projecteru2/yavirt/pkg/libvirt"
+
+ types "github.com/projecteru2/yavirt/internal/types"
)
// Domain is an autogenerated mock type for the Domain type
@@ -16,6 +23,10 @@ type Domain struct {
func (_m *Domain) AmplifyVolume(filepath string, cap uint64) error {
ret := _m.Called(filepath, cap)
+ if len(ret) == 0 {
+ panic("no return value specified for AmplifyVolume")
+ }
+
var r0 error
if rf, ok := ret.Get(0).(func(string, uint64) error); ok {
r0 = rf(filepath, cap)
@@ -26,23 +37,55 @@ func (_m *Domain) AmplifyVolume(filepath string, cap uint64) error {
return r0
}
-// AttachVolume provides a mock function with given fields: filepath, devName
-func (_m *Domain) AttachVolume(filepath string, devName string) (libvirt.DomainState, error) {
- ret := _m.Called(filepath, devName)
+// AttachGPU provides a mock function with given fields: prod, count
+func (_m *Domain) AttachGPU(prod string, count int) (libvirt.DomainState, error) {
+ ret := _m.Called(prod, count)
+
+ if len(ret) == 0 {
+ panic("no return value specified for AttachGPU")
+ }
+
+ var r0 libvirt.DomainState
+ var r1 error
+ if rf, ok := ret.Get(0).(func(string, int) (libvirt.DomainState, error)); ok {
+ return rf(prod, count)
+ }
+ if rf, ok := ret.Get(0).(func(string, int) libvirt.DomainState); ok {
+ r0 = rf(prod, count)
+ } else {
+ r0 = ret.Get(0).(libvirt.DomainState)
+ }
+
+ if rf, ok := ret.Get(1).(func(string, int) error); ok {
+ r1 = rf(prod, count)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// AttachVolume provides a mock function with given fields: buf
+func (_m *Domain) AttachVolume(buf []byte) (libvirt.DomainState, error) {
+ ret := _m.Called(buf)
+
+ if len(ret) == 0 {
+ panic("no return value specified for AttachVolume")
+ }
var r0 libvirt.DomainState
var r1 error
- if rf, ok := ret.Get(0).(func(string, string) (libvirt.DomainState, error)); ok {
- return rf(filepath, devName)
+ if rf, ok := ret.Get(0).(func([]byte) (libvirt.DomainState, error)); ok {
+ return rf(buf)
}
- if rf, ok := ret.Get(0).(func(string, string) libvirt.DomainState); ok {
- r0 = rf(filepath, devName)
+ if rf, ok := ret.Get(0).(func([]byte) libvirt.DomainState); ok {
+ r0 = rf(buf)
} else {
r0 = ret.Get(0).(libvirt.DomainState)
}
- if rf, ok := ret.Get(1).(func(string, string) error); ok {
- r1 = rf(filepath, devName)
+ if rf, ok := ret.Get(1).(func([]byte) error); ok {
+ r1 = rf(buf)
} else {
r1 = ret.Error(1)
}
@@ -50,10 +93,32 @@ func (_m *Domain) AttachVolume(filepath string, devName string) (libvirt.DomainS
return r0, r1
}
-// Boot provides a mock function with given fields:
-func (_m *Domain) Boot() error {
+// Boot provides a mock function with given fields: ctx
+func (_m *Domain) Boot(ctx context.Context) error {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Boot")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(context.Context) error); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// CheckRunning provides a mock function with given fields:
+func (_m *Domain) CheckRunning() error {
ret := _m.Called()
+ if len(ret) == 0 {
+ panic("no return value specified for CheckRunning")
+ }
+
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
@@ -68,6 +133,10 @@ func (_m *Domain) Boot() error {
func (_m *Domain) CheckShutoff() error {
ret := _m.Called()
+ if len(ret) == 0 {
+ panic("no return value specified for CheckShutoff")
+ }
+
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
@@ -82,6 +151,10 @@ func (_m *Domain) CheckShutoff() error {
func (_m *Domain) Define() error {
ret := _m.Called()
+ if len(ret) == 0 {
+ panic("no return value specified for Define")
+ }
+
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
@@ -92,10 +165,70 @@ func (_m *Domain) Define() error {
return r0
}
+// DetachGPU provides a mock function with given fields: prod, count
+func (_m *Domain) DetachGPU(prod string, count int) (libvirt.DomainState, error) {
+ ret := _m.Called(prod, count)
+
+ if len(ret) == 0 {
+ panic("no return value specified for DetachGPU")
+ }
+
+ var r0 libvirt.DomainState
+ var r1 error
+ if rf, ok := ret.Get(0).(func(string, int) (libvirt.DomainState, error)); ok {
+ return rf(prod, count)
+ }
+ if rf, ok := ret.Get(0).(func(string, int) libvirt.DomainState); ok {
+ r0 = rf(prod, count)
+ } else {
+ r0 = ret.Get(0).(libvirt.DomainState)
+ }
+
+ if rf, ok := ret.Get(1).(func(string, int) error); ok {
+ r1 = rf(prod, count)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// DetachVolume provides a mock function with given fields: dev
+func (_m *Domain) DetachVolume(dev string) (libvirt.DomainState, error) {
+ ret := _m.Called(dev)
+
+ if len(ret) == 0 {
+ panic("no return value specified for DetachVolume")
+ }
+
+ var r0 libvirt.DomainState
+ var r1 error
+ if rf, ok := ret.Get(0).(func(string) (libvirt.DomainState, error)); ok {
+ return rf(dev)
+ }
+ if rf, ok := ret.Get(0).(func(string) libvirt.DomainState); ok {
+ r0 = rf(dev)
+ } else {
+ r0 = ret.Get(0).(libvirt.DomainState)
+ }
+
+ if rf, ok := ret.Get(1).(func(string) error); ok {
+ r1 = rf(dev)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
// GetConsoleTtyname provides a mock function with given fields:
func (_m *Domain) GetConsoleTtyname() (string, error) {
ret := _m.Called()
+ if len(ret) == 0 {
+ panic("no return value specified for GetConsoleTtyname")
+ }
+
var r0 string
var r1 error
if rf, ok := ret.Get(0).(func() (string, error)); ok {
@@ -120,6 +253,10 @@ func (_m *Domain) GetConsoleTtyname() (string, error) {
func (_m *Domain) GetState() (libvirt.DomainState, error) {
ret := _m.Called()
+ if len(ret) == 0 {
+ panic("no return value specified for GetState")
+ }
+
var r0 libvirt.DomainState
var r1 error
if rf, ok := ret.Get(0).(func() (libvirt.DomainState, error)); ok {
@@ -144,6 +281,10 @@ func (_m *Domain) GetState() (libvirt.DomainState, error) {
func (_m *Domain) GetUUID() (string, error) {
ret := _m.Called()
+ if len(ret) == 0 {
+ panic("no return value specified for GetUUID")
+ }
+
var r0 string
var r1 error
if rf, ok := ret.Get(0).(func() (string, error)); ok {
@@ -164,10 +305,92 @@ func (_m *Domain) GetUUID() (string, error) {
return r0, r1
}
+// Lookup provides a mock function with given fields:
+func (_m *Domain) Lookup() (pkglibvirt.Domain, error) {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Lookup")
+ }
+
+ var r0 pkglibvirt.Domain
+ var r1 error
+ if rf, ok := ret.Get(0).(func() (pkglibvirt.Domain, error)); ok {
+ return rf()
+ }
+ if rf, ok := ret.Get(0).(func() pkglibvirt.Domain); ok {
+ r0 = rf()
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(pkglibvirt.Domain)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func() error); ok {
+ r1 = rf()
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OpenConsole provides a mock function with given fields: devname, flages
+func (_m *Domain) OpenConsole(devname string, flages types.OpenConsoleFlags) (*pkglibvirt.Console, error) {
+ ret := _m.Called(devname, flages)
+
+ if len(ret) == 0 {
+ panic("no return value specified for OpenConsole")
+ }
+
+ var r0 *pkglibvirt.Console
+ var r1 error
+ if rf, ok := ret.Get(0).(func(string, types.OpenConsoleFlags) (*pkglibvirt.Console, error)); ok {
+ return rf(devname, flages)
+ }
+ if rf, ok := ret.Get(0).(func(string, types.OpenConsoleFlags) *pkglibvirt.Console); ok {
+ r0 = rf(devname, flages)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*pkglibvirt.Console)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(string, types.OpenConsoleFlags) error); ok {
+ r1 = rf(devname, flages)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ReplaceSysVolume provides a mock function with given fields: diskXML
+func (_m *Domain) ReplaceSysVolume(diskXML string) error {
+ ret := _m.Called(diskXML)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ReplaceSysVolume")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(string) error); ok {
+ r0 = rf(diskXML)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
// Resume provides a mock function with given fields:
func (_m *Domain) Resume() error {
ret := _m.Called()
+ if len(ret) == 0 {
+ panic("no return value specified for Resume")
+ }
+
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
@@ -182,6 +405,10 @@ func (_m *Domain) Resume() error {
func (_m *Domain) SetSpec(cpu int, mem int64) error {
ret := _m.Called(cpu, mem)
+ if len(ret) == 0 {
+ panic("no return value specified for SetSpec")
+ }
+
var r0 error
if rf, ok := ret.Get(0).(func(int, int64) error); ok {
r0 = rf(cpu, mem)
@@ -192,13 +419,17 @@ func (_m *Domain) SetSpec(cpu int, mem int64) error {
return r0
}
-// Shutdown provides a mock function with given fields: force
-func (_m *Domain) Shutdown(force bool) error {
- ret := _m.Called(force)
+// Shutdown provides a mock function with given fields: ctx, force
+func (_m *Domain) Shutdown(ctx context.Context, force bool) error {
+ ret := _m.Called(ctx, force)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Shutdown")
+ }
var r0 error
- if rf, ok := ret.Get(0).(func(bool) error); ok {
- r0 = rf(force)
+ if rf, ok := ret.Get(0).(func(context.Context, bool) error); ok {
+ r0 = rf(ctx, force)
} else {
r0 = ret.Error(0)
}
@@ -210,6 +441,10 @@ func (_m *Domain) Shutdown(force bool) error {
func (_m *Domain) Suspend() error {
ret := _m.Called()
+ if len(ret) == 0 {
+ panic("no return value specified for Suspend")
+ }
+
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
@@ -224,6 +459,10 @@ func (_m *Domain) Suspend() error {
func (_m *Domain) Undefine() error {
ret := _m.Called()
+ if len(ret) == 0 {
+ panic("no return value specified for Undefine")
+ }
+
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
@@ -234,13 +473,12 @@ func (_m *Domain) Undefine() error {
return r0
}
-type mockConstructorTestingTNewDomain interface {
+// NewDomain creates a new instance of Domain. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func NewDomain(t interface {
mock.TestingT
Cleanup(func())
-}
-
-// NewDomain creates a new instance of Domain. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-func NewDomain(t mockConstructorTestingTNewDomain) *Domain {
+}) *Domain {
mock := &Domain{}
mock.Mock.Test(t)
diff --git a/internal/virt/domain/templates/disk.xml b/internal/virt/domain/templates/disk.xml
new file mode 100644
index 0000000..7982766
--- /dev/null
+++ b/internal/virt/domain/templates/disk.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+ {{ .read_iops }}
+ {{ .write_iops }}
+ {{ .read_bps }}
+ {{ .write_bps }}
+
+
diff --git a/internal/virt/template/guest.xml b/internal/virt/domain/templates/guest.xml
similarity index 72%
rename from internal/virt/template/guest.xml
rename to internal/virt/domain/templates/guest.xml
index 6fea8fb..fbe3960 100644
--- a/internal/virt/template/guest.xml
+++ b/internal/virt/domain/templates/guest.xml
@@ -1,6 +1,7 @@
{{.name}}
{{.uuid}}
+ {{ .metadata_xml }}
{{.memory}}
{{.memory}}
{{.cpu}}
@@ -9,6 +10,7 @@
YAVIRT
+ {{ .cloud_init_xml }}
yavirt
virtd
0.0.1
@@ -41,20 +43,15 @@
-
-
-
-
-
+ {{ .sysvol }}
+
{{range .datavols}}
-
-
-
-
-
+ {{ . }}
{{end}}
+
+ {{ .cdrom_src_xml }}
@@ -82,33 +79,65 @@
-
+
{{if (eq .interface "bridge")}}
-
+
+
+
{{else if (eq .interface "ethernet")}}
{{end}}
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+ {{ .vnc }}
+
+ {{range .gpus}}
+
+
+
+ {{ end }}
+
diff --git a/internal/virt/domain/templates/hostdev.xml b/internal/virt/domain/templates/hostdev.xml
new file mode 100644
index 0000000..d382e5d
--- /dev/null
+++ b/internal/virt/domain/templates/hostdev.xml
@@ -0,0 +1,5 @@
+
+
+
\ No newline at end of file
diff --git a/internal/virt/guest/bot.go b/internal/virt/guest/bot.go
index 4b5b733..31ba3a1 100644
--- a/internal/virt/guest/bot.go
+++ b/internal/virt/guest/bot.go
@@ -4,79 +4,96 @@ import (
"context"
"fmt"
"path/filepath"
- "syscall"
"time"
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/core/log"
"github.com/projecteru2/yavirt/configs"
"github.com/projecteru2/yavirt/internal/metrics"
- "github.com/projecteru2/yavirt/internal/models"
+ "github.com/projecteru2/yavirt/internal/types"
"github.com/projecteru2/yavirt/internal/virt/agent"
"github.com/projecteru2/yavirt/internal/virt/domain"
"github.com/projecteru2/yavirt/internal/virt/nic"
- "github.com/projecteru2/yavirt/internal/virt/types"
- "github.com/projecteru2/yavirt/internal/virt/volume"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/projecteru2/yavirt/internal/volume"
+ "github.com/projecteru2/yavirt/internal/volume/base"
+ volFact "github.com/projecteru2/yavirt/internal/volume/factory"
"github.com/projecteru2/yavirt/pkg/libvirt"
- "github.com/projecteru2/yavirt/pkg/log"
+ "github.com/projecteru2/yavirt/pkg/terrors"
"github.com/projecteru2/yavirt/pkg/utils"
+ vmiFact "github.com/yuyang0/vmimage/factory"
+ vmitypes "github.com/yuyang0/vmimage/types"
)
// Bot .
type Bot interface { //nolint
+ Trylock() error
+ Unlock()
Close() error
- Create() error
- Boot() error
- Shutdown(force bool) error
+ Define(ctx context.Context) error
+ Undefine() error
+
+ Boot(ctx context.Context) error
+ Shutdown(ctx context.Context, force bool) error
Suspend() error
Resume() error
- Undefine() error
+ Resize(cpu int, mem int64) error
+
Migrate() error
- OpenConsole(context.Context, types.OpenConsoleFlags) (types.Console, error)
+ OpenConsole(context.Context, types.OpenConsoleFlags) (*libvirt.Console, error)
ExecuteCommand(context.Context, []string) (output []byte, exitCode, pid int, err error)
GetState() (libvirt.DomainState, error)
GetUUID() (string, error)
+ Capture(imgName string) (*vmitypes.Image, error)
+ BindExtraNetwork() error
+
+ // fs-related functions
IsFolder(context.Context, string) (bool, error)
RemoveAll(context.Context, string) error
- Resize(cpu int, mem int64) error
- Capture(user, name string) (*models.UserImage, error)
- AmplifyVolume(vol volume.Virt, cap int64, devPath string) error
- AttachVolume(volmod *models.Volume, devName string) (rollback func(), err error)
- BindExtraNetwork() error
- OpenFile(path, mode string) (agent.File, error)
+ OpenFile(ctx context.Context, path, mode string) (agent.File, error)
MakeDirectory(ctx context.Context, path string, parent bool) error
- Trylock() error
- Unlock()
- CreateSnapshot(*models.Volume) error
- CommitSnapshot(*models.Volume, string) error
- CommitSnapshotByDay(*models.Volume, int) error
- RestoreSnapshot(*models.Volume, string) error
- CheckVolume(*models.Volume) error
- RepairVolume(*models.Volume) error
+ FSFreezeAll(ctx context.Context) (int, error)
+ FSThawAll(ctx context.Context) (int, error)
+ FSFreezeStatus(ctx context.Context) (string, error)
+
+ // GPU-related functions
+ AttachGPUs(pcm map[string]int) error
+ DetachGPUs(pcm map[string]int) error
+
+ // storage-related functions
+ ReplaceSysVolume(vol volume.Volume) error
+ AmplifyVolume(vol volume.Volume, delta int64) error
+ AttachVolume(volmod volume.Volume) (rollback func(), err error)
+ DetachVolume(vol volume.Volume) (err error)
+ CheckVolume(volume.Volume) error
+ RepairVolume(volume.Volume) error
+ CreateSnapshot(volume.Volume) error
+ CommitSnapshot(volume.Volume, string) error
+ CommitSnapshotByDay(volume.Volume, int) error
+ RestoreSnapshot(volume.Volume, string) error
}
type bot struct {
- guest *Guest
- virt libvirt.Libvirt
- dom domain.Domain
- ga *agent.Agent
- flock *utils.Flock
- newVolume func(*models.Volume) volume.Virt
+ guest *Guest
+ virt libvirt.Libvirt
+ dom domain.Domain
+ ga *agent.Agent
+ flock *utils.Flock
}
func newVirtGuest(guest *Guest) (Bot, error) {
virt, err := connectSystemLibvirt()
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
vg := &bot{
- guest: guest,
- virt: virt,
- newVolume: newVolume,
+ guest: guest,
+ virt: virt,
}
vg.dom = domain.New(vg.guest.Guest, vg.virt)
vg.flock = vg.newFlock()
- vg.ga = agent.New(vg.guest.SocketFilepath())
+
+ vg.ga = agent.New(guest.ID, virt)
return vg, nil
}
@@ -85,17 +102,14 @@ func connectSystemLibvirt() (libvirt.Libvirt, error) {
return libvirt.Connect("qemu:///system")
}
-func newVolume(volmod *models.Volume) volume.Virt {
- return volume.New(volmod)
-}
-
func (v *bot) Close() (err error) {
+ logger := log.WithFunc("Close").WithField("guest", v.guest.ID)
if _, err = v.virt.Close(); err != nil {
- log.WarnStack(err)
+ logger.Warnf(context.TODO(), "virt close error:%s", err)
}
if err = v.ga.Close(); err != nil {
- log.WarnStack(err)
+ logger.Warnf(context.TODO(), "ga close error:%s", err)
}
return
@@ -106,47 +120,84 @@ func (v *bot) Migrate() error {
return nil
}
-func (v *bot) Boot() error {
- return utils.Invoke([]func() error{
- v.dom.Boot,
- v.waitGA,
- v.setupNics,
- v.setupVols,
- v.execBatches,
- v.BindExtraNetwork,
- })
-}
+func (v *bot) Boot(ctx context.Context) error {
+ logger := log.WithFunc("Boot").WithField("guest", v.guest.ID)
-func (v *bot) waitGA() error {
- var ctx, cancel = context.WithTimeout(context.Background(), configs.Conf.GABootTimeout.Duration())
- defer cancel()
+ logger.Infof(ctx, "Boot: stage1 -> Domain boot...")
+ if err := v.dom.Boot(ctx); err != nil {
+ return err
+ }
- for i := 1; ; i++ {
- if err := v.ga.Ping(ctx); err != nil {
- select {
- case <-ctx.Done():
- return errors.Trace(err)
+ logger.Infof(ctx, "Boot: stage2 -> Waiting GA...")
+ if err := v.waitGA(ctx); err != nil {
+ return err
+ }
- default:
- log.WarnStack(err)
+ // the following operations only log error and don't return error
- i %= 10
- time.Sleep(time.Second * time.Duration(i))
+ // In normal case, we use cloud-init to set NICs, so here is just a fallback
+ logger.Info(ctx, "Boot: stage3 -> Setting NICs...")
+ if err := v.setupNics(ctx); err != nil {
+ logger.Error(ctx, err, "Boot: stage3 -> Setting NICs failed")
+ }
- if xe := v.reloadGA(); xe != nil {
- return errors.Wrap(err, xe)
- }
+ logger.Info(ctx, "Boot: stage4 -> Setting Vols...")
+ if err := v.setupVols(); err != nil {
+ logger.Error(ctx, err, "Boot: stage4 -> Setting Vols failed")
+ }
+ logger.Info(ctx, "Boot: stage5 -> Executing Batches...")
+ if err := v.execBatches(); err != nil {
+ logger.Errorf(ctx, err, "Boot: stage5 -> Executing Batches failed")
+ }
+ logger.Info(ctx, "Boot: stage6 -> Binding extra networks...")
+ if err := v.BindExtraNetwork(); err != nil {
+ logger.Error(ctx, err, "Boot: stage6 -> Binding extra networks failed")
+ }
+ return nil
+}
- continue
- }
+func (v *bot) waitGA(ctx context.Context) error {
+ logger := log.WithFunc("waitGA").WithField("guest", v.guest.ID)
+ // Create a new context with a shorter timeout
+ // so that we can return a more informative error message when timeout.
+ timeout := 7 * time.Minute
+ if daedline, ok := ctx.Deadline(); ok {
+ timeout = time.Until(daedline) - 30*time.Second
+ if timeout < 0 {
+ timeout = time.Until(daedline)
}
+ }
+ newCtx, cancel := context.WithTimeout(ctx, timeout)
+ defer cancel()
- return nil
+ for i := 0; ; i++ {
+ err := v.ga.Ping(newCtx)
+ if err == nil {
+ return nil
+ }
+
+ logger.Warnf(newCtx, "[waitGA] ping %d times, but still failed %s", i+1, err.Error())
+
+ timeout := time.Duration((i%10)+1) * time.Second
+
+ select {
+ case <-newCtx.Done():
+ errmsg := `
+timeout when waiting boot, this can be caused by:
+1. image doesn't contain qemu-guest-agent package.
+2. image or system disk is corrupted and can't be booted normally.
+ `
+ return errors.Wrap(err, errmsg)
+ case <-time.After(timeout):
+ if xe := v.reloadGA(); xe != nil {
+ return errors.CombineErrors(err, xe)
+ }
+ }
}
}
-func (v *bot) Shutdown(force bool) error {
- return v.dom.Shutdown(force)
+func (v *bot) Shutdown(ctx context.Context, force bool) error {
+ return v.dom.Shutdown(ctx, force)
}
func (v *bot) Suspend() error {
@@ -158,101 +209,148 @@ func (v *bot) Resume() error {
}
func (v *bot) Undefine() error {
- var undeVols = func() (err error) {
- v.guest.rangeVolumes(func(_ int, vol volume.Virt) bool {
- err = vol.Undefine()
- return err == nil
- })
- return
- }
-
- return utils.Invoke([]func() error{
- v.dom.Undefine,
- undeVols,
- })
-}
-
-func (v *bot) Create() error {
- return utils.Invoke([]func() error{
- v.allocVols,
- v.allocGuest,
- })
+ return v.dom.Undefine()
}
-func (v *bot) allocVols() (err error) {
- v.guest.rangeVolumes(func(_ int, vol volume.Virt) bool {
- err = vol.Alloc(v.guest.Img)
- return err == nil
- })
- return
-}
-
-func (v *bot) allocGuest() error {
+func (v *bot) Define(_ context.Context) (err error) {
if err := v.dom.Define(); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
return nil
}
-func (v *bot) CheckVolume(volmod *models.Volume) error {
- vol := v.newVolume(volmod)
- return vol.Check()
+func (v *bot) CheckVolume(volmod volume.Volume) error {
+ return volFact.Check(volmod)
}
-func (v *bot) RepairVolume(volmod *models.Volume) error {
- vol := v.newVolume(volmod)
- return vol.Repair()
+func (v *bot) RepairVolume(volmod volume.Volume) error {
+ return volFact.Repair(volmod)
}
-func (v *bot) CreateSnapshot(volmod *models.Volume) error {
- vol := v.newVolume(volmod)
- return vol.CreateSnapshot()
+func (v *bot) CreateSnapshot(volmod volume.Volume) error {
+ return volFact.CreateSnapshot(volmod)
}
-func (v *bot) CommitSnapshot(volmod *models.Volume, snapID string) error {
- vol := v.newVolume(volmod)
- return vol.CommitSnapshot(snapID)
+func (v *bot) CommitSnapshot(volmod volume.Volume, snapID string) error {
+ return volFact.CommitSnapshot(volmod, snapID)
}
-func (v *bot) CommitSnapshotByDay(volmod *models.Volume, day int) error {
- vol := v.newVolume(volmod)
- return vol.CommitSnapshotByDay(day)
+func (v *bot) CommitSnapshotByDay(volmod volume.Volume, day int) error {
+ return volFact.CommitSnapshotByDay(volmod, day)
}
-func (v *bot) RestoreSnapshot(volmod *models.Volume, snapID string) error {
- vol := v.newVolume(volmod)
- return vol.RestoreSnapshot(snapID)
+func (v *bot) RestoreSnapshot(volmod volume.Volume, snapID string) error {
+ return volFact.RestoreSnapshot(volmod, snapID)
}
// AttachVolume .
-func (v *bot) AttachVolume(volmod *models.Volume, devName string) (func(), error) {
- vol := v.newVolume(volmod)
- return vol.Attach(v.dom, v.ga, devName)
+func (v *bot) AttachVolume(vol volume.Volume) (rollback func(), err error) {
+ devName := vol.GetDevice()
+ dom, err := v.dom.Lookup()
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+
+ rollback, err = volFact.Create(vol)
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+
+ defer func() {
+ if err != nil {
+ rollback()
+ }
+ rollback = nil
+ }()
+
+ var st libvirt.DomainState
+ buf, err := vol.GenerateXML()
+ if err != nil {
+ return
+ }
+ st, err = dom.AttachDevice(string(buf))
+ if err == nil && st == libvirt.DomainRunning && configs.Conf.Storage.InitGuestVolume {
+ log.Debugf(context.TODO(), "Mount(%s): start to mount volume(%s)", v.guest.ID, vol.GetMountDir())
+ err = volFact.Mount(vol, v.ga, base.GetDevicePathByName(devName))
+ }
+ return
+}
+
+// DetachVolume .
+func (v *bot) DetachVolume(vol volume.Volume) (err error) {
+ logger := log.WithFunc("DetachVolume")
+ devPath := vol.GetDevice()
+ if configs.Conf.Storage.InitGuestVolume {
+ switch st, err := v.GetState(); {
+ case err != nil:
+ return errors.Wrap(err, "")
+ case st == libvirt.DomainRunning:
+ if err := volFact.Unmount(vol, v.ga, devPath); err != nil {
+ return errors.Wrap(err, "")
+ }
+ default:
+ logger.Warnf(context.TODO(), "the guest is not running, so ignore to umount")
+ }
+ }
+ _, err = v.dom.DetachVolume(devPath)
+ return
+}
+
+func (v *bot) ReplaceSysVolume(vol volume.Volume) error {
+ diskXML, err := vol.GenerateXML()
+ if err != nil {
+ return err
+ }
+ return v.dom.ReplaceSysVolume(string(diskXML))
}
// AmplifyVolume .
-func (v *bot) AmplifyVolume(vol volume.Virt, cap int64, devPath string) (err error) {
- _, err = vol.Amplify(cap, v.dom, v.ga, devPath)
+func (v *bot) AmplifyVolume(vol volume.Volume, delta int64) (err error) {
+ devPath := base.GetDevicePathByName(vol.GetDevice())
+ dom, err := v.dom.Lookup()
+ if err != nil {
+ return errors.Wrap(err, "")
+ }
+ _, err = volFact.Amplify(vol, delta, dom, v.ga, devPath)
return err
}
+func (v *bot) AttachGPUs(pcm map[string]int) error {
+ for prod, count := range pcm {
+ if _, err := v.dom.AttachGPU(prod, count); err != nil {
+ return errors.Wrap(err, "")
+ }
+ }
+ return nil
+}
+
+func (v *bot) DetachGPUs(pcm map[string]int) error {
+ for prod, count := range pcm {
+ if _, err := v.dom.DetachGPU(prod, count); err != nil {
+ return errors.Wrap(err, "")
+ }
+ }
+ return nil
+}
+
func (v *bot) newFlock() *utils.Flock {
- var fn = fmt.Sprintf("%s.flock", v.guest.ID)
+ var fn = fmt.Sprintf("guest_%s.flock", v.guest.ID)
var fpth = filepath.Join(configs.Conf.VirtFlockDir, fn)
return utils.NewFlock(fpth)
}
-func (v *bot) execBatches() error {
+func (v *bot) execBatches() error { //nolint:unparam
+ logger := log.WithFunc("execBatches").WithField("guest", v.guest.ID)
for _, bat := range configs.Conf.Batches {
if err := v.ga.ExecBatch(bat); err != nil {
if bat.ForceOK {
- log.ErrorStackf(err, "forced batch error")
+ logger.Errorf(context.TODO(), err, "forced batch error")
metrics.IncrError()
break
}
- log.ErrorStackf(err, "non-forced batch err")
+ logger.Errorf(context.TODO(), err, "non-forced batch err")
}
}
@@ -261,30 +359,23 @@ func (v *bot) execBatches() error {
}
func (v *bot) setupVols() (err error) {
- v.guest.rangeVolumes(func(sn int, vol volume.Virt) bool {
+ if !configs.Conf.Storage.InitGuestVolume {
+ return nil
+ }
+ v.guest.rangeVolumes(func(sn int, vol volume.Volume) bool {
if vol.IsSys() {
return true
}
- err = vol.Mount(v.ga, vol.Model().GetDevicePathBySerialNumber(sn))
+ err = volFact.Mount(vol, v.ga, base.GetDevicePathBySerialNumber(sn))
return err == nil
})
return
}
-func (v *bot) setupNics() error {
- var leng = time.Duration(len(v.guest.IPs))
- var ctx, cancel = context.WithTimeout(context.Background(), time.Minute*leng) //nolint
- defer cancel()
-
- for i, ip := range v.guest.IPs {
- var dev = fmt.Sprintf("eth%d", i)
- var distro = v.guest.Distro()
-
- if err := nic.NewNic(ip, v.ga).Setup(ctx, distro, dev); err != nil {
- return errors.Trace(err)
- }
+func (v *bot) setupNics(ctx context.Context) error {
+ if err := nic.NewNicList(v.guest.IPs, v.ga).Setup(ctx); err != nil {
+ return errors.Wrap(err, "")
}
-
return nil
}
@@ -301,10 +392,10 @@ func (v *bot) BindExtraNetwork() error {
ctx, cancel := context.WithTimeout(context.Background(), time.Minute*leng) //nolint
defer cancel()
- for i, netw := range v.guest.ExtraNetworks {
- fn := fmt.Sprintf("%s.extra%d", dev, i)
- if err := nic.NewNic(netw.IP, v.ga).AddIP(ctx, distro, dev, fn); err != nil {
- return errors.Trace(err)
+ for _, netw := range v.guest.ExtraNetworks {
+ // fn := fmt.Sprintf("%s.extra%d", dev, i)
+ if err := nic.NewNic(netw.IP, v.ga).AddIP(ctx, dev); err != nil {
+ return errors.Wrap(err, "")
}
}
@@ -313,35 +404,29 @@ func (v *bot) BindExtraNetwork() error {
func (v *bot) reloadGA() error {
if err := v.ga.Close(); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
- v.ga = agent.New(v.guest.SocketFilepath())
+ v.ga = agent.New(v.guest.ID, v.virt)
return nil
}
-func (v *bot) OpenConsole(_ context.Context, flags types.OpenConsoleFlags) (types.Console, error) {
- ttyname, err := v.dom.GetConsoleTtyname()
+func (v *bot) OpenConsole(_ context.Context, flags types.OpenConsoleFlags) (*libvirt.Console, error) {
+ err := v.dom.CheckRunning()
if err != nil {
return nil, err
}
- stream, err := v.openConsole(ttyname, flags)
- return stream, err
-}
-
-func (v *bot) openConsole(devname string, _ types.OpenConsoleFlags) (types.Console, error) {
- fd, err := syscall.Socket(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
- if err != nil {
- return nil, errors.Trace(err)
- }
-
- _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, uintptr(fd), syscall.F_SETFL, syscall.FD_CLOEXEC)
- if errno != 0 {
- return nil, errors.Trace(err)
+ // yavirtctl may specify devname directly
+ ttyname := flags.Devname
+ if ttyname == "" {
+ ttyname, err = v.dom.GetConsoleTtyname()
+ if err != nil {
+ return nil, err
+ }
}
-
- return fdAdapter{fd}, syscall.Connect(fd, &syscall.SockaddrUnix{Name: devname})
+ c, err := v.dom.OpenConsole(ttyname, flags)
+ return c, err
}
func (v *bot) ExecuteCommand(ctx context.Context, commands []string) (output []byte, exitCode, pid int, err error) {
@@ -350,7 +435,7 @@ func (v *bot) ExecuteCommand(ctx context.Context, commands []string) (output []b
switch leng := len(commands); {
case leng < 1:
- return nil, -1, -1, errors.Annotatef(errors.ErrInvalidValue, "invalid command")
+ return nil, -1, -1, errors.Wrapf(terrors.ErrInvalidValue, "invalid command")
case leng > 1:
args = commands[1:]
fallthrough
@@ -373,17 +458,35 @@ func (v *bot) GetUUID() (string, error) {
return v.dom.GetUUID()
}
-func (v *bot) Capture(user, name string) (*models.UserImage, error) {
+func (v *bot) Capture(imgName string) (uimg *vmitypes.Image, err error) {
if err := v.dom.CheckShutoff(); err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
vol, err := v.guest.sysVolume()
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
- return vol.ConvertImage(user, name)
+ if err := vol.Lock(); err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ defer vol.Unlock()
+
+ if !vol.IsSys() {
+ return nil, errors.Wrapf(terrors.ErrNotSysVolume, "%s is not a system volume", vol.GetID())
+ }
+
+ if uimg, err = vol.CaptureImage(imgName); err != nil {
+ return nil, errors.Wrapf(err, "failed to capture image %s", imgName)
+ }
+ defer func() {
+ if err != nil {
+ _ = vmiFact.RemoveLocal(context.TODO(), uimg)
+ }
+ }()
+
+ return uimg, nil
}
func (v *bot) Trylock() error {
@@ -403,8 +506,8 @@ func (v *bot) Resize(cpu int, mem int64) error {
}
// OpenFile .
-func (v *bot) OpenFile(path string, mode string) (agent.File, error) {
- return agent.OpenFile(v.ga, path, mode)
+func (v *bot) OpenFile(ctx context.Context, path string, mode string) (agent.File, error) {
+ return agent.OpenFile(ctx, v.ga, path, mode)
}
// MakeDirectory .
@@ -421,3 +524,15 @@ func (v *bot) IsFolder(ctx context.Context, path string) (bool, error) {
func (v *bot) RemoveAll(ctx context.Context, path string) error {
return v.ga.RemoveAll(ctx, path)
}
+
+func (v *bot) FSFreezeAll(ctx context.Context) (int, error) {
+ return v.ga.FSFreezeAll(ctx)
+}
+
+func (v *bot) FSThawAll(ctx context.Context) (int, error) {
+ return v.ga.FSThawAll(ctx)
+}
+
+func (v *bot) FSFreezeStatus(ctx context.Context) (string, error) {
+ return v.ga.FSFreezeStatus(ctx)
+}
diff --git a/internal/virt/guest/epoll_console.go b/internal/virt/guest/epoll_console.go
deleted file mode 100644
index f29eccc..0000000
--- a/internal/virt/guest/epoll_console.go
+++ /dev/null
@@ -1,222 +0,0 @@
-package guest
-
-import (
- "io"
- "os"
- "sync"
-
- "github.com/projecteru2/yavirt/internal/virt/types"
- "github.com/projecteru2/yavirt/pkg/errors"
- "golang.org/x/sys/unix"
-)
-
-// implement a epoll based console from guest's natural console
-// ref. https://github.com/containerd/console
-
-const (
- maxEvent = 128
-)
-
-// epoll fd and uses epoll API to perform I/O.
-type EpollConsole struct {
- types.Console
- readc *sync.Cond // signal read is ready upon receiving epoll event
- writec *sync.Cond // signal write is ready upon receiving epoll event
- sysfd int
- closed bool
-}
-
-type Epoller struct {
- efd int
- mu sync.Mutex
- fdMapping map[int]*EpollConsole // to reverse look up epoll triggered console from event's fd
- closeOnce sync.Once // only close once on calling Close()
-}
-
-var currentEpoller *Epoller
-
-func SetupEpoller() error {
- epoller, err := NewEpoller()
- if err != nil {
- return errors.Annotatef(err, "failed to initialize epoller")
- }
- currentEpoller = epoller
- go epoller.Wait() //nolint
- return nil
-}
-
-func GetCurrentEpoller() *Epoller {
- return currentEpoller
-}
-
-func NewEpoller() (*Epoller, error) { // only need 1 epoller upon deamon start & have multiple console registered
- efd, err := unix.EpollCreate1(unix.EPOLL_CLOEXEC)
- if err != nil {
- return nil, err
- }
- return &Epoller{
- efd: efd,
- fdMapping: make(map[int]*EpollConsole),
- }, nil
-}
-
-func (e *Epoller) Add(c types.Console) (*EpollConsole, error) {
- fd := c.Fd()
- // set console fd to non-blocking for epoll
- if err := unix.SetNonblock(fd, true); err != nil {
- return nil, err
- }
-
- ev := unix.EpollEvent{
- Events: unix.EPOLLIN | unix.EPOLLOUT | unix.EPOLLRDHUP | unix.EPOLLET,
- Fd: int32(fd),
- }
- if err := unix.EpollCtl(e.efd, unix.EPOLL_CTL_ADD, fd, &ev); err != nil { // register into epoller
- return nil, err
- }
- ef := &EpollConsole{
- Console: c,
- sysfd: fd,
- readc: sync.NewCond(&sync.Mutex{}),
- writec: sync.NewCond(&sync.Mutex{}),
- }
- e.mu.Lock()
- defer e.mu.Unlock()
- e.fdMapping[fd] = ef
- return ef, nil
-}
-
-// Wait to be run in a separate go routinue, converting epoll event to read/write Cond's singal
-// https://man7.org/linux/man-pages/man2/epoll_wait.2.html
-func (e *Epoller) Wait() error {
- events := make([]unix.EpollEvent, maxEvent)
- for {
- n, err := unix.EpollWait(e.efd, events, -1) // n: # of events received
- if err != nil {
- if err == unix.EINTR { // interrupted or timeout
- continue
- }
- return err
- }
- for i := 0; i < n; i++ {
- ev := &events[i]
- // EPOLLIN: read; EPOLLHUP/EPOLLERR: read close connection or error
- if ev.Events&(unix.EPOLLIN|unix.EPOLLHUP|unix.EPOLLERR) != 0 {
- if ec := e.getConsole(int(ev.Fd)); ec != nil {
- ec.signalRead()
- }
- }
- // EPOLLOUT: write
- if ev.Events&(unix.EPOLLOUT|unix.EPOLLHUP|unix.EPOLLERR) != 0 {
- if ec := e.getConsole(int(ev.Fd)); ec != nil {
- ec.signalWrite()
- }
- }
- }
- }
-}
-
-func (e *Epoller) getConsole(ecfd int) *EpollConsole {
- e.mu.Lock()
- defer e.mu.Unlock()
- return e.fdMapping[ecfd]
-}
-
-// de-register from epoll
-func (e *Epoller) CloseConsole(fd int) error {
- e.mu.Lock()
- delete(e.fdMapping, fd)
- e.mu.Unlock()
- return unix.EpollCtl(e.efd, unix.EPOLL_CTL_DEL, fd, &unix.EpollEvent{})
-}
-
-func (e *Epoller) Close() error {
- closeErr := os.ErrClosed
- e.closeOnce.Do(func() { closeErr = unix.Close(e.efd) })
- return closeErr
-}
-
-func (ec *EpollConsole) signalRead() {
- ec.readc.L.Lock()
- ec.readc.Signal()
- ec.readc.L.Unlock()
-}
-
-func (ec *EpollConsole) signalWrite() {
- ec.writec.L.Lock()
- ec.writec.Signal()
- ec.writec.L.Unlock()
-}
-
-func (ec *EpollConsole) Read(p []byte) (n int, err error) {
- var read int
- ec.readc.L.Lock()
- defer ec.readc.L.Unlock()
- for {
- read, err = ec.Console.Read(p[n:])
- n += read
- if err != nil {
- var hangup bool
- if perr, ok := err.(*os.PathError); ok {
- hangup = (perr.Err == unix.EAGAIN || perr.Err == unix.EIO)
- } else {
- hangup = (err == unix.EAGAIN || err == unix.EIO)
- }
- // if read side did not read anything yet, and epoll console is already closed, will break read loop
- if hangup && !(n == 0 && len(p) > 0 && ec.closed) {
- ec.readc.Wait()
- continue
- }
- }
- break
- }
- // if did not read anything
- if n == 0 && len(p) > 0 && err == nil {
- err = io.EOF
- }
-
- ec.readc.Signal() // singal read finsh
- return n, err
-}
-
-func (ec *EpollConsole) Write(p []byte) (n int, err error) {
- var written int
- ec.writec.L.Lock()
- defer ec.writec.L.Unlock()
- for {
- written, err = ec.Console.Write(p[n:])
- n += written
- if err != nil {
- var hangup bool
- if perr, ok := err.(*os.PathError); ok {
- hangup = (perr.Err == unix.EAGAIN || perr.Err == unix.EIO)
- } else {
- hangup = (err == unix.EAGAIN || err == unix.EIO)
- }
- if hangup {
- ec.writec.Wait()
- continue
- }
- }
- // break if not EAGAIN or IO error
- break
- }
- if n < len(p) && err != nil {
- err = io.ErrShortWrite
- }
- ec.writec.Signal()
- return n, err
-}
-
-// close func for closing ec's fd
-func (ec *EpollConsole) Shutdown(close func(int) error) error {
- ec.readc.L.Lock()
- defer ec.readc.L.Unlock()
- ec.writec.L.Lock()
- defer ec.writec.L.Unlock()
- ec.readc.Broadcast()
- ec.writec.Broadcast()
-
- ec.closed = true
- return close(ec.sysfd)
-}
diff --git a/internal/virt/guest/guest.go b/internal/virt/guest/guest.go
index 7603a0b..a766b4e 100644
--- a/internal/virt/guest/guest.go
+++ b/internal/virt/guest/guest.go
@@ -1,51 +1,62 @@
package guest
import (
+ "bytes"
"context"
+ "encoding/json"
"fmt"
"io"
+ "os"
+ "path/filepath"
"strings"
"sync"
"time"
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/core/log"
+ cpumemtypes "github.com/projecteru2/core/resource/plugins/cpumem/types"
+ "github.com/projecteru2/yavirt/configs"
+ "github.com/projecteru2/yavirt/internal/meta"
"github.com/projecteru2/yavirt/internal/models"
- "github.com/projecteru2/yavirt/internal/virt"
- "github.com/projecteru2/yavirt/internal/virt/types"
- "github.com/projecteru2/yavirt/internal/virt/volume"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/projecteru2/yavirt/internal/types"
+ interutils "github.com/projecteru2/yavirt/internal/utils"
+ "github.com/projecteru2/yavirt/internal/vmcache"
+ "github.com/projecteru2/yavirt/internal/volume"
+ "github.com/projecteru2/yavirt/internal/volume/base"
+ volFact "github.com/projecteru2/yavirt/internal/volume/factory"
"github.com/projecteru2/yavirt/pkg/libvirt"
- "github.com/projecteru2/yavirt/pkg/log"
+ "github.com/projecteru2/yavirt/pkg/terrors"
"github.com/projecteru2/yavirt/pkg/utils"
+ gputypes "github.com/yuyang0/resource-gpu/gpu/types"
+ vmiFact "github.com/yuyang0/vmimage/factory"
+ vmitypes "github.com/yuyang0/vmimage/types"
)
// Guest .
type Guest struct {
*models.Guest
- ctx virt.Context
-
newBot func(*Guest) (Bot, error)
}
// New initializes a new Guest.
-func New(ctx virt.Context, g *models.Guest) *Guest {
+func New(_ context.Context, g *models.Guest) *Guest {
return &Guest{
Guest: g,
- ctx: ctx,
newBot: newVirtGuest,
}
}
// ListLocalIDs lists all local guest domain names.
-func ListLocalIDs(virt.Context) ([]string, error) {
+func ListLocalIDs(ctx context.Context) ([]string, error) {
virt, err := connectSystemLibvirt()
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
defer func() {
if _, ce := virt.Close(); ce != nil {
- log.ErrorStack(ce)
+ log.WithFunc("ListLocalIDs").Errorf(ctx, ce, "failed to close virt")
}
}()
@@ -53,40 +64,38 @@ func ListLocalIDs(virt.Context) ([]string, error) {
}
// Load .
-func (g *Guest) Load() error {
+func (g *Guest) Load(opts ...models.Option) error {
host, err := models.LoadHost()
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
- hand, err := g.NetworkHandler(host)
+ hand, err := g.NetworkHandler()
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
- if err := g.Guest.Load(host, hand); err != nil {
- return errors.Trace(err)
+ if err := g.Guest.Load(host, hand, opts...); err != nil {
+ return errors.Wrap(err, "")
}
return g.loadExtraNetworks()
}
// SyncState .
-func (g *Guest) SyncState() error {
+func (g *Guest) SyncState(ctx context.Context) error {
switch g.Status {
- case models.StatusDestroying:
- return g.ProcessDestroy()
+ case meta.StatusDestroying:
+ return g.ProcessDestroy(ctx, false)
- case models.StatusStopping:
- return g.stop(true)
+ case meta.StatusStopping, meta.StatusStopped:
+ return g.stop(ctx, true)
- case models.StatusRunning:
- fallthrough
- case models.StatusStarting:
- return g.start()
+ case meta.StatusRunning, meta.StatusStarting:
+ return g.start(ctx)
- case models.StatusCreating:
- return g.create()
+ case meta.StatusCreating:
+ return g.create(ctx)
default:
// nothing to do
@@ -94,120 +103,217 @@ func (g *Guest) SyncState() error {
}
}
-// Start .
-func (g *Guest) Start() error {
- return utils.Invoke([]func() error{
- g.ForwardStarting,
- g.start,
+func (g *Guest) UpdateStateIfNecessary() error {
+ err := g.botOperate(func(bot Bot) error { //nolint
+ // check if there is inconsistent status
+ dce := vmcache.FetchDomainEntry(g.ID)
+ if dce != nil {
+ switch {
+ case (g.Status == meta.StatusRunning) && dce.IsStopped():
+ _ = g.ForwardStatus(meta.StatusStopped, true)
+ case (g.Status == meta.StatusStopped) && dce.IsRunning():
+ _ = g.ForwardStatus(meta.StatusRunning, true)
+ }
+ }
+ return nil
})
+ if err == nil || errors.Is(err, terrors.ErrFlockLocked) {
+ return nil
+ }
+ return err
}
-func (g *Guest) start() error {
+// Start .
+func (g *Guest) Start(ctx context.Context, force bool) error {
+ if err := g.ForwardStarting(force); err != nil {
+ return err
+ }
+ defer log.Debugf(ctx, "exit g.Start")
+ return g.start(ctx)
+}
+
+func (g *Guest) start(ctx context.Context) error {
return g.botOperate(func(bot Bot) error {
switch st, err := bot.GetState(); {
case err != nil:
- return errors.Trace(err)
+ return errors.Wrap(err, "")
case st == libvirt.DomainRunning:
- return nil
+ return g.ForwardRunning()
}
-
- return utils.Invoke([]func() error{
- bot.Boot,
- g.joinEthernet,
- g.ForwardRunning,
- })
+ log.Debugf(ctx, "Entering Boot")
+ if err := bot.Boot(ctx); err != nil {
+ return err
+ }
+ log.Debugf(ctx, "Entering joinEthernet")
+ if err := g.joinEthernet(); err != nil {
+ return err
+ }
+ log.Debugf(ctx, "Limiting bandwidth")
+ if err := g.limitBandwidth(); err != nil {
+ return err
+ }
+ log.Debugf(ctx, "Entering forwardRunning")
+ return g.ForwardRunning()
})
}
// Resize .
-func (g *Guest) Resize(cpu int, mem int64, mntCaps map[string]int64) error {
+func (g *Guest) Resize(cpumem *cpumemtypes.EngineParams, gpu *gputypes.EngineParams, vols []volume.Volume) error {
// Only checking, without touch metadata
// due to we wanna keep further booting successfully all the time.
- if !g.CheckForwardStatus(models.StatusResizing) {
- return errors.Annotatef(errors.ErrForwardStatus, "only stopped/running guest can be resized, but it's %s", g.Status)
+ if !g.CheckForwardStatus(meta.StatusResizing) {
+ return errors.Wrapf(terrors.ErrForwardStatus, "only stopped/running guest can be resized, but it's %s", g.Status)
}
- // Actually, mntCaps from ERU will include completed volumes,
- // even those volumes aren't affected.
- if len(mntCaps) > 0 {
- // Just amplifies those original volumes.
- if err := g.amplifyOrigVols(mntCaps); err != nil {
- return errors.Trace(err)
+ newVolMap := map[string]volume.Volume{}
+ for _, vol := range vols {
+ newVolMap[vol.GetMountDir()] = vol
+ }
+ if !cpumem.Remap {
+ // Actually, mntCaps from ERU will include completed volumes,
+ // even those volumes aren't affected.
+ if err := g.handleResizeVolumes(newVolMap); err != nil {
+ return errors.Wrap(err, "")
}
- // Attaches new extra volumes.
- if err := g.attachVols(mntCaps); err != nil {
- return errors.Trace(err)
+ if err := g.handleResizeGPU(gpu); err != nil {
+ return errors.Wrap(err, "")
}
}
- if cpu == g.CPU && mem == g.Memory {
+ log.WithFunc("Guest.Resize").Infof(context.TODO(), "Resize(%s): Resize cpu and memory if necessary", g.ID)
+ if int(cpumem.CPU) == g.CPU && cpumem.Memory == g.Memory {
return nil
}
- return g.resizeSpec(cpu, mem)
+ return g.resizeSpec(int(cpumem.CPU), cpumem.Memory)
}
-func (g *Guest) amplifyOrigVols(mntCaps map[string]int64) error {
- newCapMods := map[string]*models.Volume{}
- for mnt, cap := range mntCaps {
- mod, err := models.NewDataVolume(mnt, cap)
+func (g *Guest) handleResizeGPU(eParams *gputypes.EngineParams) (err error) {
+ addDiff := eParams.DeepCopy()
+ addDiff.Sub(g.GPUEngineParams)
+ subDiff := g.GPUEngineParams.DeepCopy()
+ subDiff.Sub(eParams)
+ needUpdate := false
+ if addDiff.Count() > 0 {
+ // attach new GPU
+ err = g.botOperate(func(bot Bot) error {
+ return bot.AttachGPUs(addDiff.ProdCountMap)
+ })
if err != nil {
- return errors.Trace(err)
+ return
}
- newCapMods[mod.MountDir] = mod
+ needUpdate = true
}
-
- var err error
- g.rangeVolumes(func(sn int, vol volume.Virt) bool {
- newCapMod, affected := newCapMods[vol.Model().MountDir]
- if !affected {
- return true
- }
-
- var delta int64
- switch delta = newCapMod.Capacity - vol.Model().Capacity; {
- case delta < 0:
- err = errors.Annotatef(errors.ErrCannotShrinkVolume, "mount dir: %s", newCapMod.MountDir)
- return false
- case delta == 0: // nothing changed
- return true
- }
-
+ if subDiff.Count() > 0 {
+ // detach old GPU
err = g.botOperate(func(bot Bot) error {
- return bot.AmplifyVolume(vol, delta, vol.Model().GetDevicePathBySerialNumber(sn))
+ return bot.DetachGPUs(subDiff.ProdCountMap)
})
- return err == nil
- })
-
- return err
+ if err != nil {
+ return
+ }
+ needUpdate = true
+ }
+ if needUpdate {
+ g.GPUEngineParams = eParams
+ err = g.Save()
+ }
+ return
}
-func (g *Guest) attachVols(mntCaps map[string]int64) error {
- for mnt, cap := range mntCaps {
- volmod, err := models.NewDataVolume(mnt, cap)
- switch {
- case err != nil:
- return errors.Trace(err)
- case g.Vols.Exists(volmod.MountDir):
+func (g *Guest) handleResizeVolumes(newVolMap map[string]volume.Volume) error {
+ existVolMap := make(map[string]volume.Volume)
+ for _, existVol := range g.Vols {
+ existVolMap[existVol.GetMountDir()] = existVol
+ if existVol.IsSys() {
continue
}
+ if _, ok := newVolMap[existVol.GetMountDir()]; !ok {
+ if err := g.detachVol(existVol); err != nil {
+ return errors.Wrap(err, "")
+ }
+ }
+ }
+ for mountDir, newVol := range newVolMap {
+ existVol, ok := existVolMap[mountDir]
+ if !ok { //nolint
+ if err := g.attachVol(newVol); err != nil {
+ return errors.Wrap(err, "")
+ }
+ } else {
+ if newVol.GetSize() > 0 {
+ if err := g.amplifyOrigVol(existVol, newVol.GetSize()); err != nil {
+ return errors.Wrap(err, "")
+ }
+ } else {
+ if err := g.detachVol(existVol); err != nil {
+ return errors.Wrap(err, "")
+ }
+ }
+ }
+ }
+ return nil
+}
+
+func (g *Guest) amplifyOrigVol(existVol volume.Volume, expectSize int64) error {
+ ctx := context.TODO()
- volmod.GuestID = g.ID
- volmod.Status = g.Status
- volmod.GenerateID()
- if err := g.attachVol(volmod); err != nil {
- return errors.Trace(err)
+ log.Infof(ctx, "[amplifyOrigVol] Amplifying volume %s(device:%s, guest %s)", existVol.GetID(), existVol.GetDevice(), g.ID)
+ var err error
+ delta := expectSize - existVol.GetSize()
+ if delta <= 0 {
+ if delta < 0 {
+ log.Warnf(ctx, "[amplifyOrigVol] Don't allow to shrink volume(%s)", existVol.GetID())
}
+ return nil
}
+ err = g.botOperate(func(bot Bot) error {
+ return bot.AmplifyVolume(existVol, delta)
+ })
+ if err != nil {
+ return err
+ }
return nil
}
-func (g *Guest) attachVol(volmod *models.Volume) (err error) {
+func (g *Guest) detachVol(existVol volume.Volume) error {
+ ctx := context.TODO()
+ logger := log.WithFunc("detachVol").WithField("guest", g.ID)
+
+ var err error
+ logger.Infof(ctx, "Detaching volume %v(device:%s, guest %s)", existVol, existVol.GetDevice(), g.ID)
+ err = g.botOperate(func(bot Bot) error {
+ return bot.DetachVolume(existVol)
+ })
+ if err != nil {
+ logger.Errorf(ctx, err, "Failed to detach volume(%s)", existVol.GetID())
+ return err
+ }
+ g.RemoveVol(existVol.GetID())
+ err = existVol.Delete(true)
+ if err != nil {
+ logger.Errorf(ctx, err, "Failed to delete volume in etcd(%s)", existVol.GetID())
+ return err
+ }
+ err = g.Save()
+ if err != nil {
+ logger.Errorf(ctx, err, "Failed to detach volume(%s)", existVol.GetID())
+ return err
+ }
+ return err
+}
+
+func (g *Guest) attachVol(vol volume.Volume) (err error) {
devName := g.nextVolumeName()
- if err = g.AppendVols(volmod); err != nil {
- return errors.Trace(err)
+ vol.SetGuestID(g.ID)
+ vol.SetStatus(g.Status, true) //nolint:errcheck
+ vol.GenerateID()
+ vol.SetDevice(devName)
+ log.Infof(context.TODO(), "[attachVol] Attaching volume %v(device: %s, guest %s)", vol, vol.GetDevice(), g.ID)
+ if err = g.AppendVols(vol); err != nil {
+ return errors.Wrap(err, "")
}
var rollback func()
@@ -216,12 +322,12 @@ func (g *Guest) attachVol(volmod *models.Volume) (err error) {
if rollback != nil {
rollback()
}
- g.RemoveVol(volmod.ID)
+ g.RemoveVol(vol.GetID())
}
}()
if err = g.botOperate(func(bot Bot) (ae error) {
- rollback, ae = bot.AttachVolume(volmod, devName)
+ rollback, ae = bot.AttachVolume(vol)
return ae
}); err != nil {
return
@@ -234,26 +340,27 @@ func (g *Guest) resizeSpec(cpu int, mem int64) error {
if err := g.botOperate(func(bot Bot) error {
return bot.Resize(cpu, mem)
}); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
return g.Guest.Resize(cpu, mem)
}
// ListSnapshot If volID == "", list snapshots of all vols. Else will find vol with matching volID.
-func (g *Guest) ListSnapshot(volID string) (map[*models.Volume]models.Snapshots, error) {
- volSnap := make(map[*models.Volume]models.Snapshots)
+func (g *Guest) ListSnapshot(volID string) (map[volume.Volume]base.Snapshots, error) {
+ volSnap := make(map[volume.Volume]base.Snapshots)
matched := false
for _, v := range g.Vols {
- if v.ID == volID || volID == "" {
- volSnap[v] = v.Snaps
+ if v.GetID() == volID || volID == "" {
+ api := v.NewSnapshotAPI()
+ volSnap[v] = api.List()
matched = true
}
}
if !matched {
- return nil, errors.Annotatef(errors.ErrInvalidValue, "volID %s not exists", volID)
+ return nil, errors.Wrapf(terrors.ErrInvalidValue, "volID %s not exists", volID)
}
return volSnap, nil
@@ -261,8 +368,8 @@ func (g *Guest) ListSnapshot(volID string) (map[*models.Volume]models.Snapshots,
// CheckVolume .
func (g *Guest) CheckVolume(volID string) error {
- if g.Status != models.StatusStopped && g.Status != models.StatusPaused {
- return errors.Annotatef(errors.ErrForwardStatus,
+ if g.Status != meta.StatusStopped && g.Status != meta.StatusPaused {
+ return errors.Wrapf(terrors.ErrForwardStatus,
"only paused/stopped guest can be perform volume check, but it's %s", g.Status)
}
@@ -274,7 +381,7 @@ func (g *Guest) CheckVolume(volID string) error {
if err := g.botOperate(func(bot Bot) error {
return bot.CheckVolume(vol)
}); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
return nil
@@ -282,8 +389,8 @@ func (g *Guest) CheckVolume(volID string) error {
// RepairVolume .
func (g *Guest) RepairVolume(volID string) error {
- if g.Status != models.StatusStopped {
- return errors.Annotatef(errors.ErrForwardStatus,
+ if g.Status != meta.StatusStopped {
+ return errors.Wrapf(terrors.ErrForwardStatus,
"only stopped guest can be perform volume check, but it's %s", g.Status)
}
@@ -295,7 +402,7 @@ func (g *Guest) RepairVolume(volID string) error {
if err := g.botOperate(func(bot Bot) error {
return bot.RepairVolume(vol)
}); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
return nil
@@ -303,8 +410,8 @@ func (g *Guest) RepairVolume(volID string) error {
// CreateSnapshot .
func (g *Guest) CreateSnapshot(volID string) error {
- if g.Status != models.StatusStopped && g.Status != models.StatusPaused {
- return errors.Annotatef(errors.ErrForwardStatus,
+ if g.Status != meta.StatusStopped && g.Status != meta.StatusPaused {
+ return errors.Wrapf(terrors.ErrForwardStatus,
"only paused/stopped guest can be perform snapshot operation, but it's %s", g.Status)
}
@@ -316,7 +423,7 @@ func (g *Guest) CreateSnapshot(volID string) error {
if err := g.botOperate(func(bot Bot) error {
return bot.CreateSnapshot(vol)
}); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
return nil
@@ -324,8 +431,8 @@ func (g *Guest) CreateSnapshot(volID string) error {
// CommitSnapshot .
func (g *Guest) CommitSnapshot(volID string, snapID string) error {
- if g.Status != models.StatusStopped {
- return errors.Annotatef(errors.ErrForwardStatus,
+ if g.Status != meta.StatusStopped {
+ return errors.Wrapf(terrors.ErrForwardStatus,
"only stopped guest can be perform snapshot operation, but it's %s", g.Status)
}
@@ -337,7 +444,7 @@ func (g *Guest) CommitSnapshot(volID string, snapID string) error {
if err := g.botOperate(func(bot Bot) error {
return bot.CommitSnapshot(vol, snapID)
}); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
return nil
@@ -345,8 +452,8 @@ func (g *Guest) CommitSnapshot(volID string, snapID string) error {
// CommitSnapshot .
func (g *Guest) CommitSnapshotByDay(volID string, day int) error {
- if g.Status != models.StatusStopped {
- return errors.Annotatef(errors.ErrForwardStatus,
+ if g.Status != meta.StatusStopped {
+ return errors.Wrapf(terrors.ErrForwardStatus,
"only stopped guest can be perform snapshot operation, but it's %s", g.Status)
}
@@ -358,7 +465,7 @@ func (g *Guest) CommitSnapshotByDay(volID string, day int) error {
if err := g.botOperate(func(bot Bot) error {
return bot.CommitSnapshotByDay(vol, day)
}); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
return nil
@@ -366,8 +473,8 @@ func (g *Guest) CommitSnapshotByDay(volID string, day int) error {
// RestoreSnapshot .
func (g *Guest) RestoreSnapshot(volID string, snapID string) error {
- if g.Status != models.StatusStopped {
- return errors.Annotatef(errors.ErrForwardStatus,
+ if g.Status != meta.StatusStopped {
+ return errors.Wrapf(terrors.ErrForwardStatus,
"only stopped guest can be perform snapshot operation, but it's %s", g.Status)
}
@@ -379,29 +486,22 @@ func (g *Guest) RestoreSnapshot(volID string, snapID string) error {
if err := g.botOperate(func(bot Bot) error {
return bot.RestoreSnapshot(vol, snapID)
}); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
return nil
}
// Capture .
-func (g *Guest) Capture(user, name string, overridden bool) (uimg *models.UserImage, err error) {
- var orig *models.UserImage
- if overridden {
- if orig, err = models.LoadUserImage(user, name); err != nil {
- return
- }
- }
-
+func (g *Guest) Capture(imgName string, overridden bool) (uimg *vmitypes.Image, err error) {
if err = g.ForwardCapturing(); err != nil {
return
}
if err = g.botOperate(func(bot Bot) error {
var ce error
- if uimg, ce = bot.Capture(user, name); ce != nil {
- return errors.Trace(ce)
+ if uimg, ce = bot.Capture(imgName); ce != nil {
+ return errors.Wrap(ce, "Failed to capture image")
}
return g.ForwardCaptured()
}); err != nil {
@@ -411,14 +511,11 @@ func (g *Guest) Capture(user, name string, overridden bool) (uimg *models.UserIm
if err = g.ForwardStopped(false); err != nil {
return
}
-
- if overridden {
- orig.Distro = uimg.Distro
- orig.Size = uimg.Size
- err = orig.Save()
- } else {
- err = uimg.Create()
+ rc, err := vmiFact.Push(context.TODO(), uimg, overridden)
+ if err != nil {
+ return
}
+ defer interutils.EnsureReaderClosed(rc)
return uimg, err
}
@@ -437,34 +534,59 @@ func (g *Guest) migrate() error {
})
}
-// Create .
-func (g *Guest) Create() error {
- return utils.Invoke([]func() error{
- g.ForwardCreating,
- g.create,
- })
+func (g *Guest) PrepareVolumesForCreate(ctx context.Context) error {
+ rl := interutils.GetRollbackListFromContext(ctx)
+ for _, vol := range g.Vols {
+ if err := volume.WithLocker(vol, func() error {
+ if vol.IsSys() {
+ return vol.PrepareSysDisk(ctx, g.Img)
+ }
+ return vol.PrepareDataDisk(ctx)
+ }); err != nil {
+ return err
+ }
+ if rl != nil {
+ rl.Append(func() error { return volFact.Undefine(vol) }, "dealloc volume")
+ }
+ }
+ return nil
}
-func (g *Guest) create() error {
+// DefineGuestForCreate .
+func (g *Guest) DefineGuestForCreate(ctx context.Context) error {
+ if err := g.ForwardCreating(); err != nil {
+ return err
+ }
+ rl := interutils.GetRollbackListFromContext(ctx)
+ // add a rollback function here, so
+ if rl != nil {
+ rl.Append(func() error {
+ return g.botOperate(func(bot Bot) error {
+ return bot.Undefine()
+ }, true)
+ }, "Undefine guest")
+ }
+ return g.create(ctx)
+}
+
+func (g *Guest) create(ctx context.Context) error {
return g.botOperate(func(bot Bot) error {
- return utils.Invoke([]func() error{
- bot.Create,
- })
+ return bot.Define(ctx)
})
}
// Stop .
-func (g *Guest) Stop(force bool) error {
+func (g *Guest) Stop(ctx context.Context, force bool) error {
if err := g.ForwardStopping(); !force && err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
- return g.stop(force)
+ return g.stop(ctx, force)
}
-func (g *Guest) stop(force bool) error {
+func (g *Guest) stop(ctx context.Context, force bool) error {
return g.botOperate(func(bot Bot) error {
- if err := bot.Shutdown(force); err != nil {
- return errors.Trace(err)
+ if err := bot.Shutdown(ctx, force); err != nil {
+ return errors.Wrap(err, "")
}
return g.ForwardStopped(force)
})
@@ -504,27 +626,105 @@ func (g *Guest) resume() error {
})
}
-// Destroy .
-func (g *Guest) Destroy(force bool) (<-chan error, error) {
- if force {
- if err := g.stop(true); err != nil && !errors.IsDomainNotExistsErr(err) {
- return nil, errors.Trace(err)
- }
+// rewrite the sys disk with image
+func (g *Guest) InitSysDisk(
+ ctx context.Context, img *vmitypes.Image,
+ args *types.InitSysDiskArgs, newSysVol volume.Volume,
+) error {
+ logger := log.WithFunc("InitSysDisk")
+ ciCfg, err := g.GenCloudInit()
+ if err != nil {
+ return errors.Wrap(err, "failed to generate cloud init config")
+ }
+ var (
+ ciUpdated bool
+ )
+ if args.Username != "" {
+ ciCfg.Username = args.Username
+ ciUpdated = true
+ }
+ if args.Password != "" {
+ ciCfg.Password = args.Password
+ ciUpdated = true
+ }
+ if ciUpdated {
+ bs, _ := json.Marshal(ciCfg)
+ g.JSONLabels["instance/cloud-init"] = string(bs)
}
+ if g.ImageName != img.Fullname() {
+ g.ImageName = img.Fullname()
+ g.Img = img
+ }
+ return g.botOperate(func(bot Bot) error {
+ if err := bot.Shutdown(ctx, true); err != nil {
+ return errors.Wrap(err, "")
+ }
+ if err := g.ForwardStopped(true); err != nil {
+ return errors.Wrap(err, "")
+ }
+ oldSysVol := g.Vols[0]
+ newSysVol.SetDevice(oldSysVol.GetDevice())
+ newSysVol.SetGuestID(g.ID)
+ newSysVol.SetHostname(g.HostName)
+ newSysVol.GenerateID()
+ newSysVol.SetStatus(g.Status, true) //nolint:errcheck
+ if err := newSysVol.Save(); err != nil {
+ logger.Errorf(ctx, err, "failed to save new system volume: %v", newSysVol)
+ return errors.Wrapf(err, "failed to save new system volume")
+ }
+ logger.Infof(ctx, "new system volume: %v", newSysVol)
+ // create new sys disk and write image to it
+ if err := newSysVol.PrepareSysDisk(ctx, img); err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ if err := g.SwitchVol(newSysVol, 0); err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ // remove local or rbd disk
+ if err := oldSysVol.Cleanup(); err != nil {
+ return errors.Wrap(err, "")
+ }
+ if err := oldSysVol.Delete(true); err != nil {
+ return errors.Wrap(err, "")
+ }
+ if ciUpdated {
+ output := filepath.Join(configs.Conf.VirtCloudInitDir, fmt.Sprintf("%s.iso", g.ID))
+ if err := ciCfg.ReplaceUserData(output); err != nil {
+ return errors.Wrap(err, "")
+ }
+ }
+ // change domain xml
+ if err := bot.ReplaceSysVolume(newSysVol); err != nil {
+ return errors.Wrapf(err, "failed to undefine domain when init sys disk")
+ }
+ if err := g.Save(); err != nil {
+ return errors.Wrap(err, "")
+ }
+ return nil
+ })
+}
+
+// Destroy .
+func (g *Guest) Destroy(ctx context.Context, force bool) (<-chan error, error) {
+ if err := g.Stop(ctx, force); err != nil && !terrors.IsDomainNotExistsErr(err) {
+ return nil, errors.Wrap(err, "")
+ }
if err := g.ForwardDestroying(force); err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
- log.Infof("[guest.Destroy] set state of guest %s to destroying", g.ID)
+ log.Infof(ctx, "[guest.Destroy] set state of guest %s to destroying", g.ID)
done := make(chan error, 1)
// will return immediately as the destroy request has been accepted.
// the detail work will be processed asynchronously
go func() {
- err := g.ProcessDestroy()
+ err := g.ProcessDestroy(ctx, force)
if err != nil {
- log.ErrorStackf(err, "destroy guest %s failed", g.ID)
+ log.Errorf(ctx, err, "destroy guest %s failed", g.ID)
//TODO: move to recovery list
}
done <- err
@@ -533,28 +733,67 @@ func (g *Guest) Destroy(force bool) (<-chan error, error) {
return done, nil
}
-func (g *Guest) ProcessDestroy() error {
- log.Infof("[guest.destroy] begin to destroy guest %s ", g.ID)
+func (g *Guest) ProcessDestroy(ctx context.Context, force bool) error {
+ logger := log.WithFunc("Guest.ProcessDestroy").WithField("guest", g.ID)
+ logger.Infof(ctx, "begin to destroy guest")
return g.botOperate(func(bot Bot) error {
+ if err := bot.Undefine(); err != nil {
+ logger.Errorf(ctx, err, "failed to undefine guest")
+ return errors.Wrap(err, "")
+ }
+ // delete cloud-init iso
+ ciISOFname := filepath.Join(configs.Conf.VirtCloudInitDir, fmt.Sprintf("%s.iso", g.ID))
+ _ = os.Remove(ciISOFname)
+
+ // try best behavior
if err := g.DeleteNetwork(); err != nil {
- return errors.Trace(err)
+ logger.Errorf(ctx, err, "failed to delete network")
}
- if err := bot.Undefine(); err != nil {
- return errors.Trace(err)
+ for _, vol := range g.Vols {
+ // try best behavior
+ if err := volFact.Undefine(vol); err != nil {
+ logger.Errorf(ctx, err, "failed to undefine volume (volID: %s)", vol.GetID())
+ }
}
+ return g.Delete(force)
+ }, force)
+}
- return g.Delete(false)
+func (g *Guest) FSFreezeAll(ctx context.Context) (nFS int, err error) {
+ err = g.botOperate(func(bot Bot) error {
+ var err error
+ nFS, err = bot.FSFreezeAll(ctx)
+ return err
})
+ return
+}
+
+func (g *Guest) FSThawAll(ctx context.Context) (nFS int, err error) {
+ err = g.botOperate(func(bot Bot) error {
+ var err error
+ nFS, err = bot.FSThawAll(ctx)
+ return err
+ })
+ return
+}
+
+func (g *Guest) FSFreezeStatus(ctx context.Context) (status string, err error) {
+ err = g.botOperate(func(bot Bot) error {
+ var err error
+ status, err = bot.FSFreezeStatus(ctx)
+ return err
+ })
+ return
}
const waitRetries = 30 // 30 second
// Wait .
func (g *Guest) Wait(toStatus string, block bool) error {
if !g.CheckForwardStatus(toStatus) {
- return errors.ErrForwardStatus
+ return terrors.ErrForwardStatus
}
- return g.botOperate(func(bot Bot) error {
+ return g.botOperate(func(bot Bot) error { //nolint:revive
cnt := 0
ticker := time.NewTicker(time.Second)
for range ticker.C {
@@ -583,14 +822,14 @@ func (g *Guest) GetUUID() (uuid string, err error) {
func (g *Guest) botOperate(fn func(bot Bot) error, skipLock ...bool) error {
var bot, err = g.newBot(g)
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
defer bot.Close()
if !(len(skipLock) > 0 && skipLock[0]) {
if err := bot.Trylock(); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
defer bot.Unlock()
}
@@ -603,8 +842,8 @@ func (g *Guest) CacheImage(_ sync.Locker) error {
return nil
}
-func (g *Guest) sysVolume() (vol volume.Virt, err error) {
- g.rangeVolumes(func(_ int, v volume.Virt) bool {
+func (g *Guest) sysVolume() (vol volume.Volume, err error) {
+ g.rangeVolumes(func(_ int, v volume.Volume) bool {
if v.IsSys() {
vol = v
return false
@@ -613,15 +852,15 @@ func (g *Guest) sysVolume() (vol volume.Virt, err error) {
})
if vol == nil {
- err = errors.Annotatef(errors.ErrSysVolumeNotExists, g.ID)
+ err = errors.Wrapf(terrors.ErrSysVolumeNotExists, g.ID)
}
return
}
-func (g *Guest) rangeVolumes(fn func(int, volume.Virt) bool) {
- for i, volmod := range g.Vols {
- if !fn(i, volume.New(volmod)) {
+func (g *Guest) rangeVolumes(fn func(int, volume.Volume) bool) {
+ for i, vol := range g.Vols {
+ if !fn(i, vol) {
return
}
}
@@ -629,119 +868,84 @@ func (g *Guest) rangeVolumes(fn func(int, volume.Virt) bool) {
// Distro .
func (g *Guest) Distro() string {
- return g.Img.GetDistro()
+ return g.Img.OS.Distrib
}
// AttachConsole .
func (g *Guest) AttachConsole(ctx context.Context, serverStream io.ReadWriteCloser, flags types.OpenConsoleFlags) error {
return g.botOperate(func(bot Bot) error {
// epoller should bind with deamon's lifecycle but just init/destroy here for simplicity
- epoller := GetCurrentEpoller()
- if epoller == nil {
- return errors.New("Epoller is not initialized")
- }
- g.ExecuteCommand(ctx, []string{"yaexec", "kill"}) //nolint // to grapple with yavirt collapsed with yaexec alive
- console, err := bot.OpenConsole(ctx, types.NewOpenConsoleFlags(flags.Force, flags.Safe))
- if err != nil {
- return errors.Trace(err)
- }
- epollConsole, err := epoller.Add(console)
+ console, err := bot.OpenConsole(ctx, flags)
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
- log.Infof("[guest.AttachConsole] console opened")
-
- commands := []string{"yaexec", "exec", "--"}
- commands = append(commands, flags.Commands...)
- g.ExecuteCommand(ctx, commands) //nolint
- log.Infof("[guest.AttachConsole] yaexec executing: %v", commands)
- copyDone := make(chan struct{})
- ctx, cancel := context.WithCancel(ctx)
- types.ConsoleStateManager.MarkConsoleOpen(ctx, g.ID)
+ done1 := make(chan struct{})
+ done2 := make(chan struct{})
// pty -> user
- wg := sync.WaitGroup{}
- wg.Add(1)
go func() {
defer func() {
- log.Infof("[guest.AttachConsole] copy console stream to server stream complete")
- types.ConsoleStateManager.MarkConsoleClose(ctx, g.ID)
- select {
- case copyDone <- struct{}{}:
- case <-ctx.Done():
- }
- wg.Done()
- log.Infof("[guest.AttachConsole] copy console stream goroutine exited")
+ close(done1)
+ log.Infof(ctx, "[guest.AttachConsole] copy console stream goroutine exited")
}()
- utils.CopyIO(ctx, serverStream, epollConsole) //nolint
+ console.To(ctx, serverStream) //nolint
}()
// user -> pty
- wg.Add(1)
go func() {
defer func() {
- log.Infof("[guest.AttachConsole] copy server stream to console stream complete")
- select {
- case copyDone <- struct{}{}:
- case <-ctx.Done():
- }
- wg.Done()
- log.Infof("[guest.AttachConsole] copy server stream goroutine exited")
+ close(done2)
+ log.Infof(ctx, "[guest.AttachConsole] copy server stream goroutine exited")
}()
- utils.CopyIO(ctx, epollConsole, serverStream) //nolint
- }()
- // close MPSC chan
- go func() {
- wg.Wait()
- close(copyDone)
- log.Infof("[guest.AttachConsole] copy closed")
+ initCmds := append([]byte(strings.Join(flags.Commands, " ")), '\r')
+ reader := io.MultiReader(bytes.NewBuffer(initCmds), serverStream)
+ console.From(ctx, reader) //nolint
}()
// either copy goroutine exit
select {
- case <-copyDone:
+ case <-done1:
+ case <-done2:
case <-ctx.Done():
+ log.Debugf(ctx, "[guest.AttachConsole] context done")
}
- cancel()
- // remove from epoller and shutdown console
- if err := epollConsole.Shutdown(epoller.CloseConsole); err != nil {
- log.Errorf("[guest.AttachConsole] failed to shutdown epoll console")
- }
- if err := epollConsole.Close(); err != nil {
- log.Errorf("[guest.AttachConsole] failed to close epoll console")
- }
- g.ExecuteCommand(context.Background(), []string{"yaexec", "kill"}) //nolint
- log.Infof("[guest.AttachConsole] yaexec completes: %v", commands)
+ console.Close()
+ <-done1
+ <-done2
+ log.Infof(ctx, "[guest.AttachConsole] exit.")
+ // g.ExecuteCommand(context.Background(), []string{"yaexec", "kill"}) //nolint
+ // log.Infof(ctx, "[guest.AttachConsole] yaexec completes: %v", commands)
return nil
})
}
// ResizeConsoleWindow .
-func (g *Guest) ResizeConsoleWindow(ctx context.Context, height, width uint) (err error) {
- return g.botOperate(func(bot Bot) error {
- types.ConsoleStateManager.WaitUntilConsoleOpen(ctx, g.ID)
- resizeCmd := fmt.Sprintf("yaexec resize -r %d -c %d", height, width)
- output, code, _, err := g.ExecuteCommand(ctx, strings.Split(resizeCmd, " "))
- if code != 0 || err != nil {
- log.Errorf("[guest.ResizeConsoleWindow] resize failed: %v, %v", output, err)
- }
- return err
- }, true)
+func (g *Guest) ResizeConsoleWindow(ctx context.Context, height, width uint) (err error) { //nolint
+ // TODO better way to resize console window size
+ return nil
+ // return g.botOperate(func(bot Bot) error {
+ // resizeCmd := fmt.Sprintf("yaexec resize -r %d -c %d", height, width)
+ // output, code, _, err := g.ExecuteCommand(ctx, strings.Split(resizeCmd, " "))
+ // if code != 0 || err != nil {
+ // log.Errorf("[guest.ResizeConsoleWindow] resize failed: %v, %v", output, err)
+ // }
+ // return err
+ // }, true)
}
// Cat .
-func (g *Guest) Cat(ctx context.Context, path string, dest io.WriteCloser) error {
+func (g *Guest) Cat(ctx context.Context, path string, dest io.Writer) error {
return g.botOperate(func(bot Bot) error {
- src, err := bot.OpenFile(path, "r")
+ src, err := bot.OpenFile(ctx, path, "r")
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
- defer src.Close()
+ defer src.Close(ctx)
- _, err = utils.CopyIO(ctx, dest, src)
+ _, err = src.CopyTo(ctx, dest)
return err
})
@@ -754,9 +958,9 @@ func (g *Guest) Log(ctx context.Context, n int, logPath string, dest io.WriteClo
return nil
}
switch g.Status {
- case models.StatusRunning:
+ case meta.StatusRunning:
return g.logRunning(ctx, bot, n, logPath, dest)
- case models.StatusStopped:
+ case meta.StatusStopped:
gfx, err := g.getGfx(logPath)
if err != nil {
return err
@@ -764,7 +968,7 @@ func (g *Guest) Log(ctx context.Context, n int, logPath string, dest io.WriteClo
defer gfx.Close()
return g.logStopped(n, logPath, dest, gfx)
default:
- return errors.Annotatef(errors.ErrNotValidLogStatus, "guest is %s", g.Status)
+ return errors.Wrapf(terrors.ErrNotValidLogStatus, "guest is %s", g.Status)
}
})
}
@@ -773,19 +977,19 @@ func (g *Guest) Log(ctx context.Context, n int, logPath string, dest io.WriteClo
func (g *Guest) CopyToGuest(ctx context.Context, dest string, content chan []byte, overrideFolder bool) error {
return g.botOperate(func(bot Bot) error {
switch g.Status {
- case models.StatusRunning:
+ case meta.StatusRunning:
return g.copyToGuestRunning(ctx, dest, content, bot, overrideFolder)
- case models.StatusStopped:
+ case meta.StatusStopped:
fallthrough
- case models.StatusCreating:
+ case meta.StatusCreating:
gfx, err := g.getGfx(dest)
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
defer gfx.Close()
return g.copyToGuestNotRunning(dest, content, overrideFolder, gfx)
default:
- return errors.Annotatef(errors.ErrNotValidCopyStatus, "guest is %s", g.Status)
+ return errors.Wrapf(terrors.ErrNotValidCopyStatus, "guest is %s", g.Status)
}
})
}
@@ -795,9 +999,9 @@ func (g *Guest) ExecuteCommand(ctx context.Context, commands []string) (output [
err = g.botOperate(func(bot Bot) error {
switch st, err := bot.GetState(); {
case err != nil:
- return errors.Trace(err)
+ return errors.Wrap(err, "")
case st != libvirt.DomainRunning:
- return errors.Annotatef(errors.ErrExecOnNonRunningGuest, g.ID)
+ return errors.Wrapf(terrors.ErrExecOnNonRunningGuest, g.ID)
}
output, exitCode, pid, err = bot.ExecuteCommand(ctx, commands)
@@ -807,6 +1011,20 @@ func (g *Guest) ExecuteCommand(ctx context.Context, commands []string) (output [
}
// nextVolumeName .
+// 这里不能通过guest的vols长度来生成名字,原因如下:
+// vda, vdb, vdc, 如果detach vdb, 那么这时候长度为2, 在生成名字就是vdc, 那么就冲突了
func (g *Guest) nextVolumeName() string {
- return models.GetDeviceName(g.Vols.Len())
+ seenDev := make(map[string]bool)
+ g.rangeVolumes(func(_ int, vol volume.Volume) bool {
+ seenDev[vol.GetDevice()] = true
+ return true
+ })
+
+ for idx := 0; idx < 26; idx++ {
+ dev := base.GetDeviceName(idx)
+ if !seenDev[dev] {
+ return dev
+ }
+ }
+ return ""
}
diff --git a/internal/virt/guest/guest_copy_file.go b/internal/virt/guest/guest_copy_file.go
index 7d4314f..19327fd 100644
--- a/internal/virt/guest/guest_copy_file.go
+++ b/internal/virt/guest/guest_copy_file.go
@@ -5,41 +5,41 @@ import (
"os"
"path"
+ "github.com/cockroachdb/errors"
"github.com/projecteru2/yavirt/internal/virt/guestfs"
- "github.com/projecteru2/yavirt/internal/virt/guestfs/gfsx"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/projecteru2/yavirt/pkg/terrors"
)
func (g *Guest) copyToGuestRunning(ctx context.Context, dest string, content chan []byte, bot Bot, overrideFolder bool) error {
if !overrideFolder {
if isFolder, err := bot.IsFolder(ctx, dest); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
} else if isFolder {
- return errors.ErrFolderExists
+ return terrors.ErrFolderExists
}
}
if err := bot.RemoveAll(ctx, dest); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
if err := bot.MakeDirectory(ctx, path.Dir(dest), true); err != nil {
return err
}
- src, err := bot.OpenFile(dest, "w")
+ src, err := bot.OpenFile(ctx, dest, "w")
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
- defer src.Close()
+ defer src.Close(ctx)
for {
buffer, ok := <-content
if !ok {
return nil
}
- if _, err = src.Write(buffer); err != nil {
- return errors.Trace(err)
+ if _, err = src.Write(ctx, buffer); err != nil {
+ return errors.Wrap(err, "")
}
}
}
@@ -51,12 +51,12 @@ func (g *Guest) copyToGuestNotRunning(dest string, content chan []byte, override
return err
}
if isDir {
- return errors.ErrFolderExists
+ return terrors.ErrFolderExists
}
}
if err := gfx.Remove(dest); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
if err := gfx.MakeDirectory(path.Dir(dest), true); err != nil {
@@ -65,7 +65,7 @@ func (g *Guest) copyToGuestNotRunning(dest string, content chan []byte, override
f, err := os.CreateTemp(os.TempDir(), "toCopy-*")
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
defer os.Remove(f.Name())
defer f.Close()
@@ -76,11 +76,11 @@ func (g *Guest) copyToGuestNotRunning(dest string, content chan []byte, override
break
}
if _, err = f.Write(buffer); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
}
- return errors.Trace(gfx.Upload(f.Name(), dest))
+ return errors.Wrap(gfx.Upload(f.Name(), dest), "gfx upload error")
}
func (g *Guest) getGfx(dest string) (guestfs.Guestfs, error) {
@@ -88,6 +88,5 @@ func (g *Guest) getGfx(dest string) (guestfs.Guestfs, error) {
if err != nil {
return nil, err
}
-
- return gfsx.New(vol.Filepath())
+ return vol.GetGfx()
}
diff --git a/internal/virt/guest/guest_copy_file_test.go b/internal/virt/guest/guest_copy_file_test.go
index 40d9adf..c86f909 100644
--- a/internal/virt/guest/guest_copy_file_test.go
+++ b/internal/virt/guest/guest_copy_file_test.go
@@ -6,8 +6,8 @@ import (
"github.com/projecteru2/yavirt/internal/meta"
"github.com/projecteru2/yavirt/internal/virt/agent/mocks"
- "github.com/projecteru2/yavirt/internal/virt/volume"
- "github.com/projecteru2/yavirt/pkg/errors"
+ volFact "github.com/projecteru2/yavirt/internal/volume/factory"
+ "github.com/projecteru2/yavirt/pkg/terrors"
"github.com/projecteru2/yavirt/pkg/test/assert"
"github.com/projecteru2/yavirt/pkg/test/mock"
)
@@ -22,24 +22,25 @@ func TestCopyFileRunning(t *testing.T) {
ctx, cancel := meta.Context(context.Background())
defer cancel()
- f.On("Write", mock.Anything).Return(1, nil)
- f.On("Close").Return(nil).Once()
+ f.On("Write", mock.Anything, mock.Anything).Return(1, nil)
+ f.On("Close", mock.Anything).Return(nil).Once()
bot.On("RemoveAll", mock.Anything, mock.Anything).Return(nil).Once()
bot.On("MakeDirectory", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
- bot.On("OpenFile", mock.Anything, mock.Anything).Return(f, nil).Once()
+ bot.On("OpenFile", mock.Anything, mock.Anything, mock.Anything).Return(f, nil).Once()
content := make(chan []byte, 10)
content <- []byte{'a', 'b', 'c'}
close(content)
- assert.NilErr(t, guest.copyToGuestRunning(ctx, "/root/test", content, bot, true))
+ err := guest.copyToGuestRunning(ctx, "/root/test", content, bot, true)
+ assert.NilErr(t, err)
bot.On("IsFolder", mock.Anything, mock.Anything).Return(true, nil).Once()
- assert.Equal(t, errors.ErrFolderExists, guest.copyToGuestRunning(ctx, "/root/test", content, bot, false))
+ assert.Equal(t, terrors.ErrFolderExists, guest.copyToGuestRunning(ctx, "/root/test", content, bot, false))
}
func TestCopyFileNotRunning(t *testing.T) {
var guest, _ = newMockedGuest(t)
- _, gfx := volume.NewMockedVolume()
+ _, gfx := volFact.NewMockedVolume()
gfx.On("Remove", mock.Anything).Return(nil).Once()
gfx.On("MakeDirectory", mock.Anything, mock.Anything).Return(nil).Once()
gfx.On("Upload", mock.Anything, mock.Anything).Return(nil).Once()
@@ -50,5 +51,5 @@ func TestCopyFileNotRunning(t *testing.T) {
assert.NilErr(t, guest.copyToGuestNotRunning("/root/test", content, true, gfx))
gfx.On("IsDir", mock.Anything).Return(true, nil).Once()
- assert.Equal(t, errors.ErrFolderExists, guest.copyToGuestNotRunning("/root/test", content, false, gfx))
+ assert.Equal(t, terrors.ErrFolderExists, guest.copyToGuestNotRunning("/root/test", content, false, gfx))
}
diff --git a/internal/virt/guest/guest_log.go b/internal/virt/guest/guest_log.go
index a2b07d2..16070bf 100644
--- a/internal/virt/guest/guest_log.go
+++ b/internal/virt/guest/guest_log.go
@@ -4,24 +4,23 @@ import (
"context"
"io"
+ "github.com/cockroachdb/errors"
"github.com/projecteru2/yavirt/internal/virt/guestfs"
- "github.com/projecteru2/yavirt/pkg/errors"
- "github.com/projecteru2/yavirt/pkg/utils"
)
-func (g *Guest) logRunning(ctx context.Context, bot Bot, n int, logPath string, dest io.WriteCloser) error {
- src, err := bot.OpenFile(logPath, "r")
+func (g *Guest) logRunning(ctx context.Context, bot Bot, n int, logPath string, dest io.Writer) error {
+ src, err := bot.OpenFile(ctx, logPath, "r")
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
- defer src.Close()
+ defer src.Close(ctx)
if n < 0 { // read all
- _, err = utils.CopyIO(ctx, dest, src)
+ _, err = src.CopyTo(ctx, dest)
return err
}
- content, err := src.Tail(n)
+ content, err := src.Tail(ctx, n)
if err != nil {
return err
}
@@ -30,7 +29,7 @@ func (g *Guest) logRunning(ctx context.Context, bot Bot, n int, logPath string,
return err
}
-func (g *Guest) logStopped(n int, logPath string, dest io.WriteCloser, gfx guestfs.Guestfs) error {
+func (g *Guest) logStopped(n int, logPath string, dest io.Writer, gfx guestfs.Guestfs) error {
if n < 0 { // Read all
content, err := gfx.Read(logPath)
if err != nil {
diff --git a/internal/virt/guest/guest_log_test.go b/internal/virt/guest/guest_log_test.go
index d21ea85..0484304 100644
--- a/internal/virt/guest/guest_log_test.go
+++ b/internal/virt/guest/guest_log_test.go
@@ -2,13 +2,12 @@ package guest
import (
"context"
- "io"
"os"
"testing"
"github.com/projecteru2/yavirt/internal/meta"
"github.com/projecteru2/yavirt/internal/virt/agent/mocks"
- "github.com/projecteru2/yavirt/internal/virt/volume"
+ volFact "github.com/projecteru2/yavirt/internal/volume/factory"
"github.com/projecteru2/yavirt/pkg/test/assert"
"github.com/projecteru2/yavirt/pkg/test/mock"
)
@@ -18,8 +17,7 @@ func TestLogRunning(t *testing.T) {
defer bot.AssertExpectations(t)
f := &mocks.File{}
- f.On("Read", mock.Anything).Return(0, io.EOF)
- f.On("Close").Return(nil)
+ f.On("Close", mock.Anything).Return(nil)
defer f.AssertExpectations(t)
ctx, cancel := meta.Context(context.Background())
@@ -27,17 +25,20 @@ func TestLogRunning(t *testing.T) {
content := []byte{'a', 'b', 'c'}
- bot.On("OpenFile", mock.Anything, mock.Anything).Return(f, nil).Once()
+ f.On("CopyTo", mock.Anything, mock.Anything).Return(0, nil).Once()
+ bot.On("OpenFile", mock.Anything, mock.Anything, mock.Anything).Return(f, nil).Once()
tmp, err := os.OpenFile("/dev/null", os.O_WRONLY, 0)
assert.NilErr(t, err)
- assert.NilErr(t, guest.logRunning(ctx, bot, -1, "/tmp/log", tmp))
+ err = guest.logRunning(ctx, bot, -1, "/tmp/log", tmp)
+ assert.NilErr(t, err)
tmp.Close()
- bot.On("OpenFile", mock.Anything, mock.Anything).Return(f, nil).Once()
- f.On("Tail", mock.Anything).Return(content, nil).Once()
+ bot.On("OpenFile", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(f, nil).Once()
+ f.On("Tail", mock.Anything, mock.Anything).Return(content, nil).Once()
tmp, err = os.OpenFile("/dev/null", os.O_WRONLY, 0)
assert.NilErr(t, err)
- assert.NilErr(t, guest.logRunning(ctx, bot, 1, "/tmp/log", tmp))
+ err = guest.logRunning(ctx, bot, 1, "/tmp/log", tmp)
+ assert.NilErr(t, err)
tmp.Close()
}
@@ -45,7 +46,7 @@ func TestLogStopped(t *testing.T) {
guest, bot := newMockedGuest(t)
defer bot.AssertExpectations(t)
- _, gfx := volume.NewMockedVolume()
+ _, gfx := volFact.NewMockedVolume()
defer gfx.AssertExpectations(t)
content := []byte{'a', 'b', 'c'}
diff --git a/internal/virt/guest/guest_test.go b/internal/virt/guest/guest_test.go
index dd48456..902b3e7 100644
--- a/internal/virt/guest/guest_test.go
+++ b/internal/virt/guest/guest_test.go
@@ -6,10 +6,19 @@ import (
"testing"
"time"
+ "github.com/agiledragon/gomonkey/v2"
+ cpumemtypes "github.com/projecteru2/core/resource/plugins/cpumem/types"
+ "github.com/projecteru2/yavirt/configs"
+ "github.com/projecteru2/yavirt/internal/meta"
"github.com/projecteru2/yavirt/internal/models"
+ "github.com/projecteru2/yavirt/internal/network"
+ networkFactory "github.com/projecteru2/yavirt/internal/network/factory"
+ "github.com/projecteru2/yavirt/internal/types"
"github.com/projecteru2/yavirt/internal/virt/guest/mocks"
- "github.com/projecteru2/yavirt/internal/virt/volume"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/projecteru2/yavirt/internal/volume"
+ volFact "github.com/projecteru2/yavirt/internal/volume/factory"
+ "github.com/projecteru2/yavirt/internal/volume/local"
+ volmocks "github.com/projecteru2/yavirt/internal/volume/mocks"
"github.com/projecteru2/yavirt/pkg/idgen"
"github.com/projecteru2/yavirt/pkg/libvirt"
storemocks "github.com/projecteru2/yavirt/pkg/store/mocks"
@@ -17,6 +26,9 @@ import (
"github.com/projecteru2/yavirt/pkg/test/mock"
"github.com/projecteru2/yavirt/pkg/utils"
utilmocks "github.com/projecteru2/yavirt/pkg/utils/mocks"
+ gputypes "github.com/yuyang0/resource-gpu/gpu/types"
+ vmiFact "github.com/yuyang0/vmimage/factory"
+ vmitypes "github.com/yuyang0/vmimage/types"
)
const (
@@ -25,217 +37,246 @@ const (
)
func init() {
- idgen.Setup(0, time.Now())
- models.Setup()
+ idgen.Setup(0)
+}
+
+func newTestImage(username, name, tag, baseDir string) *vmitypes.Image {
+ fullname := fmt.Sprintf("%s/%s:%s", username, name, tag)
+ if username == "" {
+ fullname = fmt.Sprintf("%s:%s", name, tag)
+ }
+ img, _ := vmiFact.NewImage(fullname)
+ return img
}
func TestCreate_WithExtVolumes(t *testing.T) {
var guest, bot = newMockedGuest(t)
defer bot.AssertExpectations(t)
- var genvol = func(id int64, cap int64) *models.Volume {
- vol, err := models.NewDataVolume("/data", cap)
+ var genvol = func(id int64, cap int64) volume.Volume {
+ vol, err := local.NewDataVolume("/data", cap)
assert.NilErr(t, err)
return vol
}
- var extVols = []*models.Volume{genvol(1, utils.GB*10), genvol(2, utils.GB*20)}
+ var extVols = []volume.Volume{genvol(1, utils.GB*10), genvol(2, utils.GB*20)}
guest.AppendVols(extVols...)
- guest.rangeVolumes(checkVolsStatus(t, models.StatusPending))
+ guest.rangeVolumes(checkVolsStatus(t, meta.StatusPending))
- var meta, metaCancel = storemocks.Mock()
- defer metaCancel()
- defer meta.AssertExpectations(t)
+ var sto, stoCancel = storemocks.Mock()
+ defer stoCancel()
+ defer sto.AssertExpectations(t)
- bot.On("Create").Return(nil).Once()
+ bot.On("Define", mock.Anything).Return(nil).Once()
bot.On("Close").Return(nil).Once()
- meta.On("Update", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
+ sto.On("Update", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
bot.On("Trylock").Return(nil)
bot.On("Unlock").Return()
- assert.NilErr(t, guest.Create())
- assert.Equal(t, models.StatusCreating, guest.Status)
- guest.rangeVolumes(checkVolsStatus(t, models.StatusCreating))
+ assert.NilErr(t, guest.DefineGuestForCreate(context.Background()))
+ assert.Equal(t, meta.StatusCreating, guest.Status)
+ guest.rangeVolumes(checkVolsStatus(t, meta.StatusCreating))
}
func TestLifecycle(t *testing.T) {
+ ctx, cancelFn := context.WithTimeout(context.Background(), 5*time.Minute)
+ defer cancelFn()
+
var guest, bot = newMockedGuest(t)
defer bot.AssertExpectations(t)
- assert.Equal(t, models.StatusPending, guest.Status)
- guest.rangeVolumes(checkVolsStatus(t, models.StatusPending))
+ assert.Equal(t, meta.StatusPending, guest.Status)
+ guest.rangeVolumes(checkVolsStatus(t, meta.StatusPending))
- var meta, metaCancel = storemocks.Mock()
- defer metaCancel()
- defer meta.AssertExpectations(t)
- meta.On("Update", mock.Anything, mock.Anything, mock.Anything).Return(nil)
+ var sto, stoCancel = storemocks.Mock()
+ defer stoCancel()
+ defer sto.AssertExpectations(t)
+ sto.On("Update", mock.Anything, mock.Anything, mock.Anything).Return(nil)
bot.On("Trylock").Return(nil)
bot.On("Unlock").Return()
- bot.On("Create").Return(nil).Once()
+ bot.On("Define", mock.Anything).Return(nil).Once()
bot.On("Close").Return(nil).Once()
- assert.NilErr(t, guest.Create())
- assert.Equal(t, models.StatusCreating, guest.Status)
- guest.rangeVolumes(checkVolsStatus(t, models.StatusCreating))
+ assert.NilErr(t, guest.DefineGuestForCreate(context.Background()))
+ assert.Equal(t, meta.StatusCreating, guest.Status)
+ guest.rangeVolumes(checkVolsStatus(t, meta.StatusCreating))
- bot.On("Boot").Return(nil).Once()
+ bot.On("Boot", ctx).Return(nil).Once()
bot.On("Close").Return(nil).Once()
bot.On("GetState").Return(libvirt.DomainShutoff, nil).Once()
- assert.NilErr(t, guest.Start())
- assert.Equal(t, models.StatusRunning, guest.Status)
- guest.rangeVolumes(checkVolsStatus(t, models.StatusRunning))
+ assert.NilErr(t, guest.Start(ctx, false))
+ assert.Equal(t, meta.StatusRunning, guest.Status)
+ guest.rangeVolumes(checkVolsStatus(t, meta.StatusRunning))
- bot.On("Shutdown", mock.Anything).Return(nil).Once()
+ bot.On("Shutdown", ctx, mock.Anything).Return(nil).Once()
bot.On("Close").Return(nil).Once()
- assert.NilErr(t, guest.Stop(true))
- assert.Equal(t, models.StatusStopped, guest.Status)
- guest.rangeVolumes(checkVolsStatus(t, models.StatusStopped))
+ assert.NilErr(t, guest.Stop(ctx, true))
+ assert.Equal(t, meta.StatusStopped, guest.Status)
+ guest.rangeVolumes(checkVolsStatus(t, meta.StatusStopped))
- assert.NilErr(t, guest.Resize(guest.CPU, guest.Memory, map[string]int64{}))
- assert.Equal(t, models.StatusStopped, guest.Status)
- guest.rangeVolumes(checkVolsStatus(t, models.StatusStopped))
+ cpumem := &cpumemtypes.EngineParams{
+ CPU: float64(guest.CPU),
+ Memory: guest.Memory,
+ }
+ gpu := &gputypes.EngineParams{
+ ProdCountMap: gputypes.ProdCountMap{},
+ }
+ assert.NilErr(t, guest.Resize(cpumem, gpu, []volume.Volume{}))
+ assert.Equal(t, meta.StatusStopped, guest.Status)
+ guest.rangeVolumes(checkVolsStatus(t, meta.StatusStopped))
- bot.On("Capture", mock.Anything, mock.Anything).Return(models.NewUserImage("anrs", "aa", 1024), nil).Once()
+ mgr := vmiFact.GetMockManager()
+ mgr.On("Push", mock.Anything, mock.Anything, mock.Anything).Return(nil, nil).Once()
+ defer mgr.AssertExpectations(t)
+ img := &vmitypes.Image{}
+
+ bot.On("Capture", mock.Anything, mock.Anything).Return(img, nil).Once()
bot.On("Close").Return(nil).Once()
- meta.On("Get", mock.Anything, mock.Anything, mock.Anything).Return(int64(0), nil)
- _, err := guest.Capture("anrs", "aa", true)
+ _, err := guest.Capture("anrs/aa", true)
assert.NilErr(t, err)
- assert.Equal(t, models.StatusStopped, guest.Status)
- guest.rangeVolumes(checkVolsStatus(t, models.StatusStopped))
+ assert.Equal(t, meta.StatusStopped, guest.Status)
+ guest.rangeVolumes(checkVolsStatus(t, meta.StatusStopped))
- bot.On("Boot").Return(nil).Once()
+ bot.On("Boot", ctx).Return(nil).Once()
bot.On("Close").Return(nil).Once()
bot.On("GetState").Return(libvirt.DomainShutoff, nil).Once()
- assert.NilErr(t, guest.Start())
- assert.Equal(t, models.StatusRunning, guest.Status)
- guest.rangeVolumes(checkVolsStatus(t, models.StatusRunning))
+ assert.NilErr(t, guest.Start(ctx, false))
+ assert.Equal(t, meta.StatusRunning, guest.Status)
+ guest.rangeVolumes(checkVolsStatus(t, meta.StatusRunning))
- bot.On("Shutdown", mock.Anything).Return(nil).Once()
+ bot.On("Shutdown", ctx, mock.Anything).Return(nil).Once()
bot.On("Close").Return(nil).Once()
- assert.NilErr(t, guest.Stop(true))
- assert.Equal(t, models.StatusStopped, guest.Status)
- guest.rangeVolumes(checkVolsStatus(t, models.StatusStopped))
+ assert.NilErr(t, guest.Stop(ctx, true))
+ assert.Equal(t, meta.StatusStopped, guest.Status)
+ guest.rangeVolumes(checkVolsStatus(t, meta.StatusStopped))
bot.On("Undefine").Return(nil).Once()
bot.On("Close").Return(nil).Once()
+ // destroy always calls stop
+ bot.On("Close").Return(nil).Once()
+ bot.On("Shutdown", ctx, false).Return(nil).Once()
- mutex := mockMutex()
- defer mutex.AssertExpectations(t)
+ sto.On("Delete", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
- meta.On("NewMutex", mock.Anything).Return(mutex, nil).Once()
- meta.On("Delete", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
- done, err := guest.Destroy(false)
+ done, err := guest.Destroy(ctx, false)
assert.NilErr(t, err)
assert.NilErr(t, <-done)
}
-func checkVolsStatus(t *testing.T, expSt string) func(int, volume.Virt) bool {
- return func(_ int, v volume.Virt) bool {
- assert.Equal(t, expSt, v.Model().Status)
+func checkVolsStatus(t *testing.T, expSt string) func(int, volume.Volume) bool {
+ return func(_ int, v volume.Volume) bool {
+ assert.Equal(t, expSt, v.GetStatus())
return true
}
}
func TestLifecycle_InvalidStatus(t *testing.T) {
+ ctx, cancelFn := context.WithTimeout(context.Background(), 5*time.Minute)
+ defer cancelFn()
+
var guest, bot = newMockedGuest(t)
defer bot.AssertExpectations(t)
- guest.Status = models.StatusDestroyed
- assert.Err(t, guest.Create())
- assert.Err(t, guest.Stop(false))
- assert.Err(t, guest.Start())
+ guest.Status = meta.StatusDestroyed
+ assert.Err(t, guest.DefineGuestForCreate(context.Background()))
+ assert.Err(t, guest.Stop(ctx, false))
+ assert.Err(t, guest.Start(ctx, false))
- var meta, metaCancel = storemocks.Mock()
- defer metaCancel()
- defer meta.AssertExpectations(t)
+ var sto, stoCancel = storemocks.Mock()
+ defer stoCancel()
+ defer sto.AssertExpectations(t)
- meta.On("Get", mock.Anything, mock.Anything, mock.Anything).Return(int64(0), nil)
- _, err := guest.Capture("anrs", "aa", true)
+ _, err := guest.Capture("anrs/aa", true)
assert.Err(t, err)
- guest.Status = models.StatusResizing
- done, err := guest.Destroy(false)
+ guest.Status = meta.StatusResizing
+ done, err := guest.Destroy(ctx, false)
assert.Err(t, err)
assert.Nil(t, done)
- guest.Status = models.StatusPending
- assert.Err(t, guest.Resize(guest.CPU, guest.Memory, map[string]int64{}))
+ guest.Status = meta.StatusPending
+
+ cpumem := &cpumemtypes.EngineParams{
+ CPU: float64(guest.CPU),
+ Memory: guest.Memory,
+ }
+
+ gpu := &gputypes.EngineParams{
+ ProdCountMap: gputypes.ProdCountMap{},
+ }
+ assert.Err(t, guest.Resize(cpumem, gpu, []volume.Volume{}))
}
func TestSyncState(t *testing.T) {
+ ctx, cancelFn := context.WithTimeout(context.Background(), 5*time.Minute)
+ defer cancelFn()
+
var guest, bot = newMockedGuest(t)
defer bot.AssertExpectations(t)
- var meta, metaCancel = storemocks.Mock()
- defer metaCancel()
- defer meta.AssertExpectations(t)
- meta.On("Update", mock.Anything, mock.Anything, mock.Anything).Return(nil)
+ var sto, stoCancel = storemocks.Mock()
+ defer stoCancel()
+ defer sto.AssertExpectations(t)
+ sto.On("Update", mock.Anything, mock.Anything, mock.Anything).Return(nil)
+ sto.On("Create", mock.Anything, mock.Anything, mock.Anything).Return(nil)
- guest.Status = models.StatusCreating
- bot.On("Create").Return(nil).Once()
+ guest.Status = meta.StatusCreating
+ bot.On("Define", mock.Anything).Return(nil).Once()
bot.On("Close").Return(nil).Once()
bot.On("Trylock").Return(nil)
bot.On("Unlock").Return()
- assert.NilErr(t, guest.SyncState())
+ assert.NilErr(t, guest.SyncState(ctx))
- guest.Status = models.StatusDestroying
- guest.rangeVolumes(func(_ int, v volume.Virt) bool {
- mod := v.Model()
- mod.Status = models.StatusDestroying
+ guest.Status = meta.StatusDestroying
+ guest.rangeVolumes(func(_ int, v volume.Volume) bool {
+ v.SetStatus(meta.StatusDestroying, true)
return true
})
- mutex := mockMutex()
- defer mutex.AssertExpectations(t)
-
bot.On("Undefine").Return(nil).Once()
bot.On("Close").Return(nil).Once()
- meta.On("NewMutex", mock.Anything).Return(mutex, nil).Once()
- meta.On("Delete", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
- assert.NilErr(t, guest.SyncState())
-
- guest.Status = models.StatusStopping
- guest.rangeVolumes(func(_ int, v volume.Virt) bool {
- mod := v.Model()
- mod.Status = models.StatusStopping
+ sto.On("Delete", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
+ assert.NilErr(t, guest.SyncState(ctx))
+
+ guest.Status = meta.StatusStopping
+ guest.rangeVolumes(func(_ int, v volume.Volume) bool {
+ v.SetStatus(meta.StatusStopping, true)
return true
})
- bot.On("Shutdown", mock.Anything).Return(nil).Once()
+ bot.On("Shutdown", ctx, mock.Anything).Return(nil).Once()
bot.On("Close").Return(nil).Once()
- assert.NilErr(t, guest.SyncState())
+ assert.NilErr(t, guest.SyncState(ctx))
- guest.Status = models.StatusStarting
- guest.rangeVolumes(func(_ int, v volume.Virt) bool {
- mod := v.Model()
- mod.Status = models.StatusStarting
+ guest.Status = meta.StatusStarting
+ guest.rangeVolumes(func(_ int, v volume.Volume) bool {
+ v.SetStatus(meta.StatusStarting, true)
return true
})
- bot.On("Boot").Return(nil).Once()
+ bot.On("Boot", ctx).Return(nil).Once()
bot.On("Close").Return(nil).Once()
bot.On("GetState").Return(libvirt.DomainShutoff, nil).Once()
- assert.NilErr(t, guest.SyncState())
+ assert.NilErr(t, guest.SyncState(ctx))
}
func TestForceDestroy(t *testing.T) {
+ ctx, cancelFn := context.WithTimeout(context.Background(), 5*time.Minute)
+ defer cancelFn()
+
guest, bot := newMockedGuest(t)
defer bot.AssertExpectations(t)
- mutex := mockMutex()
- defer mutex.AssertExpectations(t)
+ sto, stoCancel := storemocks.Mock()
+ defer stoCancel()
+ defer sto.AssertExpectations(t)
+ sto.On("Update", mock.Anything, mock.Anything, mock.Anything).Return(nil)
+ sto.On("Delete", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
- meta, metaCancel := storemocks.Mock()
- defer metaCancel()
- defer meta.AssertExpectations(t)
- meta.On("NewMutex", mock.Anything).Return(mutex, nil).Once()
- meta.On("Update", mock.Anything, mock.Anything, mock.Anything).Return(nil)
- meta.On("Delete", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
-
- guest.Status = models.StatusRunning
- bot.On("Shutdown", true).Return(nil).Once()
+ guest.Status = meta.StatusRunning
+ bot.On("Shutdown", ctx, true).Return(nil).Once()
bot.On("Undefine").Return(nil).Once()
bot.On("Close").Return(nil)
bot.On("Trylock").Return(nil)
bot.On("Unlock").Return()
- done, err := guest.Destroy(true)
+ done, err := guest.Destroy(ctx, true)
assert.NilErr(t, err)
assert.NilErr(t, <-done)
}
@@ -252,23 +293,34 @@ func mockMutex() *utilmocks.Locker {
}
func TestSyncStateSkipsRunning(t *testing.T) {
+ ctx, cancelFn := context.WithTimeout(context.Background(), 5*time.Minute)
+ defer cancelFn()
+
var guest, bot = newMockedGuest(t)
defer bot.AssertExpectations(t)
+ var sto, stoCancel = storemocks.Mock()
+ defer stoCancel()
+ defer sto.AssertExpectations(t)
+ sto.On("Update", mock.Anything, mock.Anything, mock.Anything).Return(nil)
+
bot.On("Close").Return(nil).Once()
bot.On("GetState").Return(libvirt.DomainRunning, nil).Once()
bot.On("Trylock").Return(nil)
bot.On("Unlock").Return()
- guest.Status = models.StatusRunning
- assert.NilErr(t, guest.SyncState())
+ guest.Status = meta.StatusRunning
+ for _, vol := range guest.Vols {
+ vol.SetStatus(meta.StatusRunning, true)
+ }
+ assert.NilErr(t, guest.SyncState(ctx))
}
func TestAmplifyOrigVols_HostDirMount(t *testing.T) {
guest, bot := newMockedGuest(t)
defer bot.AssertExpectations(t)
- volmod, err := models.NewDataVolume("/tmp:/data", utils.GB)
+ volmod, err := local.NewDataVolume("/tmp:/data", utils.GB)
assert.NilErr(t, err)
bot.On("Close").Return(nil).Once()
@@ -276,9 +328,10 @@ func TestAmplifyOrigVols_HostDirMount(t *testing.T) {
bot.On("Unlock").Return()
bot.On("AmplifyVolume", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
- guest.Vols = models.Volumes{volmod}
- mnt := map[string]int64{"/tmp:/data": utils.GB * 10}
- assert.NilErr(t, guest.amplifyOrigVols(mnt))
+ guest.Vols = volFact.Volumes{volmod}
+ vol, err := local.NewDataVolume("/tmp:/data", utils.GB*10)
+ assert.Nil(t, err)
+ assert.NilErr(t, guest.amplifyOrigVol(vol, 20*utils.GB))
}
func TestAttachVolumes_CheckVolumeModel(t *testing.T) {
@@ -287,29 +340,37 @@ func TestAttachVolumes_CheckVolumeModel(t *testing.T) {
bot.On("Close").Return(nil).Once()
bot.On("Trylock").Return(nil).Once()
bot.On("Unlock").Return().Once()
- bot.On("AttachVolume", mock.Anything, mock.Anything).Return(nil, nil).Once()
+ bot.On("AttachVolume", mock.Anything).Return(nil, nil).Once()
- meta, cancel := storemocks.Mock()
- defer meta.AssertExpectations(t)
+ sto, cancel := storemocks.Mock()
+ defer sto.AssertExpectations(t)
defer cancel()
- meta.On("Update", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
+ sto.On("Update", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
- guest.Status = models.StatusRunning
+ guest.Status = meta.StatusRunning
guest.HostName = "lo"
guest.ID = "guestid"
- vols := map[string]int64{"/data": utils.GB}
- assert.NilErr(t, guest.Resize(guest.CPU, guest.Memory, vols))
+ vol, err := local.NewDataVolume("/data", utils.GB)
+ assert.Nil(t, err)
+ vols := []volume.Volume{vol}
+ cpumem := &cpumemtypes.EngineParams{
+ CPU: float64(guest.CPU),
+ Memory: guest.Memory,
+ }
+
+ gpu := &gputypes.EngineParams{
+ ProdCountMap: gputypes.ProdCountMap{},
+ }
+ assert.NilErr(t, guest.Resize(cpumem, gpu, vols))
volmod := guest.Vols[1] // guest.Vols[0] is the sys volume.
- assert.True(t, len(volmod.ID) > 0)
- assert.Equal(t, guest.Status, volmod.Status)
- assert.Equal(t, models.VolDataType, volmod.Type)
- assert.Equal(t, "/data", volmod.MountDir)
- assert.Equal(t, "", volmod.HostDir)
- assert.Equal(t, utils.GB, volmod.Capacity)
- assert.Equal(t, models.VolQcow2Format, volmod.Format)
- assert.Equal(t, guest.HostName, volmod.HostName)
- assert.Equal(t, guest.ID, volmod.GuestID)
+ assert.True(t, len(volmod.GetID()) > 0)
+ assert.Equal(t, guest.Status, volmod.GetStatus())
+ assert.Equal(t, "/data", volmod.GetMountDir())
+ // assert.Equal(t, "", volmod.HostDir)
+ assert.Equal(t, utils.GB, volmod.GetSize())
+ assert.Equal(t, guest.HostName, volmod.GetHostname())
+ assert.Equal(t, guest.ID, volmod.GetGuestID())
}
func TestAttachVolumes_Rollback(t *testing.T) {
@@ -321,57 +382,318 @@ func TestAttachVolumes_Rollback(t *testing.T) {
bot.On("Close").Return(nil).Once()
bot.On("Trylock").Return(nil).Once()
bot.On("Unlock").Return().Once()
- bot.On("AttachVolume", mock.Anything, mock.Anything).Return(rollback, nil).Once()
+ bot.On("AttachVolume", mock.Anything).Return(rollback, nil).Once()
- meta, cancel := storemocks.Mock()
- defer meta.AssertExpectations(t)
+ sto, cancel := storemocks.Mock()
+ defer sto.AssertExpectations(t)
defer cancel()
- meta.On("Update", mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("faked-error")).Once()
+ sto.On("Update", mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("faked-error")).Once()
- guest.Status = models.StatusRunning
- vols := map[string]int64{"/data": utils.GB}
- assert.Err(t, guest.Resize(guest.CPU, guest.Memory, vols))
+ guest.Status = meta.StatusRunning
+ vol, err := local.NewDataVolume("/data", utils.GB)
+ assert.Nil(t, err)
+ vols := []volume.Volume{vol}
+
+ cpumem := &cpumemtypes.EngineParams{
+ CPU: float64(guest.CPU),
+ Memory: guest.Memory,
+ }
+
+ gpu := &gputypes.EngineParams{
+ ProdCountMap: gputypes.ProdCountMap{},
+ }
+ assert.Err(t, guest.Resize(cpumem, gpu, vols))
assert.Equal(t, 1, guest.Vols.Len())
- assert.Equal(t, models.VolSysType, guest.Vols[0].Type)
+ // assert.Equal(t, models.VolSysType, guest.Vols[0].Type)
assert.True(t, rolled)
}
-func TestCannotShrinkOrigVolumes(t *testing.T) {
- testcases := []struct {
- exists string
- resizing string
- }{
- {"/data", "/data"},
- {"/data", "/tmp2:/data"},
- {"/tmp:/data", "/data"},
- {"/tmp:/data", "/tmp2:/data"},
+// func TestCannotShrinkOrigVolumes(t *testing.T) {
+// testcases := []struct {
+// exists string
+// resizing string
+// }{
+// {"/data", "/data"},
+// {"/data", "/tmp2:/data"},
+// {"/tmp:/data", "/data"},
+// {"/tmp:/data", "/tmp2:/data"},
+// }
+
+// for _, tc := range testcases {
+// guest, _ := newMockedGuest(t)
+// volmod, err := local.NewDataVolume(tc.exists, utils.GB*2)
+// assert.NilErr(t, err)
+// assert.NilErr(t, guest.AppendVols(volmod))
+
+// guest.Status = meta.StatusRunning
+// vol, err := local.NewDataVolume(tc.resizing, utils.GB)
+// assert.Nil(t, err)
+// vols := []volume.Volume{vol}
+
+// cpumem := &cpumemtypes.EngineParams{
+// CPU: float64(guest.CPU),
+// Memory: guest.Memory,
+// }
+// assert.True(t, errors.Contain(
+// guest.Resize(cpumem, vols),
+// errors.ErrCannotShrinkVolume,
+// ))
+// }
+// }
+
+func TestAttachGPUs(t *testing.T) {
+ guest, bot := newMockedGuest(t)
+ defer bot.AssertExpectations(t)
+ bot.On("Close").Return(nil).Once()
+ bot.On("Trylock").Return(nil).Once()
+ bot.On("Unlock").Return().Once()
+ bot.On("AttachGPUs", mock.Anything).Return(nil, nil).Once()
+
+ sto, cancel := storemocks.Mock()
+ defer sto.AssertExpectations(t)
+ defer cancel()
+ sto.On("Update", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
+
+ guest.Status = meta.StatusRunning
+ guest.HostName = "lo"
+ guest.ID = "guestid"
+ cpumem := &cpumemtypes.EngineParams{
+ CPU: float64(guest.CPU),
+ Memory: guest.Memory,
+ }
+
+ // add 2 GPUs
+ gpu := &gputypes.EngineParams{
+ ProdCountMap: gputypes.ProdCountMap{
+ "nvidia-3070": 2,
+ },
+ }
+ assert.NilErr(t, guest.Resize(cpumem, gpu, nil))
+ assert.Equal(t, 2, guest.GPUEngineParams.Count())
+ assert.Equal(t, gpu, guest.GPUEngineParams)
+
+ // don't change
+ assert.NilErr(t, guest.Resize(cpumem, gpu, nil))
+ assert.Equal(t, 2, guest.GPUEngineParams.Count())
+ assert.Equal(t, gpu, guest.GPUEngineParams)
+ // add 2 GPUs
+ bot.On("Close").Return(nil).Once()
+ bot.On("Trylock").Return(nil).Once()
+ bot.On("Unlock").Return().Once()
+ bot.On("AttachGPUs", mock.Anything).Return(nil, nil).Once()
+ sto.On("Update", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
+ gpu = &gputypes.EngineParams{
+ ProdCountMap: gputypes.ProdCountMap{
+ "nvidia-3070": 4,
+ },
+ }
+ assert.NilErr(t, guest.Resize(cpumem, gpu, nil))
+ assert.Equal(t, 4, guest.GPUEngineParams.Count())
+ // assert.Equal(t, gpu, guest.GPUEngineParams)
+}
+
+func TestDetachGPUs(t *testing.T) {
+ guest, bot := newMockedGuest(t)
+ guest.GPUEngineParams = &gputypes.EngineParams{
+ ProdCountMap: gputypes.ProdCountMap{
+ "nvidia-3070": 5,
+ },
}
+ defer bot.AssertExpectations(t)
+ bot.On("Close").Return(nil).Once()
+ bot.On("Trylock").Return(nil).Once()
+ bot.On("Unlock").Return().Once()
+ bot.On("DetachGPUs", mock.Anything).Return(nil, nil).Once()
- for _, tc := range testcases {
- guest, _ := newMockedGuest(t)
- volmod, err := models.NewDataVolume(tc.exists, utils.GB*2)
- assert.NilErr(t, err)
- assert.NilErr(t, guest.AppendVols(volmod))
-
- guest.Status = models.StatusRunning
- vols := map[string]int64{tc.resizing: utils.GB}
- assert.True(t, errors.Contain(
- guest.Resize(guest.CPU, guest.Memory, vols),
- errors.ErrCannotShrinkVolume,
- ))
+ sto, cancel := storemocks.Mock()
+ defer sto.AssertExpectations(t)
+ defer cancel()
+ sto.On("Update", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
+
+ guest.Status = meta.StatusRunning
+ guest.HostName = "lo"
+ guest.ID = "guestid"
+ cpumem := &cpumemtypes.EngineParams{
+ CPU: float64(guest.CPU),
+ Memory: guest.Memory,
+ }
+
+ // detach 3 GPUs
+ gpu := &gputypes.EngineParams{
+ ProdCountMap: gputypes.ProdCountMap{
+ "nvidia-3070": 2,
+ },
+ }
+ assert.NilErr(t, guest.Resize(cpumem, gpu, nil))
+ assert.Equal(t, 2, guest.GPUEngineParams.Count())
+ assert.Equal(t, gpu, guest.GPUEngineParams)
+
+ // don't change
+ assert.NilErr(t, guest.Resize(cpumem, gpu, nil))
+ assert.Equal(t, 2, guest.GPUEngineParams.Count())
+ assert.Equal(t, gpu, guest.GPUEngineParams)
+ // detach 2 GPUs
+ bot.On("Close").Return(nil).Once()
+ bot.On("Trylock").Return(nil).Once()
+ bot.On("Unlock").Return().Once()
+ bot.On("DetachGPUs", mock.Anything).Return(nil, nil).Once()
+ sto.On("Update", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
+ gpu = &gputypes.EngineParams{
+ ProdCountMap: gputypes.ProdCountMap{
+ "nvidia-3070": 0,
+ },
+ }
+ assert.NilErr(t, guest.Resize(cpumem, gpu, nil))
+ assert.Equal(t, 0, guest.GPUEngineParams.Count())
+ // assert.Equal(t, gpu, guest.GPUEngineParams)
+
+ guest.GPUEngineParams = &gputypes.EngineParams{
+ ProdCountMap: gputypes.ProdCountMap{
+ "nvidia-3070": 5,
+ },
}
+ bot.On("Close").Return(nil).Once()
+ bot.On("Trylock").Return(nil).Once()
+ bot.On("Unlock").Return().Once()
+ bot.On("DetachGPUs", mock.Anything).Return(nil, nil).Once()
+ sto.On("Update", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
+ gpu = &gputypes.EngineParams{
+ ProdCountMap: gputypes.ProdCountMap{},
+ }
+ assert.NilErr(t, guest.Resize(cpumem, gpu, nil))
+ assert.Equal(t, 0, guest.GPUEngineParams.Count())
+}
+
+func TestInitSysDisk(t *testing.T) {
+ ctx, cancelFn := context.WithTimeout(context.Background(), 5*time.Minute)
+ defer cancelFn()
+
+ var sto, stoCancel = storemocks.Mock()
+ defer stoCancel()
+ defer sto.AssertExpectations(t)
+ sto.On("Update", mock.Anything, mock.Anything, mock.Anything).Return(nil)
+
+ guest, bot := newMockedGuest(t)
+ ciCfg := &types.CloudInitConfig{}
+ gomonkey.ApplyMethodReturn(guest, "GenCloudInit", ciCfg, nil)
+ gomonkey.ApplyMethodReturn(ciCfg, "GenerateISO", nil)
+ gomonkey.ApplyMethodReturn(ciCfg, "ReplaceUserData", nil)
+
+ mockVol := &volmocks.Volume{}
+ mockVol.On("Cleanup").Return(nil).Once()
+ mockVol.On("Delete", true).Return(nil).Once()
+ mockVol.On("GetDevice").Return("vda").Once()
+ mockVol.On("SetStatus", mock.Anything, mock.Anything).Return(nil).Once()
+ guest.Vols[0] = mockVol
+
+ newSysVol := &volmocks.Volume{}
+ newSysVol.On("SetDevice", "vda").Return(nil).Once()
+ newSysVol.On("SetGuestID", mock.Anything).Return(nil).Once()
+ newSysVol.On("SetHostname", mock.Anything).Return(nil).Once()
+ newSysVol.On("GenerateID").Return(nil).Once()
+ newSysVol.On("SetStatus", mock.Anything, mock.Anything).Return(nil).Once()
+ newSysVol.On("GetID").Return("xxxx").Once()
+ newSysVol.On("Save").Return(nil).Once()
+ newSysVol.On("PrepareSysDisk", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
+
+ defer bot.AssertExpectations(t)
+ bot.On("Close").Return(nil).Once()
+ bot.On("Trylock").Return(nil).Once()
+ bot.On("Unlock").Return().Once()
+
+ bot.On("Shutdown", ctx, mock.Anything).Return(nil).Once()
+ bot.On("ReplaceSysVolume", mock.Anything).Return(nil).Once()
+
+ err := guest.InitSysDisk(ctx, guest.Img, &types.InitSysDiskArgs{
+ Username: "test",
+ Password: "test",
+ }, newSysVol)
+ assert.Nil(t, err)
+ assert.Equal(t, meta.StatusStopped, guest.Status)
+}
+
+func TestFSFreeze(t *testing.T) {
+ ctx, cancelFn := context.WithTimeout(context.Background(), 5*time.Minute)
+ defer cancelFn()
+
+ guest, bot := newMockedGuest(t)
+
+ defer bot.AssertExpectations(t)
+ bot.On("Close").Return(nil).Once()
+ bot.On("Trylock").Return(nil).Once()
+ bot.On("Unlock").Return().Once()
+
+ bot.On("FSFreezeAll", ctx).Return(2, nil).Once()
+
+ nFS, err := guest.FSFreezeAll(ctx)
+ assert.Nil(t, err)
+ assert.Equal(t, 2, nFS)
+}
+
+func TestFSThawAll(t *testing.T) {
+ ctx, cancelFn := context.WithTimeout(context.Background(), 5*time.Minute)
+ defer cancelFn()
+
+ guest, bot := newMockedGuest(t)
+
+ defer bot.AssertExpectations(t)
+ bot.On("Close").Return(nil).Once()
+ bot.On("Trylock").Return(nil).Once()
+ bot.On("Unlock").Return().Once()
+
+ bot.On("FSThawAll", ctx).Return(2, nil).Once()
+
+ nFS, err := guest.FSThawAll(ctx)
+ assert.Nil(t, err)
+ assert.Equal(t, 2, nFS)
+}
+
+func TestFSFreezeStatus(t *testing.T) {
+ ctx, cancelFn := context.WithTimeout(context.Background(), 5*time.Minute)
+ defer cancelFn()
+
+ guest, bot := newMockedGuest(t)
+
+ defer bot.AssertExpectations(t)
+ bot.On("Close").Return(nil).Once()
+ bot.On("Trylock").Return(nil).Once()
+ bot.On("Unlock").Return().Once()
+
+ bot.On("FSFreezeStatus", ctx).Return("freezed", nil).Once()
+
+ status, err := guest.FSFreezeStatus(ctx)
+ assert.Nil(t, err)
+ assert.Equal(t, "freezed", status)
}
func newMockedGuest(t *testing.T) (*Guest, *mocks.Bot) {
+ err := vmiFact.Setup(&vmitypes.Config{
+ Type: "mock",
+ })
+ assert.Nil(t, err)
+ networkFactory.Setup(&configs.NetworkConfig{})
var bot = &mocks.Bot{}
- gmod, err := models.NewGuest(models.NewHost(), models.NewSysImage())
+ img, err := vmiFact.NewImage("user1/image1")
+ img.VirtualSize = 1024
+ assert.Nil(t, err)
+ assert.Equal(t, img.Fullname(), "user1/image1:latest")
+ gmod, err := models.NewGuest(models.NewHost(), img)
+ gmod.JSONLabels = make(map[string]string)
+ gmod.NetworkMode = network.FakeMode
+ gmod.GPUEngineParams = &gputypes.EngineParams{
+ ProdCountMap: gputypes.ProdCountMap{},
+ }
assert.NilErr(t, err)
+ assert.Equal(t, gmod.ImageName, "user1/image1:latest")
var guest = &Guest{
Guest: gmod,
newBot: func(g *Guest) (Bot, error) { return bot, nil },
}
+ guest.IPNets = meta.IPNets{
+ &meta.IPNet{},
+ }
return guest, bot
}
diff --git a/internal/virt/guest/manager/execution.go b/internal/virt/guest/manager/execution.go
deleted file mode 100644
index 9acf5ad..0000000
--- a/internal/virt/guest/manager/execution.go
+++ /dev/null
@@ -1,115 +0,0 @@
-package manager
-
-import (
- "container/list"
- "sync"
-
- "github.com/projecteru2/yavirt/internal/metrics"
- "github.com/projecteru2/yavirt/pkg/log"
-)
-
-type execution struct {
- sync.Mutex
- list *list.List
- id string
- started bool
- exit chan struct{}
-}
-
-func newExecution(id string) *execution {
- return &execution{
- list: list.New(),
- id: id,
- exit: make(chan struct{}),
- }
-}
-
-func (e *execution) push(t *task) {
- log.Debugf("ready to push task %s", t)
- if e.start(t) {
- log.Debugf("execution %s has been started yet for the task %s", e.id, t)
- return
- }
- log.Debugf("ready to start execution %s for the task %s", e.id, t)
-
- go func() {
- defer log.Debugf("execution %s is exiting", e.id)
-
- for {
- t := e.readTask()
- if t == nil {
- return
- }
-
- if err := t.run(); err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
-
- e.Lock()
- defer e.Unlock()
-
- if e.list.Len() > 0 {
- log.Warnf("execution %s list is not empty, but the task %s had an error", e.id, t)
-
- // Notifies there's an error, and removes all element.
- for {
- cur := e.list.Front()
- if cur == nil {
- log.Warnf("execution %s list elements were notified and cleared", e.id)
- break
- }
- e.list.Remove(cur)
-
- t := cur.Value.(*task) //nolint
- t.abort()
- }
- }
-
- e.started = false
- return
- }
- }
- }()
-}
-
-func (e *execution) readTask() (t *task) {
- e.Lock()
- defer e.Unlock()
-
- defer func() {
- if t == nil {
- e.started = false
- }
- }()
-
- cur := e.list.Front()
- if cur == nil {
- log.Debugf("execution %s list is empty", e.id)
- return
- }
-
- e.list.Remove(cur)
-
- // TODO: process exit signal.
- select {
- case <-e.exit:
- log.Warnf("execution %s had received an exit signal", e.id)
- default:
- }
-
- return cur.Value.(*task)
-}
-
-func (e *execution) start(t *task) bool {
- e.Lock()
- defer e.Unlock()
-
- e.list.PushBack(t)
-
- if e.started {
- return true
- }
-
- e.started = true
- return false
-}
diff --git a/internal/virt/guest/manager/execution_test.go b/internal/virt/guest/manager/execution_test.go
deleted file mode 100644
index 9e34ce5..0000000
--- a/internal/virt/guest/manager/execution_test.go
+++ /dev/null
@@ -1,77 +0,0 @@
-package manager
-
-import (
- "context"
- "sync"
- "testing"
- "time"
-
- "github.com/projecteru2/yavirt/internal/virt"
- "github.com/projecteru2/yavirt/pkg/test/assert"
-)
-
-func TestPush(t *testing.T) {
- task := testTask(t)
-
- exec := testExecution(t, "guest")
- exec.push(task)
-
- select {
- case <-time.After(time.Second):
- assert.Fail(t, "task hasn't done")
- case <-task.done:
- }
-
- exec.Lock()
- defer exec.Unlock()
- assert.False(t, exec.started)
- assert.Equal(t, 0, exec.list.Len())
-}
-
-func TestPushParalleled(t *testing.T) {
- exec := testExecution(t, "guest")
- group := []chan struct{}{}
-
- var wg sync.WaitGroup
- for i := 0; i < 100; i++ {
- task := testTask(t)
- group = append(group, task.done)
-
- wg.Add(1)
- go func() {
- defer wg.Done()
- exec.push(task)
- }()
- }
- wg.Wait()
-
- for i, done := range group {
- select {
- case <-time.After(time.Second):
- assert.Fail(t, "task %d hasn't done", i)
- case <-done:
- }
- }
-
- exec.Lock()
- defer exec.Unlock()
- assert.False(t, exec.started)
- assert.Equal(t, 0, exec.list.Len())
-}
-
-func testExecution(t *testing.T, id string) *execution {
- return newExecution(id)
-}
-
-func testTask(t *testing.T) *task {
- task := &task{
- id: "test",
- op: destroyOp,
- done: make(chan struct{}),
- ctx: virt.NewContext(context.Background(), nil),
- }
- task.do = func(ctx virt.Context) (interface{}, error) {
- return "successful", nil
- }
- return task
-}
diff --git a/internal/virt/guest/manager/manager.go b/internal/virt/guest/manager/manager.go
deleted file mode 100644
index 17a432c..0000000
--- a/internal/virt/guest/manager/manager.go
+++ /dev/null
@@ -1,672 +0,0 @@
-package manager
-
-import (
- "fmt"
- "io"
- "os"
- "regexp"
- "strings"
- "sync"
- "time"
-
- "github.com/projecteru2/yavirt/configs"
- "github.com/projecteru2/yavirt/internal/meta"
- "github.com/projecteru2/yavirt/internal/models"
- "github.com/projecteru2/yavirt/internal/virt"
- "github.com/projecteru2/yavirt/internal/virt/guest"
- "github.com/projecteru2/yavirt/internal/virt/types"
- "github.com/projecteru2/yavirt/pkg/errors"
- "github.com/projecteru2/yavirt/pkg/log"
- "github.com/projecteru2/yavirt/pkg/utils"
-)
-
-// Manageable wraps a group of methods.
-type Manageable interface {
- Controllable
- Executable
- Imageable
- Creatable
- Networkable
- Loadable
- Snapshotable
- Watchable
-}
-
-// Watchable wraps a group of methods about watcher.
-type Watchable interface {
- NewWatcher() (*Watcher, error)
- StartWatch()
-}
-
-// Creatable wraps a group of methods about creation.
-type Creatable interface {
- Create(ctx virt.Context, opts types.GuestCreateOption, host *models.Host, vols []*models.Volume) (vg *guest.Guest, err error)
-}
-
-// Networkable wraps a group of networking methods.
-type Networkable interface {
- ConnectExtraNetwork(ctx virt.Context, id, network, ipv4 string) (string, error)
- DisconnectExtraNetwork(ctx virt.Context, id, network string) error
-}
-
-// Executable wraps a group of executable methods.
-type Executable interface {
- AttachConsole(ctx virt.Context, id string, stream io.ReadWriteCloser, flags types.OpenConsoleFlags) (err error)
- ResizeConsoleWindow(ctx virt.Context, id string, height, width uint) (err error)
- ExecuteCommand(ctx virt.Context, id string, commands []string) (output []byte, exitCode, pid int, err error)
- Cat(ctx virt.Context, id, path string, dest io.WriteCloser) error
- CopyToGuest(ctx virt.Context, id, dest string, content chan []byte, override bool) error
- Log(ctx virt.Context, id, logPath string, n int, dest io.WriteCloser) error
-}
-
-// Controllable wraps a group of controlling methods.
-type Controllable interface {
- Resize(ctx virt.Context, id string, cpu int, mem int64, vols map[string]int64) error
- Start(ctx virt.Context, id string) error
- Suspend(ctx virt.Context, id string) error
- Resume(ctx virt.Context, id string) error
- Stop(ctx virt.Context, id string, force bool) error
- Destroy(ctx virt.Context, id string, force bool) (<-chan error, error)
- Wait(ctx virt.Context, id string, block bool) (msg string, code int, err error)
-}
-
-// Loadable wraps a group of loadable methods.
-type Loadable interface {
- Load(ctx virt.Context, id string) (*guest.Guest, error)
- LoadUUID(ctx virt.Context, id string) (string, error)
- ListLocalIDs(virt.Context) ([]string, error)
-}
-
-var imageMutex sync.Mutex
-
-// Imageable wraps a group of methods about images.
-type Imageable interface {
- Capture(ctx virt.Context, guestID, user, name string, overridden bool) (*models.UserImage, error)
- RemoveImage(ctx virt.Context, imageName, user string, force, prune bool) ([]string, error)
- ListImage(ctx virt.Context, filter string) ([]models.Image, error)
- DigestImage(ctx virt.Context, name string, local bool) ([]string, error)
-}
-
-// Snapshotable wraps a group a methods about snapshots.
-type Snapshotable interface {
- ListSnapshot(ctx virt.Context, guestID, volID string) (map[*models.Volume]models.Snapshots, error)
- CreateSnapshot(ctx virt.Context, id, volID string) error
- CommitSnapshot(ctx virt.Context, id, volID, snapID string) error
- CommitSnapshotByDay(ctx virt.Context, id, volID string, day int) error
- RestoreSnapshot(ctx virt.Context, id, volID, snapID string) error
-}
-
-// Manager implements the Manageable interface.
-type Manager struct {
- serializer *serializer
- watchers *Watchers
-}
-
-// New initializes a new Manager instance.
-func New() Manager {
- return Manager{
- serializer: newSerializer(),
- watchers: NewWatchers(),
- }
-}
-
-// Destroy destroys a guest.
-func (m Manager) Destroy(ctx virt.Context, id string, force bool) (<-chan error, error) {
- var done <-chan error
- err := m.ctrl(ctx, id, destroyOp, func(g *guest.Guest) (de error) {
- done, de = g.Destroy(force)
- return
- }, nil)
- return done, err
-}
-
-// Stop stops a guest.
-func (m Manager) Stop(ctx virt.Context, id string, force bool) error {
- return m.ctrl(ctx, id, shutOp, func(g *guest.Guest) error {
- return g.Stop(force)
- }, nil)
-}
-
-// Start boots a guest.
-func (m Manager) Start(ctx virt.Context, id string) error {
- return m.ctrl(ctx, id, bootOp, func(g *guest.Guest) error {
- if err := g.Start(); err != nil {
- return err
- }
-
- if g.LambdaOption != nil && !g.LambdaStdin {
- output, exitCode, pid, err := g.ExecuteCommand(ctx, g.LambdaOption.Cmd)
- if err != nil {
- return err
- }
- g.LambdaOption.CmdOutput = output
- g.LambdaOption.ExitCode = exitCode
- g.LambdaOption.Pid = pid
-
- if err = g.Save(); err != nil {
- return err
- }
- }
-
- return nil
- }, nil)
-}
-
-// Wait for a guest.
-func (m Manager) Wait(ctx virt.Context, id string, block bool) (msg string, code int, err error) {
- err = m.ctrl(ctx, id, miscOp, func(g *guest.Guest) error {
- if err = g.Wait(models.StatusStopped, block); err != nil {
- return err
- }
-
- if g.LambdaOption != nil {
- msg = string(g.LambdaOption.CmdOutput)
- code = g.LambdaOption.ExitCode
- }
-
- return nil
- }, nil)
- return msg, code, err
-}
-
-// Suspend suspends a guest.
-func (m Manager) Suspend(ctx virt.Context, id string) error {
- return m.ctrl(ctx, id, bootOp, func(g *guest.Guest) error {
- return g.Suspend()
- }, nil)
-}
-
-// Resume resumes a suspended guest.
-func (m Manager) Resume(ctx virt.Context, id string) error {
- return m.ctrl(ctx, id, bootOp, func(g *guest.Guest) error {
- return g.Resume()
- }, nil)
-}
-
-// Resize re-allocates spec or volumes.
-func (m Manager) Resize(ctx virt.Context, id string, cpu int, mem int64, vols map[string]int64) error {
- return m.ctrl(ctx, id, resizeOp, func(g *guest.Guest) error {
- return g.Resize(cpu, mem, vols)
- }, nil)
-}
-
-// List snapshots of volume.
-func (m Manager) ListSnapshot(ctx virt.Context, guestID, volID string) (map[*models.Volume]models.Snapshots, error) {
- g, err := m.Load(ctx, guestID)
- if err != nil {
- return nil, errors.Trace(err)
- }
-
- return g.ListSnapshot(volID)
-}
-
-// Create snapshot of volume with volID
-func (m Manager) CreateSnapshot(ctx virt.Context, id, volID string) error {
- return m.ctrl(ctx, id, createSnapshotOp, func(g *guest.Guest) error {
- suspended := false
- stopped := false
- if g.Status == models.StatusRunning {
- if err := g.Suspend(); err != nil {
- return err
- }
- suspended = true
- }
-
- if err := g.CreateSnapshot(volID); err != nil {
- return err
- }
-
- if err := g.CheckVolume(volID); err != nil {
-
- if suspended {
- if err := g.Stop(true); err != nil {
- return err
- }
- suspended = false
- stopped = true
- }
-
- if err := g.RepairVolume(volID); err != nil {
- return err
- }
- }
-
- if suspended {
- return g.Resume()
- } else if stopped {
- return g.Start()
- }
- return nil
- }, nil)
-}
-
-// Commit snapshot (with snapID) to the root backing file
-func (m Manager) CommitSnapshot(ctx virt.Context, id, volID, snapID string) error {
- return m.ctrl(ctx, id, commitSnapshotOp, func(g *guest.Guest) error {
- stopped := false
- if g.Status == models.StatusRunning {
- if err := g.Stop(true); err != nil {
- return err
- }
- stopped = true
- }
-
- if err := g.CommitSnapshot(volID, snapID); err != nil {
- return err
- }
-
- if stopped {
- return g.Start()
- }
- return nil
- }, nil)
-}
-
-// Commit snapshot that created `day` days before
-func (m Manager) CommitSnapshotByDay(ctx virt.Context, id, volID string, day int) error {
- return m.ctrl(ctx, id, commitSnapshotOp, func(g *guest.Guest) error {
- stopped := false
- if g.Status == models.StatusRunning {
- if err := g.Stop(true); err != nil {
- return err
- }
- stopped = true
- }
-
- if err := g.CommitSnapshotByDay(volID, day); err != nil {
- return err
- }
-
- if stopped {
- return g.Start()
- }
- return nil
- }, nil)
-}
-
-// Restore volume to snapshot with snapID
-func (m Manager) RestoreSnapshot(ctx virt.Context, id, volID, snapID string) error {
- return m.ctrl(ctx, id, restoreSnapshotOp, func(g *guest.Guest) error {
- stopped := false
- if g.Status == models.StatusRunning {
- if err := g.Stop(true); err != nil {
- return err
- }
- stopped = true
- }
-
- if err := g.RestoreSnapshot(volID, snapID); err != nil {
- return err
- }
-
- if stopped {
- return g.Start()
- }
- return nil
- }, nil)
-}
-
-// Capture captures an image from a guest.
-func (m Manager) Capture(ctx virt.Context, guestID, user, name string, overridden bool) (*models.UserImage, error) {
- g, err := m.Load(ctx, guestID)
- if err != nil {
- return nil, errors.Trace(err)
- }
-
- uImg, err := g.Capture(user, name, overridden)
- if err != nil {
- return nil, errors.Trace(err)
- }
-
- return uImg, nil
-}
-
-// RemoveImage removes a local image.
-func (m Manager) RemoveImage(_ virt.Context, imageName, user string, _, _ bool) ([]string, error) {
- img, err := models.LoadImage(imageName, user)
- if err != nil {
- return nil, errors.Trace(err)
- }
-
- imageMutex.Lock()
- defer imageMutex.Unlock()
-
- if exists, err := models.ImageExists(img); err != nil {
- return nil, errors.Trace(err)
- } else if exists {
- if err = os.Remove(img.Filepath()); err != nil {
- return nil, errors.Trace(err)
- }
- }
-
- return []string{img.GetID()}, nil
-}
-
-// ListImage .
-func (m Manager) ListImage(_ virt.Context, filter string) ([]models.Image, error) {
- imgs, err := models.ListSysImages()
- if err != nil {
- return nil, err
- }
-
- if len(filter) < 1 {
- return imgs, nil
- }
-
- images := []models.Image{}
- var regExp *regexp.Regexp
- filter = strings.ReplaceAll(filter, "*", ".*")
- if regExp, err = regexp.Compile(fmt.Sprintf("%s%s%s", "^", filter, "$")); err != nil {
- return nil, err
- }
-
- for _, img := range imgs {
- if regExp.MatchString(img.GetName()) {
- images = append(images, img)
- }
- }
-
- return images, nil
-}
-
-// DigestImage .
-func (m Manager) DigestImage(_ virt.Context, name string, local bool) ([]string, error) {
- if !local {
- // TODO: wait for image-hub implementation and calico update
- return []string{""}, nil
- }
-
- // If not exists return error
- // If exists return digests
-
- img, err := models.LoadSysImage(name)
- if err != nil {
- return nil, err
- }
-
- hash, err := img.UpdateHash()
- if err != nil {
- return nil, err
- }
-
- return []string{hash}, nil
-}
-
-// Create creates a new guest.
-func (m Manager) Create(ctx virt.Context, opts types.GuestCreateOption, host *models.Host, vols []*models.Volume) (*guest.Guest, error) {
- // Creates metadata.
- g, err := models.CreateGuest(opts, host, vols)
- if err != nil {
- return nil, errors.Trace(err)
- }
-
- // Destroys resource and delete metadata while rolling back.
- var vg *guest.Guest
- destroy := func() {
- if vg == nil {
- return
- }
-
- done, err := vg.Destroy(true)
- if err != nil {
- log.ErrorStack(err)
- }
-
- select {
- case err := <-done:
- if err != nil {
- log.ErrorStack(err)
- }
- case <-time.After(time.Minute):
- log.ErrorStackf(errors.ErrTimeout, "destroy timeout")
- }
- }
-
- // Creates the resource.
- create := func(_ *guest.Guest) (any, error) {
- var err error
- vg, err = m.create(ctx, g)
- return vg, err
- }
-
- res, err := m.doCtrl(ctx, g.ID, createOp, create, destroy)
- if err != nil {
- return nil, errors.Trace(err)
- }
-
- return res.(*guest.Guest), nil
-}
-
-func (m Manager) create(ctx virt.Context, g *models.Guest) (vg *guest.Guest, err error) {
- vg = guest.New(ctx, g)
- if err := vg.CacheImage(&imageMutex); err != nil {
- return nil, errors.Trace(err)
- }
-
- if vg.MAC, err = utils.QemuMAC(); err != nil {
- return nil, errors.Trace(err)
- }
-
- var rollback func() error
- if rollback, err = vg.CreateEthernet(); err != nil {
- return nil, errors.Trace(err)
- }
-
- if err = vg.Create(); err != nil {
- if re := rollback(); re != nil {
- err = errors.Wrap(err, re)
- }
- return nil, errors.Trace(err)
- }
-
- return vg, nil
-}
-
-// AttachConsole attaches to a guest's console.
-func (m Manager) AttachConsole(ctx virt.Context, id string, stream io.ReadWriteCloser, flags types.OpenConsoleFlags) error {
- g, err := m.Load(ctx, id)
- if err != nil {
- return errors.Trace(err)
- }
-
- if g.LambdaOption != nil {
- if err = g.Wait(models.StatusRunning, false); err != nil {
- return errors.Trace(err)
- }
- flags.Commands = g.LambdaOption.Cmd
- }
-
- return g.AttachConsole(ctx, stream, flags)
-}
-
-// ResizeConsoleWindow resizes a console's window.
-func (m Manager) ResizeConsoleWindow(ctx virt.Context, id string, height, width uint) error {
- g, err := m.Load(ctx, id)
- if err != nil {
- return errors.Trace(err)
- }
- return g.ResizeConsoleWindow(ctx, height, width)
-}
-
-type executeResult struct {
- output []byte
- exitCode int
- pid int
-}
-
-// ExecuteCommand executes commands.
-func (m Manager) ExecuteCommand(ctx virt.Context, id string, commands []string) (content []byte, exitCode, pid int, err error) {
- exec := func(g *guest.Guest) (any, error) {
- output, exitCode, pid, err := g.ExecuteCommand(ctx, commands)
- if err != nil {
- return nil, errors.Trace(err)
- }
- return &executeResult{output: output, exitCode: exitCode, pid: pid}, nil
- }
-
- res, err := m.doCtrl(ctx, id, miscOp, exec, nil)
- if err != nil {
- return nil, -1, -1, errors.Trace(err)
- }
-
- er, ok := res.(*executeResult)
- if !ok {
- return nil, -1, -1, errors.Annotatef(errors.ErrInvalidValue, "expect *executeResult but it's %v", res)
- }
- return er.output, er.exitCode, er.pid, nil
-}
-
-// Cat cats the file that in the guest.
-func (m Manager) Cat(ctx virt.Context, id, path string, dest io.WriteCloser) error {
- return m.ctrl(ctx, id, miscOp, func(g *guest.Guest) error {
- return g.Cat(ctx, path, dest)
- }, nil)
-}
-
-// Log shows the log file.
-func (m Manager) Log(ctx virt.Context, id, logPath string, n int, dest io.WriteCloser) error {
- return m.ctrl(ctx, id, miscOp, func(g *guest.Guest) error {
- if g.LambdaOption == nil {
- return g.Log(ctx, n, logPath, dest)
- }
-
- defer dest.Close()
- _, err := dest.Write(g.LambdaOption.CmdOutput)
- return err
- }, nil)
-}
-
-// CopyToGuest copy file to guest
-func (m Manager) CopyToGuest(ctx virt.Context, id, dest string, content chan []byte, override bool) error {
- return m.ctrl(ctx, id, miscOp, func(g *guest.Guest) error {
- return g.CopyToGuest(ctx, dest, content, override)
- }, nil)
-}
-
-// DisconnectExtraNetwork disconnects from an extra network.
-func (m Manager) DisconnectExtraNetwork(ctx virt.Context, id, network string) error {
- return m.ctrl(ctx, id, miscOp, func(g *guest.Guest) error {
- return g.DisconnectExtraNetwork(network)
- }, nil)
-}
-
-// ConnectExtraNetwork connects to an extra network.
-func (m Manager) ConnectExtraNetwork(ctx virt.Context, id, network, ipv4 string) (string, error) {
- var ip meta.IP
-
- if err := m.ctrl(ctx, id, miscOp, func(g *guest.Guest) (ce error) {
- ip, ce = g.ConnectExtraNetwork(network, ipv4)
- return ce
- }, nil); err != nil {
- return "", errors.Trace(err)
- }
-
- return ip.CIDR(), nil
-}
-
-type ctrlFunc func(*guest.Guest) error
-
-func (m Manager) ctrl(ctx virt.Context, id string, op op, fn ctrlFunc, rollback rollbackFunc) error { //nolint
- _, err := m.doCtrl(ctx, id, op, func(g *guest.Guest) (any, error) {
- return nil, fn(g)
- }, rollback)
- return err
-}
-
-type rollbackFunc func()
-type doCtrlFunc func(*guest.Guest) (any, error)
-
-func (m Manager) doCtrl(ctx virt.Context, id string, op op, fn doCtrlFunc, rollback rollbackFunc) (any, error) {
- do := func(ctx virt.Context) (any, error) {
- g, err := m.Load(ctx, id)
- if err != nil {
- return nil, errors.Trace(err)
- }
- return fn(g)
- }
- return m.do(ctx, id, op, do, rollback)
-}
-
-// ListLocals lists all local guests.
-func (m Manager) ListLocalIDs(ctx virt.Context) ([]string, error) {
- return guest.ListLocalIDs(ctx)
-}
-
-// LoadUUID read a guest's UUID.
-func (m Manager) LoadUUID(ctx virt.Context, id string) (string, error) {
- g, err := m.Load(ctx, id)
- if err != nil {
- return "", errors.Trace(err)
- }
- return g.GetUUID()
-}
-
-// Load read a guest from metadata.
-func (m Manager) Load(ctx virt.Context, id string) (*guest.Guest, error) {
- g, err := models.LoadGuest(id)
- if err != nil {
- return nil, errors.Trace(err)
- }
-
- var vg = guest.New(ctx, g)
- if err := vg.Load(); err != nil {
- return nil, errors.Trace(err)
- }
-
- return vg, nil
-}
-
-type doFunc func(virt.Context) (any, error)
-
-func (m Manager) do(ctx virt.Context, id string, op op, fn doFunc, rollback rollbackFunc) (any, error) {
- t := &task{
- id: id,
- op: op,
- do: fn,
- ctx: ctx,
- }
-
- dur := configs.Conf.VirtTimeout.Duration()
- timeout := time.After(dur)
-
- noti := m.serializer.Serialize(id, t)
-
- var result any
- var err error
-
- select {
- case <-noti.done:
- result = noti.result()
- err = noti.error()
- case <-ctx.Done():
- err = ctx.Err()
- case <-timeout:
- err = errors.Annotatef(errors.ErrTimeout, "exceed %v", dur)
- }
-
- if err != nil {
- if rollback != nil {
- rollback()
- }
- return nil, errors.Trace(err)
- }
-
- m.watchers.Watched(types.Event{
- ID: id,
- Type: guestEventType,
- Action: op.String(),
- Time: time.Now().UTC(),
- })
-
- return result, nil
-}
-
-func (m Manager) NewWatcher() (*Watcher, error) {
- return m.watchers.Get()
-}
-
-func (m Manager) StartWatch() {
- go m.watchers.Run()
-}
-
-const guestEventType = "guest"
diff --git a/internal/virt/guest/manager/mocks/Manageable.go b/internal/virt/guest/manager/mocks/Manageable.go
deleted file mode 100644
index 35cdb72..0000000
--- a/internal/virt/guest/manager/mocks/Manageable.go
+++ /dev/null
@@ -1,633 +0,0 @@
-// Code generated by mockery v2.26.1. DO NOT EDIT.
-
-package mocks
-
-import (
- io "io"
-
- guest "github.com/projecteru2/yavirt/internal/virt/guest"
-
- manager "github.com/projecteru2/yavirt/internal/virt/guest/manager"
-
- mock "github.com/stretchr/testify/mock"
-
- models "github.com/projecteru2/yavirt/internal/models"
-
- types "github.com/projecteru2/yavirt/internal/virt/types"
-
- virt "github.com/projecteru2/yavirt/internal/virt"
-)
-
-// Manageable is an autogenerated mock type for the Manageable type
-type Manageable struct {
- mock.Mock
-}
-
-// AttachConsole provides a mock function with given fields: ctx, id, stream, flags
-func (_m *Manageable) AttachConsole(ctx virt.Context, id string, stream io.ReadWriteCloser, flags types.OpenConsoleFlags) error {
- ret := _m.Called(ctx, id, stream, flags)
-
- var r0 error
- if rf, ok := ret.Get(0).(func(virt.Context, string, io.ReadWriteCloser, types.OpenConsoleFlags) error); ok {
- r0 = rf(ctx, id, stream, flags)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// Capture provides a mock function with given fields: ctx, guestID, user, name, overridden
-func (_m *Manageable) Capture(ctx virt.Context, guestID string, user string, name string, overridden bool) (*models.UserImage, error) {
- ret := _m.Called(ctx, guestID, user, name, overridden)
-
- var r0 *models.UserImage
- var r1 error
- if rf, ok := ret.Get(0).(func(virt.Context, string, string, string, bool) (*models.UserImage, error)); ok {
- return rf(ctx, guestID, user, name, overridden)
- }
- if rf, ok := ret.Get(0).(func(virt.Context, string, string, string, bool) *models.UserImage); ok {
- r0 = rf(ctx, guestID, user, name, overridden)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(*models.UserImage)
- }
- }
-
- if rf, ok := ret.Get(1).(func(virt.Context, string, string, string, bool) error); ok {
- r1 = rf(ctx, guestID, user, name, overridden)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// Cat provides a mock function with given fields: ctx, id, path, dest
-func (_m *Manageable) Cat(ctx virt.Context, id string, path string, dest io.WriteCloser) error {
- ret := _m.Called(ctx, id, path, dest)
-
- var r0 error
- if rf, ok := ret.Get(0).(func(virt.Context, string, string, io.WriteCloser) error); ok {
- r0 = rf(ctx, id, path, dest)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// CommitSnapshot provides a mock function with given fields: ctx, id, volID, snapID
-func (_m *Manageable) CommitSnapshot(ctx virt.Context, id string, volID string, snapID string) error {
- ret := _m.Called(ctx, id, volID, snapID)
-
- var r0 error
- if rf, ok := ret.Get(0).(func(virt.Context, string, string, string) error); ok {
- r0 = rf(ctx, id, volID, snapID)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// CommitSnapshotByDay provides a mock function with given fields: ctx, id, volID, day
-func (_m *Manageable) CommitSnapshotByDay(ctx virt.Context, id string, volID string, day int) error {
- ret := _m.Called(ctx, id, volID, day)
-
- var r0 error
- if rf, ok := ret.Get(0).(func(virt.Context, string, string, int) error); ok {
- r0 = rf(ctx, id, volID, day)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// ConnectExtraNetwork provides a mock function with given fields: ctx, id, network, ipv4
-func (_m *Manageable) ConnectExtraNetwork(ctx virt.Context, id string, network string, ipv4 string) (string, error) {
- ret := _m.Called(ctx, id, network, ipv4)
-
- var r0 string
- var r1 error
- if rf, ok := ret.Get(0).(func(virt.Context, string, string, string) (string, error)); ok {
- return rf(ctx, id, network, ipv4)
- }
- if rf, ok := ret.Get(0).(func(virt.Context, string, string, string) string); ok {
- r0 = rf(ctx, id, network, ipv4)
- } else {
- r0 = ret.Get(0).(string)
- }
-
- if rf, ok := ret.Get(1).(func(virt.Context, string, string, string) error); ok {
- r1 = rf(ctx, id, network, ipv4)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// CopyToGuest provides a mock function with given fields: ctx, id, dest, content, override
-func (_m *Manageable) CopyToGuest(ctx virt.Context, id string, dest string, content chan []byte, override bool) error {
- ret := _m.Called(ctx, id, dest, content, override)
-
- var r0 error
- if rf, ok := ret.Get(0).(func(virt.Context, string, string, chan []byte, bool) error); ok {
- r0 = rf(ctx, id, dest, content, override)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// Create provides a mock function with given fields: ctx, opts, host, vols
-func (_m *Manageable) Create(ctx virt.Context, opts types.GuestCreateOption, host *models.Host, vols []*models.Volume) (*guest.Guest, error) {
- ret := _m.Called(ctx, opts, host, vols)
-
- var r0 *guest.Guest
- var r1 error
- if rf, ok := ret.Get(0).(func(virt.Context, types.GuestCreateOption, *models.Host, []*models.Volume) (*guest.Guest, error)); ok {
- return rf(ctx, opts, host, vols)
- }
- if rf, ok := ret.Get(0).(func(virt.Context, types.GuestCreateOption, *models.Host, []*models.Volume) *guest.Guest); ok {
- r0 = rf(ctx, opts, host, vols)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(*guest.Guest)
- }
- }
-
- if rf, ok := ret.Get(1).(func(virt.Context, types.GuestCreateOption, *models.Host, []*models.Volume) error); ok {
- r1 = rf(ctx, opts, host, vols)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// CreateSnapshot provides a mock function with given fields: ctx, id, volID
-func (_m *Manageable) CreateSnapshot(ctx virt.Context, id string, volID string) error {
- ret := _m.Called(ctx, id, volID)
-
- var r0 error
- if rf, ok := ret.Get(0).(func(virt.Context, string, string) error); ok {
- r0 = rf(ctx, id, volID)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// Destroy provides a mock function with given fields: ctx, id, force
-func (_m *Manageable) Destroy(ctx virt.Context, id string, force bool) (<-chan error, error) {
- ret := _m.Called(ctx, id, force)
-
- var r0 <-chan error
- var r1 error
- if rf, ok := ret.Get(0).(func(virt.Context, string, bool) (<-chan error, error)); ok {
- return rf(ctx, id, force)
- }
- if rf, ok := ret.Get(0).(func(virt.Context, string, bool) <-chan error); ok {
- r0 = rf(ctx, id, force)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(<-chan error)
- }
- }
-
- if rf, ok := ret.Get(1).(func(virt.Context, string, bool) error); ok {
- r1 = rf(ctx, id, force)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// DigestImage provides a mock function with given fields: ctx, name, local
-func (_m *Manageable) DigestImage(ctx virt.Context, name string, local bool) ([]string, error) {
- ret := _m.Called(ctx, name, local)
-
- var r0 []string
- var r1 error
- if rf, ok := ret.Get(0).(func(virt.Context, string, bool) ([]string, error)); ok {
- return rf(ctx, name, local)
- }
- if rf, ok := ret.Get(0).(func(virt.Context, string, bool) []string); ok {
- r0 = rf(ctx, name, local)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]string)
- }
- }
-
- if rf, ok := ret.Get(1).(func(virt.Context, string, bool) error); ok {
- r1 = rf(ctx, name, local)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// DisconnectExtraNetwork provides a mock function with given fields: ctx, id, network
-func (_m *Manageable) DisconnectExtraNetwork(ctx virt.Context, id string, network string) error {
- ret := _m.Called(ctx, id, network)
-
- var r0 error
- if rf, ok := ret.Get(0).(func(virt.Context, string, string) error); ok {
- r0 = rf(ctx, id, network)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// ExecuteCommand provides a mock function with given fields: ctx, id, commands
-func (_m *Manageable) ExecuteCommand(ctx virt.Context, id string, commands []string) ([]byte, int, int, error) {
- ret := _m.Called(ctx, id, commands)
-
- var r0 []byte
- var r1 int
- var r2 int
- var r3 error
- if rf, ok := ret.Get(0).(func(virt.Context, string, []string) ([]byte, int, int, error)); ok {
- return rf(ctx, id, commands)
- }
- if rf, ok := ret.Get(0).(func(virt.Context, string, []string) []byte); ok {
- r0 = rf(ctx, id, commands)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]byte)
- }
- }
-
- if rf, ok := ret.Get(1).(func(virt.Context, string, []string) int); ok {
- r1 = rf(ctx, id, commands)
- } else {
- r1 = ret.Get(1).(int)
- }
-
- if rf, ok := ret.Get(2).(func(virt.Context, string, []string) int); ok {
- r2 = rf(ctx, id, commands)
- } else {
- r2 = ret.Get(2).(int)
- }
-
- if rf, ok := ret.Get(3).(func(virt.Context, string, []string) error); ok {
- r3 = rf(ctx, id, commands)
- } else {
- r3 = ret.Error(3)
- }
-
- return r0, r1, r2, r3
-}
-
-// ListImage provides a mock function with given fields: ctx, filter
-func (_m *Manageable) ListImage(ctx virt.Context, filter string) ([]models.Image, error) {
- ret := _m.Called(ctx, filter)
-
- var r0 []models.Image
- var r1 error
- if rf, ok := ret.Get(0).(func(virt.Context, string) ([]models.Image, error)); ok {
- return rf(ctx, filter)
- }
- if rf, ok := ret.Get(0).(func(virt.Context, string) []models.Image); ok {
- r0 = rf(ctx, filter)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]models.Image)
- }
- }
-
- if rf, ok := ret.Get(1).(func(virt.Context, string) error); ok {
- r1 = rf(ctx, filter)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// ListLocalIDs provides a mock function with given fields: _a0
-func (_m *Manageable) ListLocalIDs(_a0 virt.Context) ([]string, error) {
- ret := _m.Called(_a0)
-
- var r0 []string
- var r1 error
- if rf, ok := ret.Get(0).(func(virt.Context) ([]string, error)); ok {
- return rf(_a0)
- }
- if rf, ok := ret.Get(0).(func(virt.Context) []string); ok {
- r0 = rf(_a0)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]string)
- }
- }
-
- if rf, ok := ret.Get(1).(func(virt.Context) error); ok {
- r1 = rf(_a0)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// ListSnapshot provides a mock function with given fields: ctx, guestID, volID
-func (_m *Manageable) ListSnapshot(ctx virt.Context, guestID string, volID string) (map[*models.Volume]models.Snapshots, error) {
- ret := _m.Called(ctx, guestID, volID)
-
- var r0 map[*models.Volume]models.Snapshots
- var r1 error
- if rf, ok := ret.Get(0).(func(virt.Context, string, string) (map[*models.Volume]models.Snapshots, error)); ok {
- return rf(ctx, guestID, volID)
- }
- if rf, ok := ret.Get(0).(func(virt.Context, string, string) map[*models.Volume]models.Snapshots); ok {
- r0 = rf(ctx, guestID, volID)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(map[*models.Volume]models.Snapshots)
- }
- }
-
- if rf, ok := ret.Get(1).(func(virt.Context, string, string) error); ok {
- r1 = rf(ctx, guestID, volID)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// Load provides a mock function with given fields: ctx, id
-func (_m *Manageable) Load(ctx virt.Context, id string) (*guest.Guest, error) {
- ret := _m.Called(ctx, id)
-
- var r0 *guest.Guest
- var r1 error
- if rf, ok := ret.Get(0).(func(virt.Context, string) (*guest.Guest, error)); ok {
- return rf(ctx, id)
- }
- if rf, ok := ret.Get(0).(func(virt.Context, string) *guest.Guest); ok {
- r0 = rf(ctx, id)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(*guest.Guest)
- }
- }
-
- if rf, ok := ret.Get(1).(func(virt.Context, string) error); ok {
- r1 = rf(ctx, id)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// LoadUUID provides a mock function with given fields: ctx, id
-func (_m *Manageable) LoadUUID(ctx virt.Context, id string) (string, error) {
- ret := _m.Called(ctx, id)
-
- var r0 string
- var r1 error
- if rf, ok := ret.Get(0).(func(virt.Context, string) (string, error)); ok {
- return rf(ctx, id)
- }
- if rf, ok := ret.Get(0).(func(virt.Context, string) string); ok {
- r0 = rf(ctx, id)
- } else {
- r0 = ret.Get(0).(string)
- }
-
- if rf, ok := ret.Get(1).(func(virt.Context, string) error); ok {
- r1 = rf(ctx, id)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// Log provides a mock function with given fields: ctx, id, logPath, n, dest
-func (_m *Manageable) Log(ctx virt.Context, id string, logPath string, n int, dest io.WriteCloser) error {
- ret := _m.Called(ctx, id, logPath, n, dest)
-
- var r0 error
- if rf, ok := ret.Get(0).(func(virt.Context, string, string, int, io.WriteCloser) error); ok {
- r0 = rf(ctx, id, logPath, n, dest)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// NewWatcher provides a mock function with given fields:
-func (_m *Manageable) NewWatcher() (*manager.Watcher, error) {
- ret := _m.Called()
-
- var r0 *manager.Watcher
- var r1 error
- if rf, ok := ret.Get(0).(func() (*manager.Watcher, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() *manager.Watcher); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(*manager.Watcher)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// RemoveImage provides a mock function with given fields: ctx, imageName, user, force, prune
-func (_m *Manageable) RemoveImage(ctx virt.Context, imageName string, user string, force bool, prune bool) ([]string, error) {
- ret := _m.Called(ctx, imageName, user, force, prune)
-
- var r0 []string
- var r1 error
- if rf, ok := ret.Get(0).(func(virt.Context, string, string, bool, bool) ([]string, error)); ok {
- return rf(ctx, imageName, user, force, prune)
- }
- if rf, ok := ret.Get(0).(func(virt.Context, string, string, bool, bool) []string); ok {
- r0 = rf(ctx, imageName, user, force, prune)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).([]string)
- }
- }
-
- if rf, ok := ret.Get(1).(func(virt.Context, string, string, bool, bool) error); ok {
- r1 = rf(ctx, imageName, user, force, prune)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// Resize provides a mock function with given fields: ctx, id, cpu, mem, vols
-func (_m *Manageable) Resize(ctx virt.Context, id string, cpu int, mem int64, vols map[string]int64) error {
- ret := _m.Called(ctx, id, cpu, mem, vols)
-
- var r0 error
- if rf, ok := ret.Get(0).(func(virt.Context, string, int, int64, map[string]int64) error); ok {
- r0 = rf(ctx, id, cpu, mem, vols)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// ResizeConsoleWindow provides a mock function with given fields: ctx, id, height, width
-func (_m *Manageable) ResizeConsoleWindow(ctx virt.Context, id string, height uint, width uint) error {
- ret := _m.Called(ctx, id, height, width)
-
- var r0 error
- if rf, ok := ret.Get(0).(func(virt.Context, string, uint, uint) error); ok {
- r0 = rf(ctx, id, height, width)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// RestoreSnapshot provides a mock function with given fields: ctx, id, volID, snapID
-func (_m *Manageable) RestoreSnapshot(ctx virt.Context, id string, volID string, snapID string) error {
- ret := _m.Called(ctx, id, volID, snapID)
-
- var r0 error
- if rf, ok := ret.Get(0).(func(virt.Context, string, string, string) error); ok {
- r0 = rf(ctx, id, volID, snapID)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// Resume provides a mock function with given fields: ctx, id
-func (_m *Manageable) Resume(ctx virt.Context, id string) error {
- ret := _m.Called(ctx, id)
-
- var r0 error
- if rf, ok := ret.Get(0).(func(virt.Context, string) error); ok {
- r0 = rf(ctx, id)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// Start provides a mock function with given fields: ctx, id
-func (_m *Manageable) Start(ctx virt.Context, id string) error {
- ret := _m.Called(ctx, id)
-
- var r0 error
- if rf, ok := ret.Get(0).(func(virt.Context, string) error); ok {
- r0 = rf(ctx, id)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// StartWatch provides a mock function with given fields:
-func (_m *Manageable) StartWatch() {
- _m.Called()
-}
-
-// Stop provides a mock function with given fields: ctx, id, force
-func (_m *Manageable) Stop(ctx virt.Context, id string, force bool) error {
- ret := _m.Called(ctx, id, force)
-
- var r0 error
- if rf, ok := ret.Get(0).(func(virt.Context, string, bool) error); ok {
- r0 = rf(ctx, id, force)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// Suspend provides a mock function with given fields: ctx, id
-func (_m *Manageable) Suspend(ctx virt.Context, id string) error {
- ret := _m.Called(ctx, id)
-
- var r0 error
- if rf, ok := ret.Get(0).(func(virt.Context, string) error); ok {
- r0 = rf(ctx, id)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// Wait provides a mock function with given fields: ctx, id, block
-func (_m *Manageable) Wait(ctx virt.Context, id string, block bool) (string, int, error) {
- ret := _m.Called(ctx, id, block)
-
- var r0 string
- var r1 int
- var r2 error
- if rf, ok := ret.Get(0).(func(virt.Context, string, bool) (string, int, error)); ok {
- return rf(ctx, id, block)
- }
- if rf, ok := ret.Get(0).(func(virt.Context, string, bool) string); ok {
- r0 = rf(ctx, id, block)
- } else {
- r0 = ret.Get(0).(string)
- }
-
- if rf, ok := ret.Get(1).(func(virt.Context, string, bool) int); ok {
- r1 = rf(ctx, id, block)
- } else {
- r1 = ret.Get(1).(int)
- }
-
- if rf, ok := ret.Get(2).(func(virt.Context, string, bool) error); ok {
- r2 = rf(ctx, id, block)
- } else {
- r2 = ret.Error(2)
- }
-
- return r0, r1, r2
-}
-
-type mockConstructorTestingTNewManageable interface {
- mock.TestingT
- Cleanup(func())
-}
-
-// NewManageable creates a new instance of Manageable. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-func NewManageable(t mockConstructorTestingTNewManageable) *Manageable {
- mock := &Manageable{}
- mock.Mock.Test(t)
-
- t.Cleanup(func() { mock.AssertExpectations(t) })
-
- return mock
-}
diff --git a/internal/virt/guest/manager/serialize.go b/internal/virt/guest/manager/serialize.go
deleted file mode 100644
index 726047c..0000000
--- a/internal/virt/guest/manager/serialize.go
+++ /dev/null
@@ -1,31 +0,0 @@
-package manager
-
-import "sync"
-
-type serializer struct {
- sync.Map
-}
-
-func newSerializer() *serializer {
- ser := &serializer{}
-
- // TODO
- // reap invalid elements in the sync.Map.
- go func() {
- }()
-
- return ser
-}
-
-func (s *serializer) Serialize(id string, t *task) *taskNotifier {
- t.done = make(chan struct{})
-
- actual, _ := s.LoadOrStore(id, newExecution(id))
- exec := actual.(*execution) //nolint
- exec.push(t)
-
- return &taskNotifier{
- done: t.done,
- task: t,
- }
-}
diff --git a/internal/virt/guest/manager/task.go b/internal/virt/guest/manager/task.go
deleted file mode 100644
index 44e9a0a..0000000
--- a/internal/virt/guest/manager/task.go
+++ /dev/null
@@ -1,91 +0,0 @@
-package manager
-
-import (
- "fmt"
- "sync"
-
- "github.com/projecteru2/yavirt/internal/virt"
- "github.com/projecteru2/yavirt/pkg/errors"
-)
-
-const (
- destroyOp op = "destroy"
- shutOp op = "shutdown"
- bootOp op = "boot"
- createOp op = "create"
- resizeOp op = "resize"
- miscOp op = "misc"
- createSnapshotOp op = "create-snapshot"
- commitSnapshotOp op = "commit-snapshot"
- restoreSnapshotOp op = "restore-snapshot"
-)
-
-type op string
-
-func (op op) String() string {
- return string(op)
-}
-
-type task struct {
- id string
- op op
- do func(virt.Context) (any, error)
- result any
- ctx virt.Context
- done chan struct{}
- once sync.Once
- err error
-}
-
-// String .
-func (t *task) String() string {
- return fmt.Sprintf("<%s, %s>", t.op, t.id)
-}
-
-func (t *task) abort() {
- t.finish()
- t.err = errors.Trace(errors.ErrSerializedTaskAborted)
-}
-
-// terminate forcibly terminates a task.
-func (t *task) terminate() { //nolint
- // TODO
-}
-
-func (t *task) run() error {
- defer t.finish()
-
- select {
- case <-t.ctx.Done():
- if err := t.ctx.Err(); err != nil {
- t.err = err
- }
- default:
- t.result, t.err = t.do(t.ctx)
- }
-
- return t.err
-}
-
-func (t *task) finish() {
- t.once.Do(func() {
- close(t.done)
- })
-}
-
-type taskNotifier struct {
- done chan struct{}
- task *task
-}
-
-func (n taskNotifier) error() error {
- return n.task.err
-}
-
-func (n taskNotifier) result() any {
- return n.task.result
-}
-
-func (n taskNotifier) terminate() { //nolint
- n.task.terminate()
-}
diff --git a/internal/virt/guest/mocks/Bot.go b/internal/virt/guest/mocks/Bot.go
index f4f9730..374e3b1 100644
--- a/internal/virt/guest/mocks/Bot.go
+++ b/internal/virt/guest/mocks/Bot.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.26.1. DO NOT EDIT.
+// Code generated by mockery v2.42.0. DO NOT EDIT.
package mocks
@@ -7,15 +7,17 @@ import (
agent "github.com/projecteru2/yavirt/internal/virt/agent"
- libvirt "github.com/libvirt/libvirt-go"
+ internaltypes "github.com/projecteru2/yavirt/internal/types"
+
+ libvirt "github.com/projecteru2/yavirt/third_party/libvirt"
mock "github.com/stretchr/testify/mock"
- models "github.com/projecteru2/yavirt/internal/models"
+ pkglibvirt "github.com/projecteru2/yavirt/pkg/libvirt"
- types "github.com/projecteru2/yavirt/internal/virt/types"
+ types "github.com/yuyang0/vmimage/types"
- volume "github.com/projecteru2/yavirt/internal/virt/volume"
+ volume "github.com/projecteru2/yavirt/internal/volume"
)
// Bot is an autogenerated mock type for the Bot type
@@ -23,13 +25,17 @@ type Bot struct {
mock.Mock
}
-// AmplifyVolume provides a mock function with given fields: vol, cap, devPath
-func (_m *Bot) AmplifyVolume(vol volume.Virt, cap int64, devPath string) error {
- ret := _m.Called(vol, cap, devPath)
+// AmplifyVolume provides a mock function with given fields: vol, cap
+func (_m *Bot) AmplifyVolume(vol volume.Volume, cap int64) error {
+ ret := _m.Called(vol, cap)
+
+ if len(ret) == 0 {
+ panic("no return value specified for AmplifyVolume")
+ }
var r0 error
- if rf, ok := ret.Get(0).(func(volume.Virt, int64, string) error); ok {
- r0 = rf(vol, cap, devPath)
+ if rf, ok := ret.Get(0).(func(volume.Volume, int64) error); ok {
+ r0 = rf(vol, cap)
} else {
r0 = ret.Error(0)
}
@@ -37,25 +43,47 @@ func (_m *Bot) AmplifyVolume(vol volume.Virt, cap int64, devPath string) error {
return r0
}
-// AttachVolume provides a mock function with given fields: volmod, devName
-func (_m *Bot) AttachVolume(volmod *models.Volume, devName string) (func(), error) {
- ret := _m.Called(volmod, devName)
+// AttachGPUs provides a mock function with given fields: pcm
+func (_m *Bot) AttachGPUs(pcm map[string]int) error {
+ ret := _m.Called(pcm)
+
+ if len(ret) == 0 {
+ panic("no return value specified for AttachGPUs")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(map[string]int) error); ok {
+ r0 = rf(pcm)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// AttachVolume provides a mock function with given fields: volmod
+func (_m *Bot) AttachVolume(volmod volume.Volume) (func(), error) {
+ ret := _m.Called(volmod)
+
+ if len(ret) == 0 {
+ panic("no return value specified for AttachVolume")
+ }
var r0 func()
var r1 error
- if rf, ok := ret.Get(0).(func(*models.Volume, string) (func(), error)); ok {
- return rf(volmod, devName)
+ if rf, ok := ret.Get(0).(func(volume.Volume) (func(), error)); ok {
+ return rf(volmod)
}
- if rf, ok := ret.Get(0).(func(*models.Volume, string) func()); ok {
- r0 = rf(volmod, devName)
+ if rf, ok := ret.Get(0).(func(volume.Volume) func()); ok {
+ r0 = rf(volmod)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(func())
}
}
- if rf, ok := ret.Get(1).(func(*models.Volume, string) error); ok {
- r1 = rf(volmod, devName)
+ if rf, ok := ret.Get(1).(func(volume.Volume) error); ok {
+ r1 = rf(volmod)
} else {
r1 = ret.Error(1)
}
@@ -67,6 +95,10 @@ func (_m *Bot) AttachVolume(volmod *models.Volume, devName string) (func(), erro
func (_m *Bot) BindExtraNetwork() error {
ret := _m.Called()
+ if len(ret) == 0 {
+ panic("no return value specified for BindExtraNetwork")
+ }
+
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
@@ -77,13 +109,17 @@ func (_m *Bot) BindExtraNetwork() error {
return r0
}
-// Boot provides a mock function with given fields:
-func (_m *Bot) Boot() error {
- ret := _m.Called()
+// Boot provides a mock function with given fields: ctx
+func (_m *Bot) Boot(ctx context.Context) error {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Boot")
+ }
var r0 error
- if rf, ok := ret.Get(0).(func() error); ok {
- r0 = rf()
+ if rf, ok := ret.Get(0).(func(context.Context) error); ok {
+ r0 = rf(ctx)
} else {
r0 = ret.Error(0)
}
@@ -91,25 +127,29 @@ func (_m *Bot) Boot() error {
return r0
}
-// Capture provides a mock function with given fields: user, name
-func (_m *Bot) Capture(user string, name string) (*models.UserImage, error) {
- ret := _m.Called(user, name)
+// Capture provides a mock function with given fields: imgName
+func (_m *Bot) Capture(imgName string) (*types.Image, error) {
+ ret := _m.Called(imgName)
- var r0 *models.UserImage
+ if len(ret) == 0 {
+ panic("no return value specified for Capture")
+ }
+
+ var r0 *types.Image
var r1 error
- if rf, ok := ret.Get(0).(func(string, string) (*models.UserImage, error)); ok {
- return rf(user, name)
+ if rf, ok := ret.Get(0).(func(string) (*types.Image, error)); ok {
+ return rf(imgName)
}
- if rf, ok := ret.Get(0).(func(string, string) *models.UserImage); ok {
- r0 = rf(user, name)
+ if rf, ok := ret.Get(0).(func(string) *types.Image); ok {
+ r0 = rf(imgName)
} else {
if ret.Get(0) != nil {
- r0 = ret.Get(0).(*models.UserImage)
+ r0 = ret.Get(0).(*types.Image)
}
}
- if rf, ok := ret.Get(1).(func(string, string) error); ok {
- r1 = rf(user, name)
+ if rf, ok := ret.Get(1).(func(string) error); ok {
+ r1 = rf(imgName)
} else {
r1 = ret.Error(1)
}
@@ -118,11 +158,15 @@ func (_m *Bot) Capture(user string, name string) (*models.UserImage, error) {
}
// CheckVolume provides a mock function with given fields: _a0
-func (_m *Bot) CheckVolume(_a0 *models.Volume) error {
+func (_m *Bot) CheckVolume(_a0 volume.Volume) error {
ret := _m.Called(_a0)
+ if len(ret) == 0 {
+ panic("no return value specified for CheckVolume")
+ }
+
var r0 error
- if rf, ok := ret.Get(0).(func(*models.Volume) error); ok {
+ if rf, ok := ret.Get(0).(func(volume.Volume) error); ok {
r0 = rf(_a0)
} else {
r0 = ret.Error(0)
@@ -135,6 +179,10 @@ func (_m *Bot) CheckVolume(_a0 *models.Volume) error {
func (_m *Bot) Close() error {
ret := _m.Called()
+ if len(ret) == 0 {
+ panic("no return value specified for Close")
+ }
+
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
@@ -146,11 +194,15 @@ func (_m *Bot) Close() error {
}
// CommitSnapshot provides a mock function with given fields: _a0, _a1
-func (_m *Bot) CommitSnapshot(_a0 *models.Volume, _a1 string) error {
+func (_m *Bot) CommitSnapshot(_a0 volume.Volume, _a1 string) error {
ret := _m.Called(_a0, _a1)
+ if len(ret) == 0 {
+ panic("no return value specified for CommitSnapshot")
+ }
+
var r0 error
- if rf, ok := ret.Get(0).(func(*models.Volume, string) error); ok {
+ if rf, ok := ret.Get(0).(func(volume.Volume, string) error); ok {
r0 = rf(_a0, _a1)
} else {
r0 = ret.Error(0)
@@ -160,11 +212,15 @@ func (_m *Bot) CommitSnapshot(_a0 *models.Volume, _a1 string) error {
}
// CommitSnapshotByDay provides a mock function with given fields: _a0, _a1
-func (_m *Bot) CommitSnapshotByDay(_a0 *models.Volume, _a1 int) error {
+func (_m *Bot) CommitSnapshotByDay(_a0 volume.Volume, _a1 int) error {
ret := _m.Called(_a0, _a1)
+ if len(ret) == 0 {
+ panic("no return value specified for CommitSnapshotByDay")
+ }
+
var r0 error
- if rf, ok := ret.Get(0).(func(*models.Volume, int) error); ok {
+ if rf, ok := ret.Get(0).(func(volume.Volume, int) error); ok {
r0 = rf(_a0, _a1)
} else {
r0 = ret.Error(0)
@@ -173,13 +229,17 @@ func (_m *Bot) CommitSnapshotByDay(_a0 *models.Volume, _a1 int) error {
return r0
}
-// Create provides a mock function with given fields:
-func (_m *Bot) Create() error {
- ret := _m.Called()
+// CreateSnapshot provides a mock function with given fields: _a0
+func (_m *Bot) CreateSnapshot(_a0 volume.Volume) error {
+ ret := _m.Called(_a0)
+
+ if len(ret) == 0 {
+ panic("no return value specified for CreateSnapshot")
+ }
var r0 error
- if rf, ok := ret.Get(0).(func() error); ok {
- r0 = rf()
+ if rf, ok := ret.Get(0).(func(volume.Volume) error); ok {
+ r0 = rf(_a0)
} else {
r0 = ret.Error(0)
}
@@ -187,13 +247,53 @@ func (_m *Bot) Create() error {
return r0
}
-// CreateSnapshot provides a mock function with given fields: _a0
-func (_m *Bot) CreateSnapshot(_a0 *models.Volume) error {
- ret := _m.Called(_a0)
+// Define provides a mock function with given fields: ctx
+func (_m *Bot) Define(ctx context.Context) error {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Define")
+ }
var r0 error
- if rf, ok := ret.Get(0).(func(*models.Volume) error); ok {
- r0 = rf(_a0)
+ if rf, ok := ret.Get(0).(func(context.Context) error); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// DetachGPUs provides a mock function with given fields: pcm
+func (_m *Bot) DetachGPUs(pcm map[string]int) error {
+ ret := _m.Called(pcm)
+
+ if len(ret) == 0 {
+ panic("no return value specified for DetachGPUs")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(map[string]int) error); ok {
+ r0 = rf(pcm)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// DetachVolume provides a mock function with given fields: vol
+func (_m *Bot) DetachVolume(vol volume.Volume) error {
+ ret := _m.Called(vol)
+
+ if len(ret) == 0 {
+ panic("no return value specified for DetachVolume")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(volume.Volume) error); ok {
+ r0 = rf(vol)
} else {
r0 = ret.Error(0)
}
@@ -205,6 +305,10 @@ func (_m *Bot) CreateSnapshot(_a0 *models.Volume) error {
func (_m *Bot) ExecuteCommand(_a0 context.Context, _a1 []string) ([]byte, int, int, error) {
ret := _m.Called(_a0, _a1)
+ if len(ret) == 0 {
+ panic("no return value specified for ExecuteCommand")
+ }
+
var r0 []byte
var r1 int
var r2 int
@@ -241,10 +345,98 @@ func (_m *Bot) ExecuteCommand(_a0 context.Context, _a1 []string) ([]byte, int, i
return r0, r1, r2, r3
}
+// FSFreezeAll provides a mock function with given fields: ctx
+func (_m *Bot) FSFreezeAll(ctx context.Context) (int, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FSFreezeAll")
+ }
+
+ var r0 int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (int, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) int); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Get(0).(int)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// FSFreezeStatus provides a mock function with given fields: ctx
+func (_m *Bot) FSFreezeStatus(ctx context.Context) (string, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FSFreezeStatus")
+ }
+
+ var r0 string
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (string, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) string); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Get(0).(string)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// FSThawAll provides a mock function with given fields: ctx
+func (_m *Bot) FSThawAll(ctx context.Context) (int, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FSThawAll")
+ }
+
+ var r0 int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (int, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) int); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Get(0).(int)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
// GetState provides a mock function with given fields:
func (_m *Bot) GetState() (libvirt.DomainState, error) {
ret := _m.Called()
+ if len(ret) == 0 {
+ panic("no return value specified for GetState")
+ }
+
var r0 libvirt.DomainState
var r1 error
if rf, ok := ret.Get(0).(func() (libvirt.DomainState, error)); ok {
@@ -269,6 +461,10 @@ func (_m *Bot) GetState() (libvirt.DomainState, error) {
func (_m *Bot) GetUUID() (string, error) {
ret := _m.Called()
+ if len(ret) == 0 {
+ panic("no return value specified for GetUUID")
+ }
+
var r0 string
var r1 error
if rf, ok := ret.Get(0).(func() (string, error)); ok {
@@ -293,6 +489,10 @@ func (_m *Bot) GetUUID() (string, error) {
func (_m *Bot) IsFolder(_a0 context.Context, _a1 string) (bool, error) {
ret := _m.Called(_a0, _a1)
+ if len(ret) == 0 {
+ panic("no return value specified for IsFolder")
+ }
+
var r0 bool
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string) (bool, error)); ok {
@@ -317,6 +517,10 @@ func (_m *Bot) IsFolder(_a0 context.Context, _a1 string) (bool, error) {
func (_m *Bot) MakeDirectory(ctx context.Context, path string, parent bool) error {
ret := _m.Called(ctx, path, parent)
+ if len(ret) == 0 {
+ panic("no return value specified for MakeDirectory")
+ }
+
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, string, bool) error); ok {
r0 = rf(ctx, path, parent)
@@ -331,6 +535,10 @@ func (_m *Bot) MakeDirectory(ctx context.Context, path string, parent bool) erro
func (_m *Bot) Migrate() error {
ret := _m.Called()
+ if len(ret) == 0 {
+ panic("no return value specified for Migrate")
+ }
+
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
@@ -342,23 +550,27 @@ func (_m *Bot) Migrate() error {
}
// OpenConsole provides a mock function with given fields: _a0, _a1
-func (_m *Bot) OpenConsole(_a0 context.Context, _a1 types.OpenConsoleFlags) (types.Console, error) {
+func (_m *Bot) OpenConsole(_a0 context.Context, _a1 internaltypes.OpenConsoleFlags) (*pkglibvirt.Console, error) {
ret := _m.Called(_a0, _a1)
- var r0 types.Console
+ if len(ret) == 0 {
+ panic("no return value specified for OpenConsole")
+ }
+
+ var r0 *pkglibvirt.Console
var r1 error
- if rf, ok := ret.Get(0).(func(context.Context, types.OpenConsoleFlags) (types.Console, error)); ok {
+ if rf, ok := ret.Get(0).(func(context.Context, internaltypes.OpenConsoleFlags) (*pkglibvirt.Console, error)); ok {
return rf(_a0, _a1)
}
- if rf, ok := ret.Get(0).(func(context.Context, types.OpenConsoleFlags) types.Console); ok {
+ if rf, ok := ret.Get(0).(func(context.Context, internaltypes.OpenConsoleFlags) *pkglibvirt.Console); ok {
r0 = rf(_a0, _a1)
} else {
if ret.Get(0) != nil {
- r0 = ret.Get(0).(types.Console)
+ r0 = ret.Get(0).(*pkglibvirt.Console)
}
}
- if rf, ok := ret.Get(1).(func(context.Context, types.OpenConsoleFlags) error); ok {
+ if rf, ok := ret.Get(1).(func(context.Context, internaltypes.OpenConsoleFlags) error); ok {
r1 = rf(_a0, _a1)
} else {
r1 = ret.Error(1)
@@ -367,25 +579,29 @@ func (_m *Bot) OpenConsole(_a0 context.Context, _a1 types.OpenConsoleFlags) (typ
return r0, r1
}
-// OpenFile provides a mock function with given fields: path, mode
-func (_m *Bot) OpenFile(path string, mode string) (agent.File, error) {
- ret := _m.Called(path, mode)
+// OpenFile provides a mock function with given fields: ctx, path, mode
+func (_m *Bot) OpenFile(ctx context.Context, path string, mode string) (agent.File, error) {
+ ret := _m.Called(ctx, path, mode)
+
+ if len(ret) == 0 {
+ panic("no return value specified for OpenFile")
+ }
var r0 agent.File
var r1 error
- if rf, ok := ret.Get(0).(func(string, string) (agent.File, error)); ok {
- return rf(path, mode)
+ if rf, ok := ret.Get(0).(func(context.Context, string, string) (agent.File, error)); ok {
+ return rf(ctx, path, mode)
}
- if rf, ok := ret.Get(0).(func(string, string) agent.File); ok {
- r0 = rf(path, mode)
+ if rf, ok := ret.Get(0).(func(context.Context, string, string) agent.File); ok {
+ r0 = rf(ctx, path, mode)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(agent.File)
}
}
- if rf, ok := ret.Get(1).(func(string, string) error); ok {
- r1 = rf(path, mode)
+ if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok {
+ r1 = rf(ctx, path, mode)
} else {
r1 = ret.Error(1)
}
@@ -397,6 +613,10 @@ func (_m *Bot) OpenFile(path string, mode string) (agent.File, error) {
func (_m *Bot) RemoveAll(_a0 context.Context, _a1 string) error {
ret := _m.Called(_a0, _a1)
+ if len(ret) == 0 {
+ panic("no return value specified for RemoveAll")
+ }
+
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, string) error); ok {
r0 = rf(_a0, _a1)
@@ -408,11 +628,15 @@ func (_m *Bot) RemoveAll(_a0 context.Context, _a1 string) error {
}
// RepairVolume provides a mock function with given fields: _a0
-func (_m *Bot) RepairVolume(_a0 *models.Volume) error {
+func (_m *Bot) RepairVolume(_a0 volume.Volume) error {
ret := _m.Called(_a0)
+ if len(ret) == 0 {
+ panic("no return value specified for RepairVolume")
+ }
+
var r0 error
- if rf, ok := ret.Get(0).(func(*models.Volume) error); ok {
+ if rf, ok := ret.Get(0).(func(volume.Volume) error); ok {
r0 = rf(_a0)
} else {
r0 = ret.Error(0)
@@ -421,10 +645,32 @@ func (_m *Bot) RepairVolume(_a0 *models.Volume) error {
return r0
}
+// ReplaceSysVolume provides a mock function with given fields: vol
+func (_m *Bot) ReplaceSysVolume(vol volume.Volume) error {
+ ret := _m.Called(vol)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ReplaceSysVolume")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(volume.Volume) error); ok {
+ r0 = rf(vol)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
// Resize provides a mock function with given fields: cpu, mem
func (_m *Bot) Resize(cpu int, mem int64) error {
ret := _m.Called(cpu, mem)
+ if len(ret) == 0 {
+ panic("no return value specified for Resize")
+ }
+
var r0 error
if rf, ok := ret.Get(0).(func(int, int64) error); ok {
r0 = rf(cpu, mem)
@@ -436,11 +682,15 @@ func (_m *Bot) Resize(cpu int, mem int64) error {
}
// RestoreSnapshot provides a mock function with given fields: _a0, _a1
-func (_m *Bot) RestoreSnapshot(_a0 *models.Volume, _a1 string) error {
+func (_m *Bot) RestoreSnapshot(_a0 volume.Volume, _a1 string) error {
ret := _m.Called(_a0, _a1)
+ if len(ret) == 0 {
+ panic("no return value specified for RestoreSnapshot")
+ }
+
var r0 error
- if rf, ok := ret.Get(0).(func(*models.Volume, string) error); ok {
+ if rf, ok := ret.Get(0).(func(volume.Volume, string) error); ok {
r0 = rf(_a0, _a1)
} else {
r0 = ret.Error(0)
@@ -453,6 +703,10 @@ func (_m *Bot) RestoreSnapshot(_a0 *models.Volume, _a1 string) error {
func (_m *Bot) Resume() error {
ret := _m.Called()
+ if len(ret) == 0 {
+ panic("no return value specified for Resume")
+ }
+
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
@@ -463,13 +717,17 @@ func (_m *Bot) Resume() error {
return r0
}
-// Shutdown provides a mock function with given fields: force
-func (_m *Bot) Shutdown(force bool) error {
- ret := _m.Called(force)
+// Shutdown provides a mock function with given fields: ctx, force
+func (_m *Bot) Shutdown(ctx context.Context, force bool) error {
+ ret := _m.Called(ctx, force)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Shutdown")
+ }
var r0 error
- if rf, ok := ret.Get(0).(func(bool) error); ok {
- r0 = rf(force)
+ if rf, ok := ret.Get(0).(func(context.Context, bool) error); ok {
+ r0 = rf(ctx, force)
} else {
r0 = ret.Error(0)
}
@@ -481,6 +739,10 @@ func (_m *Bot) Shutdown(force bool) error {
func (_m *Bot) Suspend() error {
ret := _m.Called()
+ if len(ret) == 0 {
+ panic("no return value specified for Suspend")
+ }
+
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
@@ -495,6 +757,10 @@ func (_m *Bot) Suspend() error {
func (_m *Bot) Trylock() error {
ret := _m.Called()
+ if len(ret) == 0 {
+ panic("no return value specified for Trylock")
+ }
+
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
@@ -509,6 +775,10 @@ func (_m *Bot) Trylock() error {
func (_m *Bot) Undefine() error {
ret := _m.Called()
+ if len(ret) == 0 {
+ panic("no return value specified for Undefine")
+ }
+
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
@@ -524,13 +794,12 @@ func (_m *Bot) Unlock() {
_m.Called()
}
-type mockConstructorTestingTNewBot interface {
+// NewBot creates a new instance of Bot. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func NewBot(t interface {
mock.TestingT
Cleanup(func())
-}
-
-// NewBot creates a new instance of Bot. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-func NewBot(t mockConstructorTestingTNewBot) *Bot {
+}) *Bot {
mock := &Bot{}
mock.Mock.Test(t)
diff --git a/internal/virt/guest/network.go b/internal/virt/guest/network.go
index 35a4fa3..41dffa5 100644
--- a/internal/virt/guest/network.go
+++ b/internal/virt/guest/network.go
@@ -1,35 +1,27 @@
package guest
import (
- "bytes"
"context"
"encoding/json"
- "io"
- "os"
- "path/filepath"
- "strings"
- "time"
-
- current "github.com/containernetworking/cni/pkg/types/100"
+ "github.com/cockroachdb/errors"
+ "github.com/florianl/go-tc"
+ "github.com/projecteru2/core/log"
"github.com/projecteru2/yavirt/configs"
"github.com/projecteru2/yavirt/internal/meta"
"github.com/projecteru2/yavirt/internal/models"
- "github.com/projecteru2/yavirt/internal/vnet"
- calinet "github.com/projecteru2/yavirt/internal/vnet/calico"
- "github.com/projecteru2/yavirt/internal/vnet/handler"
- calihandler "github.com/projecteru2/yavirt/internal/vnet/handler/calico"
- vlanhandler "github.com/projecteru2/yavirt/internal/vnet/handler/vlan"
- "github.com/projecteru2/yavirt/internal/vnet/types"
- "github.com/projecteru2/yavirt/pkg/errors"
- "github.com/projecteru2/yavirt/pkg/log"
- "github.com/projecteru2/yavirt/pkg/sh"
+ "github.com/projecteru2/yavirt/internal/network"
+ networkFactory "github.com/projecteru2/yavirt/internal/network/factory"
+ "github.com/projecteru2/yavirt/internal/network/types"
+ interutils "github.com/projecteru2/yavirt/internal/utils"
+ "github.com/projecteru2/yavirt/pkg/terrors"
"github.com/projecteru2/yavirt/pkg/utils"
)
const (
- cniCmdAdd = "ADD"
- cniCmdDel = "DEL"
+ // for compatibility
+ calicoIPPoolLabelKey = "calico/ippool"
+ calicoNSLabelKey = "calico/namespace"
)
// DisconnectExtraNetwork .
@@ -44,159 +36,141 @@ func (g *Guest) ConnectExtraNetwork(_, _ string) (ip meta.IP, err error) {
return
}
-// CreateEthernet .
-func (g *Guest) CreateEthernet() (rollback func() error, err error) {
- if g.EnabledCalicoCNI {
- return g.calicoCNICreate()
+func (g *Guest) CreateNetwork(ctx context.Context) (err error) {
+ if g.MAC, err = utils.QemuMAC(); err != nil {
+ return errors.Wrap(err, "")
}
- var ip meta.IP
- if ip, err = g.assignIP(); err != nil {
- return nil, errors.Trace(err)
+ if _, err = g.createEthernet(); err != nil {
+ return errors.Wrap(err, "")
}
-
- var rollbackIP = func() error {
- return g.releaseIPs(ip)
+ rl := interutils.GetRollbackListFromContext(ctx)
+ if rl != nil {
+ rl.Append(func() error {
+ return g.botOperate(func(bot Bot) error { //nolint:revive
+ return g.DeleteNetwork()
+ }, true)
+ }, "delete network")
}
+ return nil
+}
- defer func() {
- if err != nil {
- if re := rollbackIP(); re != nil {
- err = errors.Wrap(err, re)
- }
- }
- }()
-
- var rollbackEndpoint func() error
- if rollbackEndpoint, err = g.createEndpoint(); err != nil {
- return nil, errors.Trace(err)
+func (g *Guest) getEndpointArgs() (types.EndpointArgs, error) {
+ hn := configs.Hostname()
+ args := types.EndpointArgs{
+ GuestID: g.ID,
+ MAC: g.MAC,
+ MTU: g.MTU,
+ Hostname: hn,
+ EndpointID: g.EndpointID,
+ IPs: g.IPs,
+ DevName: g.NetworkPair,
+ }
+ // just for compatibility
+ if args.MTU == 0 {
+ args.MTU = 1500
}
-
- return func() error {
- var err = errors.Errorf("rollback network for %s", ip)
-
- if re := rollbackEndpoint(); re != nil {
- return errors.Wrap(err, re)
+ switch g.NetworkMode {
+ case network.OVNMode:
+ var ovnArgs types.OVNArgs
+ rawJSON := g.JSONLabels[network.OVNLabelKey]
+ if rawJSON == "" {
+ return args, errors.Errorf("ovn args not found")
}
-
- if re := rollbackIP(); re != nil {
- return errors.Wrap(err, re)
+ if err := json.Unmarshal([]byte(rawJSON), &ovnArgs); err != nil {
+ return args, errors.Wrap(err, "")
}
-
- return err
- }, nil
+ args.OVN = ovnArgs
+ case network.CalicoMode:
+ var calicoArgs types.CalicoArgs
+ rawJSON := g.JSONLabels[network.CalicoLabelKey]
+ if rawJSON != "" {
+ if err := json.Unmarshal([]byte(rawJSON), &calicoArgs); err != nil {
+ return args, errors.Wrap(err, "")
+ }
+ } else {
+ calicoArgs.IPPool = g.JSONLabels[calicoIPPoolLabelKey]
+ calicoArgs.Namespace = g.JSONLabels[calicoNSLabelKey]
+ }
+ if calicoArgs.Namespace == "" {
+ calicoArgs.Namespace = hn
+ }
+ args.Calico = calicoArgs
+ case network.CalicoCNIMode:
+ // TODO implement CNI
+ var cniArgs types.CNIArgs
+ args.CNI = cniArgs
+ case network.VlanMode:
+ // TODO
+ var vlanArgs types.VlanArgs
+ args.Vlan = vlanArgs
+ case network.FakeMode:
+ // do nothing
+ default:
+ return args, errors.Errorf("unsupported network mode %s", g.NetworkMode)
+ }
+ return args, nil
}
-func (g *Guest) createEndpoint() (rollback func() error, err error) {
- hn := configs.Hostname()
-
- var hand handler.Handler
- hand, err = g.NetworkHandler(g.Host)
+// createEthernet .
+func (g *Guest) createEthernet() (rollback func() error, err error) {
+ var hand network.Driver
+ hand, err = g.NetworkHandler()
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
-
- var args types.EndpointArgs
- args.IPs = g.IPs
- args.MAC = g.MAC
- args.Hostname = hn
-
- var rollCreate func()
+ args, err := g.getEndpointArgs()
+ if err != nil {
+ return nil, err
+ }
+ var rollCreate func() error
args, rollCreate, err = hand.CreateEndpointNetwork(args)
switch {
case err != nil:
- return nil, errors.Trace(err)
- case args.Device != nil:
- g.NetworkPair = args.Device.Name()
+ return nil, errors.Wrap(err, "")
+ case args.DevName != "":
+ g.NetworkPair = args.DevName
}
g.EndpointID = args.EndpointID
-
- var unjoin func()
- if unjoin, err = hand.JoinEndpointNetwork(args); err != nil {
- rollCreate()
- return nil, errors.Trace(err)
- }
-
- rollback = func() error {
- unjoin()
- rollCreate()
- return nil
- }
-
- return rollback, nil
+ g.MAC = args.MAC
+ g.MTU = args.MTU
+ g.AppendIPs(args.IPs...)
+ return rollCreate, nil
}
func (g *Guest) joinEthernet() (err error) {
- if g.EnabledCalicoCNI {
- _, _, err = g.calicoCNIAdd(false)
- return errors.Trace(err)
+ var hand network.Driver
+ if hand, err = g.NetworkHandler(); err != nil {
+ return errors.Wrap(err, "")
}
- var hand handler.Handler
- if hand, err = g.NetworkHandler(g.Host); err != nil {
- return errors.Trace(err)
- }
-
- var args types.EndpointArgs
- args.IPs = g.IPs
- args.MAC = g.MAC
- args.EndpointID = g.EndpointID
-
- args.Hostname = configs.Hostname()
-
- if args.Device, err = hand.GetEndpointDevice(g.NetworkPair); err != nil {
- return errors.Trace(err)
+ args, err := g.getEndpointArgs()
+ if err != nil {
+ return errors.Wrapf(err, "failed to join ethernet")
}
-
_, err = hand.JoinEndpointNetwork(args)
return
}
-func (g *Guest) assignIP() (meta.IP, error) {
- hand, err := g.NetworkHandler(g.Host)
- if err != nil {
- return nil, errors.Trace(err)
- }
-
- ip, err := hand.AssignIP()
- if err != nil {
- return nil, errors.Trace(err)
- }
-
- g.AppendIPs(ip)
-
- return ip, nil
-}
-
// DeleteNetwork .
func (g *Guest) DeleteNetwork() error {
return g.deleteEthernet()
}
func (g *Guest) deleteEthernet() error {
- if g.EnabledCalicoCNI {
- return g.calicoCNIDel()
+ hand, err := g.NetworkHandler()
+ if err != nil {
+ return errors.Wrap(err, "")
}
- hn := configs.Hostname()
-
- hand, err := g.NetworkHandler(g.Host)
+ args, err := g.getEndpointArgs()
if err != nil {
- return errors.Trace(err)
+ return errors.Wrapf(err, "failed to delete ethernet")
}
-
- var args = types.EndpointArgs{}
- args.EndpointID = g.EndpointID
- args.Hostname = hn
-
if err := hand.DeleteEndpointNetwork(args); err != nil {
- return errors.Trace(err)
- }
-
- if err := g.releaseIPs(g.IPs...); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
g.IPs = models.IPs{}
@@ -210,180 +184,26 @@ func (g *Guest) loadExtraNetworks() error {
return nil
}
-func (g *Guest) releaseIPs(ips ...meta.IP) error {
- var hand, err = g.NetworkHandler(g.Host)
- if err != nil {
- return errors.Trace(err)
- }
- return hand.ReleaseIPs(ips...)
-}
-
// NetworkHandler .
-func (g *Guest) NetworkHandler(host *models.Host) (handler.Handler, error) {
- switch g.NetworkMode {
- case vnet.NetworkCalico:
- return g.ctx.CalicoHandler()
-
- case vnet.NetworkVlan:
- fallthrough
- case "":
- return vlanhandler.New(g.ID, host.Subnet), nil
-
- default:
- return nil, errors.Annotatef(errors.ErrInvalidValue, "invalid network: %s", g.NetworkMode)
+func (g *Guest) NetworkHandler() (network.Driver, error) {
+ d := networkFactory.GetDriver(g.NetworkMode)
+ if d == nil {
+ return nil, errors.Wrapf(terrors.ErrUnknownNetworkDriver, "guest: %s, networkMode: %s", g.ID, g.NetworkMode)
}
+ return d, nil
}
-func (g *Guest) calicoCNIDel() error {
- env := g.makeCNIEnv()
- env["CNI_COMMAND"] = cniCmdDel
-
- dat, err := g.readCNIConfig()
+func (g *Guest) limitBandwidth() error {
+ rtnl, err := tc.Open(&tc.Config{})
if err != nil {
- return errors.Trace(err)
- }
-
- _, err = execCNIPlugin(env, bytes.NewBuffer(dat), configs.Conf.CNIPluginPath)
- return err
-}
-
-func (g *Guest) calicoCNICreate() (func() error, error) {
- endpointID, err := utils.UUIDStr()
- if err != nil {
- return nil, errors.Trace(err)
- }
- endpointID = strings.ReplaceAll(endpointID, "-", "")
-
- g.EndpointID = endpointID
- g.NetworkPair = "yap" + g.EndpointID[:utils.Min(12, len(g.EndpointID))]
-
- stdout, execDel, err := g.calicoCNIAdd(true)
- if err != nil {
- return nil, errors.Trace(err)
- }
-
- if err := g.populateIPFromAddResult(stdout); err != nil {
- if de := execDel(); de != nil {
- return nil, errors.Wrap(err, de)
- }
- }
-
- return execDel, nil
-}
-
-func (g *Guest) calicoCNIAdd(needRollback bool) (stdout []byte, rollback func() error, err error) {
- env := g.makeCNIEnv()
- env["CNI_COMMAND"] = cniCmdAdd
-
- var dat []byte
- if dat, err = g.readCNIConfig(); err != nil {
- return nil, nil, errors.Trace(err)
- }
-
- if stdout, err = execCNIPlugin(env, bytes.NewBuffer(dat), configs.Conf.CNIPluginPath); err != nil {
- return nil, nil, errors.Trace(err)
- }
-
- execDel := func() error {
- env["CNI_COMMAND"] = cniCmdDel
- _, err := execCNIPlugin(env, bytes.NewBuffer(dat), configs.Conf.CNIPluginPath)
+ log.Errorf(context.TODO(), err, "[limitBandwidth] could not open rtnetlink socket")
return err
}
-
defer func() {
- if err != nil && needRollback {
- if de := execDel(); de != nil {
- err = errors.Wrap(err, de)
- }
- execDel = nil
+ if err := rtnl.Close(); err != nil {
+ log.Errorf(context.TODO(), err, "[limitBandwidth] could not close rtnetlink socket")
}
}()
- hand, err := g.calicoHandler()
- if err != nil {
- return nil, nil, errors.Trace(err)
- }
-
- // Refreshes gateway for non-Calico-CNI operations.
- if err = hand.RefreshGateway(); err != nil {
- return nil, nil, errors.Trace(err)
- }
-
- return stdout, execDel, nil
-}
-
-func (g *Guest) populateIPFromAddResult(dat []byte) error {
- var result current.Result
- if err := json.Unmarshal(dat, &result); err != nil {
- return errors.Trace(err)
- }
- if len(result.IPs) < 1 {
- return errors.Trace(errors.ErrIPIsnotAssigned)
- }
-
- hand, err := g.calicoHandler()
- if err != nil {
- return errors.Trace(err)
- }
-
- for _, ipConf := range result.IPs {
- ip, err := calinet.ParseCIDR(ipConf.Address.String())
- if err != nil {
- return errors.Trace(err)
- }
-
- gwip, err := hand.GetGatewayIP(ip)
- if err != nil {
- return errors.Trace(err)
- }
-
- ip.BindGatewayIPNet(gwip.IPNetwork())
-
- g.AppendIPs(ip)
- }
-
return nil
}
-
-func (g *Guest) readCNIConfig() ([]byte, error) {
- // TODO: follows the CNI policy, rather than hard code absolute path here.
- return os.ReadFile(configs.Conf.CNIConfigPath)
-}
-
-func (g *Guest) makeCNIEnv() map[string]string {
- return map[string]string{
- "CNI_CONTAINERID": g.ID,
- "CNI_ARGS": "IgnoreUnknown=1;MAC=" + g.MAC,
- "CNI_IFNAME": g.NetworkPair,
- "CNI_PATH": filepath.Dir(configs.Conf.CNIPluginPath),
- "CNI_NETNS": "yap",
- }
-}
-
-func (g *Guest) calicoHandler() (*calihandler.Handler, error) {
- raw, err := g.NetworkHandler(g.Host)
- if err != nil {
- return nil, errors.Trace(err)
- }
-
- hand, ok := raw.(*calihandler.Handler)
- if !ok {
- return nil, errors.Annotatef(errors.ErrInvalidValue, "invalid *calihandler.Handler: %v", raw)
- }
-
- return hand, nil
-}
-
-func execCNIPlugin(env map[string]string, stdin io.Reader, plugin string) ([]byte, error) {
- ctx, cancel := context.WithTimeout(context.Background(), time.Minute*8)
- defer cancel()
-
- log.Debugf("CNI Plugin env: %v", env)
- so, se, err := sh.ExecInOut(ctx, env, stdin, plugin)
-
- if err != nil {
- err = errors.Annotatef(err, "Failed to exec %s with %v: %s: %s", plugin, string(so), string(se))
- }
-
- return so, err
-}
diff --git a/internal/virt/guest/types.go b/internal/virt/guest/types.go
deleted file mode 100644
index 56d4daa..0000000
--- a/internal/virt/guest/types.go
+++ /dev/null
@@ -1,33 +0,0 @@
-package guest
-
-import (
- "syscall"
-)
-
-type fdAdapter struct {
- fd int
-}
-
-func (a fdAdapter) Read(p []byte) (n int, err error) {
- n, err = syscall.Read(a.fd, p)
- if err != nil { // Linux syscall.Read may return n = -1 on error
- n = 0
- }
- return
-}
-
-func (a fdAdapter) Write(p []byte) (n int, err error) {
- n, err = syscall.Write(a.fd, p)
- if err != nil { // Linux syscall.Write may return n = -1 on error
- n = 0
- }
- return
-}
-
-func (a fdAdapter) Fd() int {
- return a.fd
-}
-
-func (a fdAdapter) Close() error {
- return syscall.Close(a.fd)
-}
diff --git a/internal/virt/guestfs/gfsx/gfsx.go b/internal/virt/guestfs/gfsx/gfsx.go
index f71444c..bbc72f3 100644
--- a/internal/virt/guestfs/gfsx/gfsx.go
+++ b/internal/virt/guestfs/gfsx/gfsx.go
@@ -5,9 +5,10 @@ import (
"regexp"
"strings"
+ "github.com/cockroachdb/errors"
"github.com/projecteru2/yavirt/internal/virt/guestfs"
"github.com/projecteru2/yavirt/internal/virt/guestfs/types"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/projecteru2/yavirt/pkg/terrors"
libguestfs "github.com/projecteru2/yavirt/third_party/guestfs"
)
@@ -19,6 +20,13 @@ type Gfsx struct {
// New .
func New(path string) (_ guestfs.Guestfs, err error) {
+ opts := &libguestfs.OptargsAdd_drive{
+ Readonly_is_set: false,
+ }
+ return NewFromOpts(path, opts)
+}
+
+func NewFromOpts(path string, opts *libguestfs.OptargsAdd_drive) (_ guestfs.Guestfs, err error) {
gfsx := &Gfsx{osDevs: []string{}}
if gfsx.gfs, err = libguestfs.Create(); err != nil {
return
@@ -29,9 +37,7 @@ func New(path string) (_ guestfs.Guestfs, err error) {
}
}()
- if err = gfsx.gfs.Add_drive(path, &libguestfs.OptargsAdd_drive{
- Readonly_is_set: false,
- }); err != nil {
+ if err = gfsx.gfs.Add_drive(path, opts); err != nil {
return
}
@@ -43,7 +49,7 @@ func New(path string) (_ guestfs.Guestfs, err error) {
case err != nil:
return
case len(gfsx.osDevs) != 1:
- return nil, errors.Annotatef(errors.ErrInvalidValue, "%d OS in the image", len(gfsx.osDevs))
+ return nil, errors.Wrapf(terrors.ErrInvalidValue, "%d OS in the image", len(gfsx.osDevs))
}
if err = gfsx.gfs.Mount(gfsx.osDevs[0], "/"); err != nil {
@@ -67,7 +73,7 @@ func (g *Gfsx) Close() error {
func (g *Gfsx) GetFstabEntries() (map[string]string, error) {
cont, err := g.Cat(types.FstabFile)
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
return g.parseFstab(cont)
}
@@ -75,7 +81,7 @@ func (g *Gfsx) GetFstabEntries() (map[string]string, error) {
func (g *Gfsx) parseFstab(cont string) (map[string]string, error) {
re, err := regexp.Compile(`^(.*?)\s`) //nolint
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
entries := map[string]string{}
@@ -101,14 +107,14 @@ func (g *Gfsx) parseFstab(cont string) (map[string]string, error) {
func (g *Gfsx) GetBlkids() (types.Blkids, error) {
fss, err := g.gfs.List_filesystems()
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
blkids := types.Blkids{}
for dev := range fss {
blkid, err := g.Blkid(dev)
if err != nil {
- return nil, errors.Annotatef(err, "get blkid %s failed", dev)
+ return nil, errors.WithMessagef(err, "get blkid %s failed", dev)
}
blkids.Add(blkid)
}
@@ -120,7 +126,7 @@ func (g *Gfsx) GetBlkids() (types.Blkids, error) {
func (g *Gfsx) Blkid(dev string) (*types.Blkid, error) {
entries, err := g.gfs.Blkid(dev)
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "failed to get blkid")
}
blkid := &types.Blkid{Dev: dev}
diff --git a/internal/virt/nic/centos_config_file.go b/internal/virt/nic/centos_config_file.go
deleted file mode 100644
index f010ac6..0000000
--- a/internal/virt/nic/centos_config_file.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package nic
-
-import (
- "fmt"
-
- "github.com/projecteru2/yavirt/internal/meta"
- "github.com/projecteru2/yavirt/internal/virt/agent"
-)
-
-// CentosConfigFile .
-type CentosConfigFile struct {
- *GenericConfigFile
-}
-
-// OpenCentosConfigFile .
-func OpenCentosConfigFile(ga *agent.Agent, dev string, ip meta.IP) (fw *CentosConfigFile, err error) {
- fw = &CentosConfigFile{GenericConfigFile: &GenericConfigFile{
- path: getEthCentOSFile(dev),
- ip: ip,
- dev: dev,
- }}
- fw.file, err = agent.OpenFile(ga, fw.path, "w")
- return
-}
-
-// Save .
-func (w *CentosConfigFile) Save() (err error) {
- var conf = fmt.Sprintf(`TYPE="Ethernet"
-BOOTPROTO="static"
-NAME="%s"
-DEVICE="%s"
-ONBOOT="yes"
-IPADDR="%s"
-PREFIX="%d"
-GATEWAY="%s"
-`, w.dev, w.dev, w.ip.IPAddr(), w.ip.Prefix(), w.ip.GatewayAddr())
-
- return w.Write([]byte(conf))
-}
diff --git a/internal/virt/nic/config_file.go b/internal/virt/nic/config_file.go
deleted file mode 100644
index 2a2a117..0000000
--- a/internal/virt/nic/config_file.go
+++ /dev/null
@@ -1,37 +0,0 @@
-package nic
-
-import (
- "github.com/projecteru2/yavirt/internal/meta"
- "github.com/projecteru2/yavirt/internal/virt/agent"
-)
-
-// ConfigFile .
-type ConfigFile interface {
- Save() error
- Close() error
-}
-
-// GenericConfigFile .
-type GenericConfigFile struct {
- file agent.File
- path string
- ip meta.IP
- dev string
-}
-
-// Close .
-func (w *GenericConfigFile) Close() (err error) {
- return w.file.Close()
-}
-
-func (w *GenericConfigFile) Write(buf []byte) (err error) {
- defer func() {
- if err == nil {
- err = w.file.Flush()
- }
- }()
-
- _, err = w.file.Write(buf)
-
- return
-}
diff --git a/internal/virt/nic/nic.go b/internal/virt/nic/nic.go
index 9c08e47..b8594b6 100644
--- a/internal/virt/nic/nic.go
+++ b/internal/virt/nic/nic.go
@@ -3,98 +3,174 @@ package nic
import (
"bytes"
"context"
+ _ "embed"
"fmt"
+ "path"
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/core/log"
"github.com/projecteru2/yavirt/internal/meta"
- "github.com/projecteru2/yavirt/internal/models"
+ "github.com/projecteru2/yavirt/internal/types"
"github.com/projecteru2/yavirt/internal/virt/agent"
- "github.com/projecteru2/yavirt/internal/virt/types"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/projecteru2/yavirt/pkg/terrors"
)
-// Nic .
-type Nic struct {
- meta.IP
+//go:embed templates/vm-init.sh
+var vmInitScript string
- ga *agent.Agent
+type NICs struct {
+ ips []meta.IP
+ ga *agent.Agent
}
// NewNic .
-func NewNic(ip meta.IP, ga *agent.Agent) *Nic {
- return &Nic{IP: ip, ga: ga}
+func NewNicList(ips []meta.IP, ga *agent.Agent) *NICs {
+ return &NICs{ips: ips, ga: ga}
}
// Setup .
-func (n *Nic) Setup(ctx context.Context, distro, dev string) error {
- if err := n.SaveFile(ctx, distro, dev, dev); err != nil {
- return errors.Trace(err)
+func (nl *NICs) Setup(ctx context.Context) error {
+ args := make([]string, 0, 2*len(nl.ips))
+ for _, ip := range nl.ips {
+ args = append(args, ip.CIDR(), ip.GatewayAddr())
}
+ log.Infof(ctx, "Setup NIC list %v", nl.ips)
+ if err := nl.execVMInitScript(ctx, args...); err != nil {
+ return errors.Wrap(err, "")
+ }
+ for idx, ip := range nl.ips {
+ switch cidr, err := ip.AutoRouteCIDR(); {
+ case err != nil:
+ return errors.Wrap(err, "")
+
+ case len(cidr) > 0:
+ n, err := nl.GetNic(idx)
+ if err != nil {
+ return err
+ }
+ if err := n.delRoute(ctx, cidr); err != nil {
+ return errors.Wrap(err, "")
+ }
+ }
+ }
+ return nil
+}
- if err := n.addIP(ctx, n.CIDR(), dev); err != nil {
- return errors.Trace(err)
+func (nl *NICs) GetNic(idx int) (*Nic, error) {
+ if idx >= len(nl.ips) {
+ return nil, fmt.Errorf("NicList has only %v ips, so can't get Nic with index %v", len(nl.ips), idx)
}
+ return &Nic{
+ IP: nl.ips[idx],
+ ga: nl.ga,
+ }, nil
+}
- if err := n.enable(ctx, dev); err != nil {
- return errors.Trace(err)
+func (nl *NICs) execVMInitScript(ctx context.Context, args ...string) error {
+ vmFname := "/tmp/vm-init.sh"
+ if err := writeFileToGuest(ctx, nl.ga, []byte(vmInitScript), vmFname); err != nil {
+ return errors.Wrap(err, "")
}
+ newArgs := []string{vmFname}
+ newArgs = append(newArgs, args...)
- if err := n.addRoute(ctx, n.GatewayAddr()); err != nil {
- return errors.Trace(err)
+ var st = <-nl.ga.Exec(ctx, "bash", newArgs...)
+ if err := st.Error(); err != nil {
+ return errors.Wrapf(err, "failed to run vm-init.sh %v", args)
}
- switch cidr, err := n.AutoRouteCIDR(); {
- case err != nil:
- return errors.Trace(err)
+ st = <-nl.ga.Exec(ctx, "systemctl", "restart", "systemd-networkd")
+ if err := st.Error(); err != nil {
+ return errors.Wrapf(err, "failed to restart networkd")
+ }
- case len(cidr) > 0:
- if err := n.delRoute(ctx, cidr); err != nil {
- return errors.Trace(err)
- }
+ st = <-nl.ga.Exec(ctx, "rm", "-f", vmFname)
+ if err := st.Error(); err != nil {
+ return errors.Wrapf(err, "failed to remove vm-init.sh")
}
return nil
}
-// AddIP .
-func (n *Nic) AddIP(ctx context.Context, distro, dev, fn string) error {
- if err := n.SaveFile(ctx, distro, dev, fn); err != nil {
- return errors.Trace(err)
- }
+// Nic .
+type Nic struct {
+ meta.IP
- return n.addIP(ctx, n.CIDR(), dev)
+ ga *agent.Agent
}
-// SaveFile .
-func (n *Nic) SaveFile(_ context.Context, distro string, dev, fn string) (err error) {
- var file ConfigFile
+// NewNic .
+func NewNic(ip meta.IP, ga *agent.Agent) *Nic {
+ return &Nic{IP: ip, ga: ga}
+}
- switch distro {
- case models.DistroUbuntu:
- file, err = OpenUbuntuConfigFile(n.ga, dev, fn, n.IP)
- case models.DistroCentOS:
- file, err = OpenCentosConfigFile(n.ga, dev, n.IP)
- default:
- err = errors.Annotatef(errors.ErrInvalidValue, "invalid distro: %s", distro)
+// AddIP .
+func (n *Nic) AddIP(ctx context.Context, dev string) error {
+ if err := n.persisteNetworkCfg(ctx, dev); err != nil {
+ return errors.Wrap(err, "")
}
+ return n.addIP(ctx, n.CIDR(), dev)
+}
+
+func writeFileToGuest(ctx context.Context, ga *agent.Agent, buf []byte, fname string) (err error) {
+ var fp agent.File
+ fp, err = agent.OpenFile(ctx, ga, fname, "w")
if err != nil {
- return errors.Trace(err)
+ return err
}
- defer file.Close()
+ defer func() {
+ if err == nil {
+ err = fp.Flush(ctx)
+ }
+ }()
+
+ _, err = fp.Write(ctx, buf)
+
+ return
+}
+
+func (n *Nic) persisteNetworkCfg(ctx context.Context, dev string) (err error) {
+ // TODO: set gateway only when gateway is available
+ var netCfg = fmt.Sprintf(`
+[Match]
+Name=%s
+
+[Network]
+Address=%s
+Gateway=%s
+`, dev, n.CIDR(), n.GatewayAddr())
+
+ {
+ fname := fmt.Sprintf("10-%s.network", dev)
+ p := path.Join("/etc/systemd/network", fname)
+ if err = writeFileToGuest(ctx, n.ga, []byte(netCfg), p); err != nil {
+ return err
+ }
+ }
+ // restart networkd
+ var st = <-n.ga.Exec(ctx, "systemctl", "restart", "systemd-networkd")
+ if err = st.Error(); err != nil {
+ return errors.Wrap(err, "")
+ }
+ return
+ // if gw := w.ip.GatewayAddr(); len(gw) > 0 {
+ // conf += fmt.Sprintf(" gateway %s\n", gw)
+ // }
- return file.Save()
+ // return w.Write([]byte(conf))
}
-func (n *Nic) enable(ctx context.Context, dev string) error {
+func (n *Nic) enable(ctx context.Context, dev string) error { //nolint
var st = <-n.ga.Exec(ctx, "ip", "link", "set", dev, "up")
if err := st.Error(); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
return nil
}
-func (n *Nic) addRoute(ctx context.Context, dest string) error {
+func (n *Nic) addRoute(ctx context.Context, dest string) error { //nolint
return n.doIP(ctx, "ip", "route", "add", "default", "via", dest)
}
@@ -111,7 +187,7 @@ func (n *Nic) doIP(ctx context.Context, cmd string, args ...string) error {
_, _, err := st.CheckStdio(func(_, se []byte) bool {
return bytes.HasSuffix(bytes.Trim(se, "\n"), []byte(" File exists"))
})
- return errors.Annotatef(err, fmt.Sprintf("%s %v failed", cmd, args))
+ return errors.Wrapf(err, "%s %v failed", cmd, args)
}
// GetEthFile .
@@ -122,7 +198,7 @@ func GetEthFile(distro, dev string) (string, error) {
case types.CentOS:
return getEthCentOSFile(dev), nil
default:
- return "", errors.Annotatef(errors.ErrInvalidValue, "invalid distro: %s", distro)
+ return "", errors.Wrapf(terrors.ErrInvalidValue, "invalid distro: %s", distro)
}
}
diff --git a/internal/virt/nic/templates/vm-init.sh b/internal/virt/nic/templates/vm-init.sh
new file mode 100644
index 0000000..135d551
--- /dev/null
+++ b/internal/virt/nic/templates/vm-init.sh
@@ -0,0 +1,53 @@
+#!/bin/bash
+
+# initialize NIC
+# usage:
+# vm-init.sh ip1 gw1 ip2 gw2
+ifs=$(ip l | grep state | awk -F ': ' '{ if($2 != "lo" ) {print $2} }')
+
+for ifname in $ifs
+do
+ if ip a show dev "$ifname" | grep -q 'inet '; then
+ echo "The interface $ifname has an IP address."
+ shift 2
+ continue
+ fi
+ ip_addr=$1
+ gw_addr=$2
+
+ network="/etc/systemd/network/10-$ifname.network"
+ cat << EOF > $network
+[Match]
+Name=$ifname
+
+# [Network]
+# Gateway=$gw_addr
+
+[Address]
+Address=$ip_addr
+
+[Route]
+Gateway=$gw_addr
+# Destination=10.0.0.0/8
+GatewayOnlink=yes
+EOF
+ chmod 644 "/etc/systemd/network/10-$ifname.network"
+ # ip r add default via 169.254.1.1 dev $ifname onlink
+ shift 2
+done
+
+systemctl restart systemd-networkd
+
+# prepare dns if neccessary
+dnsOutput=$(dig +short baidu.com)
+if [ -z "$dnsOutput" ]
+then
+ echo "Setting DNS..."
+ mkdir /etc/systemd/resolved.conf.d/
+ cat << EOF > /etc/systemd/resolved.conf.d/dns_servers.conf
+[Resolve]
+DNS=8.8.8.8 1.1.1.1
+EOF
+
+ systemctl restart systemd-resolved
+fi
\ No newline at end of file
diff --git a/internal/virt/nic/ubuntu_config_file.go b/internal/virt/nic/ubuntu_config_file.go
deleted file mode 100644
index 167b5f2..0000000
--- a/internal/virt/nic/ubuntu_config_file.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package nic
-
-import (
- "fmt"
-
- "github.com/projecteru2/yavirt/internal/meta"
- "github.com/projecteru2/yavirt/internal/virt/agent"
-)
-
-// UbuntuConfigFile .
-type UbuntuConfigFile struct {
- *GenericConfigFile
-}
-
-// OpenUbuntuConfigFile .
-func OpenUbuntuConfigFile(ga *agent.Agent, dev, fn string, ip meta.IP) (fw *UbuntuConfigFile, err error) {
- fw = &UbuntuConfigFile{GenericConfigFile: &GenericConfigFile{
- path: getEthUbuntuFile(fn),
- ip: ip,
- dev: dev,
- }}
- fw.file, err = agent.OpenFile(ga, fw.path, "w")
- return
-}
-
-// Save .
-func (w *UbuntuConfigFile) Save() (err error) {
- var conf = fmt.Sprintf(`auto %s
-iface %s inet static
- address %s
- netmask %s
-`, w.dev, w.dev, w.ip.IPAddr(), w.ip.Netmask())
-
- if gw := w.ip.GatewayAddr(); len(gw) > 0 {
- conf += fmt.Sprintf(" gateway %s\n", gw)
- }
-
- return w.Write([]byte(conf))
-}
diff --git a/internal/virt/snapshot/bot.go b/internal/virt/snapshot/bot.go
deleted file mode 100644
index 731c7b1..0000000
--- a/internal/virt/snapshot/bot.go
+++ /dev/null
@@ -1,158 +0,0 @@
-package snapshot
-
-import (
- "context"
- "fmt"
- "path/filepath"
-
- "github.com/projecteru2/yavirt/configs"
- "github.com/projecteru2/yavirt/internal/models"
- virtutils "github.com/projecteru2/yavirt/internal/virt/utils"
- "github.com/projecteru2/yavirt/pkg/errors"
- "github.com/projecteru2/yavirt/pkg/sh"
- "github.com/projecteru2/yavirt/pkg/utils"
-)
-
-// Bot .
-type Bot interface {
- Close() error
- Create(vol *models.Volume) error
- Commit(models.Snapshots) error
- Restore(vol *models.Volume, chain models.Snapshots) error
- Delete() error
- Upload(force bool) error
- Download(*models.Snapshot) error
- DeleteFromBackupStorage() error
-}
-
-type bot struct {
- snap *Snapshot
- flock *utils.Flock
-}
-
-func newVirtSnap(snap *Snapshot) (Bot, error) {
- var vs = &bot{
- snap: snap,
- }
- vs.flock = vs.newFlock()
-
- if err := vs.flock.Trylock(); err != nil {
- return nil, errors.Trace(err)
- }
-
- return vs, nil
-}
-
-// Create .
-func (v *bot) Create(vol *models.Volume) error {
- tempFilepath := getTemporaryFilepath(vol.Filepath())
-
- if err := virtutils.CreateSnapshot(context.Background(), vol.Filepath(), tempFilepath); err != nil {
- return errors.Trace(err)
- }
-
- if err := sh.Copy(vol.Filepath(), v.snap.Filepath()); err != nil {
- return errors.Trace(err)
- }
-
- if err := virtutils.RebaseImage(context.Background(), tempFilepath, v.snap.Filepath()); err != nil {
- return errors.Trace(err)
- }
-
- return sh.Move(tempFilepath, vol.Filepath())
-}
-
-// Commit .
-func (v *bot) Commit(chain models.Snapshots) error {
-
- if chain.Len() == 1 {
- return nil
- }
-
- for i := 0; i < chain.Len()-1; i++ {
-
- if err := virtutils.CommitImage(context.Background(), chain[i].Filepath()); err != nil {
- return errors.Trace(err)
- }
-
- if err := sh.Remove(chain[i].Filepath()); err != nil {
- return errors.Trace(err)
- }
- }
-
- // Change name of the root snapshot to the current snapshot
- return sh.Move(chain[chain.Len()-1].Filepath(), chain[0].Filepath())
-}
-
-// Restore .
-func (v *bot) Restore(vol *models.Volume, chain models.Snapshots) error {
-
- for i := 0; i < chain.Len(); i++ {
- if err := sh.Copy(chain[i].Filepath(), getTemporaryFilepath(chain[i].Filepath())); err != nil {
- return errors.Trace(err)
- }
- }
-
- for i := 0; i < chain.Len()-1; i++ {
-
- if err := virtutils.CommitImage(context.Background(), chain[i].Filepath()); err != nil {
- return errors.Trace(err)
- }
-
- if err := sh.Remove(chain[i].Filepath()); err != nil {
- return errors.Trace(err)
- }
- }
-
- if err := sh.Move(chain[chain.Len()-1].Filepath(), vol.Filepath()); err != nil {
- return errors.Trace(err)
- }
-
- for i := 0; i < chain.Len(); i++ {
- if err := sh.Move(getTemporaryFilepath(chain[i].Filepath()), chain[i].Filepath()); err != nil {
- return errors.Trace(err)
- }
- }
-
- return nil
-}
-
-// Delete .
-func (v *bot) Delete() error {
- return sh.Remove(v.snap.Filepath())
-}
-
-// Upload .
-func (v *bot) Upload(_ bool) error {
- // TODO: implement
- // force = True means overwrite the file in backup storage
- return nil
-}
-
-// Download .
-func (v *bot) Download(_ *models.Snapshot) error {
- // TODO: implement
- // Need to check whether file already exist
- return nil
-}
-
-// DeleteFromBackupStorage .
-func (v *bot) DeleteFromBackupStorage() error {
- // TODO: implement
- return nil
-}
-
-func getTemporaryFilepath(filepath string) string {
- return filepath + ".temp"
-}
-
-func (v *bot) newFlock() *utils.Flock {
- fn := fmt.Sprintf("%s.flock", v.snap.ID)
- fpth := filepath.Join(configs.Conf.VirtFlockDir, fn)
- return utils.NewFlock(fpth)
-}
-
-func (v *bot) Close() error {
- v.flock.Close()
- return nil
-}
diff --git a/internal/virt/snapshot/bot_test.go b/internal/virt/snapshot/bot_test.go
deleted file mode 100644
index 5e96eda..0000000
--- a/internal/virt/snapshot/bot_test.go
+++ /dev/null
@@ -1,117 +0,0 @@
-package snapshot
-
-import (
- "fmt"
- "testing"
-
- "github.com/projecteru2/yavirt/internal/models"
- "github.com/projecteru2/yavirt/pkg/sh"
- shmocks "github.com/projecteru2/yavirt/pkg/sh/mocks"
- "github.com/projecteru2/yavirt/pkg/test/assert"
- "github.com/projecteru2/yavirt/pkg/test/mock"
-)
-
-func TestBotCreate(t *testing.T) {
- shx := &shmocks.Shell{}
- defer shx.AssertExpectations(t)
- cancel := sh.NewMockShell(shx)
- defer cancel()
-
- shx.On("Copy", mock.Anything, mock.Anything).Return(nil).Once()
- shx.On("Move", mock.Anything, mock.Anything).Return(nil).Once()
- shx.On("Exec", mock.Anything, "qemu-img", "create",
- "-f", "qcow2", "-F", "qcow2", mock.Anything, "-b", mock.Anything).Return(nil).Once()
- shx.On("Exec", mock.Anything, "qemu-img", "rebase", "-b", mock.Anything, mock.Anything).Return(nil).Once()
-
- sbot := &bot{
- snap: &Snapshot{
- Snapshot: models.NewSnapShot("vol-id-test"),
- },
- }
-
- err := sbot.Create(models.NewVolume("vtype", 1))
- assert.NilErr(t, err)
-}
-
-func TestBotCommit(t *testing.T) {
- shx := &shmocks.Shell{}
- defer shx.AssertExpectations(t)
- cancel := sh.NewMockShell(shx)
- defer cancel()
-
- sbot := &bot{
- snap: &Snapshot{
- Snapshot: models.NewSnapShot("vol-id-test"),
- },
- }
-
- n := 5
- chain := generateMockedSnapshots(n)
- shx.On("Move", mock.Anything, mock.Anything).Return(nil).Once()
- shx.On("Remove", mock.Anything).Return(nil).Times(n - 1)
- shx.On("Exec", mock.Anything, "qemu-img", "commit", mock.Anything).Return(nil).Times(n - 1)
-
- err := sbot.Commit(chain)
- assert.NilErr(t, err)
-
- n = 1
- chain = generateMockedSnapshots(n)
-
- err = sbot.Commit(chain)
- assert.NilErr(t, err)
-}
-
-func TestBotRestore(t *testing.T) {
- shx := &shmocks.Shell{}
- defer shx.AssertExpectations(t)
- cancel := sh.NewMockShell(shx)
- defer cancel()
-
- sbot := &bot{
- snap: &Snapshot{
- Snapshot: models.NewSnapShot("vol-id-test"),
- },
- }
-
- n := 5
- chain := generateMockedSnapshots(n)
- shx.On("Move", mock.Anything, mock.Anything).Return(nil).Times(n + 1)
- shx.On("Remove", mock.Anything).Return(nil).Times(n - 1)
- shx.On("Copy", mock.Anything, mock.Anything).Return(nil).Times(n)
- shx.On("Exec", mock.Anything, "qemu-img", "commit", mock.Anything).Return(nil).Times(n - 1)
-
- err := sbot.Restore(models.NewVolume("vtype", 1), chain)
- assert.NilErr(t, err)
-
- n = 1
- chain = generateMockedSnapshots(n)
- shx.On("Move", mock.Anything, mock.Anything).Return(nil).Times(n + 1)
- shx.On("Remove", mock.Anything).Return(nil).Times(n - 1)
- shx.On("Copy", mock.Anything, mock.Anything).Return(nil).Times(n)
- shx.On("Exec", mock.Anything, "qemu-img", "commit", mock.Anything).Return(nil).Times(n - 1)
-
- err = sbot.Restore(models.NewVolume("vtype", 1), chain)
- assert.NilErr(t, err)
-}
-
-func TestBotUpload(t *testing.T) {
- // TODO
-}
-
-func TestBotDownload(t *testing.T) {
- // TODO
-}
-
-func TestBotDeleteFromBackupStorage(t *testing.T) {
- // TODO
-}
-
-func generateMockedSnapshots(length int) models.Snapshots {
- var chain models.Snapshots
- for i := 0; i < length; i++ {
- snap := models.NewSnapShot("vol-id-test")
- snap.ID = fmt.Sprintf("id-%d", i)
- chain = append(chain, snap)
- }
- return chain
-}
diff --git a/internal/virt/snapshot/mocks/Bot.go b/internal/virt/snapshot/mocks/Bot.go
deleted file mode 100644
index 0cabd07..0000000
--- a/internal/virt/snapshot/mocks/Bot.go
+++ /dev/null
@@ -1,125 +0,0 @@
-// Code generated by mockery v0.0.0-dev. DO NOT EDIT.
-
-package mocks
-
-import (
- models "github.com/projecteru2/yavirt/internal/models"
- mock "github.com/stretchr/testify/mock"
-)
-
-// Bot is an autogenerated mock type for the Bot type
-type Bot struct {
- mock.Mock
-}
-
-// Close provides a mock function with given fields:
-func (_m *Bot) Close() error {
- ret := _m.Called()
-
- var r0 error
- if rf, ok := ret.Get(0).(func() error); ok {
- r0 = rf()
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// Commit provides a mock function with given fields: _a0
-func (_m *Bot) Commit(_a0 models.Snapshots) error {
- ret := _m.Called(_a0)
-
- var r0 error
- if rf, ok := ret.Get(0).(func(models.Snapshots) error); ok {
- r0 = rf(_a0)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// Create provides a mock function with given fields: vol
-func (_m *Bot) Create(vol *models.Volume) error {
- ret := _m.Called(vol)
-
- var r0 error
- if rf, ok := ret.Get(0).(func(*models.Volume) error); ok {
- r0 = rf(vol)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// Delete provides a mock function with given fields:
-func (_m *Bot) Delete() error {
- ret := _m.Called()
-
- var r0 error
- if rf, ok := ret.Get(0).(func() error); ok {
- r0 = rf()
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// DeleteFromBackupStorage provides a mock function with given fields:
-func (_m *Bot) DeleteFromBackupStorage() error {
- ret := _m.Called()
-
- var r0 error
- if rf, ok := ret.Get(0).(func() error); ok {
- r0 = rf()
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// Download provides a mock function with given fields: _a0
-func (_m *Bot) Download(_a0 *models.Snapshot) error {
- ret := _m.Called(_a0)
-
- var r0 error
- if rf, ok := ret.Get(0).(func(*models.Snapshot) error); ok {
- r0 = rf(_a0)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// Restore provides a mock function with given fields: vol, chain
-func (_m *Bot) Restore(vol *models.Volume, chain models.Snapshots) error {
- ret := _m.Called(vol, chain)
-
- var r0 error
- if rf, ok := ret.Get(0).(func(*models.Volume, models.Snapshots) error); ok {
- r0 = rf(vol, chain)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// Upload provides a mock function with given fields: force
-func (_m *Bot) Upload(force bool) error {
- ret := _m.Called(force)
-
- var r0 error
- if rf, ok := ret.Get(0).(func(bool) error); ok {
- r0 = rf(force)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
diff --git a/internal/virt/snapshot/snapshot.go b/internal/virt/snapshot/snapshot.go
deleted file mode 100644
index 0ac7959..0000000
--- a/internal/virt/snapshot/snapshot.go
+++ /dev/null
@@ -1,193 +0,0 @@
-package snapshot
-
-import (
- "github.com/projecteru2/yavirt/internal/models"
- "github.com/projecteru2/yavirt/pkg/errors"
-)
-
-// Interface .
-type Interface interface {
- Create(vol *models.Volume) error
- Commit(snaps models.Snapshots) (models.Snapshots, error)
- Delete() error
- Restore(vol *models.Volume, snaps models.Snapshots) error
- Upload(force bool) error
- Download(*models.Snapshot) error
-}
-
-// Snapshot .
-type Snapshot struct {
- *models.Snapshot
- newBot func(*Snapshot) (Bot, error)
-}
-
-// New .
-func New(mod *models.Snapshot) *Snapshot {
- return &Snapshot{
- Snapshot: mod,
- newBot: newVirtSnap,
- }
-}
-
-// Delete meta and file in backup storage
-func (snap *Snapshot) Delete() error {
-
- if err := snap.botOperate(func(bot Bot) error {
- return bot.DeleteFromBackupStorage()
- }); err != nil {
- return errors.Trace(err)
- }
-
- if err := snap.botOperate(func(bot Bot) error {
- return bot.Delete()
- }); err != nil {
- return errors.Trace(err)
- }
-
- if err := snap.Model().Delete(); err != nil {
- return errors.Trace(err)
- }
- return nil
-}
-
-// Create external snapshot and return a list of Volume model represent volume that newly in use.
-func (snap *Snapshot) Create(vol *models.Volume) error {
- if err := snap.botOperate(func(bot Bot) error {
- return bot.Create(vol)
- }); err != nil {
- return errors.Trace(err)
- }
-
- return snap.Upload(false)
-}
-
-// Commit current snapshot and snapshots before current snapshot to the root
-// Root(Full snapshot) -> Snap1 -> Snap2 -> Snap3 -> Vol in-use
-// After Snap2.Commit()
-// NewRoot(Full snapshot with name same as Snap 2) -> Snap3 -> Vol in-use
-// Return list of snapshot meta that needed to be removed
-func (snap *Snapshot) Commit(snaps models.Snapshots) (models.Snapshots, error) {
- chain, err := snap.getChain(snaps)
- if err != nil {
- return nil, errors.Trace(err)
- }
-
- if err = snap.downloadSnapshots(chain); err != nil {
- return nil, errors.Trace(err)
- }
-
- if err = snap.botOperate(func(bot Bot) error {
- return bot.Commit(chain)
- }); err != nil {
- return nil, errors.Trace(err)
- }
-
- if err = snap.Upload(true); err != nil {
- return nil, errors.Trace(err)
- }
-
- return chain[1:], nil
-}
-
-// Restore .
-func (snap *Snapshot) Restore(vol *models.Volume, snaps models.Snapshots) error {
- chain, err := snap.getChain(snaps)
- if err != nil {
- return errors.Trace(err)
- }
-
- if err := snap.downloadSnapshots(chain); err != nil {
- return errors.Trace(err)
- }
-
- if err := snap.botOperate(func(bot Bot) error {
- return bot.Restore(vol, chain)
- }); err != nil {
- return errors.Trace(err)
- }
-
- return nil
-}
-
-// Upload .
-func (snap *Snapshot) Upload(force bool) error {
- if err := snap.botOperate(func(bot Bot) error {
- return bot.Upload(force)
- }); err != nil {
- return errors.Trace(err)
- }
-
- return nil
-}
-
-// Download .
-func (snap *Snapshot) Download(snapmod *models.Snapshot) error {
- if err := snap.botOperate(func(bot Bot) error {
- return bot.Download(snapmod)
- }); err != nil {
- return errors.Trace(err)
- }
-
- return nil
-}
-
-// // check whether the snapshot is the last snapshot on the chain
-// // (not exist other snapshot use this snapshot as backing file)
-// func (snap *Snapshot) checkSnapshotIsLatest(snaps models.Snapshots) bool {
-// isLatest := true
-// for _, s := range snaps {
-// if s.BaseSnapshotID == snap.ID {
-// isLatest = false
-// }
-// }
-// return isLatest
-// }
-
-// calculate the whole chain
-func (snap *Snapshot) getChain(snaps models.Snapshots) (models.Snapshots, error) {
-
- if _, err := snaps.Find(snap.ID); err != nil {
- return nil, errors.Trace(err)
- }
-
- snapIDMap := make(map[string]*models.Snapshot)
- for _, s := range snaps {
- snapIDMap[s.ID] = s
- }
-
- var chain models.Snapshots
- chain = append(chain, snap.Model())
- currentID := snap.BaseSnapshotID
- for len(currentID) > 0 {
- chain = append(chain, snapIDMap[currentID])
- currentID = snapIDMap[currentID].BaseSnapshotID
- }
-
- return chain, nil
-}
-
-// download list of snapshot files
-func (snap *Snapshot) downloadSnapshots(snaps models.Snapshots) error {
- for _, s := range snaps {
- if err := snap.Download(s); err != nil {
- return err
- }
- }
- return nil
-}
-
-// Model .
-func (snap *Snapshot) Model() *models.Snapshot {
- return snap.Snapshot
-}
-
-func (snap *Snapshot) botOperate(fn func(Bot) error) error {
- bot, err := snap.newBot(snap)
- if err != nil {
- return errors.Trace(err)
- }
-
- defer bot.Close()
-
- return fn(bot)
-}
diff --git a/internal/virt/snapshot/snapshot_test.go b/internal/virt/snapshot/snapshot_test.go
deleted file mode 100644
index 4a5f386..0000000
--- a/internal/virt/snapshot/snapshot_test.go
+++ /dev/null
@@ -1,99 +0,0 @@
-package snapshot
-
-import (
- "testing"
-
- "github.com/projecteru2/yavirt/internal/models"
- snapmock "github.com/projecteru2/yavirt/internal/virt/snapshot/mocks"
- "github.com/projecteru2/yavirt/pkg/test/assert"
- "github.com/projecteru2/yavirt/pkg/test/mock"
-)
-
-func TestCreate(t *testing.T) {
- snapmod := models.NewSnapShot("vol-id-123")
-
- sbot := &snapmock.Bot{}
- sbot.On("Create", mock.Anything).Return(nil).Once()
- sbot.On("Close").Return(nil).Twice()
- sbot.On("Upload", mock.Anything).Return(nil).Once()
-
- snap := &Snapshot{
- Snapshot: snapmod,
- newBot: func(v *Snapshot) (Bot, error) { return sbot, nil },
- }
-
- err := snap.Create(models.NewVolume("vol-id-123", 1))
- assert.NilErr(t, err)
-}
-
-func TestCommit(t *testing.T) {
- snapmod := models.NewSnapShot("vol-id")
- snapmod.ID = "id-8"
- snapmod.BaseSnapshotID = "id-4"
-
- sbot := &snapmock.Bot{}
- sbot.On("Commit", mock.Anything).Return(nil).Once()
- sbot.On("Close").Return(nil).Times(10 + 2)
- sbot.On("Download", mock.Anything).Return(nil).Times(10)
- sbot.On("Upload", mock.Anything).Return(nil).Once()
-
- snap := &Snapshot{
- Snapshot: snapmod,
- newBot: func(v *Snapshot) (Bot, error) { return sbot, nil },
- }
-
- snaps := generateMockedSnapshots(10)
- snaps[8].BaseSnapshotID = "id-4"
- snaps[4].BaseSnapshotID = "id-2"
- snaps[2].BaseSnapshotID = "id-1"
-
- ret, err := snap.Commit(snaps)
- assert.NilErr(t, err)
- assert.Equal(t, ret.Len(), 3)
- assert.Equal(t, ret[0], snaps[4])
- assert.Equal(t, ret[1], snaps[2])
- assert.Equal(t, ret[2], snaps[1])
-}
-
-func TestCommitRoot(t *testing.T) {
- snapmod := models.NewSnapShot("vol-id-123")
- snapmod.ID = "id-8"
-
- sbot := &snapmock.Bot{}
- sbot.On("Commit", mock.Anything).Return(nil).Once()
- sbot.On("Close").Return(nil).Times(10 + 2)
- sbot.On("Download", mock.Anything).Return(nil).Times(10)
- sbot.On("Upload", mock.Anything).Return(nil).Once()
-
- snap := &Snapshot{
- Snapshot: snapmod,
- newBot: func(v *Snapshot) (Bot, error) { return sbot, nil },
- }
-
- snaps := generateMockedSnapshots(10)
-
- ret, err := snap.Commit(snaps)
- assert.NilErr(t, err)
- assert.Equal(t, ret.Len(), 0)
-}
-
-func TestRestore(t *testing.T) {
- snapmod := models.NewSnapShot("vol-id-123")
- snapmod.ID = "id-123"
-
- sbot := &snapmock.Bot{}
- sbot.On("Close").Return(nil).Times(10 + 1)
- sbot.On("Download", mock.Anything).Return(nil).Times(10)
- sbot.On("Restore", mock.Anything, mock.Anything).Return(nil).Once()
-
- snap := &Snapshot{
- Snapshot: snapmod,
- newBot: func(v *Snapshot) (Bot, error) { return sbot, nil },
- }
-
- snaps := generateMockedSnapshots(3)
- snaps[0].ID = "id-123"
-
- err := snap.Restore(models.NewVolume("vol-id-123", 1), snaps)
- assert.NilErr(t, err)
-}
diff --git a/internal/virt/template/disk.xml b/internal/virt/template/disk.xml
deleted file mode 100644
index 735eee3..0000000
--- a/internal/virt/template/disk.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/internal/virt/template/template.go b/internal/virt/template/template.go
index def1a6a..ece0d05 100644
--- a/internal/virt/template/template.go
+++ b/internal/virt/template/template.go
@@ -2,24 +2,27 @@ package template
import (
"bytes"
+ "fmt"
+ "io"
+ "os"
"strings"
"sync"
text "text/template"
- "github.com/projecteru2/yavirt/pkg/errors"
- "github.com/projecteru2/yavirt/pkg/utils"
+ "github.com/Masterminds/sprig/v3"
+ "github.com/cockroachdb/errors"
)
// Render .
-func Render(filepath string, args any) ([]byte, error) {
- var tmpl, err = templates.get(filepath)
+func Render(filepath string, defaultTemplStr string, args any) ([]byte, error) {
+ var tmpl, err = templates.get(filepath, defaultTemplStr)
if err != nil {
- return nil, errors.Annotatef(err, "get template %s failed", filepath)
+ return nil, errors.Wrapf(err, "get template %s failed", filepath)
}
var wr bytes.Buffer
if err := tmpl.Execute(&wr, args); err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
return wr.Bytes(), nil
@@ -32,15 +35,15 @@ type Templates struct {
sync.Map
}
-func (t *Templates) get(fpth string) (tmpl *text.Template, err error) {
+func (t *Templates) get(fpth string, defaultTemplStr string) (tmpl *text.Template, err error) {
var val, ok = t.Load(fpth)
if ok {
return val.(*text.Template), nil
}
- tmpl, err = t.parse(fpth)
+ tmpl, err = t.parse(fpth, defaultTemplStr)
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
t.Store(fpth, tmpl)
@@ -48,17 +51,27 @@ func (t *Templates) get(fpth string) (tmpl *text.Template, err error) {
return tmpl, nil
}
-func (t *Templates) parse(fpth string) (*text.Template, error) {
+func (t *Templates) parse(fpth string, defaultTemplStr string) (*text.Template, error) {
if !t.isTempl(fpth) {
return nil, errors.Errorf("%s is not a template file", fpth)
}
-
- buf, err := utils.ReadAll(fpth)
+ f, err := os.Open(fpth)
+ // if file path doesn't exist, then use default template string
+ if err != nil && os.IsNotExist(err) {
+ if defaultTemplStr == "" {
+ return nil, fmt.Errorf("Can't render %s: file doesn't exist and defaut template string is empty", fpth)
+ }
+ return text.New(fpth).Funcs(sprig.TxtFuncMap()).Parse(defaultTemplStr)
+ }
if err != nil {
- return nil, errors.Trace(err)
+ return nil, err
}
- return text.New(fpth).Parse(string(buf))
+ buf, err := io.ReadAll(f)
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ return text.New(fpth).Funcs(sprig.TxtFuncMap()).Parse(string(buf))
}
func (t *Templates) isTempl(fpth string) bool {
diff --git a/internal/virt/types/console.go b/internal/virt/types/console.go
deleted file mode 100644
index 36db709..0000000
--- a/internal/virt/types/console.go
+++ /dev/null
@@ -1,103 +0,0 @@
-package types
-
-import (
- "context"
- "io"
- "sync"
-
- "github.com/projecteru2/yavirt/pkg/libvirt"
- "github.com/projecteru2/yavirt/pkg/log"
-)
-
-type Console interface {
- io.ReadWriteCloser
- Fd() int // need fd for epoll event
-}
-
-// OpenConsoleFlags .
-type OpenConsoleFlags struct {
- Safe bool
- Force bool
- Commands []string
-}
-
-// NewOpenConsoleFlags .
-func NewOpenConsoleFlags(force, safe bool) OpenConsoleFlags {
- return OpenConsoleFlags{
- Force: force,
- Safe: safe,
- }
-}
-
-// AsLibvirtConsoleFlags .
-func (f *OpenConsoleFlags) AsLibvirtConsoleFlags() (flags libvirt.DomainConsoleFlags) {
- if f.Force {
- flags |= libvirt.DomainConsoleForce
- }
- if f.Safe {
- flags |= libvirt.DomainConsoleSafe
- }
- return
-}
-
-// ConsoleState .
-type ConsoleState struct {
- *sync.Cond
- opened bool
-}
-
-func newConsoleState() *ConsoleState {
- return &ConsoleState{
- Cond: sync.NewCond(&sync.Mutex{}),
- }
-}
-
-type consoleStateManager struct {
- sync.Map
-}
-
-func (m *consoleStateManager) WaitUntilConsoleOpen(_ context.Context, id string) {
- v, _ := m.LoadOrStore(id, newConsoleState())
- consoleState, ok := v.(*ConsoleState)
- if !ok {
- log.Errorf("[ConsoleStateManager] wrong type in map")
- return
- }
-
- consoleState.L.Lock()
- defer consoleState.L.Unlock()
- for !consoleState.opened {
- consoleState.Wait()
- }
-}
-
-func (m *consoleStateManager) MarkConsoleOpen(_ context.Context, id string) {
- v, _ := m.LoadOrStore(id, newConsoleState())
- consoleState, ok := v.(*ConsoleState)
- if !ok {
- log.Errorf("[ConsoleStateManager] wrong type in map")
- return
- }
-
- consoleState.L.Lock()
- defer consoleState.L.Unlock()
- consoleState.opened = true
- consoleState.Broadcast()
-}
-
-func (m *consoleStateManager) MarkConsoleClose(_ context.Context, id string) {
- v, _ := m.LoadOrStore(id, newConsoleState())
- consoleState, ok := v.(*ConsoleState)
- if !ok {
- log.Errorf("[ConsoleStateManager] wrong type in map")
- return
- }
-
- consoleState.L.Lock()
- defer consoleState.L.Unlock()
- consoleState.opened = false
- consoleState.Broadcast()
-}
-
-// ConsoleStateManager .
-var ConsoleStateManager consoleStateManager
diff --git a/internal/virt/types/event.go b/internal/virt/types/event.go
deleted file mode 100644
index e48ce67..0000000
--- a/internal/virt/types/event.go
+++ /dev/null
@@ -1,10 +0,0 @@
-package types
-
-import "time"
-
-type Event struct {
- ID string
- Type string
- Action string
- Time time.Time
-}
diff --git a/internal/virt/utils/sh.go b/internal/virt/utils/sh.go
deleted file mode 100644
index 55f35c7..0000000
--- a/internal/virt/utils/sh.go
+++ /dev/null
@@ -1,45 +0,0 @@
-package utils
-
-import (
- "context"
- "fmt"
- "strconv"
-
- "github.com/projecteru2/yavirt/pkg/sh"
-)
-
-// CreateImage .
-func CreateImage(ctx context.Context, fmt, path string, cap int64) error {
- return sh.ExecContext(ctx, "qemu-img", "create", "-q", "-f", fmt, path, strconv.FormatInt(cap, 10))
-}
-
-// AmplifyImage .
-func AmplifyImage(ctx context.Context, path string, delta int64) error {
- flag := fmt.Sprintf("%+d", delta)
- return sh.ExecContext(ctx, "qemu-img", "resize", path, flag)
-}
-
-// CommitImage .
-func CommitImage(ctx context.Context, path string) error {
- return sh.ExecContext(ctx, "qemu-img", "commit", path)
-}
-
-// CreateSnapshot .
-func CreateSnapshot(ctx context.Context, volPath string, newVolPath string) error {
- return sh.ExecContext(ctx, "qemu-img", "create", "-f", "qcow2", "-F", "qcow2", newVolPath, "-b", volPath)
-}
-
-// RebaseImage .
-func RebaseImage(ctx context.Context, volPath string, backingVolPath string) error {
- return sh.ExecContext(ctx, "qemu-img", "rebase", "-b", backingVolPath, volPath)
-}
-
-// Check .
-func Check(ctx context.Context, volPath string) error {
- return sh.ExecContext(ctx, "qemu-img", "check", volPath)
-}
-
-// Repair .
-func Repair(ctx context.Context, volPath string) error {
- return sh.ExecContext(ctx, "qemu-img", "check", "-r", "all", volPath)
-}
diff --git a/internal/virt/virt.go b/internal/virt/virt.go
index 7dd2e91..e21e88c 100644
--- a/internal/virt/virt.go
+++ b/internal/virt/virt.go
@@ -4,15 +4,15 @@ import (
"os"
"path/filepath"
+ "github.com/cockroachdb/errors"
"github.com/projecteru2/yavirt/configs"
- "github.com/projecteru2/yavirt/pkg/errors"
)
// Cleanup cleans flocks up.
func Cleanup() error {
files, err := os.ReadDir(configs.Conf.VirtFlockDir)
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
for _, f := range files {
@@ -20,7 +20,7 @@ func Cleanup() error {
continue
}
if err := os.Remove(filepath.Join(configs.Conf.VirtFlockDir, f.Name())); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
}
diff --git a/internal/virt/volume/bot.go b/internal/virt/volume/bot.go
deleted file mode 100644
index c7f3b3b..0000000
--- a/internal/virt/volume/bot.go
+++ /dev/null
@@ -1,590 +0,0 @@
-package volume
-
-import (
- "bytes"
- "context"
- "fmt"
- "path/filepath"
- "regexp"
- "strings"
-
- "github.com/projecteru2/yavirt/configs"
- "github.com/projecteru2/yavirt/internal/models"
- "github.com/projecteru2/yavirt/internal/virt/agent"
- "github.com/projecteru2/yavirt/internal/virt/domain"
- "github.com/projecteru2/yavirt/internal/virt/guestfs"
- "github.com/projecteru2/yavirt/internal/virt/guestfs/gfsx"
- gfsmocks "github.com/projecteru2/yavirt/internal/virt/guestfs/mocks"
- "github.com/projecteru2/yavirt/internal/virt/nic"
- "github.com/projecteru2/yavirt/internal/virt/snapshot"
- "github.com/projecteru2/yavirt/internal/virt/types"
- virtutils "github.com/projecteru2/yavirt/internal/virt/utils"
- "github.com/projecteru2/yavirt/pkg/errors"
- "github.com/projecteru2/yavirt/pkg/libvirt"
- "github.com/projecteru2/yavirt/pkg/log"
- "github.com/projecteru2/yavirt/pkg/sh"
- "github.com/projecteru2/yavirt/pkg/utils"
-)
-
-const (
- fs = "ext4"
- // Disable backing up of the device/partition
- backupDump = 0
- // Enable fsck checking the device/partition for errors at boot time.
- fsckPass = 2
-)
-
-// Bot .
-type Bot interface { //nolint
- Close() error
- Undefine() error
- Alloc() error
- AllocFromImage(models.Image) error
- Mount(ga agent.Interface, devPath string) error
- Amplify(delta int64, dom domain.Domain, ga agent.Interface, devPath string) error
- ConvertUserImage(user, name string) (*models.UserImage, error)
- Check() error
- Repair() error
- CreateSnapshot(*models.Snapshot) error
- CommitSnapshot(*models.Snapshot) error
- RestoreSnapshot(*models.Snapshot) error
- DeleteSnapshot(*models.Snapshot) error
- DeleteAllSnapshots() error
-}
-
-type bot struct {
- vol *Volume
- flock *utils.Flock
- newGuestfs func(string) (guestfs.Guestfs, error)
- newSnapshot func(*models.Snapshot) snapshot.Interface
-}
-
-func newVirtVol(vol *Volume) (Bot, error) {
- var virt = &bot{
- vol: vol,
- newGuestfs: gfsx.New,
- newSnapshot: newSnapshot,
- }
- virt.flock = virt.newFlock()
-
- if err := virt.flock.Trylock(); err != nil {
- return nil, errors.Trace(err)
- }
-
- return virt, nil
-}
-
-func newSnapshot(snapmod *models.Snapshot) snapshot.Interface {
- return snapshot.New(snapmod)
-}
-
-func (v *bot) Undefine() error {
- return sh.Remove(v.vol.Filepath())
-}
-
-func (v *bot) Close() error {
- v.flock.Close()
- return nil
-}
-
-func (v *bot) DeleteAllSnapshots() error {
- for i := v.vol.Snaps.Len() - 1; i >= 0; i-- {
- if err := v.DeleteSnapshot(v.vol.Snaps[i]); err != nil {
- return errors.Trace(err)
- }
- }
-
- return nil
-}
-
-func (v *bot) DeleteSnapshot(snapmod *models.Snapshot) error {
- fmt.Println("Destroying snap " + snapmod.ID)
- v.vol.RemoveSnap(snapmod.ID)
- if err := v.newSnapshot(snapmod).Delete(); err != nil {
- return errors.Trace(err)
- }
- return nil
-}
-
-func (v *bot) CreateSnapshot(snapmod *models.Snapshot) error {
- snap := v.newSnapshot(snapmod)
- if err := snap.Create(v.vol.Model()); err != nil {
- return err
- }
-
- snapmod.BaseSnapshotID = v.vol.BaseSnapshotID
- v.vol.BaseSnapshotID = snapmod.ID
-
- return snapmod.Create()
-}
-
-func (v *bot) CommitSnapshot(snapmod *models.Snapshot) error {
- snap := v.newSnapshot(snapmod)
- snapsToRemoved, err := snap.Commit(v.vol.Snaps)
- if err != nil {
- return errors.Trace(err)
- }
-
- for _, s := range snapsToRemoved {
- if err := v.DeleteSnapshot(s); err != nil {
- return errors.Trace(err)
- }
- }
-
- snapmod.BaseSnapshotID = ""
-
- return snapmod.Save()
-}
-
-func (v *bot) RestoreSnapshot(snapmod *models.Snapshot) error {
- snap := v.newSnapshot(snapmod)
- err := snap.Restore(v.vol.Model(), v.vol.Snaps)
- if err != nil {
- return errors.Trace(err)
- }
-
- v.vol.BaseSnapshotID = snapmod.ID
-
- return nil
-}
-
-func (v *bot) Amplify(delta int64, dom domain.Domain, ga agent.Interface, devPath string) error {
- switch st, err := dom.GetState(); {
- case err != nil:
- return errors.Trace(err)
-
- case st == libvirt.DomainShutoff:
- return virtutils.AmplifyImage(context.Background(), v.vol.Filepath(), delta)
-
- case st == libvirt.DomainRunning:
- return v.amplifyOnline(delta, dom, ga, devPath)
-
- default:
- return types.NewDomainStatesErr(st, libvirt.DomainShutoff, libvirt.DomainRunning)
- }
-}
-
-func (v *bot) amplifyOnline(delta int64, dom domain.Domain, ga agent.Interface, devPath string) error {
- if err := dom.AmplifyVolume(v.vol.Filepath(), uint64(v.vol.Capacity+delta)); err != nil {
- return errors.Trace(err)
- }
-
- ctx, cancel := context.WithTimeout(context.Background(), configs.Conf.GADiskTimeout.Duration())
- defer cancel()
- return v.amplify(ctx, ga, devPath)
-}
-
-func (v *bot) newFlock() *utils.Flock {
- var fn = fmt.Sprintf("%s.flock", v.vol.Name())
- var fpth = filepath.Join(configs.Conf.VirtFlockDir, fn)
- return utils.NewFlock(fpth)
-}
-
-func (v *bot) Mount(ga agent.Interface, devPath string) error {
- var ctx, cancel = context.WithTimeout(context.Background(), configs.Conf.GADiskTimeout.Duration())
- defer cancel()
-
- if err := v.format(ctx, ga, devPath); err != nil {
- return errors.Trace(err)
- }
-
- if err := v.mount(ctx, ga, devPath); err != nil {
- return errors.Trace(err)
- }
-
- if err := v.saveFstab(ctx, ga, devPath); err != nil {
- return errors.Trace(err)
- }
-
- switch amplified, err := v.isAmplifying(ctx, ga, devPath); {
- case err != nil:
- return errors.Trace(err)
-
- case amplified:
- return v.amplify(ctx, ga, devPath)
-
- default:
- return nil
- }
-}
-
-func (v *bot) isAmplifying(ctx context.Context, ga agent.Interface, devPath string) (bool, error) {
- mbs, err := v.getMountedBlocks(ctx, ga)
- if err != nil {
- return false, errors.Trace(err)
- }
-
- cap, err := agent.NewParted(ga, devPath).GetSize(ctx) //nolint
- if err != nil {
- return false, errors.Trace(err)
- }
-
- mbs = int64(float64(mbs) * (1 + configs.Conf.ResizeVolumeMinRatio))
- cap >>= 10 //nolint // in bytes, aka. 1K-blocks.
-
- return cap > mbs, nil
-}
-
-func (v *bot) getMountedBlocks(ctx context.Context, ga agent.Interface) (int64, error) {
- df, err := ga.GetDiskfree(ctx, v.vol.MountDir)
- if err != nil {
- return 0, errors.Trace(err)
- }
- return df.Blocks, nil
-}
-
-func (v *bot) amplify(ctx context.Context, ga agent.Interface, devPath string) error {
- // NOTICE:
- // Actually, volume raw devices aren't necessary for re-parting.
-
- stoppedServices, err := v.stopSystemdServices(ctx, ga, devPath)
- if err != nil {
- return errors.Trace(err)
- }
-
- cmds := [][]string{
- {"umount", v.vol.MountDir},
- {"partprobe"},
- {"e2fsck", "-fy", devPath},
- {"resize2fs", devPath},
- {"mount", "-a"},
- }
-
- if err := v.execCommands(ctx, ga, cmds); err != nil {
- return errors.Trace(err)
- }
-
- if err := v.restartSystemdServices(ctx, ga, stoppedServices); err != nil {
- return errors.Trace(err)
- }
-
- return nil
-}
-
-func (v *bot) saveFstab(ctx context.Context, ga agent.Interface, devPath string) error {
- var blkid, err = ga.Blkid(ctx, devPath)
- if err != nil {
- return errors.Trace(err)
- }
-
- switch exists, err := ga.Grep(ctx, blkid, types.FstabFile); {
- case err != nil:
- return errors.Trace(err)
- case exists:
- return nil
- }
-
- var line = fmt.Sprintf("\nUUID=%s %s %s defaults %d %d",
- blkid, v.vol.MountDir, fs, backupDump, fsckPass)
-
- return ga.AppendLine(types.FstabFile, []byte(line))
-}
-
-func (v *bot) mount(ctx context.Context, ga agent.Interface, devPath string) error {
- var mnt = v.vol.MountDir
- var st = <-ga.Exec(ctx, "mkdir", "-p", mnt)
- if err := st.Error(); err != nil {
- return errors.Annotatef(err, "mkdir %s failed", mnt)
- }
-
- st = <-ga.ExecOutput(ctx, "mount", "-t", fs, devPath, mnt)
- _, _, err := st.CheckStdio(func(_, se []byte) bool {
- return bytes.Contains(se, []byte("already mounted"))
- })
- return errors.Annotatef(err, "mount %s failed", mnt)
-}
-
-func (v *bot) format(ctx context.Context, ga agent.Interface, devPath string) error {
- switch formatted, err := v.isFormatted(ctx, ga); {
- case err != nil:
- return errors.Trace(err)
- case formatted:
- return nil
- }
-
- if err := v.fdisk(ctx, ga, devPath); err != nil {
- return errors.Trace(err)
- }
-
- return ga.Touch(ctx, v.formattedFlagPath())
-}
-
-func (v *bot) fdisk(ctx context.Context, ga agent.Interface, devPath string) error {
- var cmds = [][]string{
- {"parted", "-s", devPath, "mklabel", "gpt"},
- {"parted", "-s", devPath, "mkpart", "primary", "1049K", "--", "-1"},
- {"mkfs", "-F", "-t", fs, devPath},
- }
- return v.execCommands(ctx, ga, cmds)
-}
-
-func (v *bot) isFormatted(ctx context.Context, ga agent.Interface) (bool, error) {
- return ga.IsFile(ctx, v.formattedFlagPath())
-}
-
-func (v *bot) formattedFlagPath() string {
- return fmt.Sprintf("/etc/%s", v.vol.Name())
-}
-
-func (v *bot) execCommands(ctx context.Context, ga agent.Interface, cmds [][]string) error {
- for _, args := range cmds {
- var st = <-ga.ExecOutput(ctx, args[0], args[1:]...)
- if err := st.Error(); err != nil {
- return errors.Annotatef(err, "%v", args)
- }
- }
- return nil
-}
-
-func (v *bot) Alloc() error {
- var path = v.vol.Filepath()
- return virtutils.CreateImage(context.Background(), models.VolQcow2Format, path, v.vol.Capacity)
-}
-
-func (v *bot) AllocFromImage(img models.Image) error {
- if err := sh.Copy(img.Filepath(), v.vol.Filepath()); err != nil {
- return errors.Trace(err)
- }
-
- // Removes the image file form localhost if it's a user image.
- if img.GetType() == models.ImageUser {
- if err := sh.Remove(img.Filepath()); err != nil {
- // Prints the error message but it doesn't break the func.
- log.WarnStack(err)
- }
- }
-
- return nil
-}
-
-func (v *bot) ConvertUserImage(user, name string) (uimg *models.UserImage, err error) {
- uimg = models.NewUserImage(user, name, v.vol.Capacity)
- uimg.Distro = types.Unknown
-
- orig := uimg.Filepath()
- if err := sh.Copy(v.vol.Filepath(), orig); err != nil {
- return nil, errors.Trace(err)
- }
- defer func() {
- if err != nil {
- if re := sh.Remove(orig); re != nil {
- err = errors.Wrap(err, re)
- }
- }
- }()
-
- var gfs guestfs.Guestfs
- if gfs, err = v.newGuestfs(orig); err != nil {
- return nil, errors.Trace(err)
- }
- defer gfs.Close()
-
- if uimg.Distro, err = gfs.Distro(); err != nil {
- return nil, errors.Trace(err)
- }
-
- if err = v.resetUserImage(gfs, uimg.Distro); err != nil {
- return nil, errors.Trace(err)
- }
-
- if err := uimg.NextVersion(); err != nil {
- return nil, errors.Trace(err)
- }
-
- if err = sh.Move(orig, uimg.Filepath()); err != nil {
- return nil, errors.Trace(err)
- }
-
- if err = v.cleanObsoleteUserImages(uimg); err != nil {
- return nil, errors.Trace(err)
- }
-
- return uimg, nil
-}
-
-// Check .
-func (v *bot) Check() error {
- return virtutils.Check(context.Background(), v.vol.Filepath())
-}
-
-// Repair .
-func (v *bot) Repair() error {
- return virtutils.Repair(context.Background(), v.vol.Filepath())
-}
-
-func (v *bot) cleanObsoleteUserImages(_ *models.UserImage) error {
- // TODO
- return nil
-}
-
-func (v *bot) resetUserImage(gfs guestfs.Guestfs, distro string) error {
- if err := v.resetFstab(gfs); err != nil {
- return errors.Trace(err)
- }
-
- return v.resetEth0(gfs, distro)
-}
-
-func (v *bot) resetFstab(gfs guestfs.Guestfs) error {
- origFstabEntries, err := gfs.GetFstabEntries()
- if err != nil {
- return errors.Trace(err)
- }
-
- blkids, err := gfs.GetBlkids()
- if err != nil {
- return errors.Trace(err)
- }
-
- var cont string
- for dev, entry := range origFstabEntries {
- if blkids.Exists(dev) {
- cont += fmt.Sprintf("%s\n", strings.TrimSpace(entry))
- }
- }
-
- return gfs.Write(types.FstabFile, cont)
-}
-
-func (v *bot) resetEth0(gfs guestfs.Guestfs, distro string) error {
- path, err := nic.GetEthFile(distro, "eth0")
- if err != nil {
- return errors.Trace(err)
- }
- return gfs.Remove(path)
-}
-
-func (v *bot) stopSystemdServices(ctx context.Context, ga agent.Interface, devPath string) ([]string, error) {
- var st = <-ga.ExecOutput(ctx, "fuser", "-m", devPath)
- so, se, err := st.Stdio()
- if err != nil && (len(so) > 0 || len(se) > 0) { // Fuser return status code 1 if no process running
- return nil, errors.Annotatef(err, "fuser on %s failed", devPath)
- }
-
- re := regexp.MustCompile(`[0-9]+`)
- pids := re.FindAllString(string(so), -1)
-
- var stoppedServices []string
- for _, pid := range pids {
- switch serviceName, err := v.findService(ctx, ga, pid); {
- case err != nil:
- return nil, errors.Trace(err)
-
- case len(serviceName) > 0:
- if err := v.stopSystemdService(ctx, ga, serviceName); err != nil {
- return nil, errors.Trace(err)
- }
- stoppedServices = append(stoppedServices, serviceName)
-
- default:
- continue
- }
- }
-
- return stoppedServices, nil
-}
-
-func (v *bot) stopSystemdService(ctx context.Context, ga agent.Interface, serviceName string) error {
- var st = <-ga.Exec(ctx, "systemctl", "stop", serviceName)
- if err := st.Error(); err != nil {
- return errors.Annotatef(err, "systemctl stop %s failed", serviceName)
- }
-
- return nil
-}
-
-func (v *bot) restartSystemdServices(ctx context.Context, ga agent.Interface, stoppedServices []string) error {
- for _, serviceName := range stoppedServices {
- var st = <-ga.Exec(ctx, "systemctl", "start", serviceName)
- if err := st.Error(); err != nil {
- return errors.Annotatef(err, "systemctl start %s failed", serviceName)
- }
- }
- return nil
-}
-
-func (v *bot) findService(ctx context.Context, ga agent.Interface, pid string) (string, error) {
- for {
- switch name, se := v.getServiceNameByPid(ctx, ga, pid); {
- case strings.HasPrefix(se, "Failed "): // Doesn't exist systemd unit with this pid
- ppid, err := v.getPpid(ctx, ga, pid)
- if err != nil {
- return "", errors.Trace(err)
- }
- pid = ppid
-
- case len(name) > 0:
- switch valid, err := v.isService(ctx, ga, name); {
- case err != nil:
- return "", errors.Trace(err)
-
- case valid:
- return name, nil
-
- default: // unit with this pid exist but not service type
- return "", nil
- }
-
- default:
- return "", nil
- }
- }
-}
-
-func (v *bot) getPpid(ctx context.Context, ga agent.Interface, pid string) (string, error) {
- var st = <-ga.ExecOutput(ctx, "ps", "--ppid", pid)
- so, _, err := st.Stdio()
- if err != nil {
- return "", errors.Annotatef(err, "find ppid for %s failed", pid)
- }
- if len(so) == 0 {
- return "", errors.Annotatef(err, "ppid for %s is empty", pid)
- }
- return string(so), nil
-}
-
-func (v *bot) getServiceNameByPid(ctx context.Context, ga agent.Interface, pid string) (string, string) {
- var st = <-ga.ExecOutput(ctx, "systemctl", "status", pid)
- so, se, err := st.Stdio()
- if err != nil {
- return "", string(se) // No service with this pid or service is stopped/failed
- }
- soSplit := strings.Fields(string(so))
- if len(soSplit) < 2 || len(soSplit[1]) == 0 {
- return "", ""
- }
- return soSplit[1], string(se)
-}
-
-func (v *bot) isService(ctx context.Context, ga agent.Interface, unitName string) (bool, error) {
- var st = <-ga.ExecOutput(ctx, "systemctl", "list-units", "--all", "-t", "service",
- "--full", "--no-legend", unitName)
-
- so, se, err := st.Stdio()
- if err != nil {
- if len(so) > 0 || len(se) > 0 {
- return false, errors.Annotatef(err, "systemctl check service %s failed", unitName)
- }
- return false, nil // Not found service with name unitName but not considered as error
- }
- soSplit := strings.Fields(string(so))
- if len(soSplit) < 1 {
- return false, errors.Annotatef(err, "systemctl check service %s wrong output", unitName)
- }
-
- return true, nil
-}
-
-// NewMockedVolume for unit test.
-func NewMockedVolume() (Bot, *gfsmocks.Guestfs) {
- gfs := &gfsmocks.Guestfs{}
-
- vol := &bot{
- vol: &Volume{
- Volume: models.NewSysVolume(utils.GB, "unitest-image"),
- },
- newGuestfs: func(string) (guestfs.Guestfs, error) { return gfs, nil },
- }
-
- return vol, gfs
-}
diff --git a/internal/virt/volume/bot_test.go b/internal/virt/volume/bot_test.go
deleted file mode 100644
index fa6cc48..0000000
--- a/internal/virt/volume/bot_test.go
+++ /dev/null
@@ -1,243 +0,0 @@
-package volume
-
-import (
- "context"
- "encoding/base64"
- "path/filepath"
- "testing"
-
- "github.com/projecteru2/yavirt/internal/meta"
- agentmocks "github.com/projecteru2/yavirt/internal/virt/agent/mocks"
- agenttypes "github.com/projecteru2/yavirt/internal/virt/agent/types"
- guestfstypes "github.com/projecteru2/yavirt/internal/virt/guestfs/types"
- "github.com/projecteru2/yavirt/pkg/sh"
- shmocks "github.com/projecteru2/yavirt/pkg/sh/mocks"
- "github.com/projecteru2/yavirt/pkg/test/assert"
- "github.com/projecteru2/yavirt/pkg/test/mock"
-)
-
-func TestResetFstabByUUID(t *testing.T) {
- vol, gfs := NewMockedVolume()
- gfs.On("GetFstabEntries").Return(map[string]string{
- "/dev/sda1": "/dev/sda1 / ext4 defaults 0 1",
- "UUID=a3fe5809-c923-4f00-8a8c-5fe85ad9d1e5": "UUID=a3fe5809-c923-4f00-8a8c-5fe85ad9d1e5 / ext4 defaults 0 1",
- "LABEL=cloudimg-rootfs": "LABEL=cloudimg-rootfs / ext4 defaults 0 1",
- }, nil).Once()
-
- blkids := guestfstypes.Blkids{}
- blkids.Add(&guestfstypes.Blkid{Dev: "/dev/vda1", Label: "a", UUID: "34c4810a-3b02-11ec-a3d8-52540049d2ce"})
- blkids.Add(&guestfstypes.Blkid{Dev: "/dev/vda2", Label: "b", UUID: "a3fe5809-c923-4f00-8a8c-5fe85ad9d1e5"})
- blkids.Add(&guestfstypes.Blkid{Dev: "/dev/vda3", Label: "c", UUID: "581f0760-3b02-11ec-a3d8-52540049d2ce"})
- gfs.On("GetBlkids").Return(blkids, nil).Once()
-
- gfs.On("Write", "/etc/fstab", "UUID=a3fe5809-c923-4f00-8a8c-5fe85ad9d1e5 / ext4 defaults 0 1\n").Return(nil)
- assert.NilErr(t, vol.(*bot).resetFstab(gfs))
-}
-func TestResetFstabByDevname(t *testing.T) {
- vol, gfs := NewMockedVolume()
- gfs.On("GetFstabEntries").Return(map[string]string{
- "/dev/sda1": "/dev/sda1 / ext4 defaults 0 1",
- "UUID=a3fe5809-c923-4f00-8a8c-5fe85ad9d1e5": "UUID=a3fe5809-c923-4f00-8a8c-5fe85ad9d1e5 / ext4 defaults 0 1",
- "LABEL=cloudimg-rootfs": "LABEL=cloudimg-rootfs / ext4 defaults 0 1",
- }, nil).Once()
-
- blkids := guestfstypes.Blkids{}
- blkids.Add(&guestfstypes.Blkid{Dev: "/dev/sda1", Label: "a", UUID: "34c4810a-3b02-11ec-a3d8-52540049d2ce"})
- blkids.Add(&guestfstypes.Blkid{Dev: "/dev/sda2", Label: "b", UUID: "99ad936c-3ba8-11ec-879b-52540049d2ce"})
- blkids.Add(&guestfstypes.Blkid{Dev: "/dev/sda3", Label: "c", UUID: "581f0760-3b02-11ec-a3d8-52540049d2ce"})
- gfs.On("GetBlkids").Return(blkids, nil).Once()
-
- gfs.On("Write", "/etc/fstab", "/dev/sda1 / ext4 defaults 0 1\n").Return(nil)
- assert.NilErr(t, vol.(*bot).resetFstab(gfs))
-}
-
-func TestResetFstabByLabel(t *testing.T) {
- vol, gfs := NewMockedVolume()
- gfs.On("GetFstabEntries").Return(map[string]string{
- "/dev/sda1": "/dev/sda1 / ext4 defaults 0 1",
- "UUID=a3fe5809-c923-4f00-8a8c-5fe85ad9d1e5": "UUID=a3fe5809-c923-4f00-8a8c-5fe85ad9d1e5 / ext4 defaults 0 1",
- "LABEL=c": "LABEL=c / ext4 defaults 0 1",
- }, nil).Once()
-
- blkids := guestfstypes.Blkids{}
- blkids.Add(&guestfstypes.Blkid{Dev: "/dev/vda1", Label: "a", UUID: "34c4810a-3b02-11ec-a3d8-52540049d2ce"})
- blkids.Add(&guestfstypes.Blkid{Dev: "/dev/vda2", Label: "b", UUID: "99ad936c-3ba8-11ec-879b-52540049d2ce"})
- blkids.Add(&guestfstypes.Blkid{Dev: "/dev/vda3", Label: "c", UUID: "581f0760-3b02-11ec-a3d8-52540049d2ce"})
- gfs.On("GetBlkids").Return(blkids, nil).Once()
-
- gfs.On("Write", "/etc/fstab", "LABEL=c / ext4 defaults 0 1\n").Return(nil)
- assert.NilErr(t, vol.(*bot).resetFstab(gfs))
-}
-
-func TestConvertUserImage(t *testing.T) {
- shx := &shmocks.Shell{}
- defer shx.AssertExpectations(t)
- shx.On("Copy", mock.Anything, mock.Anything).Return(nil).Once()
- shx.On("Move", mock.Anything, mock.Anything).Return(nil).Once()
-
- cancel := sh.NewMockShell(shx)
- defer cancel()
-
- vol, gfs := NewMockedVolume()
- gfs.On("Distro").Return("centos", nil).Once()
- gfs.On("GetFstabEntries").Return(map[string]string{"/dev/sda1": "/dev/sda1 / ext4 defaults 0 1"}, nil).Once()
- gfs.On("GetBlkids").Return(guestfstypes.Blkids{}, nil).Once()
- gfs.On("Write", mock.Anything, mock.Anything).Return(nil).Once()
- gfs.On("Remove", mock.Anything).Return(nil).Twice()
- gfs.On("Close").Return(nil).Once()
-
- uimg, err := vol.ConvertUserImage("anrs", "aa")
- assert.NilErr(t, err)
- assert.NotNil(t, uimg)
- assert.Equal(t, "anrs", uimg.User)
- assert.Equal(t, "aa", uimg.Name)
- assert.Equal(t, "centos", uimg.Distro)
- assert.Equal(t, int64(0), uimg.Version)
- assert.Equal(t, "centos-anrs-aa-0.uimg", filepath.Base(uimg.Filepath()))
- assert.Equal(t, vol.(*bot).vol.Capacity, uimg.Size)
-}
-
-func TestStopSystemdServices(t *testing.T) {
- vol, _ := NewMockedVolume()
-
- ctx, cancel := meta.Context(context.Background())
- defer cancel()
-
- outFuser := func() <-chan agenttypes.ExecStatus {
- var done = make(chan agenttypes.ExecStatus, 1)
- var out = agenttypes.ExecStatus{
- Exited: true,
- Code: 0,
- Err: nil,
- Base64Out: base64.StdEncoding.EncodeToString([]byte("/data: 125rw")),
- }
- done <- out
- return done
- }()
-
- outSystemctlStatus125 := func() <-chan agenttypes.ExecStatus {
- var done = make(chan agenttypes.ExecStatus, 1)
- var out = agenttypes.ExecStatus{
- Exited: true,
- Code: 1,
- Base64Err: base64.StdEncoding.EncodeToString([]byte(
- "Failed to get unit for PID 12: PID 12 does not belong to any loaded unit.")),
- }
- done <- out
- return done
- }()
-
- outSystemctlStatus120 := func() <-chan agenttypes.ExecStatus {
- var done = make(chan agenttypes.ExecStatus, 1)
- var out = agenttypes.ExecStatus{
- Exited: true,
- Code: 0,
- Err: nil,
- Base64Out: base64.StdEncoding.EncodeToString([]byte("X yavirt.service - A Service for Yavirt")),
- }
- done <- out
- return done
- }()
-
- outPpid := func() <-chan agenttypes.ExecStatus {
- var done = make(chan agenttypes.ExecStatus, 1)
- var out = agenttypes.ExecStatus{
- Exited: true,
- Code: 0,
- Err: nil,
- Base64Out: base64.StdEncoding.EncodeToString([]byte("120")),
- }
- done <- out
- return done
- }()
-
- outSystemctlStop := func() <-chan agenttypes.ExecStatus {
- var done = make(chan agenttypes.ExecStatus, 1)
- var out = agenttypes.ExecStatus{
- Exited: true,
- Code: 0,
- }
- done <- out
- return done
- }()
-
- outIsServiceYavirt := func() <-chan agenttypes.ExecStatus {
- var done = make(chan agenttypes.ExecStatus, 1)
- var out = agenttypes.ExecStatus{
- Exited: true,
- Code: 0,
- Err: nil,
- Base64Out: base64.StdEncoding.EncodeToString([]byte("yavirt.service loaded active running")),
- }
- done <- out
- return done
- }()
-
- agent := &agentmocks.Interface{}
- defer agent.AssertExpectations(t)
- agent.On("ExecOutput", ctx, "fuser", "-m", "/data").Return(outFuser)
- agent.On("ExecOutput", ctx, "systemctl", "status", "125").Return(outSystemctlStatus125)
- agent.On("ExecOutput", ctx, "ps", "--ppid", "125").Return(outPpid)
- agent.On("ExecOutput", ctx, "systemctl", "status", "120").Return(outSystemctlStatus120)
- agent.On("ExecOutput", ctx, "systemctl", "list-units", "--all", "-t", "service",
- "--full", "--no-legend", "yavirt.service").Return(outIsServiceYavirt)
- agent.On("Exec", ctx, "systemctl", "stop", "yavirt.service").Return(outSystemctlStop)
-
- stoppedServices, err := vol.(*bot).stopSystemdServices(ctx, agent, "/data")
- assert.NilErr(t, err)
- assert.Equal(t, len(stoppedServices), 1)
-}
-
-func TestGetPpid(t *testing.T) {
- vol, _ := NewMockedVolume()
-
- ctx, cancel := meta.Context(context.Background())
- defer cancel()
-
- d := func() <-chan agenttypes.ExecStatus {
- var done = make(chan agenttypes.ExecStatus, 1)
- var out = agenttypes.ExecStatus{
- Exited: true,
- Code: 0,
- Err: nil,
- Base64Out: base64.StdEncoding.EncodeToString([]byte("120")),
- }
- done <- out
- return done
- }()
-
- agent := &agentmocks.Interface{}
- defer agent.AssertExpectations(t)
- agent.On("ExecOutput", ctx, "ps", "--ppid", "123").Return(d)
-
- ppid, err := vol.(*bot).getPpid(ctx, agent, "123")
- assert.NilErr(t, err)
- assert.Equal(t, ppid, "120")
-}
-
-func TestGetServiceNameByPid(t *testing.T) {
- vol, _ := NewMockedVolume()
-
- ctx, cancel := meta.Context(context.Background())
- defer cancel()
-
- d := func() <-chan agenttypes.ExecStatus {
- var done = make(chan agenttypes.ExecStatus, 1)
- var out = agenttypes.ExecStatus{
- Exited: true,
- Code: 0,
- Err: nil,
- Base64Out: base64.StdEncoding.EncodeToString([]byte("@ yavirt.service - A Service for Yavirt")),
- }
- done <- out
- return done
- }()
-
- agent := &agentmocks.Interface{}
- defer agent.AssertExpectations(t)
- agent.On("ExecOutput", ctx, "systemctl", "status", "123").Return(d)
-
- name, se := vol.(*bot).getServiceNameByPid(ctx, agent, "123")
- assert.Equal(t, name, "yavirt.service")
- assert.Equal(t, se, "")
-}
diff --git a/internal/virt/volume/mocks/Bot.go b/internal/virt/volume/mocks/Bot.go
deleted file mode 100644
index b0b7553..0000000
--- a/internal/virt/volume/mocks/Bot.go
+++ /dev/null
@@ -1,240 +0,0 @@
-// Code generated by mockery v2.26.1. DO NOT EDIT.
-
-package mocks
-
-import (
- agent "github.com/projecteru2/yavirt/internal/virt/agent"
- domain "github.com/projecteru2/yavirt/internal/virt/domain"
-
- mock "github.com/stretchr/testify/mock"
-
- models "github.com/projecteru2/yavirt/internal/models"
-)
-
-// Bot is an autogenerated mock type for the Bot type
-type Bot struct {
- mock.Mock
-}
-
-// Alloc provides a mock function with given fields:
-func (_m *Bot) Alloc() error {
- ret := _m.Called()
-
- var r0 error
- if rf, ok := ret.Get(0).(func() error); ok {
- r0 = rf()
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// AllocFromImage provides a mock function with given fields: _a0
-func (_m *Bot) AllocFromImage(_a0 models.Image) error {
- ret := _m.Called(_a0)
-
- var r0 error
- if rf, ok := ret.Get(0).(func(models.Image) error); ok {
- r0 = rf(_a0)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// Amplify provides a mock function with given fields: delta, dom, ga, devPath
-func (_m *Bot) Amplify(delta int64, dom domain.Domain, ga agent.Interface, devPath string) error {
- ret := _m.Called(delta, dom, ga, devPath)
-
- var r0 error
- if rf, ok := ret.Get(0).(func(int64, domain.Domain, agent.Interface, string) error); ok {
- r0 = rf(delta, dom, ga, devPath)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// Check provides a mock function with given fields:
-func (_m *Bot) Check() error {
- ret := _m.Called()
-
- var r0 error
- if rf, ok := ret.Get(0).(func() error); ok {
- r0 = rf()
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// Close provides a mock function with given fields:
-func (_m *Bot) Close() error {
- ret := _m.Called()
-
- var r0 error
- if rf, ok := ret.Get(0).(func() error); ok {
- r0 = rf()
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// CommitSnapshot provides a mock function with given fields: _a0
-func (_m *Bot) CommitSnapshot(_a0 *models.Snapshot) error {
- ret := _m.Called(_a0)
-
- var r0 error
- if rf, ok := ret.Get(0).(func(*models.Snapshot) error); ok {
- r0 = rf(_a0)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// ConvertUserImage provides a mock function with given fields: user, name
-func (_m *Bot) ConvertUserImage(user string, name string) (*models.UserImage, error) {
- ret := _m.Called(user, name)
-
- var r0 *models.UserImage
- var r1 error
- if rf, ok := ret.Get(0).(func(string, string) (*models.UserImage, error)); ok {
- return rf(user, name)
- }
- if rf, ok := ret.Get(0).(func(string, string) *models.UserImage); ok {
- r0 = rf(user, name)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(*models.UserImage)
- }
- }
-
- if rf, ok := ret.Get(1).(func(string, string) error); ok {
- r1 = rf(user, name)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// CreateSnapshot provides a mock function with given fields: _a0
-func (_m *Bot) CreateSnapshot(_a0 *models.Snapshot) error {
- ret := _m.Called(_a0)
-
- var r0 error
- if rf, ok := ret.Get(0).(func(*models.Snapshot) error); ok {
- r0 = rf(_a0)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// DeleteAllSnapshots provides a mock function with given fields:
-func (_m *Bot) DeleteAllSnapshots() error {
- ret := _m.Called()
-
- var r0 error
- if rf, ok := ret.Get(0).(func() error); ok {
- r0 = rf()
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// DeleteSnapshot provides a mock function with given fields: _a0
-func (_m *Bot) DeleteSnapshot(_a0 *models.Snapshot) error {
- ret := _m.Called(_a0)
-
- var r0 error
- if rf, ok := ret.Get(0).(func(*models.Snapshot) error); ok {
- r0 = rf(_a0)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// Mount provides a mock function with given fields: ga, devPath
-func (_m *Bot) Mount(ga agent.Interface, devPath string) error {
- ret := _m.Called(ga, devPath)
-
- var r0 error
- if rf, ok := ret.Get(0).(func(agent.Interface, string) error); ok {
- r0 = rf(ga, devPath)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// Repair provides a mock function with given fields:
-func (_m *Bot) Repair() error {
- ret := _m.Called()
-
- var r0 error
- if rf, ok := ret.Get(0).(func() error); ok {
- r0 = rf()
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// RestoreSnapshot provides a mock function with given fields: _a0
-func (_m *Bot) RestoreSnapshot(_a0 *models.Snapshot) error {
- ret := _m.Called(_a0)
-
- var r0 error
- if rf, ok := ret.Get(0).(func(*models.Snapshot) error); ok {
- r0 = rf(_a0)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// Undefine provides a mock function with given fields:
-func (_m *Bot) Undefine() error {
- ret := _m.Called()
-
- var r0 error
- if rf, ok := ret.Get(0).(func() error); ok {
- r0 = rf()
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-type mockConstructorTestingTNewBot interface {
- mock.TestingT
- Cleanup(func())
-}
-
-// NewBot creates a new instance of Bot. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-func NewBot(t mockConstructorTestingTNewBot) *Bot {
- mock := &Bot{}
- mock.Mock.Test(t)
-
- t.Cleanup(func() { mock.AssertExpectations(t) })
-
- return mock
-}
diff --git a/internal/virt/volume/status.go b/internal/virt/volume/status.go
deleted file mode 100644
index e096829..0000000
--- a/internal/virt/volume/status.go
+++ /dev/null
@@ -1 +0,0 @@
-package volume
diff --git a/internal/virt/volume/volume.go b/internal/virt/volume/volume.go
deleted file mode 100644
index 018d6b2..0000000
--- a/internal/virt/volume/volume.go
+++ /dev/null
@@ -1,299 +0,0 @@
-package volume
-
-import (
- "time"
-
- "github.com/projecteru2/yavirt/configs"
- "github.com/projecteru2/yavirt/internal/models"
- "github.com/projecteru2/yavirt/internal/virt/agent"
- "github.com/projecteru2/yavirt/internal/virt/domain"
- "github.com/projecteru2/yavirt/pkg/errors"
- "github.com/projecteru2/yavirt/pkg/libvirt"
- "github.com/projecteru2/yavirt/pkg/log"
- "github.com/projecteru2/yavirt/pkg/utils"
-)
-
-// Virt .
-type Virt interface { //nolint
- Mount(ga agent.Interface, devPath string) error
- IsSys() bool
- Amplify(cap int64, dom domain.Domain, ga agent.Interface, devPath string) (delta int64, err error)
- Filepath() string
- Model() *models.Volume
- Alloc(models.Image) error
- Undefine() error
- ConvertImage(user, name string) (uimg *models.UserImage, err error)
- Attach(dom domain.Domain, ga agent.Interface, devName string) (rollback func(), err error)
- Check() error
- Repair() error
- CreateSnapshot() error
- CommitSnapshot(snapID string) error
- CommitSnapshotByDay(day int) error
- RestoreSnapshot(snapID string) error
-}
-
-// Volume .
-type Volume struct {
- *models.Volume
- newBot func(*Volume) (Bot, error)
-}
-
-// New .
-func New(mod *models.Volume) *Volume {
- return &Volume{
- Volume: mod,
- newBot: newVirtVol,
- }
-}
-
-// Model .
-func (vol *Volume) Model() *models.Volume {
- return vol.Volume
-}
-
-// Undefine .
-func (vol *Volume) Undefine() error {
- if err := vol.botOperate(func(bot Bot) error {
- return bot.DeleteAllSnapshots()
- }); err != nil {
- return errors.Trace(err)
- }
-
- if err := vol.Model().Save(); err != nil {
- return errors.Trace(err)
- }
-
- return vol.botOperate(func(bot Bot) error {
- return bot.Undefine()
- })
-}
-
-// ConvertImage .
-func (vol *Volume) ConvertImage(user, name string) (uimg *models.UserImage, err error) {
- if !vol.IsSys() {
- return nil, errors.Annotatef(errors.ErrNotSysVolume, vol.ID)
- }
-
- vol.botOperate(func(bot Bot) error { //nolint
- uimg, err = bot.ConvertUserImage(user, name)
- return err
- })
-
- return
-}
-
-// Attach .
-func (vol *Volume) Attach(dom domain.Domain, ga agent.Interface, devName string) (rollback func(), err error) {
- if rollback, err = vol.create(); err != nil {
- return
- }
-
- defer func() {
- if err != nil {
- rollback()
- }
- rollback = nil
- }()
-
- var st libvirt.DomainState
- if st, err = dom.AttachVolume(vol.Filepath(), devName); err == nil && st == libvirt.DomainRunning {
- err = vol.Mount(ga, models.GetDevicePathByName(devName))
- }
-
- return
-}
-
-func (vol *Volume) create() (func(), error) {
- if err := vol.Alloc(nil); err != nil {
- return nil, errors.Trace(err)
- }
-
- if err := vol.Volume.Save(); err != nil {
- if ue := vol.Undefine(); ue != nil {
- err = errors.Wrap(err, ue)
- }
- return nil, errors.Trace(err)
- }
-
- rb := func() {
- if err := vol.Undefine(); err != nil {
- log.ErrorStack(err)
- return
- }
- if err := vol.Delete(true); err != nil {
- log.ErrorStack(err)
- }
- }
-
- return rb, nil
-}
-
-// Alloc .
-func (vol *Volume) Alloc(img models.Image) error {
- return vol.botOperate(func(bot Bot) error {
- switch vol.Type {
- case models.VolSysType:
- if img == nil {
- return errors.Annotatef(errors.ErrInvalidValue, "nil *Image")
- }
- return bot.AllocFromImage(img)
-
- case models.VolDataType:
- return bot.Alloc()
-
- default:
- return errors.Annotatef(errors.ErrInvalidValue, "invalid VolumeType: %s", vol.Type)
- }
- })
-}
-
-// Amplify .
-func (vol *Volume) Amplify(delta int64, dom domain.Domain, ga agent.Interface, devPath string) (normDelta int64, err error) {
- normDelta = utils.NormalizeMultiple1024(delta)
- newCap := vol.Capacity + normDelta
- if newCap > configs.Conf.MaxVolumeCap {
- return 0, errors.Annotatef(errors.ErrInvalidValue, "exceeds the max cap: %d", configs.Conf.MaxVolumeCap)
- }
-
- least := utils.Max(
- configs.Conf.ResizeVolumeMinSize,
- int64(float64(vol.Capacity)*configs.Conf.ResizeVolumeMinRatio),
- )
- if least > normDelta {
- return 0, errors.Annotatef(errors.ErrInvalidValue, "invalid cap: at least %d, but %d",
- vol.Capacity+least, vol.Capacity+normDelta)
- }
-
- if err = vol.botOperate(func(bot Bot) error {
- return bot.Amplify(normDelta, dom, ga, devPath)
- }); err != nil {
- return 0, errors.Trace(err)
- }
-
- err = vol.Volume.Amplify(newCap)
- return
-}
-
-// Check .
-func (vol *Volume) Check() error {
- return vol.botOperate(func(bot Bot) error {
- return bot.Check()
- })
-}
-
-// Repair .
-func (vol *Volume) Repair() error {
- return vol.botOperate(func(bot Bot) error {
- return bot.Repair()
- })
-}
-
-// CreateSnapshot .
-func (vol *Volume) CreateSnapshot() error {
-
- snapmod := models.NewSnapShot(vol.ID)
- snapmod.GenerateID()
-
- if err := vol.botOperate(func(bot Bot) error {
- return bot.CreateSnapshot(snapmod)
- }); err != nil {
- return errors.Trace(err)
- }
-
- if err := vol.AppendSnaps(snapmod); err != nil {
- return errors.Trace(err)
- }
-
- return vol.Save()
-}
-
-// CommitSnapshot .
-func (vol *Volume) CommitSnapshot(snapID string) error {
-
- snap, err := vol.Snaps.Find(snapID)
- if err != nil {
- return errors.Trace(err)
- }
-
- if snap == nil {
- return errors.Annotatef(errors.ErrInvalidValue, "invalid snapID: %s", snapID)
- }
-
- if err := vol.botOperate(func(bot Bot) error {
- return bot.CommitSnapshot(snap)
- }); err != nil {
- return errors.Trace(err)
- }
-
- return vol.Save()
-}
-
-// CommitSnapshotByDay Commit snapshots created `day` days ago.
-func (vol *Volume) CommitSnapshotByDay(day int) error {
-
- date := time.Now().AddDate(0, 0, -day).Unix()
-
- targetIdx := -1
- for i, s := range vol.Snaps {
- if s.CreatedTime > date { // Find the first snapshot that is created later than x days before
- targetIdx = i
- }
- }
-
- // No need to commit if all snapshot created within x days
- if targetIdx == 0 {
- return nil
- }
-
- // If all snapshot create x days before, keep the last one
- if targetIdx == -1 {
- targetIdx = vol.Snaps.Len() - 1
- }
-
- if err := vol.botOperate(func(bot Bot) error {
- return bot.CommitSnapshot(vol.Snaps[targetIdx])
- }); err != nil {
- return errors.Trace(err)
- }
-
- return vol.Save()
-}
-
-// RestoreSnapshot .
-func (vol *Volume) RestoreSnapshot(snapID string) error {
-
- snap, err := vol.Snaps.Find(snapID)
- if err != nil {
- return errors.Trace(err)
- }
-
- if snap == nil {
- return errors.Annotatef(errors.ErrInvalidValue, "invalid snapID: %s", snapID)
- }
-
- if err := vol.botOperate(func(bot Bot) error {
- return bot.RestoreSnapshot(snap)
- }); err != nil {
- return errors.Trace(err)
- }
-
- return vol.Save()
-}
-
-// Mount .
-func (vol *Volume) Mount(ga agent.Interface, devPath string) error {
- return vol.botOperate(func(bot Bot) error {
- return bot.Mount(ga, devPath)
- })
-}
-
-func (vol *Volume) botOperate(fn func(Bot) error) error {
- bot, err := vol.newBot(vol)
- if err != nil {
- return errors.Trace(err)
- }
-
- defer bot.Close()
-
- return fn(bot)
-}
diff --git a/internal/virt/volume/volume_test.go b/internal/virt/volume/volume_test.go
deleted file mode 100644
index 2c5df7a..0000000
--- a/internal/virt/volume/volume_test.go
+++ /dev/null
@@ -1,69 +0,0 @@
-package volume
-
-import (
- "testing"
-
- "github.com/projecteru2/yavirt/configs"
- "github.com/projecteru2/yavirt/internal/models"
- "github.com/projecteru2/yavirt/internal/virt/volume/mocks"
- storemocks "github.com/projecteru2/yavirt/pkg/store/mocks"
- "github.com/projecteru2/yavirt/pkg/test/assert"
- "github.com/projecteru2/yavirt/pkg/test/mock"
- "github.com/projecteru2/yavirt/pkg/utils"
-)
-
-func TestAmplifyFailed_DeltaLessThanMinSize(t *testing.T) {
- volmod, err := models.NewDataVolume("/data", utils.TB)
- assert.NilErr(t, err)
-
- vol := &Volume{Volume: volmod}
-
- cap := vol.Capacity + configs.Conf.ResizeVolumeMinSize - 1
- delta, err := vol.Amplify(cap, nil, nil, "")
- assert.Err(t, err)
- assert.Equal(t, int64(0), delta)
-}
-
-func TestAmplifyFailed_DeltaLessThanMinRatio(t *testing.T) {
- volmod, err := models.NewDataVolume("/data", utils.TB)
- assert.NilErr(t, err)
-
- vol := &Volume{Volume: volmod}
-
- cap := vol.Capacity + int64(float64(vol.Capacity)*configs.Conf.ResizeVolumeMinRatio-1)
- delta, err := vol.Amplify(cap, nil, nil, "")
- assert.Err(t, err)
- assert.Equal(t, int64(0), delta)
-}
-
-func TestAmplify(t *testing.T) {
- volmod, err := models.NewDataVolume("/data", 10*utils.GB)
- assert.NilErr(t, err)
-
- bot := &mocks.Bot{}
- defer bot.AssertExpectations(t)
-
- vol := &Volume{
- Volume: volmod,
- newBot: func(v *Volume) (Bot, error) { return bot, nil },
- }
-
- meta, metaCancel := storemocks.Mock()
- defer metaCancel()
- defer meta.AssertExpectations(t)
- meta.On("Update", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
-
- bot.On("Close").Return(nil).Once()
- bot.On("Amplify", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
- delta, err := vol.Amplify(configs.Conf.ResizeVolumeMinSize, nil, nil, "")
- assert.Nil(t, err)
- assert.Equal(t, configs.Conf.ResizeVolumeMinSize, delta)
- assert.Equal(t, 20*utils.GB, vol.Capacity)
-}
-
-func TestAttachVolume_Rollback(t *testing.T) {
-}
-
-func TestAttachVolume(t *testing.T) {
- // TODO
-}
diff --git a/internal/vmcache/domain.go b/internal/vmcache/domain.go
new file mode 100644
index 0000000..44f8788
--- /dev/null
+++ b/internal/vmcache/domain.go
@@ -0,0 +1,440 @@
+package vmcache
+
+import (
+ "context"
+ "encoding/xml"
+ "fmt"
+ "sync"
+ "time"
+
+ "github.com/digitalocean/go-libvirt"
+ "github.com/digitalocean/go-libvirt/socket/dialers"
+ "github.com/dustin/go-humanize"
+ "github.com/patrickmn/go-cache"
+ "github.com/projecteru2/core/log"
+ "github.com/projecteru2/libyavirt/types"
+ "github.com/projecteru2/yavirt/configs"
+ intertypes "github.com/projecteru2/yavirt/internal/types"
+ interutils "github.com/projecteru2/yavirt/internal/utils"
+ "libvirt.org/go/libvirtxml"
+)
+
+var (
+ gVC *VMCache
+)
+
+const (
+ libvirtSock = "/var/run/libvirt/libvirt-sock"
+ libvirtTimeout = 5 * time.Second
+)
+
+func newLibvirt() (*libvirt.Libvirt, error) {
+ opts := []dialers.LocalOption{
+ dialers.WithSocket(libvirtSock),
+ dialers.WithLocalTimeout(libvirtTimeout),
+ }
+ dialer := dialers.NewLocal(opts...)
+ l := libvirt.NewWithDialer(dialer)
+ if err := l.Connect(); err != nil {
+ return nil, err
+ }
+ return l, nil
+}
+
+type VMCache struct {
+ mu sync.Mutex
+ localDomainCache map[string]*DomainCacheEntry
+ statsCache *cache.Cache
+ statsUpdateInterval time.Duration
+ watchers *interutils.Watchers
+}
+
+func (vc *VMCache) NotifyEvent(e libvirt.DomainEventLifecycleMsg) {
+ evt := intertypes.Event{
+ ID: e.Dom.Name,
+ Type: intertypes.EventTypeGuest,
+ }
+ switch e.Event {
+ case DomainEventStarted:
+ evt.Op = intertypes.StartOp
+ case DomainEventStopped:
+ evt.Op = intertypes.DieOp
+ default:
+ return
+ }
+ vc.watchers.Watched(evt)
+}
+
+// in order to avoid data race, please don't change this type of value after it created
+type DomainCacheEntry struct {
+ Name string
+ UUID string
+ State libvirt.DomainState
+ VNCPort int
+ CPU int
+ Memory int64
+ GPUAddrs []string
+ Schema *libvirtxml.Domain
+
+ AppID string
+ AppSID string
+ AppName string
+ IP string
+ EruName string
+ UserName string
+ UserID string
+}
+
+// we don't copy Schema, because it never changes
+func (dce *DomainCacheEntry) Copy() *DomainCacheEntry {
+ ans := *dce
+ ans.GPUAddrs = make([]string, len(dce.GPUAddrs))
+ copy(ans.GPUAddrs, dce.GPUAddrs)
+ return &ans
+}
+
+func (dce *DomainCacheEntry) IsRunning() bool {
+ return dce.State == libvirt.DomainRunning
+}
+
+func (dce *DomainCacheEntry) IsStopped() bool {
+ return dce.State == libvirt.DomainShutoff
+}
+
+type DomainStatsResp struct {
+ DomainCacheEntry
+ Stats map[string]libvirt.TypedParam
+}
+
+func extractInfoFromXML(domcfg *libvirtxml.Domain) *DomainCacheEntry {
+ logger := log.WithFunc("extractInfoFromXML")
+ var meta intertypes.CustomDomainMetadata
+ if domcfg.Metadata != nil {
+ metadataStr := fmt.Sprintf("%s", domcfg.Metadata.XML)
+ if err := xml.Unmarshal([]byte(metadataStr), &meta); err != nil {
+ // ignore error of metadata
+ logger.Warnf(context.TODO(), "failed to unmarshal metadata:%s", err)
+ }
+ }
+ cpu := int(domcfg.VCPU.Value)
+ memStr := fmt.Sprintf("%d %s", domcfg.Memory.Value, domcfg.Memory.Unit)
+ memory, err := humanize.ParseBytes(memStr)
+ if err != nil {
+ logger.Errorf(context.TODO(), err, "failed to parse memory of %s", domcfg.Name)
+ }
+ // fetch vnc port
+ var vncPort int
+ for _, g := range domcfg.Devices.Graphics {
+ if g.VNC != nil {
+ vncPort = g.VNC.Port
+ break
+ }
+ }
+ // fetch GPU addrs
+ var gpuAddrs []string //nolint
+ for _, hd := range domcfg.Devices.Hostdevs {
+ if hd.SubsysPCI == nil {
+ continue
+ }
+ d := hd.SubsysPCI.Source.Address.Domain
+ b := hd.SubsysPCI.Source.Address.Bus
+ s := hd.SubsysPCI.Source.Address.Slot
+ f := hd.SubsysPCI.Source.Address.Function
+ addr := fmt.Sprintf("%04x:%02x:%02x.%01x", *d, *b, *s, *f)
+ gpuAddrs = append(gpuAddrs, addr)
+ }
+ logger.Debugf(context.TODO(), "GPU addrs<%s>: %v", domcfg.Name, gpuAddrs)
+
+ entry := &DomainCacheEntry{
+ Name: domcfg.Name,
+ UUID: domcfg.UUID,
+ CPU: cpu,
+ Memory: int64(memory),
+ VNCPort: vncPort,
+ GPUAddrs: gpuAddrs,
+ Schema: domcfg,
+ EruName: types.EruID(domcfg.Name),
+ IP: meta.App.IP.IP,
+ AppID: meta.App.ID.ID,
+ AppSID: meta.App.ID.SID,
+ AppName: meta.App.Name.Name,
+ UserName: meta.App.Owner.UserName,
+ UserID: meta.App.Owner.UserID,
+ }
+ return entry
+}
+
+func (vc *VMCache) updateAllDomainsHelper(l *libvirt.Libvirt) {
+ logger := log.WithFunc("updateAllDomainsHelper")
+
+ flags := libvirt.ConnectListDomainsActive | libvirt.ConnectListDomainsInactive
+ domains, _, err := l.ConnectListAllDomains(1, flags)
+ if err != nil {
+ logger.Errorf(context.TODO(), err, "failed to list domains")
+ return
+ }
+
+ newCache := map[string]*DomainCacheEntry{}
+ for _, domain := range domains {
+ var flags libvirt.DomainXMLFlags
+ xmldoc, err := l.DomainGetXMLDesc(domain, flags)
+ if err != nil {
+ logger.Errorf(context.TODO(), err, "failed to get domain xml")
+ return
+ }
+
+ domcfg := &libvirtxml.Domain{}
+ if err = domcfg.Unmarshal(xmldoc); err != nil {
+ logger.Errorf(context.TODO(), err, "failed to unmarshal domain xml")
+ return
+ }
+ entry := extractInfoFromXML(domcfg)
+ state, _, _ := l.DomainGetState(domain, 0)
+ entry.State = libvirt.DomainState(state)
+ newCache[entry.Name] = entry
+ }
+
+ // lock after libvirt operation, so it doesn't lock too long in this function
+ vc.mu.Lock()
+ defer vc.mu.Unlock()
+
+ logger.Debugf(context.TODO(), "new cache: %v", newCache)
+ vc.localDomainCache = newCache
+}
+
+func (vc *VMCache) updateAllDomains(ctx context.Context) {
+ logger := log.WithFunc("updateAllDomains")
+ defer logger.Infof(ctx, "[updateAllDomains] exit")
+ var (
+ l *libvirt.Libvirt
+ err error
+ )
+ firstCh := make(chan struct{}, 1)
+ firstCh <- struct{}{}
+ for {
+ select {
+ case <-ctx.Done():
+ return
+ case <-time.After(90 * time.Second):
+ case <-firstCh:
+ }
+
+ if l == nil || (!l.IsConnected()) {
+ l, err = newLibvirt()
+ if err != nil {
+ logger.Errorf(ctx, err, "failed to get libvirt")
+ continue
+ }
+ }
+ vc.updateAllDomainsHelper(l)
+ }
+}
+
+func (vc *VMCache) updateOneDomain(ctx context.Context, l *libvirt.Libvirt, dom libvirt.Domain) error {
+ var flags libvirt.DomainXMLFlags
+ xmldoc, err := l.DomainGetXMLDesc(dom, flags)
+ if err != nil {
+ return err
+ }
+
+ domcfg := &libvirtxml.Domain{}
+ if err = domcfg.Unmarshal(xmldoc); err != nil {
+ return err
+ }
+ entry := extractInfoFromXML(domcfg)
+ state, _, _ := l.DomainGetState(dom, 0)
+ entry.State = libvirt.DomainState(state)
+
+ vc.mu.Lock()
+ defer vc.mu.Unlock()
+ log.WithFunc("updateOneDomain").Debugf(ctx, "new entry: %s, %v", entry.Name, entry.State)
+ vc.localDomainCache[entry.Name] = entry
+ return nil
+}
+
+func (vc *VMCache) processLibvirtEvents(ctx context.Context, l *libvirt.Libvirt, ch <-chan libvirt.DomainEventLifecycleMsg) {
+ logger := log.WithFunc("processLibvirtEvents")
+ for {
+ select {
+ case evt := <-ch:
+ if evt.Dom.Name == "" {
+ logger.Warnf(ctx, "event channel seems closed %v", evt)
+ return
+ }
+ logger.Infof(ctx, "got event %v", evt)
+ switch evt.Event {
+ case DomainEventUndefined:
+ vc.mu.Lock()
+ logger.Infof(ctx, "delete domain %s", evt.Dom.Name)
+ delete(vc.localDomainCache, evt.Dom.Name)
+ vc.mu.Unlock()
+ default:
+ if err := vc.updateOneDomain(ctx, l, evt.Dom); err != nil {
+ logger.Errorf(ctx, err, "failed to update domain %s", evt.Dom.Name)
+ }
+ }
+ vc.NotifyEvent(evt)
+ case <-ctx.Done():
+ logger.Infof(context.TODO(), "[processLibvirtEvents] ctx done")
+ return
+ }
+ }
+}
+
+func (vc *VMCache) handleDomainEvents(ctx context.Context) {
+ logger := log.WithFunc("handleDomainEvents")
+ defer logger.Infof(ctx, "[handleDomainEvents] exit")
+ for {
+ select {
+ case <-ctx.Done():
+ return
+ case <-time.After(5 * time.Second):
+ }
+
+ l, err := newLibvirt()
+ if err != nil {
+ logger.Errorf(ctx, err, "failed to get libvirt")
+ continue
+ }
+
+ // we should register events listener before fetching all existing domains
+ evtCtx, evtCancel := context.WithCancel(ctx)
+ ch, err := l.LifecycleEvents(evtCtx)
+ if err != nil {
+ logger.Errorf(ctx, err, "failed to get lifecycle events")
+ evtCancel()
+ continue
+ }
+ vc.processLibvirtEvents(ctx, l, ch)
+ evtCancel()
+ }
+}
+
+func (vc *VMCache) updateStats(ctx context.Context) {
+ logger := log.WithFunc("updateStats")
+ var (
+ l *libvirt.Libvirt
+ err error
+ )
+ for {
+ select {
+ case <-ctx.Done():
+ return
+ case <-time.After(vc.statsUpdateInterval):
+ }
+
+ if l == nil || (!l.IsConnected()) {
+ l, err = newLibvirt()
+ if err != nil {
+ logger.Errorf(ctx, err, "failed to get libvirt")
+ continue
+ }
+ }
+
+ flags := libvirt.ConnectGetAllDomainsStatsRunning
+ statList, err := l.ConnectGetAllDomainStats(nil, 0, flags)
+ if err != nil {
+ logger.Error(ctx, err, "failed to get all domain stats")
+ continue
+ }
+ for _, stats := range statList {
+ statsMap := make(map[string]libvirt.TypedParam)
+ for _, p := range stats.Params {
+ statsMap[p.Field] = p
+ }
+ vc.statsCache.Set(stats.Dom.Name, statsMap, cache.DefaultExpiration)
+ }
+ }
+}
+
+func (vc *VMCache) Run(ctx context.Context, enableMetrics bool) {
+ go vc.updateAllDomains(ctx)
+ go vc.handleDomainEvents(ctx)
+ if enableMetrics {
+ go vc.updateStats(ctx)
+ }
+}
+
+func FetchStats() map[string]DomainStatsResp {
+ resps := make(map[string]DomainStatsResp)
+ gVC.mu.Lock()
+ defer gVC.mu.Unlock()
+ for name, entry := range gVC.localDomainCache {
+ if stats, ok := gVC.statsCache.Get(name); ok {
+ resp := DomainStatsResp{
+ DomainCacheEntry: *entry,
+ Stats: stats.(map[string]libvirt.TypedParam),
+ }
+ resps[name] = resp
+ }
+ }
+ return resps
+}
+
+func FetchDomainEntry(name string) *DomainCacheEntry {
+ gVC.mu.Lock()
+ defer gVC.mu.Unlock()
+ return gVC.localDomainCache[name]
+}
+
+func FetchGPUAddrs() []string {
+ gVC.mu.Lock()
+ defer gVC.mu.Unlock()
+
+ resps := make([]string, 0)
+ for _, entry := range gVC.localDomainCache {
+ resps = append(resps, entry.GPUAddrs...)
+ }
+ return resps
+}
+
+func FetchDomainGPUAddrs() map[string][]string {
+ gVC.mu.Lock()
+ defer gVC.mu.Unlock()
+
+ resps := make(map[string][]string, 0)
+ for name, entry := range gVC.localDomainCache {
+ resps[name] = entry.GPUAddrs
+ }
+ return resps
+}
+
+func FetchDomainsInfo() map[string]any {
+ gVC.mu.Lock()
+ defer gVC.mu.Unlock()
+
+ resps := make(map[string]any)
+ for name, entry := range gVC.localDomainCache {
+ resps[name] = map[string]any{
+ "gpus": entry.GPUAddrs,
+ "state": State2Str(entry.State),
+ }
+ }
+ return resps
+}
+
+// UpdateDomain is used to update a domain in cache immediately
+func UpdateDomain(name string) error {
+ l, err := newLibvirt()
+ if err != nil {
+ return err
+ }
+ defer l.Disconnect() //nolint
+ dom, err := l.DomainLookupByName(name)
+ if err != nil {
+ return err
+ }
+ return gVC.updateOneDomain(context.TODO(), l, dom)
+}
+
+func Setup(ctx context.Context, cfg *configs.Config, ws *interutils.Watchers) error {
+ statsUpdateInterval := 10 * time.Second
+ gVC = &VMCache{
+ localDomainCache: make(map[string]*DomainCacheEntry),
+ statsCache: cache.New(statsUpdateInterval+time.Second, statsUpdateInterval),
+ statsUpdateInterval: 10 * time.Second,
+ watchers: ws,
+ }
+ gVC.Run(ctx, cfg.EnableLibvirtMetrics)
+ return nil
+}
diff --git a/internal/vmcache/domain_test.go b/internal/vmcache/domain_test.go
new file mode 100644
index 0000000..4042061
--- /dev/null
+++ b/internal/vmcache/domain_test.go
@@ -0,0 +1,44 @@
+package vmcache
+
+import (
+ "testing"
+
+ "github.com/digitalocean/go-libvirt"
+ "github.com/stretchr/testify/assert"
+ "libvirt.org/go/libvirtxml"
+)
+
+func TestDomainCacheEntryCopy(t *testing.T) {
+ original := &DomainCacheEntry{
+ Name: "example",
+ UUID: "123456",
+ State: libvirt.DomainRunning,
+ VNCPort: 5900,
+ GPUAddrs: nil,
+ Schema: &libvirtxml.Domain{},
+ AppName: "myApp",
+ IP: "192.168.1.1",
+ EruName: "ERU",
+ UserName: "user",
+ UserID: "123",
+ }
+ original.GPUAddrs = make([]string, 0, 10)
+ original.GPUAddrs = append(original.GPUAddrs, "GPU1", "GPU2")
+
+ // Make a copy of the original
+ copied := original.Copy()
+
+ // Use assert to check if the copy is equal to the original
+ assert.Equal(t, original, copied, "Copied object should be equal to the original")
+
+ // Modify the original
+ original.VNCPort = 5901
+
+ // Use assert to verify that the copied object is not affected by the modification
+ assert.NotEqual(t, original, copied, "Copied object should not be affected by modifications to the original")
+ assert.Equal(t, copied.VNCPort, 5900)
+
+ original.GPUAddrs = append(original.GPUAddrs, "GPU3")
+ assert.Equal(t, copied.GPUAddrs, []string{"GPU1", "GPU2"})
+ assert.Equal(t, original.GPUAddrs, []string{"GPU1", "GPU2", "GPU3"})
+}
diff --git a/internal/vmcache/pool.go b/internal/vmcache/pool.go
new file mode 100644
index 0000000..bb79f4e
--- /dev/null
+++ b/internal/vmcache/pool.go
@@ -0,0 +1,94 @@
+package vmcache
+
+import (
+ "sync/atomic"
+ "time"
+
+ "github.com/alphadose/haxmap"
+ "github.com/digitalocean/go-libvirt"
+ "github.com/digitalocean/go-libvirt/socket/dialers"
+)
+
+// the events libvirt emits when perfoming an vrish action are as follows:
+//
+// virsh start: Resumed, Started
+// virsh shutdown: Shutdown, Stopped
+// virsh suspend: Suspended
+// virsh resume: Resumed
+const (
+ DomainEventDefined = iota
+ DomainEventUndefined
+ DomainEventStarted
+ DomainEventSuspended
+ DomainEventResumed
+ DomainEventStopped
+ DomainEventShutdown
+ DomainEventPMSuspended
+)
+
+func State2Str(state libvirt.DomainState) string {
+ switch state {
+ case libvirt.DomainNostate:
+ return "NOSTATE"
+ case libvirt.DomainRunning:
+ return "RUNNING"
+ case libvirt.DomainBlocked:
+ return "BLOCKED"
+ case libvirt.DomainPaused:
+ return "PAUSED"
+ case libvirt.DomainShutdown:
+ return "SHUTDOWN"
+ case libvirt.DomainShutoff:
+ return "SHUTOFF"
+ case libvirt.DomainCrashed:
+ return "CRASHED"
+ default:
+ return "UNKNOWN"
+ }
+}
+
+type LibvirtPool struct {
+ index atomic.Int64
+ socket string
+ timeout time.Duration
+ pool *haxmap.Map[int64, *libvirt.Libvirt]
+}
+
+func (p *LibvirtPool) newLibvirt() (*libvirt.Libvirt, error) {
+ opts := []dialers.LocalOption{
+ dialers.WithSocket(p.socket),
+ dialers.WithLocalTimeout(p.timeout),
+ }
+ dialer := dialers.NewLocal(opts...)
+ l := libvirt.NewWithDialer(dialer)
+ if err := l.Connect(); err != nil {
+ return nil, err
+ }
+ idx := p.index.Add(1)
+ p.pool.Set(idx, l)
+ go func() {
+ <-l.Disconnected()
+ p.pool.Del(idx)
+ }()
+ return l, nil
+}
+
+func (p *LibvirtPool) Get() (*libvirt.Libvirt, error) {
+ var ans *libvirt.Libvirt
+ p.pool.ForEach(func(_ int64, v *libvirt.Libvirt) bool {
+ ans = v
+ return false
+ })
+ if ans == nil {
+ return p.newLibvirt()
+ }
+ return ans, nil
+}
+
+func NewLibvirtPool(socket string, timeout time.Duration) *LibvirtPool {
+ return &LibvirtPool{
+ socket: socket,
+ timeout: timeout,
+ pool: haxmap.New[int64, *libvirt.Libvirt](),
+ }
+}
diff --git a/internal/vmcache/util.go b/internal/vmcache/util.go
new file mode 100644
index 0000000..5b88dfb
--- /dev/null
+++ b/internal/vmcache/util.go
@@ -0,0 +1,43 @@
+package vmcache
+
+import (
+ "fmt"
+
+ "github.com/digitalocean/go-libvirt"
+)
+
+func ToUint64(p libvirt.TypedParam) (val uint64, err error) {
+ switch p.Value.D {
+ case 1:
+ val = uint64(p.Value.I.(int32))
+ case 2:
+ val = uint64(p.Value.I.(uint32))
+ case 3:
+ val = uint64(p.Value.I.(int64))
+ case 4:
+ val = p.Value.I.(uint64) //nolint
+ case 6:
+ val = uint64(p.Value.I.(int32))
+ default:
+ err = fmt.Errorf("invalid parameter type %v", p.Value.D)
+ }
+ return
+}
+
+func ToFloat64(p libvirt.TypedParam) (float64, error) {
+ switch p.Value.D {
+ case 5:
+ return p.Value.I.(float64), nil
+ default:
+ return 0, fmt.Errorf("invalid parameter type %v", p.Value.D)
+ }
+}
+
+func ToString(p libvirt.TypedParam) (string, error) {
+ switch p.Value.D {
+ case 7:
+ return p.Value.I.(string), nil
+ default:
+ return "", fmt.Errorf("invalid parameter type %v", p.Value.D)
+ }
+}
diff --git a/internal/vnet/calico/calico.go b/internal/vnet/calico/calico.go
deleted file mode 100644
index 3e8ab5f..0000000
--- a/internal/vnet/calico/calico.go
+++ /dev/null
@@ -1,4 +0,0 @@
-package calico
-
-// OrchestratorID .
-const OrchestratorID = "yavirt"
diff --git a/internal/vnet/calico/const.go b/internal/vnet/calico/const.go
deleted file mode 100644
index 67734eb..0000000
--- a/internal/vnet/calico/const.go
+++ /dev/null
@@ -1,6 +0,0 @@
-package calico
-
-const (
- // CalicoIPv4Version .
- CalicoIPv4Version = 4
-)
diff --git a/internal/vnet/calico/driver.go b/internal/vnet/calico/driver.go
deleted file mode 100644
index 3655ffe..0000000
--- a/internal/vnet/calico/driver.go
+++ /dev/null
@@ -1,89 +0,0 @@
-package calico
-
-import (
- "context"
- "strings"
- "sync"
-
- calitype "github.com/projectcalico/api/pkg/apis/projectcalico/v3"
- "github.com/projectcalico/calico/libcalico-go/lib/apiconfig"
- "github.com/projectcalico/calico/libcalico-go/lib/clientv3"
- "github.com/projectcalico/calico/libcalico-go/lib/options"
-
- "github.com/projecteru2/yavirt/pkg/errors"
-)
-
-// Driver .
-type Driver struct {
- sync.Mutex
-
- clientv3.Interface
-
- poolNames map[string]struct{}
-}
-
-// NewDriver .
-func NewDriver(configFile string, poolNames []string) (*Driver, error) {
- caliConf, err := apiconfig.LoadClientConfig(configFile)
- if err != nil {
- return nil, errors.Trace(err)
- }
-
- cali, err := clientv3.New(*caliConf)
- if err != nil {
- return nil, errors.Trace(err)
- }
-
- var driver = &Driver{
- Interface: cali,
- poolNames: map[string]struct{}{},
- }
-
- for _, pn := range poolNames {
- driver.poolNames[pn] = struct{}{}
- }
-
- return driver, nil
-}
-
-func (d *Driver) getIPPool() (calitype.IPPool, error) {
- var pool calitype.IPPool
-
- var pools, err = d.IPPools().List(context.Background(), options.ListOptions{})
- switch {
- case err != nil:
- return pool, errors.Trace(err)
- case len(pools.Items) < 1:
- return pool, errors.Trace(errors.ErrCalicoPoolNotExists)
- }
-
- if len(d.poolNames) < 1 {
- return pools.Items[0], nil
- }
-
- for _, pool = range pools.Items {
- if _, exists := d.poolNames[pool.Name]; exists {
- return pool, nil
- }
- }
-
- return pool, errors.Annotatef(errors.ErrCalicoPoolNotExists, "no such pool names: %s", d.poolNamesStr())
-}
-
-func (d *Driver) poolNamesStr() string {
- var s = make([]string, len(d.poolNames), 0)
- for name := range d.poolNames {
- s = append(s, name)
- }
- return strings.Join(s, ", ")
-}
-
-// Ipam .
-func (d *Driver) Ipam() *Ipam {
- return newIpam(d)
-}
-
-// WorkloadEndpoint .
-func (d *Driver) WorkloadEndpoint() *WorkloadEndpoint {
- return newWorkloadEndpoint(d)
-}
diff --git a/internal/vnet/calico/ipam.go b/internal/vnet/calico/ipam.go
deleted file mode 100644
index 5c4ba17..0000000
--- a/internal/vnet/calico/ipam.go
+++ /dev/null
@@ -1,163 +0,0 @@
-package calico
-
-import (
- "context"
- "net"
-
- libcaliipam "github.com/projectcalico/calico/libcalico-go/lib/ipam"
- libcalinet "github.com/projectcalico/calico/libcalico-go/lib/net"
-
- "github.com/projecteru2/yavirt/configs"
- "github.com/projecteru2/yavirt/internal/meta"
- "github.com/projecteru2/yavirt/pkg/errors"
- "github.com/projecteru2/yavirt/pkg/log"
- "github.com/projecteru2/yavirt/pkg/netx"
- "github.com/projecteru2/yavirt/pkg/store/etcd"
-)
-
-// Ipam .
-type Ipam struct {
- *Driver
-}
-
-func newIpam(driver *Driver) *Ipam {
- return &Ipam{Driver: driver}
-}
-
-// Assign .
-func (ipam *Ipam) Assign(_ context.Context) (meta.IP, error) {
- hn := configs.Hostname()
-
- ipam.Lock()
- defer ipam.Unlock()
-
- ipn, err := ipam.getIPv4Net()
- if err != nil {
- return nil, errors.Trace(err)
- }
-
- var args = libcaliipam.AutoAssignArgs{
- Num4: 1,
- Hostname: hn,
- IPv4Pools: []libcalinet.IPNet{*ipn},
- IntendedUse: "Workload",
- }
-
- return ipam.assign(args)
-}
-
-func (ipam *Ipam) assign(args libcaliipam.AutoAssignArgs) (meta.IP, error) {
- var ipv4s, err = ipam.autoAssign(args)
- if err != nil {
- return nil, errors.Trace(err)
- }
-
- if len(ipv4s.IPs) < 1 {
- return nil, errors.Trace(errors.ErrInsufficientIP)
- }
-
- var ip = ipv4s.IPs[0]
- var ones, _ = ip.Mask.Size()
- if ones >= 30 {
- return nil, errors.Annotatef(errors.ErrCalicoTooSmallSubnet, "/%d", ones)
- }
-
- if err := netx.CheckIPv4(ip.IP, ip.Mask); err != nil {
- if !errors.IsIPv4IsNetworkNumberErr(err) && !errors.IsIPv4IsBroadcastErr(err) {
- return nil, errors.Trace(err)
- }
-
- // Occupies the network no. and broadcast addr.,
- // doesn't release them to Calico unallocated pool.
- // and then retry to assign.
- log.Warnf("occupy %s as it's a network no. or broadcast addr.", ip)
- return ipam.assign(args)
- }
-
- return NewIP(&ip), nil
-}
-
-func (ipam *Ipam) autoAssign(args libcaliipam.AutoAssignArgs) (ipv4s *libcaliipam.IPAMAssignments, err error) {
- etcd.RetryTimedOut(func() error { //nolint
- ipv4s, _, err = ipam.IPAM().AutoAssign(context.Background(), args)
- return err
- }, 3) //nolint:gomnd // try 3 times
- return
-}
-
-func (ipam *Ipam) getIPv4Net() (*libcalinet.IPNet, error) {
- pool, err := ipam.getIPPool()
- if err != nil {
- return nil, errors.Trace(err)
- }
-
- _, ipn, err := libcalinet.ParseCIDR(pool.Spec.CIDR)
-
- switch {
- case err != nil:
- return nil, errors.Annotatef(err, pool.Spec.CIDR)
-
- case ipn.Version() != CalicoIPv4Version:
- return nil, errors.Annotatef(errors.ErrCalicoIPv4Only, "%d", ipn.Version())
- }
-
- return ipn, err
-}
-
-// Release .
-func (ipam *Ipam) Release(ctx context.Context, ips ...meta.IP) error {
- ipam.Lock()
- defer ipam.Unlock()
-
- var releaseOpts = make([]libcaliipam.ReleaseOptions, len(ips))
- for i := range ips {
- var ip, ok = ips[i].(*IP)
- if !ok {
- return errors.Annotatef(errors.ErrInvalidValue, "expect *IP, but %v", ips[i])
- }
-
- releaseOpts[i] = libcaliipam.ReleaseOptions{Address: ip.IP.String()}
- }
-
- return etcd.RetryTimedOut(func() error {
- var _, err = ipam.IPAM().ReleaseIPs(ctx, releaseOpts...)
- return err
- }, 3) //nolint:gomnd // try 3 times
-}
-
-// Query .
-func (ipam *Ipam) Query(ctx context.Context, args meta.IPNets) ([]meta.IP, error) {
- ipam.Lock()
- defer ipam.Unlock()
-
- var ips = make([]meta.IP, len(args))
- var err error
-
- for i := range args {
- if ips[i], err = ipam.load(ctx, args[i]); err != nil {
- return nil, errors.Trace(err)
- }
- }
-
- return ips, nil
-}
-
-func (ipam *Ipam) load(_ context.Context, arg *meta.IPNet) (*IP, error) {
- var ip, err = ParseCIDR(arg.CIDR())
- if err != nil {
- return nil, errors.Trace(err)
- }
-
- gwIPNet, err := ipam.getGatewayIPNet(arg)
- if err != nil {
- return nil, errors.Trace(err)
- }
-
- ip.BindGatewayIPNet(gwIPNet)
-
- return ip, nil
-}
-
-func (ipam *Ipam) getGatewayIPNet(arg *meta.IPNet) (*net.IPNet, error) {
- return netx.ParseCIDR2(arg.GatewayCIDR())
-}
diff --git a/internal/vnet/calico/workload_endpoint.go b/internal/vnet/calico/workload_endpoint.go
deleted file mode 100644
index 39b93a9..0000000
--- a/internal/vnet/calico/workload_endpoint.go
+++ /dev/null
@@ -1,234 +0,0 @@
-package calico
-
-import (
- "context"
- "net"
- "time"
-
- libcaliapi "github.com/projectcalico/calico/libcalico-go/lib/apis/v3"
- libcalierr "github.com/projectcalico/calico/libcalico-go/lib/errors"
- libcalinames "github.com/projectcalico/calico/libcalico-go/lib/names"
- libcalinet "github.com/projectcalico/calico/libcalico-go/lib/net"
- libcaliopt "github.com/projectcalico/calico/libcalico-go/lib/options"
- k8smeta "k8s.io/apimachinery/pkg/apis/meta/v1"
- k8stypes "k8s.io/apimachinery/pkg/types"
-
- "github.com/projecteru2/yavirt/internal/meta"
- "github.com/projecteru2/yavirt/internal/vnet/types"
- "github.com/projecteru2/yavirt/pkg/errors"
- "github.com/projecteru2/yavirt/pkg/netx"
- "github.com/projecteru2/yavirt/pkg/store/etcd"
-)
-
-// WorkloadEndpoint .
-type WorkloadEndpoint struct {
- *Driver
-}
-
-func newWorkloadEndpoint(driver *Driver) *WorkloadEndpoint {
- return &WorkloadEndpoint{Driver: driver}
-}
-
-// Get .
-func (we *WorkloadEndpoint) Get(args types.EndpointArgs) (*libcaliapi.WorkloadEndpoint, error) {
- we.Lock()
- defer we.Unlock()
- return we.get(args)
-}
-
-// Create .
-func (we *WorkloadEndpoint) Create(args types.EndpointArgs) (cwe *libcaliapi.WorkloadEndpoint, err error) {
- we.Lock()
- defer we.Unlock()
-
- if cwe, err = we.getCalicoWorkloadEndpoint(args); err != nil {
- return nil, errors.Trace(err)
- }
-
- err = etcd.RetryTimedOut(func() error {
- var created, ce = we.WorkloadEndpoints().Create(context.Background(), cwe, libcaliopt.SetOptions{})
- if ce != nil {
- if _, ok := ce.(libcalierr.ErrorResourceAlreadyExists); !ok {
- return ce
- }
- }
-
- cwe = created
-
- return nil
- }, 3)
-
- return
-}
-
-func (we *WorkloadEndpoint) get(args types.EndpointArgs) (cwe *libcaliapi.WorkloadEndpoint, err error) {
- var endpName string
- if endpName, err = we.generateEndpointName(args.Hostname, args.EndpointID); err != nil {
- return nil, errors.Trace(err)
- }
-
- etcd.RetryTimedOut(func() error { //nolint
- cwe, err = we.WorkloadEndpoints().Get(context.Background(), args.Hostname, endpName, libcaliopt.GetOptions{})
- if err != nil {
- if _, ok := err.(libcalierr.ErrorResourceDoesNotExist); ok { //nolint
- err = errors.Annotatef(errors.ErrCalicoEndpointNotExists, "%s on %s", endpName, args.Hostname)
- }
- }
-
- return err
- }, 3)
-
- return
-}
-
-// Update .
-func (we *WorkloadEndpoint) Update(args types.EndpointArgs) (cwe *libcaliapi.WorkloadEndpoint, err error) {
- we.Lock()
- defer we.Unlock()
-
- cwe, err = we.getCalicoWorkloadEndpoint(args)
- if err != nil {
- return nil, errors.Trace(err)
- }
-
- cwe.ObjectMeta.UID = k8stypes.UID(args.UID)
- cwe.ObjectMeta.CreationTimestamp = k8smeta.NewTime(time.Now().UTC())
-
- err = etcd.RetryTimedOut(func() error {
- var updated, ue = we.WorkloadEndpoints().Update(context.Background(), cwe, libcaliopt.SetOptions{})
- if ue != nil {
- return ue
- }
-
- cwe = updated
-
- return nil
- }, 3)
-
- return
-}
-
-// Delete .
-func (we *WorkloadEndpoint) Delete(args types.EndpointArgs) error {
- var endpName, err = we.generateEndpointName(args.Hostname, args.EndpointID)
- if err != nil {
- return errors.Trace(err)
- }
-
- we.Lock()
- defer we.Unlock()
-
- return etcd.RetryTimedOut(func() error {
- if err := we.delete(endpName, args.Hostname); err != nil {
- if _, ok := err.(libcalierr.ErrorResourceDoesNotExist); !ok {
- return err
- }
- }
- return nil
- }, 3)
-}
-
-func (we *WorkloadEndpoint) delete(endpName, namespace string) (err error) {
- _, err = we.WorkloadEndpoints().Delete(
- context.Background(),
- namespace,
- endpName,
- libcaliopt.DeleteOptions{},
- )
- return
-}
-
-func (we *WorkloadEndpoint) getCalicoWorkloadEndpoint(args types.EndpointArgs) (*libcaliapi.WorkloadEndpoint, error) {
- endpName, err := we.generateEndpointName(args.Hostname, args.EndpointID)
- if err != nil {
- return nil, errors.Trace(err)
- }
-
- ipNets, err := we.convCalicoIPNetworks(args.IPs)
- if err != nil {
- return nil, errors.Trace(err)
- }
-
- profile, err := we.getProfile()
- if err != nil {
- return nil, errors.Trace(err)
- }
-
- wep := libcaliapi.NewWorkloadEndpoint()
- wep.Name = endpName
- wep.ObjectMeta.Namespace = args.Hostname
- wep.ObjectMeta.ResourceVersion = args.ResourceVersion
- wep.Spec.Endpoint = args.EndpointID
- wep.Spec.Node = args.Hostname
- wep.Spec.Orchestrator = OrchestratorID
- wep.Spec.Workload = OrchestratorID
- wep.Spec.InterfaceName = args.Device.Name()
- wep.Spec.MAC = args.MAC
- wep.Spec.IPNetworks = append(wep.Spec.IPNetworks, ipNets...)
- wep.Spec.Profiles = we.mergeProfile(args.Profiles, profile)
-
- return wep, nil
-}
-
-func (we *WorkloadEndpoint) mergeProfile(profiles []string, other string) []string {
- if len(profiles) < 1 {
- return []string{other}
- }
-
- for _, p := range profiles {
- if p == other {
- return profiles
- }
- }
-
- return append(profiles, other)
-}
-
-func (we *WorkloadEndpoint) generateEndpointName(hostname, endpointID string) (string, error) {
- var ident = libcalinames.WorkloadEndpointIdentifiers{
- Node: hostname,
- Orchestrator: OrchestratorID,
- Workload: OrchestratorID,
- Endpoint: endpointID,
- }
- return ident.CalculateWorkloadEndpointName(false)
-}
-
-func (we *WorkloadEndpoint) convCalicoIPNetworks(ips []meta.IP) ([]string, error) {
- var ipNets = make([]string, len(ips))
-
- for i, ip := range ips {
- ipv4, _, err := netx.ParseCIDR(ip.CIDR())
- if err != nil {
- return nil, errors.Trace(err)
- }
-
- ipNets[i] = libcalinet.IPNet{IPNet: net.IPNet{
- IP: ipv4,
- Mask: net.CIDRMask(net.IPv4len*8, net.IPv4len*8),
- }}.String()
- }
-
- return ipNets, nil
-}
-
-func (we *WorkloadEndpoint) getProfile() (string, error) {
- var pool, err = we.getIPPool()
- if err != nil {
- return "", errors.Trace(err)
- }
- return pool.ObjectMeta.Name, nil
-}
-
-// ConvIPs .
-func ConvIPs(cwe *libcaliapi.WorkloadEndpoint) (ips []meta.IP, err error) {
- ips = make([]meta.IP, len(cwe.Spec.IPNetworks))
-
- for i, cidr := range cwe.Spec.IPNetworks {
- if ips[i], err = ParseCIDR(cidr); err != nil {
- return nil, errors.Trace(err)
- }
- }
-
- return ips, nil
-}
diff --git a/internal/vnet/const.go b/internal/vnet/const.go
deleted file mode 100644
index 119222b..0000000
--- a/internal/vnet/const.go
+++ /dev/null
@@ -1,8 +0,0 @@
-package vnet
-
-const (
- // NetworkCalico .
- NetworkCalico = "calico"
- // NetworkVlan .
- NetworkVlan = "vlan"
-)
diff --git a/internal/vnet/handler/calico/calico.go b/internal/vnet/handler/calico/calico.go
deleted file mode 100644
index 0d52ae8..0000000
--- a/internal/vnet/handler/calico/calico.go
+++ /dev/null
@@ -1,34 +0,0 @@
-package calico
-
-import (
- "sync"
-
- libcaliapi "github.com/projectcalico/calico/libcalico-go/lib/apis/v3"
-
- calinet "github.com/projecteru2/yavirt/internal/vnet/calico"
- "github.com/projecteru2/yavirt/internal/vnet/device"
-)
-
-// Handler .
-type Handler struct {
- sync.Mutex
-
- cali *calinet.Driver
- dev *device.Driver
-
- gateway *device.Dummy
- gatewayWorkloadEndpoint *libcaliapi.WorkloadEndpoint
-
- poolNames []string
- hostIP string
-}
-
-// New .
-func New(dev *device.Driver, driver *calinet.Driver, poolNames []string, hostIP string) *Handler {
- return &Handler{
- dev: dev,
- cali: driver,
- hostIP: hostIP,
- poolNames: poolNames,
- }
-}
diff --git a/internal/vnet/handler/calico/const.go b/internal/vnet/handler/calico/const.go
deleted file mode 100644
index 992ef80..0000000
--- a/internal/vnet/handler/calico/const.go
+++ /dev/null
@@ -1,6 +0,0 @@
-package calico
-
-import "net"
-
-// AllonesMask .
-var AllonesMask = net.CIDRMask(32, net.IPv4len*8)
diff --git a/internal/vnet/handler/calico/endpoint.go b/internal/vnet/handler/calico/endpoint.go
deleted file mode 100644
index f9368c6..0000000
--- a/internal/vnet/handler/calico/endpoint.go
+++ /dev/null
@@ -1,104 +0,0 @@
-package calico
-
-import (
- "fmt"
- "strings"
-
- "github.com/projecteru2/yavirt/internal/vnet/device"
- "github.com/projecteru2/yavirt/internal/vnet/types"
- "github.com/projecteru2/yavirt/pkg/errors"
- "github.com/projecteru2/yavirt/pkg/log"
- "github.com/projecteru2/yavirt/pkg/utils"
-)
-
-// CreateEndpointNetwork .
-func (h *Handler) CreateEndpointNetwork(args types.EndpointArgs) (types.EndpointArgs, func(), error) {
- h.Lock()
- defer h.Unlock()
-
- var err error
-
- if args.EndpointID, err = h.generateEndpointID(); err != nil {
- return args, nil, errors.Trace(err)
- }
-
- if args.Device, err = h.createTap(); err != nil {
- return args, nil, errors.Trace(err)
- }
-
- if err = args.Device.Up(); err != nil {
- return args, nil, errors.Trace(err)
- }
-
- if _, err = h.cali.WorkloadEndpoint().Create(args); err != nil {
- return args, nil, err
- }
-
- rollback := func() {
- if err := h.DeleteEndpointNetwork(args); err != nil {
- log.ErrorStackf(err, "delete endpoint %s failed", args.EndpointID)
- }
- }
-
- return args, rollback, err
-}
-
-// JoinEndpointNetwork .
-func (h *Handler) JoinEndpointNetwork(args types.EndpointArgs) (func(), error) {
- if err := args.Check(); err != nil {
- return nil, errors.Trace(err)
- }
-
- h.Lock()
- defer h.Unlock()
-
- for _, ip := range args.IPs {
- ip.BindDevice(args.Device)
-
- if err := args.Device.AddRoute(ip.IPAddr(), h.hostIP); err != nil {
- if !errors.IsVirtLinkRouteExistsErr(err) {
- return nil, errors.Trace(err)
- }
- }
- }
-
- rollback := func() {
- dev := args.Device.Name()
- for _, ip := range args.IPs {
- cidr := fmt.Sprintf("%s/32", ip.IPAddr())
- if err := args.Device.DeleteRoute(cidr); err != nil {
- log.ErrorStackf(err, "delete route %s on %s failed", cidr, dev)
- }
- }
- }
-
- return rollback, nil
-}
-
-// DeleteEndpointNetwork .
-func (h *Handler) DeleteEndpointNetwork(args types.EndpointArgs) error {
- h.Lock()
- defer h.Unlock()
- return h.cali.WorkloadEndpoint().Delete(args)
-}
-
-// GetEndpointDevice .
-func (h *Handler) GetEndpointDevice(name string) (device.VirtLink, error) {
- dev, err := device.New()
- if err != nil {
- return nil, errors.Trace(err)
- }
-
- h.Lock()
- defer h.Unlock()
-
- return dev.ShowLink(name)
-}
-
-func (h *Handler) generateEndpointID() (string, error) {
- var uuid, err = utils.UUIDStr()
- if err != nil {
- return "", errors.Trace(err)
- }
- return strings.ReplaceAll(uuid, "-", ""), nil
-}
diff --git a/internal/vnet/handler/calico/gateway.go b/internal/vnet/handler/calico/gateway.go
deleted file mode 100644
index 5ddd170..0000000
--- a/internal/vnet/handler/calico/gateway.go
+++ /dev/null
@@ -1,201 +0,0 @@
-package calico
-
-import (
- "net"
-
- libcaliapi "github.com/projectcalico/calico/libcalico-go/lib/apis/v3"
-
- "github.com/projecteru2/yavirt/configs"
- "github.com/projecteru2/yavirt/internal/meta"
- calinet "github.com/projecteru2/yavirt/internal/vnet/calico"
- "github.com/projecteru2/yavirt/internal/vnet/device"
- "github.com/projecteru2/yavirt/internal/vnet/types"
- "github.com/projecteru2/yavirt/pkg/errors"
-)
-
-// InitGateway .
-func (h *Handler) InitGateway(gwName string) error {
- dev, err := device.New()
- if err != nil {
- return errors.Trace(err)
- }
-
- h.Lock()
- defer h.Unlock()
-
- gw, err := dev.ShowLink(gwName)
- if err != nil {
- if errors.IsVirtLinkNotExistsErr(err) {
- gw, err = dev.AddLink(device.LinkTypeDummy, gwName)
- }
-
- if err != nil {
- return errors.Trace(err)
- }
- }
-
- var ok bool
- if h.gateway, ok = gw.(*device.Dummy); !ok {
- return errors.Annotatef(errors.ErrInvalidValue, "expect *device.Dummy, but %v", gw)
- }
-
- if err := h.gateway.Up(); err != nil {
- return errors.Trace(err)
- }
-
- if err := h.loadGateway(); err != nil {
- return errors.Trace(err)
- }
-
- gwIPs, err := h.gatewayIPs()
- if err != nil {
- return errors.Trace(err)
- }
-
- return h.bindGatewayIPs(gwIPs...)
-}
-
-// Gateway .
-func (h *Handler) Gateway() *device.Dummy {
- h.Lock()
- defer h.Unlock()
- return h.gateway
-}
-
-// GatewayWorkloadEndpoint .
-func (h *Handler) GatewayWorkloadEndpoint() *libcaliapi.WorkloadEndpoint {
- h.Lock()
- defer h.Unlock()
- return h.gatewayWorkloadEndpoint
-}
-
-func (h *Handler) bindGatewayIPs(ips ...meta.IP) error {
- for _, ip := range ips {
- var addr, err = h.dev.ParseCIDR(ip.CIDR())
- if err != nil {
- return errors.Trace(err)
- }
-
- addr.IPNet = &net.IPNet{
- IP: addr.IPNet.IP,
- Mask: AllonesMask,
- }
-
- if err := h.gateway.BindAddr(addr); err != nil && !errors.IsVirtLinkAddrExistsErr(err) {
- return errors.Trace(err)
- }
-
- if err := h.gateway.ClearRoutes(); err != nil {
- return errors.Trace(err)
- }
- }
-
- return nil
-}
-
-func (h *Handler) addGatewayEndpoint(ip meta.IP) error {
- hn := configs.Hostname()
-
- var args types.EndpointArgs
- args.IPs = []meta.IP{ip}
- args.Device = h.gateway
- args.MAC = h.gateway.MAC()
- args.Hostname = hn
- args.EndpointID = configs.Conf.CalicoGatewayName
-
- gwIPs, err := h.gatewayIPs()
- if err != nil {
- return errors.Trace(err)
- }
-
- var cwe *libcaliapi.WorkloadEndpoint
-
- if len(gwIPs) > 0 {
- args.IPs = append(args.IPs, gwIPs...)
- args.ResourceVersion = h.gatewayWorkloadEndpoint.ObjectMeta.ResourceVersion
- args.UID = string(h.gatewayWorkloadEndpoint.ObjectMeta.UID)
- args.Profiles = h.gatewayWorkloadEndpoint.Spec.Profiles
- cwe, err = h.cali.WorkloadEndpoint().Update(args)
- } else {
- cwe, err = h.cali.WorkloadEndpoint().Create(args)
- }
-
- if err != nil {
- return errors.Trace(err)
- }
-
- h.gatewayWorkloadEndpoint = cwe
-
- return nil
-}
-
-// RefreshGateway refreshes gateway data.
-func (h *Handler) RefreshGateway() error {
- h.Lock()
- defer h.Unlock()
- return h.loadGateway()
-}
-
-func (h *Handler) loadGateway() error {
- hn := configs.Hostname()
-
- var args types.EndpointArgs
- args.Hostname = hn
- args.EndpointID = configs.Conf.CalicoGatewayName
-
- wep, err := h.cali.WorkloadEndpoint().Get(args)
- if err != nil {
- if errors.IsCalicoEndpointNotExistsErr(err) {
- return nil
- }
- return errors.Trace(err)
- }
-
- h.gatewayWorkloadEndpoint = wep
-
- return nil
-}
-
-// GetGatewayIP gets a gateway IP which could serve the ip.
-func (h *Handler) GetGatewayIP(ip meta.IP) (meta.IP, error) {
- h.Lock()
- defer h.Unlock()
- return h.getGatewayIP(ip)
-}
-
-func (h *Handler) getGatewayIP(ip meta.IP) (meta.IP, error) {
- if h.gatewayWorkloadEndpoint == nil {
- return nil, errors.Annotatef(errors.ErrCalicoGatewayIPNotExists, "no such gateway WorkloadEndpoint")
- }
-
- for _, cidr := range h.gatewayWorkloadEndpoint.Spec.IPNetworks {
- var gwIP, err = calinet.ParseCIDR(cidr)
- if err != nil {
- return nil, errors.Trace(err)
- }
-
- if h.isUnderGateway(gwIP, ip) {
- return gwIP, nil
- }
- }
-
- return nil, errors.Annotatef(errors.ErrCalicoGatewayIPNotExists, "for %s", ip)
-}
-
-func (h *Handler) isUnderGateway(gatewayIP, ip meta.IP) bool {
- var ipn = &net.IPNet{}
- ipn.IP = gatewayIP.NetIP()
- ipn.Mask = net.CIDRMask(ip.Prefix(), net.IPv4len*8)
- return ipn.Contains(ip.NetIP())
-}
-
-func (h *Handler) isCalicoGatewayIPNotExistsErr(err error) bool {
- return errors.Contain(err, errors.ErrCalicoGatewayIPNotExists)
-}
-
-func (h *Handler) gatewayIPs() (ips []meta.IP, err error) {
- if h.gatewayWorkloadEndpoint != nil {
- ips, err = calinet.ConvIPs(h.gatewayWorkloadEndpoint)
- }
- return
-}
diff --git a/internal/vnet/handler/calico/ipam.go b/internal/vnet/handler/calico/ipam.go
deleted file mode 100644
index c55c9a9..0000000
--- a/internal/vnet/handler/calico/ipam.go
+++ /dev/null
@@ -1,92 +0,0 @@
-package calico
-
-import (
- "context"
-
- "github.com/projecteru2/yavirt/internal/meta"
- calinet "github.com/projecteru2/yavirt/internal/vnet/calico"
- "github.com/projecteru2/yavirt/internal/vnet/ipam"
- "github.com/projecteru2/yavirt/pkg/errors"
- "github.com/projecteru2/yavirt/pkg/log"
-)
-
-// NewIP .
-func (h *Handler) NewIP(_, cidr string) (meta.IP, error) {
- return calinet.ParseCIDR(cidr)
-}
-
-// AssignIP .
-func (h *Handler) AssignIP() (ip meta.IP, err error) {
- h.Lock()
- defer h.Unlock()
- return h.assignIP(true)
-}
-
-func (h *Handler) assignIP(crossCalicoBlocks bool) (ip meta.IP, err error) {
- if ip, err = h.ipam().Assign(context.Background()); err != nil {
- return nil, errors.Trace(err)
- }
-
- var roll = ip
- defer func() {
- if err != nil && roll != nil {
- if re := h.releaseIPs(roll); re != nil {
- err = errors.Wrap(err, re)
- }
- }
- }()
-
- var gwIP meta.IP
- if gwIP, err = h.getGatewayIP(ip); err == nil {
- ip.BindGatewayIPNet(gwIP.IPNetwork())
- return ip, nil
- }
-
- switch {
- case !h.isCalicoGatewayIPNotExistsErr(err):
- return nil, errors.Annotatef(err, ip.CIDR())
- case !crossCalicoBlocks:
- return nil, errors.Annotatef(errors.ErrCalicoCannotCrossBlocks, ip.CIDR())
- }
-
- log.Warnf("%s doesn't belong any gateway, turn it into a gateway then", ip)
- if err = h.addGatewayEndpoint(ip); err != nil {
- return nil, errors.Trace(err)
- }
-
- // The assigned IP had truned into gateway workloadEndpoint,
- // so it shouldn't be rolled back even if there's a further error.
- roll = nil
-
- if err = h.bindGatewayIPs(ip); err != nil {
- log.Warnf("%s reserves as gateway addr, but bound device failed", ip)
- return nil, errors.Trace(err)
- }
-
- return h.assignIP(false)
-}
-
-// ReleaseIPs .
-func (h *Handler) ReleaseIPs(ips ...meta.IP) error {
- h.Lock()
- defer h.Unlock()
- return h.releaseIPs(ips...)
-}
-
-func (h *Handler) releaseIPs(ips ...meta.IP) error {
- return h.ipam().Release(context.Background(), ips...)
-}
-
-// QueryIPs .
-func (h *Handler) QueryIPs(ipns meta.IPNets) ([]meta.IP, error) {
- return h.ipam().Query(context.Background(), ipns)
-}
-
-func (h *Handler) ipam() ipam.Ipam {
- return h.cali.Ipam()
-}
-
-// QueryIPv4 .
-func (h *Handler) QueryIPv4(_ string) (meta.IP, error) {
- return nil, errors.Trace(errors.ErrNotImplemented)
-}
diff --git a/internal/vnet/handler/calico/ippool.go b/internal/vnet/handler/calico/ippool.go
deleted file mode 100644
index c110500..0000000
--- a/internal/vnet/handler/calico/ippool.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package calico
-
-import (
- "context"
-
- "github.com/projectcalico/calico/libcalico-go/lib/options"
-)
-
-// PoolNames .
-func (h *Handler) PoolNames() []string {
- return h.poolNames
-}
-
-// GetIPPoolCidr .
-func (h *Handler) GetIPPoolCidr(ctx context.Context, name string) (string, error) {
- ipPool, err := h.cali.IPPools().Get(ctx, name, options.GetOptions{})
- if err != nil {
- return "", err
- }
- return ipPool.Spec.CIDR, nil
-}
diff --git a/internal/vnet/handler/calico/tap.go b/internal/vnet/handler/calico/tap.go
deleted file mode 100644
index 0456ee5..0000000
--- a/internal/vnet/handler/calico/tap.go
+++ /dev/null
@@ -1,40 +0,0 @@
-package calico
-
-import (
- "fmt"
-
- "github.com/projecteru2/yavirt/internal/vnet/device"
- "github.com/projecteru2/yavirt/pkg/errors"
- "github.com/projecteru2/yavirt/pkg/utils"
-)
-
-func (h *Handler) createTap() (device.VirtLink, error) {
- var name, err = h.randTapName()
- if err != nil {
- return nil, errors.Trace(err)
- }
-
- for {
- var tap, err = h.dev.AddLink(device.LinkTypeTuntap, name)
- if err != nil {
- if errors.Contain(err, errors.ErrVirtLinkExists) {
- continue
- }
-
- return nil, errors.Trace(err)
- }
-
- return tap, nil
- }
-}
-
-func (h *Handler) randTapName() (string, error) {
- var endpID, err = h.generateEndpointID()
- if err != nil {
- return "", errors.Trace(err)
- }
-
- var name = fmt.Sprintf("yap%s", endpID[:utils.Min(12, len(endpID))])
-
- return name, nil
-}
diff --git a/internal/vnet/handler/handler.go b/internal/vnet/handler/handler.go
deleted file mode 100644
index 0e38c66..0000000
--- a/internal/vnet/handler/handler.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package handler
-
-import (
- "github.com/projecteru2/yavirt/internal/meta"
- "github.com/projecteru2/yavirt/internal/vnet/device"
- "github.com/projecteru2/yavirt/internal/vnet/types"
-)
-
-// Handler .
-type Handler interface {
- AssignIP() (meta.IP, error)
- ReleaseIPs(ips ...meta.IP) error
- QueryIPv4(ipv4 string) (meta.IP, error)
- QueryIPs(meta.IPNets) ([]meta.IP, error)
-
- CreateEndpointNetwork(types.EndpointArgs) (types.EndpointArgs, func(), error)
- JoinEndpointNetwork(types.EndpointArgs) (func(), error)
- DeleteEndpointNetwork(types.EndpointArgs) error
-
- GetEndpointDevice(devName string) (device.VirtLink, error)
-}
diff --git a/internal/vnet/handler/vlan/vlan.go b/internal/vnet/handler/vlan/vlan.go
deleted file mode 100644
index a1717c8..0000000
--- a/internal/vnet/handler/vlan/vlan.go
+++ /dev/null
@@ -1,81 +0,0 @@
-package vlan
-
-import (
- "context"
-
- "github.com/projecteru2/yavirt/internal/meta"
- "github.com/projecteru2/yavirt/internal/vnet/device"
- "github.com/projecteru2/yavirt/internal/vnet/ipam"
- "github.com/projecteru2/yavirt/internal/vnet/types"
- vlannet "github.com/projecteru2/yavirt/internal/vnet/vlan"
- "github.com/projecteru2/yavirt/pkg/errors"
-)
-
-// Handler .
-type Handler struct {
- guestID string
- subnet int64
-}
-
-// New .
-func New(guestID string, subnet int64) *Handler {
- return &Handler{guestID: guestID, subnet: subnet}
-}
-
-// NewIP .
-func (h *Handler) NewIP(_, _ string) (meta.IP, error) {
- return nil, errors.Trace(errors.ErrNotImplemented)
-}
-
-// AssignIP .
-func (h *Handler) AssignIP() (meta.IP, error) {
- return h.ipam().Assign(context.Background())
-}
-
-// ReleaseIPs .
-func (h *Handler) ReleaseIPs(ips ...meta.IP) error {
- return h.ipam().Release(context.Background(), ips...)
-}
-
-// QueryIPs .
-func (h *Handler) QueryIPs(ipns meta.IPNets) ([]meta.IP, error) {
- return h.ipam().Query(context.Background(), ipns)
-}
-
-func (h *Handler) ipam() ipam.Ipam {
- return vlannet.NewIpam(h.guestID, h.subnet)
-}
-
-// CreateEndpointNetwork .
-func (h *Handler) CreateEndpointNetwork(types.EndpointArgs) (resp types.EndpointArgs, rollback func(), err error) {
- return
-}
-
-// JoinEndpointNetwork .
-func (h *Handler) JoinEndpointNetwork(types.EndpointArgs) (rollback func(), err error) {
- // DO NOTHING
- return
-}
-
-// DeleteEndpointNetwork .
-func (h *Handler) DeleteEndpointNetwork(types.EndpointArgs) error {
- // DO NOTHING
- return nil
-}
-
-// GetEndpointDevice .
-func (h *Handler) GetEndpointDevice(string) (device.VirtLink, error) {
- // DO NOTHING
- return nil, nil
-}
-
-// QueryIPv4 .
-func (h *Handler) QueryIPv4(string) (meta.IP, error) {
- return nil, errors.Trace(errors.ErrNotImplemented)
-}
-
-// GetCidr .
-func (h *Handler) GetCidr() string {
- ip := vlannet.IP{Value: h.subnet, Subnet: &vlannet.Subnet{SubnetPrefix: 0}}
- return ip.CIDR()
-}
diff --git a/internal/vnet/ipam/ipam.go b/internal/vnet/ipam/ipam.go
deleted file mode 100644
index 4617341..0000000
--- a/internal/vnet/ipam/ipam.go
+++ /dev/null
@@ -1,14 +0,0 @@
-package ipam
-
-import (
- "context"
-
- "github.com/projecteru2/yavirt/internal/meta"
-)
-
-// Ipam .
-type Ipam interface {
- Assign(ctx context.Context) (meta.IP, error)
- Release(context.Context, ...meta.IP) error
- Query(context.Context, meta.IPNets) ([]meta.IP, error)
-}
diff --git a/internal/vnet/types/types.go b/internal/vnet/types/types.go
deleted file mode 100644
index 8cf7490..0000000
--- a/internal/vnet/types/types.go
+++ /dev/null
@@ -1,42 +0,0 @@
-package types
-
-import (
- "github.com/projecteru2/yavirt/internal/meta"
- "github.com/projecteru2/yavirt/internal/vnet/device"
- "github.com/projecteru2/yavirt/pkg/errors"
-)
-
-// EndpointArgs .
-type EndpointArgs struct {
- EndpointID string
- IPs []meta.IP
- Device device.VirtLink
- MAC string
- Hostname string
- ResourceVersion string
- UID string
- Profiles []string
-}
-
-// Check .
-func (a EndpointArgs) Check() error {
- switch {
- case len(a.EndpointID) < 1:
- return errors.Annotatef(errors.ErrInvalidValue, "EndpointID is empty")
-
- case len(a.IPs) < 1:
- return errors.Annotatef(errors.ErrInvalidValue, "IPs is empty")
-
- case a.Device == nil:
- return errors.Annotatef(errors.ErrInvalidValue, "Device is nil")
-
- case len(a.MAC) < 1:
- return errors.Annotatef(errors.ErrInvalidValue, "MAC is empty")
-
- case len(a.Hostname) < 1:
- return errors.Annotatef(errors.ErrInvalidValue, "Hostname is empty")
-
- default:
- return nil
- }
-}
diff --git a/internal/volume/base/mocks/SnapshotAPI.go b/internal/volume/base/mocks/SnapshotAPI.go
new file mode 100644
index 0000000..48b3298
--- /dev/null
+++ b/internal/volume/base/mocks/SnapshotAPI.go
@@ -0,0 +1,156 @@
+// Code generated by mockery v2.26.1. DO NOT EDIT.
+
+package mocks
+
+import (
+ base "github.com/projecteru2/yavirt/internal/volume/base"
+ mock "github.com/stretchr/testify/mock"
+)
+
+// SnapshotAPI is an autogenerated mock type for the SnapshotAPI type
+type SnapshotAPI struct {
+ mock.Mock
+}
+
+// Commit provides a mock function with given fields: rootID
+func (_m *SnapshotAPI) Commit(rootID string) error {
+ ret := _m.Called(rootID)
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(string) error); ok {
+ r0 = rf(rootID)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// CommitByDay provides a mock function with given fields: day
+func (_m *SnapshotAPI) CommitByDay(day int) error {
+ ret := _m.Called(day)
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(int) error); ok {
+ r0 = rf(day)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// Create provides a mock function with given fields:
+func (_m *SnapshotAPI) Create() error {
+ ret := _m.Called()
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func() error); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// Delete provides a mock function with given fields: id
+func (_m *SnapshotAPI) Delete(id string) error {
+ ret := _m.Called(id)
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(string) error); ok {
+ r0 = rf(id)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// DeleteAll provides a mock function with given fields:
+func (_m *SnapshotAPI) DeleteAll() error {
+ ret := _m.Called()
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func() error); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// Download provides a mock function with given fields: id
+func (_m *SnapshotAPI) Download(id string) error {
+ ret := _m.Called(id)
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(string) error); ok {
+ r0 = rf(id)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// List provides a mock function with given fields:
+func (_m *SnapshotAPI) List() base.Snapshots {
+ ret := _m.Called()
+
+ var r0 base.Snapshots
+ if rf, ok := ret.Get(0).(func() base.Snapshots); ok {
+ r0 = rf()
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(base.Snapshots)
+ }
+ }
+
+ return r0
+}
+
+// Restore provides a mock function with given fields: rootID
+func (_m *SnapshotAPI) Restore(rootID string) error {
+ ret := _m.Called(rootID)
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(string) error); ok {
+ r0 = rf(rootID)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// Upload provides a mock function with given fields: id, force
+func (_m *SnapshotAPI) Upload(id string, force bool) error {
+ ret := _m.Called(id, force)
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(string, bool) error); ok {
+ r0 = rf(id, force)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+type mockConstructorTestingTNewSnapshotAPI interface {
+ mock.TestingT
+ Cleanup(func())
+}
+
+// NewSnapshotAPI creates a new instance of SnapshotAPI. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+func NewSnapshotAPI(t mockConstructorTestingTNewSnapshotAPI) *SnapshotAPI {
+ mock := &SnapshotAPI{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/internal/volume/base/option.go b/internal/volume/base/option.go
new file mode 100644
index 0000000..45fabf2
--- /dev/null
+++ b/internal/volume/base/option.go
@@ -0,0 +1,12 @@
+package base
+
+type Option func(o *OptionValue)
+type OptionValue struct {
+ Snapshot string
+}
+
+func WithSnapshot(snapshot string) Option {
+ return func(o *OptionValue) {
+ o.Snapshot = snapshot
+ }
+}
diff --git a/internal/volume/base/snapshot.go b/internal/volume/base/snapshot.go
new file mode 100644
index 0000000..d7bbd66
--- /dev/null
+++ b/internal/volume/base/snapshot.go
@@ -0,0 +1,22 @@
+package base
+
+import "github.com/projecteru2/yavirt/internal/meta"
+
+// SnapshotAPI .
+type SnapshotAPI interface {
+ List() Snapshots
+ Create() error
+ Commit(rootID string) error
+ CommitByDay(day int) error
+ Delete(id string) error
+ DeleteAll() error
+ Restore(rootID string) error
+ Upload(id string, force bool) error
+ Download(id string) error
+}
+
+type Snapshot interface {
+ meta.GenericInterface
+}
+
+type Snapshots []Snapshot
diff --git a/internal/volume/base/util.go b/internal/volume/base/util.go
new file mode 100644
index 0000000..da460b5
--- /dev/null
+++ b/internal/volume/base/util.go
@@ -0,0 +1,245 @@
+package base
+
+import (
+ "context"
+ "fmt"
+ "path/filepath"
+ "regexp"
+ "strings"
+
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/yavirt/internal/types"
+ "github.com/projecteru2/yavirt/internal/virt/agent"
+ "github.com/projecteru2/yavirt/internal/virt/guestfs"
+ "github.com/projecteru2/yavirt/internal/virt/nic"
+ "github.com/projecteru2/yavirt/pkg/utils"
+)
+
+func ResetFstab(gfs guestfs.Guestfs) error {
+ origFstabEntries, err := gfs.GetFstabEntries()
+ if err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ blkids, err := gfs.GetBlkids()
+ if err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ var cont string
+ for dev, entry := range origFstabEntries {
+ if blkids.Exists(dev) {
+ cont += fmt.Sprintf("%s\n", strings.TrimSpace(entry))
+ }
+ }
+
+ return gfs.Write(types.FstabFile, cont)
+}
+
+func ResetUserImage(gfs guestfs.Guestfs) error {
+ if err := ResetFstab(gfs); err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ return resetEth0(gfs)
+}
+
+func resetEth0(gfs guestfs.Guestfs) error {
+ distro, err := gfs.Distro()
+ if err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ path, err := nic.GetEthFile(distro, "eth0")
+ if err != nil {
+ return errors.Wrap(err, "")
+ }
+ return gfs.Remove(path)
+}
+
+// GetDevicePathByName .
+func GetDevicePathByName(name string) string {
+ return filepath.Join("/dev", name)
+}
+
+// GetDeviceName .
+func GetDeviceName(sn int) string {
+ return fmt.Sprintf("vd%s", string(utils.LowerLetters[sn]))
+}
+
+func GetDevicePathBySerialNumber(sn int) string {
+ return GetDevicePathByName(GetDeviceName(sn))
+}
+
+// Resize root partition
+// mainly used to expand system volumn
+func ResizeRootPartition(ctx context.Context, ga agent.Interface, devPath string) error {
+ var st = <-ga.ExecOutput(ctx, "df")
+ so, se, err := st.Stdio()
+ if err != nil {
+ return errors.Wrapf(err, "run `df` failed: %s", string(se))
+ }
+ lines := strings.Split(string(so), "\n")
+ rootDev := ""
+ pidx := "" // partiton index
+ for _, line := range lines {
+ parts := strings.Fields(line)
+ if len(parts) != 6 {
+ continue
+ }
+ if parts[5] == "/" {
+ rootDev = parts[0]
+ }
+ }
+ if len(rootDev) > 0 {
+ idx := len(rootDev) - 1
+ for idx >= 0 {
+ if rootDev[idx] >= '0' && rootDev[idx] <= '9' {
+ idx--
+ }
+ }
+ devPath = rootDev[:idx+1]
+ pidx = rootDev[idx+1:]
+ }
+ if len(rootDev) == 0 || len(pidx) == 0 {
+ return errors.Errorf("Can't find root dev or sn: %s", rootDev)
+ }
+ var cmds = [][]string{
+ // {"parted", "-s", devPath, "resizepart", pidx, "100%"},
+ // Just need to run `parted devPath resizepart pidx 100%`, but parted prompt,so use pipeline here
+ {"bash", "-c", fmt.Sprintf("echo 'Y' | sudo parted ---pretend-input-tty %s resizepart %s %s", devPath, pidx, "100%")},
+ {"resize2fs", rootDev},
+ }
+ return ExecCommands(ctx, ga, cmds)
+}
+
+func ExecCommands(ctx context.Context, ga agent.Interface, cmds [][]string) error {
+ for _, args := range cmds {
+ var st = <-ga.ExecOutput(ctx, args[0], args[1:]...)
+ if err := st.Error(); err != nil {
+ return errors.Wrapf(err, "%v", args)
+ }
+ }
+ return nil
+}
+
+func StopSystemdService(ctx context.Context, ga agent.Interface, serviceName string) error {
+ var st = <-ga.Exec(ctx, "systemctl", "stop", serviceName)
+ if err := st.Error(); err != nil {
+ return errors.Wrapf(err, "systemctl stop %s failed", serviceName)
+ }
+
+ return nil
+}
+
+func RestartSystemdServices(ctx context.Context, ga agent.Interface, stoppedServices []string) error {
+ for _, serviceName := range stoppedServices {
+ var st = <-ga.Exec(ctx, "systemctl", "start", serviceName)
+ if err := st.Error(); err != nil {
+ return errors.Wrapf(err, "systemctl start %s failed", serviceName)
+ }
+ }
+ return nil
+}
+
+func StopSystemdServices(ctx context.Context, ga agent.Interface, devPath string) ([]string, error) {
+ var st = <-ga.ExecOutput(ctx, "fuser", "-m", devPath)
+ so, se, err := st.Stdio()
+ if err != nil && (len(so) > 0 || len(se) > 0) { // Fuser return status code 1 if no process running
+ return nil, errors.Wrapf(err, "fuser on %s failed", devPath)
+ }
+
+ re := regexp.MustCompile(`[0-9]+`)
+ pids := re.FindAllString(string(so), -1)
+
+ var stoppedServices []string
+ for _, pid := range pids {
+ switch serviceName, err := findService(ctx, ga, pid); {
+ case err != nil:
+ return nil, errors.Wrap(err, "")
+
+ case len(serviceName) > 0:
+ if err := StopSystemdService(ctx, ga, serviceName); err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ stoppedServices = append(stoppedServices, serviceName)
+
+ default:
+ continue
+ }
+ }
+
+ return stoppedServices, nil
+}
+
+func findService(ctx context.Context, ga agent.Interface, pid string) (string, error) {
+ for {
+ switch name, se := getServiceNameByPid(ctx, ga, pid); {
+ case strings.HasPrefix(se, "Failed "): // Doesn't exist systemd unit with this pid
+ ppid, err := getPpid(ctx, ga, pid)
+ if err != nil {
+ return "", errors.Wrap(err, "")
+ }
+ pid = ppid
+
+ case len(name) > 0:
+ switch valid, err := isService(ctx, ga, name); {
+ case err != nil:
+ return "", errors.Wrap(err, "")
+
+ case valid:
+ return name, nil
+
+ default: // unit with this pid exist but not service type
+ return "", nil
+ }
+
+ default:
+ return "", nil
+ }
+ }
+}
+
+func getPpid(ctx context.Context, ga agent.Interface, pid string) (string, error) {
+ var st = <-ga.ExecOutput(ctx, "ps", "--ppid", pid)
+ so, _, err := st.Stdio()
+ if err != nil {
+ return "", errors.Wrapf(err, "find ppid for %s failed", pid)
+ }
+ if len(so) == 0 {
+ return "", errors.Newf("ppid for %s is empty", pid)
+ }
+ return string(so), nil
+}
+
+func getServiceNameByPid(ctx context.Context, ga agent.Interface, pid string) (string, string) {
+ var st = <-ga.ExecOutput(ctx, "systemctl", "status", pid)
+ so, se, err := st.Stdio()
+ if err != nil {
+ return "", string(se) // No service with this pid or service is stopped/failed
+ }
+ soSplit := strings.Fields(string(so))
+ if len(soSplit) < 2 || len(soSplit[1]) == 0 {
+ return "", ""
+ }
+ return soSplit[1], string(se)
+}
+
+func isService(ctx context.Context, ga agent.Interface, unitName string) (bool, error) {
+ var st = <-ga.ExecOutput(ctx, "systemctl", "list-units", "--all", "-t", "service",
+ "--full", "--no-legend", unitName)
+
+ so, se, err := st.Stdio()
+ if err != nil {
+ if len(so) > 0 || len(se) > 0 {
+ return false, errors.Wrapf(err, "systemctl check service %s failed", unitName)
+ }
+ return false, nil // Not found service with name unitName but not considered as error
+ }
+ soSplit := strings.Fields(string(so))
+ if len(soSplit) < 1 {
+ return false, errors.Newf("systemctl check service %s wrong output", unitName)
+ }
+
+ return true, nil
+}
diff --git a/internal/volume/base/volume.go b/internal/volume/base/volume.go
new file mode 100644
index 0000000..cea59cb
--- /dev/null
+++ b/internal/volume/base/volume.go
@@ -0,0 +1,69 @@
+package base
+
+import (
+ "context"
+
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/yavirt/internal/meta"
+ "github.com/projecteru2/yavirt/pkg/idgen"
+ "github.com/projecteru2/yavirt/pkg/store"
+)
+
+type Volume struct {
+ *meta.Generic `mapstructure:",squash"`
+
+ SysImage string `json:"sys_image,omitempty" mapstructure:"sys_image"` // for sys volume
+ Device string `json:"device" mapstructure:"device"` // vda, vdb, vdc etc.
+ Hostname string `json:"host" mapstructure:"host"`
+ GuestID string `json:"guest" mapstructure:"guest"`
+}
+
+func New() *Volume {
+ return &Volume{
+ Generic: meta.NewGeneric(),
+ }
+}
+
+// GenerateID .
+func (v *Volume) GenerateID() {
+ v.ID = idgen.Next()
+}
+
+func (v *Volume) GetDevice() string {
+ return v.Device
+}
+
+func (v *Volume) SetDevice(dev string) {
+ v.Device = dev
+}
+
+func (v *Volume) SetHostname(name string) {
+ v.Hostname = name
+}
+
+func (v *Volume) GetHostname() string {
+ return v.Hostname
+}
+
+func (v *Volume) SetGuestID(id string) {
+ v.GuestID = id
+}
+
+func (v *Volume) GetGuestID() string {
+ return v.GuestID
+}
+
+// Delete .
+func (v *Volume) Delete(force bool) error {
+ if err := v.SetStatus(meta.StatusDestroyed, force); err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ keys := []string{v.MetaKey()}
+ vers := map[string]int64{v.MetaKey(): v.GetVer()}
+
+ ctx, cancel := meta.Context(context.Background())
+ defer cancel()
+
+ return store.Delete(ctx, keys, vers)
+}
diff --git a/internal/volume/factory/factory.go b/internal/volume/factory/factory.go
new file mode 100644
index 0000000..520a3c9
--- /dev/null
+++ b/internal/volume/factory/factory.go
@@ -0,0 +1,58 @@
+package factory
+
+import (
+ "context"
+
+ "github.com/mitchellh/mapstructure"
+ "github.com/pkg/errors"
+ "github.com/projecteru2/core/log"
+ "github.com/projecteru2/yavirt/internal/meta"
+ gfsmocks "github.com/projecteru2/yavirt/internal/virt/guestfs/mocks"
+ "github.com/projecteru2/yavirt/internal/volume"
+ "github.com/projecteru2/yavirt/internal/volume/base"
+ "github.com/projecteru2/yavirt/internal/volume/local"
+ "github.com/projecteru2/yavirt/internal/volume/rbd"
+ "github.com/projecteru2/yavirt/pkg/utils"
+)
+
+func LoadVolumes(ids []string) (vols Volumes, err error) {
+ logger := log.WithFunc("volume.factory.LoadVolumes")
+ vols = make(Volumes, len(ids))
+
+ for i, id := range ids {
+ key := meta.VolumeKey(id)
+ rawVal, ver, err := meta.LoadRaw(key)
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ var vol volume.Volume
+ if _, ok := rawVal["pool"]; ok {
+ vol = rbd.New()
+ } else {
+ vol = local.NewVolume()
+ }
+
+ if err := mapstructure.Decode(rawVal, &vol); err != nil {
+ return vols, err
+ }
+ vol.SetVer(ver)
+ // FIXME: just for compatibility, when all existing volumes contain device filed,
+ // we can delete the following code
+ if vol.GetDevice() == "" {
+ logger.Warnf(context.TODO(), "[BUG] volume(%s) has no device", vol.GetID())
+ vol.SetDevice(base.GetDeviceName(i))
+ if err := vol.Save(); err != nil {
+ logger.Errorf(context.TODO(), err, "Failed to save volume(%v)", vol)
+ }
+ }
+ vols[i] = vol
+ }
+ return vols, nil
+}
+
+// NewMockedVolume for unit test.
+func NewMockedVolume() (volume.Volume, *gfsmocks.Guestfs) {
+ gfs := &gfsmocks.Guestfs{}
+ vol := local.NewSysVolume(utils.GB, "unitest-image")
+ return vol, gfs
+}
diff --git a/internal/volume/factory/factory_test.go b/internal/volume/factory/factory_test.go
new file mode 100644
index 0000000..e926f02
--- /dev/null
+++ b/internal/volume/factory/factory_test.go
@@ -0,0 +1,100 @@
+package factory
+
+import (
+ "fmt"
+ "math/rand"
+ "testing"
+ "time"
+
+ "github.com/projecteru2/yavirt/configs"
+ "github.com/projecteru2/yavirt/internal/volume/local"
+ "github.com/projecteru2/yavirt/internal/volume/rbd"
+ "github.com/projecteru2/yavirt/pkg/idgen"
+ "github.com/projecteru2/yavirt/pkg/store"
+ "github.com/projecteru2/yavirt/pkg/test/assert"
+ "github.com/projecteru2/yavirt/pkg/utils"
+)
+
+func TestLoadVolumes(t *testing.T) {
+ idgen.Setup(111)
+ err := store.Setup(configs.Conf, t)
+ assert.NilErr(t, err)
+ v1Str := "/src:/dst:rw:1G:1:2:3:4"
+ v2Str := "pool/image:/dst:rw:1G:1:2:3:4"
+ v1, err := local.NewVolumeFromStr(v1Str)
+ assert.NilErr(t, err)
+ v2, err := rbd.NewFromStr(v2Str)
+ assert.NilErr(t, err)
+ v1.GenerateID()
+ v2.GenerateID()
+ err = v1.Save()
+ assert.NilErr(t, err)
+ err = v2.Save()
+ assert.NilErr(t, err)
+
+ vols, err := LoadVolumes([]string{v1.ID, v2.ID})
+ assert.NilErr(t, err)
+ assert.Equal(t, 2, len(vols))
+
+ vv1, ok := vols[0].(*local.Volume)
+ assert.True(t, ok)
+ assert.Equal(t, v1.ID, vv1.ID)
+ assert.Equal(t, "/src", vv1.Source)
+ assert.Equal(t, "/dst", vv1.Destination)
+ assert.Equal(t, utils.GB, vv1.SizeInBytes)
+ assert.Equal(t, int64(1), vv1.ReadIOPS)
+ assert.Equal(t, int64(2), vv1.WriteIOPS)
+ assert.Equal(t, int64(3), vv1.ReadBPS)
+ assert.Equal(t, int64(4), vv1.WriteBPS)
+
+ vv2, ok := vols[1].(*rbd.Volume)
+ assert.True(t, ok)
+ assert.Equal(t, v2.ID, vv2.ID)
+ assert.Equal(t, "pool", vv2.Pool)
+ assert.Equal(t, "image", vv2.Image)
+ assert.Equal(t, "/dst", vv2.Destination)
+ assert.Equal(t, utils.GB, vv1.SizeInBytes)
+ assert.Equal(t, int64(1), vv2.ReadIOPS)
+ assert.Equal(t, int64(2), vv2.WriteIOPS)
+ assert.Equal(t, int64(3), vv2.ReadBPS)
+ assert.Equal(t, int64(4), vv2.WriteBPS)
+}
+
+func TestVolumes(t *testing.T) {
+ idgen.Setup(111)
+ err := store.Setup(configs.Conf, t)
+ assert.NilErr(t, err)
+ var ids []string
+ for i := 0; i < 5; i++ {
+ v1Str := fmt.Sprintf("/src%d:/dst%d:rw:1G", i, 2*i)
+ v2Str := fmt.Sprintf("pool/image%d:/dst%d:rw:1G", i, 2*i+1)
+ v1, err := local.NewVolumeFromStr(v1Str)
+ assert.NilErr(t, err)
+ v2, err := rbd.NewFromStr(v2Str)
+ assert.NilErr(t, err)
+ v1.GenerateID()
+ v2.GenerateID()
+ err = v1.Save()
+ assert.NilErr(t, err)
+ err = v2.Save()
+ assert.NilErr(t, err)
+ ids = append(ids, v1.ID)
+ ids = append(ids, v2.ID)
+ }
+ vols, err := LoadVolumes(ids)
+ assert.Equal(t, 10, vols.Len())
+ assert.Equal(t, ids, vols.IDs())
+ rand.Seed(time.Now().Unix()) // initialize global pseudo random generator
+ randID := ids[rand.Intn(len(ids))]
+ vol, err := vols.Find(randID)
+ assert.NilErr(t, err)
+ assert.True(t, vols.Exists(vol.GetMountDir()))
+
+ vol, err = vols.GetMntVol("/dst9/haha")
+ assert.NilErr(t, err)
+ assert.Equal(t, "/dst9", vol.GetMountDir())
+
+ vol, err = vols.GetMntVol("/dst10/haha")
+ assert.NilErr(t, err)
+ assert.Nil(t, vol)
+}
diff --git a/internal/volume/factory/guest.go b/internal/volume/factory/guest.go
new file mode 100644
index 0000000..35be86d
--- /dev/null
+++ b/internal/volume/factory/guest.go
@@ -0,0 +1,397 @@
+package factory
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "path/filepath"
+ "strings"
+
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/core/log"
+ "github.com/projecteru2/yavirt/configs"
+ "github.com/projecteru2/yavirt/internal/types"
+ interutils "github.com/projecteru2/yavirt/internal/utils"
+ "github.com/projecteru2/yavirt/internal/virt/agent"
+ "github.com/projecteru2/yavirt/internal/volume"
+ "github.com/projecteru2/yavirt/internal/volume/base"
+ "github.com/projecteru2/yavirt/pkg/libvirt"
+ "github.com/projecteru2/yavirt/pkg/terrors"
+ "github.com/projecteru2/yavirt/pkg/utils"
+)
+
+const (
+ fs = "ext4"
+ // Disable backing up of the device/partition
+ backupDump = 0
+ // Enable fsck checking the device/partition for errors at boot time.
+ fsckPass = 2
+)
+
+// Undefine .
+func Undefine(vol volume.Volume) error {
+ if err := vol.Lock(); err != nil {
+ return errors.Wrap(err, "")
+ }
+ defer vol.Unlock()
+
+ api := vol.NewSnapshotAPI()
+ if err := api.DeleteAll(); err != nil {
+ return errors.Wrap(err, "")
+ }
+ if err := vol.Cleanup(); err != nil {
+ return errors.Wrap(err, "")
+ }
+ return nil
+}
+
+func Create(vol volume.Volume) (func(), error) {
+ if err := volume.WithLocker(vol, func() error {
+ return vol.PrepareDataDisk(context.TODO())
+ }); err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+
+ if err := vol.Save(); err != nil {
+ if ue := Undefine(vol); ue != nil {
+ err = errors.CombineErrors(err, ue)
+ }
+ return nil, errors.Wrap(err, "")
+ }
+
+ rb := func() {
+ if err := Undefine(vol); err != nil {
+ log.WithFunc("volume.Create").Error(context.TODO(), err)
+ return
+ }
+ if err := vol.Delete(true); err != nil {
+ log.WithFunc("volume.Create").Error(context.TODO(), err)
+ }
+ }
+
+ return rb, nil
+}
+
+// Amplify .
+func Amplify(vol volume.Volume, delta int64, dom libvirt.Domain, ga agent.Interface, devPath string) (normDelta int64, err error) {
+ if err := vol.Lock(); err != nil {
+ return 0, errors.Wrap(err, "")
+ }
+ defer vol.Unlock()
+
+ normDelta = utils.NormalizeMultiple1024(delta)
+ sizeInBytes := vol.GetSize()
+ newCap := sizeInBytes + normDelta
+ if newCap > configs.Conf.Resource.MaxVolumeCap {
+ return 0, errors.Wrapf(terrors.ErrInvalidValue, "exceeds the max cap: %d", configs.Conf.Resource.MaxVolumeCap)
+ }
+
+ least := utils.Max(
+ configs.Conf.ResizeVolumeMinSize,
+ int64(float64(sizeInBytes)*configs.Conf.ResizeVolumeMinRatio),
+ )
+ if least > normDelta {
+ return 0, errors.Wrapf(terrors.ErrInvalidValue, "invalid cap: at least %d, but %d",
+ sizeInBytes+least, sizeInBytes+normDelta)
+ }
+
+ st, err := dom.GetState()
+ if err != nil {
+ return 0, errors.Wrap(err, "")
+ }
+ switch st {
+ case libvirt.DomainShutoff:
+ err = interutils.AmplifyImage(context.Background(), vol.QemuImagePath(), delta)
+ case libvirt.DomainRunning:
+ err = amplifyOnline(newCap, dom, ga, devPath)
+ default:
+ err = types.NewDomainStatesErr(st, libvirt.DomainShutoff, libvirt.DomainRunning)
+ }
+ if err != nil {
+ return 0, err
+ }
+
+ vol.SetSize(newCap)
+ return normDelta, vol.Save()
+}
+
+// Check .
+func Check(vol volume.Volume) error {
+ if err := vol.Lock(); err != nil {
+ return errors.Wrap(err, "")
+ }
+ defer vol.Unlock()
+
+ return vol.Check()
+}
+
+// Repair .
+func Repair(vol volume.Volume) error {
+ if err := vol.Lock(); err != nil {
+ return errors.Wrap(err, "")
+ }
+ defer vol.Unlock()
+
+ return vol.Repair()
+}
+
+// CreateSnapshot .
+func CreateSnapshot(vol volume.Volume) error {
+ if err := vol.Lock(); err != nil {
+ return errors.Wrap(err, "")
+ }
+ defer vol.Unlock()
+
+ api := vol.NewSnapshotAPI()
+ return api.Create()
+}
+
+// CommitSnapshot .
+func CommitSnapshot(vol volume.Volume, snapID string) error {
+ if err := vol.Lock(); err != nil {
+ return errors.Wrap(err, "")
+ }
+ defer vol.Unlock()
+
+ api := vol.NewSnapshotAPI()
+ return api.Commit(snapID)
+}
+
+// CommitSnapshotByDay Commit snapshots created `day` days ago.
+func CommitSnapshotByDay(vol volume.Volume, day int) error {
+ if err := vol.Lock(); err != nil {
+ return errors.Wrap(err, "")
+ }
+ defer vol.Unlock()
+
+ api := vol.NewSnapshotAPI()
+ return api.CommitByDay(day)
+}
+
+// RestoreSnapshot .
+func RestoreSnapshot(vol volume.Volume, snapID string) error {
+ if err := vol.Lock(); err != nil {
+ return errors.Wrap(err, "")
+ }
+ defer vol.Unlock()
+
+ api := vol.NewSnapshotAPI()
+ return api.Restore(snapID)
+}
+
+// for ceph, before create snapshot, we need run fsfreeze
+func FSFreeze(ctx context.Context, ga agent.Interface, v volume.Volume, unfreeze bool) error {
+ var cmd []string
+ if unfreeze {
+ cmd = []string{"fsfreeze", "--unfreeze", v.GetMountDir()}
+ } else {
+ cmd = []string{"fsfreeze", "--freeze", v.GetMountDir()}
+ }
+ var st = <-ga.ExecOutput(ctx, cmd[0], cmd[1:]...)
+ if err := st.Error(); err != nil {
+ return errors.Wrapf(err, "%v", cmd)
+ }
+ return nil
+}
+
+// Unmount .
+func Unmount(vol volume.Volume, ga agent.Interface, devPath string) error {
+ if err := vol.Lock(); err != nil {
+ return errors.Wrap(err, "")
+ }
+ defer vol.Unlock()
+
+ var ctx, cancel = context.WithTimeout(context.Background(), configs.Conf.GADiskTimeout)
+ defer cancel()
+
+ log.WithFunc("volume.Umount").Debugf(ctx, "Umount: umount %s", devPath)
+ cmds := []string{"umount", devPath}
+ st := <-ga.ExecOutput(ctx, cmds[0], cmds[1:]...)
+ if err := st.Error(); err != nil {
+ log.WithFunc("volume.Umount").Warnf(ctx, "failed to run `%s`: %s", strings.Join(cmds, " "), err)
+ }
+
+ log.Debugf(ctx, "Umount: save fstab")
+ escapeDir := strings.ReplaceAll(vol.GetMountDir(), "/", "\\/")
+ regex := fmt.Sprintf("/%s/d", escapeDir)
+ cmds = []string{"sed", "-i", regex, "/etc/fstab"}
+ st = <-ga.ExecOutput(ctx, cmds[0], cmds[1:]...)
+ if err := st.Error(); err != nil {
+ return errors.Wrapf(err, "failed to run `%v`", strings.Join(cmds, " "))
+ }
+ return nil
+
+}
+
+// Mount .
+func Mount(vol volume.Volume, ga agent.Interface, devPath string) error {
+ if err := vol.Lock(); err != nil {
+ return errors.Wrap(err, "")
+ }
+ defer vol.Unlock()
+
+ var ctx, cancel = context.WithTimeout(context.Background(), configs.Conf.GADiskTimeout)
+ defer cancel()
+
+ log.Debugf(ctx, "Mount: format")
+ if err := format(ctx, ga, vol, devPath); err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ log.Debugf(ctx, "Mount: mount")
+ if err := mount(ctx, ga, vol, devPath); err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ log.Debugf(ctx, "Mount: save fstab")
+ if err := saveFstab(ctx, ga, vol, devPath); err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ log.Debugf(ctx, "Mount: amplify if necessary")
+ switch amplified, err := isAmplifying(ctx, ga, vol, devPath); {
+ case err != nil:
+ return errors.Wrap(err, "")
+
+ case amplified:
+ return amplifyDiskInGuest(ctx, ga, devPath)
+
+ default:
+ return nil
+ }
+}
+
+func mount(ctx context.Context, ga agent.Interface, v volume.Volume, devPath string) error {
+ var mnt = v.GetMountDir()
+ var st = <-ga.Exec(ctx, "mkdir", "-p", mnt)
+ if err := st.Error(); err != nil {
+ return errors.Wrapf(err, "mkdir %s failed", mnt)
+ }
+
+ st = <-ga.ExecOutput(ctx, "mount", "-t", fs, devPath, mnt)
+ _, _, err := st.CheckStdio(func(_, se []byte) bool {
+ return bytes.Contains(se, []byte("already mounted"))
+ })
+ if err != nil {
+ return errors.Wrapf(err, "mount %s failed", mnt)
+ }
+ return nil
+}
+
+func saveFstab(ctx context.Context, ga agent.Interface, v volume.Volume, devPath string) error {
+ var blkid, err = ga.Blkid(ctx, devPath)
+ if err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ switch exists, err := ga.Grep(ctx, blkid, types.FstabFile); {
+ case err != nil:
+ return errors.Wrap(err, "")
+ case exists:
+ return nil
+ }
+
+ var line = fmt.Sprintf("\nUUID=%s %s %s defaults %d %d",
+ blkid, v.GetMountDir(), fs, backupDump, fsckPass)
+
+ return ga.AppendLine(ctx, types.FstabFile, []byte(line))
+}
+
+func format(ctx context.Context, ga agent.Interface, v volume.Volume, devPath string) error {
+ switch formatted, err := isFormatted(ctx, ga, v); {
+ case err != nil:
+ return errors.Wrap(err, "")
+ case formatted:
+ return nil
+ }
+
+ if err := fdisk(ctx, ga, devPath); err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ return ga.Touch(ctx, formattedFlagPath(v))
+}
+
+// parted -s /dev/vdN mklabel gpt
+// parted -s /dev/vdN mkpart primary 1049K -- -1
+// mkfs -F -t ext4 /dev/vdN
+func fdisk(ctx context.Context, ga agent.Interface, devPath string) error {
+ var cmds = [][]string{
+ {"parted", "-s", devPath, "mklabel", "gpt"},
+ {"parted", "-s", devPath, "mkpart", "primary", "1049K", "--", "-1"},
+ {"mkfs", "-F", "-t", fs, devPath},
+ }
+ return base.ExecCommands(ctx, ga, cmds)
+}
+
+func isFormatted(ctx context.Context, ga agent.Interface, v volume.Volume) (bool, error) {
+ return ga.IsFile(ctx, formattedFlagPath(v))
+}
+
+func formattedFlagPath(v volume.Volume) string {
+ return fmt.Sprintf("/etc/%s", v.Name())
+}
+
+func isAmplifying(ctx context.Context, ga agent.Interface, v volume.Volume, devPath string) (bool, error) {
+ mbs, err := getMountedBlocks(ctx, ga, v)
+ if err != nil {
+ return false, errors.Wrap(err, "")
+ }
+
+ cap, err := agent.NewParted(ga, devPath).GetSize(ctx) //nolint
+ if err != nil {
+ return false, errors.Wrap(err, "")
+ }
+
+ mbs = int64(float64(mbs) * (1 + configs.Conf.ResizeVolumeMinRatio))
+ cap >>= 10 //nolint // in bytes, aka. 1K-blocks.
+
+ return cap > mbs, nil
+}
+
+func getMountedBlocks(ctx context.Context, ga agent.Interface, v volume.Volume) (int64, error) {
+ df, err := ga.GetDiskfree(ctx, v.GetMountDir())
+ if err != nil {
+ return 0, errors.Wrap(err, "")
+ }
+ return df.Blocks, nil
+}
+
+func amplifyOnline(newCap int64, dom libvirt.Domain, ga agent.Interface, devPath string) error {
+ devname := filepath.Base(devPath)
+ if err := dom.AmplifyVolume(devname, uint64(newCap)); err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ ctx, cancel := context.WithTimeout(context.Background(), configs.Conf.GADiskTimeout)
+ defer cancel()
+ return amplifyDiskInGuest(ctx, ga, devPath)
+}
+
+func amplifyDiskInGuest(ctx context.Context, ga agent.Interface, devPath string) error {
+ // NOTICE:
+ // Actually, volume raw devices aren't necessary for re-parting.
+
+ stoppedServices, err := base.StopSystemdServices(ctx, ga, devPath)
+ if err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ cmds := [][]string{
+ {"umount", devPath},
+ {"partprobe"},
+ {"e2fsck", "-fy", devPath},
+ {"resize2fs", devPath},
+ {"mount", "-a"},
+ }
+
+ if err := base.ExecCommands(ctx, ga, cmds); err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ if err := base.RestartSystemdServices(ctx, ga, stoppedServices); err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ return nil
+}
diff --git a/internal/volume/factory/volumes.go b/internal/volume/factory/volumes.go
new file mode 100644
index 0000000..1127a65
--- /dev/null
+++ b/internal/volume/factory/volumes.go
@@ -0,0 +1,157 @@
+package factory
+
+import (
+ "path/filepath"
+ "strings"
+
+ "github.com/pkg/errors"
+ "github.com/projecteru2/yavirt/internal/meta"
+ "github.com/projecteru2/yavirt/internal/volume"
+ "github.com/projecteru2/yavirt/internal/volume/base"
+ "github.com/projecteru2/yavirt/internal/volume/mocks"
+ "github.com/projecteru2/yavirt/pkg/terrors"
+)
+
+type Volumes []volume.Volume
+
+// Check .
+func (vols Volumes) Check() error {
+ for _, v := range vols {
+ if v == nil {
+ return errors.Wrapf(terrors.ErrInvalidValue, "nil *Volume")
+ }
+ if err := v.Check(); err != nil {
+ return errors.Wrap(err, "")
+ }
+ }
+ return nil
+}
+
+// Find .
+func (vols Volumes) Find(volID string) (volume.Volume, error) {
+ for _, v := range vols {
+ if v.GetID() == volID {
+ return v, nil
+ }
+ }
+
+ return nil, errors.Wrapf(terrors.ErrInvalidValue, "volID %s not exists", volID)
+}
+
+// Exists checks the volume if exists, in which mounted the directory.
+func (vols Volumes) Exists(mnt string) bool {
+ for _, vol := range vols {
+ switch {
+ case vol.IsSys():
+ continue
+ case vol.GetMountDir() == mnt:
+ return true
+ }
+ }
+ return false
+}
+
+// Len .
+func (vols Volumes) Len() int {
+ return len(vols)
+}
+
+func (vols Volumes) Resources() meta.Resources {
+ var r = make(meta.Resources, 0, len(vols))
+ for _, v := range vols {
+ // for UT, because can't marshal mock object
+ if _, ok := v.(*mocks.Volume); ok {
+ continue
+ }
+ r = append(r, v)
+ }
+ return r
+}
+
+func (vols Volumes) SetDevice() {
+ for idx, vol := range vols {
+ dev := base.GetDeviceName(idx)
+ vol.SetDevice(dev)
+ }
+}
+
+func (vols Volumes) SetGuestID(id string) {
+ for _, vol := range vols {
+ vol.SetGuestID(id)
+ }
+}
+
+func (vols Volumes) SetHostName(name string) {
+ for _, vol := range vols {
+ vol.SetHostname(name)
+ }
+}
+
+func (vols Volumes) IDs() []string {
+ var v = make([]string, len(vols))
+ for i, vol := range vols {
+ v[i] = vol.GetID()
+ }
+ return v
+}
+
+func (vols Volumes) GenID() {
+ for _, vol := range vols {
+ vol.GenerateID()
+ }
+}
+
+func (vols Volumes) SetStatus(st string, force bool) error {
+ for _, vol := range vols {
+ if err := vol.SetStatus(st, force); err != nil {
+ return errors.Wrap(err, "")
+ }
+ }
+ return nil
+}
+
+func (vols Volumes) MetaKeys() []string {
+ var keys = make([]string, len(vols))
+ for i, vol := range vols {
+ keys[i] = vol.MetaKey()
+ }
+ return keys
+}
+
+// GetMntVol return the vol of a path if exists .
+func (vols Volumes) GetMntVol(path string) (volume.Volume, error) {
+ path = filepath.Dir(path)
+ if path[0] != '/' {
+ return nil, terrors.ErrDestinationInvalid
+ }
+
+ // append a `/` to the end.
+ // this can avoid the wrong result caused by following example:
+ // path: /dst10, mount dir: /dst1
+ if !strings.HasSuffix(path, "/") {
+ path += "/"
+ }
+ var sys, maxVol volume.Volume
+ maxLen := -1
+ for _, vol := range vols {
+ if vol.IsSys() {
+ sys = vol
+ continue
+ }
+
+ mntDirLen := len(vol.GetMountDir())
+ mntDir := vol.GetMountDir()
+ if !strings.HasSuffix(mntDir, "/") {
+ mntDir += "/"
+ }
+ if mntDirLen > maxLen && strings.Index(path, mntDir) == 0 {
+ maxLen = mntDirLen
+ maxVol = vol
+ }
+ }
+
+ if maxLen < 1 {
+ return sys, nil
+ }
+ return maxVol, nil
+}
diff --git a/internal/volume/local/const.go b/internal/volume/local/const.go
new file mode 100644
index 0000000..a0c123c
--- /dev/null
+++ b/internal/volume/local/const.go
@@ -0,0 +1,9 @@
+package local
+
+const (
+ VolQcow2Format = "qcow2"
+ // VolDataType .
+ VolDataType = "dat"
+ // VolSysType .
+ VolSysType = "sys"
+)
diff --git a/internal/models/snapshot.go b/internal/volume/local/snapshot.go
similarity index 82%
rename from internal/models/snapshot.go
rename to internal/volume/local/snapshot.go
index 7a27884..6dd98b2 100644
--- a/internal/models/snapshot.go
+++ b/internal/volume/local/snapshot.go
@@ -1,4 +1,4 @@
-package models
+package local
import (
"context"
@@ -6,10 +6,11 @@ import (
"path/filepath"
"time"
+ "github.com/cockroachdb/errors"
"github.com/projecteru2/yavirt/internal/meta"
- "github.com/projecteru2/yavirt/pkg/errors"
"github.com/projecteru2/yavirt/pkg/idgen"
"github.com/projecteru2/yavirt/pkg/store"
+ "github.com/projecteru2/yavirt/pkg/terrors"
)
// Snapshot .
@@ -17,7 +18,7 @@ import (
//
// /snapshots/
type Snapshot struct {
- *Generic
+ *meta.Generic
BaseSnapshotID string `json:"base_snapshot"`
Type string `json:"type"`
@@ -26,15 +27,15 @@ type Snapshot struct {
// LoadSnapshot .
func LoadSnapshot(id string) (*Snapshot, error) {
- g := NewSnapShot("")
+ s := NewSnapShot("")
- g.ID = id
+ s.ID = id
- if err := meta.Load(g); err != nil {
- return nil, errors.Trace(err)
+ if err := meta.Load(s); err != nil {
+ return nil, errors.Wrap(err, "")
}
- return g, nil
+ return s, nil
}
// NewSnapShot .
@@ -48,7 +49,7 @@ func NewSnapShot(
}
func newSnapshot() *Snapshot {
- return &Snapshot{Generic: newGeneric()}
+ return &Snapshot{Generic: meta.NewGeneric()}
}
func (s *Snapshot) SetVolID(volID string) {
@@ -109,11 +110,11 @@ func (s *Snapshot) String() string {
// Snapshots .
type Snapshots []*Snapshot
-func (snaps *Snapshots) append(snap ...*Snapshot) {
+func (snaps *Snapshots) Append(snap ...*Snapshot) {
*snaps = append(*snaps, snap...)
}
-func (snaps Snapshots) ids() []string {
+func (snaps Snapshots) IDs() []string {
v := make([]string, len(snaps))
for i, snap := range snaps {
v[i] = snap.ID
@@ -127,7 +128,7 @@ func LoadSnapshots(ids []string) (snaps Snapshots, err error) {
for i, id := range ids {
if snaps[i], err = LoadSnapshot(id); err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
}
@@ -147,5 +148,5 @@ func (snaps Snapshots) Find(snapID string) (*Snapshot, error) {
}
}
- return nil, errors.Annotatef(errors.ErrInvalidValue, "snapID %s not exists", snapID)
+ return nil, errors.Wrapf(terrors.ErrInvalidValue, "snapID %s not exists", snapID)
}
diff --git a/internal/volume/local/snapshot_api.go b/internal/volume/local/snapshot_api.go
new file mode 100644
index 0000000..48bb1f8
--- /dev/null
+++ b/internal/volume/local/snapshot_api.go
@@ -0,0 +1,311 @@
+package local
+
+import (
+ "context"
+ "time"
+
+ "github.com/cockroachdb/errors"
+ virtutils "github.com/projecteru2/yavirt/internal/utils"
+ "github.com/projecteru2/yavirt/internal/volume/base"
+ "github.com/projecteru2/yavirt/pkg/sh"
+)
+
+// SnapshotAPI .
+type SnapshotAPI struct {
+ vol *Volume
+}
+
+// New .
+func newSnapshotAPI(v *Volume) *SnapshotAPI {
+ return &SnapshotAPI{
+ vol: v,
+ }
+}
+
+func (api *SnapshotAPI) List() base.Snapshots {
+ ans := base.Snapshots{}
+ for _, snap := range api.vol.Snaps {
+ ans = append(ans, snap)
+ }
+ return ans
+}
+
+// Delete meta and file in backup storage
+func (api *SnapshotAPI) Delete(id string) error {
+ if err := api.delete(id); err != nil {
+ return errors.Wrap(err, "")
+ }
+ return api.vol.Save()
+}
+
+func (api *SnapshotAPI) delete(id string) error {
+ vol := api.vol
+ snap, err := LoadSnapshot(id)
+ if err != nil {
+ return errors.Wrap(err, "")
+ }
+ // TODO delete backups in backup storage
+ if err := sh.Remove(snap.Filepath()); err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ vol.RemoveSnap(snap.ID)
+ if err := snap.Delete(); err != nil {
+ return errors.Wrap(err, "")
+ }
+ return nil
+}
+
+func (api *SnapshotAPI) DeleteAll() error {
+ for _, id := range api.vol.SnapIDs {
+ if err := api.delete(id); err != nil {
+ return errors.Wrap(err, "")
+ }
+ }
+ return api.vol.Save()
+}
+
+// Create external snapshot and return a list of Volume model represent volume that newly in use.
+func (api *SnapshotAPI) Create() error {
+ vol := api.vol
+ snapmod := NewSnapShot(vol.ID)
+ snapmod.GenerateID()
+
+ // change the qcow2 files
+ volFname := api.vol.Filepath()
+ tempFilepath := getTemporaryFilepath(api.vol.Filepath())
+
+ if err := virtutils.CreateSnapshot(context.Background(), volFname, tempFilepath); err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ if err := sh.Copy(volFname, snapmod.Filepath()); err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ if err := virtutils.RebaseImage(context.Background(), tempFilepath, snapmod.Filepath()); err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ if err := sh.Move(tempFilepath, volFname); err != nil {
+ return errors.Wrap(err, "")
+ }
+ if err := api.upload(snapmod, false); err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ if err := vol.AppendSnaps(snapmod); err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ // save snapshot and volume to data store
+ snapmod.BaseSnapshotID = vol.BaseSnapshotID
+ vol.BaseSnapshotID = snapmod.ID
+ if err := snapmod.Create(); err != nil {
+ return errors.Wrap(err, "")
+ }
+ return api.vol.Save()
+}
+
+// Commit current snapshot and snapshots before current snapshot to the root
+// Root(Full snapshot) -> Snap1 -> Snap2 -> Snap3 -> Vol in-use
+// After Snap2.Commit()
+// NewRoot(Full snapshot with name same as Snap 2) -> Snap3 -> Vol in-use
+func (api *SnapshotAPI) Commit(rootID string) error {
+ snap, err := LoadSnapshot(rootID)
+ if err != nil {
+ return errors.Wrap(err, "")
+ }
+ return api.commit(snap)
+}
+
+func (api *SnapshotAPI) commit(snap *Snapshot) error {
+ vol := api.vol
+ snaps := vol.Snaps
+ chain, err := getChain(snap, snaps)
+ if err != nil {
+ return errors.Wrap(err, "")
+ }
+ if chain.Len() <= 1 {
+ return nil
+ }
+
+ if err = api.downloadSnapshots(chain); err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ for i := 0; i < chain.Len()-1; i++ {
+ if err := virtutils.CommitImage(context.Background(), chain[i].Filepath()); err != nil {
+ return errors.Wrap(err, "")
+ }
+ if err := sh.Remove(chain[i].Filepath()); err != nil {
+ return errors.Wrap(err, "")
+ }
+ }
+ // Change name of the root snapshot to the current snapshot
+ if err := sh.Move(chain[chain.Len()-1].Filepath(), chain[0].Filepath()); err != nil {
+ return errors.Wrap(err, "")
+ }
+ if err = api.upload(snap, true); err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ // delete snapshot meta data
+ for _, snap := range chain[1:] {
+ api.vol.RemoveSnap(snap.ID)
+ if err := snap.Delete(); err != nil {
+ return errors.Wrap(err, "")
+ }
+ }
+ if err := api.vol.Save(); err != nil {
+ return errors.Wrap(err, "")
+ }
+ return nil
+}
+
+func (api *SnapshotAPI) CommitByDay(day int) error {
+ vol := api.vol
+ date := time.Now().AddDate(0, 0, -day).Unix()
+ targetIdx := -1
+ for i, s := range vol.Snaps {
+ if s.CreatedTime > date { // Find the first snapshot that is created later than x days before
+ targetIdx = i
+ }
+ }
+
+ // No need to commit if all snapshot created within x days
+ if targetIdx == 0 {
+ return nil
+ }
+
+ // If all snapshot create x days before, keep the last one
+ if targetIdx == -1 {
+ targetIdx = vol.Snaps.Len() - 1
+ }
+
+ return api.commit(vol.Snaps[targetIdx])
+}
+
+// Restore .
+func (api *SnapshotAPI) Restore(rootID string) error {
+ vol := api.vol
+ snap, err := LoadSnapshot(rootID)
+ if err != nil {
+ return errors.Wrap(err, "")
+ }
+ snaps := vol.Snaps
+ chain, err := getChain(snap, snaps)
+ if err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ if err := api.downloadSnapshots(chain); err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ for i := 0; i < chain.Len(); i++ {
+ if err := sh.Copy(chain[i].Filepath(), getTemporaryFilepath(chain[i].Filepath())); err != nil {
+ return errors.Wrap(err, "")
+ }
+ }
+
+ for i := 0; i < chain.Len()-1; i++ {
+ if err := virtutils.CommitImage(context.Background(), chain[i].Filepath()); err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ if err := sh.Remove(chain[i].Filepath()); err != nil {
+ return errors.Wrap(err, "")
+ }
+ }
+
+ if err := sh.Move(chain[chain.Len()-1].Filepath(), vol.Filepath()); err != nil {
+ return errors.Wrap(err, "")
+ }
+
+ for i := 0; i < chain.Len(); i++ {
+ if err := sh.Move(getTemporaryFilepath(chain[i].Filepath()), chain[i].Filepath()); err != nil {
+ return errors.Wrap(err, "")
+ }
+ }
+ vol.BaseSnapshotID = rootID
+ return vol.Save()
+}
+
+// Upload .
+func (api *SnapshotAPI) Upload(id string, force bool) error {
+ snapmod, err := LoadSnapshot(id)
+ if err != nil {
+ return errors.Wrap(err, "")
+ }
+ return api.upload(snapmod, force)
+}
+
+func (api *SnapshotAPI) upload(snapmod *Snapshot, force bool) error { //nolint
+ // TODO upload to backup storage
+
+ return nil
+}
+
+// Download .
+func (api *SnapshotAPI) Download(id string) error {
+ snapmod, err := LoadSnapshot(id)
+ if err != nil {
+ return errors.Wrap(err, "")
+ }
+ return api.download(snapmod)
+}
+
+func (api *SnapshotAPI) download(snapmod *Snapshot) error { //nolint
+ // TODO download from backup storage
+ return nil
+}
+
+// // check whether the snapshot is the last snapshot on the chain
+// // (not exist other snapshot use this snapshot as backing file)
+// func (snap *Snapshot) checkSnapshotIsLatest(snaps Snapshots) bool {
+// isLatest := true
+// for _, s := range snaps {
+// if s.BaseSnapshotID == snap.ID {
+// isLatest = false
+// }
+// }
+// return isLatest
+// }
+
+// calculate the whole chain
+func getChain(rootSnap *Snapshot, snaps Snapshots) (Snapshots, error) {
+
+ if _, err := snaps.Find(rootSnap.ID); err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+
+ snapIDMap := make(map[string]*Snapshot)
+ for _, s := range snaps {
+ snapIDMap[s.ID] = s
+ }
+
+ var chain Snapshots
+ chain = append(chain, rootSnap)
+ currentID := rootSnap.BaseSnapshotID
+ for len(currentID) > 0 {
+ chain = append(chain, snapIDMap[currentID])
+ currentID = snapIDMap[currentID].BaseSnapshotID
+ }
+
+ return chain, nil
+}
+
+// download list of snapshot files
+func (api *SnapshotAPI) downloadSnapshots(snaps Snapshots) error {
+ for _, s := range snaps {
+ if err := api.download(s); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func getTemporaryFilepath(filepath string) string {
+ return filepath + ".temp"
+}
diff --git a/internal/volume/local/snapshot_test.go b/internal/volume/local/snapshot_test.go
new file mode 100644
index 0000000..a924bd6
--- /dev/null
+++ b/internal/volume/local/snapshot_test.go
@@ -0,0 +1,94 @@
+package local
+
+// import (
+// "testing"
+
+// "github.com/projecteru2/yavirt/pkg/test/assert"
+// "github.com/projecteru2/yavirt/pkg/test/mock"
+
+// basemock "github.com/projecteru2/yavirt/internal/volume/base/mocks"
+// )
+
+// func TestCreate(t *testing.T) {
+// snapmod := NewSnapShot("vol-id-123")
+
+// sbot := &basemock.SnapshotAPI{}
+// sbot.On("Create", mock.Anything).Return(nil).Once()
+// sbot.On("Close").Return(nil).Twice()
+// sbot.On("Upload", mock.Anything).Return(nil).Once()
+
+// err := sbot.Create(NewDataVolume("vol-id-123", 1))
+// assert.NilErr(t, err)
+// }
+
+// func TestCommit(t *testing.T) {
+// snapmod := NewSnapShot("vol-id")
+// snapmod.ID = "id-8"
+// snapmod.BaseSnapshotID = "id-4"
+
+// sbot := &snapmock.Bot{}
+// sbot.On("Commit", mock.Anything).Return(nil).Once()
+// sbot.On("Close").Return(nil).Times(10 + 2)
+// sbot.On("Download", mock.Anything).Return(nil).Times(10)
+// sbot.On("Upload", mock.Anything).Return(nil).Once()
+
+// snap := &Snapshot{
+// Snapshot: snapmod,
+// newBot: func(v *Snapshot) (Bot, error) { return sbot, nil },
+// }
+
+// snaps := generateMockedSnapshots(10)
+// snaps[8].BaseSnapshotID = "id-4"
+// snaps[4].BaseSnapshotID = "id-2"
+// snaps[2].BaseSnapshotID = "id-1"
+
+// ret, err := snap.Commit(snaps)
+// assert.NilErr(t, err)
+// assert.Equal(t, ret.Len(), 3)
+// assert.Equal(t, ret[0], snaps[4])
+// assert.Equal(t, ret[1], snaps[2])
+// assert.Equal(t, ret[2], snaps[1])
+// }
+
+// func TestCommitRoot(t *testing.T) {
+// snapmod := models.NewSnapShot("vol-id-123")
+// snapmod.ID = "id-8"
+
+// sbot := &snapmock.Bot{}
+// sbot.On("Commit", mock.Anything).Return(nil).Once()
+// sbot.On("Close").Return(nil).Times(10 + 2)
+// sbot.On("Download", mock.Anything).Return(nil).Times(10)
+// sbot.On("Upload", mock.Anything).Return(nil).Once()
+
+// snap := &Snapshot{
+// Snapshot: snapmod,
+// newBot: func(v *Snapshot) (Bot, error) { return sbot, nil },
+// }
+
+// snaps := generateMockedSnapshots(10)
+
+// ret, err := snap.Commit(snaps)
+// assert.NilErr(t, err)
+// assert.Equal(t, ret.Len(), 0)
+// }
+
+// func TestRestore(t *testing.T) {
+// snapmod := models.NewSnapShot("vol-id-123")
+// snapmod.ID = "id-123"
+
+// sbot := &snapmock.Bot{}
+// sbot.On("Close").Return(nil).Times(10 + 1)
+// sbot.On("Download", mock.Anything).Return(nil).Times(10)
+// sbot.On("Restore", mock.Anything, mock.Anything).Return(nil).Once()
+
+// snap := &Snapshot{
+// Snapshot: snapmod,
+// newBot: func(v *Snapshot) (Bot, error) { return sbot, nil },
+// }
+
+// snaps := generateMockedSnapshots(3)
+// snaps[0].ID = "id-123"
+
+// err := snap.Restore(models.NewVolume("vol-id-123", 1), snaps)
+// assert.NilErr(t, err)
+// }
diff --git a/internal/volume/local/templates/disk.xml b/internal/volume/local/templates/disk.xml
new file mode 100644
index 0000000..f0beffc
--- /dev/null
+++ b/internal/volume/local/templates/disk.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+ {{ .read_iops }}
+ {{ .write_iops }}
+ {{ .read_bps }}
+ {{ .write_bps }}
+
+
\ No newline at end of file
diff --git a/internal/volume/local/util.go b/internal/volume/local/util.go
new file mode 100644
index 0000000..469c3dc
--- /dev/null
+++ b/internal/volume/local/util.go
@@ -0,0 +1 @@
+package local
diff --git a/internal/volume/local/volume.go b/internal/volume/local/volume.go
new file mode 100644
index 0000000..c2d33cc
--- /dev/null
+++ b/internal/volume/local/volume.go
@@ -0,0 +1,339 @@
+package local
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "os"
+ "path/filepath"
+ "strings"
+ "text/template"
+
+ _ "embed"
+
+ "github.com/cockroachdb/errors"
+ stotypes "github.com/projecteru2/resource-storage/storage/types"
+ "github.com/projecteru2/yavirt/configs"
+ "github.com/projecteru2/yavirt/internal/meta"
+ interutils "github.com/projecteru2/yavirt/internal/utils"
+ "github.com/projecteru2/yavirt/internal/virt/guestfs"
+ "github.com/projecteru2/yavirt/internal/virt/guestfs/gfsx"
+ "github.com/projecteru2/yavirt/internal/volume/base"
+ "github.com/projecteru2/yavirt/pkg/sh"
+ "github.com/projecteru2/yavirt/pkg/terrors"
+ "github.com/projecteru2/yavirt/pkg/utils"
+ vmiFact "github.com/yuyang0/vmimage/factory"
+ vmitypes "github.com/yuyang0/vmimage/types"
+)
+
+var (
+ //go:embed templates/disk.xml
+ diskXML string
+ tmpl *template.Template
+)
+
+// Volume .
+// etcd keys:
+//
+// /vols/
+type Volume struct {
+ base.Volume `mapstructure:",squash"`
+ stotypes.VolumeBinding `mapstructure:",squash"`
+
+ Format string `json:"format" mapstructure:"format"`
+ SnapIDs []string `json:"snaps" mapstructure:"snaps"`
+ BaseSnapshotID string `json:"base_snapshot_id" mapstructure:"base_snapshot_id"`
+ Snaps Snapshots `json:"-" mapstructure:"-"`
+ flock *utils.Flock `json:"-" mapstructure:"-"`
+}
+
+// LoadVolume loads data from etcd
+func LoadVolume(id string) (*Volume, error) {
+ var vol = NewVolume()
+ vol.ID = id
+
+ if err := meta.Load(vol); err != nil {
+ return nil, err
+ }
+
+ return vol, vol.LoadSnapshots()
+}
+
+// NewVolumeFromStr
+// format: `src:dst[:flags][:size][:read_IOPS:write_IOPS:read_bytes:write_bytes]`
+// example: `/source:/dir0:rw:1024:1000:1000:10M:10M`
+func NewVolumeFromStr(s string) (*Volume, error) {
+ vb, err := stotypes.NewVolumeBinding(s)
+ if err != nil {
+ return nil, err
+ }
+ return &Volume{
+ Format: VolQcow2Format,
+ Volume: *base.New(),
+ VolumeBinding: *vb,
+ }, nil
+}
+
+// NewSysVolume .
+func NewSysVolume(cap int64, imageName string) *Volume {
+ vol := NewVolume()
+ vol.SysImage = imageName
+ vol.Flags = "rws"
+ vol.SizeInBytes = cap
+ return vol
+}
+
+// NewDataVolume .
+func NewDataVolume(mnt string, cap int64) (*Volume, error) {
+ mnt = strings.TrimSpace(mnt)
+
+ src, dest := utils.PartRight(mnt, ":")
+ src = strings.TrimSpace(src)
+ dest = filepath.Join("/", strings.TrimSpace(dest))
+
+ if len(src) > 0 {
+ src = filepath.Join("/", src)
+ }
+
+ var vol = NewVolume()
+ vol.Source = src
+ vol.Destination = dest
+ vol.Flags = "rw"
+ vol.SizeInBytes = cap
+
+ return vol, vol.Check()
+}
+
+func NewVolume() *Volume {
+ return &Volume{
+ Volume: *base.New(),
+ Format: VolQcow2Format,
+ }
+}
+
+func (v *Volume) Lock() error {
+ fn := fmt.Sprintf("vol_%s.flock", v.ID)
+ fpth := filepath.Join(configs.Conf.VirtFlockDir, fn)
+ v.flock = utils.NewFlock(fpth)
+ if err := v.flock.Trylock(); err != nil {
+ return errors.Wrap(err, "")
+ }
+ return nil
+}
+
+func (v *Volume) Unlock() {
+ v.flock.Close()
+}
+
+func (v *Volume) QemuImagePath() string {
+ return v.Filepath()
+}
+
+func (v *Volume) GetSize() int64 {
+ return v.SizeInBytes
+}
+
+func (v *Volume) SetSize(sz int64) {
+ v.SizeInBytes = sz
+}
+
+// Load .
+func (v *Volume) LoadSnapshots() (err error) {
+ if v.Snaps, err = LoadSnapshots(v.SnapIDs); err != nil {
+ return errors.Wrap(err, "")
+ }
+ return nil
+}
+
+func (v *Volume) NewSnapshotAPI() base.SnapshotAPI {
+ return newSnapshotAPI(v)
+}
+
+// AppendSnaps .
+func (v *Volume) AppendSnaps(snaps ...*Snapshot) error {
+ if v.Snaps.Len()+len(snaps) > configs.Conf.MaxSnapshotsCount {
+ return errors.Wrapf(terrors.ErrTooManyVolumes, "at most %d", configs.Conf.MaxSnapshotsCount)
+ }
+
+ res := Snapshots(snaps)
+
+ v.Snaps.Append(snaps...)
+
+ v.SnapIDs = append(v.SnapIDs, res.IDs()...)
+
+ return nil
+}
+
+// RemoveSnaps Remove snapshots meta by preserving the order.
+func (v *Volume) RemoveSnap(snapID string) {
+ keep := 0
+
+ for i := 0; i < v.Snaps.Len(); i++ {
+ if v.Snaps[i].ID == snapID {
+ continue
+ }
+
+ v.Snaps[keep] = v.Snaps[i]
+ v.SnapIDs[keep] = v.SnapIDs[i]
+ keep++
+ }
+
+ v.Snaps = v.Snaps[:keep]
+ v.SnapIDs = v.SnapIDs[:keep]
+}
+
+// Save updates metadata to persistence store.
+func (v *Volume) Save() error {
+ if v.GetVer() == 0 {
+ return meta.Create(meta.Resources{v})
+ }
+ return meta.Save(meta.Resources{v})
+}
+
+func (v *Volume) GetMountDir() string {
+ if len(v.Destination) > 0 {
+ return v.Destination
+ }
+ return "/"
+}
+
+func (v *Volume) String() string {
+ var mnt = "/"
+ if len(v.Destination) > 0 {
+ mnt = v.Destination
+ }
+ return fmt.Sprintf("%s, %s, %s:%s, size: %d", v.Filepath(), v.Status, v.GuestID, mnt, v.SizeInBytes)
+}
+
+// Filepath .
+func (v *Volume) Filepath() string {
+ if len(v.Source) > 0 {
+ return filepath.Join(v.Source, v.Name())
+ }
+ return v.JoinVirtPath(v.Name())
+}
+
+// Name .
+func (v *Volume) Name() string {
+ ty := "dat"
+ if v.IsSys() {
+ ty = "sys"
+ }
+ return fmt.Sprintf("%s-%s.vol", ty, v.ID)
+}
+
+// Check .
+func (v *Volume) Check() error {
+ switch {
+ case v.SizeInBytes < configs.Conf.Resource.MinVolumeCap || v.SizeInBytes > configs.Conf.Resource.MaxVolumeCap:
+ return errors.Wrapf(terrors.ErrInvalidValue, "capacity: %d", v.SizeInBytes)
+ case v.Source == "/":
+ return errors.Wrapf(terrors.ErrInvalidValue, "host dir: %s", v.Source)
+ case v.Destination == "/":
+ return errors.Wrapf(terrors.ErrInvalidValue, "mount dir: %s", v.Destination)
+ default:
+ if _, err := os.Stat(v.Filepath()); err == nil {
+ return interutils.Check(context.Background(), v.Filepath())
+ }
+ return nil
+ }
+}
+
+// Repair .
+func (v *Volume) Repair() error {
+ return interutils.Repair(context.Background(), v.Filepath())
+}
+
+// IsSys .
+func (v *Volume) IsSys() bool {
+ return strings.Contains(v.Flags, "s")
+}
+
+func (v *Volume) PrepareSysDisk(ctx context.Context, img *vmitypes.Image, _ ...base.Option) error {
+ if !v.IsSys() {
+ panic("not a sys disk")
+ }
+ rc, err := vmiFact.Pull(ctx, img, vmitypes.PullPolicyAlways)
+ if err != nil {
+ return errors.Wrapf(err, "failed to pull image %s: %s", img.Fullname(), err)
+ }
+ interutils.EnsureReaderClosed(rc)
+ if err := sh.Copy(img.Filepath(), v.Filepath()); err != nil {
+ return errors.Wrap(err, "")
+ }
+ return nil
+}
+
+func (v *Volume) PrepareDataDisk(_ context.Context) error {
+ if v.IsSys() {
+ panic("not a data disk")
+ }
+ var path = v.Filepath()
+ return interutils.CreateImage(context.TODO(), VolQcow2Format, path, v.SizeInBytes)
+}
+
+// Cleanup deletes the qcow2 file
+func (v *Volume) Cleanup() error {
+ return sh.Remove(v.Filepath())
+}
+
+func (v *Volume) CaptureImage(imgName string) (uimg *vmitypes.Image, err error) {
+ tmpDir, err := os.MkdirTemp(os.TempDir(), "local-capture-")
+ if err != nil {
+ return nil, err
+ }
+ defer os.RemoveAll(tmpDir)
+
+ orig := filepath.Join(tmpDir, "vol.img")
+ if err := sh.Copy(v.Filepath(), orig); err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ var gfs guestfs.Guestfs
+ if gfs, err = gfsx.New(orig); err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ defer gfs.Close()
+ if err = base.ResetUserImage(gfs); err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+
+ uimg, err = vmiFact.NewImage(imgName)
+ if err != nil {
+ return nil, err
+ }
+ rc, err := vmiFact.Prepare(orig, uimg)
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ defer interutils.EnsureReaderClosed(rc)
+ return uimg, nil
+}
+
+func (v *Volume) GenerateXML() ([]byte, error) {
+ args := map[string]any{
+ "path": v.Filepath(),
+ "dev": v.Device,
+ "read_iops": fmt.Sprintf("%d", v.ReadIOPS),
+ "write_iops": fmt.Sprintf("%d", v.WriteIOPS),
+ "read_bps": fmt.Sprintf("%d", v.ReadBPS),
+ "write_bps": fmt.Sprintf("%d", v.WriteBPS),
+ }
+
+ if tmpl == nil {
+ t, err := template.New("local-vol-tpl").Parse(diskXML)
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ tmpl = t
+ }
+
+ var wr bytes.Buffer
+ if err := tmpl.Execute(&wr, args); err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ return wr.Bytes(), nil
+}
+
+func (v *Volume) GetGfx() (guestfs.Guestfs, error) {
+ return gfsx.New(v.Filepath())
+}
diff --git a/internal/models/volume_test.go b/internal/volume/local/volume_test.go
similarity index 73%
rename from internal/models/volume_test.go
rename to internal/volume/local/volume_test.go
index dd49423..9ed1700 100644
--- a/internal/models/volume_test.go
+++ b/internal/volume/local/volume_test.go
@@ -1,4 +1,4 @@
-package models
+package local
import (
"fmt"
@@ -34,11 +34,20 @@ func TestDataVolume(t *testing.T) {
}
for _, c := range cases {
- vol, err := NewDataVolume(c.in, configs.Conf.MinVolumeCap)
+ vol, err := NewDataVolume(c.in, configs.Conf.Resource.MinVolumeCap)
assert.NilErr(t, err)
vol.ID = "id"
- assert.Equal(t, c.dst, vol.MountDir)
+ assert.Equal(t, c.dst, vol.Destination)
assert.Equal(t, c.src, vol.Filepath())
}
}
+
+func TestGenerateXML(t *testing.T) {
+ vol, err := NewVolumeFromStr("/src:/data1:rw:2G")
+ vol.SetDevice("vda")
+ assert.NilErr(t, err)
+ bs, err := vol.GenerateXML()
+ assert.NilErr(t, err)
+ fmt.Printf("%s\n", string(bs))
+}
diff --git a/internal/volume/mocks/Volume.go b/internal/volume/mocks/Volume.go
new file mode 100644
index 0000000..1f81265
--- /dev/null
+++ b/internal/volume/mocks/Volume.go
@@ -0,0 +1,587 @@
+// Code generated by mockery v2.42.0. DO NOT EDIT.
+
+package mocks
+
+import (
+ context "context"
+
+ base "github.com/projecteru2/yavirt/internal/volume/base"
+
+ guestfs "github.com/projecteru2/yavirt/internal/virt/guestfs"
+
+ mock "github.com/stretchr/testify/mock"
+
+ types "github.com/yuyang0/vmimage/types"
+)
+
+// Volume is an autogenerated mock type for the Volume type
+type Volume struct {
+ mock.Mock
+}
+
+// CaptureImage provides a mock function with given fields: imgName
+func (_m *Volume) CaptureImage(imgName string) (*types.Image, error) {
+ ret := _m.Called(imgName)
+
+ if len(ret) == 0 {
+ panic("no return value specified for CaptureImage")
+ }
+
+ var r0 *types.Image
+ var r1 error
+ if rf, ok := ret.Get(0).(func(string) (*types.Image, error)); ok {
+ return rf(imgName)
+ }
+ if rf, ok := ret.Get(0).(func(string) *types.Image); ok {
+ r0 = rf(imgName)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Image)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(string) error); ok {
+ r1 = rf(imgName)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// Check provides a mock function with given fields:
+func (_m *Volume) Check() error {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Check")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func() error); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// Cleanup provides a mock function with given fields:
+func (_m *Volume) Cleanup() error {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Cleanup")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func() error); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// Delete provides a mock function with given fields: force
+func (_m *Volume) Delete(force bool) error {
+ ret := _m.Called(force)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Delete")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(bool) error); ok {
+ r0 = rf(force)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// GenerateID provides a mock function with given fields:
+func (_m *Volume) GenerateID() {
+ _m.Called()
+}
+
+// GenerateXML provides a mock function with given fields:
+func (_m *Volume) GenerateXML() ([]byte, error) {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for GenerateXML")
+ }
+
+ var r0 []byte
+ var r1 error
+ if rf, ok := ret.Get(0).(func() ([]byte, error)); ok {
+ return rf()
+ }
+ if rf, ok := ret.Get(0).(func() []byte); ok {
+ r0 = rf()
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]byte)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func() error); ok {
+ r1 = rf()
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// GetCreatedTime provides a mock function with given fields:
+func (_m *Volume) GetCreatedTime() int64 {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetCreatedTime")
+ }
+
+ var r0 int64
+ if rf, ok := ret.Get(0).(func() int64); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Get(0).(int64)
+ }
+
+ return r0
+}
+
+// GetDevice provides a mock function with given fields:
+func (_m *Volume) GetDevice() string {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetDevice")
+ }
+
+ var r0 string
+ if rf, ok := ret.Get(0).(func() string); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Get(0).(string)
+ }
+
+ return r0
+}
+
+// GetGfx provides a mock function with given fields:
+func (_m *Volume) GetGfx() (guestfs.Guestfs, error) {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetGfx")
+ }
+
+ var r0 guestfs.Guestfs
+ var r1 error
+ if rf, ok := ret.Get(0).(func() (guestfs.Guestfs, error)); ok {
+ return rf()
+ }
+ if rf, ok := ret.Get(0).(func() guestfs.Guestfs); ok {
+ r0 = rf()
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(guestfs.Guestfs)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func() error); ok {
+ r1 = rf()
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// GetGuestID provides a mock function with given fields:
+func (_m *Volume) GetGuestID() string {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetGuestID")
+ }
+
+ var r0 string
+ if rf, ok := ret.Get(0).(func() string); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Get(0).(string)
+ }
+
+ return r0
+}
+
+// GetHostname provides a mock function with given fields:
+func (_m *Volume) GetHostname() string {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetHostname")
+ }
+
+ var r0 string
+ if rf, ok := ret.Get(0).(func() string); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Get(0).(string)
+ }
+
+ return r0
+}
+
+// GetID provides a mock function with given fields:
+func (_m *Volume) GetID() string {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetID")
+ }
+
+ var r0 string
+ if rf, ok := ret.Get(0).(func() string); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Get(0).(string)
+ }
+
+ return r0
+}
+
+// GetMountDir provides a mock function with given fields:
+func (_m *Volume) GetMountDir() string {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetMountDir")
+ }
+
+ var r0 string
+ if rf, ok := ret.Get(0).(func() string); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Get(0).(string)
+ }
+
+ return r0
+}
+
+// GetSize provides a mock function with given fields:
+func (_m *Volume) GetSize() int64 {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetSize")
+ }
+
+ var r0 int64
+ if rf, ok := ret.Get(0).(func() int64); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Get(0).(int64)
+ }
+
+ return r0
+}
+
+// GetStatus provides a mock function with given fields:
+func (_m *Volume) GetStatus() string {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetStatus")
+ }
+
+ var r0 string
+ if rf, ok := ret.Get(0).(func() string); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Get(0).(string)
+ }
+
+ return r0
+}
+
+// GetVer provides a mock function with given fields:
+func (_m *Volume) GetVer() int64 {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetVer")
+ }
+
+ var r0 int64
+ if rf, ok := ret.Get(0).(func() int64); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Get(0).(int64)
+ }
+
+ return r0
+}
+
+// IncrVer provides a mock function with given fields:
+func (_m *Volume) IncrVer() {
+ _m.Called()
+}
+
+// IsSys provides a mock function with given fields:
+func (_m *Volume) IsSys() bool {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for IsSys")
+ }
+
+ var r0 bool
+ if rf, ok := ret.Get(0).(func() bool); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Get(0).(bool)
+ }
+
+ return r0
+}
+
+// Lock provides a mock function with given fields:
+func (_m *Volume) Lock() error {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Lock")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func() error); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// MetaKey provides a mock function with given fields:
+func (_m *Volume) MetaKey() string {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for MetaKey")
+ }
+
+ var r0 string
+ if rf, ok := ret.Get(0).(func() string); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Get(0).(string)
+ }
+
+ return r0
+}
+
+// Name provides a mock function with given fields:
+func (_m *Volume) Name() string {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Name")
+ }
+
+ var r0 string
+ if rf, ok := ret.Get(0).(func() string); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Get(0).(string)
+ }
+
+ return r0
+}
+
+// NewSnapshotAPI provides a mock function with given fields:
+func (_m *Volume) NewSnapshotAPI() base.SnapshotAPI {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for NewSnapshotAPI")
+ }
+
+ var r0 base.SnapshotAPI
+ if rf, ok := ret.Get(0).(func() base.SnapshotAPI); ok {
+ r0 = rf()
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(base.SnapshotAPI)
+ }
+ }
+
+ return r0
+}
+
+// PrepareDataDisk provides a mock function with given fields: _a0
+func (_m *Volume) PrepareDataDisk(_a0 context.Context) error {
+ ret := _m.Called(_a0)
+
+ if len(ret) == 0 {
+ panic("no return value specified for PrepareDataDisk")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(context.Context) error); ok {
+ r0 = rf(_a0)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// PrepareSysDisk provides a mock function with given fields: _a0, _a1, _a2
+func (_m *Volume) PrepareSysDisk(_a0 context.Context, _a1 *types.Image, _a2 ...base.Option) error {
+ _va := make([]interface{}, len(_a2))
+ for _i := range _a2 {
+ _va[_i] = _a2[_i]
+ }
+ var _ca []interface{}
+ _ca = append(_ca, _a0, _a1)
+ _ca = append(_ca, _va...)
+ ret := _m.Called(_ca...)
+
+ if len(ret) == 0 {
+ panic("no return value specified for PrepareSysDisk")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(context.Context, *types.Image, ...base.Option) error); ok {
+ r0 = rf(_a0, _a1, _a2...)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// QemuImagePath provides a mock function with given fields:
+func (_m *Volume) QemuImagePath() string {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for QemuImagePath")
+ }
+
+ var r0 string
+ if rf, ok := ret.Get(0).(func() string); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Get(0).(string)
+ }
+
+ return r0
+}
+
+// Repair provides a mock function with given fields:
+func (_m *Volume) Repair() error {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Repair")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func() error); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// Save provides a mock function with given fields:
+func (_m *Volume) Save() error {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Save")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func() error); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// SetDevice provides a mock function with given fields: dev
+func (_m *Volume) SetDevice(dev string) {
+ _m.Called(dev)
+}
+
+// SetGuestID provides a mock function with given fields: id
+func (_m *Volume) SetGuestID(id string) {
+ _m.Called(id)
+}
+
+// SetHostname provides a mock function with given fields: name
+func (_m *Volume) SetHostname(name string) {
+ _m.Called(name)
+}
+
+// SetSize provides a mock function with given fields: size
+func (_m *Volume) SetSize(size int64) {
+ _m.Called(size)
+}
+
+// SetStatus provides a mock function with given fields: st, force
+func (_m *Volume) SetStatus(st string, force bool) error {
+ ret := _m.Called(st, force)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SetStatus")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(string, bool) error); ok {
+ r0 = rf(st, force)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// SetVer provides a mock function with given fields: _a0
+func (_m *Volume) SetVer(_a0 int64) {
+ _m.Called(_a0)
+}
+
+// Unlock provides a mock function with given fields:
+func (_m *Volume) Unlock() {
+ _m.Called()
+}
+
+// NewVolume creates a new instance of Volume. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func NewVolume(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *Volume {
+ mock := &Volume{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/internal/volume/rbd/snapshot.go b/internal/volume/rbd/snapshot.go
new file mode 100644
index 0000000..caee8ce
--- /dev/null
+++ b/internal/volume/rbd/snapshot.go
@@ -0,0 +1 @@
+package rbd
diff --git a/internal/volume/rbd/snapshot_api.go b/internal/volume/rbd/snapshot_api.go
new file mode 100644
index 0000000..9a9be30
--- /dev/null
+++ b/internal/volume/rbd/snapshot_api.go
@@ -0,0 +1,43 @@
+package rbd
+
+import "github.com/projecteru2/yavirt/internal/volume/base"
+
+// SnapshotAPI .
+type SnapshotAPI struct {
+ vol *Volume
+}
+
+// New .
+func newSnapshotAPI(v *Volume) *SnapshotAPI {
+ return &SnapshotAPI{
+ vol: v,
+ }
+}
+
+func (api *SnapshotAPI) List() base.Snapshots {
+ return nil
+}
+func (api *SnapshotAPI) Create() error {
+ return nil
+}
+func (api *SnapshotAPI) Commit(rootID string) error { //nolint
+ return nil
+}
+func (api *SnapshotAPI) CommitByDay(day int) error { //nolint
+ return nil
+}
+func (api *SnapshotAPI) Delete(id string) error { //nolint
+ return nil
+}
+func (api *SnapshotAPI) DeleteAll() error {
+ return nil
+}
+func (api *SnapshotAPI) Restore(rootID string) error { //nolint
+ return nil
+}
+func (api *SnapshotAPI) Upload(id string, force bool) error { //nolint
+ return nil
+}
+func (api *SnapshotAPI) Download(id string) error { //nolint
+ return nil
+}
diff --git a/internal/volume/rbd/templates/disk.xml b/internal/volume/rbd/templates/disk.xml
new file mode 100644
index 0000000..63d3c29
--- /dev/null
+++ b/internal/volume/rbd/templates/disk.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/internal/volume/rbd/utils.go b/internal/volume/rbd/utils.go
new file mode 100644
index 0000000..a536fb4
--- /dev/null
+++ b/internal/volume/rbd/utils.go
@@ -0,0 +1,30 @@
+package rbd
+
+import (
+ "fmt"
+ "regexp"
+)
+
+func parseSnapName(input string) (string, string, string, error) {
+ // Define the regular expression pattern for parsing the specified format
+ regexPattern := `^([^/]+)/([^@]+)@(.+)$`
+
+ // Compile the regular expression
+ regex, err := regexp.Compile(regexPattern)
+ if err != nil {
+ return "", "", "", fmt.Errorf("failed to compile regular expression: %v", err)
+ }
+
+ // Match the regular expression against the input
+ matches := regex.FindStringSubmatch(input)
+ if matches == nil || len(matches) != 4 {
+ return "", "", "", fmt.Errorf("invalid format: %s", input)
+ }
+
+ // Extract matched components
+ pool := matches[1]
+ imgName := matches[2]
+ snapName := matches[3]
+
+ return pool, imgName, snapName, nil
+}
diff --git a/internal/volume/rbd/volume.go b/internal/volume/rbd/volume.go
new file mode 100644
index 0000000..ca1d732
--- /dev/null
+++ b/internal/volume/rbd/volume.go
@@ -0,0 +1,306 @@
+package rbd
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "strings"
+
+ _ "embed"
+
+ "text/template"
+
+ "github.com/ceph/go-ceph/rados"
+ "github.com/ceph/go-ceph/rbd"
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/core/log"
+ "github.com/projecteru2/yavirt/configs"
+ "github.com/projecteru2/yavirt/internal/meta"
+ interutils "github.com/projecteru2/yavirt/internal/utils"
+ "github.com/projecteru2/yavirt/internal/virt/guestfs"
+ "github.com/projecteru2/yavirt/internal/virt/guestfs/gfsx"
+ "github.com/projecteru2/yavirt/internal/volume/base"
+ libguestfs "github.com/projecteru2/yavirt/third_party/guestfs"
+ rbdtypes "github.com/yuyang0/resource-rbd/rbd/types"
+ vmiFact "github.com/yuyang0/vmimage/factory"
+ vmitypes "github.com/yuyang0/vmimage/types"
+)
+
+var (
+ //go:embed templates/disk.xml
+ diskXML string
+ tmpl *template.Template
+)
+
+type Volume struct {
+ base.Volume `mapstructure:",squash"`
+ rbdtypes.VolumeBinding `mapstructure:",squash"`
+}
+
+func New() *Volume {
+ return &Volume{
+ Volume: *base.New(),
+ }
+}
+
+func NewFromStr(ss string) (*Volume, error) {
+ vb, err := rbdtypes.NewVolumeBinding(ss)
+ if err != nil {
+ return nil, err
+ }
+ return &Volume{
+ Volume: *base.New(),
+ VolumeBinding: *vb,
+ }, nil
+}
+
+func (v *Volume) Name() string {
+ return fmt.Sprintf("rbd-%s", v.ID)
+}
+
+func (v *Volume) QemuImagePath() string {
+ rbdDisk := fmt.Sprintf("rbd:%s/%s:id=%s", v.Pool, v.Image, configs.Conf.Storage.Ceph.Username)
+ return rbdDisk
+}
+
+func (v *Volume) GetSize() int64 {
+ return v.SizeInBytes
+}
+
+func (v *Volume) SetSize(sz int64) {
+ v.SizeInBytes = sz
+}
+
+func (v *Volume) GetMountDir() string {
+ return v.Destination
+}
+
+func (v *Volume) IsSys() bool {
+ return strings.Contains(v.Flags, "s")
+}
+
+func (v *Volume) PrepareSysDisk(ctx context.Context, img *vmitypes.Image, opts ...base.Option) error {
+ if !v.IsSys() {
+ panic("not a sys disk")
+ }
+ logger := log.WithFunc("Prepare")
+ optVal := &base.OptionValue{}
+ for _, opt := range opts {
+ opt(optVal)
+ }
+ // check if this rbd already exists
+ client, err := GetRBDConn()
+ if err != nil {
+ return err
+ }
+ defer client.Shutdown()
+
+ ioctx, err := client.OpenIOContext(v.Pool)
+ if err != nil {
+ return err
+ }
+ defer ioctx.Destroy()
+ // check if RBD already exist
+ exist, err := v.exist(ioctx)
+ if err != nil {
+ return err
+ }
+ if exist {
+ logger.Infof(ctx, "RBD image %s already exist, skip creating", v.Image)
+ return nil
+ }
+
+ rbdDisk := fmt.Sprintf("rbd:%s/%s:id=%s", v.Pool, v.Image, configs.Conf.Storage.Ceph.Username)
+ // try to create rbd from image snapshot
+ if err := v.createSysRBDFromSnap(ctx, client, ioctx, img); err != nil {
+ logger.Warnf(ctx, "failed to create rbd(%s) from image(%s) snaoshot: %s", rbdDisk, img.Fullname(), err)
+
+ // try to create rbd from image file
+ if err := v.createSysRBDFromImageFile(ctx, img); err != nil {
+ return err
+ }
+ }
+ if err := interutils.ResizeImage(ctx, rbdDisk, v.SizeInBytes); err != nil {
+ if err := rbd.RemoveImage(ioctx, v.Image); err != nil {
+ logger.Warnf(ctx, "[rollback] failed to delete rbd %s: %s", rbdDisk, err)
+ }
+ return errors.Wrapf(err, "failed to resize rbd")
+ }
+ return nil
+}
+
+func (v *Volume) PrepareDataDisk(_ context.Context) error {
+ if v.IsSys() {
+ panic("not a data disk")
+ }
+ return nil
+}
+
+// qemu-img doesn't support checking rbd
+func (v *Volume) Check() error {
+ return nil
+}
+
+func (v *Volume) Repair() error {
+ return nil
+}
+
+func (v *Volume) GenerateXML() ([]byte, error) {
+ // prepare monitor addresses
+ cephMonitorAddrs := []map[string]string{}
+ for _, addr := range configs.Conf.Storage.Ceph.MonitorAddrs {
+ parts := strings.Split(addr, ":")
+ d := map[string]string{
+ "host": parts[0],
+ "port": parts[1],
+ }
+ cephMonitorAddrs = append(cephMonitorAddrs, d)
+ }
+
+ args := map[string]any{
+ "source": v.GetSource(),
+ "dev": v.Device,
+ "monitorAddrs": cephMonitorAddrs,
+ "username": configs.Conf.Storage.Ceph.Username,
+ "secretUUID": configs.Conf.Storage.Ceph.SecretUUID,
+ }
+ if tmpl == nil {
+ t, err := template.New("rbd-vol-tpl").Parse(diskXML)
+ if err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ tmpl = t
+ }
+
+ var wr bytes.Buffer
+ if err := tmpl.Execute(&wr, args); err != nil {
+ return nil, errors.Wrap(err, "")
+ }
+ return wr.Bytes(), nil
+}
+
+func GetRBDConn() (*rados.Conn, error) {
+ // todo... 需要安装配置 rbd rados连接
+ conn, err := rados.NewConnWithUser(configs.Conf.Storage.Ceph.Username)
+ if err != nil {
+ return nil, err
+ }
+ if err := conn.ReadDefaultConfigFile(); err != nil {
+ return nil, err
+ }
+ if err := conn.Connect(); err != nil {
+ return nil, err
+ }
+ // defer conn.Shutdown()
+ return conn, nil
+}
+
+// Cleanup is mainly used to clean old sys disk before reiniitializing sys disk
+func (v *Volume) Cleanup() error {
+ return nil
+}
+
+func (v *Volume) exist(ioctx *rados.IOContext) (bool, error) {
+ img, err := rbd.OpenImageReadOnly(ioctx, v.Image, rbd.NoSnapshot)
+ if err == nil {
+ img.Close()
+ return true, nil
+ }
+ if strings.Contains(err.Error(), "image not found") {
+ return false, nil
+ }
+ return false, err
+}
+
+func (v *Volume) CaptureImage(imgName string) (uimg *vmitypes.Image, err error) { //nolint
+ // rbdDisk := fmt.Sprintf("rbd:%s/%s:id=%s", v.Pool, v.Image, configs.Conf.Storage.Ceph.Username)
+
+ // log.Warnf("[Prepare] failed to clone snapshot(image %s, rbd: %s): %v", img.RBDName(), rbdDisk, err)
+
+ // if err := util.DumpBLK(context.TODO(), img.Filepath(), rbdDisk); err != nil {
+ // return errors.Wrap(err, "")
+ // }
+ return
+}
+
+func (v *Volume) Save() error {
+ if v.GetVer() == 0 {
+ return meta.Create(meta.Resources{v})
+ }
+ return meta.Save(meta.Resources{v})
+}
+
+func (v *Volume) Lock() error {
+ return nil
+}
+
+func (v *Volume) Unlock() {}
+
+func (v *Volume) NewSnapshotAPI() base.SnapshotAPI {
+ return newSnapshotAPI(v)
+}
+
+func (v *Volume) GetGfx() (guestfs.Guestfs, error) {
+ opts := &libguestfs.OptargsAdd_drive{
+ Readonly_is_set: false,
+ Format_is_set: true,
+ Format: "raw",
+ Protocol_is_set: true,
+ Protocol: "rbd",
+ Server_is_set: true,
+ // TODO add servers, user and secret for ceph
+ Server: []string{},
+ Username_is_set: true,
+ // User: "eru",
+ Secret_is_set: true,
+ Secret: "",
+ }
+ return gfsx.NewFromOpts(v.GetSource(), opts)
+}
+
+func (v *Volume) createSysRBDFromSnap(
+ _ context.Context, client *rados.Conn,
+ ioctx *rados.IOContext, img *vmitypes.Image,
+) (err error) {
+ snapshot := img.Snapshot
+ var srcPool, srcImgName, snapName string
+
+ if img.Snapshot != "" {
+ srcPool, srcImgName, snapName, err = parseSnapName(snapshot)
+ } else {
+ // this is for compatibility
+ srcPool = configs.Conf.Storage.Ceph.Username
+ srcImgName = img.RBDName()
+ snapName = "latest"
+ }
+ if err != nil {
+ return errors.Wrapf(err, "failed to parse snapshot name %s or image %s", snapshot, img.Fullname())
+ }
+
+ srcIOCtx := ioctx
+ if srcPool != v.Pool {
+ // try to create rbd from image rbd snapshot
+ if srcIOCtx, err = client.OpenIOContext(srcPool); err != nil {
+ return err
+ }
+ defer srcIOCtx.Destroy()
+ }
+ if err = rbd.CloneImage(srcIOCtx, srcImgName, snapName, ioctx, v.Image, rbd.NewRbdImageOptions()); err == nil {
+ return errors.Wrapf(err, "failed to clone image")
+ }
+ return nil
+}
+
+func (v *Volume) createSysRBDFromImageFile(ctx context.Context, img *vmitypes.Image) error {
+ rbdDisk := fmt.Sprintf("rbd:%s/%s:id=%s", v.Pool, v.Image, configs.Conf.Storage.Ceph.Username)
+ // try to create rbd from image file
+ rc, err := vmiFact.Pull(ctx, img, vmitypes.PullPolicyAlways)
+ if err != nil {
+ return errors.Wrapf(err, "failed to pull image %s", img.Fullname())
+ }
+ interutils.EnsureReaderClosed(rc)
+ if err := interutils.WriteBLK(ctx, img.Filepath(), rbdDisk, true); err != nil {
+ return errors.Wrap(err, "failed to write image file to rbd")
+ }
+ return nil
+}
diff --git a/internal/volume/rbd/volume_test.go b/internal/volume/rbd/volume_test.go
new file mode 100644
index 0000000..add5eb4
--- /dev/null
+++ b/internal/volume/rbd/volume_test.go
@@ -0,0 +1,39 @@
+package rbd
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/projecteru2/yavirt/pkg/test/assert"
+ "github.com/projecteru2/yavirt/pkg/utils"
+)
+
+func TestNewVolume(t *testing.T) {
+ cases := []struct {
+ in string
+ src string
+ dst string
+ size int64
+ }{
+ {"pool/image1:/data1", "pool/image1", "/data1", int64(0)},
+ {"pool/image1:/data1:rw:2G", "pool/image1", "/data1", int64(2 * utils.GB)},
+ }
+
+ for _, c := range cases {
+ vol, err := NewFromStr(c.in)
+ assert.NilErr(t, err)
+
+ assert.Equal(t, c.dst, vol.GetMountDir())
+ assert.Equal(t, c.src, vol.GetSource())
+ assert.Equal(t, c.size, vol.SizeInBytes)
+ }
+}
+
+func TestGenerateXML(t *testing.T) {
+ vol, err := NewFromStr("pool/image1:/data1:rw:2G")
+ vol.SetDevice("vda")
+ assert.NilErr(t, err)
+ bs, err := vol.GenerateXML()
+ assert.NilErr(t, err)
+ fmt.Printf("%s\n", string(bs))
+}
diff --git a/internal/volume/volume.go b/internal/volume/volume.go
new file mode 100644
index 0000000..2f18f01
--- /dev/null
+++ b/internal/volume/volume.go
@@ -0,0 +1,61 @@
+package volume
+
+import (
+ "context"
+
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/yavirt/internal/meta"
+ "github.com/projecteru2/yavirt/internal/virt/guestfs"
+ "github.com/projecteru2/yavirt/internal/volume/base"
+ vmitypes "github.com/yuyang0/vmimage/types"
+)
+
+type Volume interface { //nolint:interfacebloat
+ meta.GenericInterface
+
+ // getters
+ Name() string
+ QemuImagePath() string
+ GetMountDir() string
+ GetSize() int64
+ GetDevice() string
+ GetHostname() string
+ GetGuestID() string
+ // setters
+ SetDevice(dev string)
+ SetHostname(name string)
+ SetGuestID(id string)
+ SetSize(size int64)
+ GenerateID()
+
+ // Note: caller should call dom.Free() to release resource
+ Check() error
+ Repair() error
+ IsSys() bool
+ // prepare the volume, run before create guest.
+ PrepareSysDisk(context.Context, *vmitypes.Image, ...base.Option) error
+ PrepareDataDisk(context.Context) error
+
+ GenerateXML() ([]byte, error)
+ Cleanup() error
+ // delete data in store
+ Delete(force bool) error
+ CaptureImage(imgName string) (*vmitypes.Image, error)
+ // Save data to store
+ Save() error
+
+ Lock() error
+ Unlock()
+
+ GetGfx() (guestfs.Guestfs, error)
+
+ NewSnapshotAPI() base.SnapshotAPI
+}
+
+func WithLocker(vol Volume, fn func() error) error {
+ if err := vol.Lock(); err != nil {
+ return errors.Wrap(err, "")
+ }
+ defer vol.Unlock()
+ return fn()
+}
diff --git a/pkg/errors/const.go b/pkg/errors/const.go
deleted file mode 100644
index 102af2f..0000000
--- a/pkg/errors/const.go
+++ /dev/null
@@ -1,103 +0,0 @@
-package errors
-
-var (
- // ErrInvalidValue indicates the value is invalid.
- ErrInvalidValue = New("invalid value")
-
- // ErrExecIsRunning .
- ErrExecIsRunning = New("exec is still running")
- // ErrExecNonZeroReturn .
- ErrExecNonZeroReturn = New("exec return code is non-zero")
- // ErrExecOnNonRunningGuest .
- ErrExecOnNonRunningGuest = New("exec on a non-running guest")
-
- // ErrIPv4IsNetworkNumber .
- ErrIPv4IsNetworkNumber = New("IPv4 is a network number")
- // ErrIPv4IsBroadcastAddr .
- ErrIPv4IsBroadcastAddr = New("IPv4 is a broadcast addr")
-
- // ErrCalicoEndpointNotExists .
- ErrCalicoEndpointNotExists = New("Calico WorkloadEndpoint not exists")
- // ErrCalicoPoolNotExists .
- ErrCalicoPoolNotExists = New("Calico IP pool not exists")
- // ErrCalicoIPv4Only .
- ErrCalicoIPv4Only = New("only support Calico IPv4")
- // ErrCalicoCannotCrossBlocks .
- ErrCalicoCannotCrossBlocks = New("cannot cross Calico blocks")
- // ErrCalicoGatewayIPNotExists .
- ErrCalicoGatewayIPNotExists = New("Calico gateway IP not exists")
- // ErrCalicoTooSmallSubnet .
- ErrCalicoTooSmallSubnet = New("Calico subnet is too small to use")
-
- // ErrVirtLinkExists .
- ErrVirtLinkExists = New("link exists")
- // ErrVirtLinkNotExists .
- ErrVirtLinkNotExists = New("link not exists")
- // ErrVirtLinkAddrExists .
- ErrVirtLinkAddrExists = New("link addr exists")
- // ErrVirtLinkRouteExists .
- ErrVirtLinkRouteExists = New("link route exists")
-
- // ErrKeyExists .
- ErrKeyExists = New("key exists")
- // ErrKeyNotExists .
- ErrKeyNotExists = New("key not exists")
- // ErrKeyBadVersion .
- ErrKeyBadVersion = New("bad version")
-
- // ErrBatchOperate .
- ErrBatchOperate = New("batch operate error")
- // ErrOperateIP .
- ErrOperateIP = New("operate IP error")
- // ErrForwardStatus .
- ErrForwardStatus = New("cannot forward status")
- // ErrConnectLibvirtd .
- ErrConnectLibvirtd = New("connect libvirtd error")
- // ErrSysVolumeNotExists .
- ErrSysVolumeNotExists = New("sys volume not exists")
- // ErrNotSysVolume .
- ErrNotSysVolume = New("not sys volume")
- // ErrTooManyVolumes .
- ErrTooManyVolumes = New("too many extra volumes")
- // ErrCannotShrinkVolume .
- ErrCannotShrinkVolume = New("cannot shrink a volume")
- // ErrDomainNotExists .
- ErrDomainNotExists = New("domain not exists")
-
- // ErrTooLargeOffset .
- ErrTooLargeOffset = New("too large offset")
- // ErrNoSuchIPPool .
- ErrNoSuchIPPool = New("no such IPPool")
- // ErrTooLargeMaskBits .
- ErrTooLargeMaskBits = New("too large mask bits")
- // ErrTooSmallMaskBits .
- ErrTooSmallMaskBits = New("too small mask bits")
- // ErrInsufficientBlocks .
- ErrInsufficientBlocks = New("insufficient blocks")
- // ErrInsufficientIP .
- ErrInsufficientIP = New("insufficient free IP")
- // ErrIPIsnotAssigned .
- ErrIPIsnotAssigned = New("IP isn't assigned")
-
- // ErrSerializedTaskAborted .
- ErrSerializedTaskAborted = New("serialized task was aborted in advance")
-
- // ErrTimeout .
- ErrTimeout = New("timed out")
- // ErrNotImplemented .
- ErrNotImplemented = New("does not implemented")
-
- // ErrFolderExists .
- ErrFolderExists = New("destination folder exists")
- // ErrDestinationInvalid .
- ErrDestinationInvalid = New("destination path not valid")
- // ErrNotValidCopyStatus .
- ErrNotValidCopyStatus = New("cannot copy in this status")
- // ErrNotValidLogStatus .
- ErrNotValidLogStatus = New("cannot read log in this status")
-
- // ErrImageHubNotConfigured .
- ErrImageHubNotConfigured = New("ImageHub is not set")
- // ErrImageFileNotExists .
- ErrImageFileNotExists = New("Image File not exists")
-)
diff --git a/pkg/errors/errors.go b/pkg/errors/errors.go
deleted file mode 100644
index 09880eb..0000000
--- a/pkg/errors/errors.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package errors
-
-import je "github.com/juju/errors"
-
-var (
- // New .
- New = je.New
- // Stack .
- Stack = je.ErrorStack
- // Trace .
- Trace = je.Trace
- // Annotatef .
- Annotatef = je.Annotatef
- // Errorf .
- Errorf = je.Errorf
- // Wrap .
- Wrap = je.Wrap
- // Cause .
- Cause = je.Cause
-)
-
-// Contain .
-func Contain(a, b error) bool {
- var pre = Cause(a)
-
- // No previous error.
- if pre == a {
- return a == b
- }
-
- if pre == b {
- return true
- }
-
- return Contain(pre, b)
-}
diff --git a/pkg/idgen/idgen.go b/pkg/idgen/idgen.go
index f647351..eef705f 100644
--- a/pkg/idgen/idgen.go
+++ b/pkg/idgen/idgen.go
@@ -1,42 +1,69 @@
package idgen
import (
+ "bytes"
+ "crypto/rand"
+ "encoding/binary"
"fmt"
+ "io"
"strconv"
+ "sync/atomic"
"time"
-
- "github.com/projecteru2/yavirt/pkg/utils"
)
// Generator .
type Generator struct {
- prefix uint32
- suffix uint64
- counter utils.AtomicInt64
+ memberID uint32
+ randPrefix uint32
+ counter uint32
}
// New .
-func New(memberID uint32, seed time.Time) *Generator {
- return &Generator{
- prefix: memberID,
- suffix: uint64(seed.UnixNano()) / uint64(time.Microsecond),
+func New(memberID uint32) (*Generator, error) {
+ if memberID >= 100000 {
+ return nil, fmt.Errorf("member id is too large: %d", memberID)
}
+ return &Generator{
+ memberID: memberID,
+ randPrefix: getRandomUint32() % 1000000,
+ counter: getRandomUint32(),
+ }, nil
}
// Next .
func (g *Generator) Next() string {
- var b36 = strconv.FormatInt(g.counter.Incr(), 36)
- return fmt.Sprintf("%010d%017d%05s", g.prefix, g.suffix, b36)
+ counter := atomic.AddUint32(&g.counter, 1)
+ var b36 = strconv.FormatInt(int64(counter), 36)
+ suffix := uint64(time.Now().UnixMilli())
+ return fmt.Sprintf("%05d%06d%013d%08s", g.memberID, g.randPrefix, suffix, b36)
}
var gen *Generator
// Setup .
-func Setup(memberID uint32, seed time.Time) {
- gen = New(memberID, seed)
+func Setup(memberID uint32) (err error) {
+ gen, err = New(memberID)
+ return
}
// Next .
func Next() string {
return gen.Next()
}
+
+func CheckID(id string) bool {
+ return len(id) >= 32
+}
+
+func getRandomUint32() uint32 {
+ var b [4]byte
+ _, err := io.ReadFull(rand.Reader, b[:])
+ if err != nil {
+ panic(fmt.Errorf("cannot initialize objectid package with crypto.rand.Reader: %w", err))
+ }
+ var ans uint32
+ if err := binary.Read(bytes.NewBuffer(b[:]), binary.LittleEndian, &ans); err != nil {
+ panic(fmt.Errorf("failed to convert byte array to integer %s: %s", b, err))
+ }
+ return ans
+}
diff --git a/pkg/idgen/idgen_test.go b/pkg/idgen/idgen_test.go
index 01eabf5..3b600c5 100644
--- a/pkg/idgen/idgen_test.go
+++ b/pkg/idgen/idgen_test.go
@@ -1,17 +1,80 @@
package idgen
import (
+ "fmt"
+ "math"
+ "strconv"
+ "sync"
"testing"
+ "time"
+
+ "github.com/projecteru2/yavirt/pkg/test/assert"
)
-func TestGenerator(t *testing.T) {
- // TODO
+func TestNewGenerator(t *testing.T) {
+ for idx := 0; idx < 99999; idx++ {
+ g, err := New(uint32(idx))
+ assert.Nil(t, err)
+ assert.True(t, g.randPrefix < 1000000)
+ }
+ ss := strconv.FormatInt(int64(math.MaxUint32), 32)
+ assert.True(t, len(ss) < 8, true)
+}
+
+func TestNewID(t *testing.T) {
+ Setup(0)
+ seen := make(map[string]any)
+ for i := 0; i < 400000; i++ {
+ id := Next()
+ _, ok := seen[id]
+ assert.False(t, ok)
+ seen[id] = struct{}{}
+ assert.True(t, CheckID(id))
+ }
+}
+
+func TestConcurrency(t *testing.T) {
+ Setup(1)
+ var seen sync.Map
+ var wg sync.WaitGroup
+ for i := 0; i < 10; i++ {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ for i := 0; i < 100000; i++ {
+ id := Next()
+ assert.True(t, CheckID(id))
+ _, loaded := seen.LoadOrStore(id, struct{}{})
+ assert.False(t, loaded)
+ }
+ }()
+ }
+ wg.Wait()
+}
+
+func TestInvalidMemberID(t *testing.T) {
+ assert.NilErr(t, Setup(math.MaxUint16))
+ assert.Err(t, Setup(100000))
+ assert.Equal(t, fmt.Sprintf("%05d", math.MaxUint16), "65535")
}
-func TestGeneratorsWithSameSeed(t *testing.T) {
- // TODO
+func TestGetRandomPrefix(t *testing.T) {
+ seen := map[uint32]bool{}
+ conflict := 0
+ size := 10000
+ for idx := 0; idx < size; idx++ {
+ v := getRandomUint32()
+ if _, ok := seen[v]; ok {
+ conflict++
+ }
+ seen[v] = true
+ }
+ conflictRatio := float64(conflict) / float64(size)
+ assert.True(t, conflictRatio < 0.03)
}
-func TestGeneratorsWithDifferentSeed(t *testing.T) {
- // TODO
+func TestTimeLength(t *testing.T) {
+ t1 := time.Now().Add(200 * 365 * 24 * time.Hour)
+ microSec := t1.UnixMilli()
+ assert.Equal(t, len(fmt.Sprintf("%d", microSec)), 13)
}
diff --git a/pkg/libvirt/console.go b/pkg/libvirt/console.go
new file mode 100644
index 0000000..b9db6eb
--- /dev/null
+++ b/pkg/libvirt/console.go
@@ -0,0 +1,140 @@
+package libvirt
+
+import (
+ "context"
+ "io"
+ "sync"
+
+ "github.com/projecteru2/core/log"
+ "github.com/projecteru2/yavirt/pkg/utils"
+ libvirtgo "github.com/projecteru2/yavirt/third_party/libvirt"
+)
+
+type ConsoleFlags struct {
+ Force bool
+ Safe bool
+ Nonblock bool
+}
+
+func (cf *ConsoleFlags) genLibvirtFlags() (flags libvirtgo.DomainConsoleFlags) {
+ if cf.Force {
+ flags |= libvirtgo.DomainConsoleForce
+ }
+ if cf.Safe {
+ flags |= libvirtgo.DomainConsoleSafe
+ }
+ return
+}
+
+func (cf *ConsoleFlags) genStreamFlags() (flags libvirtgo.StreamFlags) { //nolint
+ if cf.Nonblock {
+ flags = libvirtgo.StreamNonblock
+ }
+ return
+}
+
+type Console struct {
+ // pty to user
+ fromQ *utils.BytesQueue
+ // user to pty
+ toQ *utils.BytesQueue
+
+ quit struct {
+ once sync.Once
+ c chan struct{}
+ }
+}
+
+func newConsole() *Console {
+ con := &Console{
+ fromQ: utils.NewBytesQueue(),
+ toQ: utils.NewBytesQueue(),
+ }
+ con.quit.c = make(chan struct{})
+ return con
+}
+
+func (c *Console) needExit(ctx context.Context) bool {
+ select {
+ case <-ctx.Done():
+ return true
+ case <-c.quit.c:
+ return true
+ default:
+ return false
+ }
+}
+
+func (c *Console) From(ctx context.Context, r io.Reader) error {
+ logger := log.WithFunc("Console.From")
+ buf := make([]byte, 64*1024)
+ for {
+ if c.needExit(ctx) {
+ return nil
+ }
+ n, err := r.Read(buf)
+ if n == 0 {
+ if err != nil {
+ if err != io.EOF {
+ logger.Errorf(ctx, err, "[Console:From] read error")
+ }
+ return err
+ }
+ continue
+ }
+
+ bs := buf[:n]
+ _, err = c.toQ.Write(bs)
+ if err != nil {
+ logger.Errorf(ctx, err, "write error")
+ return err
+ }
+ }
+}
+
+func (c *Console) To(ctx context.Context, w io.Writer) error {
+ logger := log.WithFunc("Console.To")
+ buf := make([]byte, 64*1024)
+ for {
+ if c.needExit(ctx) {
+ return nil
+ }
+ // pty to user
+ n, err := c.fromQ.Read(buf)
+ if n == 0 {
+ if err != nil {
+ if err != io.EOF {
+ logger.Errorf(ctx, err, "read error")
+ }
+ return err
+ }
+ continue
+ }
+ if c.needExit(ctx) {
+ return nil
+ }
+
+ _, err = w.Write(buf[:n])
+ if err != nil {
+ logger.Errorf(ctx, err, "write error")
+ return err
+ }
+ copy(buf, make([]byte, len(buf)))
+ }
+}
+
+func (c *Console) Write(buf []byte) (int, error) {
+ return c.fromQ.Write(buf)
+}
+
+func (c *Console) Read(p []byte) (int, error) {
+ return c.toQ.Read(p)
+}
+
+func (c *Console) Close() {
+ c.quit.once.Do(func() {
+ c.fromQ.Close()
+ c.toQ.Close()
+ close(c.quit.c)
+ })
+}
diff --git a/pkg/libvirt/consts.go b/pkg/libvirt/consts.go
index 4411949..b7bef4a 100644
--- a/pkg/libvirt/consts.go
+++ b/pkg/libvirt/consts.go
@@ -1,76 +1,79 @@
package libvirt
-import libvirtgo "github.com/libvirt/libvirt-go"
+import (
+ libvirtgo "github.com/projecteru2/yavirt/third_party/libvirt"
+)
const (
// ListAllDomainFlags shows all states for listing domain operation.
- ListAllDomainFlags = libvirtgo.CONNECT_LIST_DOMAINS_ACTIVE |
- libvirtgo.CONNECT_LIST_DOMAINS_INACTIVE |
- libvirtgo.CONNECT_LIST_DOMAINS_PERSISTENT |
- libvirtgo.CONNECT_LIST_DOMAINS_TRANSIENT |
- libvirtgo.CONNECT_LIST_DOMAINS_RUNNING |
- libvirtgo.CONNECT_LIST_DOMAINS_PAUSED |
- libvirtgo.CONNECT_LIST_DOMAINS_SHUTOFF |
- libvirtgo.CONNECT_LIST_DOMAINS_OTHER |
- libvirtgo.CONNECT_LIST_DOMAINS_MANAGEDSAVE |
- libvirtgo.CONNECT_LIST_DOMAINS_NO_MANAGEDSAVE |
- libvirtgo.CONNECT_LIST_DOMAINS_AUTOSTART |
- libvirtgo.CONNECT_LIST_DOMAINS_NO_AUTOSTART |
- libvirtgo.CONNECT_LIST_DOMAINS_HAS_SNAPSHOT |
- libvirtgo.CONNECT_LIST_DOMAINS_NO_SNAPSHOT
+ ListAllDomainFlags = libvirtgo.ConnectListDomainsActive |
+ libvirtgo.ConnectListDomainsInactive |
+ libvirtgo.ConnectListDomainsPersistent |
+ libvirtgo.ConnectListDomainsTransient |
+ libvirtgo.ConnectListDomainsRunning |
+ libvirtgo.ConnectListDomainsPaused |
+ libvirtgo.ConnectListDomainsShutoff |
+ libvirtgo.ConnectListDomainsOther |
+ libvirtgo.ConnectListDomainsManagedsave |
+ libvirtgo.ConnectListDomainsNoManagedsave |
+ libvirtgo.ConnectListDomainsAutostart |
+ libvirtgo.ConnectListDomainsNoAutostart |
+ libvirtgo.ConnectListDomainsHasSnapshot |
+ libvirtgo.ConnectListDomainsNoSnapshot
// DomainNoState .
- DomainNoState = libvirtgo.DOMAIN_NOSTATE
+ DomainNoState = libvirtgo.DomainNostate
// DomainRunning .
- DomainRunning = libvirtgo.DOMAIN_RUNNING
+ DomainRunning = libvirtgo.DomainRunning
// DomainUndefineManagedSave .
- DomainUndefineManagedSave = libvirtgo.DOMAIN_UNDEFINE_MANAGED_SAVE
+ DomainUndefineManagedSave = libvirtgo.DomainUndefineManagedSave
// DomainShutoff is shutted down.
- DomainShutoff = libvirtgo.DOMAIN_SHUTOFF
+ DomainShutoff = libvirtgo.DomainShutoff
// DomainShutting is shuting state.
- DomainShutting = libvirtgo.DOMAIN_SHUTDOWN
+ DomainShutting = libvirtgo.DomainShutdown
// DomainPMSuspended .
- DomainPMSuspended = libvirtgo.DOMAIN_PMSUSPENDED
+ DomainPMSuspended = libvirtgo.DomainPmsuspended
// DomainCrashed .
- DomainCrashed = libvirtgo.DOMAIN_CRASHED
+ DomainCrashed = libvirtgo.DomainCrashed
// DomainPaused .
- DomainPaused = libvirtgo.DOMAIN_PAUSED
+ DomainPaused = libvirtgo.DomainPaused
// DomainBlocked .
- DomainBlocked = libvirtgo.DOMAIN_BLOCKED
+ DomainBlocked = libvirtgo.DomainBlocked
// DomainDestroyDefault .
- DomainDestroyDefault = libvirtgo.DOMAIN_DESTROY_DEFAULT
+ DomainDestroyDefault = libvirtgo.DomainDestroyDefault
// DomainShutdownDefault .
- DomainShutdownDefault = libvirtgo.DOMAIN_SHUTDOWN_DEFAULT
+ DomainShutdownDefault = libvirtgo.DomainShutdownDefault
// DomainVcpuCurrent .
- DomainVcpuCurrent = libvirtgo.DOMAIN_VCPU_CURRENT
+ DomainVcpuCurrent = libvirtgo.DomainVCPUCurrent
// DomainVcpuMaximum .
- DomainVcpuMaximum = libvirtgo.DOMAIN_VCPU_MAXIMUM
+ DomainVcpuMaximum = libvirtgo.DomainVCPUMaximum
// DomainVcpuConfig .
- DomainVcpuConfig = libvirtgo.DOMAIN_VCPU_CONFIG
+ DomainVcpuConfig = libvirtgo.DomainVCPUConfig
+
// DomainVcpuLive .
- DomainVcpuLive = libvirtgo.DOMAIN_VCPU_LIVE
+ DomainVcpuLive = libvirtgo.DomainVCPULive
// DomainMemCurrent .
- DomainMemCurrent = libvirtgo.DOMAIN_MEM_CURRENT
+ DomainMemCurrent = libvirtgo.DomainMemCurrent
// DomainMemMaximum .
- DomainMemMaximum = libvirtgo.DOMAIN_MEM_MAXIMUM
+ DomainMemMaximum = libvirtgo.DomainMemMaximum
// DomainMemConfig .
- DomainMemConfig = libvirtgo.DOMAIN_MEM_CONFIG
+ DomainMemConfig = libvirtgo.DomainMemConfig
// DomainConsoleForce .
- DomainConsoleForce = libvirtgo.DOMAIN_CONSOLE_FORCE
+ DomainConsoleForce = libvirtgo.DomainConsoleForce
// DomainConsoleSafe .
- DomainConsoleSafe = libvirtgo.DOMAIN_CONSOLE_SAFE
+ DomainConsoleSafe = libvirtgo.DomainConsoleSafe
// DomainBlockResizeBytes .
- DomainBlockResizeBytes = libvirtgo.DOMAIN_BLOCK_RESIZE_BYTES
+ DomainBlockResizeBytes = libvirtgo.DomainBlockResizeBytes
// DomainDeviceModifyConfig .
- DomainDeviceModifyConfig = libvirtgo.DOMAIN_DEVICE_MODIFY_CONFIG
+ DomainDeviceModifyConfig = libvirtgo.DomainDeviceModifyConfig
// DomainDeviceModifyCurrent .
- DomainDeviceModifyCurrent = libvirtgo.DOMAIN_DEVICE_MODIFY_CURRENT
+ DomainDeviceModifyCurrent = libvirtgo.DomainDeviceModifyCurrent
// DomainDeviceModifyLive .
- DomainDeviceModifyLive = libvirtgo.DOMAIN_DEVICE_MODIFY_LIVE
+ DomainDeviceModifyLive = libvirtgo.DomainDeviceModifyLive
)
diff --git a/pkg/libvirt/domain.go b/pkg/libvirt/domain.go
index 37fd4a4..e9d4eac 100644
--- a/pkg/libvirt/domain.go
+++ b/pkg/libvirt/domain.go
@@ -1,15 +1,20 @@
package libvirt
import (
- libvirtgo "github.com/libvirt/libvirt-go"
+ "context"
+ "encoding/hex"
+ "time"
- "github.com/projecteru2/yavirt/pkg/errors"
- "github.com/projecteru2/yavirt/pkg/log"
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/core/log"
+ "github.com/projecteru2/yavirt/pkg/terrors"
+ libvirtgo "github.com/projecteru2/yavirt/third_party/libvirt"
)
// Domain .
type Domain interface { //nolint
Create() error
+ SetAutostart(autostart bool) error
ShutdownFlags(flags DomainShutdownFlags) error
Destroy() error
DestroyFlags(flags DomainDestroyFlags) error
@@ -19,39 +24,211 @@ type Domain interface { //nolint
SetVcpusFlags(vcpu uint, flags DomainVcpuFlags) error
SetMemoryFlags(memory uint64, flags DomainMemoryModFlags) error
+ SetMemoryStatsPeriod(period int, config, live bool) error
AmplifyVolume(filepath string, cap uint64) error
- AttachVolume(xml string) (DomainState, error)
-
- Free()
+ AttachDevice(xml string) (DomainState, error)
+ DetachDevice(xml string) (st DomainState, err error)
GetState() (DomainState, error)
GetInfo() (*DomainInfo, error)
GetUUIDString() (string, error)
GetXMLDesc(flags DomainXMLFlags) (string, error)
GetName() (string, error)
+ QemuAgentCommand(ctx context.Context, cmd string) (string, error)
+ OpenConsole(devname string, flags *ConsoleFlags) (*Console, error)
}
// Domainee is a implement of Domain.
type Domainee struct {
+ Libvirt *libvirtgo.Libvirt
*libvirtgo.Domain
}
+func (d *Domainee) Create() error {
+ err := d.Libvirt.DomainCreate(*d.Domain)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (d *Domainee) SetAutostart(autostart bool) error {
+ autostartFlag := int32(0)
+ if autostart {
+ autostartFlag = 1
+ }
+ err := d.Libvirt.DomainSetAutostart(*d.Domain, autostartFlag)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (d *Domainee) ShutdownFlags(flags DomainShutdownFlags) error {
+ err := d.Libvirt.DomainShutdownFlags(*d.Domain, libvirtgo.DomainShutdownFlagValues(flags))
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (d *Domainee) Destroy() error {
+ err := d.Libvirt.DomainDestroy(*d.Domain)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (d *Domainee) DestroyFlags(flags DomainDestroyFlags) error {
+ err := d.Libvirt.DomainDestroyFlags(*d.Domain, flags)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (d *Domainee) UndefineFlags(flags DomainUndefineFlags) error {
+ err := d.Libvirt.DomainUndefineFlags(*d.Domain, flags)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (d *Domainee) Suspend() error {
+ err := d.Libvirt.DomainSuspend(*d.Domain)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (d *Domainee) Resume() error {
+ err := d.Libvirt.DomainResume(*d.Domain)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (d *Domainee) SetVcpusFlags(vcpu uint, flags DomainVcpuFlags) error {
+ err := d.Libvirt.DomainSetVcpusFlags(*d.Domain, uint32(vcpu), uint32(flags))
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (d *Domainee) SetMemoryFlags(memory uint64, flags DomainMemoryModFlags) error {
+ err := d.Libvirt.DomainSetMemoryFlags(*d.Domain, memory, uint32(flags))
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (d *Domainee) GetInfo() (*DomainInfo, error) {
+ rState, rMaxMem, rMemory, rNrVirtCPU, rCPUTime, err := d.Libvirt.DomainGetInfo(*d.Domain)
+ if err != nil {
+ return nil, err
+ }
+ info := &libvirtgo.DomainGetInfoRet{
+ State: rState,
+ MaxMem: rMaxMem,
+ Memory: rMemory,
+ NrVirtCPU: rNrVirtCPU,
+ CPUTime: rCPUTime,
+ }
+ return info, nil
+}
+
+func (d *Domainee) GetUUIDString() (string, error) {
+ return hex.EncodeToString(d.Domain.UUID[:]), nil
+}
+
+func (d *Domainee) GetXMLDesc(flags DomainXMLFlags) (string, error) {
+ desc, err := d.Libvirt.DomainGetXMLDesc(*d.Domain, flags)
+ if err != nil {
+ return "", err
+ }
+ return desc, nil
+}
+
+func (d *Domainee) GetName() (string, error) {
+ return d.Domain.Name, nil
+}
+
// NewDomainee converts a libvirt-go Domain object to a *Domainee object.
-func NewDomainee(raw *libvirtgo.Domain) (dom *Domainee) {
+func NewDomainee(lib *libvirtgo.Libvirt, raw *libvirtgo.Domain) (dom *Domainee) {
dom = &Domainee{}
+ dom.Libvirt = lib
dom.Domain = raw
return
}
-// Free .
-func (d *Domainee) Free() {
- if err := d.Domain.Free(); err != nil {
- log.ErrorStack(err)
+func (d *Domainee) SetMemoryStatsPeriod(period int, config, live bool) error {
+ flags := libvirtgo.DomainMemCurrent
+ if config {
+ flags |= libvirtgo.DomainMemConfig
}
+ if live {
+ flags |= libvirtgo.DomainMemLive
+ }
+ return d.Libvirt.DomainSetMemoryStatsPeriod(*d.Domain, int32(period), flags)
+}
+
+func (d *Domainee) QemuAgentCommand(ctx context.Context, cmd string) (string, error) {
+ flags := uint32(0)
+ timeout := libvirtgo.DomainAgentResponseTimeoutDefault
+ if deadline, ok := ctx.Deadline(); ok {
+ remain := time.Until(deadline)
+ timeout = libvirtgo.DomainAgentResponseTimeoutValues(remain.Seconds())
+ }
+ retStrArr, err := d.Libvirt.QEMUDomainAgentCommand(*d.Domain, cmd, int32(timeout), flags)
+ if err != nil {
+ log.Debugf(ctx, "[Domainee_QemuAgentCommand] Libvirt.QEMUDomainAgentCommand err, msg: %s, trace: %s", err.Error(), errors.Wrap(err, "").Error())
+ return "", err
+ }
+ if len(retStrArr) == 0 {
+ return "", nil
+ }
+ return retStrArr[0], nil
+}
+
+func (d *Domainee) OpenConsole(devname string, cf *ConsoleFlags) (*Console, error) {
+ con := newConsole()
+ go func() {
+ err := d.Libvirt.OpenConsole(*d.Domain, libvirtgo.OptString{devname}, con, con, uint32(cf.genLibvirtFlags()))
+ if err != nil {
+ log.Errorf(context.TODO(), err, "[Domainee:OpenConsole] Libvirt.DomainOpenConsole err")
+ return
+ }
+ }()
+
+ return con, nil
+}
+
+// AttachVolume .
+func (d *Domainee) AttachDevice(xml string) (st DomainState, err error) {
+ flags := DomainDeviceModifyConfig | DomainDeviceModifyCurrent
+
+ switch st, err = d.GetState(); {
+ case err != nil:
+ return
+ case st == DomainRunning:
+ flags |= DomainDeviceModifyLive
+ case st != DomainShutoff:
+ return DomainNoState, errors.Wrapf(terrors.ErrInvalidValue, "invalid domain state: %v", st)
+ }
+
+ err = d.Libvirt.DomainAttachDeviceFlags(*d.Domain, xml, uint32(flags))
+
+ return
}
// AttachVolume .
-func (d *Domainee) AttachVolume(xml string) (st DomainState, err error) {
+func (d *Domainee) DetachDevice(xml string) (st DomainState, err error) {
flags := DomainDeviceModifyConfig | DomainDeviceModifyCurrent
switch st, err = d.GetState(); {
@@ -60,21 +237,23 @@ func (d *Domainee) AttachVolume(xml string) (st DomainState, err error) {
case st == DomainRunning:
flags |= DomainDeviceModifyLive
case st != DomainShutoff:
- return DomainNoState, errors.Annotatef(errors.ErrInvalidValue, "invalid domain state: %v", st)
+ return DomainNoState, errors.Wrapf(terrors.ErrInvalidValue, "invalid domain state: %v", st)
}
- err = d.Domain.AttachDeviceFlags(xml, flags)
+ err = d.Libvirt.DomainDetachDeviceFlags(*d.Domain, xml, uint32(flags))
return
}
// GetState .
func (d *Domainee) GetState() (st DomainState, err error) {
- st, _, err = d.Domain.GetState()
+ flags := DomainNoState
+ iSt, _, err := d.Libvirt.DomainGetState(*d.Domain, uint32(flags))
+ st = DomainState(iSt)
return
}
// AmplifyVolume .
func (d *Domainee) AmplifyVolume(filepath string, cap uint64) error {
- return d.Domain.BlockResize(filepath, cap, DomainBlockResizeBytes)
+ return d.Libvirt.DomainBlockResize(*d.Domain, filepath, cap, DomainBlockResizeBytes)
}
diff --git a/pkg/libvirt/error.go b/pkg/libvirt/error.go
index 7b17a53..9b20740 100644
--- a/pkg/libvirt/error.go
+++ b/pkg/libvirt/error.go
@@ -1,6 +1,6 @@
package libvirt
-import libvirtgo "github.com/libvirt/libvirt-go"
+import libvirtgo "github.com/projecteru2/yavirt/third_party/libvirt"
// IsErrNoDomain is the err indicating not exists.
func IsErrNoDomain(err error) bool {
@@ -9,7 +9,7 @@ func IsErrNoDomain(err error) bool {
}
if e, ok := err.(libvirtgo.Error); ok {
- return e.Code == libvirtgo.ERR_NO_DOMAIN
+ return e.Code == uint32(libvirtgo.ErrNoDomain)
}
return false
diff --git a/pkg/libvirt/libvirt.go b/pkg/libvirt/libvirt.go
index 62170c9..53204c9 100644
--- a/pkg/libvirt/libvirt.go
+++ b/pkg/libvirt/libvirt.go
@@ -1,9 +1,13 @@
package libvirt
import (
- libvirtgo "github.com/libvirt/libvirt-go"
+ "net"
+ "time"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/yavirt/pkg/terrors"
+ libvirtgo "github.com/projecteru2/yavirt/third_party/libvirt"
+ "github.com/projecteru2/yavirt/third_party/libvirt/socket/dialers"
)
// Libvirt uses to interact with libvirtd service.
@@ -12,53 +16,67 @@ type Libvirt interface {
LookupDomain(string) (Domain, error)
DefineDomain(string) (Domain, error)
ListDomainsNames() ([]string, error)
+ GetAllDomainStats(doms []libvirtgo.Domain) ([]libvirtgo.DomainStatsRecord, error)
}
// Libvirtee is a Libvirt implement.
type Libvirtee struct {
- *libvirtgo.Connect
+ *libvirtgo.Libvirt
+}
+
+func (l *Libvirtee) Close() (int, error) {
+ err := l.ConnectClose()
+ if err != nil {
+ return 0, err
+ }
+ return 1, nil
}
// Connect connects a guest's domain.
func Connect(uri string) (l *Libvirtee, err error) {
+ c, err := net.DialTimeout("unix", "/var/run/libvirt/libvirt-sock", 5*time.Second)
+ if err != nil {
+ return nil, err
+ }
l = &Libvirtee{}
- l.Connect, err = libvirtgo.NewConnect(uri)
+ l.Libvirt = libvirtgo.NewWithDialer(dialers.NewAlreadyConnected(c))
+ if err = l.ConnectToURI(libvirtgo.ConnectURI(uri)); err != nil {
+ return nil, err
+ }
return
}
// DefineDomain defines a new domain.
func (l *Libvirtee) DefineDomain(xml string) (Domain, error) {
- raw, err := l.Connect.DomainDefineXML(xml)
+ raw, err := l.DomainDefineXML(xml)
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
- return NewDomainee(raw), nil
+ return NewDomainee(l.Libvirt, &raw), nil
}
// LookupDomain looks up a domain by name.
func (l *Libvirtee) LookupDomain(name string) (Domain, error) {
- raw, err := l.Connect.LookupDomainByName(name)
+ raw, err := l.DomainLookupByName(name)
if err != nil {
if IsErrNoDomain(err) {
- return nil, errors.Annotatef(errors.ErrDomainNotExists, name)
+ return nil, errors.Wrapf(terrors.ErrDomainNotExists, name)
}
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
- return NewDomainee(raw), nil
+ return NewDomainee(l.Libvirt, &raw), nil
}
// ListDomainsNames lists all domains' name.
func (l *Libvirtee) ListDomainsNames() ([]string, error) {
raw, err := l.ListAllDomains()
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
names := make([]string, len(raw))
for i, d := range raw {
- if names[i], err = d.GetName(); err != nil {
- return nil, errors.Trace(err)
- }
+ names[i] = d.Name
}
return names, nil
@@ -66,5 +84,13 @@ func (l *Libvirtee) ListDomainsNames() ([]string, error) {
// ListAllDomains lists all domains regardless the state.
func (l *Libvirtee) ListAllDomains() ([]libvirtgo.Domain, error) {
- return l.Connect.ListAllDomains(ListAllDomainFlags)
+ flags := libvirtgo.ConnectListDomainsActive | libvirtgo.ConnectListDomainsInactive
+ dList, _, err := l.ConnectListAllDomains(int32(flags), ListAllDomainFlags)
+ return dList, err
+}
+
+func (l *Libvirtee) GetAllDomainStats(doms []libvirtgo.Domain) ([]libvirtgo.DomainStatsRecord, error) {
+ flags := libvirtgo.ConnectGetAllDomainsStatsRunning
+ var statsType libvirtgo.DomainStatsTypes
+ return l.ConnectGetAllDomainStats(doms, uint32(statsType), flags)
}
diff --git a/pkg/libvirt/mocks/Domain.go b/pkg/libvirt/mocks/Domain.go
index ed700e2..0ab7573 100644
--- a/pkg/libvirt/mocks/Domain.go
+++ b/pkg/libvirt/mocks/Domain.go
@@ -1,10 +1,14 @@
-// Code generated by mockery v2.26.1. DO NOT EDIT.
+// Code generated by mockery v2.33.2. DO NOT EDIT.
package mocks
import (
- libvirt_go "github.com/libvirt/libvirt-go"
+ context "context"
+
+ libvirt "github.com/projecteru2/yavirt/pkg/libvirt"
mock "github.com/stretchr/testify/mock"
+
+ third_partylibvirt "github.com/projecteru2/yavirt/third_party/libvirt"
)
// Domain is an autogenerated mock type for the Domain type
@@ -26,19 +30,19 @@ func (_m *Domain) AmplifyVolume(filepath string, cap uint64) error {
return r0
}
-// AttachVolume provides a mock function with given fields: xml
-func (_m *Domain) AttachVolume(xml string) (libvirt_go.DomainState, error) {
+// AttachDevice provides a mock function with given fields: xml
+func (_m *Domain) AttachDevice(xml string) (third_partylibvirt.DomainState, error) {
ret := _m.Called(xml)
- var r0 libvirt_go.DomainState
+ var r0 third_partylibvirt.DomainState
var r1 error
- if rf, ok := ret.Get(0).(func(string) (libvirt_go.DomainState, error)); ok {
+ if rf, ok := ret.Get(0).(func(string) (third_partylibvirt.DomainState, error)); ok {
return rf(xml)
}
- if rf, ok := ret.Get(0).(func(string) libvirt_go.DomainState); ok {
+ if rf, ok := ret.Get(0).(func(string) third_partylibvirt.DomainState); ok {
r0 = rf(xml)
} else {
- r0 = ret.Get(0).(libvirt_go.DomainState)
+ r0 = ret.Get(0).(third_partylibvirt.DomainState)
}
if rf, ok := ret.Get(1).(func(string) error); ok {
@@ -79,11 +83,11 @@ func (_m *Domain) Destroy() error {
}
// DestroyFlags provides a mock function with given fields: flags
-func (_m *Domain) DestroyFlags(flags libvirt_go.DomainDestroyFlags) error {
+func (_m *Domain) DestroyFlags(flags third_partylibvirt.DomainDestroyFlagsValues) error {
ret := _m.Called(flags)
var r0 error
- if rf, ok := ret.Get(0).(func(libvirt_go.DomainDestroyFlags) error); ok {
+ if rf, ok := ret.Get(0).(func(third_partylibvirt.DomainDestroyFlagsValues) error); ok {
r0 = rf(flags)
} else {
r0 = ret.Error(0)
@@ -92,25 +96,44 @@ func (_m *Domain) DestroyFlags(flags libvirt_go.DomainDestroyFlags) error {
return r0
}
-// Free provides a mock function with given fields:
-func (_m *Domain) Free() {
- _m.Called()
+// DetachDevice provides a mock function with given fields: xml
+func (_m *Domain) DetachDevice(xml string) (third_partylibvirt.DomainState, error) {
+ ret := _m.Called(xml)
+
+ var r0 third_partylibvirt.DomainState
+ var r1 error
+ if rf, ok := ret.Get(0).(func(string) (third_partylibvirt.DomainState, error)); ok {
+ return rf(xml)
+ }
+ if rf, ok := ret.Get(0).(func(string) third_partylibvirt.DomainState); ok {
+ r0 = rf(xml)
+ } else {
+ r0 = ret.Get(0).(third_partylibvirt.DomainState)
+ }
+
+ if rf, ok := ret.Get(1).(func(string) error); ok {
+ r1 = rf(xml)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
}
// GetInfo provides a mock function with given fields:
-func (_m *Domain) GetInfo() (*libvirt_go.DomainInfo, error) {
+func (_m *Domain) GetInfo() (*third_partylibvirt.DomainGetInfoRet, error) {
ret := _m.Called()
- var r0 *libvirt_go.DomainInfo
+ var r0 *third_partylibvirt.DomainGetInfoRet
var r1 error
- if rf, ok := ret.Get(0).(func() (*libvirt_go.DomainInfo, error)); ok {
+ if rf, ok := ret.Get(0).(func() (*third_partylibvirt.DomainGetInfoRet, error)); ok {
return rf()
}
- if rf, ok := ret.Get(0).(func() *libvirt_go.DomainInfo); ok {
+ if rf, ok := ret.Get(0).(func() *third_partylibvirt.DomainGetInfoRet); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
- r0 = ret.Get(0).(*libvirt_go.DomainInfo)
+ r0 = ret.Get(0).(*third_partylibvirt.DomainGetInfoRet)
}
}
@@ -148,18 +171,18 @@ func (_m *Domain) GetName() (string, error) {
}
// GetState provides a mock function with given fields:
-func (_m *Domain) GetState() (libvirt_go.DomainState, error) {
+func (_m *Domain) GetState() (third_partylibvirt.DomainState, error) {
ret := _m.Called()
- var r0 libvirt_go.DomainState
+ var r0 third_partylibvirt.DomainState
var r1 error
- if rf, ok := ret.Get(0).(func() (libvirt_go.DomainState, error)); ok {
+ if rf, ok := ret.Get(0).(func() (third_partylibvirt.DomainState, error)); ok {
return rf()
}
- if rf, ok := ret.Get(0).(func() libvirt_go.DomainState); ok {
+ if rf, ok := ret.Get(0).(func() third_partylibvirt.DomainState); ok {
r0 = rf()
} else {
- r0 = ret.Get(0).(libvirt_go.DomainState)
+ r0 = ret.Get(0).(third_partylibvirt.DomainState)
}
if rf, ok := ret.Get(1).(func() error); ok {
@@ -196,21 +219,21 @@ func (_m *Domain) GetUUIDString() (string, error) {
}
// GetXMLDesc provides a mock function with given fields: flags
-func (_m *Domain) GetXMLDesc(flags libvirt_go.DomainXMLFlags) (string, error) {
+func (_m *Domain) GetXMLDesc(flags third_partylibvirt.DomainXMLFlags) (string, error) {
ret := _m.Called(flags)
var r0 string
var r1 error
- if rf, ok := ret.Get(0).(func(libvirt_go.DomainXMLFlags) (string, error)); ok {
+ if rf, ok := ret.Get(0).(func(third_partylibvirt.DomainXMLFlags) (string, error)); ok {
return rf(flags)
}
- if rf, ok := ret.Get(0).(func(libvirt_go.DomainXMLFlags) string); ok {
+ if rf, ok := ret.Get(0).(func(third_partylibvirt.DomainXMLFlags) string); ok {
r0 = rf(flags)
} else {
r0 = ret.Get(0).(string)
}
- if rf, ok := ret.Get(1).(func(libvirt_go.DomainXMLFlags) error); ok {
+ if rf, ok := ret.Get(1).(func(third_partylibvirt.DomainXMLFlags) error); ok {
r1 = rf(flags)
} else {
r1 = ret.Error(1)
@@ -219,6 +242,56 @@ func (_m *Domain) GetXMLDesc(flags libvirt_go.DomainXMLFlags) (string, error) {
return r0, r1
}
+// OpenConsole provides a mock function with given fields: devname, flags
+func (_m *Domain) OpenConsole(devname string, flags *libvirt.ConsoleFlags) (*libvirt.Console, error) {
+ ret := _m.Called(devname, flags)
+
+ var r0 *libvirt.Console
+ var r1 error
+ if rf, ok := ret.Get(0).(func(string, *libvirt.ConsoleFlags) (*libvirt.Console, error)); ok {
+ return rf(devname, flags)
+ }
+ if rf, ok := ret.Get(0).(func(string, *libvirt.ConsoleFlags) *libvirt.Console); ok {
+ r0 = rf(devname, flags)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*libvirt.Console)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(string, *libvirt.ConsoleFlags) error); ok {
+ r1 = rf(devname, flags)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// QemuAgentCommand provides a mock function with given fields: ctx, cmd
+func (_m *Domain) QemuAgentCommand(ctx context.Context, cmd string) (string, error) {
+ ret := _m.Called(ctx, cmd)
+
+ var r0 string
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, string) (string, error)); ok {
+ return rf(ctx, cmd)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, string) string); ok {
+ r0 = rf(ctx, cmd)
+ } else {
+ r0 = ret.Get(0).(string)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
+ r1 = rf(ctx, cmd)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
// Resume provides a mock function with given fields:
func (_m *Domain) Resume() error {
ret := _m.Called()
@@ -233,12 +306,26 @@ func (_m *Domain) Resume() error {
return r0
}
+// SetAutostart provides a mock function with given fields: autostart
+func (_m *Domain) SetAutostart(autostart bool) error {
+ ret := _m.Called(autostart)
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(bool) error); ok {
+ r0 = rf(autostart)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
// SetMemoryFlags provides a mock function with given fields: memory, flags
-func (_m *Domain) SetMemoryFlags(memory uint64, flags libvirt_go.DomainMemoryModFlags) error {
+func (_m *Domain) SetMemoryFlags(memory uint64, flags third_partylibvirt.DomainMemoryModFlags) error {
ret := _m.Called(memory, flags)
var r0 error
- if rf, ok := ret.Get(0).(func(uint64, libvirt_go.DomainMemoryModFlags) error); ok {
+ if rf, ok := ret.Get(0).(func(uint64, third_partylibvirt.DomainMemoryModFlags) error); ok {
r0 = rf(memory, flags)
} else {
r0 = ret.Error(0)
@@ -247,12 +334,26 @@ func (_m *Domain) SetMemoryFlags(memory uint64, flags libvirt_go.DomainMemoryMod
return r0
}
+// SetMemoryStatsPeriod provides a mock function with given fields: period, config, live
+func (_m *Domain) SetMemoryStatsPeriod(period int, config bool, live bool) error {
+ ret := _m.Called(period, config, live)
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(int, bool, bool) error); ok {
+ r0 = rf(period, config, live)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
// SetVcpusFlags provides a mock function with given fields: vcpu, flags
-func (_m *Domain) SetVcpusFlags(vcpu uint, flags libvirt_go.DomainVcpuFlags) error {
+func (_m *Domain) SetVcpusFlags(vcpu uint, flags third_partylibvirt.DomainVCPUFlags) error {
ret := _m.Called(vcpu, flags)
var r0 error
- if rf, ok := ret.Get(0).(func(uint, libvirt_go.DomainVcpuFlags) error); ok {
+ if rf, ok := ret.Get(0).(func(uint, third_partylibvirt.DomainVCPUFlags) error); ok {
r0 = rf(vcpu, flags)
} else {
r0 = ret.Error(0)
@@ -262,11 +363,11 @@ func (_m *Domain) SetVcpusFlags(vcpu uint, flags libvirt_go.DomainVcpuFlags) err
}
// ShutdownFlags provides a mock function with given fields: flags
-func (_m *Domain) ShutdownFlags(flags libvirt_go.DomainShutdownFlags) error {
+func (_m *Domain) ShutdownFlags(flags libvirt.DomainShutdownFlags) error {
ret := _m.Called(flags)
var r0 error
- if rf, ok := ret.Get(0).(func(libvirt_go.DomainShutdownFlags) error); ok {
+ if rf, ok := ret.Get(0).(func(libvirt.DomainShutdownFlags) error); ok {
r0 = rf(flags)
} else {
r0 = ret.Error(0)
@@ -290,11 +391,11 @@ func (_m *Domain) Suspend() error {
}
// UndefineFlags provides a mock function with given fields: flags
-func (_m *Domain) UndefineFlags(flags libvirt_go.DomainUndefineFlagsValues) error {
+func (_m *Domain) UndefineFlags(flags third_partylibvirt.DomainUndefineFlagsValues) error {
ret := _m.Called(flags)
var r0 error
- if rf, ok := ret.Get(0).(func(libvirt_go.DomainUndefineFlagsValues) error); ok {
+ if rf, ok := ret.Get(0).(func(third_partylibvirt.DomainUndefineFlagsValues) error); ok {
r0 = rf(flags)
} else {
r0 = ret.Error(0)
@@ -303,13 +404,12 @@ func (_m *Domain) UndefineFlags(flags libvirt_go.DomainUndefineFlagsValues) erro
return r0
}
-type mockConstructorTestingTNewDomain interface {
+// NewDomain creates a new instance of Domain. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func NewDomain(t interface {
mock.TestingT
Cleanup(func())
-}
-
-// NewDomain creates a new instance of Domain. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-func NewDomain(t mockConstructorTestingTNewDomain) *Domain {
+}) *Domain {
mock := &Domain{}
mock.Mock.Test(t)
diff --git a/pkg/libvirt/mocks/Libvirt.go b/pkg/libvirt/mocks/Libvirt.go
index 83962ce..29e09cc 100644
--- a/pkg/libvirt/mocks/Libvirt.go
+++ b/pkg/libvirt/mocks/Libvirt.go
@@ -1,10 +1,12 @@
-// Code generated by mockery v2.26.1. DO NOT EDIT.
+// Code generated by mockery v2.33.2. DO NOT EDIT.
package mocks
import (
libvirt "github.com/projecteru2/yavirt/pkg/libvirt"
mock "github.com/stretchr/testify/mock"
+
+ third_partylibvirt "github.com/projecteru2/yavirt/third_party/libvirt"
)
// Libvirt is an autogenerated mock type for the Libvirt type
@@ -62,6 +64,32 @@ func (_m *Libvirt) DefineDomain(_a0 string) (libvirt.Domain, error) {
return r0, r1
}
+// GetAllDomainStats provides a mock function with given fields: doms
+func (_m *Libvirt) GetAllDomainStats(doms []third_partylibvirt.Domain) ([]third_partylibvirt.DomainStatsRecord, error) {
+ ret := _m.Called(doms)
+
+ var r0 []third_partylibvirt.DomainStatsRecord
+ var r1 error
+ if rf, ok := ret.Get(0).(func([]third_partylibvirt.Domain) ([]third_partylibvirt.DomainStatsRecord, error)); ok {
+ return rf(doms)
+ }
+ if rf, ok := ret.Get(0).(func([]third_partylibvirt.Domain) []third_partylibvirt.DomainStatsRecord); ok {
+ r0 = rf(doms)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]third_partylibvirt.DomainStatsRecord)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func([]third_partylibvirt.Domain) error); ok {
+ r1 = rf(doms)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
// ListDomainsNames provides a mock function with given fields:
func (_m *Libvirt) ListDomainsNames() ([]string, error) {
ret := _m.Called()
@@ -114,13 +142,12 @@ func (_m *Libvirt) LookupDomain(_a0 string) (libvirt.Domain, error) {
return r0, r1
}
-type mockConstructorTestingTNewLibvirt interface {
+// NewLibvirt creates a new instance of Libvirt. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func NewLibvirt(t interface {
mock.TestingT
Cleanup(func())
-}
-
-// NewLibvirt creates a new instance of Libvirt. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-func NewLibvirt(t mockConstructorTestingTNewLibvirt) *Libvirt {
+}) *Libvirt {
mock := &Libvirt{}
mock.Mock.Test(t)
diff --git a/pkg/libvirt/types.go b/pkg/libvirt/types.go
index a0d4b33..cc20ec4 100644
--- a/pkg/libvirt/types.go
+++ b/pkg/libvirt/types.go
@@ -1,6 +1,8 @@
package libvirt
-import libvirtgo "github.com/libvirt/libvirt-go"
+import (
+ libvirtgo "github.com/projecteru2/yavirt/third_party/libvirt"
+)
// DomainState .
type DomainState = libvirtgo.DomainState
@@ -46,7 +48,7 @@ func GetDomainStateString(s DomainState) string {
}
// DomainInfo .
-type DomainInfo = libvirtgo.DomainInfo
+type DomainInfo = libvirtgo.DomainGetInfoRet
// DomainXMLFlags .
type DomainXMLFlags = libvirtgo.DomainXMLFlags
@@ -55,16 +57,16 @@ type DomainXMLFlags = libvirtgo.DomainXMLFlags
type DomainConsoleFlags = libvirtgo.DomainConsoleFlags
// DomainShutdownFlags .
-type DomainShutdownFlags = libvirtgo.DomainShutdownFlags
+type DomainShutdownFlags libvirtgo.DomainShutdownFlagValues
// DomainDestroyFlags .
-type DomainDestroyFlags = libvirtgo.DomainDestroyFlags
+type DomainDestroyFlags = libvirtgo.DomainDestroyFlagsValues
// DomainUndefineFlags .
type DomainUndefineFlags = libvirtgo.DomainUndefineFlagsValues
// DomainVcpuFlags .
-type DomainVcpuFlags = libvirtgo.DomainVcpuFlags
+type DomainVcpuFlags = libvirtgo.DomainVCPUFlags
// DomainMemoryModFlags .
type DomainMemoryModFlags = libvirtgo.DomainMemoryModFlags
diff --git a/pkg/log/log.go b/pkg/log/log.go
deleted file mode 100644
index 99541b1..0000000
--- a/pkg/log/log.go
+++ /dev/null
@@ -1,131 +0,0 @@
-package log
-
-import (
- "fmt"
- "os"
- "path/filepath"
- "time"
-
- "github.com/getsentry/sentry-go"
- "github.com/sirupsen/logrus"
-
- "github.com/projecteru2/yavirt/pkg/errors"
-)
-
-// Setup .
-func Setup(level, file, sentryDSN string) (func(), error) {
- if err := setupLevel(level); err != nil {
- return nil, errors.Trace(err)
- }
-
- logrus.SetFormatter(&logrus.TextFormatter{FullTimestamp: true})
-
- if err := setupOutput(file); err != nil {
- return nil, errors.Trace(err)
- }
-
- return setupSentry(sentryDSN)
-}
-
-func setupSentry(dsn string) (func(), error) {
- if len(dsn) == 0 {
- return func() {}, nil
- }
-
- deferSentry := func() {
- defer sentry.Flush(time.Second * 2)
- if err := recover(); err != nil {
- sentry.CaptureMessage(fmt.Sprintf("%v", err))
- panic(err)
- }
- }
-
- return deferSentry, sentry.Init(sentry.ClientOptions{Dsn: dsn})
-}
-
-func setupOutput(file string) error {
- if len(file) < 1 {
- return nil
- }
- // make dir if necessary
- err := os.MkdirAll(filepath.Dir(file), 0755)
- if err != nil && !os.IsExist(err) {
- return err
- }
- // open file for logger
- f, err := os.OpenFile(file, os.O_APPEND|os.O_CREATE|os.O_RDWR, os.ModePerm)
- if err != nil {
- return errors.Trace(err)
- }
-
- logrus.SetOutput(f)
-
- return nil
-}
-
-func setupLevel(level string) error {
- if len(level) < 1 {
- return nil
- }
-
- var lv, err = logrus.ParseLevel(level)
- if err != nil {
- return errors.Trace(err)
- }
-
- logrus.SetLevel(lv)
-
- return nil
-}
-
-// WarnStackf .
-func WarnStackf(err error, format string, args ...any) {
- WarnStack(errors.Annotatef(err, format, args...))
-}
-
-// WarnStack .
-func WarnStack(err error) {
- Warnf(errors.Stack(err))
-}
-
-// Warnf .
-func Warnf(format string, args ...any) {
- logrus.Warnf(format, args...)
-}
-
-// ErrorStackf .
-func ErrorStackf(err error, format string, args ...any) {
- ErrorStack(errors.Annotatef(err, format, args...))
-}
-
-// ErrorStack .
-func ErrorStack(err error) {
- Errorf(errors.Stack(err))
-}
-
-// Errorf .
-func Errorf(format string, args ...any) {
- sentry.CaptureMessage(fmt.Sprintf(format, args...))
- logrus.Errorf(format, args...)
-}
-
-// Infof .
-func Infof(format string, args ...any) {
- logrus.Infof(format, args...)
-}
-
-// Debugf .
-func Debugf(format string, args ...any) {
- logrus.Debugf(format, args...)
-}
-
-// FatalStack .
-func FatalStack(err error) {
- Fatalf(errors.Stack(err))
-}
-
-// Fatalf .
-func Fatalf(format string, args ...any) {
- sentry.CaptureMessage(fmt.Sprintf(format, args...))
- logrus.Fatalf(format, args...)
-}
diff --git a/pkg/netx/http.go b/pkg/netx/http.go
index 70bf439..af10e68 100644
--- a/pkg/netx/http.go
+++ b/pkg/netx/http.go
@@ -4,14 +4,14 @@ import (
"context"
"net/http"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/cockroachdb/errors"
)
// SimpleGet .
func SimpleGet(ctx context.Context, url string) (*http.Response, error) {
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
return http.DefaultClient.Do(req.WithContext(ctx))
}
diff --git a/pkg/netx/netx.go b/pkg/netx/netx.go
index 3048e15..85b4269 100644
--- a/pkg/netx/netx.go
+++ b/pkg/netx/netx.go
@@ -2,16 +2,19 @@ package netx
import (
"net"
+ "time"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/yavirt/pkg/terrors"
"github.com/projecteru2/yavirt/pkg/utils"
+ probing "github.com/prometheus-community/pro-bing"
)
// GetOutboundIP .
func GetOutboundIP(dest string) (string, error) {
conn, err := net.Dial("udp", dest)
if err != nil {
- return "", errors.Trace(err)
+ return "", errors.Wrap(err, "")
}
defer conn.Close()
@@ -45,7 +48,7 @@ func Int2ip(i64 int64) net.IP {
// IPv4ToInt .
func IPv4ToInt(ipv4 string) (i64 int64, err error) {
if i64 = IP2int(net.ParseIP(ipv4).To4()); i64 == 0 {
- err = errors.Annotatef(errors.ErrInvalidValue, "invalid IPv4: %s", ipv4)
+ err = errors.Wrapf(terrors.ErrInvalidValue, "invalid IPv4: %s", ipv4)
}
return
}
@@ -68,12 +71,12 @@ func ParseCIDROrIP(s string) (*net.IPNet, error) {
var ip = &net.IP{}
if err = ip.UnmarshalText([]byte(s)); err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
var ipv4 = ip.To4()
if ipv4 == nil {
- return nil, errors.Annotatef(errors.ErrInvalidValue, "invalid IPv4: %s", s)
+ return nil, errors.Wrapf(terrors.ErrInvalidValue, "invalid IPv4: %s", s)
}
return &net.IPNet{
@@ -86,7 +89,7 @@ func ParseCIDROrIP(s string) (*net.IPNet, error) {
func ParseCIDR2(cidr string) (*net.IPNet, error) {
var ip, ipn, err = ParseCIDR(cidr)
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
ipn.IP = ip
@@ -98,7 +101,7 @@ func ParseCIDR2(cidr string) (*net.IPNet, error) {
func CheckIPv4(ip net.IP, mask net.IPMask) error {
var ipv4 = ip.To4()
if ipv4 == nil {
- return errors.Annotatef(errors.ErrInvalidValue, "invalid IPv4: %s", ip)
+ return errors.Wrapf(terrors.ErrInvalidValue, "invalid IPv4: %s", ip)
}
var bits = net.IPv4len * 8
@@ -107,13 +110,13 @@ func CheckIPv4(ip net.IP, mask net.IPMask) error {
switch dec, err := ConvIPv4ToUint32(ipv4); {
case err != nil:
- return errors.Trace(err)
+ return errors.Wrap(err, "")
case dec&allone == 0:
- return errors.Annotatef(errors.ErrIPv4IsNetworkNumber, "%s", ip)
+ return errors.Wrapf(terrors.ErrIPv4IsNetworkNumber, "%s", ip)
case dec&allone == allone:
- return errors.Annotatef(errors.ErrIPv4IsBroadcastAddr, "%s", ip)
+ return errors.Wrapf(terrors.ErrIPv4IsBroadcastAddr, "%s", ip)
default:
return nil
@@ -124,7 +127,7 @@ func CheckIPv4(ip net.IP, mask net.IPMask) error {
func ConvIPv4ToUint32(ip net.IP) (dec uint32, err error) {
var ipv4 = ip.To4()
if ipv4 == nil {
- return dec, errors.Annotatef(errors.ErrInvalidValue, "invalid IPv4: %s", ip)
+ return dec, errors.Wrapf(terrors.ErrInvalidValue, "invalid IPv4: %s", ip)
}
for i := 0; i < 4; i++ {
@@ -137,7 +140,56 @@ func ConvIPv4ToUint32(ip net.IP) (dec uint32, err error) {
// ParseCIDR .
func ParseCIDR(cidr string) (ip net.IP, ipn *net.IPNet, err error) {
if ip, ipn, err = net.ParseCIDR(cidr); err != nil {
- err = errors.Annotatef(errors.ErrInvalidValue, "invalid CIDR: %s", cidr)
+ err = errors.Wrapf(terrors.ErrInvalidValue, "invalid CIDR: %s", cidr)
}
return
}
+
+func DefaultGatewayIP(ipNet *net.IPNet) (net.IP, error) {
+ // Check if the IPNet is not nil
+ if ipNet == nil {
+ return nil, errors.New("IPNet is nil")
+ }
+
+ // Get the first IP address in the range
+ firstIP := ipNet.IP
+
+ // Increment the IP address to get the second IP
+ secondIP := make(net.IP, len(firstIP))
+ copy(secondIP, firstIP)
+ for i := len(secondIP) - 1; i >= 0; i-- {
+ secondIP[i]++
+ if secondIP[i] > firstIP[i] {
+ break
+ }
+ }
+
+ return secondIP, nil
+}
+
+func InSubnet(ip string, subnet string) bool {
+ _, ipNet, err := net.ParseCIDR(subnet)
+ if err != nil {
+ return false
+ }
+ ipAddr := net.ParseIP(ip)
+ if ipAddr == nil {
+ return false
+ }
+ return ipNet.Contains(ipAddr)
+}
+
+func IPReachable(ip string, timeout time.Duration) (bool, error) {
+ pinger, err := probing.NewPinger(ip)
+ if err != nil {
+ return false, err
+ }
+ pinger.Timeout = timeout
+ pinger.Count = 2
+ err = pinger.Run() // Blocks until finished.
+ if err != nil {
+ return false, err
+ }
+ stats := pinger.Statistics()
+ return stats.PacketsRecv > 0, nil
+}
diff --git a/pkg/netx/netx_test.go b/pkg/netx/netx_test.go
index ecc693f..c7afdad 100644
--- a/pkg/netx/netx_test.go
+++ b/pkg/netx/netx_test.go
@@ -120,3 +120,9 @@ func TestParseCIDROrIP(t *testing.T) {
_, err = ParseCIDROrIP("10.256.300.0")
assert.Err(t, err)
}
+
+// func TestIPReachable(t *testing.T) {
+// v, err := IPReachable("8.8.8.8", time.Second)
+// assert.Nil(t, err)
+// assert.True(t, v)
+// }
diff --git a/pkg/notify/bison/bison.go b/pkg/notify/bison/bison.go
new file mode 100644
index 0000000..d742781
--- /dev/null
+++ b/pkg/notify/bison/bison.go
@@ -0,0 +1,91 @@
+package bison
+
+import (
+ "errors"
+ "testing"
+
+ "github.com/alphadose/haxmap"
+ "github.com/projecteru2/yavirt/pkg/notify"
+ "github.com/projecteru2/yavirt/pkg/notify/services/all"
+ "github.com/projecteru2/yavirt/pkg/notify/services/dingding"
+ "github.com/projecteru2/yavirt/pkg/notify/services/mail"
+)
+
+var bs *Manager
+
+type Config struct {
+ Type string `toml:"type"`
+ DingDing dingding.Config `toml:"dingding"`
+ Mail mail.Config `toml:"mail"`
+ All all.Config `toml:"all"`
+}
+
+type Manager struct {
+ config Config
+ services *haxmap.Map[string, notify.Service]
+}
+
+func loadService(cfg *Config, ty string) (svc notify.Service, err error) {
+ switch ty {
+ case "dingding":
+ svc, err = dingding.New(cfg.DingDing)
+ case "mail":
+ svc = mail.New(cfg.Mail)
+ default:
+ return nil, errors.New("type not supported")
+ }
+ return
+}
+
+func New(cfg *Config) (mgr *Manager, err error) {
+ mgr = &Manager{
+ config: *cfg,
+ services: haxmap.New[string, notify.Service](),
+ }
+ var svc notify.Service
+ if cfg.Type == "all" {
+ var lst []notify.Service
+ for _, ty := range cfg.All.Types {
+ svc, err := loadService(cfg, ty)
+ if err != nil {
+ return nil, err
+ }
+ lst = append(lst, svc)
+ }
+ svc = all.New(lst)
+ } else {
+ svc, err = loadService(cfg, cfg.Type)
+ if err != nil {
+ return nil, err
+ }
+ }
+ mgr.services.Set(cfg.Type, svc)
+ return mgr, nil
+}
+
+func (mgr *Manager) GetService() notify.Service {
+ svc, ok := mgr.services.Get(mgr.config.Type)
+ if !ok {
+ return nil
+ }
+ return svc
+}
+
+func Setup(cfg *Config, t *testing.T) error {
+ var err error
+ if t != nil {
+ bs = &Manager{
+ config: Config{
+ Type: "test",
+ },
+ services: haxmap.New[string, notify.Service](),
+ }
+ return nil
+ }
+ bs, err = New(cfg)
+ return err
+}
+
+func GetService() notify.Service {
+ return bs.GetService()
+}
diff --git a/pkg/notify/notify.go b/pkg/notify/notify.go
new file mode 100644
index 0000000..d54952a
--- /dev/null
+++ b/pkg/notify/notify.go
@@ -0,0 +1,10 @@
+package notify
+
+import (
+ "context"
+)
+
+type Service interface {
+ Send(ctx context.Context, title, msg string) error
+ SendMarkdown(ctx context.Context, title, msg string) error
+}
diff --git a/pkg/notify/services/all/all.go b/pkg/notify/services/all/all.go
new file mode 100644
index 0000000..a461aa5
--- /dev/null
+++ b/pkg/notify/services/all/all.go
@@ -0,0 +1,42 @@
+package all
+
+import (
+ "context"
+
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/yavirt/pkg/notify"
+)
+
+type Config struct {
+ Types []string `toml:"types"`
+}
+
+type Manager struct {
+ notifiers []notify.Service
+}
+
+func New(notifiers []notify.Service) *Manager {
+ return &Manager{
+ notifiers: notifiers,
+ }
+}
+
+func (m *Manager) Send(ctx context.Context, title, msg string) error {
+ var combinedErr error
+ for _, n := range m.notifiers {
+ if err := n.Send(ctx, title, msg); err != nil {
+ combinedErr = errors.CombineErrors(combinedErr, err)
+ }
+ }
+ return combinedErr
+}
+
+func (m *Manager) SendMarkdown(ctx context.Context, title, msg string) error {
+ var combinedErr error
+ for _, n := range m.notifiers {
+ if err := n.SendMarkdown(ctx, title, msg); err != nil {
+ combinedErr = errors.CombineErrors(combinedErr, err)
+ }
+ }
+ return combinedErr
+}
diff --git a/pkg/notify/services/dingding/.gitignore b/pkg/notify/services/dingding/.gitignore
new file mode 100644
index 0000000..f90f6fc
--- /dev/null
+++ b/pkg/notify/services/dingding/.gitignore
@@ -0,0 +1 @@
+/dingding_test.go
\ No newline at end of file
diff --git a/pkg/notify/services/dingding/dingding.go b/pkg/notify/services/dingding/dingding.go
new file mode 100644
index 0000000..aad04bc
--- /dev/null
+++ b/pkg/notify/services/dingding/dingding.go
@@ -0,0 +1,36 @@
+package dingding
+
+import (
+ "context"
+ "errors"
+
+ "github.com/blinkbean/dingtalk"
+)
+
+type Config struct {
+ Token string `toml:"token"`
+}
+
+type DingDing struct {
+ config Config
+ ddtalk *dingtalk.DingTalk
+}
+
+func New(cfg Config) (*DingDing, error) {
+ if cfg.Token == "" {
+ return nil, errors.New("token is required")
+ }
+ return &DingDing{
+ config: cfg,
+ ddtalk: dingtalk.InitDingTalk([]string{cfg.Token}, "."),
+ }, nil
+}
+
+func (dd *DingDing) SendMarkdown(_ context.Context, title, content string) error {
+ return dd.ddtalk.SendMarkDownMessage(title, content)
+}
+
+func (dd *DingDing) Send(_ context.Context, title, content string) error {
+ text := title + "\n" + content
+ return dd.ddtalk.SendTextMessage(text)
+}
diff --git a/pkg/notify/services/mail/.gitignore b/pkg/notify/services/mail/.gitignore
new file mode 100644
index 0000000..fbfe4d6
--- /dev/null
+++ b/pkg/notify/services/mail/.gitignore
@@ -0,0 +1 @@
+/mail_test.go
\ No newline at end of file
diff --git a/pkg/notify/services/mail/mail.go b/pkg/notify/services/mail/mail.go
new file mode 100644
index 0000000..444175a
--- /dev/null
+++ b/pkg/notify/services/mail/mail.go
@@ -0,0 +1,126 @@
+package mail
+
+import (
+ "context"
+ "crypto/tls"
+ "fmt"
+ "net/smtp"
+ "net/textproto"
+
+ "github.com/jordan-wright/email"
+ "github.com/pkg/errors"
+ "github.com/russross/blackfriday/v2"
+)
+
+type Config struct {
+ SMTPHost string `toml:"smtp_host"`
+ SMTPPort int `toml:"smtp_port"`
+ Sender string `toml:"sender"`
+ Password string `toml:"password"`
+ Receivers []string `toml:"receivers"`
+}
+
+// Mail struct holds necessary data to send emails.
+type Mail struct {
+ usePlainText bool
+ smtpAuth smtp.Auth
+ config Config
+}
+
+// New returns a new instance of a Mail notification service.
+func New(config Config) *Mail {
+ m := &Mail{
+ usePlainText: false,
+ config: config,
+ }
+ m.smtpAuth = smtp.PlainAuth("", config.Sender, config.Password, config.SMTPHost)
+ return m
+}
+
+// BodyType is used to specify the format of the body.
+type BodyType int
+
+const (
+ // PlainText is used to specify that the body is plain text.
+ PlainText BodyType = iota
+ // HTML is used to specify that the body is HTML.
+ HTML
+)
+
+// AuthenticateSMTP authenticates you to send emails via smtp.
+// Example values: "", "test@gmail.com", "password123", "smtp.gmail.com"
+// For more information about smtp authentication, see here:
+//
+// -> https://pkg.go.dev/net/smtp#PlainAuth
+func (m *Mail) AuthenticateSMTP(identity, userName, password, host string) {
+ m.smtpAuth = smtp.PlainAuth(identity, userName, password, host)
+}
+
+// AddReceivers takes email addresses and adds them to the internal address list. The Send method will send
+// a given message to all those addresses.
+func (m *Mail) AddReceivers(addresses ...string) {
+ m.config.Receivers = append(m.config.Receivers, addresses...)
+}
+
+// BodyFormat can be used to specify the format of the body.
+// Default BodyType is HTML.
+func (m *Mail) BodyFormat(format BodyType) {
+ switch format {
+ case PlainText:
+ m.usePlainText = true
+ default:
+ m.usePlainText = false
+ }
+}
+
+func (m *Mail) newEmail(subject, message string, usePlainText bool) *email.Email {
+ msg := &email.Email{
+ To: m.config.Receivers,
+ From: m.config.Sender,
+ Subject: subject,
+ Headers: textproto.MIMEHeader{},
+ }
+
+ if usePlainText {
+ msg.Text = []byte(message)
+ } else {
+ msg.HTML = []byte(message)
+ }
+ return msg
+}
+
+func (m Mail) send(ctx context.Context, msg *email.Email) error {
+ var err error
+ select {
+ case <-ctx.Done():
+ err = ctx.Err()
+ default:
+ host := fmt.Sprintf("%s:%d", m.config.SMTPHost, m.config.SMTPPort)
+ if m.config.SMTPPort == 25 {
+ err = msg.Send(host, m.smtpAuth)
+ } else {
+ tlsconfig := &tls.Config{
+ ServerName: m.config.SMTPHost,
+ MinVersion: tls.VersionTLS12,
+ }
+ err = msg.SendWithTLS(host, m.smtpAuth, tlsconfig)
+ }
+ if err != nil {
+ err = errors.Wrap(err, "failed to send mail")
+ }
+ }
+ return err
+}
+
+// Send takes a message subject and a message body and sends them to all previously set chats. Message body supports
+// html as markup language.
+func (m Mail) Send(ctx context.Context, subject, message string) error {
+ msg := m.newEmail(subject, message, m.usePlainText)
+ return m.send(ctx, msg)
+}
+
+func (m Mail) SendMarkdown(ctx context.Context, subject, message string) error {
+ html := blackfriday.Run([]byte(message))
+ msg := m.newEmail(subject, string(html), false)
+ return m.send(ctx, msg)
+}
diff --git a/pkg/sh/shx.go b/pkg/sh/shx.go
index f0aeed3..bd41e7a 100644
--- a/pkg/sh/shx.go
+++ b/pkg/sh/shx.go
@@ -7,7 +7,7 @@ import (
"io"
"os/exec"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/cockroachdb/errors"
)
type shx struct{}
@@ -46,20 +46,20 @@ func (s shx) Exec(ctx context.Context, name string, args ...string) error {
stderr, err := cmd.StderrPipe()
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
if err := cmd.Start(); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
slurp, err := io.ReadAll(stderr)
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
if err := cmd.Wait(); err != nil {
- return errors.Annotatef(err, string(slurp))
+ return errors.Wrap(err, string(slurp))
}
return nil
diff --git a/pkg/store/etcd/codec.go b/pkg/store/etcd/codec.go
index 4db796b..97dd9ef 100644
--- a/pkg/store/etcd/codec.go
+++ b/pkg/store/etcd/codec.go
@@ -1,14 +1,14 @@
package etcd
import (
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/cockroachdb/errors"
"github.com/projecteru2/yavirt/pkg/utils"
)
func encode(v any) (string, error) { //nolint
var buf, err = utils.JSONEncode(v, "\t")
if err != nil {
- return "", errors.Trace(err)
+ return "", errors.Wrap(err, "")
}
return string(buf), nil
}
diff --git a/pkg/store/etcd/embedded/embeded.go b/pkg/store/etcd/embedded/embeded.go
new file mode 100644
index 0000000..609471f
--- /dev/null
+++ b/pkg/store/etcd/embedded/embeded.go
@@ -0,0 +1,34 @@
+package embedded
+
+import (
+ "flag"
+ "os"
+ "testing"
+
+ "go.etcd.io/etcd/client/v3/namespace"
+ "go.etcd.io/etcd/tests/v3/integration"
+)
+
+var clusters map[string]*integration.ClusterV3 = map[string]*integration.ClusterV3{}
+
+// NewCluster new a embedded cluster
+func NewCluster(t *testing.T, prefix string) *integration.ClusterV3 {
+ cluster := clusters[t.Name()]
+ if cluster == nil {
+ os.Args = []string{"test.short=false"}
+ testing.Init()
+ flag.Parse()
+ integration.BeforeTestExternal(t)
+ cluster = integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
+ t.Cleanup(func() {
+ cluster.Terminate(t)
+ delete(clusters, t.Name())
+ })
+ cliv3 := cluster.RandClient()
+ cliv3.KV = namespace.NewKV(cliv3.KV, prefix)
+ cliv3.Watcher = namespace.NewWatcher(cliv3.Watcher, prefix)
+ cliv3.Lease = namespace.NewLease(cliv3.Lease, prefix)
+ clusters[t.Name()] = cluster
+ }
+ return cluster
+}
diff --git a/pkg/store/etcd/embedded/embeded_test.go b/pkg/store/etcd/embedded/embeded_test.go
new file mode 100644
index 0000000..0f2af68
--- /dev/null
+++ b/pkg/store/etcd/embedded/embeded_test.go
@@ -0,0 +1,15 @@
+package embedded
+
+import (
+ "context"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestEmbededCluster(t *testing.T) {
+ embededETCD := NewCluster(t, "/test")
+ cliv3 := embededETCD.RandClient()
+ _, err := cliv3.MemberList(context.Background())
+ assert.NoError(t, err)
+}
diff --git a/pkg/store/etcd/etcd.go b/pkg/store/etcd/etcd.go
index d77598f..a572ea6 100644
--- a/pkg/store/etcd/etcd.go
+++ b/pkg/store/etcd/etcd.go
@@ -2,40 +2,76 @@ package etcd
import (
"context"
+ "crypto/tls"
"strconv"
"sync"
+ "testing"
clientv3 "go.etcd.io/etcd/client/v3"
+ "go.etcd.io/etcd/pkg/transport"
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/core/log"
"github.com/projecteru2/yavirt/configs"
- "github.com/projecteru2/yavirt/pkg/errors"
- "github.com/projecteru2/yavirt/pkg/log"
+ "github.com/projecteru2/yavirt/pkg/store/etcd/embedded"
+ "github.com/projecteru2/yavirt/pkg/terrors"
"github.com/projecteru2/yavirt/pkg/utils"
)
-// Etcd .
-type Etcd struct {
+// ETCDClientV3 .
+type ETCDClientV3 interface { //nolint
+ clientv3.KV
+ clientv3.Lease
+ clientv3.Watcher
+}
+
+// ETCD .
+type ETCD struct {
sync.Mutex
- cli *clientv3.Client
+ cliv3 ETCDClientV3
+ cfg configs.ETCDConfig
}
// New .
-func New() (*Etcd, error) {
- etcdcnf, err := configs.Conf.NewEtcdConfig()
- if err != nil {
- return nil, errors.Trace(err)
- }
+func New(cfg configs.ETCDConfig, t *testing.T) (*ETCD, error) {
+ var cliv3 *clientv3.Client
+ var err error
+ var tlsConfig *tls.Config
- cli, err := clientv3.New(etcdcnf)
- if err != nil {
- return nil, errors.Trace(err)
+ switch {
+ case t != nil:
+ embededETCD := embedded.NewCluster(t, cfg.Prefix)
+ cliv3 = embededETCD.RandClient()
+ log.Infof(context.TODO(), "use embedded cluster")
+ default:
+ if utils.FileExists(cfg.CA) && utils.FileExists(cfg.Key) && utils.FileExists(cfg.Cert) {
+ tlsInfo := transport.TLSInfo{
+ TrustedCAFile: cfg.CA,
+ KeyFile: cfg.Key,
+ CertFile: cfg.Cert,
+ }
+ tlsConfig, err = tlsInfo.ClientConfig()
+ if err != nil {
+ return nil, err
+ }
+ }
+ if cliv3, err = clientv3.New(clientv3.Config{
+ Endpoints: cfg.Endpoints,
+ Username: cfg.Username,
+ Password: cfg.Password,
+ TLS: tlsConfig,
+ }); err != nil {
+ return nil, err
+ }
+ // cliv3.KV = namespace.NewKV(cliv3.KV, config.Prefix)
+ // cliv3.Watcher = namespace.NewWatcher(cliv3.Watcher, config.Prefix)
+ // cliv3.Lease = namespace.NewLease(cliv3.Lease, config.Prefix)
}
-
- return &Etcd{cli: cli}, nil
+ return &ETCD{cliv3: cliv3, cfg: cfg}, nil
}
// IncrUint32 .
-func (e *Etcd) IncrUint32(ctx context.Context, key string) (n uint32, err error) {
+func (e *ETCD) IncrUint32(ctx context.Context, key string) (n uint32, err error) {
var mutex utils.Locker
if mutex, err = e.NewMutex(key); err != nil {
return
@@ -47,7 +83,7 @@ func (e *Etcd) IncrUint32(ctx context.Context, key string) (n uint32, err error)
}
defer func() {
if ue := unlock(ctx); ue != nil {
- err = errors.Wrap(err, ue)
+ err = errors.CombineErrors(err, ue)
}
}()
@@ -55,7 +91,7 @@ func (e *Etcd) IncrUint32(ctx context.Context, key string) (n uint32, err error)
var ver int64
switch ver, err = e.Get(ctx, key, &n); {
- case errors.IsKeyNotExistsErr(err):
+ case terrors.IsKeyNotExistsErr(err):
data[key] = "1"
if err = e.Create(ctx, data); err != nil {
return
@@ -74,11 +110,11 @@ func (e *Etcd) IncrUint32(ctx context.Context, key string) (n uint32, err error)
}
// Create .
-func (e *Etcd) Create(ctx context.Context, data map[string]string, opts ...clientv3.OpOption) error {
+func (e *ETCD) Create(ctx context.Context, data map[string]string, opts ...clientv3.OpOption) error {
var ev = newTxnEvent()
ev.data = data
ev.opts = opts
- ev.txnErr = errors.ErrKeyExists
+ ev.txnErr = terrors.ErrKeyExists
ev.vers = map[string]int64{}
for k := range ev.data {
@@ -89,22 +125,22 @@ func (e *Etcd) Create(ctx context.Context, data map[string]string, opts ...clien
}
// Update .
-func (e *Etcd) Update(ctx context.Context, data map[string]string, vers map[string]int64, opts ...clientv3.OpOption) error {
+func (e *ETCD) Update(ctx context.Context, data map[string]string, vers map[string]int64, opts ...clientv3.OpOption) error {
var ev = newTxnEvent()
ev.data = data
ev.opts = opts
- ev.txnErr = errors.ErrKeyBadVersion
+ ev.txnErr = terrors.ErrKeyBadVersion
ev.vers = vers
return e.batchPut(ctx, ev)
}
-func (e *Etcd) batchPut(ctx context.Context, ev *txnEvent) error {
+func (e *ETCD) batchPut(ctx context.Context, ev *txnEvent) error {
var ops, cmps = ev.generate()
switch succ, err := e.BatchOperate(ctx, ops, cmps...); {
case err != nil:
- return errors.Trace(err)
+ return errors.Wrap(err, "")
case !succ:
return ev.txnErr
@@ -114,46 +150,46 @@ func (e *Etcd) batchPut(ctx context.Context, ev *txnEvent) error {
}
// Delete .
-func (e *Etcd) Delete(ctx context.Context, keys []string, vers map[string]int64, opts ...clientv3.OpOption) error {
+func (e *ETCD) Delete(ctx context.Context, keys []string, vers map[string]int64, opts ...clientv3.OpOption) error {
var ev = newDelTxnEvent(keys, vers, opts...)
var ops, cmps = ev.generate()
switch succ, err := e.BatchOperate(ctx, ops, cmps...); {
case err != nil:
- return errors.Trace(err)
+ return errors.Wrap(err, "")
case !succ:
- return errors.Trace(errors.ErrKeyBadVersion)
+ return errors.Wrap(terrors.ErrKeyBadVersion, "ETCD.Delete")
}
return nil
}
// BatchOperate .
-func (e *Etcd) BatchOperate(ctx context.Context, ops []clientv3.Op, cmps ...clientv3.Cmp) (bool, error) {
+func (e *ETCD) BatchOperate(ctx context.Context, ops []clientv3.Op, cmps ...clientv3.Cmp) (bool, error) {
e.Lock()
defer e.Unlock()
- var txn = e.cli.Txn(ctx)
+ var txn = e.cliv3.Txn(ctx)
var resp, err = txn.If(cmps...).Then(ops...).Commit()
if err != nil {
- return false, errors.Trace(err)
+ return false, errors.Wrap(err, "")
}
return resp.Succeeded, nil
}
// GetPrefix .
-func (e *Etcd) GetPrefix(ctx context.Context, prefix string, limit int64) (map[string][]byte, map[string]int64, error) {
+func (e *ETCD) GetPrefix(ctx context.Context, prefix string, limit int64) (map[string][]byte, map[string]int64, error) {
e.Lock()
defer e.Unlock()
- var resp, err = e.cli.Get(ctx, prefix, clientv3.WithLimit(limit), clientv3.WithPrefix())
+ var resp, err = e.cliv3.Get(ctx, prefix, clientv3.WithLimit(limit), clientv3.WithPrefix())
switch {
case err != nil:
- return nil, nil, errors.Trace(err)
+ return nil, nil, errors.Wrap(err, "")
case resp.Count < 1:
- return nil, nil, errors.Annotatef(errors.ErrKeyNotExists, prefix)
+ return nil, nil, errors.Wrapf(terrors.ErrKeyNotExists, prefix)
}
var data = map[string][]byte{}
@@ -169,13 +205,13 @@ func (e *Etcd) GetPrefix(ctx context.Context, prefix string, limit int64) (map[s
}
// Exists .
-func (e *Etcd) Exists(ctx context.Context, keys []string) (map[string]bool, error) {
+func (e *ETCD) Exists(ctx context.Context, keys []string) (map[string]bool, error) {
var exists = map[string]bool{}
for _, k := range keys {
- var resp, err = e.cli.Get(ctx, k, clientv3.WithKeysOnly())
+ var resp, err = e.cliv3.Get(ctx, k, clientv3.WithKeysOnly())
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
exists[k] = resp.Count > 0
}
@@ -184,16 +220,16 @@ func (e *Etcd) Exists(ctx context.Context, keys []string) (map[string]bool, erro
}
// Get .
-func (e *Etcd) Get(ctx context.Context, key string, obj any, opts ...clientv3.OpOption) (int64, error) {
+func (e *ETCD) Get(ctx context.Context, key string, obj any, opts ...clientv3.OpOption) (int64, error) {
e.Lock()
defer e.Unlock()
- switch resp, err := e.cli.Get(ctx, key, opts...); {
+ switch resp, err := e.cliv3.Get(ctx, key, opts...); {
case err != nil:
- return 0, errors.Trace(err)
+ return 0, errors.Wrap(err, "")
case resp.Count != 1:
- return 0, errors.Annotatef(errors.ErrKeyNotExists, key)
+ return 0, errors.Wrapf(terrors.ErrKeyNotExists, key)
default:
return resp.Kvs[0].Version, decode(resp.Kvs[0].Value, obj)
@@ -201,23 +237,23 @@ func (e *Etcd) Get(ctx context.Context, key string, obj any, opts ...clientv3.Op
}
// NewMutex .
-func (e *Etcd) NewMutex(key string) (utils.Locker, error) {
- return NewMutex(e.cli, key)
+func (e *ETCD) NewMutex(key string) (utils.Locker, error) {
+ return NewMutex(e.cliv3.(*clientv3.Client), key)
}
// Close .
-func (e *Etcd) Close() error {
+func (e *ETCD) Close() error {
e.Lock()
defer e.Unlock()
- return e.cli.Close()
+ return e.cliv3.Close()
}
// RetryTimedOut .
func RetryTimedOut(fn func() error, retryTimes int) error {
for retried := 0; ; retried++ {
if err := fn(); err != nil {
- if retried < retryTimes && errors.IsETCDServerTimedOutErr(err) {
- log.Warnf("etcdserver: request timed out, retry it")
+ if retried < retryTimes && terrors.IsETCDServerTimedOutErr(err) {
+ log.Warnf(context.TODO(), "etcdserver: request timed out, retry it")
continue
}
diff --git a/pkg/store/etcd/etcd_test.go b/pkg/store/etcd/etcd_test.go
index 0d9e259..93450c3 100644
--- a/pkg/store/etcd/etcd_test.go
+++ b/pkg/store/etcd/etcd_test.go
@@ -13,21 +13,27 @@ import (
clientv3 "go.etcd.io/etcd/client/v3"
+ "github.com/cockroachdb/errors"
"github.com/projecteru2/yavirt/configs"
- "github.com/projecteru2/yavirt/pkg/errors"
"github.com/projecteru2/yavirt/pkg/test/assert"
"github.com/projecteru2/yavirt/pkg/utils"
)
+func NewTestETCD(t *testing.T) *ETCD {
+ cfg := configs.ETCDConfig{
+ Endpoints: []string{"127.0.0.1:2379"},
+ }
+ configs.Conf.Etcd.Endpoints = []string{"127.0.0.1:2379"}
+ etcd, err := New(cfg, t)
+ assert.NilErr(t, err)
+ return etcd
+}
+
func TestRealEtcdBacthOperate(t *testing.T) {
if os.Getenv("REAL_TEST") != "1" {
return
}
-
- configs.Conf.EtcdEndpoints = []string{"127.0.0.1:2379"}
- etcd, err := New()
- assert.NilErr(t, err)
-
+ etcd := NewTestETCD(t)
var ts = strconv.FormatInt(time.Now().Unix(), 10)
var delkey = filepath.Join("/yavirt-dev/v1/test/batchops/", ts)
var ctx = context.Background()
@@ -49,9 +55,7 @@ func TestRealEtcdIncrUint32(t *testing.T) {
return
}
- configs.Conf.EtcdEndpoints = []string{"127.0.0.1:2379"}
- etcd, err := New()
- assert.NilErr(t, err)
+ etcd := NewTestETCD(t)
var key = fmt.Sprintf("/yavirt-dev/v1/hosts:%d", time.Now().UnixNano())
var wg sync.WaitGroup
@@ -91,9 +95,7 @@ func TestRealEtcdCreateSerialization(t *testing.T) {
return
}
- configs.Conf.EtcdEndpoints = []string{"127.0.0.1:2379"}
- var etcd, err = New()
- assert.NilErr(t, err)
+ etcd := NewTestETCD(t)
var wg sync.WaitGroup
var key = fmt.Sprintf("/yavirt-dev/v1/hosts/%d", time.Now().UnixNano())
@@ -111,7 +113,7 @@ func TestRealEtcdCreateSerialization(t *testing.T) {
var data = map[string]string{key: strconv.Itoa(i)}
if err := etcd.Create(context.Background(), data); err != nil {
- t.Logf(" %d: %v ", i, errors.Stack(err))
+ t.Logf(" %d: %v ", i, errors.GetReportableStackTrace(err))
return
}
@@ -133,9 +135,7 @@ func TestRealEtcdUpdateSerialization(t *testing.T) {
return
}
- configs.Conf.EtcdEndpoints = []string{"127.0.0.1:2379"}
- var etcd, err = New()
- assert.NilErr(t, err)
+ etcd := NewTestETCD(t)
var key = fmt.Sprintf("/yavirt-dev/v1/hosts/%d", time.Now().UnixNano())
var data = map[string]string{key: "0"}
@@ -157,7 +157,7 @@ func TestRealEtcdUpdateSerialization(t *testing.T) {
var data = map[string]string{key: strconv.Itoa(i)}
if err := etcd.Update(context.Background(), data, vers); err != nil {
- t.Logf(" %d: %v ", i, errors.Stack(err))
+ t.Logf(" %d: %v ", i, errors.GetReportableStackTrace(err))
return
}
diff --git a/pkg/store/etcd/sync.go b/pkg/store/etcd/sync.go
index e33c16a..05d6816 100644
--- a/pkg/store/etcd/sync.go
+++ b/pkg/store/etcd/sync.go
@@ -6,7 +6,7 @@ import (
clientv3 "go.etcd.io/etcd/client/v3"
"go.etcd.io/etcd/client/v3/concurrency"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/cockroachdb/errors"
"github.com/projecteru2/yavirt/pkg/utils"
)
@@ -20,7 +20,7 @@ type Mutex struct {
func NewMutex(cli *clientv3.Client, key string) (utils.Locker, error) {
var sess, err = concurrency.NewSession(cli)
if err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
return &Mutex{
@@ -32,7 +32,7 @@ func NewMutex(cli *clientv3.Client, key string) (utils.Locker, error) {
// Lock .
func (m *Mutex) Lock(ctx context.Context) (utils.Unlocker, error) {
if err := m.mutex.Lock(ctx); err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
return m.Unlock, nil
}
@@ -41,7 +41,7 @@ func (m *Mutex) Lock(ctx context.Context) (utils.Unlocker, error) {
func (m *Mutex) Unlock(ctx context.Context) (err error) {
defer func() {
if e := m.session.Close(); e != nil {
- err = errors.Wrap(err, e)
+ err = errors.CombineErrors(err, e)
}
}()
return m.mutex.Unlock(ctx)
diff --git a/pkg/store/store.go b/pkg/store/store.go
index 3fbc4e4..ba27e4a 100644
--- a/pkg/store/store.go
+++ b/pkg/store/store.go
@@ -2,11 +2,14 @@ package store
import (
"context"
+ "testing"
clientv3 "go.etcd.io/etcd/client/v3"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/yavirt/configs"
"github.com/projecteru2/yavirt/pkg/store/etcd"
+ "github.com/projecteru2/yavirt/pkg/terrors"
"github.com/projecteru2/yavirt/pkg/utils"
)
@@ -28,21 +31,16 @@ type Store interface {
NewMutex(key string) (utils.Locker, error)
}
-// New .
-func New(metatype string) (Store, error) {
- switch metatype {
- case "etcd":
- return etcd.New()
- default:
- return nil, errors.Annotatef(errors.ErrInvalidValue, "invalid meta type: %s", metatype)
- }
-}
-
var store Store
// Setup .
-func Setup(metatype string) (err error) {
- store, err = New(metatype)
+func Setup(cfg configs.Config, t *testing.T) (err error) {
+ switch cfg.MetaType {
+ case "etcd":
+ store, err = etcd.New(cfg.Etcd, t)
+ default:
+ err = errors.Wrapf(terrors.ErrInvalidValue, "invalid meta type: %s", cfg.MetaType)
+ }
return
}
@@ -108,7 +106,7 @@ func IncrUint32(ctx context.Context, key string) (uint32, error) {
func Lock(ctx context.Context, key string) (utils.Unlocker, error) {
mutex, err := store.NewMutex(key)
if err != nil {
- return nil, errors.Annotatef(err, "create mutex %s failed", key)
+ return nil, errors.Wrapf(err, "create mutex %s failed", key)
}
return mutex.Lock(ctx)
}
diff --git a/pkg/errors/check.go b/pkg/terrors/check.go
similarity index 64%
rename from pkg/errors/check.go
rename to pkg/terrors/check.go
index a70bb20..3f2e921 100644
--- a/pkg/errors/check.go
+++ b/pkg/terrors/check.go
@@ -1,33 +1,35 @@
-package errors
+package terrors
+
+import "github.com/cockroachdb/errors"
// IsVirtLinkRouteExistsErr .
func IsVirtLinkRouteExistsErr(err error) bool {
- return Contain(err, ErrVirtLinkRouteExists)
+ return errors.Is(err, ErrVirtLinkRouteExists)
}
// IsVirtLinkNotExistsErr .
func IsVirtLinkNotExistsErr(err error) bool {
- return Contain(err, ErrVirtLinkNotExists)
+ return errors.Is(err, ErrVirtLinkNotExists)
}
// IsVirtLinkAddrExistsErr .
func IsVirtLinkAddrExistsErr(err error) bool {
- return Contain(err, ErrVirtLinkAddrExists)
+ return errors.Is(err, ErrVirtLinkAddrExists)
}
// IsCalicoEndpointNotExistsErr .
func IsCalicoEndpointNotExistsErr(err error) bool {
- return Contain(err, ErrCalicoEndpointNotExists)
+ return errors.Is(err, ErrCalicoEndpointNotExists)
}
// IsIPv4IsNetworkNumberErr .
func IsIPv4IsNetworkNumberErr(err error) bool {
- return Contain(err, ErrIPv4IsNetworkNumber)
+ return errors.Is(err, ErrIPv4IsNetworkNumber)
}
// IsIPv4IsBroadcastErr .
func IsIPv4IsBroadcastErr(err error) bool {
- return Contain(err, ErrIPv4IsBroadcastAddr)
+ return errors.Is(err, ErrIPv4IsBroadcastAddr)
}
// IsETCDServerTimedOutErr .
@@ -37,10 +39,10 @@ func IsETCDServerTimedOutErr(err error) bool {
// IsKeyNotExistsErr .
func IsKeyNotExistsErr(err error) bool {
- return Contain(err, ErrKeyNotExists)
+ return errors.Is(err, ErrKeyNotExists)
}
// IsDomainNotExistsErr .
func IsDomainNotExistsErr(err error) bool {
- return Contain(err, ErrDomainNotExists)
+ return errors.Is(err, ErrDomainNotExists)
}
diff --git a/pkg/terrors/check_test.go b/pkg/terrors/check_test.go
new file mode 100644
index 0000000..89cd7dc
--- /dev/null
+++ b/pkg/terrors/check_test.go
@@ -0,0 +1,33 @@
+package terrors
+
+import (
+ "testing"
+
+ "github.com/cockroachdb/errors"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestIsVirtLinkRouteExistsErr(t *testing.T) {
+ err := ErrVirtLinkRouteExists
+ err = errors.Wrap(err, "test")
+ assert.True(t, IsVirtLinkRouteExistsErr(err))
+ err = errors.WithMessage(err, "test1")
+ assert.True(t, IsVirtLinkRouteExistsErr(err))
+}
+
+// func TestWrap(t *testing.T) {
+// err1 := func() error {
+// return func() error {
+// return errors.Wrap(ErrVirtLinkRouteExists, "test")
+// }()
+// }()
+// err2 := func() error {
+// err := func() error {
+// return errors.Wrap(ErrVirtLinkRouteExists, "test")
+// }()
+// return errors.Wrap(err, "test1")
+// }()
+// assert.Truef(t, false, "error1: %+v", err1)
+// assert.Truef(t, false, "error2: %+v", err2)
+// assert.Truef(t, false, "error3: %+v", errors.WithMessage(err1, "test3"))
+// }
diff --git a/pkg/terrors/const.go b/pkg/terrors/const.go
new file mode 100644
index 0000000..7ceff7c
--- /dev/null
+++ b/pkg/terrors/const.go
@@ -0,0 +1,113 @@
+package terrors
+
+import "github.com/cockroachdb/errors"
+
+var (
+ // ErrInvalidValue indicates the value is invalid.
+ ErrInvalidValue = errors.New("invalid value")
+
+ // ErrExecIsRunning .
+ ErrExecIsRunning = errors.New("exec is still running")
+ // ErrExecNonZeroReturn .
+ ErrExecNonZeroReturn = errors.New("exec return code is non-zero")
+ // ErrExecOnNonRunningGuest .
+ ErrExecOnNonRunningGuest = errors.New("exec on a non-running guest")
+
+ // ErrIPv4IsNetworkNumber .
+ ErrIPv4IsNetworkNumber = errors.New("IPv4 is a network number")
+ // ErrIPv4IsBroadcastAddr .
+ ErrIPv4IsBroadcastAddr = errors.New("IPv4 is a broadcast addr")
+
+ // ErrCalicoEndpointNotExists .
+ ErrCalicoEndpointNotExists = errors.New("Calico WorkloadEndpoint not exists")
+ // ErrCalicoPoolNotExists .
+ ErrCalicoPoolNotExists = errors.New("Calico IP pool not exists")
+ // ErrCalicoIPv4Only .
+ ErrCalicoIPv4Only = errors.New("only support Calico IPv4")
+ // ErrCalicoCannotCrossBlocks .
+ ErrCalicoCannotCrossBlocks = errors.New("cannot cross Calico blocks")
+ // ErrCalicoGatewayIPNotExists .
+ ErrCalicoGatewayIPNotExists = errors.New("Calico gateway IP not exists")
+ // ErrCalicoTooSmallSubnet .
+ ErrCalicoTooSmallSubnet = errors.New("Calico subnet is too small to use")
+
+ // ErrVirtLinkExists .
+ ErrVirtLinkExists = errors.New("link exists")
+ // ErrVirtLinkNotExists .
+ ErrVirtLinkNotExists = errors.New("link not exists")
+ // ErrVirtLinkAddrExists .
+ ErrVirtLinkAddrExists = errors.New("link addr exists")
+ // ErrVirtLinkRouteExists .
+ ErrVirtLinkRouteExists = errors.New("link route exists")
+
+ // ErrKeyExists .
+ ErrKeyExists = errors.New("key exists")
+ // ErrKeyNotExists .
+ ErrKeyNotExists = errors.New("key not exists")
+ // ErrKeyBadVersion .
+ ErrKeyBadVersion = errors.New("bad version")
+
+ // ErrBatchOperate .
+ ErrBatchOperate = errors.New("batch operate error")
+ // ErrOperateIP .
+ ErrOperateIP = errors.New("operate IP error")
+ // ErrForwardStatus .
+ ErrForwardStatus = errors.New("cannot forward status")
+ // ErrConnectLibvirtd .
+ ErrConnectLibvirtd = errors.New("connect libvirtd error")
+ // ErrSysVolumeNotExists .
+ ErrSysVolumeNotExists = errors.New("sys volume not exists")
+ // ErrNotSysVolume .
+ ErrNotSysVolume = errors.New("not sys volume")
+ // ErrTooManyVolumes .
+ ErrTooManyVolumes = errors.New("too many extra volumes")
+ // ErrCannotShrinkVolume .
+ ErrCannotShrinkVolume = errors.New("cannot shrink a volume")
+ // ErrDomainNotExists .
+ ErrDomainNotExists = errors.New("domain not exists")
+ // ErrInvalidVolumeBind .
+ ErrInvalidVolumeBind = errors.New("invalid volume bind")
+
+ // ErrTooLargeOffset .
+ ErrTooLargeOffset = errors.New("too large offset")
+ // ErrNoSuchIPPool .
+ ErrNoSuchIPPool = errors.New("no such IPPool")
+ // ErrTooLargeMaskBits .
+ ErrTooLargeMaskBits = errors.New("too large mask bits")
+ // ErrTooSmallMaskBits .
+ ErrTooSmallMaskBits = errors.New("too small mask bits")
+ // ErrInsufficientBlocks .
+ ErrInsufficientBlocks = errors.New("insufficient blocks")
+ // ErrInsufficientIP .
+ ErrInsufficientIP = errors.New("insufficient free IP")
+ // ErrIPIsnotAssigned .
+ ErrIPIsnotAssigned = errors.New("IP isn't assigned")
+
+ // ErrSerializedTaskAborted .
+ ErrSerializedTaskAborted = errors.New("serialized task was aborted in advance")
+
+ // ErrTimeout .
+ ErrTimeout = errors.New("timed out")
+ // ErrNotImplemented .
+ ErrNotImplemented = errors.New("does not implemented")
+
+ // ErrFolderExists .
+ ErrFolderExists = errors.New("destination folder exists")
+ // ErrDestinationInvalid .
+ ErrDestinationInvalid = errors.New("destination path not valid")
+ // ErrNotValidCopyStatus .
+ ErrNotValidCopyStatus = errors.New("cannot copy in this status")
+ // ErrNotValidLogStatus .
+ ErrNotValidLogStatus = errors.New("cannot read log in this status")
+
+ // ErrImageHubNotConfigured .
+ ErrImageHubNotConfigured = errors.New("ImageHub is not set")
+ // ErrImageFileNotExists .
+ ErrImageFileNotExists = errors.New("Image File not exists")
+ // ErrLoadImage
+ ErrLoadImage = errors.New("Failed to load image")
+
+ ErrFlockLocked = errors.New("flock locked")
+
+ ErrUnknownNetworkDriver = errors.New("unknown network driver")
+)
diff --git a/pkg/test/assert/assert.go b/pkg/test/assert/assert.go
index 2c114d3..f8dd966 100644
--- a/pkg/test/assert/assert.go
+++ b/pkg/test/assert/assert.go
@@ -5,17 +5,17 @@ import (
"github.com/stretchr/testify/require"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/cockroachdb/errors"
)
// NilErr .
func NilErr(t *testing.T, err error) {
- Nil(t, err, errors.Stack(err))
+ Nil(t, err, errors.GetReportableStackTrace(err))
}
// Err .
func Err(t *testing.T, err error) {
- NotNil(t, err, errors.Stack(err))
+ NotNil(t, err, errors.GetReportableStackTrace(err))
}
// Nil .
diff --git a/pkg/utils/bitmap32.go b/pkg/utils/bitmap32.go
index 45a9f70..c924e1e 100644
--- a/pkg/utils/bitmap32.go
+++ b/pkg/utils/bitmap32.go
@@ -1,7 +1,8 @@
package utils
import (
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/yavirt/pkg/terrors"
)
const bitsPerSection = 32
@@ -130,7 +131,7 @@ func (b *Bitmap32) GetIndex(offset int) (mi, bi int) {
func (b *Bitmap32) checkOffset(offset int) error {
if offset >= b.Count {
- return errors.Annotatef(errors.ErrTooLargeOffset,
+ return errors.Wrapf(terrors.ErrTooLargeOffset,
"at most %d, but %d", b.Count-1, offset)
}
return nil
diff --git a/pkg/utils/bytes_queue.go b/pkg/utils/bytes_queue.go
new file mode 100644
index 0000000..228090a
--- /dev/null
+++ b/pkg/utils/bytes_queue.go
@@ -0,0 +1,120 @@
+package utils
+
+import (
+ "bytes"
+ "container/list"
+ "io"
+ "sync"
+)
+
+type BytesQueue struct {
+ cond *sync.Cond
+ l *list.List
+ quit chan struct{}
+}
+
+func NewBytesQueue() *BytesQueue {
+ return &BytesQueue{
+ l: list.New(),
+ cond: sync.NewCond(&sync.Mutex{}),
+ quit: make(chan struct{}),
+ }
+}
+
+func (q *BytesQueue) Pop() ([]byte, error) {
+ q.cond.L.Lock()
+ defer q.cond.L.Unlock()
+
+ ele := q.l.Front()
+ if ele == nil {
+ select {
+ case <-q.quit:
+ return nil, io.EOF
+ default:
+ q.cond.Wait()
+ }
+ }
+ ele = q.l.Front()
+ if ele == nil {
+ return nil, nil
+ }
+ q.l.Remove(ele)
+ return ele.Value.([]byte), nil
+}
+
+func (q *BytesQueue) Read(p []byte) (total int, err error) {
+ q.cond.L.Lock()
+ defer q.cond.L.Unlock()
+
+ ele := q.l.Front()
+ if ele == nil {
+ select {
+ case <-q.quit:
+ return 0, io.EOF
+ default:
+ q.cond.Wait()
+ }
+ }
+ ele = q.l.Front()
+ if ele == nil {
+ return 0, nil
+ }
+
+ bs := ele.Value.([]byte) //nolint
+ total = copy(p, bs)
+ if total < len(bs) {
+ ele.Value = bs[total:]
+ } else {
+ q.l.Remove(ele)
+ }
+ return
+}
+
+func (q *BytesQueue) Write(p []byte) (int, error) {
+ select {
+ case <-q.quit:
+ return 0, io.ErrClosedPipe
+ default:
+ }
+ q.cond.L.Lock()
+ q.l.PushBack(bytes.Clone(p))
+ q.cond.L.Unlock()
+ q.cond.Signal()
+ return len(p), nil
+}
+
+func (q *BytesQueue) Close() {
+ close(q.quit)
+ q.cond.Broadcast()
+}
+
+func (q *BytesQueue) HandleHead(fn func([]byte) (int, error)) (total int, err error) {
+ q.cond.L.Lock()
+ defer q.cond.L.Unlock()
+
+ ele := q.l.Front()
+ if ele == nil {
+ select {
+ case <-q.quit:
+ return 0, io.EOF
+ default:
+ return 0, nil
+ }
+ }
+ ele = q.l.Front()
+ if ele == nil {
+ return 0, nil
+ }
+
+ bs := ele.Value.([]byte) //nolint
+ total, err = fn(bs)
+ if err != nil {
+ return
+ }
+ if total < len(bs) {
+ ele.Value = bs[total:]
+ } else {
+ q.l.Remove(ele)
+ }
+ return
+}
diff --git a/pkg/utils/filepath.go b/pkg/utils/filepath.go
index 5efb8b5..703e29a 100644
--- a/pkg/utils/filepath.go
+++ b/pkg/utils/filepath.go
@@ -4,7 +4,7 @@ import (
"os"
"path/filepath"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/cockroachdb/errors"
)
// BaseFilename .
@@ -26,18 +26,26 @@ func AbsDir(fpth string) (string, error) {
func Walk(root string, fn filepath.WalkFunc) error {
var entries, err = os.ReadDir(root)
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
for _, entry := range entries {
info, err := entry.Info()
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
if err := fn(filepath.Join(root, entry.Name()), info, nil); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
}
return nil
}
+
+func FileExists(filename string) bool {
+ info, err := os.Stat(filename)
+ if os.IsNotExist(err) {
+ return false
+ }
+ return !info.IsDir()
+}
diff --git a/pkg/utils/flock.go b/pkg/utils/flock.go
index d90b15b..db162da 100644
--- a/pkg/utils/flock.go
+++ b/pkg/utils/flock.go
@@ -1,12 +1,14 @@
package utils
import (
+ "context"
"os"
"sync"
"syscall"
- "github.com/projecteru2/yavirt/pkg/errors"
- "github.com/projecteru2/yavirt/pkg/log"
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/core/log"
+ "github.com/projecteru2/yavirt/pkg/terrors"
)
const perm = os.FileMode(0600)
@@ -34,7 +36,7 @@ func (f *Flock) Trylock() error {
}
if err := f.open(); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
return f.flock(true)
@@ -51,17 +53,17 @@ func (f *Flock) flock(retry bool) error {
case err != syscall.EIO && err != syscall.EBADF:
fallthrough
case !retry:
- return errors.Errorf("%s has locked yet", f.fpth)
+ return errors.WithMessagef(terrors.ErrFlockLocked, "%s has locked yet", f.fpth)
}
var stat, err = f.file.Stat()
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
if stat.Mode()&0600 == 0600 {
if err := f.reopen(); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
}
@@ -80,7 +82,7 @@ func (f *Flock) open() error {
var fh, err = os.OpenFile(f.fpth, os.O_CREATE|os.O_RDWR, perm)
if err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
f.file = fh
@@ -98,11 +100,11 @@ func (f *Flock) Close() {
}
if err := f.unlock(); err != nil {
- log.WarnStack(err)
+ log.Error(context.TODO(), err)
}
if err := os.Remove(f.fpth); err != nil {
- log.WarnStack(err)
+ log.Error(context.TODO(), err)
}
}
@@ -112,13 +114,28 @@ func (f *Flock) Unlock() {
defer f.mut.Unlock()
if err := f.unlock(); err != nil {
- log.WarnStack(err)
+ log.Error(context.TODO(), err)
}
}
+func (f *Flock) RemoveFile() error {
+ f.mut.Lock()
+ defer f.mut.Unlock()
+ err := os.Remove(f.fpth)
+ if err == nil || os.IsNotExist(err) {
+ return nil
+ }
+ return err
+}
+
+func (f *Flock) FileExists() bool {
+ _, err := os.Stat(f.fpth)
+ return err == nil
+}
+
func (f *Flock) unlock() error {
if err := syscall.Flock(int(f.file.Fd()), syscall.LOCK_UN); err != nil {
- return errors.Trace(err)
+ return errors.Wrap(err, "")
}
f.locked = false
@@ -130,7 +147,7 @@ func (f *Flock) unlock() error {
func (f *Flock) close() {
if err := f.file.Close(); err != nil {
- log.Warnf("[util] close %s failed", f.fpth)
+ log.Warnf(context.TODO(), "[util] close %s failed", f.fpth)
}
f.file = nil
}
diff --git a/pkg/utils/flock_test.go b/pkg/utils/flock_test.go
index 91e0776..9fabea0 100644
--- a/pkg/utils/flock_test.go
+++ b/pkg/utils/flock_test.go
@@ -66,3 +66,18 @@ func TestFlockSingle(t *testing.T) {
}
wg.Wait()
}
+
+func TestRemoveExists(t *testing.T) {
+ var rand = strconv.FormatInt(time.Now().UnixNano(), 10)
+
+ var fpth = filepath.Join(os.TempDir(), rand)
+ defer os.Remove(fpth)
+
+ var flock = NewFlock(fpth)
+ assert.False(t, flock.FileExists())
+ assert.NilErr(t, flock.Trylock())
+ assert.True(t, flock.FileExists())
+ assert.Nil(t, flock.RemoveFile())
+ assert.False(t, flock.FileExists())
+ assert.Nil(t, flock.RemoveFile())
+}
diff --git a/pkg/utils/io.go b/pkg/utils/io.go
deleted file mode 100644
index 9c7dde9..0000000
--- a/pkg/utils/io.go
+++ /dev/null
@@ -1,93 +0,0 @@
-package utils
-
-import (
- "bytes"
- "context"
- "io"
- "os"
-
- "github.com/projecteru2/yavirt/pkg/errors"
- "github.com/projecteru2/yavirt/pkg/log"
-)
-
-// ReadAll .
-func ReadAll(fpth string) ([]byte, error) {
- f, err := os.Open(fpth)
- if err != nil {
- return nil, errors.Trace(err)
- }
-
- buf, err := io.ReadAll(f)
- if err != nil {
- return nil, errors.Trace(err)
- }
-
- return buf, nil
-}
-
-// WriteTempFile .
-func WriteTempFile(buf []byte) (string, error) {
- f, err := os.CreateTemp(os.TempDir(), "temp-guest-*.xml")
- if err != nil {
- return "", errors.Trace(err)
- }
-
- if _, err := f.Write(buf); err != nil {
- return "", errors.Trace(err)
- }
-
- return f.Name(), nil
-}
-
-// Scan is tested to guarantee no goroutine leaking
-func Scan(_ context.Context, reader io.Reader) <-chan []byte {
- ch := make(chan []byte)
- go func() {
- defer close(ch)
-
- for {
- p := make([]byte, 65536)
- n, err := reader.Read(p)
- if n > 0 {
- if bytes.Contains(p[:n], []byte("^]")) {
- log.Warnf("[io.Scan] reader exited: %v", reader)
- return
- }
- ch <- p[:n]
- }
-
- if err != nil {
- if err != io.EOF {
- log.Warnf("[io.Scan] error in reading %s: %s", reader, errors.Trace(err))
- }
- return
- }
- }
-
- }()
-
- return ch
-}
-
-// CopyIO is parallel to io.Copy execpt accepting context
-func CopyIO(ctx context.Context, dst io.WriteCloser, src io.Reader) (written int, err error) {
- defer dst.Close()
-
- var n int
- ch := Scan(ctx, src)
- for {
- select {
- case <-ctx.Done():
- return
- case bytes, ok := <-ch:
- if !ok {
- return
- }
- if n, err = dst.Write(bytes); err != nil {
- log.Warnf("error in copy io: %s", errors.Trace(err))
- return
- }
- written += n
- }
- }
-}
diff --git a/pkg/utils/mac.go b/pkg/utils/mac.go
index f1874a4..97fab2b 100644
--- a/pkg/utils/mac.go
+++ b/pkg/utils/mac.go
@@ -4,14 +4,14 @@ import (
"crypto/rand"
"fmt"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/cockroachdb/errors"
)
// QemuMAC .
func QemuMAC() (string, error) {
var buf, err = RandBuf(3)
if err != nil {
- return "", errors.Trace(err)
+ return "", errors.Wrap(err, "")
}
return fmt.Sprintf("52:54:00:%02x:%02x:%02x", buf[0], buf[1], buf[2]), nil
}
@@ -20,7 +20,7 @@ func QemuMAC() (string, error) {
func RandBuf(n int) ([]byte, error) {
var buf = make([]byte, n)
if _, err := rand.Read(buf); err != nil {
- return nil, errors.Trace(err)
+ return nil, errors.Wrap(err, "")
}
return buf, nil
}
diff --git a/pkg/utils/sync_map.go b/pkg/utils/sync_map.go
index 26d1cb8..6252c41 100644
--- a/pkg/utils/sync_map.go
+++ b/pkg/utils/sync_map.go
@@ -4,7 +4,7 @@ import (
"strconv"
"sync"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/projecteru2/yavirt/pkg/terrors"
)
type ExitCodeMap struct {
@@ -19,7 +19,7 @@ func NewSyncMap() *ExitCodeMap {
func (s *ExitCodeMap) Get(id string, pid int) (int, error) {
v, ok := s.Load(id + strconv.Itoa(pid))
if !ok {
- return 0, errors.ErrKeyNotExists
+ return 0, terrors.ErrKeyNotExists
}
return v.(int), nil
}
diff --git a/pkg/utils/sync_map_test.go b/pkg/utils/sync_map_test.go
index 062d78e..aaea702 100644
--- a/pkg/utils/sync_map_test.go
+++ b/pkg/utils/sync_map_test.go
@@ -3,7 +3,7 @@ package utils
import (
"testing"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/projecteru2/yavirt/pkg/terrors"
"github.com/projecteru2/yavirt/pkg/test/assert"
)
@@ -11,7 +11,7 @@ func TestSyncMap(t *testing.T) {
mp := NewSyncMap()
_, err := mp.Get("a", 0)
- assert.Equal(t, errors.ErrKeyNotExists, err)
+ assert.Equal(t, terrors.ErrKeyNotExists, err)
mp.Put("a", 0, 5)
v, err := mp.Get("a", 0)
diff --git a/pkg/utils/sync_test.go b/pkg/utils/sync_test.go
index 0f82952..a6c9481 100644
--- a/pkg/utils/sync_test.go
+++ b/pkg/utils/sync_test.go
@@ -4,7 +4,7 @@ import (
"sync"
"testing"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/cockroachdb/errors"
"github.com/projecteru2/yavirt/pkg/test/assert"
)
diff --git a/pkg/utils/time.go b/pkg/utils/time.go
index c94d102..62402d0 100644
--- a/pkg/utils/time.go
+++ b/pkg/utils/time.go
@@ -8,7 +8,7 @@ import (
// RandAfterFunc .
func RandAfterFunc(min, max time.Duration, fn func()) *time.Timer {
- t, _ := rand.Int(rand.Reader, big.NewInt(int64(max)-int64(min))) //nolint
+ t, _ := rand.Int(rand.Reader, big.NewInt(int64(max)-int64(min)))
dur := time.Duration(t.Int64()) + min
return time.AfterFunc(dur, fn)
}
diff --git a/pkg/utils/uuid.go b/pkg/utils/uuid.go
index ed2d9ee..e47f1d3 100644
--- a/pkg/utils/uuid.go
+++ b/pkg/utils/uuid.go
@@ -3,14 +3,14 @@ package utils
import (
"github.com/google/uuid"
- "github.com/projecteru2/yavirt/pkg/errors"
+ "github.com/cockroachdb/errors"
)
// UUIDStr .
func UUIDStr() (string, error) {
var u, err = uuid.NewUUID()
if err != nil {
- return "", errors.Trace(err)
+ return "", errors.Wrap(err, "NewUUID error")
}
return u.String(), nil
}
diff --git a/third_party/libvirt/AUTHORS b/third_party/libvirt/AUTHORS
new file mode 100644
index 0000000..aea2144
--- /dev/null
+++ b/third_party/libvirt/AUTHORS
@@ -0,0 +1,28 @@
+Maintainer
+----------
+DigitalOcean, Inc
+
+Original Authors
+----------------
+Ben LeMasurier
+Matt Layher
+
+Contributors
+------------
+Justin Kim
+Ricky Medina
+Charlie Drage
+Michael Koppmann
+Simarpreet Singh
+Alexander Polyakov
+Amanda Andrade
+Geoff Hickey
+Yuriy Taraday
+Sylvain Baubeau
+David Schneider
+Alec Hothan
+Akos Varga
+Peter Kurfer
+Sam Roberts
+Moritz Wanzenböck
+Jenni Griesmann
diff --git a/third_party/libvirt/CONTRIBUTING.md b/third_party/libvirt/CONTRIBUTING.md
new file mode 100644
index 0000000..6e36f0a
--- /dev/null
+++ b/third_party/libvirt/CONTRIBUTING.md
@@ -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/projecteru2/yavirt/third_party/libvirt/issues/new) or find an
+[existing issue](https://github.com/projecteru2/yavirt/third_party/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/projecteru2/yavirt/third_party/libvirt/blob/master/AUTHORS) file
+under the "Contributors" section using the format:
+`First Last `.
+
+Finally, submit a pull request for review!
+
+Feel free to join us in [`#go-libvirt` on libera chat](https://web.libera.chat/)
+if you'd like to discuss the project.
diff --git a/third_party/libvirt/LICENSE.md b/third_party/libvirt/LICENSE.md
new file mode 100644
index 0000000..f5f4b8b
--- /dev/null
+++ b/third_party/libvirt/LICENSE.md
@@ -0,0 +1,195 @@
+Apache License
+==============
+
+_Version 2.0, January 2004_
+_<>_
+
+### 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.
+
diff --git a/third_party/libvirt/README.md b/third_party/libvirt/README.md
new file mode 100644
index 0000000..9cbd1c1
--- /dev/null
+++ b/third_party/libvirt/README.md
@@ -0,0 +1,283 @@
+libvirt
+[![GoDoc](http://godoc.org/github.com/projecteru2/yavirt/third_party/libvirt?status.svg)](http://godoc.org/github.com/projecteru2/yavirt/third_party/libvirt)
+[![Build Status](https://github.com/projecteru2/yavirt/third_party/libvirt/actions/workflows/main.yml/badge.svg)](https://github.com/projecteru2/yavirt/third_party/libvirt/actions/)
+[![Report Card](https://goreportcard.com/badge/github.com/projecteru2/yavirt/third_party/libvirt)](https://goreportcard.com/report/github.com/projecteru2/yavirt/third_party/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/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).
+
+libvirt's RPC interface is quite extensive, and changes from one version to the
+next, so this project uses a pair of code generators to build the go bindings.
+The code generators should be run whenever you want to build go-libvirt for a
+new version of libvirt. See the next section for directions on re-generating
+go-libvirt.
+
+[Pull requests are welcome](https://github.com/projecteru2/yavirt/third_party/libvirt/blob/master/CONTRIBUTING.md)!
+
+Feel free to join us in [`#go-libvirt` on libera chat](https://web.libera.chat/)
+if you'd like to discuss the project.
+
+Running the Code Generators
+---------------------------
+
+The code generator doesn't run automatically when you build go-libvirt. It's
+meant to be run manually any time you change the version of libvirt you're
+using. When you download go-libvirt it will come with generated files
+corresponding to a particular version of libvirt. You can use the library as-is,
+but the generated code may be missing libvirt functions, if you're using a newer
+version of libvirt, or it may have extra functions that will return
+'unimplemented' errors if you try to call them. If this is a problem, you should
+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.
+- 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.
+
+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/projecteru2/yavirt/third_party/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/projecteru2/yavirt/third_party/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
+-------
+
+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/projecteru2/yavirt/third_party/libvirt"
+)
+
+func main() {
+ // This dials libvirt on the local machine, but you can substitute the first
+ // two parameters with "tcp", ":" 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.NewWithDialer(c)
+ if err := l.Connect(); err != nil {
+ log.Fatalf("failed to connect: %v", err)
+ }
+
+ v, err := l.ConnectGetLibVersion()
+ 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
+```
+
+Example (Connect to libvirt via TLS over TCP)
+-------
+
+```go
+package main
+
+import (
+ "crypto/tls"
+ "crypto/x509"
+
+ "fmt"
+ "io/ioutil"
+ "log"
+
+ "github.com/projecteru2/yavirt/third_party/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/projecteru2/yavirt/third_party/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/workflows](.github/workflows)
+and can be triggered manually in the GitHub UI 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.
diff --git a/third_party/libvirt/const.gen.go b/third_party/libvirt/const.gen.go
new file mode 100644
index 0000000..b20998c
--- /dev/null
+++ b/third_party/libvirt/const.gen.go
@@ -0,0 +1,2592 @@
+// 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.
+//
+
+// WARNING: This file has automatically been generated
+// Code generated by https://git.io/c-for-go. DO NOT EDIT.
+
+package libvirt
+
+const (
+ // ExportVar as defined in libvirt/libvirt-common.h:57
+ ExportVar = 0
+ // TypedParamFieldLength as defined in libvirt/libvirt-common.h:170
+ TypedParamFieldLength = 80
+ // SecurityLabelBuflen as defined in libvirt/libvirt-host.h:84
+ SecurityLabelBuflen = 4097
+ // SecurityModelBuflen as defined in libvirt/libvirt-host.h:112
+ SecurityModelBuflen = 257
+ // SecurityDoiBuflen as defined in libvirt/libvirt-host.h:119
+ SecurityDoiBuflen = 257
+ // NodeCPUStatsFieldLength as defined in libvirt/libvirt-host.h:180
+ NodeCPUStatsFieldLength = 80
+ // NodeCPUStatsKernel as defined in libvirt/libvirt-host.h:197
+ NodeCPUStatsKernel = "kernel"
+ // NodeCPUStatsUser as defined in libvirt/libvirt-host.h:205
+ NodeCPUStatsUser = "user"
+ // NodeCPUStatsIdle as defined in libvirt/libvirt-host.h:213
+ NodeCPUStatsIdle = "idle"
+ // NodeCPUStatsIowait as defined in libvirt/libvirt-host.h:221
+ NodeCPUStatsIowait = "iowait"
+ // NodeCPUStatsIntr as defined in libvirt/libvirt-host.h:229
+ NodeCPUStatsIntr = "intr"
+ // NodeCPUStatsUtilization as defined in libvirt/libvirt-host.h:238
+ NodeCPUStatsUtilization = "utilization"
+ // NodeMemoryStatsFieldLength as defined in libvirt/libvirt-host.h:258
+ NodeMemoryStatsFieldLength = 80
+ // NodeMemoryStatsTotal as defined in libvirt/libvirt-host.h:275
+ NodeMemoryStatsTotal = "total"
+ // NodeMemoryStatsFree as defined in libvirt/libvirt-host.h:284
+ NodeMemoryStatsFree = "free"
+ // NodeMemoryStatsBuffers as defined in libvirt/libvirt-host.h:292
+ NodeMemoryStatsBuffers = "buffers"
+ // NodeMemoryStatsCached as defined in libvirt/libvirt-host.h:300
+ NodeMemoryStatsCached = "cached"
+ // NodeMemorySharedPagesToScan as defined in libvirt/libvirt-host.h:321
+ NodeMemorySharedPagesToScan = "shm_pages_to_scan"
+ // NodeMemorySharedSleepMillisecs as defined in libvirt/libvirt-host.h:329
+ NodeMemorySharedSleepMillisecs = "shm_sleep_millisecs"
+ // NodeMemorySharedPagesShared as defined in libvirt/libvirt-host.h:337
+ NodeMemorySharedPagesShared = "shm_pages_shared"
+ // NodeMemorySharedPagesSharing as defined in libvirt/libvirt-host.h:345
+ NodeMemorySharedPagesSharing = "shm_pages_sharing"
+ // NodeMemorySharedPagesUnshared as defined in libvirt/libvirt-host.h:353
+ NodeMemorySharedPagesUnshared = "shm_pages_unshared"
+ // NodeMemorySharedPagesVolatile as defined in libvirt/libvirt-host.h:361
+ NodeMemorySharedPagesVolatile = "shm_pages_volatile"
+ // NodeMemorySharedFullScans as defined in libvirt/libvirt-host.h:369
+ NodeMemorySharedFullScans = "shm_full_scans"
+ // NodeMemorySharedMergeAcrossNodes as defined in libvirt/libvirt-host.h:381
+ NodeMemorySharedMergeAcrossNodes = "shm_merge_across_nodes"
+ // NodeSevPdh as defined in libvirt/libvirt-host.h:449
+ NodeSevPdh = "pdh"
+ // NodeSevCertChain as defined in libvirt/libvirt-host.h:458
+ NodeSevCertChain = "cert-chain"
+ // NodeSevCbitpos as defined in libvirt/libvirt-host.h:465
+ NodeSevCbitpos = "cbitpos"
+ // NodeSevReducedPhysBits as defined in libvirt/libvirt-host.h:473
+ NodeSevReducedPhysBits = "reduced-phys-bits"
+ // NodeSevMaxGuests as defined in libvirt/libvirt-host.h:481
+ NodeSevMaxGuests = "max-guests"
+ // NodeSevMaxEsGuests as defined in libvirt/libvirt-host.h:489
+ NodeSevMaxEsGuests = "max-es-guests"
+ // UUIDBuflen as defined in libvirt/libvirt-host.h:574
+ UUIDBuflen = 16
+ // UUIDStringBuflen as defined in libvirt/libvirt-host.h:583
+ UUIDStringBuflen = 37
+ // ConnectIdentityUserName as defined in libvirt/libvirt-host.h:608
+ ConnectIdentityUserName = "user-name"
+ // ConnectIdentityUnixUserID as defined in libvirt/libvirt-host.h:615
+ ConnectIdentityUnixUserID = "unix-user-id"
+ // ConnectIdentityGroupName as defined in libvirt/libvirt-host.h:622
+ ConnectIdentityGroupName = "group-name"
+ // ConnectIdentityUnixGroupID as defined in libvirt/libvirt-host.h:629
+ ConnectIdentityUnixGroupID = "unix-group-id"
+ // ConnectIdentityProcessID as defined in libvirt/libvirt-host.h:636
+ ConnectIdentityProcessID = "process-id"
+ // ConnectIdentityProcessTime as defined in libvirt/libvirt-host.h:647
+ ConnectIdentityProcessTime = "process-time"
+ // ConnectIdentitySaslUserName as defined in libvirt/libvirt-host.h:654
+ ConnectIdentitySaslUserName = "sasl-user-name"
+ // ConnectIdentityX509DistinguishedName as defined in libvirt/libvirt-host.h:661
+ ConnectIdentityX509DistinguishedName = "x509-distinguished-name"
+ // ConnectIdentitySelinuxContext as defined in libvirt/libvirt-host.h:668
+ ConnectIdentitySelinuxContext = "selinux-context"
+ // DomainSchedulerCPUShares as defined in libvirt/libvirt-domain.h:316
+ DomainSchedulerCPUShares = "cpu_shares"
+ // DomainSchedulerGlobalPeriod as defined in libvirt/libvirt-domain.h:324
+ DomainSchedulerGlobalPeriod = "global_period"
+ // DomainSchedulerGlobalQuota as defined in libvirt/libvirt-domain.h:332
+ DomainSchedulerGlobalQuota = "global_quota"
+ // DomainSchedulerVCPUPeriod as defined in libvirt/libvirt-domain.h:340
+ DomainSchedulerVCPUPeriod = "vcpu_period"
+ // DomainSchedulerVCPUQuota as defined in libvirt/libvirt-domain.h:348
+ DomainSchedulerVCPUQuota = "vcpu_quota"
+ // DomainSchedulerEmulatorPeriod as defined in libvirt/libvirt-domain.h:357
+ DomainSchedulerEmulatorPeriod = "emulator_period"
+ // DomainSchedulerEmulatorQuota as defined in libvirt/libvirt-domain.h:366
+ DomainSchedulerEmulatorQuota = "emulator_quota"
+ // DomainSchedulerIothreadPeriod as defined in libvirt/libvirt-domain.h:374
+ DomainSchedulerIothreadPeriod = "iothread_period"
+ // DomainSchedulerIothreadQuota as defined in libvirt/libvirt-domain.h:382
+ DomainSchedulerIothreadQuota = "iothread_quota"
+ // DomainSchedulerWeight as defined in libvirt/libvirt-domain.h:390
+ DomainSchedulerWeight = "weight"
+ // DomainSchedulerCap as defined in libvirt/libvirt-domain.h:398
+ DomainSchedulerCap = "cap"
+ // DomainSchedulerReservation as defined in libvirt/libvirt-domain.h:406
+ DomainSchedulerReservation = "reservation"
+ // DomainSchedulerLimit as defined in libvirt/libvirt-domain.h:414
+ DomainSchedulerLimit = "limit"
+ // DomainSchedulerShares as defined in libvirt/libvirt-domain.h:422
+ DomainSchedulerShares = "shares"
+ // DomainBlockStatsFieldLength as defined in libvirt/libvirt-domain.h:480
+ DomainBlockStatsFieldLength = 80
+ // DomainBlockStatsReadBytes as defined in libvirt/libvirt-domain.h:488
+ DomainBlockStatsReadBytes = "rd_bytes"
+ // DomainBlockStatsReadReq as defined in libvirt/libvirt-domain.h:496
+ DomainBlockStatsReadReq = "rd_operations"
+ // DomainBlockStatsReadTotalTimes as defined in libvirt/libvirt-domain.h:504
+ DomainBlockStatsReadTotalTimes = "rd_total_times"
+ // DomainBlockStatsWriteBytes as defined in libvirt/libvirt-domain.h:512
+ DomainBlockStatsWriteBytes = "wr_bytes"
+ // DomainBlockStatsWriteReq as defined in libvirt/libvirt-domain.h:520
+ DomainBlockStatsWriteReq = "wr_operations"
+ // DomainBlockStatsWriteTotalTimes as defined in libvirt/libvirt-domain.h:528
+ DomainBlockStatsWriteTotalTimes = "wr_total_times"
+ // DomainBlockStatsFlushReq as defined in libvirt/libvirt-domain.h:536
+ DomainBlockStatsFlushReq = "flush_operations"
+ // DomainBlockStatsFlushTotalTimes as defined in libvirt/libvirt-domain.h:544
+ DomainBlockStatsFlushTotalTimes = "flush_total_times"
+ // DomainBlockStatsErrs as defined in libvirt/libvirt-domain.h:551
+ DomainBlockStatsErrs = "errs"
+ // MigrateParamURI as defined in libvirt/libvirt-domain.h:879
+ MigrateParamURI = "migrate_uri"
+ // MigrateParamDestName as defined in libvirt/libvirt-domain.h:889
+ MigrateParamDestName = "destination_name"
+ // MigrateParamDestXML as defined in libvirt/libvirt-domain.h:908
+ MigrateParamDestXML = "destination_xml"
+ // MigrateParamPersistXML as defined in libvirt/libvirt-domain.h:923
+ MigrateParamPersistXML = "persistent_xml"
+ // MigrateParamBandwidth as defined in libvirt/libvirt-domain.h:933
+ MigrateParamBandwidth = "bandwidth"
+ // MigrateParamBandwidthPostcopy as defined in libvirt/libvirt-domain.h:942
+ MigrateParamBandwidthPostcopy = "bandwidth.postcopy"
+ // MigrateParamGraphicsURI as defined in libvirt/libvirt-domain.h:963
+ MigrateParamGraphicsURI = "graphics_uri"
+ // MigrateParamListenAddress as defined in libvirt/libvirt-domain.h:974
+ MigrateParamListenAddress = "listen_address"
+ // MigrateParamMigrateDisks as defined in libvirt/libvirt-domain.h:983
+ MigrateParamMigrateDisks = "migrate_disks"
+ // MigrateParamDisksPort as defined in libvirt/libvirt-domain.h:993
+ MigrateParamDisksPort = "disks_port"
+ // MigrateParamDisksURI as defined in libvirt/libvirt-domain.h:1006
+ MigrateParamDisksURI = "disks_uri"
+ // MigrateParamCompression as defined in libvirt/libvirt-domain.h:1016
+ MigrateParamCompression = "compression"
+ // MigrateParamCompressionMtLevel as defined in libvirt/libvirt-domain.h:1025
+ MigrateParamCompressionMtLevel = "compression.mt.level"
+ // MigrateParamCompressionMtThreads as defined in libvirt/libvirt-domain.h:1033
+ MigrateParamCompressionMtThreads = "compression.mt.threads"
+ // MigrateParamCompressionMtDthreads as defined in libvirt/libvirt-domain.h:1041
+ MigrateParamCompressionMtDthreads = "compression.mt.dthreads"
+ // MigrateParamCompressionXbzrleCache as defined in libvirt/libvirt-domain.h:1049
+ MigrateParamCompressionXbzrleCache = "compression.xbzrle.cache"
+ // MigrateParamAutoConvergeInitial as defined in libvirt/libvirt-domain.h:1058
+ MigrateParamAutoConvergeInitial = "auto_converge.initial"
+ // MigrateParamAutoConvergeIncrement as defined in libvirt/libvirt-domain.h:1068
+ MigrateParamAutoConvergeIncrement = "auto_converge.increment"
+ // MigrateParamParallelConnections as defined in libvirt/libvirt-domain.h:1076
+ MigrateParamParallelConnections = "parallel.connections"
+ // MigrateParamTLSDestination as defined in libvirt/libvirt-domain.h:1090
+ MigrateParamTLSDestination = "tls.destination"
+ // DomainCPUStatsCputime as defined in libvirt/libvirt-domain.h:1350
+ DomainCPUStatsCputime = "cpu_time"
+ // DomainCPUStatsUsertime as defined in libvirt/libvirt-domain.h:1356
+ DomainCPUStatsUsertime = "user_time"
+ // DomainCPUStatsSystemtime as defined in libvirt/libvirt-domain.h:1362
+ DomainCPUStatsSystemtime = "system_time"
+ // DomainCPUStatsVcputime as defined in libvirt/libvirt-domain.h:1369
+ DomainCPUStatsVcputime = "vcpu_time"
+ // DomainBlkioWeight as defined in libvirt/libvirt-domain.h:1398
+ DomainBlkioWeight = "weight"
+ // DomainBlkioDeviceWeight as defined in libvirt/libvirt-domain.h:1408
+ DomainBlkioDeviceWeight = "device_weight"
+ // DomainBlkioDeviceReadIops as defined in libvirt/libvirt-domain.h:1419
+ DomainBlkioDeviceReadIops = "device_read_iops_sec"
+ // DomainBlkioDeviceWriteIops as defined in libvirt/libvirt-domain.h:1430
+ DomainBlkioDeviceWriteIops = "device_write_iops_sec"
+ // DomainBlkioDeviceReadBps as defined in libvirt/libvirt-domain.h:1441
+ DomainBlkioDeviceReadBps = "device_read_bytes_sec"
+ // DomainBlkioDeviceWriteBps as defined in libvirt/libvirt-domain.h:1452
+ DomainBlkioDeviceWriteBps = "device_write_bytes_sec"
+ // DomainMemoryParamUnlimited as defined in libvirt/libvirt-domain.h:1471
+ DomainMemoryParamUnlimited = 9007199254740991
+ // DomainMemoryHardLimit as defined in libvirt/libvirt-domain.h:1480
+ DomainMemoryHardLimit = "hard_limit"
+ // DomainMemorySoftLimit as defined in libvirt/libvirt-domain.h:1489
+ DomainMemorySoftLimit = "soft_limit"
+ // DomainMemoryMinGuarantee as defined in libvirt/libvirt-domain.h:1498
+ DomainMemoryMinGuarantee = "min_guarantee"
+ // DomainMemorySwapHardLimit as defined in libvirt/libvirt-domain.h:1508
+ DomainMemorySwapHardLimit = "swap_hard_limit"
+ // DomainNumaNodeset as defined in libvirt/libvirt-domain.h:1554
+ DomainNumaNodeset = "numa_nodeset"
+ // DomainNumaMode as defined in libvirt/libvirt-domain.h:1562
+ DomainNumaMode = "numa_mode"
+ // DomainBandwidthInAverage as defined in libvirt/libvirt-domain.h:1684
+ DomainBandwidthInAverage = "inbound.average"
+ // DomainBandwidthInPeak as defined in libvirt/libvirt-domain.h:1691
+ DomainBandwidthInPeak = "inbound.peak"
+ // DomainBandwidthInBurst as defined in libvirt/libvirt-domain.h:1698
+ DomainBandwidthInBurst = "inbound.burst"
+ // DomainBandwidthInFloor as defined in libvirt/libvirt-domain.h:1705
+ DomainBandwidthInFloor = "inbound.floor"
+ // DomainBandwidthOutAverage as defined in libvirt/libvirt-domain.h:1712
+ DomainBandwidthOutAverage = "outbound.average"
+ // DomainBandwidthOutPeak as defined in libvirt/libvirt-domain.h:1719
+ DomainBandwidthOutPeak = "outbound.peak"
+ // DomainBandwidthOutBurst as defined in libvirt/libvirt-domain.h:1726
+ DomainBandwidthOutBurst = "outbound.burst"
+ // DomainIothreadPollMaxNs as defined in libvirt/libvirt-domain.h:2031
+ DomainIothreadPollMaxNs = "poll_max_ns"
+ // DomainIothreadPollGrow as defined in libvirt/libvirt-domain.h:2041
+ DomainIothreadPollGrow = "poll_grow"
+ // DomainIothreadPollShrink as defined in libvirt/libvirt-domain.h:2052
+ DomainIothreadPollShrink = "poll_shrink"
+ // PerfParamCmt as defined in libvirt/libvirt-domain.h:2245
+ PerfParamCmt = "cmt"
+ // PerfParamMbmt as defined in libvirt/libvirt-domain.h:2256
+ PerfParamMbmt = "mbmt"
+ // PerfParamMbml as defined in libvirt/libvirt-domain.h:2266
+ PerfParamMbml = "mbml"
+ // PerfParamCacheMisses as defined in libvirt/libvirt-domain.h:2276
+ PerfParamCacheMisses = "cache_misses"
+ // PerfParamCacheReferences as defined in libvirt/libvirt-domain.h:2286
+ PerfParamCacheReferences = "cache_references"
+ // PerfParamInstructions as defined in libvirt/libvirt-domain.h:2296
+ PerfParamInstructions = "instructions"
+ // PerfParamCPUCycles as defined in libvirt/libvirt-domain.h:2306
+ PerfParamCPUCycles = "cpu_cycles"
+ // PerfParamBranchInstructions as defined in libvirt/libvirt-domain.h:2316
+ PerfParamBranchInstructions = "branch_instructions"
+ // PerfParamBranchMisses as defined in libvirt/libvirt-domain.h:2326
+ PerfParamBranchMisses = "branch_misses"
+ // PerfParamBusCycles as defined in libvirt/libvirt-domain.h:2336
+ PerfParamBusCycles = "bus_cycles"
+ // PerfParamStalledCyclesFrontend as defined in libvirt/libvirt-domain.h:2347
+ PerfParamStalledCyclesFrontend = "stalled_cycles_frontend"
+ // PerfParamStalledCyclesBackend as defined in libvirt/libvirt-domain.h:2358
+ PerfParamStalledCyclesBackend = "stalled_cycles_backend"
+ // PerfParamRefCPUCycles as defined in libvirt/libvirt-domain.h:2369
+ PerfParamRefCPUCycles = "ref_cpu_cycles"
+ // PerfParamCPUClock as defined in libvirt/libvirt-domain.h:2380
+ PerfParamCPUClock = "cpu_clock"
+ // PerfParamTaskClock as defined in libvirt/libvirt-domain.h:2391
+ PerfParamTaskClock = "task_clock"
+ // PerfParamPageFaults as defined in libvirt/libvirt-domain.h:2401
+ PerfParamPageFaults = "page_faults"
+ // PerfParamContextSwitches as defined in libvirt/libvirt-domain.h:2411
+ PerfParamContextSwitches = "context_switches"
+ // PerfParamCPUMigrations as defined in libvirt/libvirt-domain.h:2421
+ PerfParamCPUMigrations = "cpu_migrations"
+ // PerfParamPageFaultsMin as defined in libvirt/libvirt-domain.h:2431
+ PerfParamPageFaultsMin = "page_faults_min"
+ // PerfParamPageFaultsMaj as defined in libvirt/libvirt-domain.h:2441
+ PerfParamPageFaultsMaj = "page_faults_maj"
+ // PerfParamAlignmentFaults as defined in libvirt/libvirt-domain.h:2451
+ PerfParamAlignmentFaults = "alignment_faults"
+ // PerfParamEmulationFaults as defined in libvirt/libvirt-domain.h:2461
+ PerfParamEmulationFaults = "emulation_faults"
+ // DomainBlockCopyBandwidth as defined in libvirt/libvirt-domain.h:2634
+ DomainBlockCopyBandwidth = "bandwidth"
+ // DomainBlockCopyGranularity as defined in libvirt/libvirt-domain.h:2645
+ DomainBlockCopyGranularity = "granularity"
+ // DomainBlockCopyBufSize as defined in libvirt/libvirt-domain.h:2654
+ DomainBlockCopyBufSize = "buf-size"
+ // DomainBlockIotuneTotalBytesSec as defined in libvirt/libvirt-domain.h:2695
+ DomainBlockIotuneTotalBytesSec = "total_bytes_sec"
+ // DomainBlockIotuneReadBytesSec as defined in libvirt/libvirt-domain.h:2703
+ DomainBlockIotuneReadBytesSec = "read_bytes_sec"
+ // DomainBlockIotuneWriteBytesSec as defined in libvirt/libvirt-domain.h:2711
+ DomainBlockIotuneWriteBytesSec = "write_bytes_sec"
+ // DomainBlockIotuneTotalIopsSec as defined in libvirt/libvirt-domain.h:2719
+ DomainBlockIotuneTotalIopsSec = "total_iops_sec"
+ // DomainBlockIotuneReadIopsSec as defined in libvirt/libvirt-domain.h:2727
+ DomainBlockIotuneReadIopsSec = "read_iops_sec"
+ // DomainBlockIotuneWriteIopsSec as defined in libvirt/libvirt-domain.h:2734
+ DomainBlockIotuneWriteIopsSec = "write_iops_sec"
+ // DomainBlockIotuneTotalBytesSecMax as defined in libvirt/libvirt-domain.h:2742
+ DomainBlockIotuneTotalBytesSecMax = "total_bytes_sec_max"
+ // DomainBlockIotuneReadBytesSecMax as defined in libvirt/libvirt-domain.h:2750
+ DomainBlockIotuneReadBytesSecMax = "read_bytes_sec_max"
+ // DomainBlockIotuneWriteBytesSecMax as defined in libvirt/libvirt-domain.h:2758
+ DomainBlockIotuneWriteBytesSecMax = "write_bytes_sec_max"
+ // DomainBlockIotuneTotalIopsSecMax as defined in libvirt/libvirt-domain.h:2766
+ DomainBlockIotuneTotalIopsSecMax = "total_iops_sec_max"
+ // DomainBlockIotuneReadIopsSecMax as defined in libvirt/libvirt-domain.h:2774
+ DomainBlockIotuneReadIopsSecMax = "read_iops_sec_max"
+ // DomainBlockIotuneWriteIopsSecMax as defined in libvirt/libvirt-domain.h:2781
+ DomainBlockIotuneWriteIopsSecMax = "write_iops_sec_max"
+ // DomainBlockIotuneTotalBytesSecMaxLength as defined in libvirt/libvirt-domain.h:2789
+ DomainBlockIotuneTotalBytesSecMaxLength = "total_bytes_sec_max_length"
+ // DomainBlockIotuneReadBytesSecMaxLength as defined in libvirt/libvirt-domain.h:2797
+ DomainBlockIotuneReadBytesSecMaxLength = "read_bytes_sec_max_length"
+ // DomainBlockIotuneWriteBytesSecMaxLength as defined in libvirt/libvirt-domain.h:2805
+ DomainBlockIotuneWriteBytesSecMaxLength = "write_bytes_sec_max_length"
+ // DomainBlockIotuneTotalIopsSecMaxLength as defined in libvirt/libvirt-domain.h:2813
+ DomainBlockIotuneTotalIopsSecMaxLength = "total_iops_sec_max_length"
+ // DomainBlockIotuneReadIopsSecMaxLength as defined in libvirt/libvirt-domain.h:2821
+ DomainBlockIotuneReadIopsSecMaxLength = "read_iops_sec_max_length"
+ // DomainBlockIotuneWriteIopsSecMaxLength as defined in libvirt/libvirt-domain.h:2829
+ DomainBlockIotuneWriteIopsSecMaxLength = "write_iops_sec_max_length"
+ // DomainBlockIotuneSizeIopsSec as defined in libvirt/libvirt-domain.h:2836
+ DomainBlockIotuneSizeIopsSec = "size_iops_sec"
+ // DomainBlockIotuneGroupName as defined in libvirt/libvirt-domain.h:2843
+ DomainBlockIotuneGroupName = "group_name"
+ // KeycodeSetRfb as defined in libvirt/libvirt-domain.h:2924
+ KeycodeSetRfb = 0
+ // DomainSendKeyMaxKeys as defined in libvirt/libvirt-domain.h:2931
+ DomainSendKeyMaxKeys = 16
+ // DomainJobOperationStr as defined in libvirt/libvirt-domain.h:3405
+ DomainJobOperationStr = "operation"
+ // DomainJobTimeElapsed as defined in libvirt/libvirt-domain.h:3415
+ DomainJobTimeElapsed = "time_elapsed"
+ // DomainJobTimeElapsedNet as defined in libvirt/libvirt-domain.h:3425
+ DomainJobTimeElapsedNet = "time_elapsed_net"
+ // DomainJobTimeRemaining as defined in libvirt/libvirt-domain.h:3435
+ DomainJobTimeRemaining = "time_remaining"
+ // DomainJobDowntime as defined in libvirt/libvirt-domain.h:3445
+ DomainJobDowntime = "downtime"
+ // DomainJobDowntimeNet as defined in libvirt/libvirt-domain.h:3454
+ DomainJobDowntimeNet = "downtime_net"
+ // DomainJobSetupTime as defined in libvirt/libvirt-domain.h:3463
+ DomainJobSetupTime = "setup_time"
+ // DomainJobDataTotal as defined in libvirt/libvirt-domain.h:3478
+ DomainJobDataTotal = "data_total"
+ // DomainJobDataProcessed as defined in libvirt/libvirt-domain.h:3488
+ DomainJobDataProcessed = "data_processed"
+ // DomainJobDataRemaining as defined in libvirt/libvirt-domain.h:3498
+ DomainJobDataRemaining = "data_remaining"
+ // DomainJobMemoryTotal as defined in libvirt/libvirt-domain.h:3508
+ DomainJobMemoryTotal = "memory_total"
+ // DomainJobMemoryProcessed as defined in libvirt/libvirt-domain.h:3518
+ DomainJobMemoryProcessed = "memory_processed"
+ // DomainJobMemoryRemaining as defined in libvirt/libvirt-domain.h:3528
+ DomainJobMemoryRemaining = "memory_remaining"
+ // DomainJobMemoryConstant as defined in libvirt/libvirt-domain.h:3540
+ DomainJobMemoryConstant = "memory_constant"
+ // DomainJobMemoryNormal as defined in libvirt/libvirt-domain.h:3550
+ DomainJobMemoryNormal = "memory_normal"
+ // DomainJobMemoryNormalBytes as defined in libvirt/libvirt-domain.h:3560
+ DomainJobMemoryNormalBytes = "memory_normal_bytes"
+ // DomainJobMemoryBps as defined in libvirt/libvirt-domain.h:3568
+ DomainJobMemoryBps = "memory_bps"
+ // DomainJobMemoryDirtyRate as defined in libvirt/libvirt-domain.h:3576
+ DomainJobMemoryDirtyRate = "memory_dirty_rate"
+ // DomainJobMemoryPageSize as defined in libvirt/libvirt-domain.h:3587
+ DomainJobMemoryPageSize = "memory_page_size"
+ // DomainJobMemoryIteration as defined in libvirt/libvirt-domain.h:3598
+ DomainJobMemoryIteration = "memory_iteration"
+ // DomainJobMemoryPostcopyReqs as defined in libvirt/libvirt-domain.h:3608
+ DomainJobMemoryPostcopyReqs = "memory_postcopy_requests"
+ // DomainJobDiskTotal as defined in libvirt/libvirt-domain.h:3618
+ DomainJobDiskTotal = "disk_total"
+ // DomainJobDiskProcessed as defined in libvirt/libvirt-domain.h:3628
+ DomainJobDiskProcessed = "disk_processed"
+ // DomainJobDiskRemaining as defined in libvirt/libvirt-domain.h:3638
+ DomainJobDiskRemaining = "disk_remaining"
+ // DomainJobDiskBps as defined in libvirt/libvirt-domain.h:3646
+ DomainJobDiskBps = "disk_bps"
+ // DomainJobCompressionCache as defined in libvirt/libvirt-domain.h:3655
+ DomainJobCompressionCache = "compression_cache"
+ // DomainJobCompressionBytes as defined in libvirt/libvirt-domain.h:3663
+ DomainJobCompressionBytes = "compression_bytes"
+ // DomainJobCompressionPages as defined in libvirt/libvirt-domain.h:3671
+ DomainJobCompressionPages = "compression_pages"
+ // DomainJobCompressionCacheMisses as defined in libvirt/libvirt-domain.h:3680
+ DomainJobCompressionCacheMisses = "compression_cache_misses"
+ // DomainJobCompressionOverflow as defined in libvirt/libvirt-domain.h:3690
+ DomainJobCompressionOverflow = "compression_overflow"
+ // DomainJobAutoConvergeThrottle as defined in libvirt/libvirt-domain.h:3699
+ DomainJobAutoConvergeThrottle = "auto_converge_throttle"
+ // DomainJobSuccess as defined in libvirt/libvirt-domain.h:3707
+ DomainJobSuccess = "success"
+ // DomainJobErrmsg as defined in libvirt/libvirt-domain.h:3715
+ DomainJobErrmsg = "errmsg"
+ // DomainJobDiskTempUsed as defined in libvirt/libvirt-domain.h:3723
+ DomainJobDiskTempUsed = "disk_temp_used"
+ // DomainJobDiskTempTotal as defined in libvirt/libvirt-domain.h:3730
+ DomainJobDiskTempTotal = "disk_temp_total"
+ // DomainTunableCPUVcpupin as defined in libvirt/libvirt-domain.h:4285
+ DomainTunableCPUVcpupin = "cputune.vcpupin%u"
+ // DomainTunableCPUEmulatorpin as defined in libvirt/libvirt-domain.h:4293
+ DomainTunableCPUEmulatorpin = "cputune.emulatorpin"
+ // DomainTunableCPUIothreadspin as defined in libvirt/libvirt-domain.h:4302
+ DomainTunableCPUIothreadspin = "cputune.iothreadpin%u"
+ // DomainTunableCPUCpuShares as defined in libvirt/libvirt-domain.h:4310
+ DomainTunableCPUCpuShares = "cputune.cpu_shares"
+ // DomainTunableCPUGlobalPeriod as defined in libvirt/libvirt-domain.h:4318
+ DomainTunableCPUGlobalPeriod = "cputune.global_period"
+ // DomainTunableCPUGlobalQuota as defined in libvirt/libvirt-domain.h:4326
+ DomainTunableCPUGlobalQuota = "cputune.global_quota"
+ // DomainTunableCPUVCPUPeriod as defined in libvirt/libvirt-domain.h:4334
+ DomainTunableCPUVCPUPeriod = "cputune.vcpu_period"
+ // DomainTunableCPUVCPUQuota as defined in libvirt/libvirt-domain.h:4342
+ DomainTunableCPUVCPUQuota = "cputune.vcpu_quota"
+ // DomainTunableCPUEmulatorPeriod as defined in libvirt/libvirt-domain.h:4351
+ DomainTunableCPUEmulatorPeriod = "cputune.emulator_period"
+ // DomainTunableCPUEmulatorQuota as defined in libvirt/libvirt-domain.h:4360
+ DomainTunableCPUEmulatorQuota = "cputune.emulator_quota"
+ // DomainTunableCPUIothreadPeriod as defined in libvirt/libvirt-domain.h:4368
+ DomainTunableCPUIothreadPeriod = "cputune.iothread_period"
+ // DomainTunableCPUIothreadQuota as defined in libvirt/libvirt-domain.h:4376
+ DomainTunableCPUIothreadQuota = "cputune.iothread_quota"
+ // DomainTunableBlkdevDisk as defined in libvirt/libvirt-domain.h:4384
+ DomainTunableBlkdevDisk = "blkdeviotune.disk"
+ // DomainTunableBlkdevTotalBytesSec as defined in libvirt/libvirt-domain.h:4392
+ DomainTunableBlkdevTotalBytesSec = "blkdeviotune.total_bytes_sec"
+ // DomainTunableBlkdevReadBytesSec as defined in libvirt/libvirt-domain.h:4400
+ DomainTunableBlkdevReadBytesSec = "blkdeviotune.read_bytes_sec"
+ // DomainTunableBlkdevWriteBytesSec as defined in libvirt/libvirt-domain.h:4408
+ DomainTunableBlkdevWriteBytesSec = "blkdeviotune.write_bytes_sec"
+ // DomainTunableBlkdevTotalIopsSec as defined in libvirt/libvirt-domain.h:4416
+ DomainTunableBlkdevTotalIopsSec = "blkdeviotune.total_iops_sec"
+ // DomainTunableBlkdevReadIopsSec as defined in libvirt/libvirt-domain.h:4424
+ DomainTunableBlkdevReadIopsSec = "blkdeviotune.read_iops_sec"
+ // DomainTunableBlkdevWriteIopsSec as defined in libvirt/libvirt-domain.h:4432
+ DomainTunableBlkdevWriteIopsSec = "blkdeviotune.write_iops_sec"
+ // DomainTunableBlkdevTotalBytesSecMax as defined in libvirt/libvirt-domain.h:4440
+ DomainTunableBlkdevTotalBytesSecMax = "blkdeviotune.total_bytes_sec_max"
+ // DomainTunableBlkdevReadBytesSecMax as defined in libvirt/libvirt-domain.h:4448
+ DomainTunableBlkdevReadBytesSecMax = "blkdeviotune.read_bytes_sec_max"
+ // DomainTunableBlkdevWriteBytesSecMax as defined in libvirt/libvirt-domain.h:4456
+ DomainTunableBlkdevWriteBytesSecMax = "blkdeviotune.write_bytes_sec_max"
+ // DomainTunableBlkdevTotalIopsSecMax as defined in libvirt/libvirt-domain.h:4464
+ DomainTunableBlkdevTotalIopsSecMax = "blkdeviotune.total_iops_sec_max"
+ // DomainTunableBlkdevReadIopsSecMax as defined in libvirt/libvirt-domain.h:4472
+ DomainTunableBlkdevReadIopsSecMax = "blkdeviotune.read_iops_sec_max"
+ // DomainTunableBlkdevWriteIopsSecMax as defined in libvirt/libvirt-domain.h:4480
+ DomainTunableBlkdevWriteIopsSecMax = "blkdeviotune.write_iops_sec_max"
+ // DomainTunableBlkdevSizeIopsSec as defined in libvirt/libvirt-domain.h:4488
+ DomainTunableBlkdevSizeIopsSec = "blkdeviotune.size_iops_sec"
+ // DomainTunableBlkdevGroupName as defined in libvirt/libvirt-domain.h:4496
+ DomainTunableBlkdevGroupName = "blkdeviotune.group_name"
+ // DomainTunableBlkdevTotalBytesSecMaxLength as defined in libvirt/libvirt-domain.h:4505
+ DomainTunableBlkdevTotalBytesSecMaxLength = "blkdeviotune.total_bytes_sec_max_length"
+ // DomainTunableBlkdevReadBytesSecMaxLength as defined in libvirt/libvirt-domain.h:4514
+ DomainTunableBlkdevReadBytesSecMaxLength = "blkdeviotune.read_bytes_sec_max_length"
+ // DomainTunableBlkdevWriteBytesSecMaxLength as defined in libvirt/libvirt-domain.h:4523
+ DomainTunableBlkdevWriteBytesSecMaxLength = "blkdeviotune.write_bytes_sec_max_length"
+ // DomainTunableBlkdevTotalIopsSecMaxLength as defined in libvirt/libvirt-domain.h:4532
+ DomainTunableBlkdevTotalIopsSecMaxLength = "blkdeviotune.total_iops_sec_max_length"
+ // DomainTunableBlkdevReadIopsSecMaxLength as defined in libvirt/libvirt-domain.h:4541
+ DomainTunableBlkdevReadIopsSecMaxLength = "blkdeviotune.read_iops_sec_max_length"
+ // DomainTunableBlkdevWriteIopsSecMaxLength as defined in libvirt/libvirt-domain.h:4550
+ DomainTunableBlkdevWriteIopsSecMaxLength = "blkdeviotune.write_iops_sec_max_length"
+ // DomainSchedFieldLength as defined in libvirt/libvirt-domain.h:4888
+ DomainSchedFieldLength = 80
+ // DomainBlkioFieldLength as defined in libvirt/libvirt-domain.h:4932
+ DomainBlkioFieldLength = 80
+ // DomainMemoryFieldLength as defined in libvirt/libvirt-domain.h:4976
+ DomainMemoryFieldLength = 80
+ // DomainLaunchSecuritySevMeasurement as defined in libvirt/libvirt-domain.h:5102
+ DomainLaunchSecuritySevMeasurement = "sev-measurement"
+ // DomainLaunchSecuritySevAPIMajor as defined in libvirt/libvirt-domain.h:5111
+ DomainLaunchSecuritySevAPIMajor = "sev-api-major"
+ // DomainLaunchSecuritySevAPIMinor as defined in libvirt/libvirt-domain.h:5119
+ DomainLaunchSecuritySevAPIMinor = "sev-api-minor"
+ // DomainLaunchSecuritySevBuildID as defined in libvirt/libvirt-domain.h:5127
+ DomainLaunchSecuritySevBuildID = "sev-build-id"
+ // DomainLaunchSecuritySevPolicy as defined in libvirt/libvirt-domain.h:5135
+ DomainLaunchSecuritySevPolicy = "sev-policy"
+ // DomainLaunchSecuritySevSecretHeader as defined in libvirt/libvirt-domain.h:5146
+ DomainLaunchSecuritySevSecretHeader = "sev-secret-header"
+ // DomainLaunchSecuritySevSecret as defined in libvirt/libvirt-domain.h:5156
+ DomainLaunchSecuritySevSecret = "sev-secret"
+ // DomainLaunchSecuritySevSecretSetAddress as defined in libvirt/libvirt-domain.h:5165
+ DomainLaunchSecuritySevSecretSetAddress = "sev-secret-set-address"
+ // NetworkPortBandwidthInAverage as defined in libvirt/libvirt-network.h:406
+ NetworkPortBandwidthInAverage = "inbound.average"
+ // NetworkPortBandwidthInPeak as defined in libvirt/libvirt-network.h:413
+ NetworkPortBandwidthInPeak = "inbound.peak"
+ // NetworkPortBandwidthInBurst as defined in libvirt/libvirt-network.h:420
+ NetworkPortBandwidthInBurst = "inbound.burst"
+ // NetworkPortBandwidthInFloor as defined in libvirt/libvirt-network.h:427
+ NetworkPortBandwidthInFloor = "inbound.floor"
+ // NetworkPortBandwidthOutAverage as defined in libvirt/libvirt-network.h:434
+ NetworkPortBandwidthOutAverage = "outbound.average"
+ // NetworkPortBandwidthOutPeak as defined in libvirt/libvirt-network.h:441
+ NetworkPortBandwidthOutPeak = "outbound.peak"
+ // NetworkPortBandwidthOutBurst as defined in libvirt/libvirt-network.h:448
+ NetworkPortBandwidthOutBurst = "outbound.burst"
+)
+
+// ConnectCloseReason as declared in libvirt/libvirt-common.h:119
+type ConnectCloseReason int32
+
+// ConnectCloseReason enumeration from libvirt/libvirt-common.h:119
+const (
+ ConnectCloseReasonError ConnectCloseReason = iota
+ ConnectCloseReasonEOF ConnectCloseReason = 1
+ ConnectCloseReasonKeepalive ConnectCloseReason = 2
+ ConnectCloseReasonClient ConnectCloseReason = 3
+)
+
+// TypedParameterType as declared in libvirt/libvirt-common.h:138
+type TypedParameterType int32
+
+// TypedParameterType enumeration from libvirt/libvirt-common.h:138
+const (
+ TypedParamInt TypedParameterType = 1
+ TypedParamUint TypedParameterType = 2
+ TypedParamLlong TypedParameterType = 3
+ TypedParamUllong TypedParameterType = 4
+ TypedParamDouble TypedParameterType = 5
+ TypedParamBoolean TypedParameterType = 6
+ TypedParamString TypedParameterType = 7
+)
+
+// TypedParameterFlags as declared in libvirt/libvirt-common.h:163
+type TypedParameterFlags int32
+
+// TypedParameterFlags enumeration from libvirt/libvirt-common.h:163
+const (
+ TypedParamStringOkay TypedParameterFlags = 4
+)
+
+// NodeSuspendTarget as declared in libvirt/libvirt-host.h:61
+type NodeSuspendTarget int32
+
+// NodeSuspendTarget enumeration from libvirt/libvirt-host.h:61
+const (
+ NodeSuspendTargetMem NodeSuspendTarget = iota
+ NodeSuspendTargetDisk NodeSuspendTarget = 1
+ NodeSuspendTargetHybrid NodeSuspendTarget = 2
+)
+
+// NodeGetCPUStatsAllCPUs as declared in libvirt/libvirt-host.h:189
+type NodeGetCPUStatsAllCPUs int32
+
+// NodeGetCPUStatsAllCPUs enumeration from libvirt/libvirt-host.h:189
+const (
+ NodeCPUStatsAllCpus NodeGetCPUStatsAllCPUs = -1
+)
+
+// NodeGetMemoryStatsAllCells as declared in libvirt/libvirt-host.h:267
+type NodeGetMemoryStatsAllCells int32
+
+// NodeGetMemoryStatsAllCells enumeration from libvirt/libvirt-host.h:267
+const (
+ NodeMemoryStatsAllCells NodeGetMemoryStatsAllCells = -1
+)
+
+// ConnectFlags as declared in libvirt/libvirt-host.h:504
+type ConnectFlags int32
+
+// ConnectFlags enumeration from libvirt/libvirt-host.h:504
+const (
+ ConnectRo ConnectFlags = 1
+ ConnectNoAliases ConnectFlags = 2
+)
+
+// ConnectCredentialType as declared in libvirt/libvirt-host.h:521
+type ConnectCredentialType int32
+
+// ConnectCredentialType enumeration from libvirt/libvirt-host.h:521
+const (
+ CredUsername ConnectCredentialType = 1
+ CredAuthname ConnectCredentialType = 2
+ CredLanguage ConnectCredentialType = 3
+ CredCnonce ConnectCredentialType = 4
+ CredPassphrase ConnectCredentialType = 5
+ CredEchoprompt ConnectCredentialType = 6
+ CredNoechoprompt ConnectCredentialType = 7
+ CredRealm ConnectCredentialType = 8
+ CredExternal ConnectCredentialType = 9
+)
+
+// CPUCompareResult as declared in libvirt/libvirt-host.h:768
+type CPUCompareResult int32
+
+// CPUCompareResult enumeration from libvirt/libvirt-host.h:768
+const (
+ CPUCompareError CPUCompareResult = -1
+ CPUCompareIncompatible CPUCompareResult = 0
+ CPUCompareIdentical CPUCompareResult = 1
+ CPUCompareSuperset CPUCompareResult = 2
+)
+
+// ConnectCompareCPUFlags as declared in libvirt/libvirt-host.h:775
+type ConnectCompareCPUFlags int32
+
+// ConnectCompareCPUFlags enumeration from libvirt/libvirt-host.h:775
+const (
+ ConnectCompareCPUFailIncompatible ConnectCompareCPUFlags = 1
+ ConnectCompareCPUValidateXML ConnectCompareCPUFlags = 2
+)
+
+// ConnectBaselineCPUFlags as declared in libvirt/libvirt-host.h:801
+type ConnectBaselineCPUFlags int32
+
+// ConnectBaselineCPUFlags enumeration from libvirt/libvirt-host.h:801
+const (
+ ConnectBaselineCPUExpandFeatures ConnectBaselineCPUFlags = 1
+ ConnectBaselineCPUMigratable ConnectBaselineCPUFlags = 2
+)
+
+// NodeAllocPagesFlags as declared in libvirt/libvirt-host.h:831
+type NodeAllocPagesFlags int32
+
+// NodeAllocPagesFlags enumeration from libvirt/libvirt-host.h:831
+const (
+ NodeAllocPagesAdd NodeAllocPagesFlags = iota
+ NodeAllocPagesSet NodeAllocPagesFlags = 1
+)
+
+// DomainState as declared in libvirt/libvirt-domain.h:70
+type DomainState int32
+
+// DomainState enumeration from libvirt/libvirt-domain.h:70
+const (
+ DomainNostate DomainState = iota
+ DomainRunning DomainState = 1
+ DomainBlocked DomainState = 2
+ DomainPaused DomainState = 3
+ DomainShutdown DomainState = 4
+ DomainShutoff DomainState = 5
+ DomainCrashed DomainState = 6
+ DomainPmsuspended DomainState = 7
+)
+
+// DomainNostateReason as declared in libvirt/libvirt-domain.h:78
+type DomainNostateReason int32
+
+// DomainNostateReason enumeration from libvirt/libvirt-domain.h:78
+const (
+ DomainNostateUnknown DomainNostateReason = iota
+)
+
+// DomainRunningReason as declared in libvirt/libvirt-domain.h:97
+type DomainRunningReason int32
+
+// DomainRunningReason enumeration from libvirt/libvirt-domain.h:97
+const (
+ DomainRunningUnknown DomainRunningReason = iota
+ DomainRunningBooted DomainRunningReason = 1
+ DomainRunningMigrated DomainRunningReason = 2
+ DomainRunningRestored DomainRunningReason = 3
+ DomainRunningFromSnapshot DomainRunningReason = 4
+ DomainRunningUnpaused DomainRunningReason = 5
+ DomainRunningMigrationCanceled DomainRunningReason = 6
+ DomainRunningSaveCanceled DomainRunningReason = 7
+ DomainRunningWakeup DomainRunningReason = 8
+ DomainRunningCrashed DomainRunningReason = 9
+ DomainRunningPostcopy DomainRunningReason = 10
+)
+
+// DomainBlockedReason as declared in libvirt/libvirt-domain.h:105
+type DomainBlockedReason int32
+
+// DomainBlockedReason enumeration from libvirt/libvirt-domain.h:105
+const (
+ DomainBlockedUnknown DomainBlockedReason = iota
+)
+
+// DomainPausedReason as declared in libvirt/libvirt-domain.h:126
+type DomainPausedReason int32
+
+// DomainPausedReason enumeration from libvirt/libvirt-domain.h:126
+const (
+ DomainPausedUnknown DomainPausedReason = iota
+ DomainPausedUser DomainPausedReason = 1
+ DomainPausedMigration DomainPausedReason = 2
+ DomainPausedSave DomainPausedReason = 3
+ DomainPausedDump DomainPausedReason = 4
+ DomainPausedIoerror DomainPausedReason = 5
+ DomainPausedWatchdog DomainPausedReason = 6
+ DomainPausedFromSnapshot DomainPausedReason = 7
+ DomainPausedShuttingDown DomainPausedReason = 8
+ DomainPausedSnapshot DomainPausedReason = 9
+ DomainPausedCrashed DomainPausedReason = 10
+ DomainPausedStartingUp DomainPausedReason = 11
+ DomainPausedPostcopy DomainPausedReason = 12
+ DomainPausedPostcopyFailed DomainPausedReason = 13
+)
+
+// DomainShutdownReason as declared in libvirt/libvirt-domain.h:135
+type DomainShutdownReason int32
+
+// DomainShutdownReason enumeration from libvirt/libvirt-domain.h:135
+const (
+ DomainShutdownUnknown DomainShutdownReason = iota
+ DomainShutdownUser DomainShutdownReason = 1
+)
+
+// DomainShutoffReason as declared in libvirt/libvirt-domain.h:152
+type DomainShutoffReason int32
+
+// DomainShutoffReason enumeration from libvirt/libvirt-domain.h:152
+const (
+ DomainShutoffUnknown DomainShutoffReason = iota
+ DomainShutoffShutdown DomainShutoffReason = 1
+ DomainShutoffDestroyed DomainShutoffReason = 2
+ DomainShutoffCrashed DomainShutoffReason = 3
+ DomainShutoffMigrated DomainShutoffReason = 4
+ DomainShutoffSaved DomainShutoffReason = 5
+ DomainShutoffFailed DomainShutoffReason = 6
+ DomainShutoffFromSnapshot DomainShutoffReason = 7
+ DomainShutoffDaemon DomainShutoffReason = 8
+)
+
+// DomainCrashedReason as declared in libvirt/libvirt-domain.h:161
+type DomainCrashedReason int32
+
+// DomainCrashedReason enumeration from libvirt/libvirt-domain.h:161
+const (
+ DomainCrashedUnknown DomainCrashedReason = iota
+ DomainCrashedPanicked DomainCrashedReason = 1
+)
+
+// DomainPMSuspendedReason as declared in libvirt/libvirt-domain.h:169
+type DomainPMSuspendedReason int32
+
+// DomainPMSuspendedReason enumeration from libvirt/libvirt-domain.h:169
+const (
+ DomainPmsuspendedUnknown DomainPMSuspendedReason = iota
+)
+
+// DomainPMSuspendedDiskReason as declared in libvirt/libvirt-domain.h:177
+type DomainPMSuspendedDiskReason int32
+
+// DomainPMSuspendedDiskReason enumeration from libvirt/libvirt-domain.h:177
+const (
+ DomainPmsuspendedDiskUnknown DomainPMSuspendedDiskReason = iota
+)
+
+// DomainControlState as declared in libvirt/libvirt-domain.h:197
+type DomainControlState int32
+
+// DomainControlState enumeration from libvirt/libvirt-domain.h:197
+const (
+ DomainControlOk DomainControlState = iota
+ DomainControlJob DomainControlState = 1
+ DomainControlOccupied DomainControlState = 2
+ DomainControlError DomainControlState = 3
+)
+
+// DomainControlErrorReason as declared in libvirt/libvirt-domain.h:217
+type DomainControlErrorReason int32
+
+// DomainControlErrorReason enumeration from libvirt/libvirt-domain.h:217
+const (
+ DomainControlErrorReasonNone DomainControlErrorReason = iota
+ DomainControlErrorReasonUnknown DomainControlErrorReason = 1
+ DomainControlErrorReasonMonitor DomainControlErrorReason = 2
+ DomainControlErrorReasonInternal DomainControlErrorReason = 3
+)
+
+// DomainModificationImpact as declared in libvirt/libvirt-domain.h:265
+type DomainModificationImpact int32
+
+// DomainModificationImpact enumeration from libvirt/libvirt-domain.h:265
+const (
+ DomainAffectCurrent DomainModificationImpact = iota
+ DomainAffectLive DomainModificationImpact = 1
+ DomainAffectConfig DomainModificationImpact = 2
+)
+
+// DomainCreateFlags as declared in libvirt/libvirt-domain.h:305
+type DomainCreateFlags int32
+
+// DomainCreateFlags enumeration from libvirt/libvirt-domain.h:305
+const (
+ DomainNone DomainCreateFlags = iota
+ DomainStartPaused DomainCreateFlags = 1
+ DomainStartAutodestroy DomainCreateFlags = 2
+ DomainStartBypassCache DomainCreateFlags = 4
+ DomainStartForceBoot DomainCreateFlags = 8
+ DomainStartValidate DomainCreateFlags = 16
+)
+
+// DomainMemoryStatTags as declared in libvirt/libvirt-domain.h:660
+type DomainMemoryStatTags int32
+
+// DomainMemoryStatTags enumeration from libvirt/libvirt-domain.h:660
+const (
+ DomainMemoryStatSwapIn DomainMemoryStatTags = iota
+ DomainMemoryStatSwapOut DomainMemoryStatTags = 1
+ DomainMemoryStatMajorFault DomainMemoryStatTags = 2
+ DomainMemoryStatMinorFault DomainMemoryStatTags = 3
+ DomainMemoryStatUnused DomainMemoryStatTags = 4
+ DomainMemoryStatAvailable DomainMemoryStatTags = 5
+ DomainMemoryStatActualBalloon DomainMemoryStatTags = 6
+ DomainMemoryStatRss DomainMemoryStatTags = 7
+ DomainMemoryStatUsable DomainMemoryStatTags = 8
+ DomainMemoryStatLastUpdate DomainMemoryStatTags = 9
+ DomainMemoryStatDiskCaches DomainMemoryStatTags = 10
+ DomainMemoryStatHugetlbPgalloc DomainMemoryStatTags = 11
+ DomainMemoryStatHugetlbPgfail DomainMemoryStatTags = 12
+ DomainMemoryStatNr DomainMemoryStatTags = 13
+)
+
+// DomainCoreDumpFlags as declared in libvirt/libvirt-domain.h:679
+type DomainCoreDumpFlags int32
+
+// DomainCoreDumpFlags enumeration from libvirt/libvirt-domain.h:679
+const (
+ DumpCrash DomainCoreDumpFlags = 1
+ DumpLive DomainCoreDumpFlags = 2
+ DumpBypassCache DomainCoreDumpFlags = 4
+ DumpReset DomainCoreDumpFlags = 8
+ DumpMemoryOnly DomainCoreDumpFlags = 16
+)
+
+// DomainCoreDumpFormat as declared in libvirt/libvirt-domain.h:703
+type DomainCoreDumpFormat int32
+
+// DomainCoreDumpFormat enumeration from libvirt/libvirt-domain.h:703
+const (
+ DomainCoreDumpFormatRaw DomainCoreDumpFormat = iota
+ DomainCoreDumpFormatKdumpZlib DomainCoreDumpFormat = 1
+ DomainCoreDumpFormatKdumpLzo DomainCoreDumpFormat = 2
+ DomainCoreDumpFormatKdumpSnappy DomainCoreDumpFormat = 3
+ DomainCoreDumpFormatWinDmp DomainCoreDumpFormat = 4
+)
+
+// DomainMigrateFlags as declared in libvirt/libvirt-domain.h:863
+type DomainMigrateFlags int32
+
+// DomainMigrateFlags enumeration from libvirt/libvirt-domain.h:863
+const (
+ MigrateLive DomainMigrateFlags = 1
+ MigratePeer2peer DomainMigrateFlags = 2
+ MigrateTunnelled DomainMigrateFlags = 4
+ MigratePersistDest DomainMigrateFlags = 8
+ MigrateUndefineSource DomainMigrateFlags = 16
+ MigratePaused DomainMigrateFlags = 32
+ MigrateNonSharedDisk DomainMigrateFlags = 64
+ MigrateNonSharedInc DomainMigrateFlags = 128
+ MigrateChangeProtection DomainMigrateFlags = 256
+ MigrateUnsafe DomainMigrateFlags = 512
+ MigrateOffline DomainMigrateFlags = 1024
+ MigrateCompressed DomainMigrateFlags = 2048
+ MigrateAbortOnError DomainMigrateFlags = 4096
+ MigrateAutoConverge DomainMigrateFlags = 8192
+ MigrateRdmaPinAll DomainMigrateFlags = 16384
+ MigratePostcopy DomainMigrateFlags = 32768
+ MigrateTLS DomainMigrateFlags = 65536
+ MigrateParallel DomainMigrateFlags = 131072
+ MigrateNonSharedSynchronousWrites DomainMigrateFlags = 262144
+)
+
+// DomainMigrateMaxSpeedFlags as declared in libvirt/libvirt-domain.h:1142
+type DomainMigrateMaxSpeedFlags int32
+
+// DomainMigrateMaxSpeedFlags enumeration from libvirt/libvirt-domain.h:1142
+const (
+ DomainMigrateMaxSpeedPostcopy DomainMigrateMaxSpeedFlags = 1
+)
+
+// DomainShutdownFlagValues as declared in libvirt/libvirt-domain.h:1208
+type DomainShutdownFlagValues int32
+
+// DomainShutdownFlagValues enumeration from libvirt/libvirt-domain.h:1208
+const (
+ DomainShutdownDefault DomainShutdownFlagValues = iota
+ DomainShutdownAcpiPowerBtn DomainShutdownFlagValues = 1
+ DomainShutdownGuestAgent DomainShutdownFlagValues = 2
+ DomainShutdownInitctl DomainShutdownFlagValues = 4
+ DomainShutdownSignal DomainShutdownFlagValues = 8
+ DomainShutdownParavirt DomainShutdownFlagValues = 16
+)
+
+// DomainRebootFlagValues as declared in libvirt/libvirt-domain.h:1221
+type DomainRebootFlagValues int32
+
+// DomainRebootFlagValues enumeration from libvirt/libvirt-domain.h:1221
+const (
+ DomainRebootDefault DomainRebootFlagValues = iota
+ DomainRebootAcpiPowerBtn DomainRebootFlagValues = 1
+ DomainRebootGuestAgent DomainRebootFlagValues = 2
+ DomainRebootInitctl DomainRebootFlagValues = 4
+ DomainRebootSignal DomainRebootFlagValues = 8
+ DomainRebootParavirt DomainRebootFlagValues = 16
+)
+
+// DomainDestroyFlagsValues as declared in libvirt/libvirt-domain.h:1239
+type DomainDestroyFlagsValues int32
+
+// DomainDestroyFlagsValues enumeration from libvirt/libvirt-domain.h:1239
+const (
+ DomainDestroyDefault DomainDestroyFlagsValues = iota
+ DomainDestroyGraceful DomainDestroyFlagsValues = 1
+)
+
+// DomainSaveRestoreFlags as declared in libvirt/libvirt-domain.h:1271
+type DomainSaveRestoreFlags int32
+
+// DomainSaveRestoreFlags enumeration from libvirt/libvirt-domain.h:1271
+const (
+ DomainSaveBypassCache DomainSaveRestoreFlags = 1
+ DomainSaveRunning DomainSaveRestoreFlags = 2
+ DomainSavePaused DomainSaveRestoreFlags = 4
+)
+
+// DomainMemoryModFlags as declared in libvirt/libvirt-domain.h:1527
+type DomainMemoryModFlags int32
+
+// DomainMemoryModFlags enumeration from libvirt/libvirt-domain.h:1527
+const (
+ DomainMemCurrent DomainMemoryModFlags = iota
+ DomainMemLive DomainMemoryModFlags = 1
+ DomainMemConfig DomainMemoryModFlags = 2
+ DomainMemMaximum DomainMemoryModFlags = 4
+)
+
+// DomainNumatuneMemMode as declared in libvirt/libvirt-domain.h:1546
+type DomainNumatuneMemMode int32
+
+// DomainNumatuneMemMode enumeration from libvirt/libvirt-domain.h:1546
+const (
+ DomainNumatuneMemStrict DomainNumatuneMemMode = iota
+ DomainNumatuneMemPreferred DomainNumatuneMemMode = 1
+ DomainNumatuneMemInterleave DomainNumatuneMemMode = 2
+ DomainNumatuneMemRestrictive DomainNumatuneMemMode = 3
+)
+
+// DomainGetHostnameFlags as declared in libvirt/libvirt-domain.h:1599
+type DomainGetHostnameFlags int32
+
+// DomainGetHostnameFlags enumeration from libvirt/libvirt-domain.h:1599
+const (
+ DomainGetHostnameLease DomainGetHostnameFlags = 1
+ DomainGetHostnameAgent DomainGetHostnameFlags = 2
+)
+
+// DomainMetadataType as declared in libvirt/libvirt-domain.h:1614
+type DomainMetadataType int32
+
+// DomainMetadataType enumeration from libvirt/libvirt-domain.h:1614
+const (
+ DomainMetadataDescription DomainMetadataType = iota
+ DomainMetadataTitle DomainMetadataType = 1
+ DomainMetadataElement DomainMetadataType = 2
+)
+
+// DomainXMLFlags as declared in libvirt/libvirt-domain.h:1644
+type DomainXMLFlags int32
+
+// DomainXMLFlags enumeration from libvirt/libvirt-domain.h:1644
+const (
+ DomainXMLSecure DomainXMLFlags = 1
+ DomainXMLInactive DomainXMLFlags = 2
+ DomainXMLUpdateCPU DomainXMLFlags = 4
+ DomainXMLMigratable DomainXMLFlags = 8
+)
+
+// DomainSaveImageXMLFlags as declared in libvirt/libvirt-domain.h:1648
+type DomainSaveImageXMLFlags int32
+
+// DomainSaveImageXMLFlags enumeration from libvirt/libvirt-domain.h:1648
+const (
+ DomainSaveImageXMLSecure DomainSaveImageXMLFlags = 1
+)
+
+// DomainBlockResizeFlags as declared in libvirt/libvirt-domain.h:1753
+type DomainBlockResizeFlags int32
+
+// DomainBlockResizeFlags enumeration from libvirt/libvirt-domain.h:1753
+const (
+ DomainBlockResizeBytes DomainBlockResizeFlags = 1
+)
+
+// DomainMemoryFlags as declared in libvirt/libvirt-domain.h:1816
+type DomainMemoryFlags int32
+
+// DomainMemoryFlags enumeration from libvirt/libvirt-domain.h:1816
+const (
+ MemoryVirtual DomainMemoryFlags = 1
+ MemoryPhysical DomainMemoryFlags = 2
+)
+
+// DomainDefineFlags as declared in libvirt/libvirt-domain.h:1826
+type DomainDefineFlags int32
+
+// DomainDefineFlags enumeration from libvirt/libvirt-domain.h:1826
+const (
+ DomainDefineValidate DomainDefineFlags = 1
+)
+
+// DomainUndefineFlagsValues as declared in libvirt/libvirt-domain.h:1853
+type DomainUndefineFlagsValues int32
+
+// DomainUndefineFlagsValues enumeration from libvirt/libvirt-domain.h:1853
+const (
+ DomainUndefineManagedSave DomainUndefineFlagsValues = 1
+ DomainUndefineSnapshotsMetadata DomainUndefineFlagsValues = 2
+ DomainUndefineNvram DomainUndefineFlagsValues = 4
+ DomainUndefineKeepNvram DomainUndefineFlagsValues = 8
+ DomainUndefineCheckpointsMetadata DomainUndefineFlagsValues = 16
+)
+
+// ConnectListAllDomainsFlags as declared in libvirt/libvirt-domain.h:1892
+type ConnectListAllDomainsFlags int32
+
+// ConnectListAllDomainsFlags enumeration from libvirt/libvirt-domain.h:1892
+const (
+ ConnectListDomainsActive ConnectListAllDomainsFlags = 1
+ ConnectListDomainsInactive ConnectListAllDomainsFlags = 2
+ ConnectListDomainsPersistent ConnectListAllDomainsFlags = 4
+ ConnectListDomainsTransient ConnectListAllDomainsFlags = 8
+ ConnectListDomainsRunning ConnectListAllDomainsFlags = 16
+ ConnectListDomainsPaused ConnectListAllDomainsFlags = 32
+ ConnectListDomainsShutoff ConnectListAllDomainsFlags = 64
+ ConnectListDomainsOther ConnectListAllDomainsFlags = 128
+ ConnectListDomainsManagedsave ConnectListAllDomainsFlags = 256
+ ConnectListDomainsNoManagedsave ConnectListAllDomainsFlags = 512
+ ConnectListDomainsAutostart ConnectListAllDomainsFlags = 1024
+ ConnectListDomainsNoAutostart ConnectListAllDomainsFlags = 2048
+ ConnectListDomainsHasSnapshot ConnectListAllDomainsFlags = 4096
+ ConnectListDomainsNoSnapshot ConnectListAllDomainsFlags = 8192
+ ConnectListDomainsHasCheckpoint ConnectListAllDomainsFlags = 16384
+ ConnectListDomainsNoCheckpoint ConnectListAllDomainsFlags = 32768
+)
+
+// VCPUState as declared in libvirt/libvirt-domain.h:1923
+type VCPUState int32
+
+// VCPUState enumeration from libvirt/libvirt-domain.h:1923
+const (
+ VCPUOffline VCPUState = iota
+ VCPURunning VCPUState = 1
+ VCPUBlocked VCPUState = 2
+)
+
+// VCPUHostCPUState as declared in libvirt/libvirt-domain.h:1928
+type VCPUHostCPUState int32
+
+// VCPUHostCPUState enumeration from libvirt/libvirt-domain.h:1928
+const (
+ VCPUInfoCPUOffline VCPUHostCPUState = -1
+ VCPUInfoCPUUnavailable VCPUHostCPUState = -2
+)
+
+// DomainVCPUFlags as declared in libvirt/libvirt-domain.h:1950
+type DomainVCPUFlags int32
+
+// DomainVCPUFlags enumeration from libvirt/libvirt-domain.h:1950
+const (
+ DomainVCPUCurrent DomainVCPUFlags = iota
+ DomainVCPULive DomainVCPUFlags = 1
+ DomainVCPUConfig DomainVCPUFlags = 2
+ DomainVCPUMaximum DomainVCPUFlags = 4
+ DomainVCPUGuest DomainVCPUFlags = 8
+ DomainVCPUHotpluggable DomainVCPUFlags = 16
+)
+
+// DomainDeviceModifyFlags as declared in libvirt/libvirt-domain.h:2167
+type DomainDeviceModifyFlags int32
+
+// DomainDeviceModifyFlags enumeration from libvirt/libvirt-domain.h:2167
+const (
+ DomainDeviceModifyCurrent DomainDeviceModifyFlags = iota
+ DomainDeviceModifyLive DomainDeviceModifyFlags = 1
+ DomainDeviceModifyConfig DomainDeviceModifyFlags = 2
+ DomainDeviceModifyForce DomainDeviceModifyFlags = 4
+)
+
+// DomainStatsTypes as declared in libvirt/libvirt-domain.h:2201
+type DomainStatsTypes int32
+
+// DomainStatsTypes enumeration from libvirt/libvirt-domain.h:2201
+const (
+ DomainStatsState DomainStatsTypes = 1
+ DomainStatsCPUTotal DomainStatsTypes = 2
+ DomainStatsBalloon DomainStatsTypes = 4
+ DomainStatsVCPU DomainStatsTypes = 8
+ DomainStatsInterface DomainStatsTypes = 16
+ DomainStatsBlock DomainStatsTypes = 32
+ DomainStatsPerf DomainStatsTypes = 64
+ DomainStatsIothread DomainStatsTypes = 128
+ DomainStatsMemory DomainStatsTypes = 256
+ DomainStatsDirtyrate DomainStatsTypes = 512
+)
+
+// ConnectGetAllDomainStatsFlags as declared in libvirt/libvirt-domain.h:2219
+type ConnectGetAllDomainStatsFlags int32
+
+// ConnectGetAllDomainStatsFlags enumeration from libvirt/libvirt-domain.h:2219
+const (
+ ConnectGetAllDomainsStatsActive ConnectGetAllDomainStatsFlags = 1
+ ConnectGetAllDomainsStatsInactive ConnectGetAllDomainStatsFlags = 2
+ ConnectGetAllDomainsStatsPersistent ConnectGetAllDomainStatsFlags = 4
+ ConnectGetAllDomainsStatsTransient ConnectGetAllDomainStatsFlags = 8
+ ConnectGetAllDomainsStatsRunning ConnectGetAllDomainStatsFlags = 16
+ ConnectGetAllDomainsStatsPaused ConnectGetAllDomainStatsFlags = 32
+ ConnectGetAllDomainsStatsShutoff ConnectGetAllDomainStatsFlags = 64
+ ConnectGetAllDomainsStatsOther ConnectGetAllDomainStatsFlags = 128
+ ConnectGetAllDomainsStatsNowait ConnectGetAllDomainStatsFlags = 536870912
+ ConnectGetAllDomainsStatsBacking ConnectGetAllDomainStatsFlags = 1073741824
+ ConnectGetAllDomainsStatsEnforceStats ConnectGetAllDomainStatsFlags = -2147483648
+)
+
+// DomainBlockJobType as declared in libvirt/libvirt-domain.h:2507
+type DomainBlockJobType int32
+
+// DomainBlockJobType enumeration from libvirt/libvirt-domain.h:2507
+const (
+ DomainBlockJobTypeUnknown DomainBlockJobType = iota
+ DomainBlockJobTypePull DomainBlockJobType = 1
+ DomainBlockJobTypeCopy DomainBlockJobType = 2
+ DomainBlockJobTypeCommit DomainBlockJobType = 3
+ DomainBlockJobTypeActiveCommit DomainBlockJobType = 4
+ DomainBlockJobTypeBackup DomainBlockJobType = 5
+)
+
+// DomainBlockJobAbortFlags as declared in libvirt/libvirt-domain.h:2519
+type DomainBlockJobAbortFlags int32
+
+// DomainBlockJobAbortFlags enumeration from libvirt/libvirt-domain.h:2519
+const (
+ DomainBlockJobAbortAsync DomainBlockJobAbortFlags = 1
+ DomainBlockJobAbortPivot DomainBlockJobAbortFlags = 2
+)
+
+// DomainBlockJobInfoFlags as declared in libvirt/libvirt-domain.h:2528
+type DomainBlockJobInfoFlags int32
+
+// DomainBlockJobInfoFlags enumeration from libvirt/libvirt-domain.h:2528
+const (
+ DomainBlockJobInfoBandwidthBytes DomainBlockJobInfoFlags = 1
+)
+
+// DomainBlockJobSetSpeedFlags as declared in libvirt/libvirt-domain.h:2557
+type DomainBlockJobSetSpeedFlags int32
+
+// DomainBlockJobSetSpeedFlags enumeration from libvirt/libvirt-domain.h:2557
+const (
+ DomainBlockJobSpeedBandwidthBytes DomainBlockJobSetSpeedFlags = 1
+)
+
+// DomainBlockPullFlags as declared in libvirt/libvirt-domain.h:2567
+type DomainBlockPullFlags int32
+
+// DomainBlockPullFlags enumeration from libvirt/libvirt-domain.h:2567
+const (
+ DomainBlockPullBandwidthBytes DomainBlockPullFlags = 64
+)
+
+// DomainBlockRebaseFlags as declared in libvirt/libvirt-domain.h:2591
+type DomainBlockRebaseFlags int32
+
+// DomainBlockRebaseFlags enumeration from libvirt/libvirt-domain.h:2591
+const (
+ DomainBlockRebaseShallow DomainBlockRebaseFlags = 1
+ DomainBlockRebaseReuseExt DomainBlockRebaseFlags = 2
+ DomainBlockRebaseCopyRaw DomainBlockRebaseFlags = 4
+ DomainBlockRebaseCopy DomainBlockRebaseFlags = 8
+ DomainBlockRebaseRelative DomainBlockRebaseFlags = 16
+ DomainBlockRebaseCopyDev DomainBlockRebaseFlags = 32
+ DomainBlockRebaseBandwidthBytes DomainBlockRebaseFlags = 64
+)
+
+// DomainBlockCopyFlags as declared in libvirt/libvirt-domain.h:2615
+type DomainBlockCopyFlags int32
+
+// DomainBlockCopyFlags enumeration from libvirt/libvirt-domain.h:2615
+const (
+ DomainBlockCopyShallow DomainBlockCopyFlags = 1
+ DomainBlockCopyReuseExt DomainBlockCopyFlags = 2
+ DomainBlockCopyTransientJob DomainBlockCopyFlags = 4
+ DomainBlockCopySynchronousWrites DomainBlockCopyFlags = 8
+)
+
+// DomainBlockCommitFlags as declared in libvirt/libvirt-domain.h:2680
+type DomainBlockCommitFlags int32
+
+// DomainBlockCommitFlags enumeration from libvirt/libvirt-domain.h:2680
+const (
+ DomainBlockCommitShallow DomainBlockCommitFlags = 1
+ DomainBlockCommitDelete DomainBlockCommitFlags = 2
+ DomainBlockCommitActive DomainBlockCommitFlags = 4
+ DomainBlockCommitRelative DomainBlockCommitFlags = 8
+ DomainBlockCommitBandwidthBytes DomainBlockCommitFlags = 16
+)
+
+// DomainDiskErrorCode as declared in libvirt/libvirt-domain.h:2871
+type DomainDiskErrorCode int32
+
+// DomainDiskErrorCode enumeration from libvirt/libvirt-domain.h:2871
+const (
+ DomainDiskErrorNone DomainDiskErrorCode = iota
+ DomainDiskErrorUnspec DomainDiskErrorCode = 1
+ DomainDiskErrorNoSpace DomainDiskErrorCode = 2
+)
+
+// KeycodeSet as declared in libvirt/libvirt-domain.h:2917
+type KeycodeSet int32
+
+// KeycodeSet enumeration from libvirt/libvirt-domain.h:2917
+const (
+ KeycodeSetLinux KeycodeSet = iota
+ KeycodeSetXt KeycodeSet = 1
+ KeycodeSetAtset1 KeycodeSet = 2
+ KeycodeSetAtset2 KeycodeSet = 3
+ KeycodeSetAtset3 KeycodeSet = 4
+ KeycodeSetOsx KeycodeSet = 5
+ KeycodeSetXtKbd KeycodeSet = 6
+ KeycodeSetUsb KeycodeSet = 7
+ KeycodeSetWin32 KeycodeSet = 8
+ KeycodeSetQnum KeycodeSet = 9
+)
+
+// DomainProcessSignal as declared in libvirt/libvirt-domain.h:3026
+type DomainProcessSignal int32
+
+// DomainProcessSignal enumeration from libvirt/libvirt-domain.h:3026
+const (
+ DomainProcessSignalNop DomainProcessSignal = iota
+ DomainProcessSignalHup DomainProcessSignal = 1
+ DomainProcessSignalInt DomainProcessSignal = 2
+ DomainProcessSignalQuit DomainProcessSignal = 3
+ DomainProcessSignalIll DomainProcessSignal = 4
+ DomainProcessSignalTrap DomainProcessSignal = 5
+ DomainProcessSignalAbrt DomainProcessSignal = 6
+ DomainProcessSignalBus DomainProcessSignal = 7
+ DomainProcessSignalFpe DomainProcessSignal = 8
+ DomainProcessSignalKill DomainProcessSignal = 9
+ DomainProcessSignalUsr1 DomainProcessSignal = 10
+ DomainProcessSignalSegv DomainProcessSignal = 11
+ DomainProcessSignalUsr2 DomainProcessSignal = 12
+ DomainProcessSignalPipe DomainProcessSignal = 13
+ DomainProcessSignalAlrm DomainProcessSignal = 14
+ DomainProcessSignalTerm DomainProcessSignal = 15
+ DomainProcessSignalStkflt DomainProcessSignal = 16
+ DomainProcessSignalChld DomainProcessSignal = 17
+ DomainProcessSignalCont DomainProcessSignal = 18
+ DomainProcessSignalStop DomainProcessSignal = 19
+ DomainProcessSignalTstp DomainProcessSignal = 20
+ DomainProcessSignalTtin DomainProcessSignal = 21
+ DomainProcessSignalTtou DomainProcessSignal = 22
+ DomainProcessSignalUrg DomainProcessSignal = 23
+ DomainProcessSignalXcpu DomainProcessSignal = 24
+ DomainProcessSignalXfsz DomainProcessSignal = 25
+ DomainProcessSignalVtalrm DomainProcessSignal = 26
+ DomainProcessSignalProf DomainProcessSignal = 27
+ DomainProcessSignalWinch DomainProcessSignal = 28
+ DomainProcessSignalPoll DomainProcessSignal = 29
+ DomainProcessSignalPwr DomainProcessSignal = 30
+ DomainProcessSignalSys DomainProcessSignal = 31
+ DomainProcessSignalRt0 DomainProcessSignal = 32
+ DomainProcessSignalRt1 DomainProcessSignal = 33
+ DomainProcessSignalRt2 DomainProcessSignal = 34
+ DomainProcessSignalRt3 DomainProcessSignal = 35
+ DomainProcessSignalRt4 DomainProcessSignal = 36
+ DomainProcessSignalRt5 DomainProcessSignal = 37
+ DomainProcessSignalRt6 DomainProcessSignal = 38
+ DomainProcessSignalRt7 DomainProcessSignal = 39
+ DomainProcessSignalRt8 DomainProcessSignal = 40
+ DomainProcessSignalRt9 DomainProcessSignal = 41
+ DomainProcessSignalRt10 DomainProcessSignal = 42
+ DomainProcessSignalRt11 DomainProcessSignal = 43
+ DomainProcessSignalRt12 DomainProcessSignal = 44
+ DomainProcessSignalRt13 DomainProcessSignal = 45
+ DomainProcessSignalRt14 DomainProcessSignal = 46
+ DomainProcessSignalRt15 DomainProcessSignal = 47
+ DomainProcessSignalRt16 DomainProcessSignal = 48
+ DomainProcessSignalRt17 DomainProcessSignal = 49
+ DomainProcessSignalRt18 DomainProcessSignal = 50
+ DomainProcessSignalRt19 DomainProcessSignal = 51
+ DomainProcessSignalRt20 DomainProcessSignal = 52
+ DomainProcessSignalRt21 DomainProcessSignal = 53
+ DomainProcessSignalRt22 DomainProcessSignal = 54
+ DomainProcessSignalRt23 DomainProcessSignal = 55
+ DomainProcessSignalRt24 DomainProcessSignal = 56
+ DomainProcessSignalRt25 DomainProcessSignal = 57
+ DomainProcessSignalRt26 DomainProcessSignal = 58
+ DomainProcessSignalRt27 DomainProcessSignal = 59
+ DomainProcessSignalRt28 DomainProcessSignal = 60
+ DomainProcessSignalRt29 DomainProcessSignal = 61
+ DomainProcessSignalRt30 DomainProcessSignal = 62
+ DomainProcessSignalRt31 DomainProcessSignal = 63
+ DomainProcessSignalRt32 DomainProcessSignal = 64
+)
+
+// DomainEventType as declared in libvirt/libvirt-domain.h:3064
+type DomainEventType int32
+
+// DomainEventType enumeration from libvirt/libvirt-domain.h:3064
+const (
+ DomainEventDefined DomainEventType = iota
+ DomainEventUndefined DomainEventType = 1
+ DomainEventStarted DomainEventType = 2
+ DomainEventSuspended DomainEventType = 3
+ DomainEventResumed DomainEventType = 4
+ DomainEventStopped DomainEventType = 5
+ DomainEventShutdown DomainEventType = 6
+ DomainEventPmsuspended DomainEventType = 7
+ DomainEventCrashed DomainEventType = 8
+)
+
+// DomainEventDefinedDetailType as declared in libvirt/libvirt-domain.h:3080
+type DomainEventDefinedDetailType int32
+
+// DomainEventDefinedDetailType enumeration from libvirt/libvirt-domain.h:3080
+const (
+ DomainEventDefinedAdded DomainEventDefinedDetailType = iota
+ DomainEventDefinedUpdated DomainEventDefinedDetailType = 1
+ DomainEventDefinedRenamed DomainEventDefinedDetailType = 2
+ DomainEventDefinedFromSnapshot DomainEventDefinedDetailType = 3
+)
+
+// DomainEventUndefinedDetailType as declared in libvirt/libvirt-domain.h:3094
+type DomainEventUndefinedDetailType int32
+
+// DomainEventUndefinedDetailType enumeration from libvirt/libvirt-domain.h:3094
+const (
+ DomainEventUndefinedRemoved DomainEventUndefinedDetailType = iota
+ DomainEventUndefinedRenamed DomainEventUndefinedDetailType = 1
+)
+
+// DomainEventStartedDetailType as declared in libvirt/libvirt-domain.h:3111
+type DomainEventStartedDetailType int32
+
+// DomainEventStartedDetailType enumeration from libvirt/libvirt-domain.h:3111
+const (
+ DomainEventStartedBooted DomainEventStartedDetailType = iota
+ DomainEventStartedMigrated DomainEventStartedDetailType = 1
+ DomainEventStartedRestored DomainEventStartedDetailType = 2
+ DomainEventStartedFromSnapshot DomainEventStartedDetailType = 3
+ DomainEventStartedWakeup DomainEventStartedDetailType = 4
+)
+
+// DomainEventSuspendedDetailType as declared in libvirt/libvirt-domain.h:3132
+type DomainEventSuspendedDetailType int32
+
+// DomainEventSuspendedDetailType enumeration from libvirt/libvirt-domain.h:3132
+const (
+ DomainEventSuspendedPaused DomainEventSuspendedDetailType = iota
+ DomainEventSuspendedMigrated DomainEventSuspendedDetailType = 1
+ DomainEventSuspendedIoerror DomainEventSuspendedDetailType = 2
+ DomainEventSuspendedWatchdog DomainEventSuspendedDetailType = 3
+ DomainEventSuspendedRestored DomainEventSuspendedDetailType = 4
+ DomainEventSuspendedFromSnapshot DomainEventSuspendedDetailType = 5
+ DomainEventSuspendedAPIError DomainEventSuspendedDetailType = 6
+ DomainEventSuspendedPostcopy DomainEventSuspendedDetailType = 7
+ DomainEventSuspendedPostcopyFailed DomainEventSuspendedDetailType = 8
+)
+
+// DomainEventResumedDetailType as declared in libvirt/libvirt-domain.h:3149
+type DomainEventResumedDetailType int32
+
+// DomainEventResumedDetailType enumeration from libvirt/libvirt-domain.h:3149
+const (
+ DomainEventResumedUnpaused DomainEventResumedDetailType = iota
+ DomainEventResumedMigrated DomainEventResumedDetailType = 1
+ DomainEventResumedFromSnapshot DomainEventResumedDetailType = 2
+ DomainEventResumedPostcopy DomainEventResumedDetailType = 3
+)
+
+// DomainEventStoppedDetailType as declared in libvirt/libvirt-domain.h:3168
+type DomainEventStoppedDetailType int32
+
+// DomainEventStoppedDetailType enumeration from libvirt/libvirt-domain.h:3168
+const (
+ DomainEventStoppedShutdown DomainEventStoppedDetailType = iota
+ DomainEventStoppedDestroyed DomainEventStoppedDetailType = 1
+ DomainEventStoppedCrashed DomainEventStoppedDetailType = 2
+ DomainEventStoppedMigrated DomainEventStoppedDetailType = 3
+ DomainEventStoppedSaved DomainEventStoppedDetailType = 4
+ DomainEventStoppedFailed DomainEventStoppedDetailType = 5
+ DomainEventStoppedFromSnapshot DomainEventStoppedDetailType = 6
+)
+
+// DomainEventShutdownDetailType as declared in libvirt/libvirt-domain.h:3191
+type DomainEventShutdownDetailType int32
+
+// DomainEventShutdownDetailType enumeration from libvirt/libvirt-domain.h:3191
+const (
+ DomainEventShutdownFinished DomainEventShutdownDetailType = iota
+ DomainEventShutdownGuest DomainEventShutdownDetailType = 1
+ DomainEventShutdownHost DomainEventShutdownDetailType = 2
+)
+
+// DomainEventPMSuspendedDetailType as declared in libvirt/libvirt-domain.h:3205
+type DomainEventPMSuspendedDetailType int32
+
+// DomainEventPMSuspendedDetailType enumeration from libvirt/libvirt-domain.h:3205
+const (
+ DomainEventPmsuspendedMemory DomainEventPMSuspendedDetailType = iota
+ DomainEventPmsuspendedDisk DomainEventPMSuspendedDetailType = 1
+)
+
+// DomainEventCrashedDetailType as declared in libvirt/libvirt-domain.h:3219
+type DomainEventCrashedDetailType int32
+
+// DomainEventCrashedDetailType enumeration from libvirt/libvirt-domain.h:3219
+const (
+ DomainEventCrashedPanicked DomainEventCrashedDetailType = iota
+ DomainEventCrashedCrashloaded DomainEventCrashedDetailType = 1
+)
+
+// DomainMemoryFailureRecipientType as declared in libvirt/libvirt-domain.h:3236
+type DomainMemoryFailureRecipientType int32
+
+// DomainMemoryFailureRecipientType enumeration from libvirt/libvirt-domain.h:3236
+const (
+ DomainEventMemoryFailureRecipientHypervisor DomainMemoryFailureRecipientType = iota
+ DomainEventMemoryFailureRecipientGuest DomainMemoryFailureRecipientType = 1
+)
+
+// DomainMemoryFailureActionType as declared in libvirt/libvirt-domain.h:3265
+type DomainMemoryFailureActionType int32
+
+// DomainMemoryFailureActionType enumeration from libvirt/libvirt-domain.h:3265
+const (
+ DomainEventMemoryFailureActionIgnore DomainMemoryFailureActionType = iota
+ DomainEventMemoryFailureActionInject DomainMemoryFailureActionType = 1
+ DomainEventMemoryFailureActionFatal DomainMemoryFailureActionType = 2
+ DomainEventMemoryFailureActionReset DomainMemoryFailureActionType = 3
+)
+
+// DomainMemoryFailureFlags as declared in libvirt/libvirt-domain.h:3276
+type DomainMemoryFailureFlags int32
+
+// DomainMemoryFailureFlags enumeration from libvirt/libvirt-domain.h:3276
+const (
+ DomainMemoryFailureActionRequired DomainMemoryFailureFlags = 1
+ DomainMemoryFailureRecursive DomainMemoryFailureFlags = 2
+)
+
+// DomainJobType as declared in libvirt/libvirt-domain.h:3321
+type DomainJobType int32
+
+// DomainJobType enumeration from libvirt/libvirt-domain.h:3321
+const (
+ DomainJobNone DomainJobType = iota
+ DomainJobBounded DomainJobType = 1
+ DomainJobUnbounded DomainJobType = 2
+ DomainJobCompleted DomainJobType = 3
+ DomainJobFailed DomainJobType = 4
+ DomainJobCancelled DomainJobType = 5
+)
+
+// DomainGetJobStatsFlags as declared in libvirt/libvirt-domain.h:3370
+type DomainGetJobStatsFlags int32
+
+// DomainGetJobStatsFlags enumeration from libvirt/libvirt-domain.h:3370
+const (
+ DomainJobStatsCompleted DomainGetJobStatsFlags = 1
+ DomainJobStatsKeepCompleted DomainGetJobStatsFlags = 2
+)
+
+// DomainJobOperation as declared in libvirt/libvirt-domain.h:3396
+type DomainJobOperation int32
+
+// DomainJobOperation enumeration from libvirt/libvirt-domain.h:3396
+const (
+ DomainJobOperationStrUnknown DomainJobOperation = iota
+ DomainJobOperationStrStart DomainJobOperation = 1
+ DomainJobOperationStrSave DomainJobOperation = 2
+ DomainJobOperationStrRestore DomainJobOperation = 3
+ DomainJobOperationStrMigrationIn DomainJobOperation = 4
+ DomainJobOperationStrMigrationOut DomainJobOperation = 5
+ DomainJobOperationStrSnapshot DomainJobOperation = 6
+ DomainJobOperationStrSnapshotRevert DomainJobOperation = 7
+ DomainJobOperationStrDump DomainJobOperation = 8
+ DomainJobOperationStrBackup DomainJobOperation = 9
+)
+
+// DomainEventWatchdogAction as declared in libvirt/libvirt-domain.h:3780
+type DomainEventWatchdogAction int32
+
+// DomainEventWatchdogAction enumeration from libvirt/libvirt-domain.h:3780
+const (
+ DomainEventWatchdogNone DomainEventWatchdogAction = iota
+ DomainEventWatchdogPause DomainEventWatchdogAction = 1
+ DomainEventWatchdogReset DomainEventWatchdogAction = 2
+ DomainEventWatchdogPoweroff DomainEventWatchdogAction = 3
+ DomainEventWatchdogShutdown DomainEventWatchdogAction = 4
+ DomainEventWatchdogDebug DomainEventWatchdogAction = 5
+ DomainEventWatchdogInjectnmi DomainEventWatchdogAction = 6
+)
+
+// DomainEventIOErrorAction as declared in libvirt/libvirt-domain.h:3811
+type DomainEventIOErrorAction int32
+
+// DomainEventIOErrorAction enumeration from libvirt/libvirt-domain.h:3811
+const (
+ DomainEventIoErrorNone DomainEventIOErrorAction = iota
+ DomainEventIoErrorPause DomainEventIOErrorAction = 1
+ DomainEventIoErrorReport DomainEventIOErrorAction = 2
+)
+
+// DomainEventGraphicsPhase as declared in libvirt/libvirt-domain.h:3874
+type DomainEventGraphicsPhase int32
+
+// DomainEventGraphicsPhase enumeration from libvirt/libvirt-domain.h:3874
+const (
+ DomainEventGraphicsConnect DomainEventGraphicsPhase = iota
+ DomainEventGraphicsInitialize DomainEventGraphicsPhase = 1
+ DomainEventGraphicsDisconnect DomainEventGraphicsPhase = 2
+)
+
+// DomainEventGraphicsAddressType as declared in libvirt/libvirt-domain.h:3889
+type DomainEventGraphicsAddressType int32
+
+// DomainEventGraphicsAddressType enumeration from libvirt/libvirt-domain.h:3889
+const (
+ DomainEventGraphicsAddressIpv4 DomainEventGraphicsAddressType = iota
+ DomainEventGraphicsAddressIpv6 DomainEventGraphicsAddressType = 1
+ DomainEventGraphicsAddressUnix DomainEventGraphicsAddressType = 2
+)
+
+// ConnectDomainEventBlockJobStatus as declared in libvirt/libvirt-domain.h:3977
+type ConnectDomainEventBlockJobStatus int32
+
+// ConnectDomainEventBlockJobStatus enumeration from libvirt/libvirt-domain.h:3977
+const (
+ DomainBlockJobCompleted ConnectDomainEventBlockJobStatus = iota
+ DomainBlockJobFailed ConnectDomainEventBlockJobStatus = 1
+ DomainBlockJobCanceled ConnectDomainEventBlockJobStatus = 2
+ DomainBlockJobReady ConnectDomainEventBlockJobStatus = 3
+)
+
+// ConnectDomainEventDiskChangeReason as declared in libvirt/libvirt-domain.h:4027
+type ConnectDomainEventDiskChangeReason int32
+
+// ConnectDomainEventDiskChangeReason enumeration from libvirt/libvirt-domain.h:4027
+const (
+ DomainEventDiskChangeMissingOnStart ConnectDomainEventDiskChangeReason = iota
+ DomainEventDiskDropMissingOnStart ConnectDomainEventDiskChangeReason = 1
+)
+
+// DomainEventTrayChangeReason as declared in libvirt/libvirt-domain.h:4068
+type DomainEventTrayChangeReason int32
+
+// DomainEventTrayChangeReason enumeration from libvirt/libvirt-domain.h:4068
+const (
+ DomainEventTrayChangeOpen DomainEventTrayChangeReason = iota
+ DomainEventTrayChangeClose DomainEventTrayChangeReason = 1
+)
+
+// ConnectDomainEventAgentLifecycleState as declared in libvirt/libvirt-domain.h:4585
+type ConnectDomainEventAgentLifecycleState int32
+
+// ConnectDomainEventAgentLifecycleState enumeration from libvirt/libvirt-domain.h:4585
+const (
+ ConnectDomainEventAgentLifecycleStateConnected ConnectDomainEventAgentLifecycleState = 1
+ ConnectDomainEventAgentLifecycleStateDisconnected ConnectDomainEventAgentLifecycleState = 2
+)
+
+// ConnectDomainEventAgentLifecycleReason as declared in libvirt/libvirt-domain.h:4595
+type ConnectDomainEventAgentLifecycleReason int32
+
+// ConnectDomainEventAgentLifecycleReason enumeration from libvirt/libvirt-domain.h:4595
+const (
+ ConnectDomainEventAgentLifecycleReasonUnknown ConnectDomainEventAgentLifecycleReason = iota
+ ConnectDomainEventAgentLifecycleReasonDomainStarted ConnectDomainEventAgentLifecycleReason = 1
+ ConnectDomainEventAgentLifecycleReasonChannel ConnectDomainEventAgentLifecycleReason = 2
+)
+
+// DomainEventID as declared in libvirt/libvirt-domain.h:4749
+type DomainEventID int32
+
+// DomainEventID enumeration from libvirt/libvirt-domain.h:4749
+const (
+ DomainEventIDLifecycle DomainEventID = iota
+ DomainEventIDReboot DomainEventID = 1
+ DomainEventIDRtcChange DomainEventID = 2
+ DomainEventIDWatchdog DomainEventID = 3
+ DomainEventIDIoError DomainEventID = 4
+ DomainEventIDGraphics DomainEventID = 5
+ DomainEventIDIoErrorReason DomainEventID = 6
+ DomainEventIDControlError DomainEventID = 7
+ DomainEventIDBlockJob DomainEventID = 8
+ DomainEventIDDiskChange DomainEventID = 9
+ DomainEventIDTrayChange DomainEventID = 10
+ DomainEventIDPmwakeup DomainEventID = 11
+ DomainEventIDPmsuspend DomainEventID = 12
+ DomainEventIDBalloonChange DomainEventID = 13
+ DomainEventIDPmsuspendDisk DomainEventID = 14
+ DomainEventIDDeviceRemoved DomainEventID = 15
+ DomainEventIDBlockJob2 DomainEventID = 16
+ DomainEventIDTunable DomainEventID = 17
+ DomainEventIDAgentLifecycle DomainEventID = 18
+ DomainEventIDDeviceAdded DomainEventID = 19
+ DomainEventIDMigrationIteration DomainEventID = 20
+ DomainEventIDJobCompleted DomainEventID = 21
+ DomainEventIDDeviceRemovalFailed DomainEventID = 22
+ DomainEventIDMetadataChange DomainEventID = 23
+ DomainEventIDBlockThreshold DomainEventID = 24
+ DomainEventIDMemoryFailure DomainEventID = 25
+ DomainEventIDMemoryDeviceSizeChange DomainEventID = 26
+)
+
+// DomainConsoleFlags as declared in libvirt/libvirt-domain.h:4776
+type DomainConsoleFlags int32
+
+// DomainConsoleFlags enumeration from libvirt/libvirt-domain.h:4776
+const (
+ DomainConsoleForce DomainConsoleFlags = 1
+ DomainConsoleSafe DomainConsoleFlags = 2
+)
+
+// DomainChannelFlags as declared in libvirt/libvirt-domain.h:4792
+type DomainChannelFlags int32
+
+// DomainChannelFlags enumeration from libvirt/libvirt-domain.h:4792
+const (
+ DomainChannelForce DomainChannelFlags = 1
+)
+
+// DomainOpenGraphicsFlags as declared in libvirt/libvirt-domain.h:4801
+type DomainOpenGraphicsFlags int32
+
+// DomainOpenGraphicsFlags enumeration from libvirt/libvirt-domain.h:4801
+const (
+ DomainOpenGraphicsSkipauth DomainOpenGraphicsFlags = 1
+)
+
+// DomainSetTimeFlags as declared in libvirt/libvirt-domain.h:4858
+type DomainSetTimeFlags int32
+
+// DomainSetTimeFlags enumeration from libvirt/libvirt-domain.h:4858
+const (
+ DomainTimeSync DomainSetTimeFlags = 1
+)
+
+// SchedParameterType as declared in libvirt/libvirt-domain.h:4879
+type SchedParameterType int32
+
+// SchedParameterType enumeration from libvirt/libvirt-domain.h:4879
+const (
+ DomainSchedFieldInt SchedParameterType = 1
+ DomainSchedFieldUint SchedParameterType = 2
+ DomainSchedFieldLlong SchedParameterType = 3
+ DomainSchedFieldUllong SchedParameterType = 4
+ DomainSchedFieldDouble SchedParameterType = 5
+ DomainSchedFieldBoolean SchedParameterType = 6
+)
+
+// BlkioParameterType as declared in libvirt/libvirt-domain.h:4923
+type BlkioParameterType int32
+
+// BlkioParameterType enumeration from libvirt/libvirt-domain.h:4923
+const (
+ DomainBlkioParamInt BlkioParameterType = 1
+ DomainBlkioParamUint BlkioParameterType = 2
+ DomainBlkioParamLlong BlkioParameterType = 3
+ DomainBlkioParamUllong BlkioParameterType = 4
+ DomainBlkioParamDouble BlkioParameterType = 5
+ DomainBlkioParamBoolean BlkioParameterType = 6
+)
+
+// MemoryParameterType as declared in libvirt/libvirt-domain.h:4967
+type MemoryParameterType int32
+
+// MemoryParameterType enumeration from libvirt/libvirt-domain.h:4967
+const (
+ DomainMemoryParamInt MemoryParameterType = 1
+ DomainMemoryParamUint MemoryParameterType = 2
+ DomainMemoryParamLlong MemoryParameterType = 3
+ DomainMemoryParamUllong MemoryParameterType = 4
+ DomainMemoryParamDouble MemoryParameterType = 5
+ DomainMemoryParamBoolean MemoryParameterType = 6
+)
+
+// DomainInterfaceAddressesSource as declared in libvirt/libvirt-domain.h:5005
+type DomainInterfaceAddressesSource int32
+
+// DomainInterfaceAddressesSource enumeration from libvirt/libvirt-domain.h:5005
+const (
+ DomainInterfaceAddressesSrcLease DomainInterfaceAddressesSource = iota
+ DomainInterfaceAddressesSrcAgent DomainInterfaceAddressesSource = 1
+ DomainInterfaceAddressesSrcArp DomainInterfaceAddressesSource = 2
+)
+
+// DomainSetUserPasswordFlags as declared in libvirt/libvirt-domain.h:5033
+type DomainSetUserPasswordFlags int32
+
+// DomainSetUserPasswordFlags enumeration from libvirt/libvirt-domain.h:5033
+const (
+ DomainPasswordEncrypted DomainSetUserPasswordFlags = 1
+)
+
+// DomainLifecycle as declared in libvirt/libvirt-domain.h:5072
+type DomainLifecycle int32
+
+// DomainLifecycle enumeration from libvirt/libvirt-domain.h:5072
+const (
+ DomainLifecyclePoweroff DomainLifecycle = iota
+ DomainLifecycleReboot DomainLifecycle = 1
+ DomainLifecycleCrash DomainLifecycle = 2
+)
+
+// DomainLifecycleAction as declared in libvirt/libvirt-domain.h:5085
+type DomainLifecycleAction int32
+
+// DomainLifecycleAction enumeration from libvirt/libvirt-domain.h:5085
+const (
+ DomainLifecycleActionDestroy DomainLifecycleAction = iota
+ DomainLifecycleActionRestart DomainLifecycleAction = 1
+ DomainLifecycleActionRestartRename DomainLifecycleAction = 2
+ DomainLifecycleActionPreserve DomainLifecycleAction = 3
+ DomainLifecycleActionCoredumpDestroy DomainLifecycleAction = 4
+ DomainLifecycleActionCoredumpRestart DomainLifecycleAction = 5
+)
+
+// DomainGuestInfoTypes as declared in libvirt/libvirt-domain.h:5185
+type DomainGuestInfoTypes int32
+
+// DomainGuestInfoTypes enumeration from libvirt/libvirt-domain.h:5185
+const (
+ DomainGuestInfoUsers DomainGuestInfoTypes = 1
+ DomainGuestInfoOs DomainGuestInfoTypes = 2
+ DomainGuestInfoTimezone DomainGuestInfoTypes = 4
+ DomainGuestInfoHostname DomainGuestInfoTypes = 8
+ DomainGuestInfoFilesystem DomainGuestInfoTypes = 16
+ DomainGuestInfoDisks DomainGuestInfoTypes = 32
+ DomainGuestInfoInterfaces DomainGuestInfoTypes = 64
+)
+
+// DomainAgentResponseTimeoutValues as declared in libvirt/libvirt-domain.h:5197
+type DomainAgentResponseTimeoutValues int32
+
+// DomainAgentResponseTimeoutValues enumeration from libvirt/libvirt-domain.h:5197
+const (
+ DomainAgentResponseTimeoutBlock DomainAgentResponseTimeoutValues = -2
+ DomainAgentResponseTimeoutDefault DomainAgentResponseTimeoutValues = -1
+ DomainAgentResponseTimeoutNowait DomainAgentResponseTimeoutValues = 0
+)
+
+// DomainBackupBeginFlags as declared in libvirt/libvirt-domain.h:5206
+type DomainBackupBeginFlags int32
+
+// DomainBackupBeginFlags enumeration from libvirt/libvirt-domain.h:5206
+const (
+ DomainBackupBeginReuseExternal DomainBackupBeginFlags = 1
+)
+
+// DomainAuthorizedSSHKeysSetFlags as declared in libvirt/libvirt-domain.h:5225
+type DomainAuthorizedSSHKeysSetFlags int32
+
+// DomainAuthorizedSSHKeysSetFlags enumeration from libvirt/libvirt-domain.h:5225
+const (
+ DomainAuthorizedSSHKeysSetAppend DomainAuthorizedSSHKeysSetFlags = 1
+ DomainAuthorizedSSHKeysSetRemove DomainAuthorizedSSHKeysSetFlags = 2
+)
+
+// DomainMessageType as declared in libvirt/libvirt-domain.h:5236
+type DomainMessageType int32
+
+// DomainMessageType enumeration from libvirt/libvirt-domain.h:5236
+const (
+ DomainMessageDeprecation DomainMessageType = 1
+ DomainMessageTainting DomainMessageType = 2
+)
+
+// DomainDirtyRateStatus as declared in libvirt/libvirt-domain.h:5258
+type DomainDirtyRateStatus int32
+
+// DomainDirtyRateStatus enumeration from libvirt/libvirt-domain.h:5258
+const (
+ DomainDirtyrateUnstarted DomainDirtyRateStatus = iota
+ DomainDirtyrateMeasuring DomainDirtyRateStatus = 1
+ DomainDirtyrateMeasured DomainDirtyRateStatus = 2
+)
+
+// DomainCheckpointCreateFlags as declared in libvirt/libvirt-domain-checkpoint.h:62
+type DomainCheckpointCreateFlags int32
+
+// DomainCheckpointCreateFlags enumeration from libvirt/libvirt-domain-checkpoint.h:62
+const (
+ DomainCheckpointCreateRedefine DomainCheckpointCreateFlags = 1
+ DomainCheckpointCreateQuiesce DomainCheckpointCreateFlags = 2
+ DomainCheckpointCreateRedefineValidate DomainCheckpointCreateFlags = 4
+)
+
+// DomainCheckpointXMLFlags as declared in libvirt/libvirt-domain-checkpoint.h:75
+type DomainCheckpointXMLFlags int32
+
+// DomainCheckpointXMLFlags enumeration from libvirt/libvirt-domain-checkpoint.h:75
+const (
+ DomainCheckpointXMLSecure DomainCheckpointXMLFlags = 1
+ DomainCheckpointXMLNoDomain DomainCheckpointXMLFlags = 2
+ DomainCheckpointXMLSize DomainCheckpointXMLFlags = 4
+)
+
+// DomainCheckpointListFlags as declared in libvirt/libvirt-domain-checkpoint.h:105
+type DomainCheckpointListFlags int32
+
+// DomainCheckpointListFlags enumeration from libvirt/libvirt-domain-checkpoint.h:105
+const (
+ DomainCheckpointListRoots DomainCheckpointListFlags = 1
+ DomainCheckpointListDescendants DomainCheckpointListFlags = 1
+ DomainCheckpointListTopological DomainCheckpointListFlags = 2
+ DomainCheckpointListLeaves DomainCheckpointListFlags = 4
+ DomainCheckpointListNoLeaves DomainCheckpointListFlags = 8
+)
+
+// DomainCheckpointDeleteFlags as declared in libvirt/libvirt-domain-checkpoint.h:131
+type DomainCheckpointDeleteFlags int32
+
+// DomainCheckpointDeleteFlags enumeration from libvirt/libvirt-domain-checkpoint.h:131
+const (
+ DomainCheckpointDeleteChildren DomainCheckpointDeleteFlags = 1
+ DomainCheckpointDeleteMetadataOnly DomainCheckpointDeleteFlags = 2
+ DomainCheckpointDeleteChildrenOnly DomainCheckpointDeleteFlags = 4
+)
+
+// DomainSnapshotCreateFlags as declared in libvirt/libvirt-domain-snapshot.h:76
+type DomainSnapshotCreateFlags int32
+
+// DomainSnapshotCreateFlags enumeration from libvirt/libvirt-domain-snapshot.h:76
+const (
+ DomainSnapshotCreateRedefine DomainSnapshotCreateFlags = 1
+ DomainSnapshotCreateCurrent DomainSnapshotCreateFlags = 2
+ DomainSnapshotCreateNoMetadata DomainSnapshotCreateFlags = 4
+ DomainSnapshotCreateHalt DomainSnapshotCreateFlags = 8
+ DomainSnapshotCreateDiskOnly DomainSnapshotCreateFlags = 16
+ DomainSnapshotCreateReuseExt DomainSnapshotCreateFlags = 32
+ DomainSnapshotCreateQuiesce DomainSnapshotCreateFlags = 64
+ DomainSnapshotCreateAtomic DomainSnapshotCreateFlags = 128
+ DomainSnapshotCreateLive DomainSnapshotCreateFlags = 256
+ DomainSnapshotCreateValidate DomainSnapshotCreateFlags = 512
+)
+
+// DomainSnapshotXMLFlags as declared in libvirt/libvirt-domain-snapshot.h:85
+type DomainSnapshotXMLFlags int32
+
+// DomainSnapshotXMLFlags enumeration from libvirt/libvirt-domain-snapshot.h:85
+const (
+ DomainSnapshotXMLSecure DomainSnapshotXMLFlags = 1
+)
+
+// DomainSnapshotListFlags as declared in libvirt/libvirt-domain-snapshot.h:144
+type DomainSnapshotListFlags int32
+
+// DomainSnapshotListFlags enumeration from libvirt/libvirt-domain-snapshot.h:144
+const (
+ DomainSnapshotListRoots DomainSnapshotListFlags = 1
+ DomainSnapshotListDescendants DomainSnapshotListFlags = 1
+ DomainSnapshotListLeaves DomainSnapshotListFlags = 4
+ DomainSnapshotListNoLeaves DomainSnapshotListFlags = 8
+ DomainSnapshotListMetadata DomainSnapshotListFlags = 2
+ DomainSnapshotListNoMetadata DomainSnapshotListFlags = 16
+ DomainSnapshotListInactive DomainSnapshotListFlags = 32
+ DomainSnapshotListActive DomainSnapshotListFlags = 64
+ DomainSnapshotListDiskOnly DomainSnapshotListFlags = 128
+ DomainSnapshotListInternal DomainSnapshotListFlags = 256
+ DomainSnapshotListExternal DomainSnapshotListFlags = 512
+ DomainSnapshotListTopological DomainSnapshotListFlags = 1024
+)
+
+// DomainSnapshotRevertFlags as declared in libvirt/libvirt-domain-snapshot.h:201
+type DomainSnapshotRevertFlags int32
+
+// DomainSnapshotRevertFlags enumeration from libvirt/libvirt-domain-snapshot.h:201
+const (
+ DomainSnapshotRevertRunning DomainSnapshotRevertFlags = 1
+ DomainSnapshotRevertPaused DomainSnapshotRevertFlags = 2
+ DomainSnapshotRevertForce DomainSnapshotRevertFlags = 4
+)
+
+// DomainSnapshotDeleteFlags as declared in libvirt/libvirt-domain-snapshot.h:215
+type DomainSnapshotDeleteFlags int32
+
+// DomainSnapshotDeleteFlags enumeration from libvirt/libvirt-domain-snapshot.h:215
+const (
+ DomainSnapshotDeleteChildren DomainSnapshotDeleteFlags = 1
+ DomainSnapshotDeleteMetadataOnly DomainSnapshotDeleteFlags = 2
+ DomainSnapshotDeleteChildrenOnly DomainSnapshotDeleteFlags = 4
+)
+
+// EventHandleType as declared in libvirt/libvirt-event.h:43
+type EventHandleType int32
+
+// EventHandleType enumeration from libvirt/libvirt-event.h:43
+const (
+ EventHandleReadable EventHandleType = 1
+ EventHandleWritable EventHandleType = 2
+ EventHandleError EventHandleType = 4
+ EventHandleHangup EventHandleType = 8
+)
+
+// ConnectListAllInterfacesFlags as declared in libvirt/libvirt-interface.h:64
+type ConnectListAllInterfacesFlags int32
+
+// ConnectListAllInterfacesFlags enumeration from libvirt/libvirt-interface.h:64
+const (
+ ConnectListInterfacesInactive ConnectListAllInterfacesFlags = 1
+ ConnectListInterfacesActive ConnectListAllInterfacesFlags = 2
+)
+
+// InterfaceXMLFlags as declared in libvirt/libvirt-interface.h:80
+type InterfaceXMLFlags int32
+
+// InterfaceXMLFlags enumeration from libvirt/libvirt-interface.h:80
+const (
+ InterfaceXMLInactive InterfaceXMLFlags = 1
+)
+
+// InterfaceDefineFlags as declared in libvirt/libvirt-interface.h:84
+type InterfaceDefineFlags int32
+
+// InterfaceDefineFlags enumeration from libvirt/libvirt-interface.h:84
+const (
+ InterfaceDefineValidate InterfaceDefineFlags = 1
+)
+
+// NetworkXMLFlags as declared in libvirt/libvirt-network.h:32
+type NetworkXMLFlags int32
+
+// NetworkXMLFlags enumeration from libvirt/libvirt-network.h:32
+const (
+ NetworkXMLInactive NetworkXMLFlags = 1
+)
+
+// ConnectListAllNetworksFlags as declared in libvirt/libvirt-network.h:100
+type ConnectListAllNetworksFlags int32
+
+// ConnectListAllNetworksFlags enumeration from libvirt/libvirt-network.h:100
+const (
+ ConnectListNetworksInactive ConnectListAllNetworksFlags = 1
+ ConnectListNetworksActive ConnectListAllNetworksFlags = 2
+ ConnectListNetworksPersistent ConnectListAllNetworksFlags = 4
+ ConnectListNetworksTransient ConnectListAllNetworksFlags = 8
+ ConnectListNetworksAutostart ConnectListAllNetworksFlags = 16
+ ConnectListNetworksNoAutostart ConnectListAllNetworksFlags = 32
+)
+
+// NetworkCreateFlags as declared in libvirt/libvirt-network.h:118
+type NetworkCreateFlags int32
+
+// NetworkCreateFlags enumeration from libvirt/libvirt-network.h:118
+const (
+ NetworkCreateValidate NetworkCreateFlags = 1
+)
+
+// NetworkDefineFlags as declared in libvirt/libvirt-network.h:131
+type NetworkDefineFlags int32
+
+// NetworkDefineFlags enumeration from libvirt/libvirt-network.h:131
+const (
+ NetworkDefineValidate NetworkDefineFlags = 1
+)
+
+// NetworkUpdateCommand as declared in libvirt/libvirt-network.h:163
+type NetworkUpdateCommand int32
+
+// NetworkUpdateCommand enumeration from libvirt/libvirt-network.h:163
+const (
+ NetworkUpdateCommandNone NetworkUpdateCommand = iota
+ NetworkUpdateCommandModify NetworkUpdateCommand = 1
+ NetworkUpdateCommandDelete NetworkUpdateCommand = 2
+ NetworkUpdateCommandAddLast NetworkUpdateCommand = 3
+ NetworkUpdateCommandAddFirst NetworkUpdateCommand = 4
+)
+
+// NetworkUpdateSection as declared in libvirt/libvirt-network.h:189
+type NetworkUpdateSection int32
+
+// NetworkUpdateSection enumeration from libvirt/libvirt-network.h:189
+const (
+ NetworkSectionNone NetworkUpdateSection = iota
+ NetworkSectionBridge NetworkUpdateSection = 1
+ NetworkSectionDomain NetworkUpdateSection = 2
+ NetworkSectionIP NetworkUpdateSection = 3
+ NetworkSectionIPDhcpHost NetworkUpdateSection = 4
+ NetworkSectionIPDhcpRange NetworkUpdateSection = 5
+ NetworkSectionForward NetworkUpdateSection = 6
+ NetworkSectionForwardInterface NetworkUpdateSection = 7
+ NetworkSectionForwardPf NetworkUpdateSection = 8
+ NetworkSectionPortgroup NetworkUpdateSection = 9
+ NetworkSectionDNSHost NetworkUpdateSection = 10
+ NetworkSectionDNSTxt NetworkUpdateSection = 11
+ NetworkSectionDNSSrv NetworkUpdateSection = 12
+)
+
+// NetworkUpdateFlags as declared in libvirt/libvirt-network.h:201
+type NetworkUpdateFlags int32
+
+// NetworkUpdateFlags enumeration from libvirt/libvirt-network.h:201
+const (
+ NetworkUpdateAffectCurrent NetworkUpdateFlags = iota
+ NetworkUpdateAffectLive NetworkUpdateFlags = 1
+ NetworkUpdateAffectConfig NetworkUpdateFlags = 2
+)
+
+// NetworkEventLifecycleType as declared in libvirt/libvirt-network.h:259
+type NetworkEventLifecycleType int32
+
+// NetworkEventLifecycleType enumeration from libvirt/libvirt-network.h:259
+const (
+ NetworkEventDefined NetworkEventLifecycleType = iota
+ NetworkEventUndefined NetworkEventLifecycleType = 1
+ NetworkEventStarted NetworkEventLifecycleType = 2
+ NetworkEventStopped NetworkEventLifecycleType = 3
+)
+
+// NetworkEventID as declared in libvirt/libvirt-network.h:307
+type NetworkEventID int32
+
+// NetworkEventID enumeration from libvirt/libvirt-network.h:307
+const (
+ NetworkEventIDLifecycle NetworkEventID = iota
+)
+
+// IPAddrType as declared in libvirt/libvirt-network.h:316
+type IPAddrType int32
+
+// IPAddrType enumeration from libvirt/libvirt-network.h:316
+const (
+ IPAddrTypeIpv4 IPAddrType = iota
+ IPAddrTypeIpv6 IPAddrType = 1
+)
+
+// NetworkPortCreateFlags as declared in libvirt/libvirt-network.h:378
+type NetworkPortCreateFlags int32
+
+// NetworkPortCreateFlags enumeration from libvirt/libvirt-network.h:378
+const (
+ NetworkPortCreateReclaim NetworkPortCreateFlags = 1
+ NetworkPortCreateValidate NetworkPortCreateFlags = 2
+)
+
+// ConnectListAllNodeDeviceFlags as declared in libvirt/libvirt-nodedev.h:92
+type ConnectListAllNodeDeviceFlags int32
+
+// ConnectListAllNodeDeviceFlags enumeration from libvirt/libvirt-nodedev.h:92
+const (
+ ConnectListNodeDevicesCapSystem ConnectListAllNodeDeviceFlags = 1
+ ConnectListNodeDevicesCapPciDev ConnectListAllNodeDeviceFlags = 2
+ ConnectListNodeDevicesCapUsbDev ConnectListAllNodeDeviceFlags = 4
+ ConnectListNodeDevicesCapUsbInterface ConnectListAllNodeDeviceFlags = 8
+ ConnectListNodeDevicesCapNet ConnectListAllNodeDeviceFlags = 16
+ ConnectListNodeDevicesCapScsiHost ConnectListAllNodeDeviceFlags = 32
+ ConnectListNodeDevicesCapScsiTarget ConnectListAllNodeDeviceFlags = 64
+ ConnectListNodeDevicesCapScsi ConnectListAllNodeDeviceFlags = 128
+ ConnectListNodeDevicesCapStorage ConnectListAllNodeDeviceFlags = 256
+ ConnectListNodeDevicesCapFcHost ConnectListAllNodeDeviceFlags = 512
+ ConnectListNodeDevicesCapVports ConnectListAllNodeDeviceFlags = 1024
+ ConnectListNodeDevicesCapScsiGeneric ConnectListAllNodeDeviceFlags = 2048
+ ConnectListNodeDevicesCapDrm ConnectListAllNodeDeviceFlags = 4096
+ ConnectListNodeDevicesCapMdevTypes ConnectListAllNodeDeviceFlags = 8192
+ ConnectListNodeDevicesCapMdev ConnectListAllNodeDeviceFlags = 16384
+ ConnectListNodeDevicesCapCcwDev ConnectListAllNodeDeviceFlags = 32768
+ ConnectListNodeDevicesCapCssDev ConnectListAllNodeDeviceFlags = 65536
+ ConnectListNodeDevicesCapVdpa ConnectListAllNodeDeviceFlags = 131072
+ ConnectListNodeDevicesCapApCard ConnectListAllNodeDeviceFlags = 262144
+ ConnectListNodeDevicesCapApQueue ConnectListAllNodeDeviceFlags = 524288
+ ConnectListNodeDevicesCapApMatrix ConnectListAllNodeDeviceFlags = 1048576
+ ConnectListNodeDevicesCapVpd ConnectListAllNodeDeviceFlags = 2097152
+ ConnectListNodeDevicesInactive ConnectListAllNodeDeviceFlags = 1073741824
+ ConnectListNodeDevicesActive ConnectListAllNodeDeviceFlags = -2147483648
+)
+
+// NodeDeviceEventID as declared in libvirt/libvirt-nodedev.h:182
+type NodeDeviceEventID int32
+
+// NodeDeviceEventID enumeration from libvirt/libvirt-nodedev.h:182
+const (
+ NodeDeviceEventIDLifecycle NodeDeviceEventID = iota
+ NodeDeviceEventIDUpdate NodeDeviceEventID = 1
+)
+
+// NodeDeviceEventLifecycleType as declared in libvirt/libvirt-nodedev.h:226
+type NodeDeviceEventLifecycleType int32
+
+// NodeDeviceEventLifecycleType enumeration from libvirt/libvirt-nodedev.h:226
+const (
+ NodeDeviceEventCreated NodeDeviceEventLifecycleType = iota
+ NodeDeviceEventDeleted NodeDeviceEventLifecycleType = 1
+ NodeDeviceEventDefined NodeDeviceEventLifecycleType = 2
+ NodeDeviceEventUndefined NodeDeviceEventLifecycleType = 3
+)
+
+// NWFilterDefineFlags as declared in libvirt/libvirt-nwfilter.h:85
+type NWFilterDefineFlags int32
+
+// NWFilterDefineFlags enumeration from libvirt/libvirt-nwfilter.h:85
+const (
+ NwfilterDefineValidate NWFilterDefineFlags = 1
+)
+
+// NWFilterBindingCreateFlags as declared in libvirt/libvirt-nwfilter.h:113
+type NWFilterBindingCreateFlags int32
+
+// NWFilterBindingCreateFlags enumeration from libvirt/libvirt-nwfilter.h:113
+const (
+ NwfilterBindingCreateValidate NWFilterBindingCreateFlags = 1
+)
+
+// SecretUsageType as declared in libvirt/libvirt-secret.h:56
+type SecretUsageType int32
+
+// SecretUsageType enumeration from libvirt/libvirt-secret.h:56
+const (
+ SecretUsageTypeNone SecretUsageType = iota
+ SecretUsageTypeVolume SecretUsageType = 1
+ SecretUsageTypeCeph SecretUsageType = 2
+ SecretUsageTypeIscsi SecretUsageType = 3
+ SecretUsageTypeTLS SecretUsageType = 4
+ SecretUsageTypeVtpm SecretUsageType = 5
+)
+
+// ConnectListAllSecretsFlags as declared in libvirt/libvirt-secret.h:79
+type ConnectListAllSecretsFlags int32
+
+// ConnectListAllSecretsFlags enumeration from libvirt/libvirt-secret.h:79
+const (
+ ConnectListSecretsEphemeral ConnectListAllSecretsFlags = 1
+ ConnectListSecretsNoEphemeral ConnectListAllSecretsFlags = 2
+ ConnectListSecretsPrivate ConnectListAllSecretsFlags = 4
+ ConnectListSecretsNoPrivate ConnectListAllSecretsFlags = 8
+)
+
+// SecretDefineFlags as declared in libvirt/libvirt-secret.h:94
+type SecretDefineFlags int32
+
+// SecretDefineFlags enumeration from libvirt/libvirt-secret.h:94
+const (
+ SecretDefineValidate SecretDefineFlags = 1
+)
+
+// SecretEventID as declared in libvirt/libvirt-secret.h:145
+type SecretEventID int32
+
+// SecretEventID enumeration from libvirt/libvirt-secret.h:145
+const (
+ SecretEventIDLifecycle SecretEventID = iota
+ SecretEventIDValueChanged SecretEventID = 1
+)
+
+// SecretEventLifecycleType as declared in libvirt/libvirt-secret.h:187
+type SecretEventLifecycleType int32
+
+// SecretEventLifecycleType enumeration from libvirt/libvirt-secret.h:187
+const (
+ SecretEventDefined SecretEventLifecycleType = iota
+ SecretEventUndefined SecretEventLifecycleType = 1
+)
+
+// StoragePoolState as declared in libvirt/libvirt-storage.h:57
+type StoragePoolState int32
+
+// StoragePoolState enumeration from libvirt/libvirt-storage.h:57
+const (
+ StoragePoolInactive StoragePoolState = iota
+ StoragePoolBuilding StoragePoolState = 1
+ StoragePoolRunning StoragePoolState = 2
+ StoragePoolDegraded StoragePoolState = 3
+ StoragePoolInaccessible StoragePoolState = 4
+)
+
+// StoragePoolBuildFlags as declared in libvirt/libvirt-storage.h:65
+type StoragePoolBuildFlags int32
+
+// StoragePoolBuildFlags enumeration from libvirt/libvirt-storage.h:65
+const (
+ StoragePoolBuildNew StoragePoolBuildFlags = iota
+ StoragePoolBuildRepair StoragePoolBuildFlags = 1
+ StoragePoolBuildResize StoragePoolBuildFlags = 2
+ StoragePoolBuildNoOverwrite StoragePoolBuildFlags = 4
+ StoragePoolBuildOverwrite StoragePoolBuildFlags = 8
+)
+
+// StoragePoolDeleteFlags as declared in libvirt/libvirt-storage.h:70
+type StoragePoolDeleteFlags int32
+
+// StoragePoolDeleteFlags enumeration from libvirt/libvirt-storage.h:70
+const (
+ StoragePoolDeleteNormal StoragePoolDeleteFlags = iota
+ StoragePoolDeleteZeroed StoragePoolDeleteFlags = 1
+)
+
+// StoragePoolCreateFlags as declared in libvirt/libvirt-storage.h:88
+type StoragePoolCreateFlags int32
+
+// StoragePoolCreateFlags enumeration from libvirt/libvirt-storage.h:88
+const (
+ StoragePoolCreateNormal StoragePoolCreateFlags = iota
+ StoragePoolCreateWithBuild StoragePoolCreateFlags = 1
+ StoragePoolCreateWithBuildOverwrite StoragePoolCreateFlags = 2
+ StoragePoolCreateWithBuildNoOverwrite StoragePoolCreateFlags = 4
+)
+
+// StorageVolType as declared in libvirt/libvirt-storage.h:130
+type StorageVolType int32
+
+// StorageVolType enumeration from libvirt/libvirt-storage.h:130
+const (
+ StorageVolFile StorageVolType = iota
+ StorageVolBlock StorageVolType = 1
+ StorageVolDir StorageVolType = 2
+ StorageVolNetwork StorageVolType = 3
+ StorageVolNetdir StorageVolType = 4
+ StorageVolPloop StorageVolType = 5
+)
+
+// StorageVolDeleteFlags as declared in libvirt/libvirt-storage.h:136
+type StorageVolDeleteFlags int32
+
+// StorageVolDeleteFlags enumeration from libvirt/libvirt-storage.h:136
+const (
+ StorageVolDeleteNormal StorageVolDeleteFlags = iota
+ StorageVolDeleteZeroed StorageVolDeleteFlags = 1
+ StorageVolDeleteWithSnapshots StorageVolDeleteFlags = 2
+)
+
+// StorageVolWipeAlgorithm as declared in libvirt/libvirt-storage.h:168
+type StorageVolWipeAlgorithm int32
+
+// StorageVolWipeAlgorithm enumeration from libvirt/libvirt-storage.h:168
+const (
+ StorageVolWipeAlgZero StorageVolWipeAlgorithm = iota
+ StorageVolWipeAlgNnsa StorageVolWipeAlgorithm = 1
+ StorageVolWipeAlgDod StorageVolWipeAlgorithm = 2
+ StorageVolWipeAlgBsi StorageVolWipeAlgorithm = 3
+ StorageVolWipeAlgGutmann StorageVolWipeAlgorithm = 4
+ StorageVolWipeAlgSchneier StorageVolWipeAlgorithm = 5
+ StorageVolWipeAlgPfitzner7 StorageVolWipeAlgorithm = 6
+ StorageVolWipeAlgPfitzner33 StorageVolWipeAlgorithm = 7
+ StorageVolWipeAlgRandom StorageVolWipeAlgorithm = 8
+ StorageVolWipeAlgTrim StorageVolWipeAlgorithm = 9
+)
+
+// StorageVolInfoFlags as declared in libvirt/libvirt-storage.h:176
+type StorageVolInfoFlags int32
+
+// StorageVolInfoFlags enumeration from libvirt/libvirt-storage.h:176
+const (
+ StorageVolUseAllocation StorageVolInfoFlags = iota
+ StorageVolGetPhysical StorageVolInfoFlags = 1
+)
+
+// StorageXMLFlags as declared in libvirt/libvirt-storage.h:190
+type StorageXMLFlags int32
+
+// StorageXMLFlags enumeration from libvirt/libvirt-storage.h:190
+const (
+ StorageXMLInactive StorageXMLFlags = 1
+)
+
+// ConnectListAllStoragePoolsFlags as declared in libvirt/libvirt-storage.h:249
+type ConnectListAllStoragePoolsFlags int32
+
+// ConnectListAllStoragePoolsFlags enumeration from libvirt/libvirt-storage.h:249
+const (
+ ConnectListStoragePoolsInactive ConnectListAllStoragePoolsFlags = 1
+ ConnectListStoragePoolsActive ConnectListAllStoragePoolsFlags = 2
+ ConnectListStoragePoolsPersistent ConnectListAllStoragePoolsFlags = 4
+ ConnectListStoragePoolsTransient ConnectListAllStoragePoolsFlags = 8
+ ConnectListStoragePoolsAutostart ConnectListAllStoragePoolsFlags = 16
+ ConnectListStoragePoolsNoAutostart ConnectListAllStoragePoolsFlags = 32
+ ConnectListStoragePoolsDir ConnectListAllStoragePoolsFlags = 64
+ ConnectListStoragePoolsFs ConnectListAllStoragePoolsFlags = 128
+ ConnectListStoragePoolsNetfs ConnectListAllStoragePoolsFlags = 256
+ ConnectListStoragePoolsLogical ConnectListAllStoragePoolsFlags = 512
+ ConnectListStoragePoolsDisk ConnectListAllStoragePoolsFlags = 1024
+ ConnectListStoragePoolsIscsi ConnectListAllStoragePoolsFlags = 2048
+ ConnectListStoragePoolsScsi ConnectListAllStoragePoolsFlags = 4096
+ ConnectListStoragePoolsMpath ConnectListAllStoragePoolsFlags = 8192
+ ConnectListStoragePoolsRbd ConnectListAllStoragePoolsFlags = 16384
+ ConnectListStoragePoolsSheepdog ConnectListAllStoragePoolsFlags = 32768
+ ConnectListStoragePoolsGluster ConnectListAllStoragePoolsFlags = 65536
+ ConnectListStoragePoolsZfs ConnectListAllStoragePoolsFlags = 131072
+ ConnectListStoragePoolsVstorage ConnectListAllStoragePoolsFlags = 262144
+ ConnectListStoragePoolsIscsiDirect ConnectListAllStoragePoolsFlags = 524288
+)
+
+// StoragePoolDefineFlags as declared in libvirt/libvirt-storage.h:277
+type StoragePoolDefineFlags int32
+
+// StoragePoolDefineFlags enumeration from libvirt/libvirt-storage.h:277
+const (
+ StoragePoolDefineValidate StoragePoolDefineFlags = 1
+)
+
+// StorageVolCreateFlags as declared in libvirt/libvirt-storage.h:351
+type StorageVolCreateFlags int32
+
+// StorageVolCreateFlags enumeration from libvirt/libvirt-storage.h:351
+const (
+ StorageVolCreatePreallocMetadata StorageVolCreateFlags = 1
+ StorageVolCreateReflink StorageVolCreateFlags = 2
+)
+
+// StorageVolDownloadFlags as declared in libvirt/libvirt-storage.h:363
+type StorageVolDownloadFlags int32
+
+// StorageVolDownloadFlags enumeration from libvirt/libvirt-storage.h:363
+const (
+ StorageVolDownloadSparseStream StorageVolDownloadFlags = 1
+)
+
+// StorageVolUploadFlags as declared in libvirt/libvirt-storage.h:372
+type StorageVolUploadFlags int32
+
+// StorageVolUploadFlags enumeration from libvirt/libvirt-storage.h:372
+const (
+ StorageVolUploadSparseStream StorageVolUploadFlags = 1
+)
+
+// StorageVolResizeFlags as declared in libvirt/libvirt-storage.h:403
+type StorageVolResizeFlags int32
+
+// StorageVolResizeFlags enumeration from libvirt/libvirt-storage.h:403
+const (
+ StorageVolResizeAllocate StorageVolResizeFlags = 1
+ StorageVolResizeDelta StorageVolResizeFlags = 2
+ StorageVolResizeShrink StorageVolResizeFlags = 4
+)
+
+// StoragePoolEventID as declared in libvirt/libvirt-storage.h:439
+type StoragePoolEventID int32
+
+// StoragePoolEventID enumeration from libvirt/libvirt-storage.h:439
+const (
+ StoragePoolEventIDLifecycle StoragePoolEventID = iota
+ StoragePoolEventIDRefresh StoragePoolEventID = 1
+)
+
+// StoragePoolEventLifecycleType as declared in libvirt/libvirt-storage.h:485
+type StoragePoolEventLifecycleType int32
+
+// StoragePoolEventLifecycleType enumeration from libvirt/libvirt-storage.h:485
+const (
+ StoragePoolEventDefined StoragePoolEventLifecycleType = iota
+ StoragePoolEventUndefined StoragePoolEventLifecycleType = 1
+ StoragePoolEventStarted StoragePoolEventLifecycleType = 2
+ StoragePoolEventStopped StoragePoolEventLifecycleType = 3
+ StoragePoolEventCreated StoragePoolEventLifecycleType = 4
+ StoragePoolEventDeleted StoragePoolEventLifecycleType = 5
+)
+
+// StreamFlags as declared in libvirt/libvirt-stream.h:33
+type StreamFlags int32
+
+// StreamFlags enumeration from libvirt/libvirt-stream.h:33
+const (
+ StreamNonblock StreamFlags = 1
+)
+
+// StreamRecvFlagsValues as declared in libvirt/libvirt-stream.h:49
+type StreamRecvFlagsValues int32
+
+// StreamRecvFlagsValues enumeration from libvirt/libvirt-stream.h:49
+const (
+ StreamRecvStopAtHole StreamRecvFlagsValues = 1
+)
+
+// StreamEventType as declared in libvirt/libvirt-stream.h:237
+type StreamEventType int32
+
+// StreamEventType enumeration from libvirt/libvirt-stream.h:237
+const (
+ StreamEventReadable StreamEventType = 1
+ StreamEventWritable StreamEventType = 2
+ StreamEventError StreamEventType = 4
+ StreamEventHangup StreamEventType = 8
+)
+
+// ErrorLevel as declared in libvirt/virterror.h:42
+type ErrorLevel int32
+
+// ErrorLevel enumeration from libvirt/virterror.h:42
+const (
+ ErrNone ErrorLevel = iota
+ ErrWarning ErrorLevel = 1
+ ErrError ErrorLevel = 2
+)
+
+// ErrorDomain as declared in libvirt/virterror.h:144
+type ErrorDomain int32
+
+// ErrorDomain enumeration from libvirt/virterror.h:144
+const (
+ fromNone ErrorDomain = iota
+ fromXen ErrorDomain = 1
+ fromXend ErrorDomain = 2
+ fromXenstore ErrorDomain = 3
+ fromSexpr ErrorDomain = 4
+ fromXML ErrorDomain = 5
+ fromDom ErrorDomain = 6
+ fromRPC ErrorDomain = 7
+ fromProxy ErrorDomain = 8
+ fromConf ErrorDomain = 9
+ fromQemu ErrorDomain = 10
+ fromNet ErrorDomain = 11
+ fromTest ErrorDomain = 12
+ fromRemote ErrorDomain = 13
+ fromOpenvz ErrorDomain = 14
+ fromXenxm ErrorDomain = 15
+ fromStatsLinux ErrorDomain = 16
+ fromLxc ErrorDomain = 17
+ fromStorage ErrorDomain = 18
+ fromNetwork ErrorDomain = 19
+ fromDomain ErrorDomain = 20
+ fromUml ErrorDomain = 21
+ fromNodedev ErrorDomain = 22
+ fromXenInotify ErrorDomain = 23
+ fromSecurity ErrorDomain = 24
+ fromVbox ErrorDomain = 25
+ fromInterface ErrorDomain = 26
+ fromOne ErrorDomain = 27
+ fromEsx ErrorDomain = 28
+ fromPhyp ErrorDomain = 29
+ fromSecret ErrorDomain = 30
+ fromCPU ErrorDomain = 31
+ fromXenapi ErrorDomain = 32
+ fromNwfilter ErrorDomain = 33
+ fromHook ErrorDomain = 34
+ fromDomainSnapshot ErrorDomain = 35
+ fromAudit ErrorDomain = 36
+ fromSysinfo ErrorDomain = 37
+ fromStreams ErrorDomain = 38
+ fromVmware ErrorDomain = 39
+ fromEvent ErrorDomain = 40
+ fromLibxl ErrorDomain = 41
+ fromLocking ErrorDomain = 42
+ fromHyperv ErrorDomain = 43
+ fromCapabilities ErrorDomain = 44
+ fromURI ErrorDomain = 45
+ fromAuth ErrorDomain = 46
+ fromDbus ErrorDomain = 47
+ fromParallels ErrorDomain = 48
+ fromDevice ErrorDomain = 49
+ fromSSH ErrorDomain = 50
+ fromLockspace ErrorDomain = 51
+ fromInitctl ErrorDomain = 52
+ fromIdentity ErrorDomain = 53
+ fromCgroup ErrorDomain = 54
+ fromAccess ErrorDomain = 55
+ fromSystemd ErrorDomain = 56
+ fromBhyve ErrorDomain = 57
+ fromCrypto ErrorDomain = 58
+ fromFirewall ErrorDomain = 59
+ fromPolkit ErrorDomain = 60
+ fromThread ErrorDomain = 61
+ fromAdmin ErrorDomain = 62
+ fromLogging ErrorDomain = 63
+ fromXenxl ErrorDomain = 64
+ fromPerf ErrorDomain = 65
+ fromLibssh ErrorDomain = 66
+ fromResctrl ErrorDomain = 67
+ fromFirewalld ErrorDomain = 68
+ fromDomainCheckpoint ErrorDomain = 69
+ fromTpm ErrorDomain = 70
+ fromBpf ErrorDomain = 71
+ fromCh ErrorDomain = 72
+)
+
+// ErrorNumber as declared in libvirt/virterror.h:342
+type ErrorNumber int32
+
+// ErrorNumber enumeration from libvirt/virterror.h:342
+const (
+ ErrOk ErrorNumber = iota
+ ErrInternalError ErrorNumber = 1
+ ErrNoMemory ErrorNumber = 2
+ ErrNoSupport ErrorNumber = 3
+ ErrUnknownHost ErrorNumber = 4
+ ErrNoConnect ErrorNumber = 5
+ ErrInvalidConn ErrorNumber = 6
+ ErrInvalidDomain ErrorNumber = 7
+ ErrInvalidArg ErrorNumber = 8
+ ErrOperationFailed ErrorNumber = 9
+ ErrGetFailed ErrorNumber = 10
+ ErrPostFailed ErrorNumber = 11
+ ErrHTTPError ErrorNumber = 12
+ ErrSexprSerial ErrorNumber = 13
+ ErrNoXen ErrorNumber = 14
+ ErrXenCall ErrorNumber = 15
+ ErrOsType ErrorNumber = 16
+ ErrNoKernel ErrorNumber = 17
+ ErrNoRoot ErrorNumber = 18
+ ErrNoSource ErrorNumber = 19
+ ErrNoTarget ErrorNumber = 20
+ ErrNoName ErrorNumber = 21
+ ErrNoOs ErrorNumber = 22
+ ErrNoDevice ErrorNumber = 23
+ ErrNoXenstore ErrorNumber = 24
+ ErrDriverFull ErrorNumber = 25
+ ErrCallFailed ErrorNumber = 26
+ ErrXMLError ErrorNumber = 27
+ ErrDomExist ErrorNumber = 28
+ ErrOperationDenied ErrorNumber = 29
+ ErrOpenFailed ErrorNumber = 30
+ ErrReadFailed ErrorNumber = 31
+ ErrParseFailed ErrorNumber = 32
+ ErrConfSyntax ErrorNumber = 33
+ ErrWriteFailed ErrorNumber = 34
+ ErrXMLDetail ErrorNumber = 35
+ ErrInvalidNetwork ErrorNumber = 36
+ ErrNetworkExist ErrorNumber = 37
+ ErrSystemError ErrorNumber = 38
+ ErrRPC ErrorNumber = 39
+ ErrGnutlsError ErrorNumber = 40
+ WarNoNetwork ErrorNumber = 41
+ ErrNoDomain ErrorNumber = 42
+ ErrNoNetwork ErrorNumber = 43
+ ErrInvalidMac ErrorNumber = 44
+ ErrAuthFailed ErrorNumber = 45
+ ErrInvalidStoragePool ErrorNumber = 46
+ ErrInvalidStorageVol ErrorNumber = 47
+ WarNoStorage ErrorNumber = 48
+ ErrNoStoragePool ErrorNumber = 49
+ ErrNoStorageVol ErrorNumber = 50
+ WarNoNode ErrorNumber = 51
+ ErrInvalidNodeDevice ErrorNumber = 52
+ ErrNoNodeDevice ErrorNumber = 53
+ ErrNoSecurityModel ErrorNumber = 54
+ ErrOperationInvalid ErrorNumber = 55
+ WarNoInterface ErrorNumber = 56
+ ErrNoInterface ErrorNumber = 57
+ ErrInvalidInterface ErrorNumber = 58
+ ErrMultipleInterfaces ErrorNumber = 59
+ WarNoNwfilter ErrorNumber = 60
+ ErrInvalidNwfilter ErrorNumber = 61
+ ErrNoNwfilter ErrorNumber = 62
+ ErrBuildFirewall ErrorNumber = 63
+ WarNoSecret ErrorNumber = 64
+ ErrInvalidSecret ErrorNumber = 65
+ ErrNoSecret ErrorNumber = 66
+ ErrConfigUnsupported ErrorNumber = 67
+ ErrOperationTimeout ErrorNumber = 68
+ ErrMigratePersistFailed ErrorNumber = 69
+ ErrHookScriptFailed ErrorNumber = 70
+ ErrInvalidDomainSnapshot ErrorNumber = 71
+ ErrNoDomainSnapshot ErrorNumber = 72
+ ErrInvalidStream ErrorNumber = 73
+ ErrArgumentUnsupported ErrorNumber = 74
+ ErrStorageProbeFailed ErrorNumber = 75
+ ErrStoragePoolBuilt ErrorNumber = 76
+ ErrSnapshotRevertRisky ErrorNumber = 77
+ ErrOperationAborted ErrorNumber = 78
+ ErrAuthCancelled ErrorNumber = 79
+ ErrNoDomainMetadata ErrorNumber = 80
+ ErrMigrateUnsafe ErrorNumber = 81
+ ErrOverflow ErrorNumber = 82
+ ErrBlockCopyActive ErrorNumber = 83
+ ErrOperationUnsupported ErrorNumber = 84
+ ErrSSH ErrorNumber = 85
+ ErrAgentUnresponsive ErrorNumber = 86
+ ErrResourceBusy ErrorNumber = 87
+ ErrAccessDenied ErrorNumber = 88
+ ErrDbusService ErrorNumber = 89
+ ErrStorageVolExist ErrorNumber = 90
+ ErrCPUIncompatible ErrorNumber = 91
+ ErrXMLInvalidSchema ErrorNumber = 92
+ ErrMigrateFinishOk ErrorNumber = 93
+ ErrAuthUnavailable ErrorNumber = 94
+ ErrNoServer ErrorNumber = 95
+ ErrNoClient ErrorNumber = 96
+ ErrAgentUnsynced ErrorNumber = 97
+ ErrLibssh ErrorNumber = 98
+ ErrDeviceMissing ErrorNumber = 99
+ ErrInvalidNwfilterBinding ErrorNumber = 100
+ ErrNoNwfilterBinding ErrorNumber = 101
+ ErrInvalidDomainCheckpoint ErrorNumber = 102
+ ErrNoDomainCheckpoint ErrorNumber = 103
+ ErrNoDomainBackup ErrorNumber = 104
+ ErrInvalidNetworkPort ErrorNumber = 105
+ ErrNetworkPortExist ErrorNumber = 106
+ ErrNoNetworkPort ErrorNumber = 107
+ ErrNoHostname ErrorNumber = 108
+ ErrCheckpointInconsistent ErrorNumber = 109
+ ErrMultipleDomains ErrorNumber = 110
+)
diff --git a/third_party/libvirt/doc.go b/third_party/libvirt/doc.go
new file mode 100644
index 0000000..980818d
--- /dev/null
+++ b/third_party/libvirt/doc.go
@@ -0,0 +1,70 @@
+// 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 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/projecteru2/yavirt/third_party/libvirt"
+// )
+//
+// func main() {
+// // This dials libvirt on the local machine, but you can substitute the first
+// // two parameters with "tcp", ":" 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
diff --git a/third_party/libvirt/internal/constants/qemu_protocol.gen.go b/third_party/libvirt/internal/constants/qemu_protocol.gen.go
new file mode 100644
index 0000000..208986d
--- /dev/null
+++ b/third_party/libvirt/internal/constants/qemu_protocol.gen.go
@@ -0,0 +1,47 @@
+// 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
+
+// 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.
+const (
+ // From enums:
+ // QEMUProcDomainMonitorCommand is libvirt's QEMU_PROC_DOMAIN_MONITOR_COMMAND
+ QEMUProcDomainMonitorCommand = 1
+ // QEMUProcDomainAttach is libvirt's QEMU_PROC_DOMAIN_ATTACH
+ QEMUProcDomainAttach = 2
+ // QEMUProcDomainAgentCommand is libvirt's QEMU_PROC_DOMAIN_AGENT_COMMAND
+ QEMUProcDomainAgentCommand = 3
+ // QEMUProcConnectDomainMonitorEventRegister is libvirt's QEMU_PROC_CONNECT_DOMAIN_MONITOR_EVENT_REGISTER
+ QEMUProcConnectDomainMonitorEventRegister = 4
+ // QEMUProcConnectDomainMonitorEventDeregister is libvirt's QEMU_PROC_CONNECT_DOMAIN_MONITOR_EVENT_DEREGISTER
+ QEMUProcConnectDomainMonitorEventDeregister = 5
+ // QEMUProcDomainMonitorEvent is libvirt's QEMU_PROC_DOMAIN_MONITOR_EVENT
+ QEMUProcDomainMonitorEvent = 6
+
+
+ // From consts:
+ // QEMUProgram is libvirt's QEMU_PROGRAM
+ QEMUProgram = 0x20008087
+ // QEMUProtocolVersion is libvirt's QEMU_PROTOCOL_VERSION
+ QEMUProtocolVersion = 1
+)
diff --git a/third_party/libvirt/internal/constants/remote_protocol.gen.go b/third_party/libvirt/internal/constants/remote_protocol.gen.go
new file mode 100644
index 0000000..2afddde
--- /dev/null
+++ b/third_party/libvirt/internal/constants/remote_protocol.gen.go
@@ -0,0 +1,1051 @@
+// 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
+
+// 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.
+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
+ // ProcConnectGetStoragePoolCapabilities is libvirt's REMOTE_PROC_CONNECT_GET_STORAGE_POOL_CAPABILITIES
+ ProcConnectGetStoragePoolCapabilities = 403
+ // ProcNetworkListAllPorts is libvirt's REMOTE_PROC_NETWORK_LIST_ALL_PORTS
+ ProcNetworkListAllPorts = 404
+ // ProcNetworkPortLookupByUUID is libvirt's REMOTE_PROC_NETWORK_PORT_LOOKUP_BY_UUID
+ ProcNetworkPortLookupByUUID = 405
+ // ProcNetworkPortCreateXML is libvirt's REMOTE_PROC_NETWORK_PORT_CREATE_XML
+ ProcNetworkPortCreateXML = 406
+ // ProcNetworkPortGetParameters is libvirt's REMOTE_PROC_NETWORK_PORT_GET_PARAMETERS
+ ProcNetworkPortGetParameters = 407
+ // ProcNetworkPortSetParameters is libvirt's REMOTE_PROC_NETWORK_PORT_SET_PARAMETERS
+ ProcNetworkPortSetParameters = 408
+ // ProcNetworkPortGetXMLDesc is libvirt's REMOTE_PROC_NETWORK_PORT_GET_XML_DESC
+ ProcNetworkPortGetXMLDesc = 409
+ // ProcNetworkPortDelete is libvirt's REMOTE_PROC_NETWORK_PORT_DELETE
+ ProcNetworkPortDelete = 410
+ // ProcDomainCheckpointCreateXML is libvirt's REMOTE_PROC_DOMAIN_CHECKPOINT_CREATE_XML
+ ProcDomainCheckpointCreateXML = 411
+ // ProcDomainCheckpointGetXMLDesc is libvirt's REMOTE_PROC_DOMAIN_CHECKPOINT_GET_XML_DESC
+ ProcDomainCheckpointGetXMLDesc = 412
+ // ProcDomainListAllCheckpoints is libvirt's REMOTE_PROC_DOMAIN_LIST_ALL_CHECKPOINTS
+ ProcDomainListAllCheckpoints = 413
+ // ProcDomainCheckpointListAllChildren is libvirt's REMOTE_PROC_DOMAIN_CHECKPOINT_LIST_ALL_CHILDREN
+ ProcDomainCheckpointListAllChildren = 414
+ // ProcDomainCheckpointLookupByName is libvirt's REMOTE_PROC_DOMAIN_CHECKPOINT_LOOKUP_BY_NAME
+ ProcDomainCheckpointLookupByName = 415
+ // ProcDomainCheckpointGetParent is libvirt's REMOTE_PROC_DOMAIN_CHECKPOINT_GET_PARENT
+ ProcDomainCheckpointGetParent = 416
+ // ProcDomainCheckpointDelete is libvirt's REMOTE_PROC_DOMAIN_CHECKPOINT_DELETE
+ ProcDomainCheckpointDelete = 417
+ // ProcDomainGetGuestInfo is libvirt's REMOTE_PROC_DOMAIN_GET_GUEST_INFO
+ ProcDomainGetGuestInfo = 418
+ // ProcConnectSetIdentity is libvirt's REMOTE_PROC_CONNECT_SET_IDENTITY
+ ProcConnectSetIdentity = 419
+ // ProcDomainAgentSetResponseTimeout is libvirt's REMOTE_PROC_DOMAIN_AGENT_SET_RESPONSE_TIMEOUT
+ ProcDomainAgentSetResponseTimeout = 420
+ // ProcDomainBackupBegin is libvirt's REMOTE_PROC_DOMAIN_BACKUP_BEGIN
+ ProcDomainBackupBegin = 421
+ // ProcDomainBackupGetXMLDesc is libvirt's REMOTE_PROC_DOMAIN_BACKUP_GET_XML_DESC
+ ProcDomainBackupGetXMLDesc = 422
+ // ProcDomainEventMemoryFailure is libvirt's REMOTE_PROC_DOMAIN_EVENT_MEMORY_FAILURE
+ ProcDomainEventMemoryFailure = 423
+ // ProcDomainAuthorizedSshKeysGet is libvirt's REMOTE_PROC_DOMAIN_AUTHORIZED_SSH_KEYS_GET
+ 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
+ // ProcDomainStartDirtyRateCalc is libvirt's REMOTE_PROC_DOMAIN_START_DIRTY_RATE_CALC
+ ProcDomainStartDirtyRateCalc = 427
+ // ProcNodeDeviceDefineXML is libvirt's REMOTE_PROC_NODE_DEVICE_DEFINE_XML
+ ProcNodeDeviceDefineXML = 428
+ // ProcNodeDeviceUndefine is libvirt's REMOTE_PROC_NODE_DEVICE_UNDEFINE
+ ProcNodeDeviceUndefine = 429
+ // ProcNodeDeviceCreate is libvirt's REMOTE_PROC_NODE_DEVICE_CREATE
+ ProcNodeDeviceCreate = 430
+ // ProcNwfilterDefineXMLFlags is libvirt's REMOTE_PROC_NWFILTER_DEFINE_XML_FLAGS
+ ProcNwfilterDefineXMLFlags = 431
+ // ProcNetworkDefineXMLFlags is libvirt's REMOTE_PROC_NETWORK_DEFINE_XML_FLAGS
+ ProcNetworkDefineXMLFlags = 432
+ // ProcNodeDeviceGetAutostart is libvirt's REMOTE_PROC_NODE_DEVICE_GET_AUTOSTART
+ ProcNodeDeviceGetAutostart = 433
+ // ProcNodeDeviceSetAutostart is libvirt's REMOTE_PROC_NODE_DEVICE_SET_AUTOSTART
+ ProcNodeDeviceSetAutostart = 434
+ // ProcNodeDeviceIsPersistent is libvirt's REMOTE_PROC_NODE_DEVICE_IS_PERSISTENT
+ ProcNodeDeviceIsPersistent = 435
+ // ProcNodeDeviceIsActive is libvirt's REMOTE_PROC_NODE_DEVICE_IS_ACTIVE
+ ProcNodeDeviceIsActive = 436
+ // ProcNetworkCreateXMLFlags is libvirt's REMOTE_PROC_NETWORK_CREATE_XML_FLAGS
+ ProcNetworkCreateXMLFlags = 437
+ // ProcDomainEventMemoryDeviceSizeChange is libvirt's REMOTE_PROC_DOMAIN_EVENT_MEMORY_DEVICE_SIZE_CHANGE
+ ProcDomainEventMemoryDeviceSizeChange = 438
+ // ProcDomainSetLaunchSecurityState is libvirt's REMOTE_PROC_DOMAIN_SET_LAUNCH_SECURITY_STATE
+ ProcDomainSetLaunchSecurityState = 439
+
+
+ // From consts:
+ // StringMax is libvirt's REMOTE_STRING_MAX
+ StringMax = 4194304
+ // ConnectIdentityParamsMax is libvirt's REMOTE_CONNECT_IDENTITY_PARAMS_MAX
+ ConnectIdentityParamsMax = 20
+ // 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
+ // NetworkPortListMax is libvirt's REMOTE_NETWORK_PORT_LIST_MAX
+ NetworkPortListMax = 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
+ // DomainCheckpointListMax is libvirt's REMOTE_DOMAIN_CHECKPOINT_LIST_MAX
+ DomainCheckpointListMax = 16384
+ // 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
+ // DomainLaunchSecurityStateParamsMax is libvirt's REMOTE_DOMAIN_LAUNCH_SECURITY_STATE_PARAMS_MAX
+ DomainLaunchSecurityStateParamsMax = 64
+ // DomainGuestInfoParamsMax is libvirt's REMOTE_DOMAIN_GUEST_INFO_PARAMS_MAX
+ DomainGuestInfoParamsMax = 2048
+ // NetworkPortParametersMax is libvirt's REMOTE_NETWORK_PORT_PARAMETERS_MAX
+ 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
+ Program = 0x20008086
+ // ProtocolVersion is libvirt's REMOTE_PROTOCOL_VERSION
+ ProtocolVersion = 1
+)
diff --git a/third_party/libvirt/internal/event/event.go b/third_party/libvirt/internal/event/event.go
new file mode 100644
index 0000000..67a1885
--- /dev/null
+++ b/third_party/libvirt/internal/event/event.go
@@ -0,0 +1,20 @@
+// Copyright 2020 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 event
+
+// Event represents an internal Event.
+type Event interface {
+ GetCallbackID() int32
+}
diff --git a/third_party/libvirt/internal/event/stream.go b/third_party/libvirt/internal/event/stream.go
new file mode 100644
index 0000000..98ae269
--- /dev/null
+++ b/third_party/libvirt/internal/event/stream.go
@@ -0,0 +1,157 @@
+// Copyright 2020 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 event
+
+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.
+// Client behavior will not cause incoming events to block.
+type Stream struct {
+ // Program specifies the source of the events - libvirt or QEMU.
+ Program uint32
+
+ // CallbackID is returned by the event registration call.
+ CallbackID int32
+
+ // 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
+}
+
+// Push appends a new event to the queue.
+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.
+func (s *Stream) Shutdown() {
+ if s.shutdown != nil {
+ s.shutdown()
+ }
+}
+
+// start starts the event processing loop, which will continue to run until
+// terminated by the returned context.CancelFunc.
+func (s *Stream) start() context.CancelFunc {
+ ctx, cancel := context.WithCancel(context.Background())
+
+ go s.process(ctx)
+
+ 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
+// 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) {
+ // 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 {
+ sendCh, nextEvt := nextEvent()
+
+ select {
+ // new event received, append to queue
+ case e := <-s.in:
+ s.queue = append(s.queue, e)
+
+ 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
+ }
+ }
+}
diff --git a/third_party/libvirt/internal/event/stream_test.go b/third_party/libvirt/internal/event/stream_test.go
new file mode 100644
index 0000000..01ac47f
--- /dev/null
+++ b/third_party/libvirt/internal/event/stream_test.go
@@ -0,0 +1,85 @@
+package event
+
+import (
+ "fmt"
+ "sync"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+type testEvent struct{ id int32 }
+
+func (e testEvent) GetCallbackID() int32 {
+ return e.id
+}
+
+func testEvents(count int) []Event {
+ ev := make([]Event, count)
+
+ for i := 0; i < count; i++ {
+ ev[i] = testEvent{int32(i)}
+ }
+
+ return ev
+}
+
+// TestStreamSequential tests the stream objects by first writing some entries
+// the stream, then reading them back.
+func TestStreamSequential(t *testing.T) {
+ const evCount = 100000
+
+ s := NewStream(1, 2)
+ defer s.Shutdown()
+ events := testEvents(evCount)
+
+ // send a bunch of "events", and make sure we receive them all.
+ fmt.Println("sending test events to queue")
+ for i, e := range events {
+ assert.Equal(t, int32(i), e.GetCallbackID())
+ s.Push(e)
+ assert.Equal(t, i+1, s.Len())
+ }
+
+ assert.Equal(t, evCount, s.Len())
+
+ fmt.Println("reading events from queue")
+ for _, e := range events {
+ qe, ok := <-s.Recv()
+ assert.True(t, ok)
+ assert.Equal(t, e, qe)
+ }
+
+ assert.Zero(t, s.Len())
+}
+
+// TestStreamParallel tests the stream object with a pair of goroutines, one
+// writing to the queue, the other reading from it.
+func TestStreamParallel(t *testing.T) {
+ const evCount = 10000
+
+ s := NewStream(1, 2)
+ defer s.Shutdown()
+ events := testEvents(evCount)
+ wg := sync.WaitGroup{}
+ wg.Add(2)
+
+ // Start 2 goroutines, one to send, the other to receive.
+ go func() {
+ defer wg.Done()
+ for _, e := range events {
+ s.Push(e)
+ }
+ }()
+
+ go func() {
+ defer wg.Done()
+ for i := 0; i < evCount; i++ {
+ e := <-s.Recv()
+ assert.Equal(t, int32(i), e.GetCallbackID())
+ }
+ }()
+
+ wg.Wait()
+ assert.Zero(t, s.Len())
+}
diff --git a/third_party/libvirt/internal/go-xdr/LICENSE b/third_party/libvirt/internal/go-xdr/LICENSE
new file mode 100644
index 0000000..0cc3543
--- /dev/null
+++ b/third_party/libvirt/internal/go-xdr/LICENSE
@@ -0,0 +1,13 @@
+Copyright (c) 2012-2014 Dave Collins
+
+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.
\ No newline at end of file
diff --git a/third_party/libvirt/internal/go-xdr/README.md b/third_party/libvirt/internal/go-xdr/README.md
new file mode 100644
index 0000000..bf14be3
--- /dev/null
+++ b/third_party/libvirt/internal/go-xdr/README.md
@@ -0,0 +1,146 @@
+go-xdr
+======
+
+[![Build Status](https://travis-ci.org/davecgh/go-xdr.png?branch=master)]
+(https://travis-ci.org/davecgh/go-xdr) [![Coverage Status]
+(https://coveralls.io/repos/davecgh/go-xdr/badge.png?branch=master)]
+(https://coveralls.io/r/davecgh/go-xdr?branch=master)
+
+Go-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) in Pure Go (Golang). A comprehensive suite of tests are
+provided to ensure proper functionality. It is licensed under the liberal ISC
+license, so it may be used in open source or commercial projects.
+
+NOTE: Version 1 of this package is still available via the
+github.com/davecgh/go-xdr/xdr import path to avoid breaking existing clients. However, it is highly recommended that all old clients upgrade to version 2
+and all new clients use version 2. In addition to some speed optimizations,
+version 2 has been been updated to work with standard the io.Reader and
+io.Writer interfaces instead of raw byte slices. This allows it to be much more
+flexible and work directly with files, network connections, etc.
+
+## Documentation
+
+[![GoDoc](https://godoc.org/github.com/davecgh/go-xdr/xdr2?status.png)]
+(http://godoc.org/github.com/davecgh/go-xdr/xdr2)
+
+Full `go doc` style documentation for the project can be viewed online without
+installing this package by using the excellent GoDoc site here:
+http://godoc.org/github.com/davecgh/go-xdr/xdr2
+
+You can also view the documentation locally once the package is installed with
+the `godoc` tool by running `godoc -http=":6060"` and pointing your browser to
+http://localhost:6060/pkg/github.com/davecgh/go-xdr/xdr2/
+
+## Installation
+
+```bash
+$ go get github.com/davecgh/go-xdr/xdr2
+```
+
+## Sample Decode Program
+
+```Go
+package main
+
+import (
+ "bytes"
+ "fmt"
+
+ "github.com/davecgh/go-xdr/xdr2"
+)
+
+func main() {
+ // Hypothetical image header format.
+ type ImageHeader struct {
+ Signature [3]byte
+ Version uint32
+ IsGrayscale bool
+ NumSections uint32
+ }
+
+ // XDR encoded data described by the above structure. Typically this would
+ // be read from a file or across the network, but use a manual byte array
+ // here as an example.
+ encodedData := []byte{
+ 0xAB, 0xCD, 0xEF, 0x00, // Signature
+ 0x00, 0x00, 0x00, 0x02, // Version
+ 0x00, 0x00, 0x00, 0x01, // IsGrayscale
+ 0x00, 0x00, 0x00, 0x0A, // NumSections
+ }
+
+ // Declare a variable to provide Unmarshal with a concrete type and instance
+ // to decode into.
+ var h ImageHeader
+ bytesRead, err := xdr.Unmarshal(bytes.NewReader(encodedData), &h)
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+
+ fmt.Println("bytes read:", bytesRead)
+ fmt.Printf("h: %+v", h)
+}
+```
+
+The struct instance, `h`, will then contain the following values:
+
+```Go
+h.Signature = [3]byte{0xAB, 0xCD, 0xEF}
+h.Version = 2
+h.IsGrayscale = true
+h.NumSections = 10
+```
+
+## Sample Encode Program
+
+```Go
+package main
+
+import (
+ "bytes"
+ "fmt"
+
+ "github.com/davecgh/go-xdr/xdr2"
+)
+
+func main() {
+ // Hypothetical image header format.
+ type ImageHeader struct {
+ Signature [3]byte
+ Version uint32
+ IsGrayscale bool
+ NumSections uint32
+ }
+
+ // Sample image header data.
+ h := ImageHeader{[3]byte{0xAB, 0xCD, 0xEF}, 2, true, 10}
+
+ // Use marshal to automatically determine the appropriate underlying XDR
+ // types and encode.
+ var w bytes.Buffer
+ bytesWritten, err := xdr.Marshal(&w, &h)
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+
+ encodedData := w.Bytes()
+ fmt.Println("bytes written:", bytesWritten)
+ fmt.Println("encoded data:", encodedData)
+}
+```
+
+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,
+```
+
+## License
+
+Go-xdr is licensed under the liberal ISC License.
diff --git a/third_party/libvirt/internal/go-xdr/goclean.sh b/third_party/libvirt/internal/go-xdr/goclean.sh
new file mode 100755
index 0000000..5e996cb
--- /dev/null
+++ b/third_party/libvirt/internal/go-xdr/goclean.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+# The script does automatic checking on a Go package and its sub-packages, including:
+# 1. gofmt (http://golang.org/cmd/gofmt/)
+# 2. goimports (https://github.com/bradfitz/goimports)
+# 3. golint (https://github.com/golang/lint)
+# 4. go vet (http://golang.org/cmd/vet)
+# 5. test coverage (http://blog.golang.org/cover)
+
+set -e
+
+# Automatic checks
+cd xdr2
+test -z "$(gofmt -l -w . | tee /dev/stderr)"
+test -z "$(goimports -l -w . | tee /dev/stderr)"
+test -z "$(golint . | tee /dev/stderr)"
+go vet ./...
+env GORACE="halt_on_error=1" go test -v -race ./...
+
+# Run test coverage on each subdirectories and merge the coverage profile.
+
+echo "mode: count" > profile.cov
+
+# Standard go tooling behavior is to ignore dirs with leading underscores.
+for dir in $(find . -maxdepth 10 -not -path './.git*' -not -path '*/_*' -type d);
+do
+if ls $dir/*.go &> /dev/null; then
+ go test -covermode=count -coverprofile=$dir/profile.tmp $dir
+ if [ -f $dir/profile.tmp ]; then
+ cat $dir/profile.tmp | tail -n +2 >> profile.cov
+ rm $dir/profile.tmp
+ fi
+fi
+done
+
+go tool cover -func profile.cov
+
+# To submit the test coverage result to coveralls.io,
+# use goveralls (https://github.com/mattn/goveralls)
+# goveralls -coverprofile=profile.cov -service=travis-ci
diff --git a/third_party/libvirt/internal/go-xdr/xdr2/bench_test.go b/third_party/libvirt/internal/go-xdr/xdr2/bench_test.go
new file mode 100644
index 0000000..56f6b2b
--- /dev/null
+++ b/third_party/libvirt/internal/go-xdr/xdr2/bench_test.go
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2012-2014 Dave Collins
+ *
+ * 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_test
+
+import (
+ "bytes"
+ "testing"
+ "unsafe"
+
+ "github.com/projecteru2/yavirt/third_party/libvirt/internal/go-xdr/xdr2"
+)
+
+// BenchmarkUnmarshal benchmarks the Unmarshal function by using a dummy
+// ImageHeader structure.
+func BenchmarkUnmarshal(b *testing.B) {
+ b.StopTimer()
+ // Hypothetical image header format.
+ type ImageHeader struct {
+ Signature [3]byte
+ Version uint32
+ IsGrayscale bool
+ NumSections uint32
+ }
+ // XDR encoded data described by the above structure.
+ encodedData := []byte{
+ 0xAB, 0xCD, 0xEF, 0x00,
+ 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x0A,
+ }
+ var h ImageHeader
+ b.StartTimer()
+
+ for i := 0; i < b.N; i++ {
+ r := bytes.NewReader(encodedData)
+ _, _ = xdr.Unmarshal(r, &h)
+ }
+ b.SetBytes(int64(len(encodedData)))
+}
+
+// BenchmarkMarshal benchmarks the Marshal function by using a dummy ImageHeader
+// structure.
+func BenchmarkMarshal(b *testing.B) {
+ b.StopTimer()
+ // Hypothetical image header format.
+ type ImageHeader struct {
+ Signature [3]byte
+ Version uint32
+ IsGrayscale bool
+ NumSections uint32
+ }
+ h := ImageHeader{[3]byte{0xAB, 0xCD, 0xEF}, 2, true, 10}
+ size := unsafe.Sizeof(h)
+ w := bytes.NewBuffer(nil)
+ b.StartTimer()
+
+ for i := 0; i < b.N; i++ {
+ w.Reset()
+ _, _ = xdr.Marshal(w, &h)
+ }
+ b.SetBytes(int64(size))
+}
diff --git a/third_party/libvirt/internal/go-xdr/xdr2/decode.go b/third_party/libvirt/internal/go-xdr/xdr2/decode.go
new file mode 100644
index 0000000..7f33f7d
--- /dev/null
+++ b/third_party/libvirt/internal/go-xdr/xdr2/decode.go
@@ -0,0 +1,896 @@
+/*
+ * Copyright (c) 2012-2014 Dave Collins
+ *
+ * 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
+ [] <- XDR Variable-Length Array
+ [#] <- 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}
+}
diff --git a/third_party/libvirt/internal/go-xdr/xdr2/decode_test.go b/third_party/libvirt/internal/go-xdr/xdr2/decode_test.go
new file mode 100644
index 0000000..19820c6
--- /dev/null
+++ b/third_party/libvirt/internal/go-xdr/xdr2/decode_test.go
@@ -0,0 +1,793 @@
+/*
+ * Copyright (c) 2012-2014 Dave Collins
+ *
+ * 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_test
+
+import (
+ "bytes"
+ "fmt"
+ "math"
+ "reflect"
+ "testing"
+ "time"
+
+ . "github.com/projecteru2/yavirt/third_party/libvirt/internal/go-xdr/xdr2"
+)
+
+// subTest is used to allow testing of the Unmarshal function into struct fields
+// which are structs themselves.
+type subTest struct {
+ A string
+ B uint8
+}
+
+// allTypesTest is used to allow testing of the Unmarshal function into struct
+// fields of all supported types.
+type allTypesTest struct {
+ A int8
+ B uint8
+ C int16
+ D uint16
+ E int32
+ F uint32
+ G int64
+ H uint64
+ I bool
+ J float32
+ K float64
+ L string
+ M []byte
+ N [3]byte
+ O []int16
+ P [2]subTest
+ Q *subTest
+ R map[string]uint32
+ S time.Time
+}
+
+// opaqueStruct is used to test handling of uint8 slices and arrays.
+type opaqueStruct struct {
+ Slice []uint8 `xdropaque:"false"`
+ Array [1]uint8 `xdropaque:"false"`
+}
+
+// testExpectedURet is a convenience method to test an expected number of bytes
+// read and error for an unmarshal.
+func testExpectedURet(t *testing.T, name string, n, wantN int, err, wantErr error) bool {
+ // First ensure the number of bytes read is the expected value. The
+ // byes read should be accurate even when an error occurs.
+ if n != wantN {
+ t.Errorf("%s: unexpected num bytes read - got: %v want: %v\n",
+ name, n, wantN)
+ return false
+ }
+
+ // Next check for the expected error.
+ if reflect.TypeOf(err) != reflect.TypeOf(wantErr) {
+ t.Errorf("%s: failed to detect error - got: %v <%[2]T> want: %T",
+ name, err, wantErr)
+ return false
+ }
+ if rerr, ok := err.(*UnmarshalError); ok {
+ if werr, ok := wantErr.(*UnmarshalError); ok {
+ if rerr.ErrorCode != werr.ErrorCode {
+ t.Errorf("%s: failed to detect error code - "+
+ "got: %v want: %v", name,
+ rerr.ErrorCode, werr.ErrorCode)
+ return false
+ }
+ }
+ }
+
+ return true
+}
+
+// TestUnmarshal ensures the Unmarshal function works properly with all types.
+func TestUnmarshal(t *testing.T) {
+ // Variables for various unsupported Unmarshal types.
+ var nilInterface interface{}
+ var testChan chan int
+ var testFunc func()
+ var testComplex64 complex64
+ var testComplex128 complex128
+
+ // structTestIn is input data for the big struct test of all supported
+ // types.
+ structTestIn := []byte{
+ 0x00, 0x00, 0x00, 0x7F, // A
+ 0x00, 0x00, 0x00, 0xFF, // B
+ 0x00, 0x00, 0x7F, 0xFF, // C
+ 0x00, 0x00, 0xFF, 0xFF, // D
+ 0x7F, 0xFF, 0xFF, 0xFF, // E
+ 0xFF, 0xFF, 0xFF, 0xFF, // F
+ 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // G
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // H
+ 0x00, 0x00, 0x00, 0x01, // I
+ 0x40, 0x48, 0xF5, 0xC3, // J
+ 0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18, // K
+ 0x00, 0x00, 0x00, 0x03, 0x78, 0x64, 0x72, 0x00, // L
+ 0x00, 0x00, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04, // M
+ 0x01, 0x02, 0x03, 0x00, // N
+ 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, // O
+ 0x00, 0x00, 0x00, 0x03, 0x6F, 0x6E, 0x65, 0x00, // P[0].A
+ 0x00, 0x00, 0x00, 0x01, // P[0].B
+ 0x00, 0x00, 0x00, 0x03, 0x74, 0x77, 0x6F, 0x00, // P[1].A
+ 0x00, 0x00, 0x00, 0x02, // P[1].B
+ 0x00, 0x00, 0x00, 0x03, 0x62, 0x61, 0x72, 0x00, // Q.A
+ 0x00, 0x00, 0x00, 0x03, // Q.B
+ 0x00, 0x00, 0x00, 0x02, // R length
+ 0x00, 0x00, 0x00, 0x04, 0x6D, 0x61, 0x70, 0x31, // R key map1
+ 0x00, 0x00, 0x00, 0x01, // R value map1
+ 0x00, 0x00, 0x00, 0x04, 0x6D, 0x61, 0x70, 0x32, // R key map2
+ 0x00, 0x00, 0x00, 0x02, // R value map2
+ 0x00, 0x00, 0x00, 0x14, 0x32, 0x30, 0x31, 0x34,
+ 0x2d, 0x30, 0x34, 0x2d, 0x30, 0x34, 0x54, 0x30,
+ 0x33, 0x3a, 0x32, 0x34, 0x3a, 0x34, 0x38, 0x5a, // S
+ }
+
+ // structTestWant is the expected output after unmarshalling
+ // structTestIn.
+ structTestWant := allTypesTest{
+ 127, // A
+ 255, // B
+ 32767, // C
+ 65535, // D
+ 2147483647, // E
+ 4294967295, // F
+ 9223372036854775807, // G
+ 18446744073709551615, // H
+ true, // I
+ 3.14, // J
+ 3.141592653589793, // K
+ "xdr", // L
+ []byte{1, 2, 3, 4}, // M
+ [3]byte{1, 2, 3}, // N
+ []int16{512, 1024, 2048}, // O
+ [2]subTest{{"one", 1}, {"two", 2}}, // P
+ &subTest{"bar", 3}, // Q
+ map[string]uint32{"map1": 1, "map2": 2}, // R
+ time.Unix(1396581888, 0).UTC(), // S
+ }
+
+ tests := []struct {
+ in []byte // input bytes
+ wantVal interface{} // expected value
+ wantN int // expected number of bytes read
+ err error // expected error
+ }{
+ // int8 - XDR Integer
+ {[]byte{0x00, 0x00, 0x00, 0x00}, int8(0), 4, nil},
+ {[]byte{0x00, 0x00, 0x00, 0x40}, int8(64), 4, nil},
+ {[]byte{0x00, 0x00, 0x00, 0x7F}, int8(127), 4, nil},
+ {[]byte{0xFF, 0xFF, 0xFF, 0xFF}, int8(-1), 4, nil},
+ {[]byte{0xFF, 0xFF, 0xFF, 0x80}, int8(-128), 4, nil},
+ // Expected Failures -- 128, -129 overflow int8 and not enough
+ // bytes
+ {[]byte{0x00, 0x00, 0x00, 0x80}, int8(0), 4, &UnmarshalError{ErrorCode: ErrOverflow}},
+ {[]byte{0xFF, 0xFF, 0xFF, 0x7F}, int8(0), 4, &UnmarshalError{ErrorCode: ErrOverflow}},
+ {[]byte{0x00, 0x00, 0x00}, int8(0), 3, &UnmarshalError{ErrorCode: ErrIO}},
+
+ // uint8 - XDR Unsigned Integer
+ {[]byte{0x00, 0x00, 0x00, 0x00}, uint8(0), 4, nil},
+ {[]byte{0x00, 0x00, 0x00, 0x40}, uint8(64), 4, nil},
+ {[]byte{0x00, 0x00, 0x00, 0xFF}, uint8(255), 4, nil},
+ // Expected Failures -- 256, -1 overflow uint8 and not enough
+ // bytes
+ {[]byte{0x00, 0x00, 0x01, 0x00}, uint8(0), 4, &UnmarshalError{ErrorCode: ErrOverflow}},
+ {[]byte{0xFF, 0xFF, 0xFF, 0xFF}, uint8(0), 4, &UnmarshalError{ErrorCode: ErrOverflow}},
+ {[]byte{0x00, 0x00, 0x00}, uint8(0), 3, &UnmarshalError{ErrorCode: ErrIO}},
+
+ // int16 - XDR Integer
+ {[]byte{0x00, 0x00, 0x00, 0x00}, int16(0), 4, nil},
+ {[]byte{0x00, 0x00, 0x04, 0x00}, int16(1024), 4, nil},
+ {[]byte{0x00, 0x00, 0x7F, 0xFF}, int16(32767), 4, nil},
+ {[]byte{0xFF, 0xFF, 0xFF, 0xFF}, int16(-1), 4, nil},
+ {[]byte{0xFF, 0xFF, 0x80, 0x00}, int16(-32768), 4, nil},
+ // Expected Failures -- 32768, -32769 overflow int16 and not
+ // enough bytes
+ {[]byte{0x00, 0x00, 0x80, 0x00}, int16(0), 4, &UnmarshalError{ErrorCode: ErrOverflow}},
+ {[]byte{0xFF, 0xFF, 0x7F, 0xFF}, int16(0), 4, &UnmarshalError{ErrorCode: ErrOverflow}},
+ {[]byte{0x00, 0x00, 0x00}, uint16(0), 3, &UnmarshalError{ErrorCode: ErrIO}},
+
+ // uint16 - XDR Unsigned Integer
+ {[]byte{0x00, 0x00, 0x00, 0x00}, uint16(0), 4, nil},
+ {[]byte{0x00, 0x00, 0x04, 0x00}, uint16(1024), 4, nil},
+ {[]byte{0x00, 0x00, 0xFF, 0xFF}, uint16(65535), 4, nil},
+ // Expected Failures -- 65536, -1 overflow uint16 and not enough
+ // bytes
+ {[]byte{0x00, 0x01, 0x00, 0x00}, uint16(0), 4, &UnmarshalError{ErrorCode: ErrOverflow}},
+ {[]byte{0xFF, 0xFF, 0xFF, 0xFF}, uint16(0), 4, &UnmarshalError{ErrorCode: ErrOverflow}},
+ {[]byte{0x00, 0x00, 0x00}, uint16(0), 3, &UnmarshalError{ErrorCode: ErrIO}},
+
+ // int32 - XDR Integer
+ {[]byte{0x00, 0x00, 0x00, 0x00}, int32(0), 4, nil},
+ {[]byte{0x00, 0x04, 0x00, 0x00}, int32(262144), 4, nil},
+ {[]byte{0x7F, 0xFF, 0xFF, 0xFF}, int32(2147483647), 4, nil},
+ {[]byte{0xFF, 0xFF, 0xFF, 0xFF}, int32(-1), 4, nil},
+ {[]byte{0x80, 0x00, 0x00, 0x00}, int32(-2147483648), 4, nil},
+ // Expected Failure -- not enough bytes
+ {[]byte{0x00, 0x00, 0x00}, int32(0), 3, &UnmarshalError{ErrorCode: ErrIO}},
+
+ // uint32 - XDR Unsigned Integer
+ {[]byte{0x00, 0x00, 0x00, 0x00}, uint32(0), 4, nil},
+ {[]byte{0x00, 0x04, 0x00, 0x00}, uint32(262144), 4, nil},
+ {[]byte{0xFF, 0xFF, 0xFF, 0xFF}, uint32(4294967295), 4, nil},
+ // Expected Failure -- not enough bytes
+ {[]byte{0x00, 0x00, 0x00}, uint32(0), 3, &UnmarshalError{ErrorCode: ErrIO}},
+
+ // int64 - XDR Hyper Integer
+ {[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, int64(0), 8, nil},
+ {[]byte{0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00}, int64(1 << 34), 8, nil},
+ {[]byte{0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00}, int64(1 << 42), 8, nil},
+ {[]byte{0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, int64(9223372036854775807), 8, nil},
+ {[]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, int64(-1), 8, nil},
+ {[]byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, int64(-9223372036854775808), 8, nil},
+ // Expected Failures -- not enough bytes
+ {[]byte{0x7f, 0xff, 0xff}, int64(0), 3, &UnmarshalError{ErrorCode: ErrIO}},
+ {[]byte{0x7f, 0x00, 0xff, 0x00}, int64(0), 4, &UnmarshalError{ErrorCode: ErrIO}},
+
+ // uint64 - XDR Unsigned Hyper Integer
+ {[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, uint64(0), 8, nil},
+ {[]byte{0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00}, uint64(1 << 34), 8, nil},
+ {[]byte{0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00}, uint64(1 << 42), 8, nil},
+ {[]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, uint64(18446744073709551615), 8, nil},
+ {[]byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, uint64(9223372036854775808), 8, nil},
+ // Expected Failures -- not enough bytes
+ {[]byte{0xff, 0xff, 0xff}, uint64(0), 3, &UnmarshalError{ErrorCode: ErrIO}},
+ {[]byte{0xff, 0x00, 0xff, 0x00}, uint64(0), 4, &UnmarshalError{ErrorCode: ErrIO}},
+
+ // bool - XDR Integer
+ {[]byte{0x00, 0x00, 0x00, 0x00}, false, 4, nil},
+ {[]byte{0x00, 0x00, 0x00, 0x01}, true, 4, nil},
+ // Expected Failures -- only 0 or 1 is a valid bool
+ {[]byte{0x01, 0x00, 0x00, 0x00}, true, 4, &UnmarshalError{ErrorCode: ErrBadEnumValue}},
+ {[]byte{0x00, 0x00, 0x40, 0x00}, true, 4, &UnmarshalError{ErrorCode: ErrBadEnumValue}},
+
+ // float32 - XDR Floating-Point
+ {[]byte{0x00, 0x00, 0x00, 0x00}, float32(0), 4, nil},
+ {[]byte{0x40, 0x48, 0xF5, 0xC3}, float32(3.14), 4, nil},
+ {[]byte{0x49, 0x96, 0xB4, 0x38}, float32(1234567.0), 4, nil},
+ {[]byte{0xFF, 0x80, 0x00, 0x00}, float32(math.Inf(-1)), 4, nil},
+ {[]byte{0x7F, 0x80, 0x00, 0x00}, float32(math.Inf(0)), 4, nil},
+ // Expected Failures -- not enough bytes
+ {[]byte{0xff, 0xff}, float32(0), 2, &UnmarshalError{ErrorCode: ErrIO}},
+ {[]byte{0xff, 0x00, 0xff}, float32(0), 3, &UnmarshalError{ErrorCode: ErrIO}},
+
+ // float64 - XDR Double-precision Floating-Point
+ {[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, float64(0), 8, nil},
+ {[]byte{0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18}, float64(3.141592653589793), 8, nil},
+ {[]byte{0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, float64(math.Inf(-1)), 8, nil},
+ {[]byte{0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, float64(math.Inf(0)), 8, nil},
+ // Expected Failures -- not enough bytes
+ {[]byte{0xff, 0xff, 0xff}, float64(0), 3, &UnmarshalError{ErrorCode: ErrIO}},
+ {[]byte{0xff, 0x00, 0xff, 0x00}, float64(0), 4, &UnmarshalError{ErrorCode: ErrIO}},
+
+ // string - XDR String
+ {[]byte{0x00, 0x00, 0x00, 0x00}, "", 4, nil},
+ {[]byte{0x00, 0x00, 0x00, 0x03, 0x78, 0x64, 0x72, 0x00}, "xdr", 8, nil},
+ {[]byte{0x00, 0x00, 0x00, 0x06, 0xCF, 0x84, 0x3D, 0x32, 0xCF, 0x80, 0x00, 0x00}, "τ=2π", 12, nil},
+ // Expected Failures -- not enough bytes for length, length
+ // larger than allowed, and len larger than available bytes.
+ {[]byte{0x00, 0x00, 0xFF}, "", 3, &UnmarshalError{ErrorCode: ErrIO}},
+ {[]byte{0xFF, 0xFF, 0xFF, 0xFF}, "", 4, &UnmarshalError{ErrorCode: ErrOverflow}},
+ {[]byte{0x00, 0x00, 0x00, 0xFF}, "", 4, &UnmarshalError{ErrorCode: ErrIO}},
+
+ // []byte - XDR Variable Opaque
+ {[]byte{0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00}, []byte{0x01}, 8, nil},
+ {[]byte{0x00, 0x00, 0x00, 0x03, 0x01, 0x02, 0x03, 0x00}, []byte{0x01, 0x02, 0x03}, 8, nil},
+ // Expected Failures -- not enough bytes for length, length
+ // larger than allowed, and data larger than available bytes.
+ {[]byte{0x00, 0x00, 0xFF}, []byte{}, 3, &UnmarshalError{ErrorCode: ErrIO}},
+ {[]byte{0xFF, 0xFF, 0xFF, 0xFF}, []byte{}, 4, &UnmarshalError{ErrorCode: ErrOverflow}},
+ {[]byte{0x00, 0x00, 0x00, 0xFF}, []byte{}, 4, &UnmarshalError{ErrorCode: ErrIO}},
+
+ // [#]byte - XDR Fixed Opaque
+ {[]byte{0x01, 0x00, 0x00, 0x00}, [1]byte{0x01}, 4, nil},
+ {[]byte{0x01, 0x02, 0x00, 0x00}, [2]byte{0x01, 0x02}, 4, nil},
+ {[]byte{0x01, 0x02, 0x03, 0x00}, [3]byte{0x01, 0x02, 0x03}, 4, nil},
+ {[]byte{0x01, 0x02, 0x03, 0x04}, [4]byte{0x01, 0x02, 0x03, 0x04}, 4, nil},
+ {[]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x00, 0x00}, [5]byte{0x01, 0x02, 0x03, 0x04, 0x05}, 8, nil},
+ // Expected Failure -- fixed opaque data not padded
+ {[]byte{0x01}, [1]byte{}, 1, &UnmarshalError{ErrorCode: ErrIO}},
+
+ // [] - XDR Variable-Length Array
+ {[]byte{0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00},
+ []int16{512, 1024, 2048}, 16, nil},
+ {[]byte{0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00}, []bool{true, false}, 12, nil},
+ // Expected Failure -- 2 entries in array - not enough bytes
+ {[]byte{0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01}, []bool{}, 8, &UnmarshalError{ErrorCode: ErrIO}},
+
+ // [#] - XDR Fixed-Length Array
+ {[]byte{0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00}, [2]uint32{512, 1024}, 8, nil},
+ // Expected Failure -- 2 entries in array - not enough bytes
+ {[]byte{0x00, 0x00, 0x00, 0x02}, [2]uint32{}, 4, &UnmarshalError{ErrorCode: ErrIO}},
+
+ // map[string]uint32
+ {[]byte{0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x6D, 0x61, 0x70, 0x31, 0x00, 0x00, 0x00, 0x01},
+ map[string]uint32{"map1": 1}, 16, nil},
+ // Expected Failures -- not enough bytes in length, 1 map
+ // element no extra bytes, 1 map element not enough bytes for
+ // key, 1 map element not enough bytes for value.
+ {[]byte{0x00, 0x00, 0x00}, map[string]uint32{}, 3, &UnmarshalError{ErrorCode: ErrIO}},
+ {[]byte{0x00, 0x00, 0x00, 0x01}, map[string]uint32{}, 4, &UnmarshalError{ErrorCode: ErrIO}},
+ {[]byte{0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00}, map[string]uint32{}, 7, &UnmarshalError{ErrorCode: ErrIO}},
+ {[]byte{0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x6D, 0x61, 0x70, 0x31},
+ map[string]uint32{}, 12, &UnmarshalError{ErrorCode: ErrIO}},
+
+ // time.Time - XDR String per RFC3339
+ {[]byte{
+ 0x00, 0x00, 0x00, 0x14, 0x32, 0x30, 0x31, 0x34,
+ 0x2d, 0x30, 0x34, 0x2d, 0x30, 0x34, 0x54, 0x30,
+ 0x33, 0x3a, 0x32, 0x34, 0x3a, 0x34, 0x38, 0x5a,
+ }, time.Unix(1396581888, 0).UTC(), 24, nil},
+ // Expected Failures -- not enough bytes, improperly formatted
+ // time
+ {[]byte{0x00, 0x00, 0x00}, time.Time{}, 3, &UnmarshalError{ErrorCode: ErrIO}},
+ {[]byte{0x00, 0x00, 0x00, 0x00}, time.Time{}, 4, &UnmarshalError{ErrorCode: ErrParseTime}},
+
+ // struct - XDR Structure -- test struct contains all supported types
+ {structTestIn, structTestWant, len(structTestIn), nil},
+ {[]byte{0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02},
+ opaqueStruct{[]uint8{1}, [1]uint8{2}}, 12, nil},
+ // Expected Failures -- normal struct not enough bytes, non
+ // opaque data not enough bytes for slice, non opaque data not
+ // enough bytes for slice.
+ {[]byte{0x00, 0x00}, allTypesTest{}, 2, &UnmarshalError{ErrorCode: ErrIO}},
+ {[]byte{0x00, 0x00, 0x00}, opaqueStruct{}, 3, &UnmarshalError{ErrorCode: ErrIO}},
+ {[]byte{0x00, 0x00, 0x00, 0x00, 0x00}, opaqueStruct{}, 5, &UnmarshalError{ErrorCode: ErrIO}},
+
+ // Expected errors
+ {nil, nilInterface, 0, &UnmarshalError{ErrorCode: ErrNilInterface}},
+ {nil, &nilInterface, 0, &UnmarshalError{ErrorCode: ErrNilInterface}},
+ {nil, testChan, 0, &UnmarshalError{ErrorCode: ErrUnsupportedType}},
+ {nil, &testChan, 0, &UnmarshalError{ErrorCode: ErrUnsupportedType}},
+ {nil, testFunc, 0, &UnmarshalError{ErrorCode: ErrUnsupportedType}},
+ {nil, &testFunc, 0, &UnmarshalError{ErrorCode: ErrUnsupportedType}},
+ {nil, testComplex64, 0, &UnmarshalError{ErrorCode: ErrUnsupportedType}},
+ {nil, &testComplex64, 0, &UnmarshalError{ErrorCode: ErrUnsupportedType}},
+ {nil, testComplex128, 0, &UnmarshalError{ErrorCode: ErrUnsupportedType}},
+ {nil, &testComplex128, 0, &UnmarshalError{ErrorCode: ErrUnsupportedType}},
+ }
+
+ for i, test := range tests {
+ // Attempt to unmarshal to a non-pointer version of each
+ // positive test type to ensure the appropriate error is
+ // returned.
+ if test.err == nil && test.wantVal != nil {
+ testName := fmt.Sprintf("Unmarshal #%d (non-pointer)", i)
+ wantErr := &UnmarshalError{ErrorCode: ErrBadArguments}
+
+ wvt := reflect.TypeOf(test.wantVal)
+ want := reflect.New(wvt).Elem().Interface()
+ n, err := Unmarshal(bytes.NewReader(test.in), want)
+ if !testExpectedURet(t, testName, n, 0, err, wantErr) {
+ continue
+ }
+ }
+
+ testName := fmt.Sprintf("Unmarshal #%d", i)
+ // Create a new pointer to the appropriate type.
+ var want interface{}
+ if test.wantVal != nil {
+ wvt := reflect.TypeOf(test.wantVal)
+ want = reflect.New(wvt).Interface()
+ }
+ n, err := Unmarshal(bytes.NewReader(test.in), want)
+
+ // First ensure the number of bytes read is the expected value
+ // and the error is the expected one.
+ if !testExpectedURet(t, testName, n, test.wantN, err, test.err) {
+ continue
+ }
+ if test.err != nil {
+ continue
+ }
+
+ // Finally, ensure the read value is the expected one.
+ wantElem := reflect.Indirect(reflect.ValueOf(want)).Interface()
+ if !reflect.DeepEqual(wantElem, test.wantVal) {
+ t.Errorf("%s: unexpected result - got: %v want: %v\n",
+ testName, wantElem, test.wantVal)
+ continue
+ }
+ }
+}
+
+// decodeFunc is used to identify which public function of the Decoder object
+// a test applies to.
+type decodeFunc int
+
+const (
+ fDecodeBool decodeFunc = iota
+ fDecodeDouble
+ fDecodeEnum
+ fDecodeFixedOpaque
+ fDecodeFloat
+ fDecodeHyper
+ fDecodeInt
+ fDecodeOpaque
+ fDecodeString
+ fDecodeUhyper
+ fDecodeUint
+)
+
+// Map of decodeFunc values to names for pretty printing.
+var decodeFuncStrings = map[decodeFunc]string{
+ fDecodeBool: "DecodeBool",
+ fDecodeDouble: "DecodeDouble",
+ fDecodeEnum: "DecodeEnum",
+ fDecodeFixedOpaque: "DecodeFixedOpaque",
+ fDecodeFloat: "DecodeFloat",
+ fDecodeHyper: "DecodeHyper",
+ fDecodeInt: "DecodeInt",
+ fDecodeOpaque: "DecodeOpaque",
+ fDecodeString: "DecodeString",
+ fDecodeUhyper: "DecodeUhyper",
+ fDecodeUint: "DecodeUint",
+}
+
+// String implements the fmt.Stringer interface and returns the encode function
+// as a human-readable string.
+func (f decodeFunc) String() string {
+ if s := decodeFuncStrings[f]; s != "" {
+ return s
+ }
+ return fmt.Sprintf("Unknown decodeFunc (%d)", f)
+}
+
+// TestDecoder ensures a Decoder works as intended.
+func TestDecoder(t *testing.T) {
+ type test struct {
+ f decodeFunc // function to use to decode
+ in []byte // input bytes
+ wantVal interface{} // expected value
+ wantN int // expected number of bytes read
+ maxSize uint // read limiter value
+ err error // expected error
+ }
+ tests := []test{
+ // Bool
+ {fDecodeBool, []byte{0x00, 0x00, 0x00, 0x00}, false, 4, 0, nil},
+ {fDecodeBool, []byte{0x00, 0x00, 0x00, 0x01}, true, 4, 0, nil},
+ // Expected Failures -- only 0 or 1 is a valid bool
+ {fDecodeBool, []byte{0x01, 0x00, 0x00, 0x00}, true, 4, 0, &UnmarshalError{ErrorCode: ErrBadEnumValue}},
+ {fDecodeBool, []byte{0x00, 0x00, 0x40, 0x00}, true, 4, 0, &UnmarshalError{ErrorCode: ErrBadEnumValue}},
+
+ // Double
+ {fDecodeDouble, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, float64(0), 8, 0, nil},
+ {fDecodeDouble, []byte{0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18}, float64(3.141592653589793), 8, 0, nil},
+ {fDecodeDouble, []byte{0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, float64(math.Inf(-1)), 8, 0, nil},
+ {fDecodeDouble, []byte{0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, float64(math.Inf(0)), 8, 0, nil},
+
+ // Enum
+ {fDecodeEnum, []byte{0x00, 0x00, 0x00, 0x00}, int32(0), 4, 0, nil},
+ {fDecodeEnum, []byte{0x00, 0x00, 0x00, 0x01}, int32(1), 4, 0, nil},
+ {fDecodeEnum, []byte{0x00, 0x00, 0x00, 0x02}, nil, 4, 0, &UnmarshalError{ErrorCode: ErrBadEnumValue}},
+ {fDecodeEnum, []byte{0x12, 0x34, 0x56, 0x78}, nil, 4, 0, &UnmarshalError{ErrorCode: ErrBadEnumValue}},
+ {fDecodeEnum, []byte{0x00}, nil, 1, 0, &UnmarshalError{ErrorCode: ErrIO}},
+
+ // FixedOpaque
+ {fDecodeFixedOpaque, []byte{0x01, 0x00, 0x00, 0x00}, []byte{0x01}, 4, 0, nil},
+ {fDecodeFixedOpaque, []byte{0x01, 0x02, 0x00, 0x00}, []byte{0x01, 0x02}, 4, 0, nil},
+ {fDecodeFixedOpaque, []byte{0x01, 0x02, 0x03, 0x00}, []byte{0x01, 0x02, 0x03}, 4, 0, nil},
+ {fDecodeFixedOpaque, []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, 4, 0, nil},
+ {fDecodeFixedOpaque, []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x00, 0x00}, []byte{0x01, 0x02, 0x03, 0x04, 0x05}, 8, 0, nil},
+ // Expected Failure -- fixed opaque data not padded
+ {fDecodeFixedOpaque, []byte{0x01}, []byte{0x00}, 1, 0, &UnmarshalError{ErrorCode: ErrIO}},
+
+ // Float
+ {fDecodeFloat, []byte{0x00, 0x00, 0x00, 0x00}, float32(0), 4, 0, nil},
+ {fDecodeFloat, []byte{0x40, 0x48, 0xF5, 0xC3}, float32(3.14), 4, 0, nil},
+ {fDecodeFloat, []byte{0x49, 0x96, 0xB4, 0x38}, float32(1234567.0), 4, 0, nil},
+ {fDecodeFloat, []byte{0xFF, 0x80, 0x00, 0x00}, float32(math.Inf(-1)), 4, 0, nil},
+ {fDecodeFloat, []byte{0x7F, 0x80, 0x00, 0x00}, float32(math.Inf(0)), 4, 0, nil},
+
+ // Hyper
+ {fDecodeHyper, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, int64(0), 8, 0, nil},
+ {fDecodeHyper, []byte{0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00}, int64(1 << 34), 8, 0, nil},
+ {fDecodeHyper, []byte{0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00}, int64(1 << 42), 8, 0, nil},
+ {fDecodeHyper, []byte{0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, int64(9223372036854775807), 8, 0, nil},
+ {fDecodeHyper, []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, int64(-1), 8, 0, nil},
+ {fDecodeHyper, []byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, int64(-9223372036854775808), 8, 0, nil},
+
+ // Int
+ {fDecodeInt, []byte{0x00, 0x00, 0x00, 0x00}, int32(0), 4, 0, nil},
+ {fDecodeInt, []byte{0x00, 0x04, 0x00, 0x00}, int32(262144), 4, 0, nil},
+ {fDecodeInt, []byte{0x7F, 0xFF, 0xFF, 0xFF}, int32(2147483647), 4, 0, nil},
+ {fDecodeInt, []byte{0xFF, 0xFF, 0xFF, 0xFF}, int32(-1), 4, 0, nil},
+ {fDecodeInt, []byte{0x80, 0x00, 0x00, 0x00}, int32(-2147483648), 4, 0, nil},
+
+ // Opaque
+ {fDecodeOpaque, []byte{0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00}, []byte{0x01}, 8, 0, nil},
+ {fDecodeOpaque, []byte{0x00, 0x00, 0x00, 0x03, 0x01, 0x02, 0x03, 0x00}, []byte{0x01, 0x02, 0x03}, 8, 0, nil},
+ // Expected Failures -- not enough bytes for length, length
+ // larger than allowed, and data larger than available bytes.
+ {fDecodeOpaque, []byte{0x00, 0x00, 0xFF}, []byte{}, 3, 0, &UnmarshalError{ErrorCode: ErrIO}},
+ {fDecodeOpaque, []byte{0xFF, 0xFF, 0xFF, 0xFF}, []byte{}, 4, 0, &UnmarshalError{ErrorCode: ErrOverflow}},
+ {fDecodeOpaque, []byte{0x7F, 0xFF, 0xFF, 0xFD}, []byte{}, 4, 0, &UnmarshalError{ErrorCode: ErrOverflow}},
+ {fDecodeOpaque, []byte{0x00, 0x00, 0x00, 0xFF}, []byte{}, 4, 0, &UnmarshalError{ErrorCode: ErrIO}},
+ // Hit maxReadSize in opaque
+ {fDecodeOpaque, []byte{0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00}, []byte{0x01}, 8, 4, nil},
+ {fDecodeOpaque, []byte{0x00, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00}, []byte{}, 4, 4, &UnmarshalError{ErrorCode: ErrOverflow}},
+
+ // String
+ {fDecodeString, []byte{0x00, 0x00, 0x00, 0x00}, "", 4, 0, nil},
+ {fDecodeString, []byte{0x00, 0x00, 0x00, 0x03, 0x78, 0x64, 0x72, 0x00}, "xdr", 8, 0, nil},
+ {fDecodeString, []byte{0x00, 0x00, 0x00, 0x06, 0xCF, 0x84, 0x3D, 0x32, 0xCF, 0x80, 0x00, 0x00}, "τ=2π", 12, 0, nil},
+ // Expected Failures -- not enough bytes for length, length
+ // larger than allowed, and len larger than available bytes.
+ {fDecodeString, []byte{0x00, 0x00, 0xFF}, "", 3, 0, &UnmarshalError{ErrorCode: ErrIO}},
+ {fDecodeString, []byte{0xFF, 0xFF, 0xFF, 0xFF}, "", 4, 0, &UnmarshalError{ErrorCode: ErrOverflow}},
+ {fDecodeString, []byte{0x00, 0x00, 0x00, 0xFF}, "", 4, 0, &UnmarshalError{ErrorCode: ErrIO}},
+ // Hit maxReadSize in string
+ {fDecodeString, []byte{0x00, 0x00, 0x00, 0x03, 0x78, 0x64, 0x72, 0x00}, "xdr", 8, 4, nil},
+ {fDecodeString, []byte{0x00, 0x00, 0x00, 0x03, 0x78, 0x64, 0x72, 0x00}, "xdr", 4, 2, &UnmarshalError{ErrorCode: ErrOverflow}},
+
+ // Uhyper
+ {fDecodeUhyper, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, uint64(0), 8, 0, nil},
+ {fDecodeUhyper, []byte{0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00}, uint64(1 << 34), 8, 0, nil},
+ {fDecodeUhyper, []byte{0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00}, uint64(1 << 42), 8, 0, nil},
+ {fDecodeUhyper, []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, uint64(18446744073709551615), 8, 0, nil},
+ {fDecodeUhyper, []byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, uint64(9223372036854775808), 8, 0, nil},
+
+ // Uint
+ {fDecodeUint, []byte{0x00, 0x00, 0x00, 0x00}, uint32(0), 4, 0, nil},
+ {fDecodeUint, []byte{0x00, 0x04, 0x00, 0x00}, uint32(262144), 4, 0, nil},
+ {fDecodeUint, []byte{0xFF, 0xFF, 0xFF, 0xFF}, uint32(4294967295), 4, 0, nil},
+ }
+
+ validEnums := make(map[int32]bool)
+ validEnums[0] = true
+ validEnums[1] = true
+
+ var rv interface{}
+ var n int
+ var err error
+
+ decoders := []func(test) *Decoder{
+ func(t test) *Decoder {
+ // return DecoderLimited for test cases that can't succeed.
+ if t.maxSize == 0 {
+ return NewDecoder(bytes.NewReader(t.in))
+ }
+ return NewDecoderLimited(bytes.NewReader(t.in), t.maxSize)
+ },
+ func(t test) *Decoder {
+ return NewDecoderLimited(bytes.NewReader(t.in), t.maxSize)
+ },
+ }
+ for _, decoder := range decoders {
+ for i, test := range tests {
+ dec := decoder(test)
+ switch test.f {
+ case fDecodeBool:
+ rv, n, err = dec.DecodeBool()
+ case fDecodeDouble:
+ rv, n, err = dec.DecodeDouble()
+ case fDecodeEnum:
+ rv, n, err = dec.DecodeEnum(validEnums)
+ case fDecodeFixedOpaque:
+ want := test.wantVal.([]byte)
+ rv, n, err = dec.DecodeFixedOpaque(int32(len(want)))
+ case fDecodeFloat:
+ rv, n, err = dec.DecodeFloat()
+ case fDecodeHyper:
+ rv, n, err = dec.DecodeHyper()
+ case fDecodeInt:
+ rv, n, err = dec.DecodeInt()
+ case fDecodeOpaque:
+ rv, n, err = dec.DecodeOpaque()
+ case fDecodeString:
+ rv, n, err = dec.DecodeString()
+ case fDecodeUhyper:
+ rv, n, err = dec.DecodeUhyper()
+ case fDecodeUint:
+ rv, n, err = dec.DecodeUint()
+ default:
+ t.Errorf("%v #%d unrecognized function", test.f, i)
+ continue
+ }
+
+ // First ensure the number of bytes read is the expected value
+ // and the error is the expected one.
+ testName := fmt.Sprintf("%v #%d", test.f, i)
+ if !testExpectedURet(t, testName, n, test.wantN, err, test.err) {
+ continue
+ }
+ if test.err != nil {
+ continue
+ }
+
+ // Finally, ensure the read value is the expected one.
+ if !reflect.DeepEqual(rv, test.wantVal) {
+ t.Errorf("%s: unexpected result - got: %v want: %v\n",
+ testName, rv, test.wantVal)
+ continue
+ }
+ }
+ }
+}
+
+// TestUnmarshalLimited ensures the UnmarshalLimited function properly handles
+// various cases not already covered by the other tests.
+func TestUnmarshalLimited(t *testing.T) {
+ buf := []byte{
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x02,
+ }
+
+ testName := "UnmarshalLimited to capped slice"
+ cappedSlice := make([]bool, 0, 1)
+ expectedN := 8
+ expectedErr := error(nil)
+ expectedVal := []bool{true}
+ n, err := UnmarshalLimited(bytes.NewReader(buf), &cappedSlice, 8)
+ if testExpectedURet(t, testName, n, expectedN, err, expectedErr) {
+ if !reflect.DeepEqual(cappedSlice, expectedVal) {
+ t.Errorf("%s: unexpected result - got: %v want: %v\n",
+ testName, cappedSlice, expectedVal)
+ }
+ }
+
+ // Positive map test.
+ buf = []byte{
+ 0x00, 0x00, 0x00, 0x02, // R length
+ 0x00, 0x00, 0x00, 0x04, 0x6D, 0x61, 0x70, 0x31, // R key map1
+ 0x00, 0x00, 0x00, 0x01, // R value map1
+ 0x00, 0x00, 0x00, 0x04, 0x6D, 0x61, 0x70, 0x32, // R key map2
+ 0x00, 0x00, 0x00, 0x02, // R value map2
+ }
+ type myMap struct {
+ R map[string]uint32
+ }
+ expectedMapVal := &myMap{
+ R: map[string]uint32{"map1": 1, "map2": 2}, // R
+ }
+ var m myMap
+ n, err = UnmarshalLimited(bytes.NewReader(buf), &m, 28)
+ expectedN = 28
+ if testExpectedURet(t, testName, n, expectedN, err, expectedErr) {
+ if !reflect.DeepEqual(&m, expectedMapVal) {
+ t.Errorf("%s: unexpected result - got: %v want: %v\n",
+ testName, m, expectedMapVal)
+ }
+ }
+}
+
+// TestUnmarshalCorners ensures the Unmarshal function properly handles various
+// cases not already covered by the other tests.
+func TestUnmarshalCorners(t *testing.T) {
+ buf := []byte{
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x02,
+ }
+
+ // Ensure unmarshal to unsettable pointer returns the expected error.
+ testName := "Unmarshal to unsettable pointer"
+ var i32p *int32
+ expectedN := 0
+ expectedErr := error(&UnmarshalError{ErrorCode: ErrNotSettable})
+ n, err := Unmarshal(bytes.NewReader(buf), i32p)
+ testExpectedURet(t, testName, n, expectedN, err, expectedErr)
+
+ // Ensure decode of unsettable pointer returns the expected error.
+ testName = "Decode to unsettable pointer"
+ expectedN = 0
+ expectedErr = &UnmarshalError{ErrorCode: ErrNotSettable}
+ n, err = TstDecode(bytes.NewReader(buf))(reflect.ValueOf(i32p))
+ testExpectedURet(t, testName, n, expectedN, err, expectedErr)
+
+ // Ensure unmarshal to indirected unsettable pointer returns the
+ // expected error.
+ testName = "Unmarshal to indirected unsettable pointer"
+ ii32p := interface{}(i32p)
+ expectedN = 0
+ expectedErr = &UnmarshalError{ErrorCode: ErrNotSettable}
+ n, err = Unmarshal(bytes.NewReader(buf), &ii32p)
+ testExpectedURet(t, testName, n, expectedN, err, expectedErr)
+
+ // Ensure unmarshal to embedded unsettable interface value returns the
+ // expected error.
+ testName = "Unmarshal to embedded unsettable interface value"
+ var i32 int32
+ ii32 := interface{}(i32)
+ expectedN = 0
+ expectedErr = &UnmarshalError{ErrorCode: ErrNotSettable}
+ n, err = Unmarshal(bytes.NewReader(buf), &ii32)
+ testExpectedURet(t, testName, n, expectedN, err, expectedErr)
+
+ // Ensure unmarshal to embedded interface value works properly.
+ testName = "Unmarshal to embedded interface value"
+ ii32vp := interface{}(&i32)
+ expectedN = 4
+ expectedErr = nil
+ ii32vpr := int32(1)
+ expectedVal := interface{}(&ii32vpr)
+ n, err = Unmarshal(bytes.NewReader(buf), &ii32vp)
+ if testExpectedURet(t, testName, n, expectedN, err, expectedErr) {
+ if !reflect.DeepEqual(ii32vp, expectedVal) {
+ t.Errorf("%s: unexpected result - got: %v want: %v\n",
+ testName, ii32vp, expectedVal)
+ }
+ }
+
+ // Ensure decode of an invalid reflect value returns the expected
+ // error.
+ testName = "Decode invalid reflect value"
+ expectedN = 0
+ expectedErr = error(&UnmarshalError{ErrorCode: ErrUnsupportedType})
+ n, err = TstDecode(bytes.NewReader(buf))(reflect.Value{})
+ testExpectedURet(t, testName, n, expectedN, err, expectedErr)
+
+ // Ensure unmarshal to a slice with a cap and 0 length adjusts the
+ // length properly.
+ testName = "Unmarshal to capped slice"
+ cappedSlice := make([]bool, 0, 1)
+ expectedN = 8
+ expectedErr = nil
+ expectedVal = []bool{true}
+ n, err = Unmarshal(bytes.NewReader(buf), &cappedSlice)
+ if testExpectedURet(t, testName, n, expectedN, err, expectedErr) {
+ if !reflect.DeepEqual(cappedSlice, expectedVal) {
+ t.Errorf("%s: unexpected result - got: %v want: %v\n",
+ testName, cappedSlice, expectedVal)
+ }
+ }
+
+ // Ensure unmarshal to struct with both exported and unexported fields
+ // skips the unexported fields but still unmarshals to the exported
+ // fields.
+ type unexportedStruct struct {
+ unexported int
+ Exported int
+ }
+ testName = "Unmarshal to struct with exported and unexported fields"
+ var tstruct unexportedStruct
+ expectedN = 4
+ expectedErr = nil
+ expectedVal = unexportedStruct{0, 1}
+ n, err = Unmarshal(bytes.NewReader(buf), &tstruct)
+ if testExpectedURet(t, testName, n, expectedN, err, expectedErr) {
+ if !reflect.DeepEqual(tstruct, expectedVal) {
+ t.Errorf("%s: unexpected result - got: %v want: %v\n",
+ testName, tstruct, expectedVal)
+ }
+ }
+
+ // Ensure decode to struct with unsettable fields return expected error.
+ type unsettableStruct struct {
+ Exported int
+ }
+ testName = "Decode to struct with unsettable fields"
+ var ustruct unsettableStruct
+ expectedN = 0
+ expectedErr = error(&UnmarshalError{ErrorCode: ErrNotSettable})
+ n, err = TstDecode(bytes.NewReader(buf))(reflect.ValueOf(ustruct))
+ testExpectedURet(t, testName, n, expectedN, err, expectedErr)
+
+ // Ensure decode to struct with unsettable pointer fields return
+ // expected error.
+ type unsettablePointerStruct struct {
+ Exported *int
+ }
+ testName = "Decode to struct with unsettable pointer fields"
+ var upstruct unsettablePointerStruct
+ expectedN = 0
+ expectedErr = error(&UnmarshalError{ErrorCode: ErrNotSettable})
+ n, err = TstDecode(bytes.NewReader(buf))(reflect.ValueOf(upstruct))
+ testExpectedURet(t, testName, n, expectedN, err, expectedErr)
+}
diff --git a/third_party/libvirt/internal/go-xdr/xdr2/doc.go b/third_party/libvirt/internal/go-xdr/xdr2/doc.go
new file mode 100644
index 0000000..8823d62
--- /dev/null
+++ b/third_party/libvirt/internal/go-xdr/xdr2/doc.go
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2012-2014 Dave Collins
+ *
+ * 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
+ [] <-> XDR Variable-Length Array
+ [#] <-> 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
diff --git a/third_party/libvirt/internal/go-xdr/xdr2/encode.go b/third_party/libvirt/internal/go-xdr/xdr2/encode.go
new file mode 100644
index 0000000..7bac268
--- /dev/null
+++ b/third_party/libvirt/internal/go-xdr/xdr2/encode.go
@@ -0,0 +1,669 @@
+/*
+ * Copyright (c) 2012-2014 Dave Collins
+ *
+ * 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
+ [] -> XDR Variable-Length Array
+ [#] -> 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}
+}
diff --git a/third_party/libvirt/internal/go-xdr/xdr2/encode_test.go b/third_party/libvirt/internal/go-xdr/xdr2/encode_test.go
new file mode 100644
index 0000000..be52de3
--- /dev/null
+++ b/third_party/libvirt/internal/go-xdr/xdr2/encode_test.go
@@ -0,0 +1,594 @@
+/*
+ * Copyright (c) 2012-2014 Dave Collins
+ *
+ * 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_test
+
+import (
+ "fmt"
+ "math"
+ "reflect"
+ "testing"
+ "time"
+
+ . "github.com/projecteru2/yavirt/third_party/libvirt/internal/go-xdr/xdr2"
+)
+
+// testExpectedMRet is a convenience method to test an expected number of bytes
+// written and error for a marshal.
+func testExpectedMRet(t *testing.T, name string, n, wantN int, err, wantErr error) bool {
+ // First ensure the number of bytes written is the expected value. The
+ // bytes read should be accurate even when an error occurs.
+ if n != wantN {
+ t.Errorf("%s: unexpected num bytes written - got: %v want: %v\n",
+ name, n, wantN)
+ return false
+ }
+
+ // Next check for the expected error.
+ if reflect.TypeOf(err) != reflect.TypeOf(wantErr) {
+ t.Errorf("%s: failed to detect error - got: %v <%[2]T> want: %T",
+ name, err, wantErr)
+ return false
+ }
+ if rerr, ok := err.(*MarshalError); ok {
+ if werr, ok := wantErr.(*MarshalError); ok {
+ if rerr.ErrorCode != werr.ErrorCode {
+ t.Errorf("%s: failed to detect error code - "+
+ "got: %v want: %v", name,
+ rerr.ErrorCode, werr.ErrorCode)
+ return false
+ }
+ }
+ }
+
+ return true
+}
+
+// TestMarshal ensures the Marshal function works properly with all types.
+func TestMarshal(t *testing.T) {
+ // Variables for various unsupported Marshal types.
+ var nilInterface interface{}
+ var testChan chan int
+ var testFunc func()
+ var testComplex64 complex64
+ var testComplex128 complex128
+
+ // testInterface is used to test Marshal with values nested in an
+ // interface.
+ testInterface := interface{}(17)
+
+ // structMarshalTestIn is input data for the big struct test of all
+ // supported types.
+ structMarshalTestIn := allTypesTest{
+ 127, // A
+ 255, // B
+ 32767, // C
+ 65535, // D
+ 2147483647, // E
+ 4294967295, // F
+ 9223372036854775807, // G
+ 18446744073709551615, // H
+ true, // I
+ 3.14, // J
+ 3.141592653589793, // K
+ "xdr", // L
+ []byte{1, 2, 3, 4}, // M
+ [3]byte{1, 2, 3}, // N
+ []int16{512, 1024, 2048}, // O
+ [2]subTest{{"one", 1}, {"two", 2}}, // P
+ &subTest{"bar", 3}, // Q
+ map[string]uint32{"map1": 1}, // R
+ time.Unix(1396581888, 0).UTC(), // S
+ }
+
+ // structMarshalTestWant is the expected output after marshalling
+ // structMarshalTestIn.
+ structMarshalTestWant := []byte{
+ 0x00, 0x00, 0x00, 0x7F, // A
+ 0x00, 0x00, 0x00, 0xFF, // B
+ 0x00, 0x00, 0x7F, 0xFF, // C
+ 0x00, 0x00, 0xFF, 0xFF, // D
+ 0x7F, 0xFF, 0xFF, 0xFF, // E
+ 0xFF, 0xFF, 0xFF, 0xFF, // F
+ 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // G
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // H
+ 0x00, 0x00, 0x00, 0x01, // I
+ 0x40, 0x48, 0xF5, 0xC3, // J
+ 0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18, // K
+ 0x00, 0x00, 0x00, 0x03, 0x78, 0x64, 0x72, 0x00, // L
+ 0x00, 0x00, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04, // M
+ 0x01, 0x02, 0x03, 0x00, // N
+ 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, // O
+ 0x00, 0x00, 0x00, 0x03, 0x6F, 0x6E, 0x65, 0x00, // P[0].A
+ 0x00, 0x00, 0x00, 0x01, // P[0].B
+ 0x00, 0x00, 0x00, 0x03, 0x74, 0x77, 0x6F, 0x00, // P[1].A
+ 0x00, 0x00, 0x00, 0x02, // P[1].B
+ 0x00, 0x00, 0x00, 0x03, 0x62, 0x61, 0x72, 0x00, // Q.A
+ 0x00, 0x00, 0x00, 0x03, // Q.B
+ 0x00, 0x00, 0x00, 0x01, // R length
+ 0x00, 0x00, 0x00, 0x04, 0x6D, 0x61, 0x70, 0x31, // R key map1
+ 0x00, 0x00, 0x00, 0x01, // R value map1
+ 0x00, 0x00, 0x00, 0x14, 0x32, 0x30, 0x31, 0x34,
+ 0x2d, 0x30, 0x34, 0x2d, 0x30, 0x34, 0x54, 0x30,
+ 0x33, 0x3a, 0x32, 0x34, 0x3a, 0x34, 0x38, 0x5a, // S
+ }
+
+ tests := []struct {
+ in interface{} // input value
+ wantBytes []byte // expected bytes
+ wantN int // expected/max number of bytes written
+ err error // expected error
+ }{
+ // interface
+ {testInterface, []byte{0x00, 0x00, 0x00, 0x11}, 4, nil},
+ {&testInterface, []byte{0x00, 0x00, 0x00, 0x11}, 4, nil},
+
+ // int8 - XDR Integer
+ {int8(0), []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
+ {int8(64), []byte{0x00, 0x00, 0x00, 0x40}, 4, nil},
+ {int8(127), []byte{0x00, 0x00, 0x00, 0x7F}, 4, nil},
+ {int8(-1), []byte{0xFF, 0xFF, 0xFF, 0xFF}, 4, nil},
+ {int8(-128), []byte{0xFF, 0xFF, 0xFF, 0x80}, 4, nil},
+ // Expected Failure -- Short write
+ {int8(127), []byte{0x00, 0x00, 0x00}, 3, &MarshalError{ErrorCode: ErrIO}},
+
+ // uint8 - XDR Unsigned Integer
+ {uint8(0), []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
+ {uint8(64), []byte{0x00, 0x00, 0x00, 0x40}, 4, nil},
+ {uint8(255), []byte{0x00, 0x00, 0x00, 0xFF}, 4, nil},
+ // Expected Failure -- Short write
+ {uint8(255), []byte{0x00, 0x00}, 2, &MarshalError{ErrorCode: ErrIO}},
+
+ // int16 - XDR Integer
+ {int16(0), []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
+ {int16(1024), []byte{0x00, 0x00, 0x04, 0x00}, 4, nil},
+ {int16(32767), []byte{0x00, 0x00, 0x7F, 0xFF}, 4, nil},
+ {int16(-1), []byte{0xFF, 0xFF, 0xFF, 0xFF}, 4, nil},
+ {int16(-32768), []byte{0xFF, 0xFF, 0x80, 0x00}, 4, nil},
+ // Expected Failure -- Short write
+ {int16(-32768), []byte{0xFF}, 1, &MarshalError{ErrorCode: ErrIO}},
+
+ // uint16 - XDR Unsigned Integer
+ {uint16(0), []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
+ {uint16(1024), []byte{0x00, 0x00, 0x04, 0x00}, 4, nil},
+ {uint16(65535), []byte{0x00, 0x00, 0xFF, 0xFF}, 4, nil},
+ // Expected Failure -- Short write
+ {uint16(65535), []byte{0x00, 0x00}, 2, &MarshalError{ErrorCode: ErrIO}},
+
+ // int32 - XDR Integer
+ {int32(0), []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
+ {int32(262144), []byte{0x00, 0x04, 0x00, 0x00}, 4, nil},
+ {int32(2147483647), []byte{0x7F, 0xFF, 0xFF, 0xFF}, 4, nil},
+ {int32(-1), []byte{0xFF, 0xFF, 0xFF, 0xFF}, 4, nil},
+ {int32(-2147483648), []byte{0x80, 0x00, 0x00, 0x00}, 4, nil},
+ // Expected Failure -- Short write
+ {int32(2147483647), []byte{0x7F, 0xFF, 0xFF}, 3, &MarshalError{ErrorCode: ErrIO}},
+
+ // uint32 - XDR Unsigned Integer
+ {uint32(0), []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
+ {uint32(262144), []byte{0x00, 0x04, 0x00, 0x00}, 4, nil},
+ {uint32(4294967295), []byte{0xFF, 0xFF, 0xFF, 0xFF}, 4, nil},
+ // Expected Failure -- Short write
+ {uint32(262144), []byte{0x00, 0x04, 0x00}, 3, &MarshalError{ErrorCode: ErrIO}},
+
+ // int64 - XDR Hyper Integer
+ {int64(0), []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
+ {int64(1 << 34), []byte{0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00}, 8, nil},
+ {int64(1 << 42), []byte{0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
+ {int64(9223372036854775807), []byte{0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 8, nil},
+ {int64(-1), []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 8, nil},
+ {int64(-9223372036854775808), []byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
+ // Expected Failure -- Short write
+ {int64(-9223372036854775808), []byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 7, &MarshalError{ErrorCode: ErrIO}},
+
+ // uint64 - XDR Unsigned Hyper Integer
+ {uint64(0), []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
+ {uint64(1 << 34), []byte{0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00}, 8, nil},
+ {uint64(1 << 42), []byte{0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
+ {uint64(18446744073709551615), []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 8, nil},
+ {uint64(9223372036854775808), []byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
+ // Expected Failure -- Short write
+ {uint64(9223372036854775808), []byte{0x80}, 1, &MarshalError{ErrorCode: ErrIO}},
+
+ // bool - XDR Integer
+ {false, []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
+ {true, []byte{0x00, 0x00, 0x00, 0x01}, 4, nil},
+ // Expected Failure -- Short write
+ {true, []byte{0x00, 0x00, 0x00}, 3, &MarshalError{ErrorCode: ErrIO}},
+
+ // float32 - XDR Floating-Point
+ {float32(0), []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
+ {float32(3.14), []byte{0x40, 0x48, 0xF5, 0xC3}, 4, nil},
+ {float32(1234567.0), []byte{0x49, 0x96, 0xB4, 0x38}, 4, nil},
+ {float32(math.Inf(-1)), []byte{0xFF, 0x80, 0x00, 0x00}, 4, nil},
+ {float32(math.Inf(0)), []byte{0x7F, 0x80, 0x00, 0x00}, 4, nil},
+ // Expected Failure -- Short write
+ {float32(3.14), []byte{0x40, 0x48, 0xF5}, 3, &MarshalError{ErrorCode: ErrIO}},
+
+ // float64 - XDR Double-precision Floating-Point
+ {float64(0), []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
+ {float64(3.141592653589793), []byte{0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18}, 8, nil},
+ {float64(math.Inf(-1)), []byte{0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
+ {float64(math.Inf(0)), []byte{0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
+ // Expected Failure -- Short write
+ {float64(3.141592653589793), []byte{0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d}, 7, &MarshalError{ErrorCode: ErrIO}},
+
+ // string - XDR String
+ {"", []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
+ {"xdr", []byte{0x00, 0x00, 0x00, 0x03, 0x78, 0x64, 0x72, 0x00}, 8, nil},
+ {"τ=2π", []byte{0x00, 0x00, 0x00, 0x06, 0xCF, 0x84, 0x3D, 0x32, 0xCF, 0x80, 0x00, 0x00}, 12, nil},
+ // Expected Failures -- Short write in length and payload
+ {"xdr", []byte{0x00, 0x00, 0x00}, 3, &MarshalError{ErrorCode: ErrIO}},
+ {"xdr", []byte{0x00, 0x00, 0x00, 0x03, 0x78}, 5, &MarshalError{ErrorCode: ErrIO}},
+
+ // []byte - XDR Variable Opaque
+ {[]byte{0x01}, []byte{0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00}, 8, nil},
+ {[]byte{0x01, 0x02, 0x03}, []byte{0x00, 0x00, 0x00, 0x03, 0x01, 0x02, 0x03, 0x00}, 8, nil},
+ // Expected Failures -- Short write in length and payload
+ {[]byte{0x01}, []byte{0x00, 0x00, 0x00}, 3, &MarshalError{ErrorCode: ErrIO}},
+ {[]byte{0x01}, []byte{0x00, 0x00, 0x00, 0x01, 0x01}, 5, &MarshalError{ErrorCode: ErrIO}},
+
+ // [#]byte - XDR Fixed Opaque
+ {[1]byte{0x01}, []byte{0x01, 0x00, 0x00, 0x00}, 4, nil}, // No & here to test unaddressable arrays
+ {&[2]byte{0x01, 0x02}, []byte{0x01, 0x02, 0x00, 0x00}, 4, nil},
+ {&[3]byte{0x01, 0x02, 0x03}, []byte{0x01, 0x02, 0x03, 0x00}, 4, nil},
+ {&[4]byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, 4, nil},
+ {&[5]byte{0x01, 0x02, 0x03, 0x04, 0x05}, []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x00, 0x00}, 8, nil},
+ // Expected Failure -- Short write
+ {[1]byte{0x01}, []byte{0x01, 0x00, 0x00}, 3, &MarshalError{ErrorCode: ErrIO}},
+
+ // [] - XDR Variable-Length Array
+ {&[]int16{512, 1024, 2048},
+ []byte{0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00},
+ 16, nil},
+ {[]bool{true, false}, []byte{0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00}, 12, nil},
+ // Expected Failures -- Short write in number of elements and
+ // payload
+ {[]bool{true, false}, []byte{0x00, 0x00, 0x00}, 3, &MarshalError{ErrorCode: ErrIO}},
+ {[]bool{true, false}, []byte{0x00, 0x00, 0x00, 0x02, 0x00}, 5, &MarshalError{ErrorCode: ErrIO}},
+
+ // [#] - XDR Fixed-Length Array
+ {&[2]uint32{512, 1024}, []byte{0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00}, 8, nil},
+ // Expected Failures -- Short write in number of elements and
+ // payload
+ {[2]uint32{512, 1024}, []byte{0x00, 0x00, 0x02}, 3, &MarshalError{ErrorCode: ErrIO}},
+ {[2]uint32{512, 1024}, []byte{0x00, 0x00, 0x02, 0x00, 0x00}, 5, &MarshalError{ErrorCode: ErrIO}},
+
+ // map[string]uint32
+ {map[string]uint32{"map1": 1},
+ []byte{0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x6D, 0x61, 0x70, 0x31, 0x00, 0x00, 0x00, 0x01},
+ 16, nil},
+ // Expected Failures -- Short write in number of elements, key,
+ // and payload
+ {map[string]uint32{"map1": 1}, []byte{0x00, 0x00, 0x00}, 3, &MarshalError{ErrorCode: ErrIO}},
+ {map[string]uint32{"map1": 1}, []byte{0x00, 0x00, 0x00, 0x01, 0x00}, 5, &MarshalError{ErrorCode: ErrIO}},
+ {map[string]uint32{"map1": 1}, []byte{0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04}, 8, &MarshalError{ErrorCode: ErrIO}},
+ {map[string]uint32{"map1": 1},
+ []byte{0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x6D, 0x61, 0x70, 0x31},
+ 12, &MarshalError{ErrorCode: ErrIO}},
+
+ // time.Time - XDR String per RFC3339
+ {time.Unix(1396581888, 0).UTC(),
+ []byte{
+ 0x00, 0x00, 0x00, 0x14, 0x32, 0x30, 0x31, 0x34,
+ 0x2d, 0x30, 0x34, 0x2d, 0x30, 0x34, 0x54, 0x30,
+ 0x33, 0x3a, 0x32, 0x34, 0x3a, 0x34, 0x38, 0x5a,
+ }, 24, nil},
+ // Expected Failure -- Short write
+ {time.Unix(1396581888, 0).UTC(), []byte{0x00, 0x00, 0x00, 0x14, 0x32, 0x30, 0x31, 0x34}, 8, &MarshalError{ErrorCode: ErrIO}},
+
+ // struct - XDR Structure -- test struct contains all supported types
+ {&structMarshalTestIn, structMarshalTestWant, len(structMarshalTestWant), nil},
+ {opaqueStruct{[]uint8{1}, [1]uint8{2}},
+ []byte{
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x02,
+ }, 12, nil},
+ // Expected Failures -- Short write in variable length,
+ // variable payload, and fixed payload.
+ {structMarshalTestIn, structMarshalTestWant[:3], 3, &MarshalError{ErrorCode: ErrIO}},
+ {opaqueStruct{[]uint8{1}, [1]uint8{2}}, []byte{0x00, 0x00, 0x00}, 3, &MarshalError{ErrorCode: ErrIO}},
+ {opaqueStruct{[]uint8{1}, [1]uint8{2}}, []byte{0x00, 0x00, 0x00, 0x01}, 4, &MarshalError{ErrorCode: ErrIO}},
+ {opaqueStruct{[]uint8{1}, [1]uint8{2}},
+ []byte{0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01},
+ 8, &MarshalError{ErrorCode: ErrIO}},
+
+ // Expected errors
+ {nilInterface, []byte{}, 0, &MarshalError{ErrorCode: ErrNilInterface}},
+ {&nilInterface, []byte{}, 0, &MarshalError{ErrorCode: ErrNilInterface}},
+ {(*interface{})(nil), []byte{}, 0, &MarshalError{ErrorCode: ErrBadArguments}},
+ {testChan, []byte{}, 0, &MarshalError{ErrorCode: ErrUnsupportedType}},
+ {&testChan, []byte{}, 0, &MarshalError{ErrorCode: ErrUnsupportedType}},
+ {testFunc, []byte{}, 0, &MarshalError{ErrorCode: ErrUnsupportedType}},
+ {&testFunc, []byte{}, 0, &MarshalError{ErrorCode: ErrUnsupportedType}},
+ {testComplex64, []byte{}, 0, &MarshalError{ErrorCode: ErrUnsupportedType}},
+ {&testComplex64, []byte{}, 0, &MarshalError{ErrorCode: ErrUnsupportedType}},
+ {testComplex128, []byte{}, 0, &MarshalError{ErrorCode: ErrUnsupportedType}},
+ {&testComplex128, []byte{}, 0, &MarshalError{ErrorCode: ErrUnsupportedType}},
+ }
+
+ for i, test := range tests {
+ data := newFixedWriter(test.wantN)
+ n, err := Marshal(data, test.in)
+
+ // First ensure the number of bytes written is the expected
+ // value and the error is the expected one.
+ testName := fmt.Sprintf("Marshal #%d", i)
+ testExpectedMRet(t, testName, n, test.wantN, err, test.err)
+
+ rv := data.Bytes()
+ if len(rv) != len(test.wantBytes) {
+ t.Errorf("%s: unexpected len - got: %v want: %v\n",
+ testName, len(rv), len(test.wantBytes))
+ continue
+ }
+ if !reflect.DeepEqual(rv, test.wantBytes) {
+ t.Errorf("%s: unexpected result - got: %v want: %v\n",
+ testName, rv, test.wantBytes)
+ continue
+ }
+ }
+}
+
+// encodeFunc is used to identify which public function of the Encoder object
+// a test applies to.
+type encodeFunc int
+
+const (
+ fEncodeBool encodeFunc = iota
+ fEncodeDouble
+ fEncodeEnum
+ fEncodeFixedOpaque
+ fEncodeFloat
+ fEncodeHyper
+ fEncodeInt
+ fEncodeOpaque
+ fEncodeString
+ fEncodeUhyper
+ fEncodeUint
+)
+
+// Map of encodeFunc values to names for pretty printing.
+var encodeFuncStrings = map[encodeFunc]string{
+ fEncodeBool: "EncodeBool",
+ fEncodeDouble: "EncodeDouble",
+ fEncodeEnum: "EncodeEnum",
+ fEncodeFixedOpaque: "EncodeFixedOpaque",
+ fEncodeFloat: "EncodeFloat",
+ fEncodeHyper: "EncodeHyper",
+ fEncodeInt: "EncodeInt",
+ fEncodeOpaque: "EncodeOpaque",
+ fEncodeString: "EncodeString",
+ fEncodeUhyper: "EncodeUhyper",
+ fEncodeUint: "EncodeUint",
+}
+
+// String implements the fmt.Stringer interface and returns the encode function
+// as a human-readable string.
+func (f encodeFunc) String() string {
+ if s := encodeFuncStrings[f]; s != "" {
+ return s
+ }
+ return fmt.Sprintf("Unknown encodeFunc (%d)", f)
+}
+
+// TestEncoder ensures an Encoder works as intended.
+func TestEncoder(t *testing.T) {
+ tests := []struct {
+ f encodeFunc // function to use to encode
+ in interface{} // input value
+ wantBytes []byte // expected bytes
+ wantN int // expected number of bytes written
+ err error // expected error
+ }{
+ // Bool
+ {fEncodeBool, false, []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
+ {fEncodeBool, true, []byte{0x00, 0x00, 0x00, 0x01}, 4, nil},
+ // Expected Failure -- Short write
+ {fEncodeBool, true, []byte{0x00, 0x00, 0x00}, 3, &MarshalError{ErrorCode: ErrIO}},
+
+ // Double
+ {fEncodeDouble, float64(0), []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
+ {fEncodeDouble, float64(3.141592653589793), []byte{0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18}, 8, nil},
+ {fEncodeDouble, float64(math.Inf(-1)), []byte{0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
+ {fEncodeDouble, float64(math.Inf(0)), []byte{0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
+ // Expected Failure -- Short write
+ {fEncodeDouble, float64(3.141592653589793), []byte{0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d}, 7, &MarshalError{ErrorCode: ErrIO}},
+
+ // Enum
+ {fEncodeEnum, int32(0), []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
+ {fEncodeEnum, int32(1), []byte{0x00, 0x00, 0x00, 0x01}, 4, nil},
+ // Expected Failures -- Invalid enum values
+ {fEncodeEnum, int32(2), []byte{}, 0, &MarshalError{ErrorCode: ErrBadEnumValue}},
+ {fEncodeEnum, int32(1234), []byte{}, 0, &MarshalError{ErrorCode: ErrBadEnumValue}},
+
+ // FixedOpaque
+ {fEncodeFixedOpaque, []byte{0x01}, []byte{0x01, 0x00, 0x00, 0x00}, 4, nil},
+ {fEncodeFixedOpaque, []byte{0x01, 0x02}, []byte{0x01, 0x02, 0x00, 0x00}, 4, nil},
+ {fEncodeFixedOpaque, []byte{0x01, 0x02, 0x03}, []byte{0x01, 0x02, 0x03, 0x00}, 4, nil},
+ {fEncodeFixedOpaque, []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, 4, nil},
+ {fEncodeFixedOpaque, []byte{0x01, 0x02, 0x03, 0x04, 0x05}, []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x00, 0x00}, 8, nil},
+ // Expected Failure -- Short write
+ {fEncodeFixedOpaque, []byte{0x01}, []byte{0x01, 0x00, 0x00}, 3, &MarshalError{ErrorCode: ErrIO}},
+
+ // Float
+ {fEncodeFloat, float32(0), []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
+ {fEncodeFloat, float32(3.14), []byte{0x40, 0x48, 0xF5, 0xC3}, 4, nil},
+ {fEncodeFloat, float32(1234567.0), []byte{0x49, 0x96, 0xB4, 0x38}, 4, nil},
+ {fEncodeFloat, float32(math.Inf(-1)), []byte{0xFF, 0x80, 0x00, 0x00}, 4, nil},
+ {fEncodeFloat, float32(math.Inf(0)), []byte{0x7F, 0x80, 0x00, 0x00}, 4, nil},
+ // Expected Failure -- Short write
+ {fEncodeFloat, float32(3.14), []byte{0x40, 0x48, 0xF5}, 3, &MarshalError{ErrorCode: ErrIO}},
+
+ // Hyper
+ {fEncodeHyper, int64(0), []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
+ {fEncodeHyper, int64(1 << 34), []byte{0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00}, 8, nil},
+ {fEncodeHyper, int64(1 << 42), []byte{0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
+ {fEncodeHyper, int64(9223372036854775807), []byte{0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 8, nil},
+ {fEncodeHyper, int64(-1), []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 8, nil},
+ {fEncodeHyper, int64(-9223372036854775808), []byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
+ // Expected Failure -- Short write
+ {fEncodeHyper, int64(-9223372036854775808), []byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 7, &MarshalError{ErrorCode: ErrIO}},
+
+ // Int
+ {fEncodeInt, int32(0), []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
+ {fEncodeInt, int32(262144), []byte{0x00, 0x04, 0x00, 0x00}, 4, nil},
+ {fEncodeInt, int32(2147483647), []byte{0x7F, 0xFF, 0xFF, 0xFF}, 4, nil},
+ {fEncodeInt, int32(-1), []byte{0xFF, 0xFF, 0xFF, 0xFF}, 4, nil},
+ {fEncodeInt, int32(-2147483648), []byte{0x80, 0x00, 0x00, 0x00}, 4, nil},
+ // Expected Failure -- Short write
+ {fEncodeInt, int32(2147483647), []byte{0x7F, 0xFF, 0xFF}, 3, &MarshalError{ErrorCode: ErrIO}},
+
+ // Opaque
+ {fEncodeOpaque, []byte{0x01}, []byte{0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00}, 8, nil},
+ {fEncodeOpaque, []byte{0x01, 0x02, 0x03}, []byte{0x00, 0x00, 0x00, 0x03, 0x01, 0x02, 0x03, 0x00}, 8, nil},
+ // Expected Failures -- Short write in length and payload
+ {fEncodeOpaque, []byte{0x01}, []byte{0x00, 0x00, 0x00}, 3, &MarshalError{ErrorCode: ErrIO}},
+ {fEncodeOpaque, []byte{0x01}, []byte{0x00, 0x00, 0x00, 0x01, 0x01}, 5, &MarshalError{ErrorCode: ErrIO}},
+
+ // String
+ {fEncodeString, "", []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
+ {fEncodeString, "xdr", []byte{0x00, 0x00, 0x00, 0x03, 0x78, 0x64, 0x72, 0x00}, 8, nil},
+ {fEncodeString, "τ=2π", []byte{0x00, 0x00, 0x00, 0x06, 0xCF, 0x84, 0x3D, 0x32, 0xCF, 0x80, 0x00, 0x00}, 12, nil},
+ // Expected Failures -- Short write in length and payload
+ {fEncodeString, "xdr", []byte{0x00, 0x00, 0x00}, 3, &MarshalError{ErrorCode: ErrIO}},
+ {fEncodeString, "xdr", []byte{0x00, 0x00, 0x00, 0x03, 0x78}, 5, &MarshalError{ErrorCode: ErrIO}},
+
+ // Uhyper
+ {fEncodeUhyper, uint64(0), []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
+ {fEncodeUhyper, uint64(1 << 34), []byte{0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00}, 8, nil},
+ {fEncodeUhyper, uint64(1 << 42), []byte{0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
+ {fEncodeUhyper, uint64(18446744073709551615), []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 8, nil},
+ {fEncodeUhyper, uint64(9223372036854775808), []byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8, nil},
+ // Expected Failure -- Short write
+ {fEncodeUhyper, uint64(9223372036854775808), []byte{0x80}, 1, &MarshalError{ErrorCode: ErrIO}},
+
+ // Uint
+ {fEncodeUint, uint32(0), []byte{0x00, 0x00, 0x00, 0x00}, 4, nil},
+ {fEncodeUint, uint32(262144), []byte{0x00, 0x04, 0x00, 0x00}, 4, nil},
+ {fEncodeUint, uint32(4294967295), []byte{0xFF, 0xFF, 0xFF, 0xFF}, 4, nil},
+ // Expected Failure -- Short write
+ {fEncodeUint, uint32(262144), []byte{0x00, 0x04, 0x00}, 3, &MarshalError{ErrorCode: ErrIO}},
+ }
+
+ validEnums := make(map[int32]bool)
+ validEnums[0] = true
+ validEnums[1] = true
+
+ var err error
+ var n int
+
+ for i, test := range tests {
+ data := newFixedWriter(test.wantN)
+ enc := NewEncoder(data)
+ switch test.f {
+ case fEncodeBool:
+ in := test.in.(bool)
+ n, err = enc.EncodeBool(in)
+ case fEncodeDouble:
+ in := test.in.(float64)
+ n, err = enc.EncodeDouble(in)
+ case fEncodeEnum:
+ in := test.in.(int32)
+ n, err = enc.EncodeEnum(in, validEnums)
+ case fEncodeFixedOpaque:
+ in := test.in.([]byte)
+ n, err = enc.EncodeFixedOpaque(in)
+ case fEncodeFloat:
+ in := test.in.(float32)
+ n, err = enc.EncodeFloat(in)
+ case fEncodeHyper:
+ in := test.in.(int64)
+ n, err = enc.EncodeHyper(in)
+ case fEncodeInt:
+ in := test.in.(int32)
+ n, err = enc.EncodeInt(in)
+ case fEncodeOpaque:
+ in := test.in.([]byte)
+ n, err = enc.EncodeOpaque(in)
+ case fEncodeString:
+ in := test.in.(string)
+ n, err = enc.EncodeString(in)
+ case fEncodeUhyper:
+ in := test.in.(uint64)
+ n, err = enc.EncodeUhyper(in)
+ case fEncodeUint:
+ in := test.in.(uint32)
+ n, err = enc.EncodeUint(in)
+ default:
+ t.Errorf("%v #%d unrecognized function", test.f, i)
+ continue
+ }
+
+ // First ensure the number of bytes written is the expected
+ // value and the error is the expected one.
+ testName := fmt.Sprintf("%v #%d", test.f, i)
+ testExpectedMRet(t, testName, n, test.wantN, err, test.err)
+
+ // Finally, ensure the written bytes are what is expected.
+ rv := data.Bytes()
+ if len(rv) != len(test.wantBytes) {
+ t.Errorf("%s: unexpected len - got: %v want: %v\n",
+ testName, len(rv), len(test.wantBytes))
+ continue
+ }
+ if !reflect.DeepEqual(rv, test.wantBytes) {
+ t.Errorf("%s: unexpected result - got: %v want: %v\n",
+ testName, rv, test.wantBytes)
+ continue
+ }
+ }
+}
+
+// TestMarshalCorners ensures the Marshal function properly handles various
+// cases not already covered by the other tests.
+func TestMarshalCorners(t *testing.T) {
+ // Ensure encode of an invalid reflect value returns the expected
+ // error.
+ testName := "Encode invalid reflect value"
+ expectedN := 0
+ expectedErr := error(&MarshalError{ErrorCode: ErrUnsupportedType})
+ expectedVal := []byte{}
+ data := newFixedWriter(expectedN)
+ n, err := TstEncode(data)(reflect.Value{})
+ testExpectedMRet(t, testName, n, expectedN, err, expectedErr)
+ if !reflect.DeepEqual(data.Bytes(), expectedVal) {
+ t.Errorf("%s: unexpected result - got: %x want: %x\n",
+ testName, data.Bytes(), expectedVal)
+ }
+
+ // Ensure marshal of a struct with both exported and unexported fields
+ // skips the unexported fields but still marshals to the exported
+ // fields.
+ type unexportedStruct struct {
+ unexported int
+ Exported int
+ }
+ testName = "Marshal struct with exported and unexported fields"
+ tstruct := unexportedStruct{0, 1}
+ expectedN = 4
+ expectedErr = nil
+ expectedVal = []byte{0x00, 0x00, 0x00, 0x01}
+ data = newFixedWriter(expectedN)
+ n, err = Marshal(data, tstruct)
+ testExpectedMRet(t, testName, n, expectedN, err, expectedErr)
+ if !reflect.DeepEqual(data.Bytes(), expectedVal) {
+ t.Errorf("%s: unexpected result - got: %x want: %x\n",
+ testName, data.Bytes(), expectedVal)
+ }
+
+}
diff --git a/third_party/libvirt/internal/go-xdr/xdr2/error.go b/third_party/libvirt/internal/go-xdr/xdr2/error.go
new file mode 100644
index 0000000..42079ad
--- /dev/null
+++ b/third_party/libvirt/internal/go-xdr/xdr2/error.go
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2012-2014 Dave Collins
+ *
+ * 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
+}
diff --git a/third_party/libvirt/internal/go-xdr/xdr2/error_test.go b/third_party/libvirt/internal/go-xdr/xdr2/error_test.go
new file mode 100644
index 0000000..8fc3356
--- /dev/null
+++ b/third_party/libvirt/internal/go-xdr/xdr2/error_test.go
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2014 Dave Collins
+ *
+ * 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_test
+
+import (
+ "errors"
+ "testing"
+
+ . "github.com/projecteru2/yavirt/third_party/libvirt/internal/go-xdr/xdr2"
+)
+
+// TestErrorCodeStringer tests the stringized output for the ErrorCode type.
+func TestErrorCodeStringer(t *testing.T) {
+ tests := []struct {
+ in ErrorCode
+ want string
+ }{
+ {ErrBadArguments, "ErrBadArguments"},
+ {ErrUnsupportedType, "ErrUnsupportedType"},
+ {ErrBadEnumValue, "ErrBadEnumValue"},
+ {ErrNotSettable, "ErrNotSettable"},
+ {ErrOverflow, "ErrOverflow"},
+ {ErrNilInterface, "ErrNilInterface"},
+ {ErrIO, "ErrIO"},
+ {ErrParseTime, "ErrParseTime"},
+ {0xffff, "Unknown ErrorCode (65535)"},
+ }
+
+ for i, test := range tests {
+ result := test.in.String()
+ if result != test.want {
+ t.Errorf("String #%d\n got: %s want: %s", i, result,
+ test.want)
+ continue
+ }
+ }
+}
+
+// TestUnmarshalError tests the error output for the UnmarshalError type.
+func TestUnmarshalError(t *testing.T) {
+ tests := []struct {
+ in UnmarshalError
+ want string
+ }{
+ {
+ UnmarshalError{
+ ErrorCode: ErrIO,
+ Func: "test",
+ Description: "EOF while decoding 5 bytes",
+ Value: "testval",
+ },
+ "xdr:test: EOF while decoding 5 bytes - read: 'testval'",
+ },
+ {
+ UnmarshalError{
+ ErrorCode: ErrBadEnumValue,
+ Func: "test",
+ Description: "invalid enum",
+ Value: "testenum",
+ },
+ "xdr:test: invalid enum - read: 'testenum'",
+ },
+ {
+ UnmarshalError{
+ ErrorCode: ErrNilInterface,
+ Func: "test",
+ Description: "can't unmarshal to nil interface",
+ Value: nil,
+ },
+ "xdr:test: can't unmarshal to nil interface",
+ },
+ }
+
+ for i, test := range tests {
+ result := test.in.Error()
+ if result != test.want {
+ t.Errorf("Error #%d\n got: %s want: %s", i, result,
+ test.want)
+ continue
+ }
+ }
+}
+
+// TestMarshalError tests the error output for the MarshalError type.
+func TestMarshalError(t *testing.T) {
+ tests := []struct {
+ in MarshalError
+ want string
+ }{
+ {
+ MarshalError{
+ ErrorCode: ErrIO,
+ Func: "test",
+ Description: "EOF while encoding 5 bytes",
+ Value: []byte{0x01, 0x02},
+ },
+ "xdr:test: EOF while encoding 5 bytes - wrote: '[1 2]'",
+ },
+ {
+ MarshalError{
+ ErrorCode: ErrBadEnumValue,
+ Func: "test",
+ Description: "invalid enum",
+ Value: "testenum",
+ },
+ "xdr:test: invalid enum - value: 'testenum'",
+ },
+ {
+ MarshalError{
+ ErrorCode: ErrNilInterface,
+ Func: "test",
+ Description: "can't marshal to nil interface",
+ Value: nil,
+ },
+ "xdr:test: can't marshal to nil interface",
+ },
+ }
+
+ for i, test := range tests {
+ result := test.in.Error()
+ if result != test.want {
+ t.Errorf("Error #%d\n got: %s want: %s", i, result,
+ test.want)
+ continue
+ }
+ }
+}
+
+// TestIOErr ensures the IsIO function behaves as expected given different error
+// types.
+func TestIOErr(t *testing.T) {
+ tests := []struct {
+ in error
+ want bool
+ }{
+ {
+ &MarshalError{
+ ErrorCode: ErrIO,
+ Func: "test",
+ Description: "EOF while encoding 5 bytes",
+ Value: []byte{0x01, 0x02},
+ },
+ true,
+ },
+ {
+ &MarshalError{
+ ErrorCode: ErrUnsupportedType,
+ Func: "test",
+ Description: "ErrUnsupportedType",
+ Value: []byte{},
+ },
+ false,
+ },
+ {
+ &UnmarshalError{
+ ErrorCode: ErrIO,
+ Func: "test",
+ Description: "EOF while decoding 5 bytes",
+ Value: []byte{0x01, 0x02},
+ },
+ true,
+ },
+ {
+ &UnmarshalError{
+ ErrorCode: ErrUnsupportedType,
+ Func: "test",
+ Description: "ErrUnsupportedType",
+ Value: []byte{},
+ },
+ false,
+ },
+ {
+ errors.New("boom"),
+ false,
+ },
+ }
+
+ for i, test := range tests {
+ result := IsIO(test.in)
+ if result != test.want {
+ t.Errorf("Error #%d\n got: %v want: %v", i, result,
+ test.want)
+ continue
+ }
+ }
+}
diff --git a/third_party/libvirt/internal/go-xdr/xdr2/example_test.go b/third_party/libvirt/internal/go-xdr/xdr2/example_test.go
new file mode 100644
index 0000000..5861478
--- /dev/null
+++ b/third_party/libvirt/internal/go-xdr/xdr2/example_test.go
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2012-2014 Dave Collins
+ *
+ * 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_test
+
+import (
+ "bytes"
+ "fmt"
+
+ "github.com/projecteru2/yavirt/third_party/libvirt/internal/go-xdr/xdr2"
+)
+
+// This example demonstrates how to use Marshal to automatically XDR encode
+// data using reflection.
+func ExampleMarshal() {
+ // Hypothetical image header format.
+ type ImageHeader struct {
+ Signature [3]byte
+ Version uint32
+ IsGrayscale bool
+ NumSections uint32
+ }
+
+ // Sample image header data.
+ h := ImageHeader{[3]byte{0xAB, 0xCD, 0xEF}, 2, true, 10}
+
+ // Use marshal to automatically determine the appropriate underlying XDR
+ // types and encode.
+ var w bytes.Buffer
+ bytesWritten, err := xdr.Marshal(&w, &h)
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+
+ fmt.Println("bytes written:", bytesWritten)
+ fmt.Println("encoded data:", w.Bytes())
+
+ // Output:
+ // bytes written: 16
+ // encoded data: [171 205 239 0 0 0 0 2 0 0 0 1 0 0 0 10]
+}
+
+// This example demonstrates how to use Unmarshal to decode XDR encoded data
+// from a byte slice into a struct.
+func ExampleUnmarshal() {
+ // Hypothetical image header format.
+ type ImageHeader struct {
+ Signature [3]byte
+ Version uint32
+ IsGrayscale bool
+ NumSections uint32
+ }
+
+ // XDR encoded data described by the above structure. Typically this
+ // would be read from a file or across the network, but use a manual
+ // byte array here as an example.
+ encodedData := []byte{
+ 0xAB, 0xCD, 0xEF, 0x00, // Signature
+ 0x00, 0x00, 0x00, 0x02, // Version
+ 0x00, 0x00, 0x00, 0x01, // IsGrayscale
+ 0x00, 0x00, 0x00, 0x0A, // NumSections
+ }
+
+ // Declare a variable to provide Unmarshal with a concrete type and
+ // instance to decode into.
+ var h ImageHeader
+ bytesRead, err := xdr.Unmarshal(bytes.NewReader(encodedData), &h)
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+
+ fmt.Println("bytes read:", bytesRead)
+ fmt.Printf("h: %+v", h)
+
+ // Output:
+ // bytes read: 16
+ // h: {Signature:[171 205 239] Version:2 IsGrayscale:true NumSections:10}
+}
+
+// This example demonstrates how to manually decode XDR encoded data from a
+// reader. Compare this example with the Unmarshal example which performs the
+// same task automatically by utilizing a struct type definition and reflection.
+func ExampleNewDecoder() {
+ // XDR encoded data for a hypothetical ImageHeader struct as follows:
+ // type ImageHeader struct {
+ // Signature [3]byte
+ // Version uint32
+ // IsGrayscale bool
+ // NumSections uint32
+ // }
+ encodedData := []byte{
+ 0xAB, 0xCD, 0xEF, 0x00, // Signature
+ 0x00, 0x00, 0x00, 0x02, // Version
+ 0x00, 0x00, 0x00, 0x01, // IsGrayscale
+ 0x00, 0x00, 0x00, 0x0A, // NumSections
+ }
+
+ // Get a new decoder for manual decoding.
+ dec := xdr.NewDecoder(bytes.NewReader(encodedData))
+
+ signature, _, err := dec.DecodeFixedOpaque(3)
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+
+ version, _, err := dec.DecodeUint()
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+
+ isGrayscale, _, err := dec.DecodeBool()
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+
+ numSections, _, err := dec.DecodeUint()
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+
+ fmt.Println("signature:", signature)
+ fmt.Println("version:", version)
+ fmt.Println("isGrayscale:", isGrayscale)
+ fmt.Println("numSections:", numSections)
+
+ // Output:
+ // signature: [171 205 239]
+ // version: 2
+ // isGrayscale: true
+ // numSections: 10
+}
+
+// This example demonstrates how to manually encode XDR data from Go variables.
+// Compare this example with the Marshal example which performs the same task
+// automatically by utilizing a struct type definition and reflection.
+func ExampleNewEncoder() {
+ // Data for a hypothetical ImageHeader struct as follows:
+ // type ImageHeader struct {
+ // Signature [3]byte
+ // Version uint32
+ // IsGrayscale bool
+ // NumSections uint32
+ // }
+ signature := []byte{0xAB, 0xCD, 0xEF}
+ version := uint32(2)
+ isGrayscale := true
+ numSections := uint32(10)
+
+ // Get a new encoder for manual encoding.
+ var w bytes.Buffer
+ enc := xdr.NewEncoder(&w)
+
+ _, err := enc.EncodeFixedOpaque(signature)
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+
+ _, err = enc.EncodeUint(version)
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+
+ _, err = enc.EncodeBool(isGrayscale)
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+
+ _, err = enc.EncodeUint(numSections)
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+
+ fmt.Println("encoded data:", w.Bytes())
+
+ // Output:
+ // encoded data: [171 205 239 0 0 0 0 2 0 0 0 1 0 0 0 10]
+}
diff --git a/third_party/libvirt/internal/go-xdr/xdr2/fixedIO_test.go b/third_party/libvirt/internal/go-xdr/xdr2/fixedIO_test.go
new file mode 100644
index 0000000..d329a9a
--- /dev/null
+++ b/third_party/libvirt/internal/go-xdr/xdr2/fixedIO_test.go
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2014 Dave Collins
+ *
+ * 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_test
+
+import (
+ "io"
+)
+
+// fixedWriter implements the io.Writer interface and intentially allows
+// testing of error paths by forcing short writes.
+type fixedWriter struct {
+ b []byte
+ pos int
+}
+
+// Write writes the contents of p to w. When the contents of p would cause
+// the writer to exceed the maximum allowed size of the fixed writer, the writer
+// writes as many bytes as possible to reach the maximum allowed size and
+// io.ErrShortWrite is returned.
+//
+// This satisfies the io.Writer interface.
+func (w *fixedWriter) Write(p []byte) (int, error) {
+ if w.pos+len(p) > cap(w.b) {
+ n := copy(w.b[w.pos:], p[:cap(w.b)-w.pos])
+ w.pos += n
+ return n, io.ErrShortWrite
+ }
+
+ n := copy(w.b[w.pos:], p)
+ w.pos += n
+ return n, nil
+}
+
+// Bytes returns the bytes already written to the fixed writer.
+func (w *fixedWriter) Bytes() []byte {
+ return w.b
+}
+
+// newFixedWriter returns a new io.Writer that will error once more bytes than
+// the specified max have been written.
+func newFixedWriter(max int) *fixedWriter {
+ b := make([]byte, max, max)
+ fw := fixedWriter{b, 0}
+ return &fw
+}
diff --git a/third_party/libvirt/internal/go-xdr/xdr2/internal_test.go b/third_party/libvirt/internal/go-xdr/xdr2/internal_test.go
new file mode 100644
index 0000000..bd180d4
--- /dev/null
+++ b/third_party/libvirt/internal/go-xdr/xdr2/internal_test.go
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2012-2014 Dave Collins
+ *
+ * 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.
+ */
+
+/*
+This test file is part of the xdr package rather than than the xdr_test package
+so it can bridge access to the internals to properly test cases which are either
+not possible or can't reliably be tested via the public interface. The functions
+are only exported while the tests are being run.
+*/
+
+package xdr
+
+import (
+ "io"
+ "reflect"
+)
+
+// TstEncode creates a new Encoder to the passed writer and returns the internal
+// encode function on the Encoder.
+func TstEncode(w io.Writer) func(v reflect.Value) (int, error) {
+ enc := NewEncoder(w)
+ return enc.encode
+}
+
+// TstDecode creates a new Decoder for the passed reader and returns the
+// internal decode function on the Decoder.
+func TstDecode(r io.Reader) func(v reflect.Value) (int, error) {
+ dec := NewDecoder(r)
+ return dec.decode
+}
diff --git a/third_party/libvirt/internal/lvgen/constants.tmpl b/third_party/libvirt/internal/lvgen/constants.tmpl
new file mode 100644
index 0000000..6dcc56b
--- /dev/null
+++ b/third_party/libvirt/internal/lvgen/constants.tmpl
@@ -0,0 +1,36 @@
+// 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
+
+// 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.
+const (
+ // From enums:
+{{range .EnumVals}} // {{.Name}} is libvirt's {{.LVName}}
+ {{.Name}} = {{.Val}}
+{{end}}
+
+ // From consts:
+{{range .Consts}} // {{.Name}} is libvirt's {{.LVName}}
+ {{.Name}} = {{.Val}}
+{{end -}}
+)
diff --git a/third_party/libvirt/internal/lvgen/gen/main.go b/third_party/libvirt/internal/lvgen/gen/main.go
new file mode 100644
index 0000000..4602b72
--- /dev/null
+++ b/third_party/libvirt/internal/lvgen/gen/main.go
@@ -0,0 +1,61 @@
+// Copyright 2017 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 main
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "github.com/projecteru2/yavirt/third_party/libvirt/internal/lvgen"
+)
+
+var protoPaths = [...]string{
+ "src/remote/remote_protocol.x",
+ "src/remote/qemu_protocol.x",
+}
+
+func main() {
+ lvPath := os.Getenv("LIBVIRT_SOURCE")
+ if lvPath == "" {
+ fmt.Println("set $LIBVIRT_SOURCE to point to the root of the libvirt sources and retry")
+ os.Exit(1)
+ }
+ fmt.Println("protocol file processing")
+ for _, p := range protoPaths {
+ protoPath := filepath.Join(lvPath, p)
+ fmt.Println(" processing", p)
+ err := processProto(protoPath)
+ if err != nil {
+ fmt.Println("go-libvirt code generator failed:", err)
+ os.Exit(1)
+ }
+ }
+}
+
+func processProto(lvFile string) error {
+ rdr, err := os.Open(lvFile)
+ if err != nil {
+ fmt.Printf("failed to open protocol file at %v: %v\n", lvFile, err)
+ os.Exit(1)
+ }
+ defer rdr.Close()
+
+ // extract the base filename, without extension, for the generator to use.
+ name := strings.TrimSuffix(filepath.Base(lvFile), filepath.Ext(lvFile))
+
+ return lvgen.Generate(name, rdr)
+}
diff --git a/third_party/libvirt/internal/lvgen/generate.go b/third_party/libvirt/internal/lvgen/generate.go
new file mode 100644
index 0000000..2ff318e
--- /dev/null
+++ b/third_party/libvirt/internal/lvgen/generate.go
@@ -0,0 +1,865 @@
+// Copyright 2017 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 lvgen
+
+import (
+ "fmt"
+ "go/ast"
+ "io"
+ "os"
+ "strconv"
+ "strings"
+ "text/template"
+ "unicode"
+ "unicode/utf8"
+
+ "golang.org/x/tools/go/loader"
+)
+
+// If you're making changes to the generator, or troubleshooting the generated
+// code, the docs for sunrpc and xdr (the line encoding) are helpful:
+// https://docs.oracle.com/cd/E26502_01/html/E35597/
+
+// ConstItem stores an const's symbol and value from the parser. This struct is
+// also used for enums.
+type ConstItem struct {
+ Name string
+ LVName string
+ Val string
+}
+
+// Generator holds all the information parsed out of the protocol file.
+type Generator struct {
+ // Enums holds the enum declarations. The type of enums is always int32.
+ Enums []Decl
+ // EnumVals holds the list of enum values found by the parser. In sunrpc as
+ // in go, these are not separately namespaced.
+ EnumVals []ConstItem
+ // Consts holds all the const items found by the parser.
+ Consts []ConstItem
+ // Structs holds a list of all the structs found by the parser
+ Structs []Structure
+ // StructMap is a map of the structs we find for quick searching.
+ StructMap map[string]int
+ // Typedefs holds all the type definitions from 'typedef ...' lines.
+ Typedefs []Typedef
+ // Unions holds all the discriminated unions.
+ Unions []Union
+ // UnionMap is a map of the unions we find for quick searching.
+ UnionMap map[string]int
+ // Procs holds all the discovered libvirt procedures.
+ Procs []Proc
+}
+
+func newGenerator() Generator {
+ return Generator{
+ StructMap: make(map[string]int),
+ UnionMap: make(map[string]int),
+ }
+}
+
+// Gen accumulates items as the parser runs, and is then used to produce the
+// output.
+var Gen Generator
+
+// CurrentEnumVal is the auto-incrementing value assigned to enums that aren't
+// explicitly given a value.
+var CurrentEnumVal int64
+
+// goEquivTypes maps the basic types defined in the rpc spec to their golang
+// equivalents.
+var goEquivTypes = map[string]string{
+ // Some of the identifiers in the rpc specification are reserved words or
+ // pre-existing types in go. This renames them to something safe.
+ "type": "lvtype",
+ "error": "lverror",
+ "nil": "lvnil",
+
+ // The libvirt spec uses this NonnullString type, which is a string with a
+ // specified maximum length. This makes the go code more confusing, and
+ // we're not enforcing the limit anyway, so collapse it here. This also
+ // requires us to ditch the typedef that would otherwise be generated.
+ "NonnullString": "string",
+
+ // We rename Error to remote_error in order to use libvirt.Error as the exposed
+ // type, only with necessary fields exposed
+ "Error": "remote_error",
+
+ // TODO: Get rid of these. They're only needed because we lose information
+ // that the parser has (the parser knows it has emitted a go type), and then
+ // we capitalize types to make them public.
+ "Int": "int",
+ "Uint": "uint",
+ "Int8": "int8",
+ "Uint8": "uint8",
+ "Int16": "int16",
+ "Uint16": "uint16",
+ "Int32": "int32",
+ "Uint32": "uint32",
+ "Int64": "int64",
+ "Uint64": "uint64",
+ "Float32": "float32",
+ "Float64": "float64",
+ "Bool": "bool",
+ "Byte": "byte",
+}
+
+// These defines are from libvirt-common.h. They should be fetched from there,
+// but for now they're hardcoded here. (These are the discriminant values for
+// TypedParams.)
+var lvTypedParams = map[string]uint32{
+ "VIR_TYPED_PARAM_INT": 1,
+ "VIR_TYPED_PARAM_UINT": 2,
+ "VIR_TYPED_PARAM_LLONG": 3,
+ "VIR_TYPED_PARAM_ULLONG": 4,
+ "VIR_TYPED_PARAM_DOUBLE": 5,
+ "VIR_TYPED_PARAM_BOOLEAN": 6,
+ "VIR_TYPED_PARAM_STRING": 7,
+}
+
+// Decl records a declaration, like 'int x' or 'remote_nonnull_string str'
+type Decl struct {
+ Name, LVName, Type string
+}
+
+// NewDecl returns a new declaration struct.
+func NewDecl(identifier, itype string) *Decl {
+ goidentifier := identifierTransform(identifier)
+ itype = typeTransform(itype)
+ return &Decl{Name: goidentifier, LVName: identifier, Type: itype}
+}
+
+// Structure records the name and members of a struct definition.
+type Structure struct {
+ Name string
+ LVName string
+ Members []Decl
+}
+
+// Typedef holds the name and underlying type for a typedef.
+type Typedef struct {
+ Decl
+}
+
+// Union holds a "discriminated union", which consists of a discriminant, which
+// tells you what kind of thing you're looking at, and a number of encodings.
+type Union struct {
+ Name string
+ DiscriminantType string
+ Cases []Case
+}
+
+// Case holds a single case of a discriminated union.
+type Case struct {
+ CaseName string
+ DiscriminantVal string
+ Decl
+}
+
+// Proc holds information about a libvirt procedure the parser has found.
+type Proc struct {
+ Program string // The program name. Blank for REMOTE_ procs.
+ Num int64 // The libvirt procedure number.
+ Name string // The name of the go func.
+ LVName string // The name of the libvirt proc this wraps.
+ Args []Decl // The contents of the args struct for this procedure.
+ Ret []Decl // The contents of the ret struct for this procedure.
+ ArgsStruct string // The name of the args struct for this procedure.
+ RetStruct string // The name of the ret struct for this procedure.
+ ReadStreamIdx int // The index of read stream in function argument list
+ WriteStreamIdx int // The index of read stream in function argument list
+}
+
+// ProcMeta holds information about a libvirt procedure, and is used during code
+// generation.
+type ProcMeta struct {
+ ReadStream int
+ WriteStream int
+}
+
+type structStack []*Structure
+
+// CurrentStruct will point to a struct record if we're in a struct declaration.
+// When the parser adds a declaration, it will be added to the open struct if
+// there is one.
+var CurrentStruct structStack
+
+// Since it's possible to have an embedded struct definition, this implements
+// a stack to keep track of the current structure.
+func (s *structStack) empty() bool {
+ return len(*s) == 0
+}
+func (s *structStack) push(st *Structure) {
+ *s = append(*s, st)
+}
+func (s *structStack) pop() *Structure {
+ if s.empty() {
+ return nil
+ }
+ st := (*s)[len(*s)-1]
+ *s = (*s)[:len(*s)-1]
+ return st
+}
+func (s *structStack) peek() *Structure {
+ if s.empty() {
+ return nil
+ }
+ return (*s)[len(*s)-1]
+}
+
+// CurrentTypedef will point to a typedef record if we're parsing one. Typedefs
+// can define a struct or union type, but the preferred for is struct xxx{...},
+// so we may never see the typedef form in practice.
+var CurrentTypedef *Typedef
+
+// CurrentUnion holds the current discriminated union record.
+var CurrentUnion *Union
+
+// CurrentCase holds the current case record while the parser is in a union and
+// a case statement.
+var CurrentCase *Case
+
+// Generate will output go bindings for libvirt. The lvPath parameter should be
+// the path to the root of the libvirt source directory to use for the
+// generation.
+func Generate(name string, proto io.Reader) error {
+ // Start with a clean state
+ Gen = newGenerator()
+
+ lexer, err := NewLexer(proto)
+ if err != nil {
+ return err
+ }
+ go lexer.Run()
+ parser := yyNewParser()
+ yyErrorVerbose = true
+ // Turn this on if you're debugging.
+ // yyDebug = 3
+ rv := parser.Parse(lexer)
+ if rv != 0 {
+ return fmt.Errorf("failed to parse libvirt protocol: %v", rv)
+ }
+
+ // When parsing is done, we can link the procedures we've found to their
+ // argument types.
+ procLink()
+
+ // Generate and write the output.
+ constsName := fmt.Sprintf("../constants/%v.gen.go", name)
+ constFile, err := os.Create(constsName)
+ if err != nil {
+ return err
+ }
+ defer constFile.Close()
+ procName := fmt.Sprintf("../../%v.gen.go", name)
+ procFile, err := os.Create(procName)
+ if err != nil {
+ return err
+ }
+ defer procFile.Close()
+
+ return genGo(constFile, procFile)
+}
+
+// genGo is called when the parsing is done; it generates the golang output
+// files using templates.
+func genGo(constFile, procFile io.Writer) error {
+ t, err := template.ParseFiles("constants.tmpl")
+ if err != nil {
+ return err
+ }
+ if err = t.Execute(constFile, Gen); err != nil {
+ return err
+ }
+
+ t, err = template.ParseFiles("procedures.tmpl")
+ if err != nil {
+ return err
+ }
+ return t.Execute(procFile, Gen)
+}
+
+// constNameTransform changes an upcased, snake-style name like
+// REMOTE_PROTOCOL_VERSION to a comfortable Go name like ProtocolVersion. It
+// also tries to upcase abbreviations so a name like DOMAIN_GET_XML becomes
+// DomainGetXML, not DomainGetXml.
+func constNameTransform(name string) string {
+ decamelize := strings.ContainsRune(name, '_')
+ name = strings.TrimPrefix(name, "REMOTE_")
+ if decamelize {
+ name = fromSnakeToCamel(name)
+ }
+ name = fixAbbrevs(name)
+ return name
+}
+
+// procNameTransform returns a Go name for a remote procedure.
+func procNameTransform(name string) string {
+ // Remove "PROC_" from the name, then transform it like a const name.
+ nn := strings.Replace(name, "PROC_", "", 1)
+ return constNameTransform(nn)
+}
+
+// procProgramName returns the program associated with a remote procedure.
+// Procedure names follow the pattern, "_PROC_". This
+// returns the part, as a camel-cased value. This value will be empty
+// for REMOTE_PROC procedures because we trim REMOTE_, but that's OK.
+func procProgramName(name string) string {
+ ix := strings.Index(name, "PROC_")
+ return constNameTransform(name[:ix])
+}
+
+func identifierTransform(name string) string {
+ decamelize := strings.ContainsRune(name, '_')
+ nn := strings.TrimPrefix(name, "remote_")
+ nn = strings.TrimPrefix(nn, "VIR_")
+ if decamelize {
+ nn = fromSnakeToCamel(nn)
+ } else {
+ nn = publicize(nn)
+ }
+ nn = fixAbbrevs(nn)
+ nn = checkIdentifier(nn)
+ // Many types in libvirt are prefixed with "Nonnull" to distinguish them
+ // from optional values. We add "Opt" to optional values and strip "Nonnull"
+ // because this makes the go code clearer.
+ nn = strings.TrimPrefix(nn, "Nonnull")
+ return nn
+}
+
+func typeTransform(name string) string {
+ nn := strings.TrimLeft(name, "*[]")
+ diff := len(name) - len(nn)
+ nn = identifierTransform(nn)
+ return name[0:diff] + nn
+}
+
+func publicize(name string) string {
+ if len(name) <= 0 {
+ return name
+ }
+ r, n := utf8.DecodeRuneInString(name)
+ name = string(unicode.ToUpper(r)) + name[n:]
+ return name
+}
+
+// fromSnakeToCamel transmutes a snake-cased string to a camel-cased one. All
+// runes that follow an underscore are up-cased, and the underscores themselves
+// are omitted.
+//
+// ex: "PROC_DOMAIN_GET_METADATA" -> "ProcDomainGetMetadata"
+func fromSnakeToCamel(s string) string {
+ buf := make([]rune, 0, len(s))
+ // Start rune will be upper case - we generate all public symbols.
+ hump := true
+
+ for _, r := range s {
+ if r == '_' {
+ hump = true
+ } else {
+ var transform func(rune) rune
+ if hump == true {
+ transform = unicode.ToUpper
+ } else {
+ transform = unicode.ToLower
+ }
+ buf = append(buf, transform(r))
+ hump = false
+ }
+ }
+
+ return string(buf)
+}
+
+// abbrevs is a list of abbreviations which should be all upper-case in a name.
+// (This is really just to keep the go linters happy and to produce names that
+// are intuitive to a go developer.)
+var abbrevs = []string{"Xml", "Io", "Uuid", "Cpu", "Id", "Ip", "Qemu"}
+
+// fixAbbrevs up-cases all instances of anything in the 'abbrevs' array. This
+// would be a simple matter, but we don't want to upcase an abbreviation if it's
+// actually part of a larger word, so it's not so simple.
+func fixAbbrevs(s string) string {
+ for _, a := range abbrevs {
+ for loc := 0; ; {
+ loc = strings.Index(s[loc:], a)
+ if loc == -1 {
+ break
+ }
+ r := 'A'
+ if len(a) < len(s[loc:]) {
+ r, _ = utf8.DecodeRune([]byte(s[loc+len(a):]))
+ }
+ if unicode.IsLower(r) == false {
+ s = s[:loc] + strings.Replace(s[loc:], a, strings.ToUpper(a), 1)
+ }
+ loc++
+ }
+ }
+ return s
+}
+
+// procLink associates a libvirt procedure with the types that are its arguments
+// and return values, filling out those fields in the procedure struct. These
+// types are extracted by iterating through the argument and return structures
+// defined in the protocol file. If one or both of these structs is not defined
+// then either the args or return values are empty.
+func procLink() {
+ flagTypes := mapFlagTypes()
+
+ for ix, proc := range Gen.Procs {
+ argsName := proc.Name + "Args"
+ retName := proc.Name + "Ret"
+ argsIx, hasArgs := Gen.StructMap[argsName]
+ retIx, hasRet := Gen.StructMap[retName]
+ if hasArgs {
+ argsStruct := Gen.Structs[argsIx]
+ Gen.Procs[ix].ArgsStruct = argsStruct.Name
+ changeFlagType(proc.Name, &argsStruct, flagTypes)
+ Gen.Procs[ix].Args = argsStruct.Members
+ }
+ if hasRet {
+ retStruct := Gen.Structs[retIx]
+ Gen.Procs[ix].RetStruct = retStruct.Name
+ Gen.Procs[ix].Ret = retStruct.Members
+ }
+ }
+}
+
+// mapFlagTypes builds a map of the C types which appear to correspond to the
+// various flags fields in libvirt calls. Determining whether a type actually
+// corresponds to a set of flags is done by pattern matching the type name;
+// libvirt isn't completely consistent about the names of flag types, but they
+// all seem to have one of three suffixes, so that's what we look for here.
+//
+// This code uses the loader package to load the constants file generated by
+// c-for-go, which runs against libvirt's C sources. This file is generated by
+// 'go generate ./...' prior to the lvgen/ generator being run.
+func mapFlagTypes() map[string]ast.Expr {
+ pconf := loader.Config{}
+ f, err := pconf.ParseFile("../../const.gen.go", nil)
+ if err != nil {
+ panic(fmt.Sprintln("failed to read constants file: ", err))
+ }
+ pconf.CreateFromFiles("const", f)
+ prog, err := pconf.Load()
+ if err != nil {
+ panic(fmt.Sprintln("failed to load package: ", err))
+ }
+ cpkg := prog.Package("const")
+
+ tmap := make(map[string]ast.Expr)
+ ast.Inspect(cpkg.Files[0], func(n ast.Node) bool {
+ switch t := n.(type) {
+ case *ast.TypeSpec:
+ // There isn't a single name pattern that covers all of the flag
+ // types, so we'll collect all the types that map to int32 here.
+ if fmt.Sprintf("%s", t.Type) == "int32" {
+ tmap[t.Name.String()] = t.Type
+ }
+ }
+ return true
+ })
+ return tmap
+}
+
+// Many libvirt calls use flags whose values come from a set of definitions
+// whose name we can't predict. So this map exists to do the translation for us.
+// The only way to remove this fragile map would be to use the comments from the
+// .c files in libvirt, which contain doxygen-style parameter comments that
+// specify the valid value types for flags.
+var flagMap = map[string]string{
+ "ConnectOpen": "ConnectFlags",
+ "DomainAddIothread": "DomainModificationImpact",
+ "DomainCoreDumpWithFormat": "DomainCoreDumpFlags",
+ "DomainCreateXML": "DomainCreateFlags",
+ "DomainCreateWithFiles": "DomainCreateFlags",
+ "DomainCreateXMLWithFiles": "DomainCreateFlags",
+ "DomainDefineXMLFlags": "DomainDefineFlags",
+ "DomainDelIothread": "DomainModificationImpact",
+ "DomainDestroyFlags": "DomainDestroyFlagsValues",
+ "DomainGetCPUStats": "TypedParameterFlags",
+ "DomainGetEmulatorPinInfo": "DomainModificationImpact",
+ "DomainGetInterfaceParameters": "DomainModificationImpact",
+ "DomainGetIothreadInfo": "DomainModificationImpact",
+ "DomainGetMetadata": "DomainModificationImpact",
+ "DomainGetPerfEvents": "DomainModificationImpact",
+ "DomainGetXMLDesc": "DomainXMLFlags",
+ "DomainManagedSaveDefineXML": "DomainSaveRestoreFlags",
+ "DomainManagedSaveGetXMLDesc": "DomainXMLFlags",
+ "DomainMemoryPeek": "DomainMemoryFlags",
+ "DomainMigratePerform3Params": "DomainMigrateFlags",
+ "DomainOpenChannel": "DomainChannelFlags",
+ "DomainOpenGraphicsFd": "DomainOpenGraphicsFlags",
+ "DomainPinEmulator": "DomainModificationImpact",
+ "DomainPinIothread": "DomainModificationImpact",
+ "DomainSetLifecycleAction": "DomainModificationImpact",
+ "DomainSetMemoryStatsPeriod": "DomainMemoryModFlags",
+ "DomainSetMetadata": "DomainModificationImpact",
+ "DomainSetPerfEvents": "DomainModificationImpact",
+ "DomainSetVcpu": "DomainModificationImpact",
+ "DomainShutdownFlags": "DomainShutdownFlagValues",
+ "DomainUndefineFlags": "DomainUndefineFlagsValues",
+ "DomainUpdateDeviceFlags": "DomainDeviceModifyFlags",
+ "StoragePoolCreateXML": "StoragePoolCreateFlags",
+ "StoragePoolGetXMLDesc": "StorageXMLFlags",
+ "StorageVolCreateXML": "StorageVolCreateFlags",
+ "StorageVolCreateXMLFrom": "StorageVolCreateFlags",
+}
+
+// findFlagType attempts to find a real type for the flags passed to a given
+// libvirt routine.
+func findFlagType(procName string, flagTypes map[string]ast.Expr) (string, bool) {
+ flagName, ok := flagMap[procName]
+ if ok {
+ // Verify the mapped name exists
+ if _, ok = flagTypes[flagName]; ok == false {
+ // If one of the manual flag mappings is wrong, complain but
+ // continue. This happens with older versions of libvirt.
+ fmt.Printf("manual flag type %v for %v not found, continuing", flagName, procName)
+ return "", false
+ }
+ return flagName, true
+ }
+
+ // Not in the manual map, so do a search using the 3 patterns libvirt uses.
+ tnames := [...]string{procName + "Flags", procName + "FlagValues", procName + "FlagsValues"}
+ for _, n := range tnames {
+ if _, ok := flagTypes[n]; ok == true {
+ return n, true
+ }
+ }
+
+ return "", false
+}
+
+// changeFlagType looks up the go type for a libvirt call's flags field. In C
+// these flags are all uint32, and you have to consult the documentation to
+// determine what the valid set of flags is for a given libvirt call. For Go
+// we're attempting to do better by specifying an actual type so that the
+// possible values are easier to determine. This is a heuristic, however, based
+// on naming patterns in the libvirt code. To do better we would need to look at
+// the doxygen-style comments in the libvirt sources.
+//
+// Failing to find a flags type isn't a fatal error, it just means that we'll
+// leave the flags with a type of uint32.
+func changeFlagType(procName string, s *Structure, flagTypes map[string]ast.Expr) {
+ for ix, d := range s.Members {
+ if d.Name == "Flags" {
+ tname, found := findFlagType(procName, flagTypes)
+
+ if found {
+ s.Members[ix].Type = tname
+ } else {
+ // If you're adding procedures to to the manual map, you may
+ // want to uncomment this to see what flag types are not found.
+ // fmt.Println("flags type for", procName, "not found")
+ }
+ }
+ }
+}
+
+//---------------------------------------------------------------------------
+// Routines called by the parser's actions.
+//---------------------------------------------------------------------------
+
+// StartEnum is called when the parser has found a valid enum.
+func StartEnum(name string) {
+ // Enums are always signed 32-bit integers.
+ goname := identifierTransform(name)
+ Gen.Enums = append(Gen.Enums, Decl{goname, name, "int32"})
+ // Set the automatic value var to -1; it will be incremented before being
+ // assigned to an enum value.
+ CurrentEnumVal = -1
+}
+
+// AddEnumVal will add a new enum value to the list.
+func AddEnumVal(name, val string) error {
+ ev, err := parseNumber(val)
+ if err != nil {
+ return fmt.Errorf("invalid enum value %v = %v", name, val)
+ }
+ return addEnumVal(name, ev, nil)
+}
+
+// AddProcEnumVal adds a procedure enum to our list of remote procedures which
+// we will later generate code for. These declarations look like enums, but have
+// a (currently optional) comment block above them which we partially parse for
+// information about the procedure's in/output streams. Metadata is parsed from
+// annotations in libvirt RPC description file that are in block comment
+// preceding every function in enum, it looks like this:
+//
+// /**
+// * @generate: both
+// * @readstream: 1
+// * @sparseflag: VIR_STORAGE_VOL_DOWNLOAD_SPARSE_STREAM
+// * @acl: storage_vol:data_read
+// */
+//
+// See full description of possible annotations in libvirt's
+// src/remote/remote_protocol.x at the top of remote_procedure enum. We're
+// parsing only @readstream and @writestream annotations at the moment.
+func AddProcEnumVal(name, val string, meta string) error {
+ ev, err := parseNumber(val)
+ if err != nil {
+ return fmt.Errorf("invalid enum value %v = %v", name, val)
+ }
+ metaObj, err := parseMeta(meta)
+ if err != nil {
+ return fmt.Errorf("invalid metadata for enum value %v: %v", name, err)
+ }
+
+ // Confusingly, the procedure name we use for generating code has "Proc"
+ // stripped, but the name of the enum does not.
+ program := procProgramName(name)
+ procName := procNameTransform(name)
+ enumName := constNameTransform(name)
+ Gen.EnumVals = append(Gen.EnumVals, ConstItem{enumName, name, strconv.FormatInt(ev, 10)})
+ CurrentEnumVal = ev
+
+ proc := &Proc{Program: program, Num: ev, Name: procName,
+ LVName: name, ReadStreamIdx: -1, WriteStreamIdx: -1}
+ if metaObj != nil {
+ proc.ReadStreamIdx = metaObj.ReadStream
+ proc.WriteStreamIdx = metaObj.WriteStream
+ }
+ Gen.Procs = append(Gen.Procs, *proc)
+ return nil
+}
+
+// AddEnumAutoVal adds an enum to the list, using the automatically-incremented
+// value. This is called when the parser finds an enum definition without an
+// explicit value.
+func AddEnumAutoVal(name string) error {
+ CurrentEnumVal++
+ return addEnumVal(name, CurrentEnumVal, nil)
+}
+
+func addEnumVal(name string, val int64, meta *ProcMeta) error {
+ goname := constNameTransform(name)
+ Gen.EnumVals = append(Gen.EnumVals, ConstItem{goname, name, fmt.Sprintf("%d", val)})
+ CurrentEnumVal = val
+ return nil
+}
+
+// AddConst adds a new constant to the parser's list.
+func AddConst(name, val string) error {
+ _, err := parseNumber(val)
+ if err != nil {
+ return fmt.Errorf("invalid const value %v = %v", name, val)
+ }
+ goname := constNameTransform(name)
+ Gen.Consts = append(Gen.Consts, ConstItem{goname, name, val})
+ return nil
+}
+
+// parseNumber makes sure that a parsed numerical value can be parsed to a 64-
+// bit integer.
+func parseNumber(val string) (int64, error) {
+ base := 10
+ if strings.HasPrefix(val, "0x") {
+ base = 16
+ val = val[2:]
+ }
+ n, err := strconv.ParseInt(val, base, 64)
+ return n, err
+}
+
+// parseMeta parses procedure metadata to simple string mapping
+func parseMeta(meta string) (*ProcMeta, error) {
+ res := &ProcMeta{
+ ReadStream: -1,
+ WriteStream: -1,
+ }
+ for _, line := range strings.Split(meta, "\n") {
+ atInd := strings.Index(line, "@")
+ if atInd == -1 {
+ // Should be only first and last line of comment
+ continue
+ }
+ spl := strings.SplitN(line[atInd+1:], ":", 2)
+ if len(spl) != 2 {
+ return nil, fmt.Errorf("invalid annotation: %s", meta)
+ }
+ spl[1] = strings.Trim(spl[1], " ")
+ switch spl[0] {
+ case "readstream":
+ var err error
+ res.ReadStream, err = strconv.Atoi(spl[1])
+ if err != nil {
+ return nil, fmt.Errorf("invalid value for readstream: %s", spl[1])
+ }
+ case "writestream":
+ var err error
+ res.WriteStream, err = strconv.Atoi(spl[1])
+ if err != nil {
+ return nil, fmt.Errorf("invalid value for writestream: %s", spl[1])
+ }
+ }
+ }
+ return res, nil
+}
+
+// StartStruct is called from the parser when a struct definition is found, but
+// before the member declarations are processed.
+func StartStruct(name string) {
+ goname := identifierTransform(name)
+ CurrentStruct.push(&Structure{Name: goname, LVName: name})
+}
+
+// AddStruct is called when the parser has finished parsing a struct. It adds
+// the now-complete struct definition to the generator's list.
+func AddStruct() {
+ st := *CurrentStruct.pop()
+ Gen.StructMap[st.Name] = len(Gen.Structs)
+ Gen.Structs = append(Gen.Structs, st)
+}
+
+// StartTypedef is called when the parser finds a typedef.
+func StartTypedef() {
+ CurrentTypedef = &Typedef{}
+}
+
+// StartUnion is called by the parser when it finds a union declaraion.
+func StartUnion(name string) {
+ name = identifierTransform(name)
+ CurrentUnion = &Union{Name: name}
+}
+
+// AddUnion is called by the parser when it has finished processing a union
+// type. It adds the union to the generator's list and clears the CurrentUnion
+// pointer. We handle unions by declaring an interface for the union type, and
+// adding methods to each of the cases so that they satisfy the interface.
+func AddUnion() {
+ Gen.UnionMap[CurrentUnion.Name] = len(Gen.Unions)
+ Gen.Unions = append(Gen.Unions, *CurrentUnion)
+ CurrentUnion = nil
+}
+
+// StartCase is called when the parser finds a case statement within a union.
+func StartCase(dvalue string) {
+ // In libvirt, the discriminant values are all C pre- processor definitions.
+ // Since we don't run the C pre-processor on the protocol file, they're
+ // still just names when we get them - we don't actually have their integer
+ // values. We'll use the strings to build the type names, although this is
+ // brittle, because we're defining a type for each of the case values, and
+ // that type needs a name.
+ caseName := dvalue
+ if ix := strings.LastIndexByte(caseName, '_'); ix != -1 {
+ caseName = caseName[ix+1:]
+ }
+ caseName = fromSnakeToCamel(caseName)
+ dv, ok := lvTypedParams[dvalue]
+ if ok {
+ dvalue = strconv.FormatUint(uint64(dv), 10)
+ }
+ CurrentCase = &Case{CaseName: caseName, DiscriminantVal: dvalue}
+}
+
+// AddCase is called when the parser finishes parsing a case.
+func AddCase() {
+ CurrentUnion.Cases = append(CurrentUnion.Cases, *CurrentCase)
+ CurrentCase = nil
+}
+
+// AddDeclaration is called by the parser when it find a declaration (int x).
+// The declaration will be added to any open container (such as a struct, if the
+// parser is working through a struct definition.)
+func AddDeclaration(identifier, itype string) {
+ addDecl(NewDecl(identifier, itype))
+}
+
+// addDecl adds a declaration to the current container.
+func addDecl(decl *Decl) {
+ if !CurrentStruct.empty() {
+ st := CurrentStruct.peek()
+ st.Members = append(st.Members, *decl)
+ } else if CurrentTypedef != nil {
+ CurrentTypedef.Name = decl.Name
+ CurrentTypedef.LVName = decl.LVName
+ CurrentTypedef.Type = decl.Type
+ if CurrentTypedef.Name != "string" {
+ // Omit recursive typedefs. These happen because we're massaging
+ // some of the type names.
+ Gen.Typedefs = append(Gen.Typedefs, *CurrentTypedef)
+ }
+ CurrentTypedef = nil
+ } else if CurrentCase != nil {
+ CurrentCase.Name = decl.Name
+ CurrentCase.Type = decl.Type
+ } else if CurrentUnion != nil {
+ CurrentUnion.DiscriminantType = decl.Type
+ }
+}
+
+// AddFixedArray is called by the parser to add a fixed-length array to the
+// current container (struct, union, etc). Fixed-length arrays are not length-
+// prefixed.
+func AddFixedArray(identifier, itype, len string) {
+ atype := fmt.Sprintf("[%v]%v", len, itype)
+ addDecl(NewDecl(identifier, atype))
+}
+
+// AddVariableArray is called by the parser to add a variable-length array.
+// Variable-length arrays are prefixed with a 32-bit unsigned length, and may
+// also have a maximum length specified.
+func AddVariableArray(identifier, itype, len string) {
+ // This code ignores the length restriction (array), so as of now we
+ // can't check to make sure that we're not exceeding that restriction when
+ // we fill in message buffers. That may not matter, if libvirt's checking is
+ // careful enough.
+ atype := "[]" + itype
+ // Handle strings specially. In the rpcgen definition a string is specified
+ // as a variable-length array, either with or without a max length. We want
+ // these to be go strings, so we'll just remove the array specifier.
+ if itype == "string" {
+ atype = itype
+ }
+ addDecl(NewDecl(identifier, atype))
+}
+
+// AddOptValue is called by the parser to add an optional value. These are
+// declared in the protocol definition file using a syntax that looks like a
+// pointer declaration, but are actually represented by a variable-sized array
+// with a maximum size of 1.
+func AddOptValue(identifier, itype string) {
+ atype := "[]" + itype
+ decl := NewDecl(identifier, atype)
+ newType := "Opt" + decl.Name
+ goEquivTypes[decl.Name] = newType
+ decl.Name = newType
+ addDecl(decl)
+}
+
+// checkIdentifier determines whether an identifier is in our translation list.
+// If so it returns the translated name. This is used to massage the type names
+// we're emitting.
+func checkIdentifier(i string) string {
+ nn, reserved := goEquivTypes[i]
+ if reserved {
+ return nn
+ }
+ return i
+}
+
+// GetUnion returns the type information for a union. If the provided type name
+// isn't a union, this will return a zero-value Union type.
+func (decl *Decl) GetUnion() Union {
+ ix, ok := Gen.UnionMap[decl.Type]
+ if ok {
+ return Gen.Unions[ix]
+ }
+ return Union{}
+}
diff --git a/third_party/libvirt/internal/lvgen/lv-gen.go b/third_party/libvirt/internal/lvgen/lv-gen.go
new file mode 100644
index 0000000..e99b9b5
--- /dev/null
+++ b/third_party/libvirt/internal/lvgen/lv-gen.go
@@ -0,0 +1,29 @@
+// Copyright 2017 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 lvgen contains the instructions for regenerating the libvirt
+// bindings. We do this by parsing the remote_protocol.x file included in the
+// libvirt sources. Bindings will be generated if you run `go generate` in this
+// directory.
+package lvgen
+
+// Before running `go generate`:
+// 1) Make sure goyacc is installed from golang.org/x/tools (you can use this
+// command: `go get golang.org/x/tools/...`)
+// 2) Set the environment variable LIBVIRT_SOURCE to point to the top level
+// directory containing the version of libvirt for which you want to generate
+// bindings.
+
+//go:generate goyacc sunrpc.y
+//go:generate go run gen/main.go
diff --git a/third_party/libvirt/internal/lvgen/lvlexer.go b/third_party/libvirt/internal/lvgen/lvlexer.go
new file mode 100644
index 0000000..36e100b
--- /dev/null
+++ b/third_party/libvirt/internal/lvgen/lvlexer.go
@@ -0,0 +1,357 @@
+// Copyright 2017 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 lvgen
+
+import (
+ "fmt"
+ "io"
+ "io/ioutil"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+)
+
+// eof is returned by the lexer when there's no more input.
+const eof = -1
+
+// oneRuneTokens lists the runes the lexer will consider to be tokens when it
+// finds them. These are returned to the parser using the integer value of their
+// runes.
+var oneRuneTokens = `{}[]<>(),=;:*`
+
+var keywords = map[string]int{
+ "hyper": HYPER,
+ "int": INT,
+ "short": SHORT,
+ "char": CHAR,
+ "bool": BOOL,
+ "case": CASE,
+ "const": CONST,
+ "default": DEFAULT,
+ "double": DOUBLE,
+ "enum": ENUM,
+ "float": FLOAT,
+ "opaque": OPAQUE,
+ "string": STRING,
+ "struct": STRUCT,
+ "switch": SWITCH,
+ "typedef": TYPEDEF,
+ "union": UNION,
+ "unsigned": UNSIGNED,
+ "void": VOID,
+ "program": PROGRAM,
+ "version": VERSION,
+}
+
+// item is a lexeme, or what the lexer returns to the parser.
+type item struct {
+ typ int
+ val string
+ line, column int
+}
+
+// String will display lexer items for humans to debug. There are some
+// calculations here due to the way goyacc arranges token values; see the
+// generated file y.go for an idea what's going on here, but the basic idea is
+// that the lower token type values are reserved for single-rune tokens, which
+// the lexer reports using the value of the rune itself. Everything else is
+// allocated a range of type value up above all the possible single-rune values.
+func (i item) String() string {
+ tokType := i.typ
+ if tokType >= yyPrivate {
+ if tokType < yyPrivate+len(yyTok2) {
+ tokType = yyTok2[tokType-yyPrivate]
+ }
+ }
+ rv := fmt.Sprintf("%s %q %d:%d", yyTokname(tokType), i.val, i.line, i.column)
+ return rv
+}
+
+// Lexer stores the state of this lexer.
+type Lexer struct {
+ input string // the string we're scanning.
+ start int // start position of the item.
+ pos int // current position in the input.
+ line int // the current line (for error reporting).
+ column int // current position within the current line.
+ width int // width of the last rune scanned.
+ items chan item // channel of scanned lexer items (lexemes).
+ lastItem item // The last item the lexer handed the parser
+}
+
+// NewLexer will return a new lexer for the passed-in reader.
+func NewLexer(rdr io.Reader) (*Lexer, error) {
+ l := &Lexer{}
+
+ b, err := ioutil.ReadAll(rdr)
+ if err != nil {
+ return nil, err
+ }
+ l.input = string(b)
+ l.items = make(chan item)
+
+ return l, nil
+}
+
+// Run starts the lexer, and should be called in a goroutine.
+func (l *Lexer) Run() {
+ for state := lexText; state != nil; {
+ state = state(l)
+ }
+ close(l.items)
+}
+
+// emit returns a token to the parser.
+func (l *Lexer) emit(t int) {
+ l.items <- item{t, l.input[l.start:l.pos], l.line, l.column}
+ l.start = l.pos
+}
+
+// Lex gets the next token.
+func (l *Lexer) Lex(st *yySymType) int {
+ s := <-l.items
+ l.lastItem = s
+ st.val = s.val
+ return int(s.typ)
+}
+
+// Error is called by the parser when it finds a problem.
+func (l *Lexer) Error(s string) {
+ fmt.Printf("parse error at %d:%d: %v\n", l.lastItem.line+1, l.lastItem.column+1, s)
+ fmt.Printf("error at %q\n", l.lastItem.val)
+}
+
+// errorf is used by the lexer to report errors. It inserts an ERROR token into
+// the items channel, and sets the state to nil, which stops the lexer's state
+// machine.
+func (l *Lexer) errorf(format string, args ...interface{}) stateFn {
+ l.items <- item{ERROR, fmt.Sprintf(format, args...), l.line, l.column}
+ return nil
+}
+
+// next returns the rune at the current location, and advances to the next rune
+// in the input.
+func (l *Lexer) next() (r rune) {
+ if l.pos >= len(l.input) {
+ l.width = 0
+ return eof
+ }
+ r, l.width = utf8.DecodeRuneInString(l.input[l.pos:])
+ l.pos += l.width
+ l.column++
+ if r == '\n' {
+ l.line++
+ l.column = 0
+ }
+ return r
+}
+
+// ignore discards the current text from start to pos.
+func (l *Lexer) ignore() {
+ l.start = l.pos
+}
+
+// backup moves back one character, but can only be called once per next() call.
+func (l *Lexer) backup() {
+ l.pos -= l.width
+ if l.column > 0 {
+ l.column--
+ } else {
+ l.line--
+ }
+ l.width = 0
+}
+
+// peek looks ahead at the next rune in the stream without consuming it.
+func (l *Lexer) peek() rune {
+ r := l.next()
+ l.backup()
+ return r
+}
+
+// accept will advance to the next rune if it's contained in the string of valid
+// runes passed in by the caller.
+func (l *Lexer) accept(valid string) bool {
+ if strings.IndexRune(valid, l.next()) >= 0 {
+ return true
+ }
+ l.backup()
+ return false
+}
+
+// acceptRun advances over a number of valid runes, stopping as soon as it hits
+// one not on the list.
+func (l *Lexer) acceptRun(valid string) {
+ for strings.IndexRune(valid, l.next()) >= 0 {
+ }
+ l.backup()
+}
+
+// procIdent checks whether an identifier matches the pattern for a procedure
+// enum.
+func procIdent(ident string) bool {
+ // The pattern we're looking for is "_PROC_", like
+ // "REMOTE_PROC_DOMAIN_OPEN_CONSOLE"
+ if ix := strings.Index(ident, "_PROC_"); ix != -1 {
+ if strings.Index(ident[:ix], "_") == -1 {
+ return true
+ }
+ }
+ return false
+}
+
+// keyword checks whether the current lexeme is a keyword or not. If so it
+// returns the keyword's token id, otherwise it returns IDENTIFIER.
+func (l *Lexer) keyword() int {
+ ident := l.input[l.start:l.pos]
+ tok, ok := keywords[ident]
+ if ok == true {
+ return int(tok)
+ }
+ if procIdent(ident) {
+ return PROCIDENTIFIER
+ }
+ return IDENTIFIER
+}
+
+// oneRuneToken determines whether a rune is a token. If so it returns the token
+// id and true, otherwise it returns false.
+func (l *Lexer) oneRuneToken(r rune) (int, bool) {
+ if strings.IndexRune(oneRuneTokens, r) >= 0 {
+ return int(r), true
+ }
+
+ return 0, false
+}
+
+// State functions
+type stateFn func(*Lexer) stateFn
+
+// lexText is the master lex routine. The lexer is started in this state.
+func lexText(l *Lexer) stateFn {
+ for {
+ if strings.HasPrefix(l.input[l.pos:], "/*") {
+ return lexBlockComment
+ }
+ r := l.next()
+ if r == eof {
+ break
+ }
+ if unicode.IsSpace(r) {
+ l.ignore()
+ return lexText
+ }
+ if l.column == 1 && r == '%' {
+ l.backup()
+ return lexDirective
+ }
+ if unicode.IsLetter(r) {
+ l.backup()
+ return lexIdent
+ }
+ if unicode.IsNumber(r) || r == '-' {
+ l.backup()
+ return lexNumber
+ }
+ if t, isToken := l.oneRuneToken(r); isToken == true {
+ l.emit(t)
+ }
+ }
+
+ return nil
+}
+
+// lexBlockComment is used when we find a comment marker '/*' in the input.
+func lexBlockComment(l *Lexer) stateFn {
+ // Double star is used only at the start of metadata comments
+ metadataComment := strings.HasPrefix(l.input[l.pos:], "/**")
+ for {
+ if strings.HasPrefix(l.input[l.pos:], "*/") {
+ // Found the end. Advance past the '*/' and discard the comment body
+ // unless it's a metadata comment
+ l.next()
+ l.next()
+ if metadataComment {
+ l.emit(METADATACOMMENT)
+ } else {
+ l.ignore()
+ }
+ return lexText
+ }
+ if l.next() == eof {
+ return l.errorf("unterminated block comment")
+ }
+ }
+}
+
+// lexIdent handles identifiers.
+func lexIdent(l *Lexer) stateFn {
+ for {
+ r := l.next()
+ if unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_' {
+ continue
+ }
+ l.backup()
+ break
+ }
+ // We may have a keyword, so check for that before emitting.
+ l.emit(l.keyword())
+
+ return lexText
+}
+
+// lexNumber handles decimal and hexadecimal numbers. Decimal numbers may begin
+// with a '-'; hex numbers begin with '0x' and do not accept leading '-'.
+func lexNumber(l *Lexer) stateFn {
+ // Leading '-' is ok
+ digits := "0123456789"
+ neg := l.accept("-")
+ if !neg {
+ // allow '0x' for hex numbers, as long as there's not a leading '-'.
+ r := l.peek()
+ if r == '0' {
+ l.next()
+ if l.accept("x") {
+ digits = "0123456789ABCDEFabcdef"
+ }
+ }
+ }
+ // followed by any number of digits
+ l.acceptRun(digits)
+ r := l.peek()
+ if unicode.IsLetter(r) {
+ l.next()
+ return l.errorf("invalid number: %q", l.input[l.start:l.pos])
+ }
+ l.emit(CONSTANT)
+ return lexText
+}
+
+// lexDirective handles lines beginning with '%'. These are used to emit C code
+// directly to the output file. For now we're ignoring them, but some of the
+// constants in the protocol file do depend on values from #included header
+// files, so that may need to change.
+func lexDirective(l *Lexer) stateFn {
+ for {
+ r := l.next()
+ if r == '\n' {
+ l.ignore()
+ return lexText
+ }
+ if r == eof {
+ return l.errorf("unterminated directive")
+ }
+ }
+}
diff --git a/third_party/libvirt/internal/lvgen/procedures.tmpl b/third_party/libvirt/internal/lvgen/procedures.tmpl
new file mode 100644
index 0000000..65ccb2b
--- /dev/null
+++ b/third_party/libvirt/internal/lvgen/procedures.tmpl
@@ -0,0 +1,117 @@
+// 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 libvirt
+
+import (
+ "bytes"
+ "io"
+
+ "github.com/projecteru2/yavirt/third_party/libvirt/internal/constants"
+ "github.com/projecteru2/yavirt/third_party/libvirt/internal/go-xdr/xdr2"
+)
+
+// References to prevent "imported and not used" errors.
+var (
+ _ = bytes.Buffer{}
+ _ = io.Copy
+ _ = constants.Program
+ _ = xdr.Unmarshal
+)
+
+//
+// Typedefs:
+//
+{{range .Typedefs}}// {{.Name}} is libvirt's {{.LVName}}
+type {{.Name}} {{.Type}}
+{{end}}
+//
+// Enums:
+//
+{{range .Enums}}// {{.Name}} is libvirt's {{.LVName}}
+type {{.Name}} {{.Type}}
+{{end}}
+//
+// Structs:
+//
+{{range .Structs}}// {{.Name}} is libvirt's {{.LVName}}
+type {{.Name}} struct {
+{{range .Members}} {{.Name}} {{.Type}}
+{{end -}}
+}
+
+{{end}}
+{{range .Unions}}// {{.Name}} is a discriminated union.
+type {{.Name}} struct {
+ D uint32
+ I interface{}
+}
+{{end -}}
+{{range .Unions}}{{$uname := .Name}}{{range .Cases}}{{$casetype := printf "%v%v" $uname .CaseName}}
+// New{{$casetype}} creates a discriminated union value satisfying
+// the {{$uname}} interface.
+func New{{$casetype}}(v {{.Type}}) *{{$uname}} {
+ return &{{$uname}}{D: {{.DiscriminantVal}}, I: v}
+}
+{{end}}
+{{- end}}
+{{range $proc := .Procs}}
+// {{.Name}} is the go wrapper for {{.LVName}}.
+func (l *Libvirt) {{.Name}}(
+ {{- range $ix, $arg := .Args}}
+ {{- if (eq $ix $proc.WriteStreamIdx)}}{{if $ix}}, {{end}}outStream io.Reader{{end}}
+ {{- if (eq $ix $proc.ReadStreamIdx)}}{{if $ix}}, {{end}}inStream io.Writer{{end}}
+ {{- if $ix}}, {{end}}{{.Name}} {{.Type}}
+ {{- end -}}
+) ({{range .Ret}}r{{.Name}} {{.Type}}, {{end}}err error) {
+ var buf []byte
+{{if .ArgsStruct}}
+ args := {{.ArgsStruct}} {
+{{range .Args}} {{.Name}}: {{.Name}},
+{{end}} }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+{{end}}
+{{if .RetStruct}} var r response{{end}}
+ {{if .RetStruct}}r{{else}}_{{end}}, err = l.requestStream({{.Num}}, constants.{{.Program}}Program, buf,
+ {{- if (ne .WriteStreamIdx -1)}} outStream,{{else}} nil,{{end}}
+ {{- if (ne .ReadStreamIdx -1)}} inStream{{else}} nil{{end -}}
+ )
+ if err != nil {
+ return
+ }
+{{if .RetStruct}}
+ // Return value unmarshaling
+ tpd := typedParamDecoder{}
+ ct := map[string]xdr.TypeDecoder{"libvirt.TypedParam": tpd}
+ rdr := bytes.NewReader(r.Payload)
+ dec := xdr.NewDecoderCustomTypes(rdr, 0, ct)
+{{range .Ret}} // {{.Name}}: {{.Type}}
+ _, err = dec.Decode(&r{{.Name}})
+ if err != nil {
+ return
+ }
+{{end}}{{end}}
+ return
+}
+{{end}}
diff --git a/third_party/libvirt/internal/lvgen/sunrpc.y b/third_party/libvirt/internal/lvgen/sunrpc.y
new file mode 100644
index 0000000..96b3366
--- /dev/null
+++ b/third_party/libvirt/internal/lvgen/sunrpc.y
@@ -0,0 +1,279 @@
+// Copyright 2017 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.
+
+// The generated code notice below is output to the generated file. *This* file,
+// (sunrpc.y) is the yacc grammar for the sunrpc protocol language, and is *not*
+// generated.
+
+%{
+// Copyright 2017 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 goyacc. DO NOT EDIT.
+//
+// To regenerate, run 'go generate' in internal/lvgen.
+//
+
+package lvgen
+
+import (
+ //"fmt"
+)
+
+%}
+
+// SymType
+%union{
+ val string
+}
+
+// XDR tokens:
+%token BOOL CASE CONST DEFAULT DOUBLE ENUM FLOAT OPAQUE STRING STRUCT
+%token SWITCH TYPEDEF UNION UNSIGNED VOID HYPER INT SHORT CHAR
+%token IDENTIFIER CONSTANT ERROR
+// RPCL additional tokens:
+%token PROGRAM VERSION
+%token METADATACOMMENT
+%token PROCIDENTIFIER
+
+%%
+
+specification
+ : definition_list
+ ;
+
+value
+ : IDENTIFIER
+ | CONSTANT
+ ;
+
+definition_list
+ : definition ';'
+ | definition ';' definition_list
+ ;
+
+definition
+ : enum_definition
+ | const_definition
+ | typedef_definition
+ | struct_definition
+ | union_definition
+ | program_definition
+ ;
+
+enum_definition
+ : ENUM enum_ident '{' enum_value_list '}' { StartEnum($2.val) }
+ ;
+
+enum_value_list
+ : enum_value
+ | enum_value ',' enum_value_list
+ ;
+
+enum_value
+ : enum_value_ident {
+ err := AddEnumAutoVal($1.val)
+ if err != nil {
+ yylex.Error(err.Error())
+ return 1
+ }
+ }
+ | enum_value_ident '=' value {
+ err := AddEnumVal($1.val, $3.val)
+ if err != nil {
+ yylex.Error(err.Error())
+ return 1
+ }
+ }
+ | enum_proc_ident '=' value {
+ err := AddProcEnumVal($1.val, $3.val, "")
+ if err != nil {
+ yylex.Error(err.Error())
+ return 1
+ }
+ }
+ | METADATACOMMENT enum_proc_ident '=' value {
+ err := AddProcEnumVal($2.val, $4.val, $1.val)
+ if err != nil {
+ yylex.Error(err.Error())
+ return 1
+ }
+ }
+ ;
+
+enum_proc_ident
+ : PROCIDENTIFIER
+ ;
+
+enum_ident
+ : IDENTIFIER
+ ;
+
+enum_value_ident
+ : IDENTIFIER
+ ;
+
+// Ignore consts that are set to IDENTIFIERs - this isn't allowed by the spec,
+// but occurs in the file because libvirt runs the pre-processor on the protocol
+// file, and it handles replacing the identifier with it's #defined value.
+const_definition
+ : CONST const_ident '=' IDENTIFIER
+ | CONST const_ident '=' CONSTANT {
+ err := AddConst($2.val, $4.val)
+ if err != nil {
+ yylex.Error(err.Error())
+ return 1
+ }
+ }
+ ;
+
+const_ident
+ : IDENTIFIER
+ ;
+
+typedef_definition
+ : TYPEDEF {StartTypedef()} declaration
+ ;
+
+declaration
+ : simple_declaration
+ | fixed_array_declaration
+ | variable_array_declaration
+ | pointer_declaration
+ ;
+
+simple_declaration
+ : type_specifier variable_ident {AddDeclaration($2.val, $1.val)}
+ ;
+
+type_specifier
+ : int_spec
+ | UNSIGNED int_spec {$$.val = "u"+$2.val}
+ | FLOAT {$$.val = "float32"}
+ | DOUBLE {$$.val = "float64"}
+ | BOOL {$$.val = "bool"}
+ | STRING {$$.val = "string"}
+ | OPAQUE {$$.val = "byte"}
+ | enum_definition
+ | struct_definition
+ | union_definition
+ | IDENTIFIER
+ ;
+
+int_spec
+ : HYPER {$$.val = "int64"}
+ | INT {$$.val = "int32"}
+ | SHORT {$$.val = "int16"}
+ | CHAR {$$.val = "int8"}
+ ;
+
+variable_ident
+ : IDENTIFIER
+ ;
+
+fixed_array_declaration
+ : type_specifier variable_ident '[' value ']' { AddFixedArray($2.val, $1.val, $4.val) }
+ ;
+
+variable_array_declaration
+ : type_specifier variable_ident '<' value '>' { AddVariableArray($2.val, $1.val, $4.val) }
+ | type_specifier variable_ident '<' '>' { AddVariableArray($2.val, $1.val, "") }
+ ;
+
+// while pointer_declarations may look like their familiar c-equivalents, in the
+// XDR language they actually declare "Optional-data". The simplest
+// representation to use for these is a variable-length array with a size of 1.
+// See the XDR spec for a more complete explanation of this.
+pointer_declaration
+ : type_specifier '*' variable_ident { AddOptValue($3.val, $1.val) }
+ ;
+
+struct_definition
+ : STRUCT struct_ident '{' {StartStruct($2.val)} declaration_list '}' { AddStruct() }
+ ;
+
+struct_ident
+ : IDENTIFIER
+ ;
+
+declaration_list
+ : declaration ';'
+ | declaration ';' declaration_list
+ ;
+
+union_definition
+ : UNION union_ident {StartUnion($2.val)} SWITCH '(' simple_declaration ')' '{' case_list '}' {AddUnion()}
+ ;
+
+union_ident
+ : IDENTIFIER
+ ;
+
+case_list
+ : case ';'
+ | case ';' case_list
+ ;
+
+case
+ : CASE value {StartCase($2.val)} ':' declaration {AddCase()}
+ | DEFAULT {StartCase("default")} ':' declaration {AddCase()}
+ ;
+
+program_definition
+ : PROGRAM program_ident '{' version_list '}' '=' value
+ ;
+
+program_ident
+ : IDENTIFIER
+ ;
+
+version_list
+ : version ';'
+ | version ';' version_list
+ ;
+
+version
+ : VERSION version_ident '{' procedure_list '}' '=' value ';'
+ ;
+
+version_ident
+ : IDENTIFIER
+ ;
+
+procedure_list
+ : procedure ';'
+ | procedure ';' procedure_list
+ ;
+
+procedure
+ : type_specifier procedure_ident '(' type_specifier ')' '=' value ';'
+ ;
+
+procedure_ident
+ : IDENTIFIER
+ ;
+
+%%
diff --git a/third_party/libvirt/internal/lvgen/y.go b/third_party/libvirt/internal/lvgen/y.go
new file mode 100644
index 0000000..1ea031b
--- /dev/null
+++ b/third_party/libvirt/internal/lvgen/y.go
@@ -0,0 +1,799 @@
+// Code generated by goyacc sunrpc.y. DO NOT EDIT.
+
+//line sunrpc.y:20
+// Copyright 2017 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 goyacc. DO NOT EDIT.
+//
+// To regenerate, run 'go generate' in internal/lvgen.
+//
+
+package lvgen
+
+import __yyfmt__ "fmt"
+
+//line sunrpc.y:40
+
+import (
+//"fmt"
+)
+
+//line sunrpc.y:49
+type yySymType struct {
+ yys int
+ val string
+}
+
+const BOOL = 57346
+const CASE = 57347
+const CONST = 57348
+const DEFAULT = 57349
+const DOUBLE = 57350
+const ENUM = 57351
+const FLOAT = 57352
+const OPAQUE = 57353
+const STRING = 57354
+const STRUCT = 57355
+const SWITCH = 57356
+const TYPEDEF = 57357
+const UNION = 57358
+const UNSIGNED = 57359
+const VOID = 57360
+const HYPER = 57361
+const INT = 57362
+const SHORT = 57363
+const CHAR = 57364
+const IDENTIFIER = 57365
+const CONSTANT = 57366
+const ERROR = 57367
+const PROGRAM = 57368
+const VERSION = 57369
+const METADATACOMMENT = 57370
+const PROCIDENTIFIER = 57371
+
+var yyToknames = [...]string{
+ "$end",
+ "error",
+ "$unk",
+ "BOOL",
+ "CASE",
+ "CONST",
+ "DEFAULT",
+ "DOUBLE",
+ "ENUM",
+ "FLOAT",
+ "OPAQUE",
+ "STRING",
+ "STRUCT",
+ "SWITCH",
+ "TYPEDEF",
+ "UNION",
+ "UNSIGNED",
+ "VOID",
+ "HYPER",
+ "INT",
+ "SHORT",
+ "CHAR",
+ "IDENTIFIER",
+ "CONSTANT",
+ "ERROR",
+ "PROGRAM",
+ "VERSION",
+ "METADATACOMMENT",
+ "PROCIDENTIFIER",
+ "';'",
+ "'{'",
+ "'}'",
+ "','",
+ "'='",
+ "'['",
+ "']'",
+ "'<'",
+ "'>'",
+ "'*'",
+ "'('",
+ "')'",
+ "':'",
+}
+
+var yyStatenames = [...]string{}
+
+const yyEofCode = 1
+const yyErrCode = 2
+const yyInitialStackSize = 16
+
+//line sunrpc.y:279
+
+//line yacctab:1
+var yyExca = [...]int{
+ -1, 1,
+ 1, -1,
+ -2, 0,
+}
+
+const yyPrivate = 57344
+
+const yyLast = 157
+
+var yyAct = [...]int{
+ 89, 82, 36, 119, 111, 81, 64, 70, 32, 55,
+ 58, 137, 134, 136, 108, 125, 90, 91, 83, 66,
+ 37, 106, 78, 31, 79, 105, 139, 61, 123, 101,
+ 74, 96, 41, 93, 76, 65, 40, 10, 39, 43,
+ 42, 13, 75, 30, 14, 38, 126, 48, 49, 50,
+ 51, 47, 115, 97, 84, 73, 114, 103, 60, 67,
+ 54, 52, 29, 59, 61, 118, 142, 135, 127, 116,
+ 77, 98, 80, 85, 16, 72, 66, 92, 11, 94,
+ 95, 10, 90, 91, 88, 13, 100, 12, 14, 62,
+ 63, 87, 99, 102, 104, 69, 27, 25, 15, 23,
+ 20, 18, 110, 2, 107, 117, 113, 109, 48, 49,
+ 50, 51, 46, 8, 112, 45, 7, 44, 4, 113,
+ 28, 124, 128, 121, 130, 122, 86, 71, 131, 8,
+ 26, 132, 7, 129, 4, 133, 138, 120, 53, 140,
+ 141, 24, 68, 22, 35, 34, 33, 21, 19, 57,
+ 56, 17, 9, 6, 5, 3, 1,
+}
+
+var yyPact = [...]int{
+ 72, -1000, -1000, 44, -1000, -1000, -1000, -1000, -1000, -1000,
+ 78, 77, -1000, 76, 74, 73, 72, 31, -1000, 9,
+ -1000, 28, 30, -1000, -1000, -1000, 29, -1000, -1000, 35,
+ 66, -1000, -1000, -1000, -1000, -1000, -4, -1000, 89, -1000,
+ -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
+ -1000, -1000, -1000, 81, 48, 23, -3, 8, 0, -2,
+ -1000, -1000, -1000, -1000, -13, 53, -1000, -1000, 28, -22,
+ 22, 43, 68, -1000, 35, 59, 59, -1, 59, -7,
+ -1000, 21, 41, 28, -5, 48, 26, -1000, -1000, -1000,
+ -1000, -1000, -1000, 59, -11, -17, -1000, -1000, 28, -27,
+ 53, 59, -1000, 28, -1000, -1000, -1000, -1000, 25, -1000,
+ -1000, 20, 39, 42, 118, -6, 28, -25, -1000, 14,
+ 38, 59, -1000, 59, -1000, 28, -1000, 118, -1000, -30,
+ 37, -28, -1000, -31, 28, -1000, -8, 28, -1000, 59,
+ -1000, 36, -1000,
+}
+
+var yyPgo = [...]int{
+ 0, 156, 103, 0, 155, 117, 154, 153, 115, 112,
+ 152, 151, 9, 150, 149, 10, 148, 147, 1, 8,
+ 146, 145, 144, 2, 6, 20, 143, 142, 5, 141,
+ 138, 3, 137, 135, 133, 130, 7, 127, 126, 4,
+ 114, 105,
+}
+
+var yyR1 = [...]int{
+ 0, 1, 3, 3, 2, 2, 4, 4, 4, 4,
+ 4, 4, 5, 12, 12, 13, 13, 13, 13, 15,
+ 11, 14, 6, 6, 16, 17, 7, 18, 18, 18,
+ 18, 19, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 25, 25, 25, 25, 24, 20, 21,
+ 21, 22, 27, 8, 26, 28, 28, 30, 9, 29,
+ 31, 31, 33, 32, 34, 32, 10, 35, 36, 36,
+ 37, 38, 39, 39, 40, 41,
+}
+
+var yyR2 = [...]int{
+ 0, 1, 1, 1, 2, 3, 1, 1, 1, 1,
+ 1, 1, 5, 1, 3, 1, 3, 3, 4, 1,
+ 1, 1, 4, 4, 1, 0, 3, 1, 1, 1,
+ 1, 2, 1, 2, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 5, 5,
+ 4, 3, 0, 6, 1, 2, 3, 0, 10, 1,
+ 2, 3, 0, 5, 0, 4, 7, 1, 2, 3,
+ 8, 1, 2, 3, 8, 1,
+}
+
+var yyChk = [...]int{
+ -1000, -1, -2, -4, -5, -6, -7, -8, -9, -10,
+ 9, 6, 15, 13, 16, 26, 30, -11, 23, -16,
+ 23, -17, -26, 23, -29, 23, -35, 23, -2, 31,
+ 34, -18, -19, -20, -21, -22, -23, -25, 17, 10,
+ 8, 4, 12, 11, -5, -8, -9, 23, 19, 20,
+ 21, 22, 31, -30, 31, -12, -13, -14, -15, 28,
+ 23, 29, 23, 24, -24, 39, 23, -25, -27, 14,
+ -36, -37, 27, 32, 33, 34, 34, -15, 35, 37,
+ -24, -28, -18, 40, 32, 30, -38, 23, -12, -3,
+ 23, 24, -3, 34, -3, -3, 38, 32, 30, -19,
+ -23, 34, -36, 31, -3, 36, 38, -28, 41, -24,
+ -3, -39, -40, -23, 31, 32, 30, -41, 23, -31,
+ -32, 5, 7, 34, -39, 40, 32, 30, -3, -34,
+ -3, -23, -31, -33, 42, 30, 41, 42, -18, 34,
+ -18, -3, 30,
+}
+
+var yyDef = [...]int{
+ 0, -2, 1, 0, 6, 7, 8, 9, 10, 11,
+ 0, 0, 25, 0, 0, 0, 4, 0, 20, 0,
+ 24, 0, 0, 54, 57, 59, 0, 67, 5, 0,
+ 0, 26, 27, 28, 29, 30, 0, 32, 0, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 52, 0, 0, 0, 13, 15, 0, 0,
+ 21, 19, 22, 23, 31, 0, 47, 33, 0, 0,
+ 0, 0, 0, 12, 0, 0, 0, 0, 0, 0,
+ 51, 0, 0, 0, 0, 68, 0, 71, 14, 16,
+ 2, 3, 17, 0, 0, 0, 50, 53, 55, 0,
+ 0, 0, 69, 0, 18, 48, 49, 56, 0, 31,
+ 66, 0, 0, 0, 0, 0, 72, 0, 75, 0,
+ 0, 0, 64, 0, 73, 0, 58, 60, 62, 0,
+ 0, 0, 61, 0, 0, 70, 0, 0, 65, 0,
+ 63, 0, 74,
+}
+
+var yyTok1 = [...]int{
+ 1, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 40, 41, 39, 3, 33, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 42, 30,
+ 37, 34, 38, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 35, 3, 36, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 31, 3, 32,
+}
+
+var yyTok2 = [...]int{
+ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 24, 25, 26, 27, 28, 29,
+}
+
+var yyTok3 = [...]int{
+ 0,
+}
+
+var yyErrorMessages = [...]struct {
+ state int
+ token int
+ msg string
+}{}
+
+//line yaccpar:1
+
+/* parser for yacc output */
+
+var (
+ yyDebug = 0
+ yyErrorVerbose = false
+)
+
+type yyLexer interface {
+ Lex(lval *yySymType) int
+ Error(s string)
+}
+
+type yyParser interface {
+ Parse(yyLexer) int
+ Lookahead() int
+}
+
+type yyParserImpl struct {
+ lval yySymType
+ stack [yyInitialStackSize]yySymType
+ char int
+}
+
+func (p *yyParserImpl) Lookahead() int {
+ return p.char
+}
+
+func yyNewParser() yyParser {
+ return &yyParserImpl{}
+}
+
+const yyFlag = -1000
+
+func yyTokname(c int) string {
+ if c >= 1 && c-1 < len(yyToknames) {
+ if yyToknames[c-1] != "" {
+ return yyToknames[c-1]
+ }
+ }
+ return __yyfmt__.Sprintf("tok-%v", c)
+}
+
+func yyStatname(s int) string {
+ if s >= 0 && s < len(yyStatenames) {
+ if yyStatenames[s] != "" {
+ return yyStatenames[s]
+ }
+ }
+ return __yyfmt__.Sprintf("state-%v", s)
+}
+
+func yyErrorMessage(state, lookAhead int) string {
+ const TOKSTART = 4
+
+ if !yyErrorVerbose {
+ return "syntax error"
+ }
+
+ for _, e := range yyErrorMessages {
+ if e.state == state && e.token == lookAhead {
+ return "syntax error: " + e.msg
+ }
+ }
+
+ res := "syntax error: unexpected " + yyTokname(lookAhead)
+
+ // To match Bison, suggest at most four expected tokens.
+ expected := make([]int, 0, 4)
+
+ // Look for shiftable tokens.
+ base := yyPact[state]
+ for tok := TOKSTART; tok-1 < len(yyToknames); tok++ {
+ if n := base + tok; n >= 0 && n < yyLast && yyChk[yyAct[n]] == tok {
+ if len(expected) == cap(expected) {
+ return res
+ }
+ expected = append(expected, tok)
+ }
+ }
+
+ if yyDef[state] == -2 {
+ i := 0
+ for yyExca[i] != -1 || yyExca[i+1] != state {
+ i += 2
+ }
+
+ // Look for tokens that we accept or reduce.
+ for i += 2; yyExca[i] >= 0; i += 2 {
+ tok := yyExca[i]
+ if tok < TOKSTART || yyExca[i+1] == 0 {
+ continue
+ }
+ if len(expected) == cap(expected) {
+ return res
+ }
+ expected = append(expected, tok)
+ }
+
+ // If the default action is to accept or reduce, give up.
+ if yyExca[i+1] != 0 {
+ return res
+ }
+ }
+
+ for i, tok := range expected {
+ if i == 0 {
+ res += ", expecting "
+ } else {
+ res += " or "
+ }
+ res += yyTokname(tok)
+ }
+ return res
+}
+
+func yylex1(lex yyLexer, lval *yySymType) (char, token int) {
+ token = 0
+ char = lex.Lex(lval)
+ if char <= 0 {
+ token = yyTok1[0]
+ goto out
+ }
+ if char < len(yyTok1) {
+ token = yyTok1[char]
+ goto out
+ }
+ if char >= yyPrivate {
+ if char < yyPrivate+len(yyTok2) {
+ token = yyTok2[char-yyPrivate]
+ goto out
+ }
+ }
+ for i := 0; i < len(yyTok3); i += 2 {
+ token = yyTok3[i+0]
+ if token == char {
+ token = yyTok3[i+1]
+ goto out
+ }
+ }
+
+out:
+ if token == 0 {
+ token = yyTok2[1] /* unknown char */
+ }
+ if yyDebug >= 3 {
+ __yyfmt__.Printf("lex %s(%d)\n", yyTokname(token), uint(char))
+ }
+ return char, token
+}
+
+func yyParse(yylex yyLexer) int {
+ return yyNewParser().Parse(yylex)
+}
+
+func (yyrcvr *yyParserImpl) Parse(yylex yyLexer) int {
+ var yyn int
+ var yyVAL yySymType
+ var yyDollar []yySymType
+ _ = yyDollar // silence set and not used
+ yyS := yyrcvr.stack[:]
+
+ Nerrs := 0 /* number of errors */
+ Errflag := 0 /* error recovery flag */
+ yystate := 0
+ yyrcvr.char = -1
+ yytoken := -1 // yyrcvr.char translated into internal numbering
+ defer func() {
+ // Make sure we report no lookahead when not parsing.
+ yystate = -1
+ yyrcvr.char = -1
+ yytoken = -1
+ }()
+ yyp := -1
+ goto yystack
+
+ret0:
+ return 0
+
+ret1:
+ return 1
+
+yystack:
+ /* put a state and value onto the stack */
+ if yyDebug >= 4 {
+ __yyfmt__.Printf("char %v in %v\n", yyTokname(yytoken), yyStatname(yystate))
+ }
+
+ yyp++
+ if yyp >= len(yyS) {
+ nyys := make([]yySymType, len(yyS)*2)
+ copy(nyys, yyS)
+ yyS = nyys
+ }
+ yyS[yyp] = yyVAL
+ yyS[yyp].yys = yystate
+
+yynewstate:
+ yyn = yyPact[yystate]
+ if yyn <= yyFlag {
+ goto yydefault /* simple state */
+ }
+ if yyrcvr.char < 0 {
+ yyrcvr.char, yytoken = yylex1(yylex, &yyrcvr.lval)
+ }
+ yyn += yytoken
+ if yyn < 0 || yyn >= yyLast {
+ goto yydefault
+ }
+ yyn = yyAct[yyn]
+ if yyChk[yyn] == yytoken { /* valid shift */
+ yyrcvr.char = -1
+ yytoken = -1
+ yyVAL = yyrcvr.lval
+ yystate = yyn
+ if Errflag > 0 {
+ Errflag--
+ }
+ goto yystack
+ }
+
+yydefault:
+ /* default state action */
+ yyn = yyDef[yystate]
+ if yyn == -2 {
+ if yyrcvr.char < 0 {
+ yyrcvr.char, yytoken = yylex1(yylex, &yyrcvr.lval)
+ }
+
+ /* look through exception table */
+ xi := 0
+ for {
+ if yyExca[xi+0] == -1 && yyExca[xi+1] == yystate {
+ break
+ }
+ xi += 2
+ }
+ for xi += 2; ; xi += 2 {
+ yyn = yyExca[xi+0]
+ if yyn < 0 || yyn == yytoken {
+ break
+ }
+ }
+ yyn = yyExca[xi+1]
+ if yyn < 0 {
+ goto ret0
+ }
+ }
+ if yyn == 0 {
+ /* error ... attempt to resume parsing */
+ switch Errflag {
+ case 0: /* brand new error */
+ yylex.Error(yyErrorMessage(yystate, yytoken))
+ Nerrs++
+ if yyDebug >= 1 {
+ __yyfmt__.Printf("%s", yyStatname(yystate))
+ __yyfmt__.Printf(" saw %s\n", yyTokname(yytoken))
+ }
+ fallthrough
+
+ case 1, 2: /* incompletely recovered error ... try again */
+ Errflag = 3
+
+ /* find a state where "error" is a legal shift action */
+ for yyp >= 0 {
+ yyn = yyPact[yyS[yyp].yys] + yyErrCode
+ if yyn >= 0 && yyn < yyLast {
+ yystate = yyAct[yyn] /* simulate a shift of "error" */
+ if yyChk[yystate] == yyErrCode {
+ goto yystack
+ }
+ }
+
+ /* the current p has no shift on "error", pop stack */
+ if yyDebug >= 2 {
+ __yyfmt__.Printf("error recovery pops state %d\n", yyS[yyp].yys)
+ }
+ yyp--
+ }
+ /* there is no state on the stack with an error shift ... abort */
+ goto ret1
+
+ case 3: /* no shift yet; clobber input char */
+ if yyDebug >= 2 {
+ __yyfmt__.Printf("error recovery discards %s\n", yyTokname(yytoken))
+ }
+ if yytoken == yyEofCode {
+ goto ret1
+ }
+ yyrcvr.char = -1
+ yytoken = -1
+ goto yynewstate /* try again in the same state */
+ }
+ }
+
+ /* reduction by production yyn */
+ if yyDebug >= 2 {
+ __yyfmt__.Printf("reduce %v in:\n\t%v\n", yyn, yyStatname(yystate))
+ }
+
+ yynt := yyn
+ yypt := yyp
+ _ = yypt // guard against "declared and not used"
+
+ yyp -= yyR2[yyn]
+ // yyp is now the index of $0. Perform the default action. Iff the
+ // reduced production is ε, $1 is possibly out of range.
+ if yyp+1 >= len(yyS) {
+ nyys := make([]yySymType, len(yyS)*2)
+ copy(nyys, yyS)
+ yyS = nyys
+ }
+ yyVAL = yyS[yyp+1]
+
+ /* consult goto table to find next state */
+ yyn = yyR1[yyn]
+ yyg := yyPgo[yyn]
+ yyj := yyg + yyS[yyp].yys + 1
+
+ if yyj >= yyLast {
+ yystate = yyAct[yyg]
+ } else {
+ yystate = yyAct[yyj]
+ if yyChk[yystate] != -yyn {
+ yystate = yyAct[yyg]
+ }
+ }
+ // dummy call; replaced with literal code
+ switch yynt {
+
+ case 12:
+ yyDollar = yyS[yypt-5 : yypt+1]
+//line sunrpc.y:88
+ {
+ StartEnum(yyDollar[2].val)
+ }
+ case 15:
+ yyDollar = yyS[yypt-1 : yypt+1]
+//line sunrpc.y:97
+ {
+ err := AddEnumAutoVal(yyDollar[1].val)
+ if err != nil {
+ yylex.Error(err.Error())
+ return 1
+ }
+ }
+ case 16:
+ yyDollar = yyS[yypt-3 : yypt+1]
+//line sunrpc.y:104
+ {
+ err := AddEnumVal(yyDollar[1].val, yyDollar[3].val)
+ if err != nil {
+ yylex.Error(err.Error())
+ return 1
+ }
+ }
+ case 17:
+ yyDollar = yyS[yypt-3 : yypt+1]
+//line sunrpc.y:111
+ {
+ err := AddProcEnumVal(yyDollar[1].val, yyDollar[3].val, "")
+ if err != nil {
+ yylex.Error(err.Error())
+ return 1
+ }
+ }
+ case 18:
+ yyDollar = yyS[yypt-4 : yypt+1]
+//line sunrpc.y:118
+ {
+ err := AddProcEnumVal(yyDollar[2].val, yyDollar[4].val, yyDollar[1].val)
+ if err != nil {
+ yylex.Error(err.Error())
+ return 1
+ }
+ }
+ case 23:
+ yyDollar = yyS[yypt-4 : yypt+1]
+//line sunrpc.y:144
+ {
+ err := AddConst(yyDollar[2].val, yyDollar[4].val)
+ if err != nil {
+ yylex.Error(err.Error())
+ return 1
+ }
+ }
+ case 25:
+ yyDollar = yyS[yypt-1 : yypt+1]
+//line sunrpc.y:158
+ {
+ StartTypedef()
+ }
+ case 31:
+ yyDollar = yyS[yypt-2 : yypt+1]
+//line sunrpc.y:169
+ {
+ AddDeclaration(yyDollar[2].val, yyDollar[1].val)
+ }
+ case 33:
+ yyDollar = yyS[yypt-2 : yypt+1]
+//line sunrpc.y:174
+ {
+ yyVAL.val = "u" + yyDollar[2].val
+ }
+ case 34:
+ yyDollar = yyS[yypt-1 : yypt+1]
+//line sunrpc.y:175
+ {
+ yyVAL.val = "float32"
+ }
+ case 35:
+ yyDollar = yyS[yypt-1 : yypt+1]
+//line sunrpc.y:176
+ {
+ yyVAL.val = "float64"
+ }
+ case 36:
+ yyDollar = yyS[yypt-1 : yypt+1]
+//line sunrpc.y:177
+ {
+ yyVAL.val = "bool"
+ }
+ case 37:
+ yyDollar = yyS[yypt-1 : yypt+1]
+//line sunrpc.y:178
+ {
+ yyVAL.val = "string"
+ }
+ case 38:
+ yyDollar = yyS[yypt-1 : yypt+1]
+//line sunrpc.y:179
+ {
+ yyVAL.val = "byte"
+ }
+ case 43:
+ yyDollar = yyS[yypt-1 : yypt+1]
+//line sunrpc.y:187
+ {
+ yyVAL.val = "int64"
+ }
+ case 44:
+ yyDollar = yyS[yypt-1 : yypt+1]
+//line sunrpc.y:188
+ {
+ yyVAL.val = "int32"
+ }
+ case 45:
+ yyDollar = yyS[yypt-1 : yypt+1]
+//line sunrpc.y:189
+ {
+ yyVAL.val = "int16"
+ }
+ case 46:
+ yyDollar = yyS[yypt-1 : yypt+1]
+//line sunrpc.y:190
+ {
+ yyVAL.val = "int8"
+ }
+ case 48:
+ yyDollar = yyS[yypt-5 : yypt+1]
+//line sunrpc.y:198
+ {
+ AddFixedArray(yyDollar[2].val, yyDollar[1].val, yyDollar[4].val)
+ }
+ case 49:
+ yyDollar = yyS[yypt-5 : yypt+1]
+//line sunrpc.y:202
+ {
+ AddVariableArray(yyDollar[2].val, yyDollar[1].val, yyDollar[4].val)
+ }
+ case 50:
+ yyDollar = yyS[yypt-4 : yypt+1]
+//line sunrpc.y:203
+ {
+ AddVariableArray(yyDollar[2].val, yyDollar[1].val, "")
+ }
+ case 51:
+ yyDollar = yyS[yypt-3 : yypt+1]
+//line sunrpc.y:211
+ {
+ AddOptValue(yyDollar[3].val, yyDollar[1].val)
+ }
+ case 52:
+ yyDollar = yyS[yypt-3 : yypt+1]
+//line sunrpc.y:215
+ {
+ StartStruct(yyDollar[2].val)
+ }
+ case 53:
+ yyDollar = yyS[yypt-6 : yypt+1]
+//line sunrpc.y:215
+ {
+ AddStruct()
+ }
+ case 57:
+ yyDollar = yyS[yypt-2 : yypt+1]
+//line sunrpc.y:228
+ {
+ StartUnion(yyDollar[2].val)
+ }
+ case 58:
+ yyDollar = yyS[yypt-10 : yypt+1]
+//line sunrpc.y:228
+ {
+ AddUnion()
+ }
+ case 62:
+ yyDollar = yyS[yypt-2 : yypt+1]
+//line sunrpc.y:241
+ {
+ StartCase(yyDollar[2].val)
+ }
+ case 63:
+ yyDollar = yyS[yypt-5 : yypt+1]
+//line sunrpc.y:241
+ {
+ AddCase()
+ }
+ case 64:
+ yyDollar = yyS[yypt-1 : yypt+1]
+//line sunrpc.y:242
+ {
+ StartCase("default")
+ }
+ case 65:
+ yyDollar = yyS[yypt-4 : yypt+1]
+//line sunrpc.y:242
+ {
+ AddCase()
+ }
+ }
+ goto yystack /* stack new state and value */
+}
diff --git a/third_party/libvirt/internal/lvgen/y.output b/third_party/libvirt/internal/lvgen/y.output
new file mode 100644
index 0000000..55f5389
--- /dev/null
+++ b/third_party/libvirt/internal/lvgen/y.output
@@ -0,0 +1,1259 @@
+
+state 0
+ $accept: .specification $end
+
+ CONST shift 11
+ ENUM shift 10
+ STRUCT shift 13
+ TYPEDEF shift 12
+ UNION shift 14
+ PROGRAM shift 15
+ . error
+
+ specification goto 1
+ definition_list goto 2
+ definition goto 3
+ enum_definition goto 4
+ const_definition goto 5
+ typedef_definition goto 6
+ struct_definition goto 7
+ union_definition goto 8
+ program_definition goto 9
+
+state 1
+ $accept: specification.$end
+
+ $end accept
+ . error
+
+
+state 2
+ specification: definition_list. (1)
+
+ . reduce 1 (src line 64)
+
+
+state 3
+ definition_list: definition.';'
+ definition_list: definition.';' definition_list
+
+ ';' shift 16
+ . error
+
+
+state 4
+ definition: enum_definition. (6)
+
+ . reduce 6 (src line 78)
+
+
+state 5
+ definition: const_definition. (7)
+
+ . reduce 7 (src line 80)
+
+
+state 6
+ definition: typedef_definition. (8)
+
+ . reduce 8 (src line 81)
+
+
+state 7
+ definition: struct_definition. (9)
+
+ . reduce 9 (src line 82)
+
+
+state 8
+ definition: union_definition. (10)
+
+ . reduce 10 (src line 83)
+
+
+state 9
+ definition: program_definition. (11)
+
+ . reduce 11 (src line 84)
+
+
+state 10
+ enum_definition: ENUM.enum_ident '{' enum_value_list '}'
+
+ IDENTIFIER shift 18
+ . error
+
+ enum_ident goto 17
+
+state 11
+ const_definition: CONST.const_ident '=' IDENTIFIER
+ const_definition: CONST.const_ident '=' CONSTANT
+
+ IDENTIFIER shift 20
+ . error
+
+ const_ident goto 19
+
+state 12
+ typedef_definition: TYPEDEF.$$25 declaration
+ $$25: . (25)
+
+ . reduce 25 (src line 157)
+
+ $$25 goto 21
+
+state 13
+ struct_definition: STRUCT.struct_ident '{' $$52 declaration_list '}'
+
+ IDENTIFIER shift 23
+ . error
+
+ struct_ident goto 22
+
+state 14
+ union_definition: UNION.union_ident $$57 SWITCH '(' simple_declaration ')' '{' case_list '}'
+
+ IDENTIFIER shift 25
+ . error
+
+ union_ident goto 24
+
+state 15
+ program_definition: PROGRAM.program_ident '{' version_list '}' '=' value
+
+ IDENTIFIER shift 27
+ . error
+
+ program_ident goto 26
+
+state 16
+ definition_list: definition ';'. (4)
+ definition_list: definition ';'.definition_list
+
+ CONST shift 11
+ ENUM shift 10
+ STRUCT shift 13
+ TYPEDEF shift 12
+ UNION shift 14
+ PROGRAM shift 15
+ . reduce 4 (src line 73)
+
+ definition_list goto 28
+ definition goto 3
+ enum_definition goto 4
+ const_definition goto 5
+ typedef_definition goto 6
+ struct_definition goto 7
+ union_definition goto 8
+ program_definition goto 9
+
+state 17
+ enum_definition: ENUM enum_ident.'{' enum_value_list '}'
+
+ '{' shift 29
+ . error
+
+
+state 18
+ enum_ident: IDENTIFIER. (20)
+
+ . reduce 20 (src line 131)
+
+
+state 19
+ const_definition: CONST const_ident.'=' IDENTIFIER
+ const_definition: CONST const_ident.'=' CONSTANT
+
+ '=' shift 30
+ . error
+
+
+state 20
+ const_ident: IDENTIFIER. (24)
+
+ . reduce 24 (src line 153)
+
+
+state 21
+ typedef_definition: TYPEDEF $$25.declaration
+
+ BOOL shift 41
+ DOUBLE shift 40
+ ENUM shift 10
+ FLOAT shift 39
+ OPAQUE shift 43
+ STRING shift 42
+ STRUCT shift 13
+ UNION shift 14
+ UNSIGNED shift 38
+ HYPER shift 48
+ INT shift 49
+ SHORT shift 50
+ CHAR shift 51
+ IDENTIFIER shift 47
+ . error
+
+ enum_definition goto 44
+ struct_definition goto 45
+ union_definition goto 46
+ declaration goto 31
+ simple_declaration goto 32
+ fixed_array_declaration goto 33
+ variable_array_declaration goto 34
+ pointer_declaration goto 35
+ type_specifier goto 36
+ int_spec goto 37
+
+state 22
+ struct_definition: STRUCT struct_ident.'{' $$52 declaration_list '}'
+
+ '{' shift 52
+ . error
+
+
+state 23
+ struct_ident: IDENTIFIER. (54)
+
+ . reduce 54 (src line 218)
+
+
+state 24
+ union_definition: UNION union_ident.$$57 SWITCH '(' simple_declaration ')' '{' case_list '}'
+ $$57: . (57)
+
+ . reduce 57 (src line 227)
+
+ $$57 goto 53
+
+state 25
+ union_ident: IDENTIFIER. (59)
+
+ . reduce 59 (src line 231)
+
+
+state 26
+ program_definition: PROGRAM program_ident.'{' version_list '}' '=' value
+
+ '{' shift 54
+ . error
+
+
+state 27
+ program_ident: IDENTIFIER. (67)
+
+ . reduce 67 (src line 249)
+
+
+state 28
+ definition_list: definition ';' definition_list. (5)
+
+ . reduce 5 (src line 75)
+
+
+state 29
+ enum_definition: ENUM enum_ident '{'.enum_value_list '}'
+
+ IDENTIFIER shift 60
+ METADATACOMMENT shift 59
+ PROCIDENTIFIER shift 61
+ . error
+
+ enum_value_list goto 55
+ enum_value goto 56
+ enum_value_ident goto 57
+ enum_proc_ident goto 58
+
+state 30
+ const_definition: CONST const_ident '='.IDENTIFIER
+ const_definition: CONST const_ident '='.CONSTANT
+
+ IDENTIFIER shift 62
+ CONSTANT shift 63
+ . error
+
+
+state 31
+ typedef_definition: TYPEDEF $$25 declaration. (26)
+
+ . reduce 26 (src line 158)
+
+
+state 32
+ declaration: simple_declaration. (27)
+
+ . reduce 27 (src line 161)
+
+
+state 33
+ declaration: fixed_array_declaration. (28)
+
+ . reduce 28 (src line 163)
+
+
+state 34
+ declaration: variable_array_declaration. (29)
+
+ . reduce 29 (src line 164)
+
+
+state 35
+ declaration: pointer_declaration. (30)
+
+ . reduce 30 (src line 165)
+
+
+state 36
+ simple_declaration: type_specifier.variable_ident
+ fixed_array_declaration: type_specifier.variable_ident '[' value ']'
+ variable_array_declaration: type_specifier.variable_ident '<' value '>'
+ variable_array_declaration: type_specifier.variable_ident '<' '>'
+ pointer_declaration: type_specifier.'*' variable_ident
+
+ IDENTIFIER shift 66
+ '*' shift 65
+ . error
+
+ variable_ident goto 64
+
+state 37
+ type_specifier: int_spec. (32)
+
+ . reduce 32 (src line 172)
+
+
+state 38
+ type_specifier: UNSIGNED.int_spec
+
+ HYPER shift 48
+ INT shift 49
+ SHORT shift 50
+ CHAR shift 51
+ . error
+
+ int_spec goto 67
+
+state 39
+ type_specifier: FLOAT. (34)
+
+ . reduce 34 (src line 175)
+
+
+state 40
+ type_specifier: DOUBLE. (35)
+
+ . reduce 35 (src line 176)
+
+
+state 41
+ type_specifier: BOOL. (36)
+
+ . reduce 36 (src line 177)
+
+
+state 42
+ type_specifier: STRING. (37)
+
+ . reduce 37 (src line 178)
+
+
+state 43
+ type_specifier: OPAQUE. (38)
+
+ . reduce 38 (src line 179)
+
+
+state 44
+ type_specifier: enum_definition. (39)
+
+ . reduce 39 (src line 180)
+
+
+state 45
+ type_specifier: struct_definition. (40)
+
+ . reduce 40 (src line 181)
+
+
+state 46
+ type_specifier: union_definition. (41)
+
+ . reduce 41 (src line 182)
+
+
+state 47
+ type_specifier: IDENTIFIER. (42)
+
+ . reduce 42 (src line 183)
+
+
+state 48
+ int_spec: HYPER. (43)
+
+ . reduce 43 (src line 186)
+
+
+state 49
+ int_spec: INT. (44)
+
+ . reduce 44 (src line 188)
+
+
+state 50
+ int_spec: SHORT. (45)
+
+ . reduce 45 (src line 189)
+
+
+state 51
+ int_spec: CHAR. (46)
+
+ . reduce 46 (src line 190)
+
+
+state 52
+ struct_definition: STRUCT struct_ident '{'.$$52 declaration_list '}'
+ $$52: . (52)
+
+ . reduce 52 (src line 214)
+
+ $$52 goto 68
+
+state 53
+ union_definition: UNION union_ident $$57.SWITCH '(' simple_declaration ')' '{' case_list '}'
+
+ SWITCH shift 69
+ . error
+
+
+state 54
+ program_definition: PROGRAM program_ident '{'.version_list '}' '=' value
+
+ VERSION shift 72
+ . error
+
+ version_list goto 70
+ version goto 71
+
+state 55
+ enum_definition: ENUM enum_ident '{' enum_value_list.'}'
+
+ '}' shift 73
+ . error
+
+
+state 56
+ enum_value_list: enum_value. (13)
+ enum_value_list: enum_value.',' enum_value_list
+
+ ',' shift 74
+ . reduce 13 (src line 91)
+
+
+state 57
+ enum_value: enum_value_ident. (15)
+ enum_value: enum_value_ident.'=' value
+
+ '=' shift 75
+ . reduce 15 (src line 96)
+
+
+state 58
+ enum_value: enum_proc_ident.'=' value
+
+ '=' shift 76
+ . error
+
+
+state 59
+ enum_value: METADATACOMMENT.enum_proc_ident '=' value
+
+ PROCIDENTIFIER shift 61
+ . error
+
+ enum_proc_ident goto 77
+
+state 60
+ enum_value_ident: IDENTIFIER. (21)
+
+ . reduce 21 (src line 135)
+
+
+state 61
+ enum_proc_ident: PROCIDENTIFIER. (19)
+
+ . reduce 19 (src line 127)
+
+
+state 62
+ const_definition: CONST const_ident '=' IDENTIFIER. (22)
+
+ . reduce 22 (src line 142)
+
+
+state 63
+ const_definition: CONST const_ident '=' CONSTANT. (23)
+
+ . reduce 23 (src line 144)
+
+
+state 64
+ simple_declaration: type_specifier variable_ident. (31)
+ fixed_array_declaration: type_specifier variable_ident.'[' value ']'
+ variable_array_declaration: type_specifier variable_ident.'<' value '>'
+ variable_array_declaration: type_specifier variable_ident.'<' '>'
+
+ '[' shift 78
+ '<' shift 79
+ . reduce 31 (src line 168)
+
+
+state 65
+ pointer_declaration: type_specifier '*'.variable_ident
+
+ IDENTIFIER shift 66
+ . error
+
+ variable_ident goto 80
+
+state 66
+ variable_ident: IDENTIFIER. (47)
+
+ . reduce 47 (src line 193)
+
+
+state 67
+ type_specifier: UNSIGNED int_spec. (33)
+
+ . reduce 33 (src line 174)
+
+
+state 68
+ struct_definition: STRUCT struct_ident '{' $$52.declaration_list '}'
+
+ BOOL shift 41
+ DOUBLE shift 40
+ ENUM shift 10
+ FLOAT shift 39
+ OPAQUE shift 43
+ STRING shift 42
+ STRUCT shift 13
+ UNION shift 14
+ UNSIGNED shift 38
+ HYPER shift 48
+ INT shift 49
+ SHORT shift 50
+ CHAR shift 51
+ IDENTIFIER shift 47
+ . error
+
+ enum_definition goto 44
+ struct_definition goto 45
+ union_definition goto 46
+ declaration goto 82
+ simple_declaration goto 32
+ fixed_array_declaration goto 33
+ variable_array_declaration goto 34
+ pointer_declaration goto 35
+ type_specifier goto 36
+ int_spec goto 37
+ declaration_list goto 81
+
+state 69
+ union_definition: UNION union_ident $$57 SWITCH.'(' simple_declaration ')' '{' case_list '}'
+
+ '(' shift 83
+ . error
+
+
+state 70
+ program_definition: PROGRAM program_ident '{' version_list.'}' '=' value
+
+ '}' shift 84
+ . error
+
+
+state 71
+ version_list: version.';'
+ version_list: version.';' version_list
+
+ ';' shift 85
+ . error
+
+
+state 72
+ version: VERSION.version_ident '{' procedure_list '}' '=' value ';'
+
+ IDENTIFIER shift 87
+ . error
+
+ version_ident goto 86
+
+state 73
+ enum_definition: ENUM enum_ident '{' enum_value_list '}'. (12)
+
+ . reduce 12 (src line 87)
+
+
+state 74
+ enum_value_list: enum_value ','.enum_value_list
+
+ IDENTIFIER shift 60
+ METADATACOMMENT shift 59
+ PROCIDENTIFIER shift 61
+ . error
+
+ enum_value_list goto 88
+ enum_value goto 56
+ enum_value_ident goto 57
+ enum_proc_ident goto 58
+
+state 75
+ enum_value: enum_value_ident '='.value
+
+ IDENTIFIER shift 90
+ CONSTANT shift 91
+ . error
+
+ value goto 89
+
+state 76
+ enum_value: enum_proc_ident '='.value
+
+ IDENTIFIER shift 90
+ CONSTANT shift 91
+ . error
+
+ value goto 92
+
+state 77
+ enum_value: METADATACOMMENT enum_proc_ident.'=' value
+
+ '=' shift 93
+ . error
+
+
+state 78
+ fixed_array_declaration: type_specifier variable_ident '['.value ']'
+
+ IDENTIFIER shift 90
+ CONSTANT shift 91
+ . error
+
+ value goto 94
+
+state 79
+ variable_array_declaration: type_specifier variable_ident '<'.value '>'
+ variable_array_declaration: type_specifier variable_ident '<'.'>'
+
+ IDENTIFIER shift 90
+ CONSTANT shift 91
+ '>' shift 96
+ . error
+
+ value goto 95
+
+state 80
+ pointer_declaration: type_specifier '*' variable_ident. (51)
+
+ . reduce 51 (src line 210)
+
+
+state 81
+ struct_definition: STRUCT struct_ident '{' $$52 declaration_list.'}'
+
+ '}' shift 97
+ . error
+
+
+state 82
+ declaration_list: declaration.';'
+ declaration_list: declaration.';' declaration_list
+
+ ';' shift 98
+ . error
+
+
+state 83
+ union_definition: UNION union_ident $$57 SWITCH '('.simple_declaration ')' '{' case_list '}'
+
+ BOOL shift 41
+ DOUBLE shift 40
+ ENUM shift 10
+ FLOAT shift 39
+ OPAQUE shift 43
+ STRING shift 42
+ STRUCT shift 13
+ UNION shift 14
+ UNSIGNED shift 38
+ HYPER shift 48
+ INT shift 49
+ SHORT shift 50
+ CHAR shift 51
+ IDENTIFIER shift 47
+ . error
+
+ enum_definition goto 44
+ struct_definition goto 45
+ union_definition goto 46
+ simple_declaration goto 99
+ type_specifier goto 100
+ int_spec goto 37
+
+state 84
+ program_definition: PROGRAM program_ident '{' version_list '}'.'=' value
+
+ '=' shift 101
+ . error
+
+
+state 85
+ version_list: version ';'. (68)
+ version_list: version ';'.version_list
+
+ VERSION shift 72
+ . reduce 68 (src line 253)
+
+ version_list goto 102
+ version goto 71
+
+state 86
+ version: VERSION version_ident.'{' procedure_list '}' '=' value ';'
+
+ '{' shift 103
+ . error
+
+
+state 87
+ version_ident: IDENTIFIER. (71)
+
+ . reduce 71 (src line 262)
+
+
+state 88
+ enum_value_list: enum_value ',' enum_value_list. (14)
+
+ . reduce 14 (src line 93)
+
+
+state 89
+ enum_value: enum_value_ident '=' value. (16)
+
+ . reduce 16 (src line 104)
+
+
+state 90
+ value: IDENTIFIER. (2)
+
+ . reduce 2 (src line 68)
+
+
+state 91
+ value: CONSTANT. (3)
+
+ . reduce 3 (src line 70)
+
+
+state 92
+ enum_value: enum_proc_ident '=' value. (17)
+
+ . reduce 17 (src line 111)
+
+
+state 93
+ enum_value: METADATACOMMENT enum_proc_ident '='.value
+
+ IDENTIFIER shift 90
+ CONSTANT shift 91
+ . error
+
+ value goto 104
+
+state 94
+ fixed_array_declaration: type_specifier variable_ident '[' value.']'
+
+ ']' shift 105
+ . error
+
+
+state 95
+ variable_array_declaration: type_specifier variable_ident '<' value.'>'
+
+ '>' shift 106
+ . error
+
+
+state 96
+ variable_array_declaration: type_specifier variable_ident '<' '>'. (50)
+
+ . reduce 50 (src line 203)
+
+
+state 97
+ struct_definition: STRUCT struct_ident '{' $$52 declaration_list '}'. (53)
+
+ . reduce 53 (src line 215)
+
+
+state 98
+ declaration_list: declaration ';'. (55)
+ declaration_list: declaration ';'.declaration_list
+
+ BOOL shift 41
+ DOUBLE shift 40
+ ENUM shift 10
+ FLOAT shift 39
+ OPAQUE shift 43
+ STRING shift 42
+ STRUCT shift 13
+ UNION shift 14
+ UNSIGNED shift 38
+ HYPER shift 48
+ INT shift 49
+ SHORT shift 50
+ CHAR shift 51
+ IDENTIFIER shift 47
+ . reduce 55 (src line 222)
+
+ enum_definition goto 44
+ struct_definition goto 45
+ union_definition goto 46
+ declaration goto 82
+ simple_declaration goto 32
+ fixed_array_declaration goto 33
+ variable_array_declaration goto 34
+ pointer_declaration goto 35
+ type_specifier goto 36
+ int_spec goto 37
+ declaration_list goto 107
+
+state 99
+ union_definition: UNION union_ident $$57 SWITCH '(' simple_declaration.')' '{' case_list '}'
+
+ ')' shift 108
+ . error
+
+
+state 100
+ simple_declaration: type_specifier.variable_ident
+
+ IDENTIFIER shift 66
+ . error
+
+ variable_ident goto 109
+
+state 101
+ program_definition: PROGRAM program_ident '{' version_list '}' '='.value
+
+ IDENTIFIER shift 90
+ CONSTANT shift 91
+ . error
+
+ value goto 110
+
+state 102
+ version_list: version ';' version_list. (69)
+
+ . reduce 69 (src line 255)
+
+
+state 103
+ version: VERSION version_ident '{'.procedure_list '}' '=' value ';'
+
+ BOOL shift 41
+ DOUBLE shift 40
+ ENUM shift 10
+ FLOAT shift 39
+ OPAQUE shift 43
+ STRING shift 42
+ STRUCT shift 13
+ UNION shift 14
+ UNSIGNED shift 38
+ HYPER shift 48
+ INT shift 49
+ SHORT shift 50
+ CHAR shift 51
+ IDENTIFIER shift 47
+ . error
+
+ enum_definition goto 44
+ struct_definition goto 45
+ union_definition goto 46
+ type_specifier goto 113
+ int_spec goto 37
+ procedure_list goto 111
+ procedure goto 112
+
+state 104
+ enum_value: METADATACOMMENT enum_proc_ident '=' value. (18)
+
+ . reduce 18 (src line 118)
+
+
+state 105
+ fixed_array_declaration: type_specifier variable_ident '[' value ']'. (48)
+
+ . reduce 48 (src line 197)
+
+
+state 106
+ variable_array_declaration: type_specifier variable_ident '<' value '>'. (49)
+
+ . reduce 49 (src line 201)
+
+
+state 107
+ declaration_list: declaration ';' declaration_list. (56)
+
+ . reduce 56 (src line 224)
+
+
+state 108
+ union_definition: UNION union_ident $$57 SWITCH '(' simple_declaration ')'.'{' case_list '}'
+
+ '{' shift 114
+ . error
+
+
+state 109
+ simple_declaration: type_specifier variable_ident. (31)
+
+ . reduce 31 (src line 168)
+
+
+state 110
+ program_definition: PROGRAM program_ident '{' version_list '}' '=' value. (66)
+
+ . reduce 66 (src line 245)
+
+
+state 111
+ version: VERSION version_ident '{' procedure_list.'}' '=' value ';'
+
+ '}' shift 115
+ . error
+
+
+state 112
+ procedure_list: procedure.';'
+ procedure_list: procedure.';' procedure_list
+
+ ';' shift 116
+ . error
+
+
+state 113
+ procedure: type_specifier.procedure_ident '(' type_specifier ')' '=' value ';'
+
+ IDENTIFIER shift 118
+ . error
+
+ procedure_ident goto 117
+
+state 114
+ union_definition: UNION union_ident $$57 SWITCH '(' simple_declaration ')' '{'.case_list '}'
+
+ CASE shift 121
+ DEFAULT shift 122
+ . error
+
+ case_list goto 119
+ case goto 120
+
+state 115
+ version: VERSION version_ident '{' procedure_list '}'.'=' value ';'
+
+ '=' shift 123
+ . error
+
+
+state 116
+ procedure_list: procedure ';'. (72)
+ procedure_list: procedure ';'.procedure_list
+
+ BOOL shift 41
+ DOUBLE shift 40
+ ENUM shift 10
+ FLOAT shift 39
+ OPAQUE shift 43
+ STRING shift 42
+ STRUCT shift 13
+ UNION shift 14
+ UNSIGNED shift 38
+ HYPER shift 48
+ INT shift 49
+ SHORT shift 50
+ CHAR shift 51
+ IDENTIFIER shift 47
+ . reduce 72 (src line 266)
+
+ enum_definition goto 44
+ struct_definition goto 45
+ union_definition goto 46
+ type_specifier goto 113
+ int_spec goto 37
+ procedure_list goto 124
+ procedure goto 112
+
+state 117
+ procedure: type_specifier procedure_ident.'(' type_specifier ')' '=' value ';'
+
+ '(' shift 125
+ . error
+
+
+state 118
+ procedure_ident: IDENTIFIER. (75)
+
+ . reduce 75 (src line 275)
+
+
+state 119
+ union_definition: UNION union_ident $$57 SWITCH '(' simple_declaration ')' '{' case_list.'}'
+
+ '}' shift 126
+ . error
+
+
+state 120
+ case_list: case.';'
+ case_list: case.';' case_list
+
+ ';' shift 127
+ . error
+
+
+state 121
+ case: CASE.value $$62 ':' declaration
+
+ IDENTIFIER shift 90
+ CONSTANT shift 91
+ . error
+
+ value goto 128
+
+state 122
+ case: DEFAULT.$$64 ':' declaration
+ $$64: . (64)
+
+ . reduce 64 (src line 242)
+
+ $$64 goto 129
+
+state 123
+ version: VERSION version_ident '{' procedure_list '}' '='.value ';'
+
+ IDENTIFIER shift 90
+ CONSTANT shift 91
+ . error
+
+ value goto 130
+
+state 124
+ procedure_list: procedure ';' procedure_list. (73)
+
+ . reduce 73 (src line 268)
+
+
+state 125
+ procedure: type_specifier procedure_ident '('.type_specifier ')' '=' value ';'
+
+ BOOL shift 41
+ DOUBLE shift 40
+ ENUM shift 10
+ FLOAT shift 39
+ OPAQUE shift 43
+ STRING shift 42
+ STRUCT shift 13
+ UNION shift 14
+ UNSIGNED shift 38
+ HYPER shift 48
+ INT shift 49
+ SHORT shift 50
+ CHAR shift 51
+ IDENTIFIER shift 47
+ . error
+
+ enum_definition goto 44
+ struct_definition goto 45
+ union_definition goto 46
+ type_specifier goto 131
+ int_spec goto 37
+
+state 126
+ union_definition: UNION union_ident $$57 SWITCH '(' simple_declaration ')' '{' case_list '}'. (58)
+
+ . reduce 58 (src line 228)
+
+
+state 127
+ case_list: case ';'. (60)
+ case_list: case ';'.case_list
+
+ CASE shift 121
+ DEFAULT shift 122
+ . reduce 60 (src line 235)
+
+ case_list goto 132
+ case goto 120
+
+state 128
+ case: CASE value.$$62 ':' declaration
+ $$62: . (62)
+
+ . reduce 62 (src line 240)
+
+ $$62 goto 133
+
+state 129
+ case: DEFAULT $$64.':' declaration
+
+ ':' shift 134
+ . error
+
+
+state 130
+ version: VERSION version_ident '{' procedure_list '}' '=' value.';'
+
+ ';' shift 135
+ . error
+
+
+state 131
+ procedure: type_specifier procedure_ident '(' type_specifier.')' '=' value ';'
+
+ ')' shift 136
+ . error
+
+
+state 132
+ case_list: case ';' case_list. (61)
+
+ . reduce 61 (src line 237)
+
+
+state 133
+ case: CASE value $$62.':' declaration
+
+ ':' shift 137
+ . error
+
+
+state 134
+ case: DEFAULT $$64 ':'.declaration
+
+ BOOL shift 41
+ DOUBLE shift 40
+ ENUM shift 10
+ FLOAT shift 39
+ OPAQUE shift 43
+ STRING shift 42
+ STRUCT shift 13
+ UNION shift 14
+ UNSIGNED shift 38
+ HYPER shift 48
+ INT shift 49
+ SHORT shift 50
+ CHAR shift 51
+ IDENTIFIER shift 47
+ . error
+
+ enum_definition goto 44
+ struct_definition goto 45
+ union_definition goto 46
+ declaration goto 138
+ simple_declaration goto 32
+ fixed_array_declaration goto 33
+ variable_array_declaration goto 34
+ pointer_declaration goto 35
+ type_specifier goto 36
+ int_spec goto 37
+
+state 135
+ version: VERSION version_ident '{' procedure_list '}' '=' value ';'. (70)
+
+ . reduce 70 (src line 258)
+
+
+state 136
+ procedure: type_specifier procedure_ident '(' type_specifier ')'.'=' value ';'
+
+ '=' shift 139
+ . error
+
+
+state 137
+ case: CASE value $$62 ':'.declaration
+
+ BOOL shift 41
+ DOUBLE shift 40
+ ENUM shift 10
+ FLOAT shift 39
+ OPAQUE shift 43
+ STRING shift 42
+ STRUCT shift 13
+ UNION shift 14
+ UNSIGNED shift 38
+ HYPER shift 48
+ INT shift 49
+ SHORT shift 50
+ CHAR shift 51
+ IDENTIFIER shift 47
+ . error
+
+ enum_definition goto 44
+ struct_definition goto 45
+ union_definition goto 46
+ declaration goto 140
+ simple_declaration goto 32
+ fixed_array_declaration goto 33
+ variable_array_declaration goto 34
+ pointer_declaration goto 35
+ type_specifier goto 36
+ int_spec goto 37
+
+state 138
+ case: DEFAULT $$64 ':' declaration. (65)
+
+ . reduce 65 (src line 242)
+
+
+state 139
+ procedure: type_specifier procedure_ident '(' type_specifier ')' '='.value ';'
+
+ IDENTIFIER shift 90
+ CONSTANT shift 91
+ . error
+
+ value goto 141
+
+state 140
+ case: CASE value $$62 ':' declaration. (63)
+
+ . reduce 63 (src line 241)
+
+
+state 141
+ procedure: type_specifier procedure_ident '(' type_specifier ')' '=' value.';'
+
+ ';' shift 142
+ . error
+
+
+state 142
+ procedure: type_specifier procedure_ident '(' type_specifier ')' '=' value ';'. (74)
+
+ . reduce 74 (src line 271)
+
+
+42 terminals, 42 nonterminals
+76 grammar rules, 143/16000 states
+0 shift/reduce, 0 reduce/reduce conflicts reported
+91 working sets used
+memory: parser 163/240000
+40 extra closures
+223 shift entries, 1 exceptions
+73 goto entries
+63 entries saved by goto default
+Optimizer space used: output 157/240000
+157 table entries, 0 zero
+maximum spread: 42, maximum offset: 139
diff --git a/third_party/libvirt/libvirt.go b/third_party/libvirt/libvirt.go
new file mode 100644
index 0000000..36f534d
--- /dev/null
+++ b/third_party/libvirt/libvirt.go
@@ -0,0 +1,892 @@
+// 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
+
+// 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 (
+ "bytes"
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "net"
+ "sync"
+ "syscall"
+ "time"
+
+ "github.com/projecteru2/yavirt/third_party/libvirt/internal/constants"
+ "github.com/projecteru2/yavirt/third_party/libvirt/internal/event"
+ xdr "github.com/projecteru2/yavirt/third_party/libvirt/internal/go-xdr/xdr2"
+ "github.com/projecteru2/yavirt/third_party/libvirt/socket"
+ "github.com/projecteru2/yavirt/third_party/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 {
+ // 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
+ callbacks map[int32]chan response
+
+ // event listeners
+ emux sync.RWMutex
+ events map[int32]*event.Stream
+
+ // next request serial number
+ s int32
+}
+
+// DomainEvent represents a libvirt domain event.
+type DomainEvent struct {
+ CallbackID int32
+ 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() int32 {
+ return de.CallbackID
+}
+
+// GetCallbackID returns the callback ID of a libvirt lifecycle event.
+func (m DomainEventCallbackLifecycleMsg) GetCallbackID() int32 {
+ return m.CallbackID
+}
+
+// GetCallbackID returns the callback ID.
+func (e *DomainEventCallbackRebootMsg) GetCallbackID() int32 {
+ return e.CallbackID
+}
+
+// GetCallbackID returns the callback ID.
+func (e *DomainEventCallbackRtcChangeMsg) GetCallbackID() int32 {
+ return e.CallbackID
+}
+
+// GetCallbackID returns the callback ID.
+func (e *DomainEventCallbackWatchdogMsg) GetCallbackID() int32 {
+ return e.CallbackID
+}
+
+// GetCallbackID returns the callback ID.
+func (e *DomainEventCallbackIOErrorMsg) GetCallbackID() int32 {
+ return e.CallbackID
+}
+
+// GetCallbackID returns the callback ID.
+func (e *DomainEventCallbackIOErrorReasonMsg) GetCallbackID() int32 {
+ return e.CallbackID
+}
+
+// GetCallbackID returns the callback ID.
+func (e *DomainEventCallbackGraphicsMsg) GetCallbackID() int32 {
+ return e.CallbackID
+}
+
+// GetCallbackID returns the callback ID.
+func (e *DomainEventCallbackBlockJobMsg) GetCallbackID() int32 {
+ return e.CallbackID
+}
+
+// GetCallbackID returns the callback ID.
+func (e *DomainEventCallbackDiskChangeMsg) GetCallbackID() int32 {
+ return e.CallbackID
+}
+
+// GetCallbackID returns the callback ID.
+func (e *DomainEventCallbackTrayChangeMsg) GetCallbackID() int32 {
+ return e.CallbackID
+}
+
+// GetCallbackID returns the callback ID.
+func (e *DomainEventCallbackPmwakeupMsg) GetCallbackID() int32 {
+ return e.CallbackID
+}
+
+// GetCallbackID returns the callback ID.
+func (e *DomainEventCallbackPmsuspendMsg) GetCallbackID() int32 {
+ return e.CallbackID
+}
+
+// GetCallbackID returns the callback ID.
+func (e *DomainEventCallbackBalloonChangeMsg) GetCallbackID() int32 {
+ return e.CallbackID
+}
+
+// GetCallbackID returns the callback ID.
+func (e *DomainEventCallbackPmsuspendDiskMsg) GetCallbackID() int32 {
+ return e.CallbackID
+}
+
+// GetCallbackID returns the callback ID.
+func (e *DomainEventCallbackControlErrorMsg) GetCallbackID() int32 {
+ return e.CallbackID
+}
+
+// GetCallbackID returns the callback ID.
+func (e *DomainEventCallbackDeviceRemovedMsg) GetCallbackID() int32 {
+ return e.CallbackID
+}
+
+// GetCallbackID returns the callback ID.
+func (e *DomainEventCallbackTunableMsg) GetCallbackID() int32 {
+ return e.CallbackID
+}
+
+// GetCallbackID returns the callback ID.
+func (e *DomainEventCallbackDeviceAddedMsg) GetCallbackID() int32 {
+ return e.CallbackID
+}
+
+// GetCallbackID returns the callback ID.
+func (e *DomainEventCallbackAgentLifecycleMsg) GetCallbackID() int32 {
+ return e.CallbackID
+}
+
+// GetCallbackID returns the callback ID.
+func (e *DomainEventCallbackMigrationIterationMsg) GetCallbackID() int32 {
+ return e.CallbackID
+}
+
+// GetCallbackID returns the callback ID.
+func (e *DomainEventCallbackJobCompletedMsg) GetCallbackID() int32 {
+ return e.CallbackID
+}
+
+// GetCallbackID returns the callback ID.
+func (e *DomainEventCallbackDeviceRemovalFailedMsg) GetCallbackID() int32 {
+ return e.CallbackID
+}
+
+// GetCallbackID returns the callback ID.
+func (e *DomainEventCallbackMetadataChangeMsg) GetCallbackID() int32 {
+ return e.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
+}
+
+// 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: string(uri),
+ Flags: 0,
+ }
+
+ buf, err := encode(&payload)
+ if err != nil {
+ return err
+ }
+
+ err = l.authenticate()
+ if err != nil {
+ return err
+ }
+
+ _, err = l.request(constants.ProcConnectOpen, constants.Program, buf)
+ if err != nil {
+ return err
+ }
+
+ return 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
+ }
+
+ // 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
+}
+
+// IsConnected indicates whether or not there is currently a connection to
+// libvirtd.
+func (l *Libvirt) IsConnected() bool {
+ select {
+ case <-l.Disconnected():
+ return false
+ default:
+ return true
+ }
+}
+
+// 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 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
+}
+
+// SubscribeQEMUEvents streams domain events until the provided context is
+// cancelled. 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. QEMU domain events.
+func (l *Libvirt) SubscribeQEMUEvents(ctx context.Context, dom string) (<-chan DomainEvent, error) {
+ d, err := l.lookup(dom)
+ if err != nil {
+ return nil, err
+ }
+
+ callbackID, err := l.QEMUConnectDomainMonitorEventRegister([]Domain{d}, nil, 0)
+ if err != nil {
+ return nil, err
+ }
+
+ stream := event.NewStream(constants.QEMUProgram, callbackID)
+ l.addStream(stream)
+ ch := make(chan DomainEvent)
+ go func() {
+ ctx, cancel := context.WithCancel(ctx)
+ defer cancel()
+ defer l.unsubscribeQEMUEvents(stream)
+ defer stream.Shutdown()
+ defer close(ch)
+
+ for {
+ select {
+ case ev, ok := <-stream.Recv():
+ if !ok {
+ return
+ }
+ ch <- *ev.(*DomainEvent)
+ case <-ctx.Done():
+ return
+ }
+ }
+ }()
+
+ return ch, nil
+}
+
+// unsubscribeQEMUEvents stops the flow of events from QEMU through libvirt.
+func (l *Libvirt) unsubscribeQEMUEvents(stream *event.Stream) error {
+ err := l.QEMUConnectDomainMonitorEventDeregister(stream.CallbackID)
+ l.removeStream(stream.CallbackID)
+
+ return err
+}
+
+// SubscribeEvents allows the caller to subscribe to any of the event types
+// supported by libvirt. The events will continue to be streamed until the
+// caller cancels the provided context. After canceling the context, callers
+// should wait until the channel is closed to be sure they're collected all the
+// events.
+func (l *Libvirt) SubscribeEvents(ctx context.Context, eventID DomainEventID,
+ dom OptDomain) (<-chan interface{}, error) {
+
+ callbackID, err := l.ConnectDomainEventCallbackRegisterAny(int32(eventID), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ stream := event.NewStream(constants.QEMUProgram, callbackID)
+ l.addStream(stream)
+
+ ch := make(chan interface{})
+ go func() {
+ ctx, cancel := context.WithCancel(ctx)
+ defer cancel()
+ defer l.unsubscribeEvents(stream)
+ defer stream.Shutdown()
+ defer func() { close(ch) }()
+
+ for {
+ select {
+ case ev, ok := <-stream.Recv():
+ if !ok {
+ return
+ }
+ ch <- ev
+ case <-ctx.Done():
+ return
+ }
+ }
+ }()
+
+ return ch, nil
+}
+
+// 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` 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.
+func (l *Libvirt) unsubscribeEvents(stream *event.Stream) error {
+ err := l.ConnectDomainEventCallbackDeregisterAny(stream.CallbackID)
+ l.removeStream(stream.CallbackID)
+
+ return err
+}
+
+// LifecycleEvents streams lifecycle events until the provided context is
+// cancelled. 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(ctx context.Context) (<-chan DomainEventLifecycleMsg, error) {
+ callbackID, err := l.ConnectDomainEventCallbackRegisterAny(int32(DomainEventIDLifecycle), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ stream := event.NewStream(constants.Program, callbackID)
+ l.addStream(stream)
+
+ ch := make(chan DomainEventLifecycleMsg)
+
+ go func() {
+ ctx, cancel := context.WithCancel(ctx)
+ defer cancel()
+ defer l.unsubscribeEvents(stream)
+ defer stream.Shutdown()
+ defer func() { close(ch) }()
+
+ for {
+ select {
+ case ev, ok := <-stream.Recv():
+ if !ok {
+ return
+ }
+ ch <- ev.(*DomainEventCallbackLifecycleMsg).Msg
+ case <-ctx.Done():
+ return
+ }
+ }
+ }()
+
+ return ch, 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.QEMUProcDomainMonitorCommand, constants.QEMUProgram, 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 `.
+// 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
+}
+
+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.
+ }
+
+ 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)
+}
diff --git a/third_party/libvirt/libvirt.yml b/third_party/libvirt/libvirt.yml
new file mode 100644
index 0000000..08a3e3b
--- /dev/null
+++ b/third_party/libvirt/libvirt.yml
@@ -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, ./lv_source/build/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: "^From"}
+ 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}
diff --git a/third_party/libvirt/libvirt_integration_test.go b/third_party/libvirt/libvirt_integration_test.go
new file mode 100644
index 0000000..dd8c391
--- /dev/null
+++ b/third_party/libvirt/libvirt_integration_test.go
@@ -0,0 +1,506 @@
+// 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.
+
+//go:build integration
+// +build integration
+
+package libvirt
+
+import (
+ "bytes"
+ "encoding/xml"
+ "errors"
+ "net"
+ "sync"
+ "testing"
+ "time"
+
+ "github.com/projecteru2/yavirt/third_party/libvirt/socket"
+ "github.com/projecteru2/yavirt/third_party/libvirt/socket/dialers"
+)
+
+// In order for this test to work, libvirtd must be running and listening for
+// tcp connections. Then the items (domain, secret, storage pool) in the top level testdata directory
+// need to have been previously defined. (See the "Setup test artifacts" steps
+// in .github/workflows/main.yml for how to use virsh for this.)
+//
+// TODO: The setup steps should be moved into a script that can be manually
+// called or used by ci.
+
+const (
+ testAddr = "127.0.0.1"
+ testPort = "16509"
+
+ testDomainName = "test"
+)
+
+func TestDeprecatedConnectDisconnectIntegration(t *testing.T) {
+ l := New(testConn(t))
+
+ if err := l.Connect(); err != nil {
+ t.Fatal(err)
+ }
+
+ if err := l.Disconnect(); err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestConnectDisconnectIntegration(t *testing.T) {
+ l := NewWithDialer(testDialer(t))
+
+ if err := l.Connect(); err != nil {
+ t.Fatal(err)
+ }
+
+ if err := l.Disconnect(); err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestConnectToURIIntegration(t *testing.T) {
+ l := NewWithDialer(testDialer(t))
+
+ if err := l.ConnectToURI(TestDefault); err != nil {
+ t.Error(err)
+ }
+ defer l.Disconnect()
+}
+
+func checkCapabilities(t *testing.T, l *Libvirt) error {
+ t.Helper()
+
+ resp, err := l.Capabilities()
+ if err != nil {
+ return err
+ }
+
+ // verify UUID exists within returned XML
+ var caps struct {
+ Host struct {
+ UUID string `xml:"uuid"`
+ } `xml:"host"`
+ }
+
+ if err := xml.Unmarshal(resp, &caps); err != nil {
+ return err
+ }
+
+ if caps.Host.UUID == "" {
+ return errors.New("expected capabilities to contain a UUID")
+ }
+
+ return nil
+}
+
+func TestDeprecatedCapabilities(t *testing.T) {
+ l := New(testConn(t))
+
+ if err := l.Connect(); err != nil {
+ t.Fatal(err)
+ }
+ defer l.Disconnect()
+
+ if err := checkCapabilities(t, l); err != nil {
+ t.Errorf("check capabilities error: %v", err)
+ }
+}
+
+func TestCapabilities(t *testing.T) {
+ l := NewWithDialer(testDialer(t))
+
+ if err := l.Connect(); err != nil {
+ t.Fatal(err)
+ }
+ defer l.Disconnect()
+
+ if err := checkCapabilities(t, l); err != nil {
+ t.Errorf("check capabilities error: %v", err)
+ }
+}
+
+func TestUsingNeverConnected(t *testing.T) {
+ l := NewWithDialer(testDialer(t))
+
+ // should fail because Connect was never called
+ _, err := l.DomainLookupByName(testDomainName)
+ if err == nil {
+ t.Fatal("using a never connected libvirt should fail")
+ }
+}
+
+func TestUsingAfterDisconnect(t *testing.T) {
+ l := NewWithDialer(testDialer(t))
+
+ if err := l.Connect(); err != nil {
+ t.Fatal(err)
+ }
+
+ if err := l.Disconnect(); err != nil {
+ t.Fatal(err)
+ }
+
+ // should fail because Disconnect was already called
+ _, err := l.DomainLookupByName(testDomainName)
+ if err == nil {
+ t.Fatal("using a disconnected libvirt should fail")
+ }
+}
+
+func TestLostConnection(t *testing.T) {
+ // In order to be able to close the connection external to libvirt,
+ // we use an already established dialer.
+ conn := testConn(t)
+ l := NewWithDialer(dialers.NewAlreadyConnected(conn))
+
+ if err := l.Connect(); err != nil {
+ t.Fatal(err)
+ }
+
+ // forcibly close the connection out from under the Libvirt object
+ conn.Close()
+
+ <-l.Disconnected()
+
+ // this should return an error about the connection being lost
+ _, err := l.DomainLookupByName(testDomainName)
+ if err == nil {
+ t.Error("using a libvirt with a lost connection should fail")
+ }
+
+ // Disconnect should still return success when the connection was already
+ // lost.
+ if err := l.Disconnect(); err != nil {
+ t.Fatalf("disconnect should still succeed after connection is lost"+
+ ": %v", err)
+ }
+
+}
+
+func TestMultipleConnections(t *testing.T) {
+ l := NewWithDialer(testDialer(t))
+
+ if err := l.Connect(); err != nil {
+ t.Fatal(err)
+ }
+ if err := l.Disconnect(); err != nil {
+ t.Fatal(err)
+ }
+
+ // Now connect again and make sure stuff still works
+ if err := l.Connect(); err != nil {
+ t.Fatal(err)
+ }
+ defer l.Disconnect()
+
+ if err := checkCapabilities(t, l); err != nil {
+ t.Errorf("failed to use reconnected libvirt: %v", err)
+ }
+}
+
+func TestSecretsIntegration(t *testing.T) {
+ l := NewWithDialer(testDialer(t))
+
+ if err := l.Connect(); err != nil {
+ t.Fatal(err)
+ }
+ defer l.Disconnect()
+
+ secrets, err := l.Secrets()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ wantLen := 1
+ gotLen := len(secrets)
+ if gotLen != wantLen {
+ t.Fatalf("expected %d secrets, got %d", wantLen, gotLen)
+ }
+
+ s := secrets[0]
+
+ wantType := SecretUsageTypeVolume
+ if s.UsageType != int32(wantType) {
+ t.Errorf("expected usage type: %d, got %d", wantType, s.UsageType)
+ }
+
+ wantID := "/tmp"
+ if s.UsageID != wantID {
+ t.Errorf("expected usage id: %q, got %q", wantID, s.UsageID)
+ }
+
+ // 19fdc2f2-fa64-46f3-bacf-42a8aafca6dd
+ wantUUID := [UUIDBuflen]byte{
+ 0x19, 0xfd, 0xc2, 0xf2, 0xfa, 0x64, 0x46, 0xf3,
+ 0xba, 0xcf, 0x42, 0xa8, 0xaa, 0xfc, 0xa6, 0xdd,
+ }
+ if s.UUID != wantUUID {
+ t.Errorf("expected UUID %q, got %q", wantUUID, s.UUID)
+ }
+}
+
+func TestStoragePoolIntegration(t *testing.T) {
+ l := NewWithDialer(testDialer(t))
+
+ if err := l.Connect(); err != nil {
+ t.Fatal(err)
+ }
+ defer l.Disconnect()
+
+ wantName := "test"
+ pool, err := l.StoragePool(wantName)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ gotName := pool.Name
+ if gotName != wantName {
+ t.Errorf("expected name %q, got %q", wantName, gotName)
+ }
+}
+
+func TestStoragePoolInvalidIntegration(t *testing.T) {
+ l := NewWithDialer(testDialer(t))
+
+ if err := l.Connect(); err != nil {
+ t.Fatal(err)
+ }
+ defer l.Disconnect()
+
+ _, err := l.StoragePool("test-does-not-exist")
+ if err == nil {
+ t.Errorf("expected non-existent storage pool return error")
+ }
+}
+
+func TestStoragePoolsIntegration(t *testing.T) {
+ l := NewWithDialer(testDialer(t))
+
+ if err := l.Connect(); err != nil {
+ t.Fatal(err)
+ }
+ defer l.Disconnect()
+
+ pools, err := l.StoragePools(ConnectListStoragePoolsActive)
+ if err != nil {
+ t.Error(err)
+ }
+
+ wantLen := 1
+ gotLen := len(pools)
+ if gotLen != wantLen {
+ t.Fatalf("expected %d storage pool, got %d", wantLen, gotLen)
+ }
+
+ wantName := "test"
+ gotName := pools[0].Name
+ if gotName != wantName {
+ t.Errorf("expected name %q, got %q", wantName, gotName)
+ }
+}
+
+func TestStoragePoolsAutostartIntegration(t *testing.T) {
+ l := NewWithDialer(testDialer(t))
+
+ if err := l.Connect(); err != nil {
+ t.Fatal(err)
+ }
+ defer l.Disconnect()
+
+ pools, err := l.StoragePools(ConnectListStoragePoolsAutostart)
+ if err != nil {
+ t.Error(err)
+ }
+
+ wantLen := 0
+ gotLen := len(pools)
+ if gotLen != wantLen {
+ t.Errorf("expected %d storage pool, got %d", wantLen, gotLen)
+ }
+}
+
+func TestStoragePoolRefreshIntegration(t *testing.T) {
+ l := NewWithDialer(testDialer(t))
+
+ if err := l.Connect(); err != nil {
+ t.Fatal(err)
+ }
+ defer l.Disconnect()
+
+ pool, err := l.StoragePool("test")
+ if err != nil {
+ t.Error(err)
+ }
+
+ err = l.StoragePoolRefresh(pool, 0)
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func TestStoragePoolRefreshInvalidIntegration(t *testing.T) {
+ l := NewWithDialer(testDialer(t))
+
+ if err := l.Connect(); err != nil {
+ t.Fatal(err)
+ }
+ defer l.Disconnect()
+
+ pool, err := l.StoragePool("test-does-not-exist")
+ if err == nil {
+ t.Error(err)
+ }
+
+ err = l.StoragePoolRefresh(pool, 0)
+ if err == nil {
+ t.Error("expected non-existent storage pool to fail refresh")
+ }
+}
+
+func TestXMLIntegration(t *testing.T) {
+ l := NewWithDialer(testDialer(t))
+
+ if err := l.Connect(); err != nil {
+ t.Error(err)
+ }
+ defer l.Disconnect()
+
+ var flags DomainXMLFlags
+ data, err := l.XML("test", flags)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var v interface{}
+ if err := xml.Unmarshal(data, &v); err != nil {
+ t.Error(err)
+ }
+}
+
+func TestVolumeUploadDownloadIntegration(t *testing.T) {
+ testdata := []byte("Hello, world!")
+ l := NewWithDialer(testDialer(t))
+
+ if err := l.Connect(); err != nil {
+ t.Error(err)
+ }
+ defer l.Disconnect()
+
+ pool, err := l.StoragePool("test")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var volObj struct {
+ XMLName xml.Name `xml:"volume"`
+ Name string `xml:"name"`
+ Capacity struct {
+ Value uint64 `xml:",chardata"`
+ } `xml:"capacity"`
+ Target struct {
+ Format struct {
+ Type string `xml:"type,attr"`
+ } `xml:"format"`
+ } `xml:"target"`
+ }
+ volObj.Name = "testvol"
+ volObj.Capacity.Value = uint64(len(testdata))
+ volObj.Target.Format.Type = "raw"
+ xmlVol, err := xml.Marshal(volObj)
+ if err != nil {
+ t.Fatal(err)
+ }
+ vol, err := l.StorageVolCreateXML(pool, string(xmlVol), 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer l.StorageVolDelete(vol, 0)
+ err = l.StorageVolUpload(vol, bytes.NewBuffer(testdata), 0, 0, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ var buf bytes.Buffer
+ err = l.StorageVolDownload(vol, &buf, 0, 0, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if bytes.Compare(testdata, buf.Bytes()) != 0 {
+ t.Fatal("download not what we uploaded")
+ }
+}
+
+// verify we're able to concurrently communicate with libvirtd.
+// see: https://github.com/projecteru2/yavirt/third_party/libvirt/pull/52
+func Test_concurrentWrite(t *testing.T) {
+ l := NewWithDialer(testDialer(t))
+
+ if err := l.Connect(); err != nil {
+ t.Error(err)
+ }
+ defer l.Disconnect()
+
+ count := 10
+ wg := sync.WaitGroup{}
+ wg.Add(count)
+
+ start := make(chan struct{})
+ done := make(chan struct{})
+
+ go func() {
+ wg.Wait()
+ close(done)
+ }()
+
+ for i := 0; i < count; i++ {
+ go func() {
+ defer wg.Done()
+ <-start
+
+ _, err := l.Domains()
+ if err != nil {
+ t.Fatal(err)
+ }
+ }()
+ }
+
+ close(start)
+
+ select {
+ case <-done:
+ case <-time.After(10 * time.Second):
+ t.Fatal("timed out waiting for execution to complete")
+ }
+}
+
+func testDialer(t *testing.T) socket.Dialer {
+ t.Helper()
+
+ return dialers.NewRemote(
+ testAddr,
+ dialers.UsePort(testPort),
+ dialers.WithRemoteTimeout(time.Second*2),
+ )
+}
+
+func testConn(t *testing.T) net.Conn {
+ t.Helper()
+
+ dialer := testDialer(t)
+ conn, err := dialer.Dial()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ return conn
+}
diff --git a/third_party/libvirt/libvirt_patch.go b/third_party/libvirt/libvirt_patch.go
new file mode 100644
index 0000000..c5134fb
--- /dev/null
+++ b/third_party/libvirt/libvirt_patch.go
@@ -0,0 +1,30 @@
+package libvirt
+
+import (
+ "io"
+
+ "github.com/projecteru2/yavirt/third_party/libvirt/internal/constants"
+)
+
+// OpenConsole is the go wrapper for REMOTE_PROC_DOMAIN_OPEN_CONSOLE.
+func (l *Libvirt) OpenConsole(Dom Domain, DevName OptString, inStream io.Reader, outStream io.Writer, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainOpenConsoleArgs{
+ Dom: Dom,
+ DevName: DevName,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(201, constants.Program, buf, inStream, outStream)
+ if err != nil {
+ return
+ }
+
+ return
+}
diff --git a/third_party/libvirt/libvirt_test.go b/third_party/libvirt/libvirt_test.go
new file mode 100644
index 0000000..ab762ac
--- /dev/null
+++ b/third_party/libvirt/libvirt_test.go
@@ -0,0 +1,861 @@
+// 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 (
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "testing"
+ "time"
+
+ "github.com/projecteru2/yavirt/third_party/libvirt/libvirttest"
+)
+
+func TestDeprecatedConnectAndDisconnect(t *testing.T) {
+ dialer := libvirttest.New()
+ conn, err := dialer.Dial()
+ if err != nil {
+ t.Fatalf("failed to establish test connection: %v", err)
+ }
+ l := New(conn)
+
+ err = l.Connect()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = l.Disconnect()
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func TestConnectAndDisconnect(t *testing.T) {
+ dialer := libvirttest.New()
+ l := NewWithDialer(dialer)
+
+ err := l.Connect()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = l.Disconnect()
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func TestLibvirt_ConnectToURI(t *testing.T) {
+ type args struct {
+ uri ConnectURI
+ }
+ tests := []struct {
+ name string
+ args args
+ wantErr bool
+ }{
+ {
+ name: "connect to test:///default socket",
+ args: args{
+ uri: TestDefault,
+ },
+ wantErr: false,
+ },
+ {
+ name: "connect to qemu:///session socket",
+ args: args{
+ uri: QEMUSession,
+ },
+ wantErr: false,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ dialer := libvirttest.New()
+ libvirtConn := NewWithDialer(dialer)
+
+ if err := libvirtConn.ConnectToURI(tt.args.uri); (err != nil) != tt.wantErr {
+ t.Errorf("ConnectToURI() error = %v, wantErr %v", err, tt.wantErr)
+ }
+ libvirtConn.Disconnect()
+ })
+ }
+}
+
+func TestDisconnectCleanup(t *testing.T) {
+ dialer := libvirttest.New()
+ l := NewWithDialer(dialer)
+
+ err := l.Connect()
+ if err != nil {
+ t.Fatalf("connect failed: %v", err)
+ }
+
+ // register a callback
+ ch := make(chan response)
+ l.register(1, ch)
+
+ err = l.Disconnect()
+ if err != nil {
+ t.Errorf("disconnect failed: %v", err)
+ }
+
+ // now make sure that the Disconnect deregistered the callback
+ // do it via a select just to avoid the 10 minute unit test timeout on
+ // failure
+ select {
+ case <-ch:
+ t.Log("callback channel appropriately closed")
+ case <-time.After(10 * time.Second):
+ t.Errorf("callback channel not closed")
+ }
+}
+
+func TestLostConnectionCleanup(t *testing.T) {
+ dialer := libvirttest.New()
+ l := NewWithDialer(dialer)
+
+ err := l.Connect()
+ if err != nil {
+ t.Fatalf("connect failed: %v", err)
+ }
+
+ // register a callback
+ ch := make(chan response)
+ l.register(1, ch)
+
+ // forcibly just close the fake libvirt tester side of the pipe to lose
+ // the connection.
+ // This should be detected and cleaned up without having to call Disconnect.
+ dialer.Test.Close()
+
+ // now make sure that deregistered the callback
+ // do it via a select just to avoid the 10 minute unit test timeout on
+ // failure
+ select {
+ case <-ch:
+ t.Log("callback channel appropriately closed")
+ case <-time.After(10 * time.Second):
+ t.Fatalf("callback channel not closed")
+ }
+}
+
+func TestMonitorDisconnect(t *testing.T) {
+ dialer := libvirttest.New()
+ lv := NewWithDialer(dialer)
+
+ // Haven't connected yet.
+ select {
+ case <-lv.Disconnected():
+ default:
+ t.Fatalf("chan is open but should be closed")
+ }
+
+ err := lv.Connect()
+ if err != nil {
+ t.Fatalf("connect failed: %v", err)
+ }
+
+ select {
+ case <-lv.Disconnected():
+ t.Fatalf("chan should be open but is closed")
+ default:
+ }
+
+ err = lv.Disconnect()
+ if err != nil {
+ t.Fatalf("disconnect failed: %v", err)
+ }
+
+ select {
+ case <-lv.Disconnected():
+ default:
+ t.Fatalf("chan still open after Disconnect")
+ }
+}
+
+func TestMigrate(t *testing.T) {
+ dialer := libvirttest.New()
+ l := NewWithDialer(dialer)
+
+ err := l.Connect()
+ if err != nil {
+ t.Fatalf("connect failed: %v", err)
+ }
+ defer l.Disconnect()
+
+ flags := MigrateLive |
+ MigratePeer2peer |
+ MigratePersistDest |
+ MigrateChangeProtection |
+ MigrateAbortOnError |
+ MigrateAutoConverge |
+ MigrateNonSharedDisk
+
+ dom, err := l.DomainLookupByName("test")
+ if err != nil {
+ t.Fatalf("failed to lookup domain: %v", err)
+ }
+ dconnuri := []string{"qemu+tcp://foo/system"}
+ if _, err := l.DomainMigratePerform3Params(dom, dconnuri,
+ []TypedParam{}, []byte{}, flags); err != nil {
+ t.Fatalf("unexpected live migration error: %v", err)
+ }
+}
+
+func TestMigrateSetMaxSpeed(t *testing.T) {
+ dialer := libvirttest.New()
+ l := NewWithDialer(dialer)
+
+ err := l.Connect()
+ if err != nil {
+ t.Fatalf("connect failed: %v", err)
+ }
+ defer l.Disconnect()
+
+ dom, err := l.DomainLookupByName("test")
+ if err != nil {
+ t.Fatalf("failed to lookup domain: %v", err)
+ }
+
+ if err := l.DomainMigrateSetMaxSpeed(dom, 100, 0); err != nil {
+ t.Fatalf("unexpected error setting max speed for migrate: %v", err)
+ }
+}
+
+func TestDomainsWithDeprecatedNew(t *testing.T) {
+ dialer := libvirttest.New()
+ conn, err := dialer.Dial()
+ if err != nil {
+ t.Fatalf("failed to dial test connection: %v", err)
+ }
+ l := New(conn)
+
+ err = l.Connect()
+ if err != nil {
+ t.Fatalf("connect failed: %v", err)
+ }
+ defer l.Disconnect()
+
+ domains, err := l.Domains()
+ if err != nil {
+ t.Error(err)
+ }
+
+ wantLen := 2
+ gotLen := len(domains)
+ if gotLen != wantLen {
+ t.Errorf("expected %d domains to be returned, got %d", wantLen, gotLen)
+ }
+
+ for i, d := range domains {
+ wantID := i + 1
+ if d.ID != int32(wantID) {
+ t.Errorf("expected domain ID %q, got %q", wantID, d.ID)
+ }
+
+ wantName := fmt.Sprintf("aaaaaaa-%d", i+1)
+ if d.Name != wantName {
+ t.Errorf("expected domain name %q, got %q", wantName, d.Name)
+ }
+ }
+}
+
+func TestDomains(t *testing.T) {
+ dialer := libvirttest.New()
+ l := NewWithDialer(dialer)
+
+ err := l.Connect()
+ if err != nil {
+ t.Fatalf("connect failed: %v", err)
+ }
+ defer l.Disconnect()
+
+ domains, err := l.Domains()
+ if err != nil {
+ t.Error(err)
+ }
+
+ wantLen := 2
+ gotLen := len(domains)
+ if gotLen != wantLen {
+ t.Errorf("expected %d domains to be returned, got %d", wantLen, gotLen)
+ }
+
+ for i, d := range domains {
+ wantID := i + 1
+ if d.ID != int32(wantID) {
+ t.Errorf("expected domain ID %q, got %q", wantID, d.ID)
+ }
+
+ wantName := fmt.Sprintf("aaaaaaa-%d", i+1)
+ if d.Name != wantName {
+ t.Errorf("expected domain name %q, got %q", wantName, d.Name)
+ }
+ }
+}
+
+func TestDomainState(t *testing.T) {
+ dialer := libvirttest.New()
+ l := NewWithDialer(dialer)
+
+ err := l.Connect()
+ if err != nil {
+ t.Fatalf("connect failed: %v", err)
+ }
+ defer l.Disconnect()
+
+ wantState := DomainState(DomainRunning)
+ gotState, err := l.DomainState("test")
+ if err != nil {
+ t.Error(err)
+ }
+
+ if gotState != wantState {
+ t.Errorf("expected domain state %d, got %d", wantState, gotState)
+ }
+}
+
+func TestDomainMemoryStats(t *testing.T) {
+ dialer := libvirttest.New()
+ l := NewWithDialer(dialer)
+
+ err := l.Connect()
+ if err != nil {
+ t.Fatalf("connect failed: %v", err)
+ }
+ defer l.Disconnect()
+
+ wantDomainMemoryStats := []DomainMemoryStat{
+ {
+ Tag: 6,
+ Val: 1048576,
+ },
+ {
+ Tag: 7,
+ Val: 91272,
+ },
+ }
+
+ d, err := l.lookup("test")
+ if err != nil {
+ t.Error(err)
+ }
+
+ gotDomainMemoryStats, err := l.DomainMemoryStats(d, 8, 0)
+ if err != nil {
+ t.Error(err)
+ }
+
+ if len(gotDomainMemoryStats) == 0 {
+ t.Error("No memory stats returned!")
+ }
+
+ for i := range wantDomainMemoryStats {
+ if wantDomainMemoryStats[i] != gotDomainMemoryStats[i] {
+ t.Errorf("expected domain memory stat %v, got %v", wantDomainMemoryStats[i], gotDomainMemoryStats[i])
+ }
+ }
+}
+
+func TestEvents(t *testing.T) {
+ dialer := libvirttest.New()
+ l := NewWithDialer(dialer)
+
+ err := l.Connect()
+ if err != nil {
+ t.Fatalf("connect failed: %v", err)
+ }
+ defer l.Disconnect()
+
+ done := make(chan error)
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ stream, err := l.SubscribeQEMUEvents(ctx, "test")
+ if err != nil {
+ t.Error(err)
+ }
+
+ go func() {
+ var e DomainEvent
+
+ select {
+ case e = <-stream:
+ case <-time.After(time.Second * 5):
+ done <- errors.New("expected event, received timeout")
+ }
+
+ result := struct {
+ Device string `json:"device"`
+ Len int `json:"len"`
+ Offset int `json:"offset"`
+ Speed int `json:"speed"`
+ Type string `json:"type"`
+ }{}
+
+ if err := json.Unmarshal(e.Details, &result); err != nil {
+ t.Error(err)
+ }
+
+ expected := "drive-ide0-0-0"
+ if result.Device != expected {
+ t.Errorf("expected device %q, got %q", expected, result.Device)
+ }
+
+ done <- nil
+ }()
+
+ // send an event to the listener goroutine
+ dialer.Test.Write(append(testEventHeader, testEvent...))
+
+ // wait for completion
+ if err := <-done; err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestRun(t *testing.T) {
+ dialer := libvirttest.New()
+ l := NewWithDialer(dialer)
+
+ err := l.Connect()
+ if err != nil {
+ t.Fatalf("connect failed: %v", err)
+ }
+ defer l.Disconnect()
+
+ res, err := l.Run("test", []byte(`{"query-version"}`))
+ if err != nil {
+ t.Error(err)
+ }
+
+ type version struct {
+ Return struct {
+ Package string `json:"package"`
+ QEMU struct {
+ Major int `json:"major"`
+ Micro int `json:"micro"`
+ Minor int `json:"minor"`
+ } `json:"qemu"`
+ } `json:"return"`
+ }
+
+ var v version
+ err = json.Unmarshal(res, &v)
+ if err != nil {
+ t.Error(err)
+ }
+
+ expected := 2
+ if v.Return.QEMU.Major != expected {
+ t.Errorf("expected qemu major version %d, got %d", expected, v.Return.QEMU.Major)
+ }
+}
+
+func TestRunFail(t *testing.T) {
+ dialer := libvirttest.New()
+ l := NewWithDialer(dialer)
+ dialer.Fail = true
+
+ err := l.Connect()
+ if err != nil {
+ t.Fatalf("connect failed: %v", err)
+ }
+ defer l.Disconnect()
+
+ _, err = l.Run("test", []byte(`{"drive-foo"}`))
+ if err == nil {
+ t.Error("expected qemu error")
+ }
+}
+
+func TestSecrets(t *testing.T) {
+ dialer := libvirttest.New()
+ l := NewWithDialer(dialer)
+
+ err := l.Connect()
+ if err != nil {
+ t.Fatalf("connect failed: %v", err)
+ }
+ defer l.Disconnect()
+
+ secrets, err := l.Secrets()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ wantLen := 1
+ gotLen := len(secrets)
+ if gotLen != wantLen {
+ t.Fatalf("expected %d secrets, got %d", wantLen, gotLen)
+ }
+
+ s := secrets[0]
+ wantType := int32(SecretUsageTypeVolume)
+ if s.UsageType != wantType {
+ t.Errorf("expected usage type %d, got %d", wantType, s.UsageType)
+ }
+
+ wantID := "/tmp"
+ if s.UsageID != wantID {
+ t.Errorf("expected usage id %q, got %q", wantID, s.UsageID)
+ }
+
+ // 19fdc2f2-fa64-46f3-bacf-42a8aafca6dd
+ wantUUID := [UUIDBuflen]byte{
+ 0x19, 0xfd, 0xc2, 0xf2, 0xfa, 0x64, 0x46, 0xf3,
+ 0xba, 0xcf, 0x42, 0xa8, 0xaa, 0xfc, 0xa6, 0xdd,
+ }
+ if s.UUID != wantUUID {
+ t.Errorf("expected UUID %q, got %q", wantUUID, s.UUID)
+ }
+}
+
+func TestStoragePool(t *testing.T) {
+ dialer := libvirttest.New()
+ l := NewWithDialer(dialer)
+
+ err := l.Connect()
+ if err != nil {
+ t.Fatalf("connect failed: %v", err)
+ }
+ defer l.Disconnect()
+
+ wantName := "default"
+ pool, err := l.StoragePool(wantName)
+ if err != nil {
+ t.Error(err)
+ }
+
+ gotName := pool.Name
+ if gotName != wantName {
+ t.Errorf("expected name %q, got %q", wantName, gotName)
+ }
+
+ // bb30a11c-0846-4827-8bba-3e6b5cf1b65f
+ wantUUID := [UUIDBuflen]byte{
+ 0xbb, 0x30, 0xa1, 0x1c, 0x08, 0x46, 0x48, 0x27,
+ 0x8b, 0xba, 0x3e, 0x6b, 0x5c, 0xf1, 0xb6, 0x5f,
+ }
+ gotUUID := pool.UUID
+ if gotUUID != wantUUID {
+ t.Errorf("expected UUID %q, got %q", wantUUID, gotUUID)
+ }
+}
+
+func TestStoragePools(t *testing.T) {
+ dialer := libvirttest.New()
+ l := NewWithDialer(dialer)
+
+ err := l.Connect()
+ if err != nil {
+ t.Fatalf("connect failed: %v", err)
+ }
+ defer l.Disconnect()
+
+ pools, err := l.StoragePools(ConnectListStoragePoolsTransient)
+ if err != nil {
+ t.Error(err)
+ }
+
+ wantLen := 1
+ gotLen := len(pools)
+ if gotLen != wantLen {
+ t.Errorf("expected %d storage pool, got %d", wantLen, gotLen)
+ }
+
+ wantName := "default"
+ gotName := pools[0].Name
+ if gotName != wantName {
+ t.Errorf("expected name %q, got %q", wantName, gotName)
+ }
+
+ // bb30a11c-0846-4827-8bba-3e6b5cf1b65f
+ wantUUID := [UUIDBuflen]byte{
+ 0xbb, 0x30, 0xa1, 0x1c, 0x08, 0x46, 0x48, 0x27,
+ 0x8b, 0xba, 0x3e, 0x6b, 0x5c, 0xf1, 0xb6, 0x5f,
+ }
+ gotUUID := pools[0].UUID
+ if gotUUID != wantUUID {
+ t.Errorf("expected UUID %q, got %q", wantUUID, gotUUID)
+ }
+}
+
+func TestStoragePoolRefresh(t *testing.T) {
+ dialer := libvirttest.New()
+ l := NewWithDialer(dialer)
+
+ err := l.Connect()
+ if err != nil {
+ t.Fatalf("connect failed: %v", err)
+ }
+ defer l.Disconnect()
+
+ pool, err := l.StoragePool("default")
+ if err != nil {
+ t.Error(err)
+ }
+ err = l.StoragePoolRefresh(pool, 0)
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func TestUndefine(t *testing.T) {
+ dialer := libvirttest.New()
+ l := NewWithDialer(dialer)
+
+ err := l.Connect()
+ if err != nil {
+ t.Fatalf("connect failed: %v", err)
+ }
+ defer l.Disconnect()
+
+ var flags DomainUndefineFlagsValues
+ if err := l.Undefine("test", flags); err != nil {
+ t.Fatalf("unexpected undefine error: %v", err)
+ }
+}
+
+func TestDestroy(t *testing.T) {
+ dialer := libvirttest.New()
+ l := NewWithDialer(dialer)
+
+ err := l.Connect()
+ if err != nil {
+ t.Fatalf("connect failed: %v", err)
+ }
+ defer l.Disconnect()
+
+ var flags DomainDestroyFlagsValues
+ if err := l.Destroy("test", flags); err != nil {
+ t.Fatalf("unexpected destroy error: %v", err)
+ }
+}
+
+func TestVersion(t *testing.T) {
+ dialer := libvirttest.New()
+ l := NewWithDialer(dialer)
+
+ err := l.Connect()
+ if err != nil {
+ t.Fatalf("connect failed: %v", err)
+ }
+ defer l.Disconnect()
+
+ version, err := l.Version()
+ if err != nil {
+ t.Error(err)
+ }
+
+ expected := "1.3.4"
+ if version != expected {
+ t.Errorf("expected version %q, got %q", expected, version)
+ }
+}
+
+func TestDefineXML(t *testing.T) {
+ dialer := libvirttest.New()
+ l := NewWithDialer(dialer)
+
+ err := l.Connect()
+ if err != nil {
+ t.Fatalf("connect failed: %v", err)
+ }
+ defer l.Disconnect()
+
+ var flags DomainDefineFlags
+ var buf []byte
+ if err := l.DefineXML(buf, flags); err != nil {
+ t.Fatalf("unexpected define error: %v", err)
+ }
+}
+
+func TestDomainCreateWithFlags(t *testing.T) {
+ dialer := libvirttest.New()
+ l := NewWithDialer(dialer)
+
+ err := l.Connect()
+ if err != nil {
+ t.Fatalf("connect failed: %v", err)
+ }
+ defer l.Disconnect()
+
+ d, err := l.lookup("test")
+ if err != nil {
+ t.Fatalf("failed to lookup domain: %v", err)
+ }
+ var flags uint32
+ if _, err := l.DomainCreateWithFlags(d, flags); err != nil {
+ t.Fatalf("unexpected create error: %v", err)
+ }
+}
+
+func TestShutdown(t *testing.T) {
+ dialer := libvirttest.New()
+ l := NewWithDialer(dialer)
+
+ err := l.Connect()
+ if err != nil {
+ t.Fatalf("connect failed: %v", err)
+ }
+ defer l.Disconnect()
+
+ var flags DomainShutdownFlagValues
+ if err := l.Shutdown("test", flags); err != nil {
+ t.Fatalf("unexpected shutdown error: %v", err)
+ }
+}
+
+func TestReboot(t *testing.T) {
+ dialer := libvirttest.New()
+ l := NewWithDialer(dialer)
+
+ err := l.Connect()
+ if err != nil {
+ t.Fatalf("connect failed: %v", err)
+ }
+ defer l.Disconnect()
+
+ var flags DomainRebootFlagValues
+ if err := l.Reboot("test", flags); err != nil {
+ t.Fatalf("unexpected reboot error: %v", err)
+ }
+}
+
+func TestReset(t *testing.T) {
+ dialer := libvirttest.New()
+ l := NewWithDialer(dialer)
+
+ err := l.Connect()
+ if err != nil {
+ t.Fatalf("connect failed: %v", err)
+ }
+ defer l.Disconnect()
+
+ if err := l.Reset("test"); err != nil {
+ t.Fatalf("unexpected reset error: %v", err)
+ }
+}
+
+func TestSetBlockIOTune(t *testing.T) {
+ dialer := libvirttest.New()
+ l := NewWithDialer(dialer)
+
+ err := l.Connect()
+ if err != nil {
+ t.Fatalf("connect failed: %v", err)
+ }
+ defer l.Disconnect()
+
+ if err := l.SetBlockIOTune("test", "vda", BlockLimit{"write_bytes_sec", 5000000}); err != nil {
+ t.Fatalf("unexpected SetBlockIOTune error: %v", err)
+ }
+}
+
+func TestGetBlockIOTune(t *testing.T) {
+ dialer := libvirttest.New()
+ l := NewWithDialer(dialer)
+
+ err := l.Connect()
+ if err != nil {
+ t.Fatalf("connect failed: %v", err)
+ }
+ defer l.Disconnect()
+
+ limits, err := l.GetBlockIOTune("do-test", "vda")
+ if err != nil {
+ t.Fatalf("unexpected GetBlockIOTune error: %v", err)
+ }
+
+ lim := BlockLimit{"write_bytes_sec", 500000}
+ if limits[2] != lim {
+ t.Fatalf("unexpected result in limits list: %v", limits[2])
+ }
+}
+
+// ConnectGetAllDomainStats is a good test, since its return values include an
+// array of TypedParams embedded in a struct.
+func TestConnectGetAllDomainStats(t *testing.T) {
+ dialer := libvirttest.New()
+ l := NewWithDialer(dialer)
+
+ err := l.Connect()
+ if err != nil {
+ t.Fatalf("connect failed: %v", err)
+ }
+ defer l.Disconnect()
+
+ doms, _, err := l.ConnectListAllDomains(1, 0)
+ if err != nil {
+ t.Fatalf("unexpected error listing all domains")
+ }
+
+ stats, err := l.ConnectGetAllDomainStats(doms, uint32(DomainStatsState), 0)
+ if err != nil {
+ t.Fatalf("unexpected error getting domain stats")
+ }
+
+ // Verify that the stats records we got back look like this:
+ // [{state.state {1 1}} {state.reason {1 2}}]
+ // [{state.state {1 1}} {state.reason {1 1}}]
+ if len(stats) != 2 {
+ t.Fatalf("expected 2 domain stats records, got %d", len(stats))
+ }
+
+ tp1 := NewTypedParamValueInt(1)
+ if stats[1].Params[0].Field != "state.state" {
+ t.Fatalf("unexpected domain statistic %v", stats[1].Params[0].Field)
+ }
+ if stats[1].Params[1].Field != "state.reason" {
+ t.Fatalf("unexpected domain statistic %v", stats[1].Params[1].Field)
+ }
+ if stats[1].Params[0].Value != *tp1 {
+ t.Fatalf("unexpected typed param value %v", stats[1].Params[0].Value)
+ }
+ if stats[1].Params[1].Value != *tp1 {
+ t.Fatalf("unexpected typed param value %v", stats[1].Params[1].Value)
+ }
+}
+
+func TestIsConnected(t *testing.T) {
+ dialer := libvirttest.New()
+ l := NewWithDialer(dialer)
+
+ if l.IsConnected() {
+ t.Error("expected IsConnected == false, got true")
+ }
+
+ err := l.Connect()
+ if err != nil {
+ t.Error(err)
+ }
+
+ if !l.IsConnected() {
+ t.Error("expected IsConnected == true, got false")
+ }
+
+ err = l.Disconnect()
+ if err != nil {
+ t.Error(err)
+ }
+
+ if l.IsConnected() {
+ t.Error("expected IsConnected == false, got true")
+ }
+}
diff --git a/third_party/libvirt/libvirttest/libvirt.go b/third_party/libvirt/libvirttest/libvirt.go
new file mode 100644
index 0000000..4375359
--- /dev/null
+++ b/third_party/libvirt/libvirttest/libvirt.go
@@ -0,0 +1,724 @@
+// Copyright 2022 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 libvirttest provides a mock libvirt server for RPC testing.
+package libvirttest
+
+import (
+ "bytes"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "net"
+ "os"
+ "sync/atomic"
+
+ "github.com/projecteru2/yavirt/third_party/libvirt/internal/constants"
+)
+
+var testDomainResponse = []byte{
+ 0x00, 0x00, 0x00, 0x38, // length
+ 0x20, 0x00, 0x80, 0x86, // program
+ 0x00, 0x00, 0x00, 0x01, // version
+ 0x00, 0x00, 0x00, 0x17, // procedure
+ 0x00, 0x00, 0x00, 0x01, // type
+ 0x00, 0x00, 0x00, 0x00, // serial
+ 0x00, 0x00, 0x00, 0x00, // status
+
+ // domain name ("test")
+ 0x00, 0x00, 0x00, 0x04, 0x74, 0x65, 0x73, 0x74,
+
+ // uuid (dc229f87d4de47198cfd2e21c6105b01)
+ 0xdc, 0x22, 0x9f, 0x87, 0xd4, 0xde, 0x47, 0x19,
+ 0x8c, 0xfd, 0x2e, 0x21, 0xc6, 0x10, 0x5b, 0x01,
+
+ // domain id (14)
+ 0x00, 0x00, 0x00, 0x0e,
+}
+
+var testRegisterEvent = []byte{
+ 0x00, 0x00, 0x00, 0x20, // length
+ 0x20, 0x00, 0x80, 0x87, // program
+ 0x00, 0x00, 0x00, 0x01, // version
+ 0x00, 0x00, 0x00, 0x04, // procedure
+ 0x00, 0x00, 0x00, 0x01, // type
+ 0x00, 0x00, 0x00, 0x00, // serial
+ 0x00, 0x00, 0x00, 0x00, // status
+ 0x00, 0x00, 0x00, 0x01, // callback id
+}
+
+var testDeregisterEvent = []byte{
+ 0x00, 0x00, 0x00, 0x1c, // length
+ 0x20, 0x00, 0x80, 0x87, // program
+ 0x00, 0x00, 0x00, 0x01, // version
+ 0x00, 0x00, 0x00, 0x05, // procedure
+ 0x00, 0x00, 0x00, 0x01, // type
+ 0x00, 0x00, 0x00, 0x00, // serial
+ 0x00, 0x00, 0x00, 0x00, // status
+}
+
+var testAuthReply = []byte{
+ 0x00, 0x00, 0x00, 0x24, // length
+ 0x20, 0x00, 0x80, 0x86, // program
+ 0x00, 0x00, 0x00, 0x01, // version
+ 0x00, 0x00, 0x00, 0x42, // procedure
+ 0x00, 0x00, 0x00, 0x01, // type
+ 0x00, 0x00, 0x00, 0x00, // serial
+ 0x00, 0x00, 0x00, 0x00, // status
+ 0x00, 0x00, 0x00, 0x01, // list length
+ 0x00, 0x00, 0x00, 0x00, // first entry (== no auth)
+}
+
+var testConnectReply = []byte{
+ 0x00, 0x00, 0x00, 0x1c, // length
+ 0x20, 0x00, 0x80, 0x86, // program
+ 0x00, 0x00, 0x00, 0x01, // version
+ 0x00, 0x00, 0x00, 0x01, // procedure
+ 0x00, 0x00, 0x00, 0x01, // type
+ 0x00, 0x00, 0x00, 0x00, // serial
+ 0x00, 0x00, 0x00, 0x00, // status
+}
+
+var testDisconnectReply = []byte{
+ 0x00, 0x00, 0x00, 0x1c, // length
+ 0x20, 0x00, 0x80, 0x86, // program
+ 0x00, 0x00, 0x00, 0x01, // version
+ 0x00, 0x00, 0x00, 0x02, // procedure
+ 0x00, 0x00, 0x00, 0x01, // type
+ 0x00, 0x00, 0x00, 0x00, // serial
+ 0x00, 0x00, 0x00, 0x00, // status
+}
+
+var testMigrateReply = []byte{
+ 0x00, 0x00, 0x00, 0x20, // length
+ 0x20, 0x00, 0x80, 0x86, // program
+ 0x00, 0x00, 0x00, 0x01, // version
+ 0x00, 0x00, 0x01, 0x31, // procedure
+ 0x00, 0x00, 0x00, 0x01, // type
+ 0x00, 0x00, 0x00, 0x00, // serial
+ 0x00, 0x00, 0x00, 0x00, // status
+
+ // cookie out: 0
+ 0x00, 0x00, 0x00, 0x00,
+}
+
+var testRunReply = []byte{
+ 0x00, 0x00, 0x00, 0x78, // length
+ 0x20, 0x00, 0x80, 0x87, // program
+ 0x00, 0x00, 0x00, 0x01, // version
+ 0x00, 0x00, 0x00, 0x01, // procedure
+ 0x00, 0x00, 0x00, 0x01, // type
+ 0x00, 0x00, 0x00, 0x00, // serial
+ 0x00, 0x00, 0x00, 0x00, // status
+
+ // {"return":{"qemu":{"micro":1,"minor":5,"major":2},"package":""},"id":"libvirt-53"}
+ 0x00, 0x00, 0x00, 0x52, 0x7b, 0x22, 0x72, 0x65,
+ 0x74, 0x75, 0x72, 0x6e, 0x22, 0x3a, 0x7b, 0x22,
+ 0x71, 0x65, 0x6d, 0x75, 0x22, 0x3a, 0x7b, 0x22,
+ 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x22, 0x3a, 0x31,
+ 0x2c, 0x22, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x22,
+ 0x3a, 0x35, 0x2c, 0x22, 0x6d, 0x61, 0x6a, 0x6f,
+ 0x72, 0x22, 0x3a, 0x32, 0x7d, 0x2c, 0x22, 0x70,
+ 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x22, 0x3a,
+ 0x22, 0x22, 0x7d, 0x2c, 0x22, 0x69, 0x64, 0x22,
+ 0x3a, 0x22, 0x6c, 0x69, 0x62, 0x76, 0x69, 0x72,
+ 0x74, 0x2d, 0x35, 0x33, 0x22, 0x7d,
+
+ // All trailing NULL characters should be removed
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+}
+
+var testRunReplyFail = []byte{
+ 0x00, 0x00, 0x00, 0x8c, // length
+ 0x20, 0x00, 0x80, 0x87, // program
+ 0x00, 0x00, 0x00, 0x01, // version
+ 0x00, 0x00, 0x00, 0x01, // procedure
+ 0x00, 0x00, 0x00, 0x01, // type
+ 0x00, 0x00, 0x00, 0x0a, // serial
+ 0x00, 0x00, 0x00, 0x00, // status
+
+ // {"id":"libvirt-68","error":{"class":"CommandNotFound","desc":"The command drive-foo has not been found"}}`
+ 0x00, 0x00, 0x00, 0x69, 0x7b, 0x22, 0x69, 0x64,
+ 0x22, 0x3a, 0x22, 0x6c, 0x69, 0x62, 0x76, 0x69,
+ 0x72, 0x74, 0x2d, 0x36, 0x38, 0x22, 0x2c, 0x22,
+ 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x3a, 0x7b,
+ 0x22, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x22, 0x3a,
+ 0x22, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
+ 0x4e, 0x6f, 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64,
+ 0x22, 0x2c, 0x22, 0x64, 0x65, 0x73, 0x63, 0x22,
+ 0x3a, 0x22, 0x54, 0x68, 0x65, 0x20, 0x63, 0x6f,
+ 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x20, 0x64, 0x72,
+ 0x69, 0x76, 0x65, 0x2d, 0x66, 0x6f, 0x6f, 0x20,
+ 0x68, 0x61, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20,
+ 0x62, 0x65, 0x65, 0x6e, 0x20, 0x66, 0x6f, 0x75,
+ 0x6e, 0x64, 0x22, 0x7d, 0x7d, 0x00, 0x00, 0x00,
+}
+
+var testSetSpeedReply = []byte{
+ 0x00, 0x00, 0x00, 0x1c, // length
+ 0x20, 0x00, 0x80, 0x86, // program
+ 0x00, 0x00, 0x00, 0x01, // version
+ 0x00, 0x00, 0x00, 0xcf, // procedure
+ 0x00, 0x00, 0x00, 0x01, // type
+ 0x00, 0x00, 0x00, 0x00, // serial
+ 0x00, 0x00, 0x00, 0x00, // status
+}
+
+var testDomainsReply = []byte{
+ 0x00, 0x00, 0x00, 0x6c, // length
+ 0x20, 0x00, 0x80, 0x86, // program
+ 0x00, 0x00, 0x00, 0x01, // version
+ 0x00, 0x00, 0x01, 0x11, // procedure
+ 0x00, 0x00, 0x00, 0x01, // type
+ 0x00, 0x00, 0x00, 0x00, // serial
+ 0x00, 0x00, 0x00, 0x00, // status
+
+ // struct of domains
+ 0x00, 0x00, 0x00, 0x02,
+
+ // first domain
+ // name - aaaaaaa-1
+ 0x00, 0x00, 0x00, 0x09, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x2d, 0x31, 0x00, 0x00, 0x00,
+ // uuid - dc:32:9f:87:d4:de:47:19:8c:fd:2e:21:c6:10:5b:01
+ 0xdc, 0x32, 0x9f, 0x87, 0xd4, 0xde, 0x47, 0x19,
+ 0x8c, 0xfd, 0x2e, 0x21, 0xc6, 0x10, 0x5b, 0x01,
+ // id
+ 0x00, 0x00, 0x00, 0x01,
+
+ // second domain
+ // name - aaaaaaa-2
+ 0x00, 0x00, 0x00, 0x09, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x2d, 0x32, 0x00, 0x00, 0x00,
+ // uuid - dc:22:9f:87:d4:de:47:19:8c:fd:2e:21:c6:10:5b:01
+ 0xdc, 0x22, 0x9f, 0x87, 0xd4, 0xde, 0x47, 0x19, 0x8c,
+ 0xfd, 0x2e, 0x21, 0xc6, 0x10, 0x5b, 0x01, 0x00, 0x00,
+ // id
+ 0x00, 0x02, 0x00,
+
+ // count of domains returned
+ 0x00, 0x00, 0x02,
+}
+
+var testDomainMemoryStatsReply = []byte{
+ 0x00, 0x00, 0x00, 0x38, // length
+ 0x20, 0x00, 0x80, 0x86, // program
+ 0x00, 0x00, 0x00, 0x01, // version
+ 0x00, 0x00, 0x00, 0x9f, // procedure
+ 0x00, 0x00, 0x00, 0x01, // type
+ 0x00, 0x00, 0x00, 0x00, // serial
+ 0x00, 0x00, 0x00, 0x00, // status
+
+ // tag 6 val 1048576
+ // tag 7 val 91272
+ 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x06,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x07,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x64, 0x88,
+}
+
+var testDomainStateReply = []byte{
+ 0x00, 0x00, 0x00, 0x24, // length
+ 0x20, 0x00, 0x80, 0x86, // program
+ 0x00, 0x00, 0x00, 0x01, // version
+ 0x00, 0x00, 0x00, 0xd4, // procedure
+ 0x00, 0x00, 0x00, 0x01, // type
+ 0x00, 0x00, 0x00, 0x00, // serial
+ 0x00, 0x00, 0x00, 0x00, // status
+ 0x00, 0x00, 0x00, 0x01, // state
+ 0x00, 0x00, 0x00, 0x01, // reason
+}
+
+var testSecretsReply = []byte{
+ 0x00, 0x00, 0x00, 0x40, // length
+ 0x20, 0x00, 0x80, 0x86, // program
+ 0x00, 0x00, 0x00, 0x01, // version
+ 0x00, 0x00, 0x01, 0x1f, // procedure
+ 0x00, 0x00, 0x00, 0x01, // type
+ 0x00, 0x00, 0x00, 0x00, // serial
+ 0x00, 0x00, 0x00, 0x00, // status
+
+ // list of secrets
+ 0x00, 0x00, 0x00, 0x01,
+
+ // first secret
+ // UUID: 19fdc2f2fa64-46f3bacf42a8aafca6dd
+ 0x19, 0xfd, 0xc2, 0xf2, 0xfa, 0x64, 0x46, 0xf3,
+ 0xba, 0xcf, 0x42, 0xa8, 0xaa, 0xfc, 0xa6, 0xdd,
+
+ // usage type: (1, volume)
+ 0x00, 0x00, 0x00, 0x01,
+
+ // usage id: "/tmp"
+ 0x00, 0x00, 0x00, 0x04, 0x2f, 0x74, 0x6d, 0x70,
+
+ // end of secrets
+ 0x00, 0x00, 0x00, 0x01,
+}
+
+var testStoragePoolLookup = []byte{
+ 0x00, 0x00, 0x00, 0x38, // length
+ 0x20, 0x00, 0x80, 0x86, // program
+ 0x00, 0x00, 0x00, 0x01, // version
+ 0x00, 0x00, 0x00, 0x54, // procedure
+ 0x00, 0x00, 0x00, 0x01, // type
+ 0x00, 0x00, 0x00, 0x00, // serial
+ 0x00, 0x00, 0x00, 0x00, // status
+
+ // pool: name = default
+ 0x00, 0x00, 0x00, 0x07, 0x64, 0x65, 0x66, 0x61,
+ 0x75, 0x6c, 0x74, 0x00,
+
+ // uuid = bb30a11c084648278bba3e6b5cf1b65f
+ 0xbb, 0x30, 0xa1, 0x1c, 0x08, 0x46, 0x48, 0x27,
+ 0x8b, 0xba, 0x3e, 0x6b, 0x5c, 0xf1, 0xb6, 0x5f,
+}
+
+var testStoragePoolRefresh = []byte{
+ 0x00, 0x00, 0x00, 0x1c, // length
+ 0x20, 0x00, 0x80, 0x86, // program
+ 0x00, 0x00, 0x00, 0x01, // version
+ 0x00, 0x00, 0x00, 0x53, // procedure
+ 0x00, 0x00, 0x00, 0x01, // type
+ 0x00, 0x00, 0x00, 0x00, // serial
+ 0x00, 0x00, 0x00, 0x00, // status
+}
+
+var testListPoolsReply = []byte{
+ 0x00, 0x00, 0x00, 0x40, // length
+ 0x20, 0x00, 0x80, 0x86, // program
+ 0x00, 0x00, 0x00, 0x01, // version
+ 0x00, 0x00, 0x01, 0x19, // procedure
+ 0x00, 0x00, 0x00, 0x01, // type
+ 0x00, 0x00, 0x00, 0x00, // serial
+ 0x00, 0x00, 0x00, 0x00, // status
+
+ 0x00, 0x00, 0x00, 0x01, // pools
+
+ // first pool, name: "default"
+ 0x00, 0x00, 0x00, 0x07, 0x64, 0x65, 0x66, 0x61,
+ 0x75, 0x6c, 0x74, 0x00,
+
+ // uuid: bb30a11c084648278bba3e6b5cf1b65f
+ 0xbb, 0x30, 0xa1, 0x1c, 0x08, 0x46, 0x48, 0x27,
+ 0x8b, 0xba, 0x3e, 0x6b, 0x5c, 0xf1, 0xb6, 0x5f,
+
+ 0x00, 0x00, 0x00, 0x01, // count
+}
+
+var testUndefineReply = []byte{
+ 0x00, 0x00, 0x00, 0x1c, // length
+ 0x20, 0x00, 0x80, 0x86, // program
+ 0x00, 0x00, 0x00, 0x01, // version
+ 0x00, 0x00, 0x00, 0xe7, // procedure
+ 0x00, 0x00, 0x00, 0x01, // type
+ 0x00, 0x00, 0x00, 0x00, // serial
+ 0x00, 0x00, 0x00, 0x00, // status
+}
+
+var testDestroyReply = []byte{
+ 0x00, 0x00, 0x00, 0x1c, // length
+ 0x20, 0x00, 0x80, 0x86, // program
+ 0x00, 0x00, 0x00, 0x01, // version
+ 0x00, 0x00, 0x00, 0xea, // procedure
+ 0x00, 0x00, 0x00, 0x01, // type
+ 0x00, 0x00, 0x00, 0x00, // serial
+ 0x00, 0x00, 0x00, 0x00, // status
+}
+
+var testVersionReply = []byte{
+ 0x00, 0x00, 0x00, 0x24, // length
+ 0x20, 0x00, 0x80, 0x86, // program
+ 0x00, 0x00, 0x00, 0x01, // version
+ 0x00, 0x00, 0x00, 0x9d, // procedure
+ 0x00, 0x00, 0x00, 0x01, // type
+ 0x00, 0x00, 0x00, 0x00, // serial
+ 0x00, 0x00, 0x00, 0x00, // status
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x4d, 0xfc, // version (1003004)
+}
+
+var testDefineXML = []byte{
+ 0x00, 0x00, 0x00, 0x38, // length
+ 0x20, 0x00, 0x80, 0x86, // program
+ 0x00, 0x00, 0x00, 0x01, // version
+ 0x00, 0x00, 0x01, 0x5e, // procedure
+ 0x00, 0x00, 0x00, 0x01, // type
+ 0x00, 0x00, 0x00, 0x00, // serial
+ 0x00, 0x00, 0x00, 0x00, // status
+ 0x00, 0x00, 0x00, 0x04, // dom
+ 0x74, 0x65, 0x73, 0x74, // name
+ // uuid
+ 0xaf, 0xc2, 0xef, 0x71, 0x66, 0xe0, 0x45, 0xa7,
+ 0xa5, 0xec, 0xd8, 0xba, 0x1e, 0xa8, 0x17, 0x7d,
+ 0xff, 0xff, 0xff, 0xff, // id
+}
+
+var testCreateWithFlags = []byte{
+ 0x00, 0x00, 0x00, 0x38, // length
+ 0x20, 0x00, 0x80, 0x86, // program
+ 0x00, 0x00, 0x00, 0x01, // version
+ 0x00, 0x00, 0x01, 0x5e, // procedure
+ 0x00, 0x00, 0x00, 0x01, // type
+ 0x00, 0x00, 0x00, 0x00, // serial
+ 0x00, 0x00, 0x00, 0x00, // status
+ 0x00, 0x00, 0x00, 0x04, // dom
+ 0x74, 0x65, 0x73, 0x74, // name
+ // uuid
+ 0xaf, 0xc2, 0xef, 0x71, 0x66, 0xe0, 0x45, 0xa7,
+ 0xa5, 0xec, 0xd8, 0xba, 0x1e, 0xa8, 0x17, 0x7d,
+ 0xff, 0xff, 0xff, 0xff, // id
+}
+
+var testShutdownReply = []byte{
+ 0x00, 0x00, 0x00, 0x1c, // length
+ 0x20, 0x00, 0x80, 0x86, // program
+ 0x00, 0x00, 0x00, 0x01, // version
+ 0x00, 0x00, 0x00, 0xea, // procedure
+ 0x00, 0x00, 0x00, 0x01, // type
+ 0x00, 0x00, 0x00, 0x00, // serial
+ 0x00, 0x00, 0x00, 0x00, // status
+}
+
+var testRebootReply = []byte{
+ 0x00, 0x00, 0x00, 0x1c, // length
+ 0x20, 0x00, 0x80, 0x86, // program
+ 0x00, 0x00, 0x00, 0x01, // version
+ 0x00, 0x00, 0x00, 0xea, // procedure
+ 0x00, 0x00, 0x00, 0x01, // type
+ 0x00, 0x00, 0x00, 0x00, // serial
+ 0x00, 0x00, 0x00, 0x00, // status
+}
+
+var testSetBlockIoTuneReply = []byte{
+ 0x00, 0x00, 0x00, 0x1c, // length
+ 0x20, 0x00, 0x80, 0x86, // program
+ 0x00, 0x00, 0x00, 0x01, // version
+ 0x00, 0x00, 0x00, 0xfc, // procedure
+ 0x00, 0x00, 0x00, 0x00, // type
+ 0x00, 0x00, 0x00, 0x00, // serial
+ 0x00, 0x00, 0x00, 0x00, // status
+}
+
+// This result block was obtained by calling `fmt.Printf("%#v", r.Payload)` on
+// the result returned by an actual call to GetBlockIoTune, and then adding the
+// standard header to the beginning. The length parameter has to be correct!
+var testGetBlockIoTuneReply = []byte{
+ 0x00, 0x00, 0x03, 0x00, // length
+ 0x20, 0x00, 0x80, 0x86, // program
+ 0x00, 0x00, 0x00, 0x01, // version
+ 0x00, 0x00, 0x00, 0xfd, // procedure
+ 0x00, 0x00, 0x00, 0x00, // type
+ 0x00, 0x00, 0x00, 0x00, // serial
+ 0x00, 0x00, 0x00, 0x00, // status
+
+ 0x0, 0x0, 0x0, 0x14, // 14 TypedParams follow
+
+ 0x0, 0x0, 0x0, 0xf, // field name is 15 bytes, padded to a multiple of 4
+ 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x73, 0x65, 0x63, 0x0,
+ 0x0, 0x0, 0x0, 0x4, // type
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // value
+
+ 0x0, 0x0, 0x0, 0xe,
+ 0x72, 0x65, 0x61, 0x64, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x73, 0x65, 0x63, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x4,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+
+ 0x0, 0x0, 0x0, 0xf,
+ 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x73, 0x65, 0x63, 0x0,
+ 0x0, 0x0, 0x0, 0x4,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xa1, 0x20,
+
+ 0x0, 0x0, 0x0, 0xe,
+ 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x69, 0x6f, 0x70, 0x73, 0x5f, 0x73, 0x65, 0x63, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x4,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+
+ 0x0, 0x0, 0x0, 0xd,
+ 0x72, 0x65, 0x61, 0x64, 0x5f, 0x69, 0x6f, 0x70, 0x73, 0x5f, 0x73, 0x65, 0x63, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x4,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+
+ 0x0, 0x0, 0x0, 0xe,
+ 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x69, 0x6f, 0x70, 0x73, 0x5f, 0x73, 0x65, 0x63, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x4,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+
+ 0x0, 0x0, 0x0, 0x13,
+ 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x73, 0x65, 0x63, 0x5f, 0x6d, 0x61, 0x78, 0x0,
+ 0x0, 0x0, 0x0, 0x4,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+
+ 0x0, 0x0, 0x0, 0x12,
+ 0x72, 0x65, 0x61, 0x64, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x73, 0x65, 0x63, 0x5f, 0x6d, 0x61, 0x78, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x4,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+
+ 0x0, 0x0, 0x0, 0x13,
+ 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x73, 0x65, 0x63, 0x5f, 0x6d, 0x61, 0x78, 0x0,
+ 0x0, 0x0, 0x0, 0x4,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc3, 0x50,
+
+ 0x0, 0x0, 0x0, 0x12,
+ 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x69, 0x6f, 0x70, 0x73, 0x5f, 0x73, 0x65, 0x63, 0x5f, 0x6d, 0x61, 0x78, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x4,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+
+ 0x0, 0x0, 0x0, 0x11,
+ 0x72, 0x65, 0x61, 0x64, 0x5f, 0x69, 0x6f, 0x70, 0x73, 0x5f, 0x73, 0x65, 0x63, 0x5f, 0x6d, 0x61, 0x78, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x4,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+
+ 0x0, 0x0, 0x0, 0x12,
+ 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x69, 0x6f, 0x70, 0x73, 0x5f, 0x73, 0x65, 0x63, 0x5f, 0x6d, 0x61, 0x78, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x4,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+
+ 0x0, 0x0, 0x0, 0xd,
+ 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x69, 0x6f, 0x70, 0x73, 0x5f, 0x73, 0x65, 0x63, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x4,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+
+ 0x0, 0x0, 0x0, 0x1a,
+ 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x73, 0x65, 0x63, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x4,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+
+ 0x0, 0x0, 0x0, 0x19,
+ 0x72, 0x65, 0x61, 0x64, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x73, 0x65, 0x63, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x4,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+
+ 0x0, 0x0, 0x0, 0x1a,
+ 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x73, 0x65, 0x63, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x4,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
+
+ 0x0, 0x0, 0x0, 0x19,
+ 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x69, 0x6f, 0x70, 0x73, 0x5f, 0x73, 0x65, 0x63, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x4,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+
+ 0x0, 0x0, 0x0, 0x18,
+ 0x72, 0x65, 0x61, 0x64, 0x5f, 0x69, 0x6f, 0x70, 0x73, 0x5f, 0x73, 0x65, 0x63, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68,
+ 0x0, 0x0, 0x0, 0x4,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+
+ 0x0, 0x0, 0x0, 0x19,
+ 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x69, 0x6f, 0x70, 0x73, 0x5f, 0x73, 0x65, 0x63, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x4,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+
+ 0x0, 0x0, 0x0, 0xa, // This is field "group_name", a string (type 7), whose value is "somename"
+ 0x67, 0x72, 0x6F, 0x75, 0x70, 0x5F, 0x6E, 0x61, 0x6D, 0x65, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x7,
+ 0x0, 0x0, 0x0, 0x8,
+ 0x73, 0x6F, 0x6D, 0x65, 0x6E, 0x61, 0x6D, 0x65,
+
+ 0x0, 0x0, 0x0, 0x0, // End of TypedParams
+}
+
+var testGetAllDomainStatsReply = []byte{
+ 0x00, 0x00, 0x00, 0xd8, // length
+ 0x20, 0x00, 0x80, 0x86, // program
+ 0x00, 0x00, 0x00, 0x01, // version
+ 0x00, 0x00, 0x01, 0x58, // procedure
+ 0x00, 0x00, 0x00, 0x00, // type
+ 0x00, 0x00, 0x00, 0x00, // serial
+ 0x00, 0x00, 0x00, 0x00, // status
+
+ 0x0, 0x0, 0x0, 0x2, // 2 domain stats records follow
+
+ // Domain 0: "Droplet-844329"
+ 0x0, 0x0, 0x0, 0xe, // Domain name is 14 bytes, padded to 4-byte boundary
+ 0x44, 0x72, 0x6f, 0x70, 0x6c, 0x65, 0x74, 0x2d, 0x38, 0x34, 0x34, 0x33, 0x32, 0x39, 0x0, 0x0,
+ 0x51, 0x53, 0x24, 0x2e, 0xc6, 0xbd, 0x44, 0x59, 0xa9, 0xff, 0x20, 0xca, 0x79, 0x8f, 0x31, 0x71, // 16-byte UUID
+ 0xff, 0xff, 0xff, 0xff, // ID
+
+ 0x0, 0x0, 0x0, 0x2, // Array of 2 TypedParams.
+ 0x0, 0x0, 0x0, 0xb, // Field name contains 11 bytes, padded to 4-byte boundary ("state.state")
+ 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x0,
+ 0x0, 0x0, 0x0, 0x1, // Type
+ 0x0, 0x0, 0x0, 0x1, // Value
+
+ 0x0, 0x0, 0x0, 0xc, // Field name contains 12 bytes ("state.reason")
+ 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e,
+ 0x0, 0x0, 0x0, 0x1, // Type
+ 0x0, 0x0, 0x0, 0x2, // Value
+
+ // Domain 1: "Droplet-33436"
+ 0x0, 0x0, 0x0, 0xd,
+ 0x44, 0x72, 0x6f, 0x70, 0x6c, 0x65, 0x74, 0x2d, 0x33, 0x33, 0x34, 0x33, 0x36, 0x0, 0x0, 0x0,
+ 0x24, 0xd, 0x94, 0xc5, 0xf0, 0x47, 0x45, 0x8b, 0x89, 0xf1, 0xcd, 0x3a, 0xe6, 0xd6, 0x2b, 0x5d,
+ 0xff, 0xff, 0xff, 0xff,
+
+ 0x0, 0x0, 0x0, 0x2,
+ 0x0, 0x0, 0x0, 0xb,
+ 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x0,
+ 0x0, 0x0, 0x0, 0x1,
+ 0x0, 0x0, 0x0, 0x1,
+
+ 0x0, 0x0, 0x0, 0xc,
+ 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e,
+ 0x0, 0x0, 0x0, 0x1,
+ 0x0, 0x0, 0x0, 0x1,
+
+ // 0x0, 0x0, 0x0, 0xe, 0x44, 0x72, 0x6f, 0x70, 0x6c, 0x65, 0x74, 0x2d, 0x38, 0x34, 0x34, 0x33, 0x33, 0x30, 0x0, 0x0, 0xfb, 0x21, 0xa7, 0xe7, 0x69, 0x89, 0x4c, 0x56, 0xaa, 0xcb, 0x3, 0xde, 0xfc, 0x41, 0xbe, 0xb4, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0xb, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0xc, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0xe, 0x44, 0x72, 0x6f, 0x70, 0x6c, 0x65, 0x74, 0x2d, 0x36, 0x36, 0x32, 0x36, 0x32, 0x35, 0x0, 0x0, 0x37, 0x1b, 0xf, 0xd7, 0xb4, 0xeb, 0x4a, 0xca, 0xae, 0xfd, 0x10, 0xf9, 0x9f, 0x42, 0xf4, 0x23, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0xb, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0xc, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0xe, 0x44, 0x72, 0x6f, 0x70, 0x6c, 0x65, 0x74, 0x2d, 0x36, 0x33, 0x39, 0x38, 0x35, 0x35, 0x0, 0x0, 0xed, 0x77, 0x55, 0x81, 0xa, 0xe6, 0x4d, 0x99, 0xac, 0xbd, 0x7f, 0xd0, 0x3e, 0x81, 0xb6, 0x1c, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0xb, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0xc, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0xe, 0x44, 0x72, 0x6f, 0x70, 0x6c, 0x65, 0x74, 0x2d, 0x36, 0x36, 0x39, 0x31, 0x31, 0x34, 0x0, 0x0, 0x9e, 0x15, 0x30, 0x92, 0x14, 0x49, 0x40, 0xb1, 0xa8, 0x84, 0xd, 0x40, 0x16, 0x37, 0x9c, 0xf3, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0xb, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0xc, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0xe, 0x44, 0x72, 0x6f, 0x70, 0x6c, 0x65, 0x74, 0x2d, 0x38, 0x39, 0x39, 0x38, 0x36, 0x37, 0x0, 0x0, 0x23, 0x81, 0x16, 0xe6, 0x7f, 0x3a, 0x4a, 0x80, 0xac, 0x1, 0xe4, 0x77, 0x6, 0xa5, 0x8b, 0x82, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0xb, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0xc, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e,
+ // 0x0, 0x0, 0x0, 0x1,
+ // 0x0, 0x0, 0x0, 0x2
+}
+
+// MockLibvirt provides a mock libvirt server for testing.
+type MockLibvirt struct {
+ client net.Conn
+ Test net.Conn
+ Fail bool
+ serial uint32
+ disconnected chan struct{}
+}
+
+// New creates a new mock Libvirt server.
+func New() *MockLibvirt {
+ m := &MockLibvirt{
+ disconnected: make(chan struct{}),
+ }
+ close(m.disconnected)
+ return m
+}
+
+// Dial creates a pipe to use for the server and client
+func (m *MockLibvirt) Dial() (net.Conn, error) {
+ serv, conn := net.Pipe()
+
+ m.client = conn
+ m.Test = serv
+ m.disconnected = make(chan struct{})
+
+ go func() {
+ m.handle(serv)
+ fmt.Println("libvirttest pipe closed")
+ close(m.disconnected)
+ }()
+
+ return m.client, nil
+}
+
+func (m *MockLibvirt) handle(conn net.Conn) {
+ for {
+ // packetLengthSize + headerSize
+ buf := make([]byte, 28)
+ _, err := conn.Read(buf)
+ if errors.Is(err, io.EOF) {
+ return
+ }
+
+ // extract program
+ prog := binary.BigEndian.Uint32(buf[4:8])
+
+ // extract procedure
+ proc := binary.BigEndian.Uint32(buf[12:16])
+
+ switch prog {
+ case constants.Program:
+ m.handleRemote(proc, conn)
+ case constants.QEMUProgram:
+ m.handleQEMU(proc, conn)
+ }
+ }
+}
+
+func (m *MockLibvirt) handleRemote(procedure uint32, conn net.Conn) {
+ switch procedure {
+ case constants.ProcAuthList:
+ conn.Write(m.reply(testAuthReply))
+ case constants.ProcStoragePoolRefresh:
+ conn.Write(m.reply(testStoragePoolRefresh))
+ case constants.ProcStoragePoolLookupByName:
+ conn.Write(m.reply(testStoragePoolLookup))
+ case constants.ProcConnectOpen:
+ conn.Write(m.reply(testConnectReply))
+ case constants.ProcConnectClose:
+ conn.Write(m.reply(testDisconnectReply))
+ case constants.ProcConnectGetLibVersion:
+ conn.Write(m.reply(testVersionReply))
+ case constants.ProcDomainLookupByName:
+ conn.Write(m.reply(testDomainResponse))
+ case constants.ProcConnectListAllDomains:
+ conn.Write(m.reply(testDomainsReply))
+ case constants.ProcConnectListAllStoragePools:
+ conn.Write(m.reply(testListPoolsReply))
+ case constants.ProcConnectListAllSecrets:
+ conn.Write(m.reply(testSecretsReply))
+ case constants.ProcDomainGetState:
+ conn.Write(m.reply(testDomainStateReply))
+ case constants.ProcDomainMemoryStats:
+ conn.Write(m.reply(testDomainMemoryStatsReply))
+ case constants.ProcDomainMigrateSetMaxSpeed:
+ conn.Write(m.reply(testSetSpeedReply))
+ case constants.ProcDomainMigratePerform3Params:
+ conn.Write(m.reply(testMigrateReply))
+ case constants.ProcDomainUndefineFlags:
+ conn.Write(m.reply(testUndefineReply))
+ case constants.ProcDomainDestroyFlags:
+ conn.Write(m.reply(testDestroyReply))
+ case constants.ProcDomainDefineXMLFlags:
+ conn.Write(m.reply(testDefineXML))
+ case constants.ProcDomainReboot:
+ conn.Write(m.reply(testRebootReply))
+ case constants.ProcDomainReset:
+ conn.Write(m.reply(testRebootReply))
+ case constants.ProcDomainCreateWithFlags:
+ conn.Write(m.reply(testCreateWithFlags))
+ case constants.ProcDomainShutdownFlags:
+ conn.Write(m.reply(testShutdownReply))
+ case constants.ProcDomainSetBlockIOTune:
+ conn.Write(m.reply(testSetBlockIoTuneReply))
+ case constants.ProcDomainGetBlockIOTune:
+ conn.Write(m.reply(testGetBlockIoTuneReply))
+ case constants.ProcConnectGetAllDomainStats:
+ conn.Write(m.reply(testGetAllDomainStatsReply))
+ default:
+ fmt.Fprintln(os.Stderr, "unknown procedure", procedure)
+ }
+}
+
+func (m *MockLibvirt) handleQEMU(procedure uint32, conn net.Conn) {
+ switch procedure {
+ case constants.QEMUProcConnectDomainMonitorEventRegister:
+ conn.Write(m.reply(testRegisterEvent))
+ case constants.QEMUProcConnectDomainMonitorEventDeregister:
+ conn.Write(m.reply(testDeregisterEvent))
+ case constants.QEMUProcDomainMonitorCommand:
+ if m.Fail {
+ conn.Write(m.reply(testRunReplyFail))
+ } else {
+ conn.Write(m.reply(testRunReply))
+ }
+ }
+}
+
+// reply automatically injects the correct serial
+// number into the provided response buffer.
+func (m *MockLibvirt) reply(buf []byte) []byte {
+ var rspbuf bytes.Buffer
+ io.Copy(&rspbuf, bytes.NewReader(buf))
+ rsp := rspbuf.Bytes()
+
+ serial := atomic.AddUint32(&m.serial, 1)
+ binary.BigEndian.PutUint32(rsp[20:24], serial)
+ return rsp
+}
diff --git a/third_party/libvirt/qemu_protocol.gen.go b/third_party/libvirt/qemu_protocol.gen.go
new file mode 100644
index 0000000..0d51082
--- /dev/null
+++ b/third_party/libvirt/qemu_protocol.gen.go
@@ -0,0 +1,292 @@
+// 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 libvirt
+
+import (
+ "bytes"
+ "io"
+
+ "github.com/projecteru2/yavirt/third_party/libvirt/internal/constants"
+ "github.com/projecteru2/yavirt/third_party/libvirt/internal/go-xdr/xdr2"
+)
+
+// References to prevent "imported and not used" errors.
+var (
+ _ = bytes.Buffer{}
+ _ = io.Copy
+ _ = constants.Program
+ _ = xdr.Unmarshal
+)
+
+//
+// Typedefs:
+//
+
+//
+// Enums:
+//
+// QEMUProcedure is libvirt's qemu_procedure
+type QEMUProcedure int32
+
+//
+// Structs:
+//
+// QEMUDomainMonitorCommandArgs is libvirt's qemu_domain_monitor_command_args
+type QEMUDomainMonitorCommandArgs struct {
+ Dom Domain
+ Cmd string
+ Flags uint32
+}
+
+// QEMUDomainMonitorCommandRet is libvirt's qemu_domain_monitor_command_ret
+type QEMUDomainMonitorCommandRet struct {
+ Result string
+}
+
+// QEMUDomainAttachArgs is libvirt's qemu_domain_attach_args
+type QEMUDomainAttachArgs struct {
+ PidValue uint32
+ Flags uint32
+}
+
+// QEMUDomainAttachRet is libvirt's qemu_domain_attach_ret
+type QEMUDomainAttachRet struct {
+ Dom Domain
+}
+
+// QEMUDomainAgentCommandArgs is libvirt's qemu_domain_agent_command_args
+type QEMUDomainAgentCommandArgs struct {
+ Dom Domain
+ Cmd string
+ Timeout int32
+ Flags uint32
+}
+
+// QEMUDomainAgentCommandRet is libvirt's qemu_domain_agent_command_ret
+type QEMUDomainAgentCommandRet struct {
+ Result OptString
+}
+
+// QEMUConnectDomainMonitorEventRegisterArgs is libvirt's qemu_connect_domain_monitor_event_register_args
+type QEMUConnectDomainMonitorEventRegisterArgs struct {
+ Dom OptDomain
+ Event OptString
+ Flags uint32
+}
+
+// QEMUConnectDomainMonitorEventRegisterRet is libvirt's qemu_connect_domain_monitor_event_register_ret
+type QEMUConnectDomainMonitorEventRegisterRet struct {
+ CallbackID int32
+}
+
+// QEMUConnectDomainMonitorEventDeregisterArgs is libvirt's qemu_connect_domain_monitor_event_deregister_args
+type QEMUConnectDomainMonitorEventDeregisterArgs struct {
+ CallbackID int32
+}
+
+// QEMUDomainMonitorEventMsg is libvirt's qemu_domain_monitor_event_msg
+type QEMUDomainMonitorEventMsg struct {
+ CallbackID int32
+ Dom Domain
+ Event string
+ Seconds int64
+ Micros uint32
+ Details OptString
+}
+
+
+
+
+// QEMUDomainMonitorCommand is the go wrapper for QEMU_PROC_DOMAIN_MONITOR_COMMAND.
+func (l *Libvirt) QEMUDomainMonitorCommand(Dom Domain, Cmd string, Flags uint32) (rResult string, err error) {
+ var buf []byte
+
+ args := QEMUDomainMonitorCommandArgs {
+ Dom: Dom,
+ Cmd: Cmd,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(1, constants.QEMUProgram, 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)
+ // Result: string
+ _, err = dec.Decode(&rResult)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// QEMUDomainAttach is the go wrapper for QEMU_PROC_DOMAIN_ATTACH.
+func (l *Libvirt) QEMUDomainAttach(PidValue uint32, Flags uint32) (rDom Domain, err error) {
+ var buf []byte
+
+ args := QEMUDomainAttachArgs {
+ PidValue: PidValue,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(2, constants.QEMUProgram, 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)
+ // Dom: Domain
+ _, err = dec.Decode(&rDom)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// QEMUDomainAgentCommand is the go wrapper for QEMU_PROC_DOMAIN_AGENT_COMMAND.
+func (l *Libvirt) QEMUDomainAgentCommand(Dom Domain, Cmd string, Timeout int32, Flags uint32) (rResult OptString, err error) {
+ var buf []byte
+
+ args := QEMUDomainAgentCommandArgs {
+ Dom: Dom,
+ Cmd: Cmd,
+ Timeout: Timeout,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(3, constants.QEMUProgram, 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)
+ // Result: OptString
+ _, err = dec.Decode(&rResult)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// QEMUConnectDomainMonitorEventRegister is the go wrapper for QEMU_PROC_CONNECT_DOMAIN_MONITOR_EVENT_REGISTER.
+func (l *Libvirt) QEMUConnectDomainMonitorEventRegister(Dom OptDomain, Event OptString, Flags uint32) (rCallbackID int32, err error) {
+ var buf []byte
+
+ args := QEMUConnectDomainMonitorEventRegisterArgs {
+ Dom: Dom,
+ Event: Event,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(4, constants.QEMUProgram, 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)
+ // CallbackID: int32
+ _, err = dec.Decode(&rCallbackID)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// QEMUConnectDomainMonitorEventDeregister is the go wrapper for QEMU_PROC_CONNECT_DOMAIN_MONITOR_EVENT_DEREGISTER.
+func (l *Libvirt) QEMUConnectDomainMonitorEventDeregister(CallbackID int32) (err error) {
+ var buf []byte
+
+ args := QEMUConnectDomainMonitorEventDeregisterArgs {
+ CallbackID: CallbackID,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+
+ _, err = l.requestStream(5, constants.QEMUProgram, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// QEMUDomainMonitorEvent is the go wrapper for QEMU_PROC_DOMAIN_MONITOR_EVENT.
+func (l *Libvirt) QEMUDomainMonitorEvent() (err error) {
+ var buf []byte
+
+
+ _, err = l.requestStream(6, constants.QEMUProgram, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
diff --git a/third_party/libvirt/remote_protocol.gen.go b/third_party/libvirt/remote_protocol.gen.go
new file mode 100644
index 0000000..f670e8f
--- /dev/null
+++ b/third_party/libvirt/remote_protocol.gen.go
@@ -0,0 +1,16786 @@
+// 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 libvirt
+
+import (
+ "bytes"
+ "io"
+
+ "github.com/projecteru2/yavirt/third_party/libvirt/internal/constants"
+ "github.com/projecteru2/yavirt/third_party/libvirt/internal/go-xdr/xdr2"
+)
+
+// References to prevent "imported and not used" errors.
+var (
+ _ = bytes.Buffer{}
+ _ = io.Copy
+ _ = constants.Program
+ _ = xdr.Unmarshal
+)
+
+// Typedefs:
+//
+// OptString is libvirt's remote_string
+type OptString []string
+
+// UUID is libvirt's remote_uuid
+type UUID [UUIDBuflen]byte
+
+// OptDomain is libvirt's remote_domain
+type OptDomain []Domain
+
+// OptNetwork is libvirt's remote_network
+type OptNetwork []Network
+
+// OptNetworkPort is libvirt's remote_network_port
+type OptNetworkPort []NetworkPort
+
+// OptNwfilter is libvirt's remote_nwfilter
+type OptNwfilter []Nwfilter
+
+// OptNwfilterBinding is libvirt's remote_nwfilter_binding
+type OptNwfilterBinding []NwfilterBinding
+
+// OptStoragePool is libvirt's remote_storage_pool
+type OptStoragePool []StoragePool
+
+// OptStorageVol is libvirt's remote_storage_vol
+type OptStorageVol []StorageVol
+
+// OptNodeDevice is libvirt's remote_node_device
+type OptNodeDevice []NodeDevice
+
+// OptSecret is libvirt's remote_secret
+type OptSecret []Secret
+
+// Enums:
+//
+// AuthType is libvirt's remote_auth_type
+type AuthType int32
+
+// Procedure is libvirt's remote_procedure
+type Procedure int32
+
+// Structs:
+//
+// Domain is libvirt's remote_nonnull_domain
+type Domain struct {
+ Name string
+ UUID UUID
+ ID int32
+}
+
+// Network is libvirt's remote_nonnull_network
+type Network struct {
+ Name string
+ UUID UUID
+}
+
+// NetworkPort is libvirt's remote_nonnull_network_port
+type NetworkPort struct {
+ Net Network
+ UUID UUID
+}
+
+// Nwfilter is libvirt's remote_nonnull_nwfilter
+type Nwfilter struct {
+ Name string
+ UUID UUID
+}
+
+// NwfilterBinding is libvirt's remote_nonnull_nwfilter_binding
+type NwfilterBinding struct {
+ Portdev string
+ Filtername string
+}
+
+// Interface is libvirt's remote_nonnull_interface
+type Interface struct {
+ Name string
+ Mac string
+}
+
+// StoragePool is libvirt's remote_nonnull_storage_pool
+type StoragePool struct {
+ Name string
+ UUID UUID
+}
+
+// StorageVol is libvirt's remote_nonnull_storage_vol
+type StorageVol struct {
+ Pool string
+ Name string
+ Key string
+}
+
+// NodeDevice is libvirt's remote_nonnull_node_device
+type NodeDevice struct {
+ Name string
+}
+
+// Secret is libvirt's remote_nonnull_secret
+type Secret struct {
+ UUID UUID
+ UsageType int32
+ UsageID string
+}
+
+// DomainCheckpoint is libvirt's remote_nonnull_domain_checkpoint
+type DomainCheckpoint struct {
+ Name string
+ Dom Domain
+}
+
+// DomainSnapshot is libvirt's remote_nonnull_domain_snapshot
+type DomainSnapshot struct {
+ Name string
+ Dom Domain
+}
+
+// remote_error is libvirt's remote_error
+type remote_error struct {
+ Code int32
+ OptDomain int32
+ Message OptString
+ Level int32
+ Dom OptDomain
+ Str1 OptString
+ Str2 OptString
+ Str3 OptString
+ Int1 int32
+ Int2 int32
+ Net OptNetwork
+}
+
+// VcpuInfo is libvirt's remote_vcpu_info
+type VcpuInfo struct {
+ Number uint32
+ State int32
+ CPUTime uint64
+ CPU int32
+}
+
+// TypedParam is libvirt's remote_typed_param
+type TypedParam struct {
+ Field string
+ Value TypedParamValue
+}
+
+// NodeGetCPUStats is libvirt's remote_node_get_cpu_stats
+type NodeGetCPUStats struct {
+ Field string
+ Value uint64
+}
+
+// NodeGetMemoryStats is libvirt's remote_node_get_memory_stats
+type NodeGetMemoryStats struct {
+ Field string
+ Value uint64
+}
+
+// DomainDiskError is libvirt's remote_domain_disk_error
+type DomainDiskError struct {
+ Disk string
+ remote_error int32
+}
+
+// ConnectOpenArgs is libvirt's remote_connect_open_args
+type ConnectOpenArgs struct {
+ Name OptString
+ Flags ConnectFlags
+}
+
+// ConnectSupportsFeatureArgs is libvirt's remote_connect_supports_feature_args
+type ConnectSupportsFeatureArgs struct {
+ Feature int32
+}
+
+// ConnectSupportsFeatureRet is libvirt's remote_connect_supports_feature_ret
+type ConnectSupportsFeatureRet struct {
+ Supported int32
+}
+
+// ConnectGetTypeRet is libvirt's remote_connect_get_type_ret
+type ConnectGetTypeRet struct {
+ Type string
+}
+
+// ConnectGetVersionRet is libvirt's remote_connect_get_version_ret
+type ConnectGetVersionRet struct {
+ HvVer uint64
+}
+
+// ConnectGetLibVersionRet is libvirt's remote_connect_get_lib_version_ret
+type ConnectGetLibVersionRet struct {
+ LibVer uint64
+}
+
+// ConnectGetHostnameRet is libvirt's remote_connect_get_hostname_ret
+type ConnectGetHostnameRet struct {
+ Hostname string
+}
+
+// ConnectGetSysinfoArgs is libvirt's remote_connect_get_sysinfo_args
+type ConnectGetSysinfoArgs struct {
+ Flags uint32
+}
+
+// ConnectGetSysinfoRet is libvirt's remote_connect_get_sysinfo_ret
+type ConnectGetSysinfoRet struct {
+ Sysinfo string
+}
+
+// ConnectGetUriRet is libvirt's remote_connect_get_uri_ret
+type ConnectGetUriRet struct {
+ Uri string
+}
+
+// ConnectGetMaxVcpusArgs is libvirt's remote_connect_get_max_vcpus_args
+type ConnectGetMaxVcpusArgs struct {
+ Type OptString
+}
+
+// ConnectGetMaxVcpusRet is libvirt's remote_connect_get_max_vcpus_ret
+type ConnectGetMaxVcpusRet struct {
+ MaxVcpus int32
+}
+
+// NodeGetInfoRet is libvirt's remote_node_get_info_ret
+type NodeGetInfoRet struct {
+ Model [32]int8
+ Memory uint64
+ Cpus int32
+ Mhz int32
+ Nodes int32
+ Sockets int32
+ Cores int32
+ Threads int32
+}
+
+// ConnectGetCapabilitiesRet is libvirt's remote_connect_get_capabilities_ret
+type ConnectGetCapabilitiesRet struct {
+ Capabilities string
+}
+
+// ConnectGetDomainCapabilitiesArgs is libvirt's remote_connect_get_domain_capabilities_args
+type ConnectGetDomainCapabilitiesArgs struct {
+ Emulatorbin OptString
+ Arch OptString
+ Machine OptString
+ Virttype OptString
+ Flags uint32
+}
+
+// ConnectGetDomainCapabilitiesRet is libvirt's remote_connect_get_domain_capabilities_ret
+type ConnectGetDomainCapabilitiesRet struct {
+ Capabilities string
+}
+
+// NodeGetCPUStatsArgs is libvirt's remote_node_get_cpu_stats_args
+type NodeGetCPUStatsArgs struct {
+ CPUNum int32
+ Nparams int32
+ Flags uint32
+}
+
+// NodeGetCPUStatsRet is libvirt's remote_node_get_cpu_stats_ret
+type NodeGetCPUStatsRet struct {
+ Params []NodeGetCPUStats
+ Nparams int32
+}
+
+// NodeGetMemoryStatsArgs is libvirt's remote_node_get_memory_stats_args
+type NodeGetMemoryStatsArgs struct {
+ Nparams int32
+ CellNum int32
+ Flags uint32
+}
+
+// NodeGetMemoryStatsRet is libvirt's remote_node_get_memory_stats_ret
+type NodeGetMemoryStatsRet struct {
+ Params []NodeGetMemoryStats
+ Nparams int32
+}
+
+// NodeGetCellsFreeMemoryArgs is libvirt's remote_node_get_cells_free_memory_args
+type NodeGetCellsFreeMemoryArgs struct {
+ StartCell int32
+ Maxcells int32
+}
+
+// NodeGetCellsFreeMemoryRet is libvirt's remote_node_get_cells_free_memory_ret
+type NodeGetCellsFreeMemoryRet struct {
+ Cells []uint64
+}
+
+// NodeGetFreeMemoryRet is libvirt's remote_node_get_free_memory_ret
+type NodeGetFreeMemoryRet struct {
+ FreeMem uint64
+}
+
+// DomainGetSchedulerTypeArgs is libvirt's remote_domain_get_scheduler_type_args
+type DomainGetSchedulerTypeArgs struct {
+ Dom Domain
+}
+
+// DomainGetSchedulerTypeRet is libvirt's remote_domain_get_scheduler_type_ret
+type DomainGetSchedulerTypeRet struct {
+ Type string
+ Nparams int32
+}
+
+// DomainGetSchedulerParametersArgs is libvirt's remote_domain_get_scheduler_parameters_args
+type DomainGetSchedulerParametersArgs struct {
+ Dom Domain
+ Nparams int32
+}
+
+// DomainGetSchedulerParametersRet is libvirt's remote_domain_get_scheduler_parameters_ret
+type DomainGetSchedulerParametersRet struct {
+ Params []TypedParam
+}
+
+// DomainGetSchedulerParametersFlagsArgs is libvirt's remote_domain_get_scheduler_parameters_flags_args
+type DomainGetSchedulerParametersFlagsArgs struct {
+ Dom Domain
+ Nparams int32
+ Flags uint32
+}
+
+// DomainGetSchedulerParametersFlagsRet is libvirt's remote_domain_get_scheduler_parameters_flags_ret
+type DomainGetSchedulerParametersFlagsRet struct {
+ Params []TypedParam
+}
+
+// DomainSetSchedulerParametersArgs is libvirt's remote_domain_set_scheduler_parameters_args
+type DomainSetSchedulerParametersArgs struct {
+ Dom Domain
+ Params []TypedParam
+}
+
+// DomainSetSchedulerParametersFlagsArgs is libvirt's remote_domain_set_scheduler_parameters_flags_args
+type DomainSetSchedulerParametersFlagsArgs struct {
+ Dom Domain
+ Params []TypedParam
+ Flags uint32
+}
+
+// DomainSetBlkioParametersArgs is libvirt's remote_domain_set_blkio_parameters_args
+type DomainSetBlkioParametersArgs struct {
+ Dom Domain
+ Params []TypedParam
+ Flags uint32
+}
+
+// DomainGetBlkioParametersArgs is libvirt's remote_domain_get_blkio_parameters_args
+type DomainGetBlkioParametersArgs struct {
+ Dom Domain
+ Nparams int32
+ Flags uint32
+}
+
+// DomainGetBlkioParametersRet is libvirt's remote_domain_get_blkio_parameters_ret
+type DomainGetBlkioParametersRet struct {
+ Params []TypedParam
+ Nparams int32
+}
+
+// DomainSetMemoryParametersArgs is libvirt's remote_domain_set_memory_parameters_args
+type DomainSetMemoryParametersArgs struct {
+ Dom Domain
+ Params []TypedParam
+ Flags uint32
+}
+
+// DomainGetMemoryParametersArgs is libvirt's remote_domain_get_memory_parameters_args
+type DomainGetMemoryParametersArgs struct {
+ Dom Domain
+ Nparams int32
+ Flags uint32
+}
+
+// DomainGetMemoryParametersRet is libvirt's remote_domain_get_memory_parameters_ret
+type DomainGetMemoryParametersRet struct {
+ Params []TypedParam
+ Nparams int32
+}
+
+// DomainBlockResizeArgs is libvirt's remote_domain_block_resize_args
+type DomainBlockResizeArgs struct {
+ Dom Domain
+ Disk string
+ Size uint64
+ Flags DomainBlockResizeFlags
+}
+
+// DomainSetNumaParametersArgs is libvirt's remote_domain_set_numa_parameters_args
+type DomainSetNumaParametersArgs struct {
+ Dom Domain
+ Params []TypedParam
+ Flags uint32
+}
+
+// DomainGetNumaParametersArgs is libvirt's remote_domain_get_numa_parameters_args
+type DomainGetNumaParametersArgs struct {
+ Dom Domain
+ Nparams int32
+ Flags uint32
+}
+
+// DomainGetNumaParametersRet is libvirt's remote_domain_get_numa_parameters_ret
+type DomainGetNumaParametersRet struct {
+ Params []TypedParam
+ Nparams int32
+}
+
+// DomainSetPerfEventsArgs is libvirt's remote_domain_set_perf_events_args
+type DomainSetPerfEventsArgs struct {
+ Dom Domain
+ Params []TypedParam
+ Flags DomainModificationImpact
+}
+
+// DomainGetPerfEventsArgs is libvirt's remote_domain_get_perf_events_args
+type DomainGetPerfEventsArgs struct {
+ Dom Domain
+ Flags DomainModificationImpact
+}
+
+// DomainGetPerfEventsRet is libvirt's remote_domain_get_perf_events_ret
+type DomainGetPerfEventsRet struct {
+ Params []TypedParam
+}
+
+// DomainBlockStatsArgs is libvirt's remote_domain_block_stats_args
+type DomainBlockStatsArgs struct {
+ Dom Domain
+ Path string
+}
+
+// DomainBlockStatsRet is libvirt's remote_domain_block_stats_ret
+type DomainBlockStatsRet struct {
+ RdReq int64
+ RdBytes int64
+ WrReq int64
+ WrBytes int64
+ Errs int64
+}
+
+// DomainBlockStatsFlagsArgs is libvirt's remote_domain_block_stats_flags_args
+type DomainBlockStatsFlagsArgs struct {
+ Dom Domain
+ Path string
+ Nparams int32
+ Flags uint32
+}
+
+// DomainBlockStatsFlagsRet is libvirt's remote_domain_block_stats_flags_ret
+type DomainBlockStatsFlagsRet struct {
+ Params []TypedParam
+ Nparams int32
+}
+
+// DomainInterfaceStatsArgs is libvirt's remote_domain_interface_stats_args
+type DomainInterfaceStatsArgs struct {
+ Dom Domain
+ Device string
+}
+
+// DomainInterfaceStatsRet is libvirt's remote_domain_interface_stats_ret
+type DomainInterfaceStatsRet struct {
+ RxBytes int64
+ RxPackets int64
+ RxErrs int64
+ RxDrop int64
+ TxBytes int64
+ TxPackets int64
+ TxErrs int64
+ TxDrop int64
+}
+
+// DomainSetInterfaceParametersArgs is libvirt's remote_domain_set_interface_parameters_args
+type DomainSetInterfaceParametersArgs struct {
+ Dom Domain
+ Device string
+ Params []TypedParam
+ Flags uint32
+}
+
+// DomainGetInterfaceParametersArgs is libvirt's remote_domain_get_interface_parameters_args
+type DomainGetInterfaceParametersArgs struct {
+ Dom Domain
+ Device string
+ Nparams int32
+ Flags DomainModificationImpact
+}
+
+// DomainGetInterfaceParametersRet is libvirt's remote_domain_get_interface_parameters_ret
+type DomainGetInterfaceParametersRet struct {
+ Params []TypedParam
+ Nparams int32
+}
+
+// DomainMemoryStatsArgs is libvirt's remote_domain_memory_stats_args
+type DomainMemoryStatsArgs struct {
+ Dom Domain
+ MaxStats uint32
+ Flags uint32
+}
+
+// DomainMemoryStat is libvirt's remote_domain_memory_stat
+type DomainMemoryStat struct {
+ Tag int32
+ Val uint64
+}
+
+// DomainMemoryStatsRet is libvirt's remote_domain_memory_stats_ret
+type DomainMemoryStatsRet struct {
+ Stats []DomainMemoryStat
+}
+
+// DomainBlockPeekArgs is libvirt's remote_domain_block_peek_args
+type DomainBlockPeekArgs struct {
+ Dom Domain
+ Path string
+ Offset uint64
+ Size uint32
+ Flags uint32
+}
+
+// DomainBlockPeekRet is libvirt's remote_domain_block_peek_ret
+type DomainBlockPeekRet struct {
+ Buffer []byte
+}
+
+// DomainMemoryPeekArgs is libvirt's remote_domain_memory_peek_args
+type DomainMemoryPeekArgs struct {
+ Dom Domain
+ Offset uint64
+ Size uint32
+ Flags DomainMemoryFlags
+}
+
+// DomainMemoryPeekRet is libvirt's remote_domain_memory_peek_ret
+type DomainMemoryPeekRet struct {
+ Buffer []byte
+}
+
+// DomainGetBlockInfoArgs is libvirt's remote_domain_get_block_info_args
+type DomainGetBlockInfoArgs struct {
+ Dom Domain
+ Path string
+ Flags uint32
+}
+
+// DomainGetBlockInfoRet is libvirt's remote_domain_get_block_info_ret
+type DomainGetBlockInfoRet struct {
+ Allocation uint64
+ Capacity uint64
+ Physical uint64
+}
+
+// ConnectListDomainsArgs is libvirt's remote_connect_list_domains_args
+type ConnectListDomainsArgs struct {
+ Maxids int32
+}
+
+// ConnectListDomainsRet is libvirt's remote_connect_list_domains_ret
+type ConnectListDomainsRet struct {
+ Ids []int32
+}
+
+// ConnectNumOfDomainsRet is libvirt's remote_connect_num_of_domains_ret
+type ConnectNumOfDomainsRet struct {
+ Num int32
+}
+
+// DomainCreateXMLArgs is libvirt's remote_domain_create_xml_args
+type DomainCreateXMLArgs struct {
+ XMLDesc string
+ Flags DomainCreateFlags
+}
+
+// DomainCreateXMLRet is libvirt's remote_domain_create_xml_ret
+type DomainCreateXMLRet struct {
+ Dom Domain
+}
+
+// DomainCreateXMLWithFilesArgs is libvirt's remote_domain_create_xml_with_files_args
+type DomainCreateXMLWithFilesArgs struct {
+ XMLDesc string
+ Flags DomainCreateFlags
+}
+
+// DomainCreateXMLWithFilesRet is libvirt's remote_domain_create_xml_with_files_ret
+type DomainCreateXMLWithFilesRet struct {
+ Dom Domain
+}
+
+// DomainLookupByIDArgs is libvirt's remote_domain_lookup_by_id_args
+type DomainLookupByIDArgs struct {
+ ID int32
+}
+
+// DomainLookupByIDRet is libvirt's remote_domain_lookup_by_id_ret
+type DomainLookupByIDRet struct {
+ Dom Domain
+}
+
+// DomainLookupByUUIDArgs is libvirt's remote_domain_lookup_by_uuid_args
+type DomainLookupByUUIDArgs struct {
+ UUID UUID
+}
+
+// DomainLookupByUUIDRet is libvirt's remote_domain_lookup_by_uuid_ret
+type DomainLookupByUUIDRet struct {
+ Dom Domain
+}
+
+// DomainLookupByNameArgs is libvirt's remote_domain_lookup_by_name_args
+type DomainLookupByNameArgs struct {
+ Name string
+}
+
+// DomainLookupByNameRet is libvirt's remote_domain_lookup_by_name_ret
+type DomainLookupByNameRet struct {
+ Dom Domain
+}
+
+// DomainSuspendArgs is libvirt's remote_domain_suspend_args
+type DomainSuspendArgs struct {
+ Dom Domain
+}
+
+// DomainResumeArgs is libvirt's remote_domain_resume_args
+type DomainResumeArgs struct {
+ Dom Domain
+}
+
+// DomainPmSuspendForDurationArgs is libvirt's remote_domain_pm_suspend_for_duration_args
+type DomainPmSuspendForDurationArgs struct {
+ Dom Domain
+ Target uint32
+ Duration uint64
+ Flags uint32
+}
+
+// DomainPmWakeupArgs is libvirt's remote_domain_pm_wakeup_args
+type DomainPmWakeupArgs struct {
+ Dom Domain
+ Flags uint32
+}
+
+// DomainShutdownArgs is libvirt's remote_domain_shutdown_args
+type DomainShutdownArgs struct {
+ Dom Domain
+}
+
+// DomainRebootArgs is libvirt's remote_domain_reboot_args
+type DomainRebootArgs struct {
+ Dom Domain
+ Flags DomainRebootFlagValues
+}
+
+// DomainResetArgs is libvirt's remote_domain_reset_args
+type DomainResetArgs struct {
+ Dom Domain
+ Flags uint32
+}
+
+// DomainDestroyArgs is libvirt's remote_domain_destroy_args
+type DomainDestroyArgs struct {
+ Dom Domain
+}
+
+// DomainDestroyFlagsArgs is libvirt's remote_domain_destroy_flags_args
+type DomainDestroyFlagsArgs struct {
+ Dom Domain
+ Flags DomainDestroyFlagsValues
+}
+
+// DomainGetOsTypeArgs is libvirt's remote_domain_get_os_type_args
+type DomainGetOsTypeArgs struct {
+ Dom Domain
+}
+
+// DomainGetOsTypeRet is libvirt's remote_domain_get_os_type_ret
+type DomainGetOsTypeRet struct {
+ Type string
+}
+
+// DomainGetMaxMemoryArgs is libvirt's remote_domain_get_max_memory_args
+type DomainGetMaxMemoryArgs struct {
+ Dom Domain
+}
+
+// DomainGetMaxMemoryRet is libvirt's remote_domain_get_max_memory_ret
+type DomainGetMaxMemoryRet struct {
+ Memory uint64
+}
+
+// DomainSetMaxMemoryArgs is libvirt's remote_domain_set_max_memory_args
+type DomainSetMaxMemoryArgs struct {
+ Dom Domain
+ Memory uint64
+}
+
+// DomainSetMemoryArgs is libvirt's remote_domain_set_memory_args
+type DomainSetMemoryArgs struct {
+ Dom Domain
+ Memory uint64
+}
+
+// DomainSetMemoryFlagsArgs is libvirt's remote_domain_set_memory_flags_args
+type DomainSetMemoryFlagsArgs struct {
+ Dom Domain
+ Memory uint64
+ Flags uint32
+}
+
+// DomainSetMemoryStatsPeriodArgs is libvirt's remote_domain_set_memory_stats_period_args
+type DomainSetMemoryStatsPeriodArgs struct {
+ Dom Domain
+ Period int32
+ Flags DomainMemoryModFlags
+}
+
+// DomainGetInfoArgs is libvirt's remote_domain_get_info_args
+type DomainGetInfoArgs struct {
+ Dom Domain
+}
+
+// DomainGetInfoRet is libvirt's remote_domain_get_info_ret
+type DomainGetInfoRet struct {
+ State uint8
+ MaxMem uint64
+ Memory uint64
+ NrVirtCPU uint16
+ CPUTime uint64
+}
+
+// DomainSaveArgs is libvirt's remote_domain_save_args
+type DomainSaveArgs struct {
+ Dom Domain
+ To string
+}
+
+// DomainSaveFlagsArgs is libvirt's remote_domain_save_flags_args
+type DomainSaveFlagsArgs struct {
+ Dom Domain
+ To string
+ Dxml OptString
+ Flags uint32
+}
+
+// DomainRestoreArgs is libvirt's remote_domain_restore_args
+type DomainRestoreArgs struct {
+ From string
+}
+
+// DomainRestoreFlagsArgs is libvirt's remote_domain_restore_flags_args
+type DomainRestoreFlagsArgs struct {
+ From string
+ Dxml OptString
+ Flags uint32
+}
+
+// DomainSaveImageGetXMLDescArgs is libvirt's remote_domain_save_image_get_xml_desc_args
+type DomainSaveImageGetXMLDescArgs struct {
+ File string
+ Flags uint32
+}
+
+// DomainSaveImageGetXMLDescRet is libvirt's remote_domain_save_image_get_xml_desc_ret
+type DomainSaveImageGetXMLDescRet struct {
+ XML string
+}
+
+// DomainSaveImageDefineXMLArgs is libvirt's remote_domain_save_image_define_xml_args
+type DomainSaveImageDefineXMLArgs struct {
+ File string
+ Dxml string
+ Flags uint32
+}
+
+// DomainCoreDumpArgs is libvirt's remote_domain_core_dump_args
+type DomainCoreDumpArgs struct {
+ Dom Domain
+ To string
+ Flags DomainCoreDumpFlags
+}
+
+// DomainCoreDumpWithFormatArgs is libvirt's remote_domain_core_dump_with_format_args
+type DomainCoreDumpWithFormatArgs struct {
+ Dom Domain
+ To string
+ Dumpformat uint32
+ Flags DomainCoreDumpFlags
+}
+
+// DomainScreenshotArgs is libvirt's remote_domain_screenshot_args
+type DomainScreenshotArgs struct {
+ Dom Domain
+ Screen uint32
+ Flags uint32
+}
+
+// DomainScreenshotRet is libvirt's remote_domain_screenshot_ret
+type DomainScreenshotRet struct {
+ Mime OptString
+}
+
+// DomainGetXMLDescArgs is libvirt's remote_domain_get_xml_desc_args
+type DomainGetXMLDescArgs struct {
+ Dom Domain
+ Flags DomainXMLFlags
+}
+
+// DomainGetXMLDescRet is libvirt's remote_domain_get_xml_desc_ret
+type DomainGetXMLDescRet struct {
+ XML string
+}
+
+// DomainMigratePrepareArgs is libvirt's remote_domain_migrate_prepare_args
+type DomainMigratePrepareArgs struct {
+ UriIn OptString
+ Flags uint64
+ Dname OptString
+ Resource uint64
+}
+
+// DomainMigratePrepareRet is libvirt's remote_domain_migrate_prepare_ret
+type DomainMigratePrepareRet struct {
+ Cookie []byte
+ UriOut OptString
+}
+
+// DomainMigratePerformArgs is libvirt's remote_domain_migrate_perform_args
+type DomainMigratePerformArgs struct {
+ Dom Domain
+ Cookie []byte
+ Uri string
+ Flags uint64
+ Dname OptString
+ Resource uint64
+}
+
+// DomainMigrateFinishArgs is libvirt's remote_domain_migrate_finish_args
+type DomainMigrateFinishArgs struct {
+ Dname string
+ Cookie []byte
+ Uri string
+ Flags uint64
+}
+
+// DomainMigrateFinishRet is libvirt's remote_domain_migrate_finish_ret
+type DomainMigrateFinishRet struct {
+ Ddom Domain
+}
+
+// DomainMigratePrepare2Args is libvirt's remote_domain_migrate_prepare2_args
+type DomainMigratePrepare2Args struct {
+ UriIn OptString
+ Flags uint64
+ Dname OptString
+ Resource uint64
+ DomXML string
+}
+
+// DomainMigratePrepare2Ret is libvirt's remote_domain_migrate_prepare2_ret
+type DomainMigratePrepare2Ret struct {
+ Cookie []byte
+ UriOut OptString
+}
+
+// DomainMigrateFinish2Args is libvirt's remote_domain_migrate_finish2_args
+type DomainMigrateFinish2Args struct {
+ Dname string
+ Cookie []byte
+ Uri string
+ Flags uint64
+ Retcode int32
+}
+
+// DomainMigrateFinish2Ret is libvirt's remote_domain_migrate_finish2_ret
+type DomainMigrateFinish2Ret struct {
+ Ddom Domain
+}
+
+// ConnectListDefinedDomainsArgs is libvirt's remote_connect_list_defined_domains_args
+type ConnectListDefinedDomainsArgs struct {
+ Maxnames int32
+}
+
+// ConnectListDefinedDomainsRet is libvirt's remote_connect_list_defined_domains_ret
+type ConnectListDefinedDomainsRet struct {
+ Names []string
+}
+
+// ConnectNumOfDefinedDomainsRet is libvirt's remote_connect_num_of_defined_domains_ret
+type ConnectNumOfDefinedDomainsRet struct {
+ Num int32
+}
+
+// DomainCreateArgs is libvirt's remote_domain_create_args
+type DomainCreateArgs struct {
+ Dom Domain
+}
+
+// DomainCreateWithFlagsArgs is libvirt's remote_domain_create_with_flags_args
+type DomainCreateWithFlagsArgs struct {
+ Dom Domain
+ Flags uint32
+}
+
+// DomainCreateWithFlagsRet is libvirt's remote_domain_create_with_flags_ret
+type DomainCreateWithFlagsRet struct {
+ Dom Domain
+}
+
+// DomainCreateWithFilesArgs is libvirt's remote_domain_create_with_files_args
+type DomainCreateWithFilesArgs struct {
+ Dom Domain
+ Flags DomainCreateFlags
+}
+
+// DomainCreateWithFilesRet is libvirt's remote_domain_create_with_files_ret
+type DomainCreateWithFilesRet struct {
+ Dom Domain
+}
+
+// DomainDefineXMLArgs is libvirt's remote_domain_define_xml_args
+type DomainDefineXMLArgs struct {
+ XML string
+}
+
+// DomainDefineXMLRet is libvirt's remote_domain_define_xml_ret
+type DomainDefineXMLRet struct {
+ Dom Domain
+}
+
+// DomainDefineXMLFlagsArgs is libvirt's remote_domain_define_xml_flags_args
+type DomainDefineXMLFlagsArgs struct {
+ XML string
+ Flags DomainDefineFlags
+}
+
+// DomainDefineXMLFlagsRet is libvirt's remote_domain_define_xml_flags_ret
+type DomainDefineXMLFlagsRet struct {
+ Dom Domain
+}
+
+// DomainUndefineArgs is libvirt's remote_domain_undefine_args
+type DomainUndefineArgs struct {
+ Dom Domain
+}
+
+// DomainUndefineFlagsArgs is libvirt's remote_domain_undefine_flags_args
+type DomainUndefineFlagsArgs struct {
+ Dom Domain
+ Flags DomainUndefineFlagsValues
+}
+
+// DomainInjectNmiArgs is libvirt's remote_domain_inject_nmi_args
+type DomainInjectNmiArgs struct {
+ Dom Domain
+ Flags uint32
+}
+
+// DomainSendKeyArgs is libvirt's remote_domain_send_key_args
+type DomainSendKeyArgs struct {
+ Dom Domain
+ Codeset uint32
+ Holdtime uint32
+ Keycodes []uint32
+ Flags uint32
+}
+
+// DomainSendProcessSignalArgs is libvirt's remote_domain_send_process_signal_args
+type DomainSendProcessSignalArgs struct {
+ Dom Domain
+ PidValue int64
+ Signum uint32
+ Flags uint32
+}
+
+// DomainSetVcpusArgs is libvirt's remote_domain_set_vcpus_args
+type DomainSetVcpusArgs struct {
+ Dom Domain
+ Nvcpus uint32
+}
+
+// DomainSetVcpusFlagsArgs is libvirt's remote_domain_set_vcpus_flags_args
+type DomainSetVcpusFlagsArgs struct {
+ Dom Domain
+ Nvcpus uint32
+ Flags uint32
+}
+
+// DomainGetVcpusFlagsArgs is libvirt's remote_domain_get_vcpus_flags_args
+type DomainGetVcpusFlagsArgs struct {
+ Dom Domain
+ Flags uint32
+}
+
+// DomainGetVcpusFlagsRet is libvirt's remote_domain_get_vcpus_flags_ret
+type DomainGetVcpusFlagsRet struct {
+ Num int32
+}
+
+// DomainPinVcpuArgs is libvirt's remote_domain_pin_vcpu_args
+type DomainPinVcpuArgs struct {
+ Dom Domain
+ Vcpu uint32
+ Cpumap []byte
+}
+
+// DomainPinVcpuFlagsArgs is libvirt's remote_domain_pin_vcpu_flags_args
+type DomainPinVcpuFlagsArgs struct {
+ Dom Domain
+ Vcpu uint32
+ Cpumap []byte
+ Flags uint32
+}
+
+// DomainGetVcpuPinInfoArgs is libvirt's remote_domain_get_vcpu_pin_info_args
+type DomainGetVcpuPinInfoArgs struct {
+ Dom Domain
+ Ncpumaps int32
+ Maplen int32
+ Flags uint32
+}
+
+// DomainGetVcpuPinInfoRet is libvirt's remote_domain_get_vcpu_pin_info_ret
+type DomainGetVcpuPinInfoRet struct {
+ Cpumaps []byte
+ Num int32
+}
+
+// DomainPinEmulatorArgs is libvirt's remote_domain_pin_emulator_args
+type DomainPinEmulatorArgs struct {
+ Dom Domain
+ Cpumap []byte
+ Flags DomainModificationImpact
+}
+
+// DomainGetEmulatorPinInfoArgs is libvirt's remote_domain_get_emulator_pin_info_args
+type DomainGetEmulatorPinInfoArgs struct {
+ Dom Domain
+ Maplen int32
+ Flags DomainModificationImpact
+}
+
+// DomainGetEmulatorPinInfoRet is libvirt's remote_domain_get_emulator_pin_info_ret
+type DomainGetEmulatorPinInfoRet struct {
+ Cpumaps []byte
+ Ret int32
+}
+
+// DomainGetVcpusArgs is libvirt's remote_domain_get_vcpus_args
+type DomainGetVcpusArgs struct {
+ Dom Domain
+ Maxinfo int32
+ Maplen int32
+}
+
+// DomainGetVcpusRet is libvirt's remote_domain_get_vcpus_ret
+type DomainGetVcpusRet struct {
+ Info []VcpuInfo
+ Cpumaps []byte
+}
+
+// DomainGetMaxVcpusArgs is libvirt's remote_domain_get_max_vcpus_args
+type DomainGetMaxVcpusArgs struct {
+ Dom Domain
+}
+
+// DomainGetMaxVcpusRet is libvirt's remote_domain_get_max_vcpus_ret
+type DomainGetMaxVcpusRet struct {
+ Num int32
+}
+
+// DomainIothreadInfo is libvirt's remote_domain_iothread_info
+type DomainIothreadInfo struct {
+ IothreadID uint32
+ Cpumap []byte
+}
+
+// DomainGetIothreadInfoArgs is libvirt's remote_domain_get_iothread_info_args
+type DomainGetIothreadInfoArgs struct {
+ Dom Domain
+ Flags DomainModificationImpact
+}
+
+// DomainGetIothreadInfoRet is libvirt's remote_domain_get_iothread_info_ret
+type DomainGetIothreadInfoRet struct {
+ Info []DomainIothreadInfo
+ Ret uint32
+}
+
+// DomainPinIothreadArgs is libvirt's remote_domain_pin_iothread_args
+type DomainPinIothreadArgs struct {
+ Dom Domain
+ IothreadsID uint32
+ Cpumap []byte
+ Flags DomainModificationImpact
+}
+
+// DomainAddIothreadArgs is libvirt's remote_domain_add_iothread_args
+type DomainAddIothreadArgs struct {
+ Dom Domain
+ IothreadID uint32
+ Flags DomainModificationImpact
+}
+
+// DomainDelIothreadArgs is libvirt's remote_domain_del_iothread_args
+type DomainDelIothreadArgs struct {
+ Dom Domain
+ IothreadID uint32
+ Flags DomainModificationImpact
+}
+
+// DomainSetIothreadParamsArgs is libvirt's remote_domain_set_iothread_params_args
+type DomainSetIothreadParamsArgs struct {
+ Dom Domain
+ IothreadID uint32
+ Params []TypedParam
+ Flags uint32
+}
+
+// DomainGetSecurityLabelArgs is libvirt's remote_domain_get_security_label_args
+type DomainGetSecurityLabelArgs struct {
+ Dom Domain
+}
+
+// DomainGetSecurityLabelRet is libvirt's remote_domain_get_security_label_ret
+type DomainGetSecurityLabelRet struct {
+ Label []int8
+ Enforcing int32
+}
+
+// DomainGetSecurityLabelListArgs is libvirt's remote_domain_get_security_label_list_args
+type DomainGetSecurityLabelListArgs struct {
+ Dom Domain
+}
+
+// DomainGetSecurityLabelListRet is libvirt's remote_domain_get_security_label_list_ret
+type DomainGetSecurityLabelListRet struct {
+ Labels []DomainGetSecurityLabelRet
+ Ret int32
+}
+
+// NodeGetSecurityModelRet is libvirt's remote_node_get_security_model_ret
+type NodeGetSecurityModelRet struct {
+ Model []int8
+ Doi []int8
+}
+
+// DomainAttachDeviceArgs is libvirt's remote_domain_attach_device_args
+type DomainAttachDeviceArgs struct {
+ Dom Domain
+ XML string
+}
+
+// DomainAttachDeviceFlagsArgs is libvirt's remote_domain_attach_device_flags_args
+type DomainAttachDeviceFlagsArgs struct {
+ Dom Domain
+ XML string
+ Flags uint32
+}
+
+// DomainDetachDeviceArgs is libvirt's remote_domain_detach_device_args
+type DomainDetachDeviceArgs struct {
+ Dom Domain
+ XML string
+}
+
+// DomainDetachDeviceFlagsArgs is libvirt's remote_domain_detach_device_flags_args
+type DomainDetachDeviceFlagsArgs struct {
+ Dom Domain
+ XML string
+ Flags uint32
+}
+
+// DomainUpdateDeviceFlagsArgs is libvirt's remote_domain_update_device_flags_args
+type DomainUpdateDeviceFlagsArgs struct {
+ Dom Domain
+ XML string
+ Flags DomainDeviceModifyFlags
+}
+
+// DomainDetachDeviceAliasArgs is libvirt's remote_domain_detach_device_alias_args
+type DomainDetachDeviceAliasArgs struct {
+ Dom Domain
+ Alias string
+ Flags uint32
+}
+
+// DomainGetAutostartArgs is libvirt's remote_domain_get_autostart_args
+type DomainGetAutostartArgs struct {
+ Dom Domain
+}
+
+// DomainGetAutostartRet is libvirt's remote_domain_get_autostart_ret
+type DomainGetAutostartRet struct {
+ Autostart int32
+}
+
+// DomainSetAutostartArgs is libvirt's remote_domain_set_autostart_args
+type DomainSetAutostartArgs struct {
+ Dom Domain
+ Autostart int32
+}
+
+// DomainSetMetadataArgs is libvirt's remote_domain_set_metadata_args
+type DomainSetMetadataArgs struct {
+ Dom Domain
+ Type int32
+ Metadata OptString
+ Key OptString
+ Uri OptString
+ Flags DomainModificationImpact
+}
+
+// DomainGetMetadataArgs is libvirt's remote_domain_get_metadata_args
+type DomainGetMetadataArgs struct {
+ Dom Domain
+ Type int32
+ Uri OptString
+ Flags DomainModificationImpact
+}
+
+// DomainGetMetadataRet is libvirt's remote_domain_get_metadata_ret
+type DomainGetMetadataRet struct {
+ Metadata string
+}
+
+// DomainBlockJobAbortArgs is libvirt's remote_domain_block_job_abort_args
+type DomainBlockJobAbortArgs struct {
+ Dom Domain
+ Path string
+ Flags DomainBlockJobAbortFlags
+}
+
+// DomainGetBlockJobInfoArgs is libvirt's remote_domain_get_block_job_info_args
+type DomainGetBlockJobInfoArgs struct {
+ Dom Domain
+ Path string
+ Flags uint32
+}
+
+// DomainGetBlockJobInfoRet is libvirt's remote_domain_get_block_job_info_ret
+type DomainGetBlockJobInfoRet struct {
+ Found int32
+ Type int32
+ Bandwidth uint64
+ Cur uint64
+ End uint64
+}
+
+// DomainBlockJobSetSpeedArgs is libvirt's remote_domain_block_job_set_speed_args
+type DomainBlockJobSetSpeedArgs struct {
+ Dom Domain
+ Path string
+ Bandwidth uint64
+ Flags DomainBlockJobSetSpeedFlags
+}
+
+// DomainBlockPullArgs is libvirt's remote_domain_block_pull_args
+type DomainBlockPullArgs struct {
+ Dom Domain
+ Path string
+ Bandwidth uint64
+ Flags DomainBlockPullFlags
+}
+
+// DomainBlockRebaseArgs is libvirt's remote_domain_block_rebase_args
+type DomainBlockRebaseArgs struct {
+ Dom Domain
+ Path string
+ Base OptString
+ Bandwidth uint64
+ Flags DomainBlockRebaseFlags
+}
+
+// DomainBlockCopyArgs is libvirt's remote_domain_block_copy_args
+type DomainBlockCopyArgs struct {
+ Dom Domain
+ Path string
+ Destxml string
+ Params []TypedParam
+ Flags DomainBlockCopyFlags
+}
+
+// DomainBlockCommitArgs is libvirt's remote_domain_block_commit_args
+type DomainBlockCommitArgs struct {
+ Dom Domain
+ Disk string
+ Base OptString
+ Top OptString
+ Bandwidth uint64
+ Flags DomainBlockCommitFlags
+}
+
+// DomainSetBlockIOTuneArgs is libvirt's remote_domain_set_block_io_tune_args
+type DomainSetBlockIOTuneArgs struct {
+ Dom Domain
+ Disk string
+ Params []TypedParam
+ Flags uint32
+}
+
+// DomainGetBlockIOTuneArgs is libvirt's remote_domain_get_block_io_tune_args
+type DomainGetBlockIOTuneArgs struct {
+ Dom Domain
+ Disk OptString
+ Nparams int32
+ Flags uint32
+}
+
+// DomainGetBlockIOTuneRet is libvirt's remote_domain_get_block_io_tune_ret
+type DomainGetBlockIOTuneRet struct {
+ Params []TypedParam
+ Nparams int32
+}
+
+// DomainGetCPUStatsArgs is libvirt's remote_domain_get_cpu_stats_args
+type DomainGetCPUStatsArgs struct {
+ Dom Domain
+ Nparams uint32
+ StartCPU int32
+ Ncpus uint32
+ Flags TypedParameterFlags
+}
+
+// DomainGetCPUStatsRet is libvirt's remote_domain_get_cpu_stats_ret
+type DomainGetCPUStatsRet struct {
+ Params []TypedParam
+ Nparams int32
+}
+
+// DomainGetHostnameArgs is libvirt's remote_domain_get_hostname_args
+type DomainGetHostnameArgs struct {
+ Dom Domain
+ Flags DomainGetHostnameFlags
+}
+
+// DomainGetHostnameRet is libvirt's remote_domain_get_hostname_ret
+type DomainGetHostnameRet struct {
+ Hostname string
+}
+
+// ConnectNumOfNetworksRet is libvirt's remote_connect_num_of_networks_ret
+type ConnectNumOfNetworksRet struct {
+ Num int32
+}
+
+// ConnectListNetworksArgs is libvirt's remote_connect_list_networks_args
+type ConnectListNetworksArgs struct {
+ Maxnames int32
+}
+
+// ConnectListNetworksRet is libvirt's remote_connect_list_networks_ret
+type ConnectListNetworksRet struct {
+ Names []string
+}
+
+// ConnectNumOfDefinedNetworksRet is libvirt's remote_connect_num_of_defined_networks_ret
+type ConnectNumOfDefinedNetworksRet struct {
+ Num int32
+}
+
+// ConnectListDefinedNetworksArgs is libvirt's remote_connect_list_defined_networks_args
+type ConnectListDefinedNetworksArgs struct {
+ Maxnames int32
+}
+
+// ConnectListDefinedNetworksRet is libvirt's remote_connect_list_defined_networks_ret
+type ConnectListDefinedNetworksRet struct {
+ Names []string
+}
+
+// NetworkLookupByUUIDArgs is libvirt's remote_network_lookup_by_uuid_args
+type NetworkLookupByUUIDArgs struct {
+ UUID UUID
+}
+
+// NetworkLookupByUUIDRet is libvirt's remote_network_lookup_by_uuid_ret
+type NetworkLookupByUUIDRet struct {
+ Net Network
+}
+
+// NetworkLookupByNameArgs is libvirt's remote_network_lookup_by_name_args
+type NetworkLookupByNameArgs struct {
+ Name string
+}
+
+// NetworkLookupByNameRet is libvirt's remote_network_lookup_by_name_ret
+type NetworkLookupByNameRet struct {
+ Net Network
+}
+
+// NetworkCreateXMLArgs is libvirt's remote_network_create_xml_args
+type NetworkCreateXMLArgs struct {
+ XML string
+}
+
+// NetworkCreateXMLRet is libvirt's remote_network_create_xml_ret
+type NetworkCreateXMLRet struct {
+ Net Network
+}
+
+// NetworkCreateXMLFlagsArgs is libvirt's remote_network_create_xml_flags_args
+type NetworkCreateXMLFlagsArgs struct {
+ XML string
+ Flags uint32
+}
+
+// NetworkCreateXMLFlagsRet is libvirt's remote_network_create_xml_flags_ret
+type NetworkCreateXMLFlagsRet struct {
+ Net Network
+}
+
+// NetworkDefineXMLArgs is libvirt's remote_network_define_xml_args
+type NetworkDefineXMLArgs struct {
+ XML string
+}
+
+// NetworkDefineXMLRet is libvirt's remote_network_define_xml_ret
+type NetworkDefineXMLRet struct {
+ Net Network
+}
+
+// NetworkDefineXMLFlagsArgs is libvirt's remote_network_define_xml_flags_args
+type NetworkDefineXMLFlagsArgs struct {
+ XML string
+ Flags uint32
+}
+
+// NetworkDefineXMLFlagsRet is libvirt's remote_network_define_xml_flags_ret
+type NetworkDefineXMLFlagsRet struct {
+ Net Network
+}
+
+// NetworkUndefineArgs is libvirt's remote_network_undefine_args
+type NetworkUndefineArgs struct {
+ Net Network
+}
+
+// NetworkUpdateArgs is libvirt's remote_network_update_args
+type NetworkUpdateArgs struct {
+ Net Network
+ Command uint32
+ Section uint32
+ ParentIndex int32
+ XML string
+ Flags NetworkUpdateFlags
+}
+
+// NetworkCreateArgs is libvirt's remote_network_create_args
+type NetworkCreateArgs struct {
+ Net Network
+}
+
+// NetworkDestroyArgs is libvirt's remote_network_destroy_args
+type NetworkDestroyArgs struct {
+ Net Network
+}
+
+// NetworkGetXMLDescArgs is libvirt's remote_network_get_xml_desc_args
+type NetworkGetXMLDescArgs struct {
+ Net Network
+ Flags uint32
+}
+
+// NetworkGetXMLDescRet is libvirt's remote_network_get_xml_desc_ret
+type NetworkGetXMLDescRet struct {
+ XML string
+}
+
+// NetworkGetBridgeNameArgs is libvirt's remote_network_get_bridge_name_args
+type NetworkGetBridgeNameArgs struct {
+ Net Network
+}
+
+// NetworkGetBridgeNameRet is libvirt's remote_network_get_bridge_name_ret
+type NetworkGetBridgeNameRet struct {
+ Name string
+}
+
+// NetworkGetAutostartArgs is libvirt's remote_network_get_autostart_args
+type NetworkGetAutostartArgs struct {
+ Net Network
+}
+
+// NetworkGetAutostartRet is libvirt's remote_network_get_autostart_ret
+type NetworkGetAutostartRet struct {
+ Autostart int32
+}
+
+// NetworkSetAutostartArgs is libvirt's remote_network_set_autostart_args
+type NetworkSetAutostartArgs struct {
+ Net Network
+ Autostart int32
+}
+
+// ConnectNumOfNwfiltersRet is libvirt's remote_connect_num_of_nwfilters_ret
+type ConnectNumOfNwfiltersRet struct {
+ Num int32
+}
+
+// ConnectListNwfiltersArgs is libvirt's remote_connect_list_nwfilters_args
+type ConnectListNwfiltersArgs struct {
+ Maxnames int32
+}
+
+// ConnectListNwfiltersRet is libvirt's remote_connect_list_nwfilters_ret
+type ConnectListNwfiltersRet struct {
+ Names []string
+}
+
+// NwfilterLookupByUUIDArgs is libvirt's remote_nwfilter_lookup_by_uuid_args
+type NwfilterLookupByUUIDArgs struct {
+ UUID UUID
+}
+
+// NwfilterLookupByUUIDRet is libvirt's remote_nwfilter_lookup_by_uuid_ret
+type NwfilterLookupByUUIDRet struct {
+ OptNwfilter Nwfilter
+}
+
+// NwfilterLookupByNameArgs is libvirt's remote_nwfilter_lookup_by_name_args
+type NwfilterLookupByNameArgs struct {
+ Name string
+}
+
+// NwfilterLookupByNameRet is libvirt's remote_nwfilter_lookup_by_name_ret
+type NwfilterLookupByNameRet struct {
+ OptNwfilter Nwfilter
+}
+
+// NwfilterDefineXMLArgs is libvirt's remote_nwfilter_define_xml_args
+type NwfilterDefineXMLArgs struct {
+ XML string
+}
+
+// NwfilterDefineXMLRet is libvirt's remote_nwfilter_define_xml_ret
+type NwfilterDefineXMLRet struct {
+ OptNwfilter Nwfilter
+}
+
+// NwfilterDefineXMLFlagsArgs is libvirt's remote_nwfilter_define_xml_flags_args
+type NwfilterDefineXMLFlagsArgs struct {
+ XML string
+ Flags uint32
+}
+
+// NwfilterDefineXMLFlagsRet is libvirt's remote_nwfilter_define_xml_flags_ret
+type NwfilterDefineXMLFlagsRet struct {
+ OptNwfilter Nwfilter
+}
+
+// NwfilterUndefineArgs is libvirt's remote_nwfilter_undefine_args
+type NwfilterUndefineArgs struct {
+ OptNwfilter Nwfilter
+}
+
+// NwfilterGetXMLDescArgs is libvirt's remote_nwfilter_get_xml_desc_args
+type NwfilterGetXMLDescArgs struct {
+ OptNwfilter Nwfilter
+ Flags uint32
+}
+
+// NwfilterGetXMLDescRet is libvirt's remote_nwfilter_get_xml_desc_ret
+type NwfilterGetXMLDescRet struct {
+ XML string
+}
+
+// ConnectNumOfInterfacesRet is libvirt's remote_connect_num_of_interfaces_ret
+type ConnectNumOfInterfacesRet struct {
+ Num int32
+}
+
+// ConnectListInterfacesArgs is libvirt's remote_connect_list_interfaces_args
+type ConnectListInterfacesArgs struct {
+ Maxnames int32
+}
+
+// ConnectListInterfacesRet is libvirt's remote_connect_list_interfaces_ret
+type ConnectListInterfacesRet struct {
+ Names []string
+}
+
+// ConnectNumOfDefinedInterfacesRet is libvirt's remote_connect_num_of_defined_interfaces_ret
+type ConnectNumOfDefinedInterfacesRet struct {
+ Num int32
+}
+
+// ConnectListDefinedInterfacesArgs is libvirt's remote_connect_list_defined_interfaces_args
+type ConnectListDefinedInterfacesArgs struct {
+ Maxnames int32
+}
+
+// ConnectListDefinedInterfacesRet is libvirt's remote_connect_list_defined_interfaces_ret
+type ConnectListDefinedInterfacesRet struct {
+ Names []string
+}
+
+// InterfaceLookupByNameArgs is libvirt's remote_interface_lookup_by_name_args
+type InterfaceLookupByNameArgs struct {
+ Name string
+}
+
+// InterfaceLookupByNameRet is libvirt's remote_interface_lookup_by_name_ret
+type InterfaceLookupByNameRet struct {
+ Iface Interface
+}
+
+// InterfaceLookupByMacStringArgs is libvirt's remote_interface_lookup_by_mac_string_args
+type InterfaceLookupByMacStringArgs struct {
+ Mac string
+}
+
+// InterfaceLookupByMacStringRet is libvirt's remote_interface_lookup_by_mac_string_ret
+type InterfaceLookupByMacStringRet struct {
+ Iface Interface
+}
+
+// InterfaceGetXMLDescArgs is libvirt's remote_interface_get_xml_desc_args
+type InterfaceGetXMLDescArgs struct {
+ Iface Interface
+ Flags uint32
+}
+
+// InterfaceGetXMLDescRet is libvirt's remote_interface_get_xml_desc_ret
+type InterfaceGetXMLDescRet struct {
+ XML string
+}
+
+// InterfaceDefineXMLArgs is libvirt's remote_interface_define_xml_args
+type InterfaceDefineXMLArgs struct {
+ XML string
+ Flags uint32
+}
+
+// InterfaceDefineXMLRet is libvirt's remote_interface_define_xml_ret
+type InterfaceDefineXMLRet struct {
+ Iface Interface
+}
+
+// InterfaceUndefineArgs is libvirt's remote_interface_undefine_args
+type InterfaceUndefineArgs struct {
+ Iface Interface
+}
+
+// InterfaceCreateArgs is libvirt's remote_interface_create_args
+type InterfaceCreateArgs struct {
+ Iface Interface
+ Flags uint32
+}
+
+// InterfaceDestroyArgs is libvirt's remote_interface_destroy_args
+type InterfaceDestroyArgs struct {
+ Iface Interface
+ Flags uint32
+}
+
+// InterfaceChangeBeginArgs is libvirt's remote_interface_change_begin_args
+type InterfaceChangeBeginArgs struct {
+ Flags uint32
+}
+
+// InterfaceChangeCommitArgs is libvirt's remote_interface_change_commit_args
+type InterfaceChangeCommitArgs struct {
+ Flags uint32
+}
+
+// InterfaceChangeRollbackArgs is libvirt's remote_interface_change_rollback_args
+type InterfaceChangeRollbackArgs struct {
+ Flags uint32
+}
+
+// AuthListRet is libvirt's remote_auth_list_ret
+type AuthListRet struct {
+ Types []AuthType
+}
+
+// AuthSaslInitRet is libvirt's remote_auth_sasl_init_ret
+type AuthSaslInitRet struct {
+ Mechlist string
+}
+
+// AuthSaslStartArgs is libvirt's remote_auth_sasl_start_args
+type AuthSaslStartArgs struct {
+ Mech string
+ Nil int32
+ Data []int8
+}
+
+// AuthSaslStartRet is libvirt's remote_auth_sasl_start_ret
+type AuthSaslStartRet struct {
+ Complete int32
+ Nil int32
+ Data []int8
+}
+
+// AuthSaslStepArgs is libvirt's remote_auth_sasl_step_args
+type AuthSaslStepArgs struct {
+ Nil int32
+ Data []int8
+}
+
+// AuthSaslStepRet is libvirt's remote_auth_sasl_step_ret
+type AuthSaslStepRet struct {
+ Complete int32
+ Nil int32
+ Data []int8
+}
+
+// AuthPolkitRet is libvirt's remote_auth_polkit_ret
+type AuthPolkitRet struct {
+ Complete int32
+}
+
+// ConnectNumOfStoragePoolsRet is libvirt's remote_connect_num_of_storage_pools_ret
+type ConnectNumOfStoragePoolsRet struct {
+ Num int32
+}
+
+// ConnectListStoragePoolsArgs is libvirt's remote_connect_list_storage_pools_args
+type ConnectListStoragePoolsArgs struct {
+ Maxnames int32
+}
+
+// ConnectListStoragePoolsRet is libvirt's remote_connect_list_storage_pools_ret
+type ConnectListStoragePoolsRet struct {
+ Names []string
+}
+
+// ConnectNumOfDefinedStoragePoolsRet is libvirt's remote_connect_num_of_defined_storage_pools_ret
+type ConnectNumOfDefinedStoragePoolsRet struct {
+ Num int32
+}
+
+// ConnectListDefinedStoragePoolsArgs is libvirt's remote_connect_list_defined_storage_pools_args
+type ConnectListDefinedStoragePoolsArgs struct {
+ Maxnames int32
+}
+
+// ConnectListDefinedStoragePoolsRet is libvirt's remote_connect_list_defined_storage_pools_ret
+type ConnectListDefinedStoragePoolsRet struct {
+ Names []string
+}
+
+// ConnectFindStoragePoolSourcesArgs is libvirt's remote_connect_find_storage_pool_sources_args
+type ConnectFindStoragePoolSourcesArgs struct {
+ Type string
+ SrcSpec OptString
+ Flags uint32
+}
+
+// ConnectFindStoragePoolSourcesRet is libvirt's remote_connect_find_storage_pool_sources_ret
+type ConnectFindStoragePoolSourcesRet struct {
+ XML string
+}
+
+// StoragePoolLookupByUUIDArgs is libvirt's remote_storage_pool_lookup_by_uuid_args
+type StoragePoolLookupByUUIDArgs struct {
+ UUID UUID
+}
+
+// StoragePoolLookupByUUIDRet is libvirt's remote_storage_pool_lookup_by_uuid_ret
+type StoragePoolLookupByUUIDRet struct {
+ Pool StoragePool
+}
+
+// StoragePoolLookupByNameArgs is libvirt's remote_storage_pool_lookup_by_name_args
+type StoragePoolLookupByNameArgs struct {
+ Name string
+}
+
+// StoragePoolLookupByNameRet is libvirt's remote_storage_pool_lookup_by_name_ret
+type StoragePoolLookupByNameRet struct {
+ Pool StoragePool
+}
+
+// StoragePoolLookupByVolumeArgs is libvirt's remote_storage_pool_lookup_by_volume_args
+type StoragePoolLookupByVolumeArgs struct {
+ Vol StorageVol
+}
+
+// StoragePoolLookupByVolumeRet is libvirt's remote_storage_pool_lookup_by_volume_ret
+type StoragePoolLookupByVolumeRet struct {
+ Pool StoragePool
+}
+
+// StoragePoolLookupByTargetPathArgs is libvirt's remote_storage_pool_lookup_by_target_path_args
+type StoragePoolLookupByTargetPathArgs struct {
+ Path string
+}
+
+// StoragePoolLookupByTargetPathRet is libvirt's remote_storage_pool_lookup_by_target_path_ret
+type StoragePoolLookupByTargetPathRet struct {
+ Pool StoragePool
+}
+
+// StoragePoolCreateXMLArgs is libvirt's remote_storage_pool_create_xml_args
+type StoragePoolCreateXMLArgs struct {
+ XML string
+ Flags StoragePoolCreateFlags
+}
+
+// StoragePoolCreateXMLRet is libvirt's remote_storage_pool_create_xml_ret
+type StoragePoolCreateXMLRet struct {
+ Pool StoragePool
+}
+
+// StoragePoolDefineXMLArgs is libvirt's remote_storage_pool_define_xml_args
+type StoragePoolDefineXMLArgs struct {
+ XML string
+ Flags uint32
+}
+
+// StoragePoolDefineXMLRet is libvirt's remote_storage_pool_define_xml_ret
+type StoragePoolDefineXMLRet struct {
+ Pool StoragePool
+}
+
+// StoragePoolBuildArgs is libvirt's remote_storage_pool_build_args
+type StoragePoolBuildArgs struct {
+ Pool StoragePool
+ Flags StoragePoolBuildFlags
+}
+
+// StoragePoolUndefineArgs is libvirt's remote_storage_pool_undefine_args
+type StoragePoolUndefineArgs struct {
+ Pool StoragePool
+}
+
+// StoragePoolCreateArgs is libvirt's remote_storage_pool_create_args
+type StoragePoolCreateArgs struct {
+ Pool StoragePool
+ Flags StoragePoolCreateFlags
+}
+
+// StoragePoolDestroyArgs is libvirt's remote_storage_pool_destroy_args
+type StoragePoolDestroyArgs struct {
+ Pool StoragePool
+}
+
+// StoragePoolDeleteArgs is libvirt's remote_storage_pool_delete_args
+type StoragePoolDeleteArgs struct {
+ Pool StoragePool
+ Flags StoragePoolDeleteFlags
+}
+
+// StoragePoolRefreshArgs is libvirt's remote_storage_pool_refresh_args
+type StoragePoolRefreshArgs struct {
+ Pool StoragePool
+ Flags uint32
+}
+
+// StoragePoolGetXMLDescArgs is libvirt's remote_storage_pool_get_xml_desc_args
+type StoragePoolGetXMLDescArgs struct {
+ Pool StoragePool
+ Flags StorageXMLFlags
+}
+
+// StoragePoolGetXMLDescRet is libvirt's remote_storage_pool_get_xml_desc_ret
+type StoragePoolGetXMLDescRet struct {
+ XML string
+}
+
+// StoragePoolGetInfoArgs is libvirt's remote_storage_pool_get_info_args
+type StoragePoolGetInfoArgs struct {
+ Pool StoragePool
+}
+
+// StoragePoolGetInfoRet is libvirt's remote_storage_pool_get_info_ret
+type StoragePoolGetInfoRet struct {
+ State uint8
+ Capacity uint64
+ Allocation uint64
+ Available uint64
+}
+
+// StoragePoolGetAutostartArgs is libvirt's remote_storage_pool_get_autostart_args
+type StoragePoolGetAutostartArgs struct {
+ Pool StoragePool
+}
+
+// StoragePoolGetAutostartRet is libvirt's remote_storage_pool_get_autostart_ret
+type StoragePoolGetAutostartRet struct {
+ Autostart int32
+}
+
+// StoragePoolSetAutostartArgs is libvirt's remote_storage_pool_set_autostart_args
+type StoragePoolSetAutostartArgs struct {
+ Pool StoragePool
+ Autostart int32
+}
+
+// StoragePoolNumOfVolumesArgs is libvirt's remote_storage_pool_num_of_volumes_args
+type StoragePoolNumOfVolumesArgs struct {
+ Pool StoragePool
+}
+
+// StoragePoolNumOfVolumesRet is libvirt's remote_storage_pool_num_of_volumes_ret
+type StoragePoolNumOfVolumesRet struct {
+ Num int32
+}
+
+// StoragePoolListVolumesArgs is libvirt's remote_storage_pool_list_volumes_args
+type StoragePoolListVolumesArgs struct {
+ Pool StoragePool
+ Maxnames int32
+}
+
+// StoragePoolListVolumesRet is libvirt's remote_storage_pool_list_volumes_ret
+type StoragePoolListVolumesRet struct {
+ Names []string
+}
+
+// StorageVolLookupByNameArgs is libvirt's remote_storage_vol_lookup_by_name_args
+type StorageVolLookupByNameArgs struct {
+ Pool StoragePool
+ Name string
+}
+
+// StorageVolLookupByNameRet is libvirt's remote_storage_vol_lookup_by_name_ret
+type StorageVolLookupByNameRet struct {
+ Vol StorageVol
+}
+
+// StorageVolLookupByKeyArgs is libvirt's remote_storage_vol_lookup_by_key_args
+type StorageVolLookupByKeyArgs struct {
+ Key string
+}
+
+// StorageVolLookupByKeyRet is libvirt's remote_storage_vol_lookup_by_key_ret
+type StorageVolLookupByKeyRet struct {
+ Vol StorageVol
+}
+
+// StorageVolLookupByPathArgs is libvirt's remote_storage_vol_lookup_by_path_args
+type StorageVolLookupByPathArgs struct {
+ Path string
+}
+
+// StorageVolLookupByPathRet is libvirt's remote_storage_vol_lookup_by_path_ret
+type StorageVolLookupByPathRet struct {
+ Vol StorageVol
+}
+
+// StorageVolCreateXMLArgs is libvirt's remote_storage_vol_create_xml_args
+type StorageVolCreateXMLArgs struct {
+ Pool StoragePool
+ XML string
+ Flags StorageVolCreateFlags
+}
+
+// StorageVolCreateXMLRet is libvirt's remote_storage_vol_create_xml_ret
+type StorageVolCreateXMLRet struct {
+ Vol StorageVol
+}
+
+// StorageVolCreateXMLFromArgs is libvirt's remote_storage_vol_create_xml_from_args
+type StorageVolCreateXMLFromArgs struct {
+ Pool StoragePool
+ XML string
+ Clonevol StorageVol
+ Flags StorageVolCreateFlags
+}
+
+// StorageVolCreateXMLFromRet is libvirt's remote_storage_vol_create_xml_from_ret
+type StorageVolCreateXMLFromRet struct {
+ Vol StorageVol
+}
+
+// StorageVolDeleteArgs is libvirt's remote_storage_vol_delete_args
+type StorageVolDeleteArgs struct {
+ Vol StorageVol
+ Flags StorageVolDeleteFlags
+}
+
+// StorageVolWipeArgs is libvirt's remote_storage_vol_wipe_args
+type StorageVolWipeArgs struct {
+ Vol StorageVol
+ Flags uint32
+}
+
+// StorageVolWipePatternArgs is libvirt's remote_storage_vol_wipe_pattern_args
+type StorageVolWipePatternArgs struct {
+ Vol StorageVol
+ Algorithm uint32
+ Flags uint32
+}
+
+// StorageVolGetXMLDescArgs is libvirt's remote_storage_vol_get_xml_desc_args
+type StorageVolGetXMLDescArgs struct {
+ Vol StorageVol
+ Flags uint32
+}
+
+// StorageVolGetXMLDescRet is libvirt's remote_storage_vol_get_xml_desc_ret
+type StorageVolGetXMLDescRet struct {
+ XML string
+}
+
+// StorageVolGetInfoArgs is libvirt's remote_storage_vol_get_info_args
+type StorageVolGetInfoArgs struct {
+ Vol StorageVol
+}
+
+// StorageVolGetInfoRet is libvirt's remote_storage_vol_get_info_ret
+type StorageVolGetInfoRet struct {
+ Type int8
+ Capacity uint64
+ Allocation uint64
+}
+
+// StorageVolGetInfoFlagsArgs is libvirt's remote_storage_vol_get_info_flags_args
+type StorageVolGetInfoFlagsArgs struct {
+ Vol StorageVol
+ Flags uint32
+}
+
+// StorageVolGetInfoFlagsRet is libvirt's remote_storage_vol_get_info_flags_ret
+type StorageVolGetInfoFlagsRet struct {
+ Type int8
+ Capacity uint64
+ Allocation uint64
+}
+
+// StorageVolGetPathArgs is libvirt's remote_storage_vol_get_path_args
+type StorageVolGetPathArgs struct {
+ Vol StorageVol
+}
+
+// StorageVolGetPathRet is libvirt's remote_storage_vol_get_path_ret
+type StorageVolGetPathRet struct {
+ Name string
+}
+
+// StorageVolResizeArgs is libvirt's remote_storage_vol_resize_args
+type StorageVolResizeArgs struct {
+ Vol StorageVol
+ Capacity uint64
+ Flags StorageVolResizeFlags
+}
+
+// NodeNumOfDevicesArgs is libvirt's remote_node_num_of_devices_args
+type NodeNumOfDevicesArgs struct {
+ Cap OptString
+ Flags uint32
+}
+
+// NodeNumOfDevicesRet is libvirt's remote_node_num_of_devices_ret
+type NodeNumOfDevicesRet struct {
+ Num int32
+}
+
+// NodeListDevicesArgs is libvirt's remote_node_list_devices_args
+type NodeListDevicesArgs struct {
+ Cap OptString
+ Maxnames int32
+ Flags uint32
+}
+
+// NodeListDevicesRet is libvirt's remote_node_list_devices_ret
+type NodeListDevicesRet struct {
+ Names []string
+}
+
+// NodeDeviceLookupByNameArgs is libvirt's remote_node_device_lookup_by_name_args
+type NodeDeviceLookupByNameArgs struct {
+ Name string
+}
+
+// NodeDeviceLookupByNameRet is libvirt's remote_node_device_lookup_by_name_ret
+type NodeDeviceLookupByNameRet struct {
+ Dev NodeDevice
+}
+
+// NodeDeviceLookupScsiHostByWwnArgs is libvirt's remote_node_device_lookup_scsi_host_by_wwn_args
+type NodeDeviceLookupScsiHostByWwnArgs struct {
+ Wwnn string
+ Wwpn string
+ Flags uint32
+}
+
+// NodeDeviceLookupScsiHostByWwnRet is libvirt's remote_node_device_lookup_scsi_host_by_wwn_ret
+type NodeDeviceLookupScsiHostByWwnRet struct {
+ Dev NodeDevice
+}
+
+// NodeDeviceGetXMLDescArgs is libvirt's remote_node_device_get_xml_desc_args
+type NodeDeviceGetXMLDescArgs struct {
+ Name string
+ Flags uint32
+}
+
+// NodeDeviceGetXMLDescRet is libvirt's remote_node_device_get_xml_desc_ret
+type NodeDeviceGetXMLDescRet struct {
+ XML string
+}
+
+// NodeDeviceGetParentArgs is libvirt's remote_node_device_get_parent_args
+type NodeDeviceGetParentArgs struct {
+ Name string
+}
+
+// NodeDeviceGetParentRet is libvirt's remote_node_device_get_parent_ret
+type NodeDeviceGetParentRet struct {
+ ParentName OptString
+}
+
+// NodeDeviceNumOfCapsArgs is libvirt's remote_node_device_num_of_caps_args
+type NodeDeviceNumOfCapsArgs struct {
+ Name string
+}
+
+// NodeDeviceNumOfCapsRet is libvirt's remote_node_device_num_of_caps_ret
+type NodeDeviceNumOfCapsRet struct {
+ Num int32
+}
+
+// NodeDeviceListCapsArgs is libvirt's remote_node_device_list_caps_args
+type NodeDeviceListCapsArgs struct {
+ Name string
+ Maxnames int32
+}
+
+// NodeDeviceListCapsRet is libvirt's remote_node_device_list_caps_ret
+type NodeDeviceListCapsRet struct {
+ Names []string
+}
+
+// NodeDeviceDettachArgs is libvirt's remote_node_device_dettach_args
+type NodeDeviceDettachArgs struct {
+ Name string
+}
+
+// NodeDeviceDetachFlagsArgs is libvirt's remote_node_device_detach_flags_args
+type NodeDeviceDetachFlagsArgs struct {
+ Name string
+ DriverName OptString
+ Flags uint32
+}
+
+// NodeDeviceReAttachArgs is libvirt's remote_node_device_re_attach_args
+type NodeDeviceReAttachArgs struct {
+ Name string
+}
+
+// NodeDeviceResetArgs is libvirt's remote_node_device_reset_args
+type NodeDeviceResetArgs struct {
+ Name string
+}
+
+// NodeDeviceCreateXMLArgs is libvirt's remote_node_device_create_xml_args
+type NodeDeviceCreateXMLArgs struct {
+ XMLDesc string
+ Flags uint32
+}
+
+// NodeDeviceCreateXMLRet is libvirt's remote_node_device_create_xml_ret
+type NodeDeviceCreateXMLRet struct {
+ Dev NodeDevice
+}
+
+// NodeDeviceDestroyArgs is libvirt's remote_node_device_destroy_args
+type NodeDeviceDestroyArgs struct {
+ Name string
+}
+
+// NodeDeviceDefineXMLArgs is libvirt's remote_node_device_define_xml_args
+type NodeDeviceDefineXMLArgs struct {
+ XMLDesc string
+ Flags uint32
+}
+
+// NodeDeviceDefineXMLRet is libvirt's remote_node_device_define_xml_ret
+type NodeDeviceDefineXMLRet struct {
+ Dev NodeDevice
+}
+
+// NodeDeviceUndefineArgs is libvirt's remote_node_device_undefine_args
+type NodeDeviceUndefineArgs struct {
+ Name string
+ Flags uint32
+}
+
+// NodeDeviceCreateArgs is libvirt's remote_node_device_create_args
+type NodeDeviceCreateArgs struct {
+ Name string
+ Flags uint32
+}
+
+// NodeDeviceGetAutostartArgs is libvirt's remote_node_device_get_autostart_args
+type NodeDeviceGetAutostartArgs struct {
+ Name string
+}
+
+// NodeDeviceGetAutostartRet is libvirt's remote_node_device_get_autostart_ret
+type NodeDeviceGetAutostartRet struct {
+ Autostart int32
+}
+
+// NodeDeviceSetAutostartArgs is libvirt's remote_node_device_set_autostart_args
+type NodeDeviceSetAutostartArgs struct {
+ Name string
+ Autostart int32
+}
+
+// NodeDeviceIsPersistentArgs is libvirt's remote_node_device_is_persistent_args
+type NodeDeviceIsPersistentArgs struct {
+ Name string
+}
+
+// NodeDeviceIsPersistentRet is libvirt's remote_node_device_is_persistent_ret
+type NodeDeviceIsPersistentRet struct {
+ Persistent int32
+}
+
+// NodeDeviceIsActiveArgs is libvirt's remote_node_device_is_active_args
+type NodeDeviceIsActiveArgs struct {
+ Name string
+}
+
+// NodeDeviceIsActiveRet is libvirt's remote_node_device_is_active_ret
+type NodeDeviceIsActiveRet struct {
+ Active int32
+}
+
+// ConnectDomainEventRegisterRet is libvirt's remote_connect_domain_event_register_ret
+type ConnectDomainEventRegisterRet struct {
+ CbRegistered int32
+}
+
+// ConnectDomainEventDeregisterRet is libvirt's remote_connect_domain_event_deregister_ret
+type ConnectDomainEventDeregisterRet struct {
+ CbRegistered int32
+}
+
+// DomainEventLifecycleMsg is libvirt's remote_domain_event_lifecycle_msg
+type DomainEventLifecycleMsg struct {
+ Dom Domain
+ Event int32
+ Detail int32
+}
+
+// DomainEventCallbackLifecycleMsg is libvirt's remote_domain_event_callback_lifecycle_msg
+type DomainEventCallbackLifecycleMsg struct {
+ CallbackID int32
+ Msg DomainEventLifecycleMsg
+}
+
+// ConnectDomainXMLFromNativeArgs is libvirt's remote_connect_domain_xml_from_native_args
+type ConnectDomainXMLFromNativeArgs struct {
+ NativeFormat string
+ NativeConfig string
+ Flags uint32
+}
+
+// ConnectDomainXMLFromNativeRet is libvirt's remote_connect_domain_xml_from_native_ret
+type ConnectDomainXMLFromNativeRet struct {
+ DomainXML string
+}
+
+// ConnectDomainXMLToNativeArgs is libvirt's remote_connect_domain_xml_to_native_args
+type ConnectDomainXMLToNativeArgs struct {
+ NativeFormat string
+ DomainXML string
+ Flags uint32
+}
+
+// ConnectDomainXMLToNativeRet is libvirt's remote_connect_domain_xml_to_native_ret
+type ConnectDomainXMLToNativeRet struct {
+ NativeConfig string
+}
+
+// ConnectNumOfSecretsRet is libvirt's remote_connect_num_of_secrets_ret
+type ConnectNumOfSecretsRet struct {
+ Num int32
+}
+
+// ConnectListSecretsArgs is libvirt's remote_connect_list_secrets_args
+type ConnectListSecretsArgs struct {
+ Maxuuids int32
+}
+
+// ConnectListSecretsRet is libvirt's remote_connect_list_secrets_ret
+type ConnectListSecretsRet struct {
+ Uuids []string
+}
+
+// SecretLookupByUUIDArgs is libvirt's remote_secret_lookup_by_uuid_args
+type SecretLookupByUUIDArgs struct {
+ UUID UUID
+}
+
+// SecretLookupByUUIDRet is libvirt's remote_secret_lookup_by_uuid_ret
+type SecretLookupByUUIDRet struct {
+ OptSecret Secret
+}
+
+// SecretDefineXMLArgs is libvirt's remote_secret_define_xml_args
+type SecretDefineXMLArgs struct {
+ XML string
+ Flags uint32
+}
+
+// SecretDefineXMLRet is libvirt's remote_secret_define_xml_ret
+type SecretDefineXMLRet struct {
+ OptSecret Secret
+}
+
+// SecretGetXMLDescArgs is libvirt's remote_secret_get_xml_desc_args
+type SecretGetXMLDescArgs struct {
+ OptSecret Secret
+ Flags uint32
+}
+
+// SecretGetXMLDescRet is libvirt's remote_secret_get_xml_desc_ret
+type SecretGetXMLDescRet struct {
+ XML string
+}
+
+// SecretSetValueArgs is libvirt's remote_secret_set_value_args
+type SecretSetValueArgs struct {
+ OptSecret Secret
+ Value []byte
+ Flags uint32
+}
+
+// SecretGetValueArgs is libvirt's remote_secret_get_value_args
+type SecretGetValueArgs struct {
+ OptSecret Secret
+ Flags uint32
+}
+
+// SecretGetValueRet is libvirt's remote_secret_get_value_ret
+type SecretGetValueRet struct {
+ Value []byte
+}
+
+// SecretUndefineArgs is libvirt's remote_secret_undefine_args
+type SecretUndefineArgs struct {
+ OptSecret Secret
+}
+
+// SecretLookupByUsageArgs is libvirt's remote_secret_lookup_by_usage_args
+type SecretLookupByUsageArgs struct {
+ UsageType int32
+ UsageID string
+}
+
+// SecretLookupByUsageRet is libvirt's remote_secret_lookup_by_usage_ret
+type SecretLookupByUsageRet struct {
+ OptSecret Secret
+}
+
+// DomainMigratePrepareTunnelArgs is libvirt's remote_domain_migrate_prepare_tunnel_args
+type DomainMigratePrepareTunnelArgs struct {
+ Flags uint64
+ Dname OptString
+ Resource uint64
+ DomXML string
+}
+
+// ConnectIsSecureRet is libvirt's remote_connect_is_secure_ret
+type ConnectIsSecureRet struct {
+ Secure int32
+}
+
+// DomainIsActiveArgs is libvirt's remote_domain_is_active_args
+type DomainIsActiveArgs struct {
+ Dom Domain
+}
+
+// DomainIsActiveRet is libvirt's remote_domain_is_active_ret
+type DomainIsActiveRet struct {
+ Active int32
+}
+
+// DomainIsPersistentArgs is libvirt's remote_domain_is_persistent_args
+type DomainIsPersistentArgs struct {
+ Dom Domain
+}
+
+// DomainIsPersistentRet is libvirt's remote_domain_is_persistent_ret
+type DomainIsPersistentRet struct {
+ Persistent int32
+}
+
+// DomainIsUpdatedArgs is libvirt's remote_domain_is_updated_args
+type DomainIsUpdatedArgs struct {
+ Dom Domain
+}
+
+// DomainIsUpdatedRet is libvirt's remote_domain_is_updated_ret
+type DomainIsUpdatedRet struct {
+ Updated int32
+}
+
+// NetworkIsActiveArgs is libvirt's remote_network_is_active_args
+type NetworkIsActiveArgs struct {
+ Net Network
+}
+
+// NetworkIsActiveRet is libvirt's remote_network_is_active_ret
+type NetworkIsActiveRet struct {
+ Active int32
+}
+
+// NetworkIsPersistentArgs is libvirt's remote_network_is_persistent_args
+type NetworkIsPersistentArgs struct {
+ Net Network
+}
+
+// NetworkIsPersistentRet is libvirt's remote_network_is_persistent_ret
+type NetworkIsPersistentRet struct {
+ Persistent int32
+}
+
+// StoragePoolIsActiveArgs is libvirt's remote_storage_pool_is_active_args
+type StoragePoolIsActiveArgs struct {
+ Pool StoragePool
+}
+
+// StoragePoolIsActiveRet is libvirt's remote_storage_pool_is_active_ret
+type StoragePoolIsActiveRet struct {
+ Active int32
+}
+
+// StoragePoolIsPersistentArgs is libvirt's remote_storage_pool_is_persistent_args
+type StoragePoolIsPersistentArgs struct {
+ Pool StoragePool
+}
+
+// StoragePoolIsPersistentRet is libvirt's remote_storage_pool_is_persistent_ret
+type StoragePoolIsPersistentRet struct {
+ Persistent int32
+}
+
+// InterfaceIsActiveArgs is libvirt's remote_interface_is_active_args
+type InterfaceIsActiveArgs struct {
+ Iface Interface
+}
+
+// InterfaceIsActiveRet is libvirt's remote_interface_is_active_ret
+type InterfaceIsActiveRet struct {
+ Active int32
+}
+
+// ConnectCompareCPUArgs is libvirt's remote_connect_compare_cpu_args
+type ConnectCompareCPUArgs struct {
+ XML string
+ Flags ConnectCompareCPUFlags
+}
+
+// ConnectCompareCPURet is libvirt's remote_connect_compare_cpu_ret
+type ConnectCompareCPURet struct {
+ Result int32
+}
+
+// ConnectBaselineCPUArgs is libvirt's remote_connect_baseline_cpu_args
+type ConnectBaselineCPUArgs struct {
+ XMLCPUs []string
+ Flags ConnectBaselineCPUFlags
+}
+
+// ConnectBaselineCPURet is libvirt's remote_connect_baseline_cpu_ret
+type ConnectBaselineCPURet struct {
+ CPU string
+}
+
+// DomainGetJobInfoArgs is libvirt's remote_domain_get_job_info_args
+type DomainGetJobInfoArgs struct {
+ Dom Domain
+}
+
+// DomainGetJobInfoRet is libvirt's remote_domain_get_job_info_ret
+type DomainGetJobInfoRet struct {
+ Type int32
+ TimeElapsed uint64
+ TimeRemaining uint64
+ DataTotal uint64
+ DataProcessed uint64
+ DataRemaining uint64
+ MemTotal uint64
+ MemProcessed uint64
+ MemRemaining uint64
+ FileTotal uint64
+ FileProcessed uint64
+ FileRemaining uint64
+}
+
+// DomainGetJobStatsArgs is libvirt's remote_domain_get_job_stats_args
+type DomainGetJobStatsArgs struct {
+ Dom Domain
+ Flags DomainGetJobStatsFlags
+}
+
+// DomainGetJobStatsRet is libvirt's remote_domain_get_job_stats_ret
+type DomainGetJobStatsRet struct {
+ Type int32
+ Params []TypedParam
+}
+
+// DomainAbortJobArgs is libvirt's remote_domain_abort_job_args
+type DomainAbortJobArgs struct {
+ Dom Domain
+}
+
+// DomainMigrateGetMaxDowntimeArgs is libvirt's remote_domain_migrate_get_max_downtime_args
+type DomainMigrateGetMaxDowntimeArgs struct {
+ Dom Domain
+ Flags uint32
+}
+
+// DomainMigrateGetMaxDowntimeRet is libvirt's remote_domain_migrate_get_max_downtime_ret
+type DomainMigrateGetMaxDowntimeRet struct {
+ Downtime uint64
+}
+
+// DomainMigrateSetMaxDowntimeArgs is libvirt's remote_domain_migrate_set_max_downtime_args
+type DomainMigrateSetMaxDowntimeArgs struct {
+ Dom Domain
+ Downtime uint64
+ Flags uint32
+}
+
+// DomainMigrateGetCompressionCacheArgs is libvirt's remote_domain_migrate_get_compression_cache_args
+type DomainMigrateGetCompressionCacheArgs struct {
+ Dom Domain
+ Flags uint32
+}
+
+// DomainMigrateGetCompressionCacheRet is libvirt's remote_domain_migrate_get_compression_cache_ret
+type DomainMigrateGetCompressionCacheRet struct {
+ CacheSize uint64
+}
+
+// DomainMigrateSetCompressionCacheArgs is libvirt's remote_domain_migrate_set_compression_cache_args
+type DomainMigrateSetCompressionCacheArgs struct {
+ Dom Domain
+ CacheSize uint64
+ Flags uint32
+}
+
+// DomainMigrateSetMaxSpeedArgs is libvirt's remote_domain_migrate_set_max_speed_args
+type DomainMigrateSetMaxSpeedArgs struct {
+ Dom Domain
+ Bandwidth uint64
+ Flags uint32
+}
+
+// DomainMigrateGetMaxSpeedArgs is libvirt's remote_domain_migrate_get_max_speed_args
+type DomainMigrateGetMaxSpeedArgs struct {
+ Dom Domain
+ Flags uint32
+}
+
+// DomainMigrateGetMaxSpeedRet is libvirt's remote_domain_migrate_get_max_speed_ret
+type DomainMigrateGetMaxSpeedRet struct {
+ Bandwidth uint64
+}
+
+// ConnectDomainEventRegisterAnyArgs is libvirt's remote_connect_domain_event_register_any_args
+type ConnectDomainEventRegisterAnyArgs struct {
+ EventID int32
+}
+
+// ConnectDomainEventDeregisterAnyArgs is libvirt's remote_connect_domain_event_deregister_any_args
+type ConnectDomainEventDeregisterAnyArgs struct {
+ EventID int32
+}
+
+// ConnectDomainEventCallbackRegisterAnyArgs is libvirt's remote_connect_domain_event_callback_register_any_args
+type ConnectDomainEventCallbackRegisterAnyArgs struct {
+ EventID int32
+ Dom OptDomain
+}
+
+// ConnectDomainEventCallbackRegisterAnyRet is libvirt's remote_connect_domain_event_callback_register_any_ret
+type ConnectDomainEventCallbackRegisterAnyRet struct {
+ CallbackID int32
+}
+
+// ConnectDomainEventCallbackDeregisterAnyArgs is libvirt's remote_connect_domain_event_callback_deregister_any_args
+type ConnectDomainEventCallbackDeregisterAnyArgs struct {
+ CallbackID int32
+}
+
+// DomainEventRebootMsg is libvirt's remote_domain_event_reboot_msg
+type DomainEventRebootMsg struct {
+ Dom Domain
+}
+
+// DomainEventCallbackRebootMsg is libvirt's remote_domain_event_callback_reboot_msg
+type DomainEventCallbackRebootMsg struct {
+ CallbackID int32
+ Msg DomainEventRebootMsg
+}
+
+// DomainEventRtcChangeMsg is libvirt's remote_domain_event_rtc_change_msg
+type DomainEventRtcChangeMsg struct {
+ Dom Domain
+ Offset int64
+}
+
+// DomainEventCallbackRtcChangeMsg is libvirt's remote_domain_event_callback_rtc_change_msg
+type DomainEventCallbackRtcChangeMsg struct {
+ CallbackID int32
+ Msg DomainEventRtcChangeMsg
+}
+
+// DomainEventWatchdogMsg is libvirt's remote_domain_event_watchdog_msg
+type DomainEventWatchdogMsg struct {
+ Dom Domain
+ Action int32
+}
+
+// DomainEventCallbackWatchdogMsg is libvirt's remote_domain_event_callback_watchdog_msg
+type DomainEventCallbackWatchdogMsg struct {
+ CallbackID int32
+ Msg DomainEventWatchdogMsg
+}
+
+// DomainEventIOErrorMsg is libvirt's remote_domain_event_io_error_msg
+type DomainEventIOErrorMsg struct {
+ Dom Domain
+ SrcPath string
+ DevAlias string
+ Action int32
+}
+
+// DomainEventCallbackIOErrorMsg is libvirt's remote_domain_event_callback_io_error_msg
+type DomainEventCallbackIOErrorMsg struct {
+ CallbackID int32
+ Msg DomainEventIOErrorMsg
+}
+
+// DomainEventIOErrorReasonMsg is libvirt's remote_domain_event_io_error_reason_msg
+type DomainEventIOErrorReasonMsg struct {
+ Dom Domain
+ SrcPath string
+ DevAlias string
+ Action int32
+ Reason string
+}
+
+// DomainEventCallbackIOErrorReasonMsg is libvirt's remote_domain_event_callback_io_error_reason_msg
+type DomainEventCallbackIOErrorReasonMsg struct {
+ CallbackID int32
+ Msg DomainEventIOErrorReasonMsg
+}
+
+// DomainEventGraphicsAddress is libvirt's remote_domain_event_graphics_address
+type DomainEventGraphicsAddress struct {
+ Family int32
+ Node string
+ Service string
+}
+
+// DomainEventGraphicsIdentity is libvirt's remote_domain_event_graphics_identity
+type DomainEventGraphicsIdentity struct {
+ Type string
+ Name string
+}
+
+// DomainEventGraphicsMsg is libvirt's remote_domain_event_graphics_msg
+type DomainEventGraphicsMsg struct {
+ Dom Domain
+ Phase int32
+ Local DomainEventGraphicsAddress
+ Remote DomainEventGraphicsAddress
+ AuthScheme string
+ Subject []DomainEventGraphicsIdentity
+}
+
+// DomainEventCallbackGraphicsMsg is libvirt's remote_domain_event_callback_graphics_msg
+type DomainEventCallbackGraphicsMsg struct {
+ CallbackID int32
+ Msg DomainEventGraphicsMsg
+}
+
+// DomainEventBlockJobMsg is libvirt's remote_domain_event_block_job_msg
+type DomainEventBlockJobMsg struct {
+ Dom Domain
+ Path string
+ Type int32
+ Status int32
+}
+
+// DomainEventCallbackBlockJobMsg is libvirt's remote_domain_event_callback_block_job_msg
+type DomainEventCallbackBlockJobMsg struct {
+ CallbackID int32
+ Msg DomainEventBlockJobMsg
+}
+
+// DomainEventDiskChangeMsg is libvirt's remote_domain_event_disk_change_msg
+type DomainEventDiskChangeMsg struct {
+ Dom Domain
+ OldSrcPath OptString
+ NewSrcPath OptString
+ DevAlias string
+ Reason int32
+}
+
+// DomainEventCallbackDiskChangeMsg is libvirt's remote_domain_event_callback_disk_change_msg
+type DomainEventCallbackDiskChangeMsg struct {
+ CallbackID int32
+ Msg DomainEventDiskChangeMsg
+}
+
+// DomainEventTrayChangeMsg is libvirt's remote_domain_event_tray_change_msg
+type DomainEventTrayChangeMsg struct {
+ Dom Domain
+ DevAlias string
+ Reason int32
+}
+
+// DomainEventCallbackTrayChangeMsg is libvirt's remote_domain_event_callback_tray_change_msg
+type DomainEventCallbackTrayChangeMsg struct {
+ CallbackID int32
+ Msg DomainEventTrayChangeMsg
+}
+
+// DomainEventPmwakeupMsg is libvirt's remote_domain_event_pmwakeup_msg
+type DomainEventPmwakeupMsg struct {
+ Dom Domain
+}
+
+// DomainEventCallbackPmwakeupMsg is libvirt's remote_domain_event_callback_pmwakeup_msg
+type DomainEventCallbackPmwakeupMsg struct {
+ CallbackID int32
+ Reason int32
+ Msg DomainEventPmwakeupMsg
+}
+
+// DomainEventPmsuspendMsg is libvirt's remote_domain_event_pmsuspend_msg
+type DomainEventPmsuspendMsg struct {
+ Dom Domain
+}
+
+// DomainEventCallbackPmsuspendMsg is libvirt's remote_domain_event_callback_pmsuspend_msg
+type DomainEventCallbackPmsuspendMsg struct {
+ CallbackID int32
+ Reason int32
+ Msg DomainEventPmsuspendMsg
+}
+
+// DomainEventBalloonChangeMsg is libvirt's remote_domain_event_balloon_change_msg
+type DomainEventBalloonChangeMsg struct {
+ Dom Domain
+ Actual uint64
+}
+
+// DomainEventCallbackBalloonChangeMsg is libvirt's remote_domain_event_callback_balloon_change_msg
+type DomainEventCallbackBalloonChangeMsg struct {
+ CallbackID int32
+ Msg DomainEventBalloonChangeMsg
+}
+
+// DomainEventPmsuspendDiskMsg is libvirt's remote_domain_event_pmsuspend_disk_msg
+type DomainEventPmsuspendDiskMsg struct {
+ Dom Domain
+}
+
+// DomainEventCallbackPmsuspendDiskMsg is libvirt's remote_domain_event_callback_pmsuspend_disk_msg
+type DomainEventCallbackPmsuspendDiskMsg struct {
+ CallbackID int32
+ Reason int32
+ Msg DomainEventPmsuspendDiskMsg
+}
+
+// DomainManagedSaveArgs is libvirt's remote_domain_managed_save_args
+type DomainManagedSaveArgs struct {
+ Dom Domain
+ Flags uint32
+}
+
+// DomainHasManagedSaveImageArgs is libvirt's remote_domain_has_managed_save_image_args
+type DomainHasManagedSaveImageArgs struct {
+ Dom Domain
+ Flags uint32
+}
+
+// DomainHasManagedSaveImageRet is libvirt's remote_domain_has_managed_save_image_ret
+type DomainHasManagedSaveImageRet struct {
+ Result int32
+}
+
+// DomainManagedSaveRemoveArgs is libvirt's remote_domain_managed_save_remove_args
+type DomainManagedSaveRemoveArgs struct {
+ Dom Domain
+ Flags uint32
+}
+
+// DomainManagedSaveGetXMLDescArgs is libvirt's remote_domain_managed_save_get_xml_desc_args
+type DomainManagedSaveGetXMLDescArgs struct {
+ Dom Domain
+ Flags DomainXMLFlags
+}
+
+// DomainManagedSaveGetXMLDescRet is libvirt's remote_domain_managed_save_get_xml_desc_ret
+type DomainManagedSaveGetXMLDescRet struct {
+ XML string
+}
+
+// DomainManagedSaveDefineXMLArgs is libvirt's remote_domain_managed_save_define_xml_args
+type DomainManagedSaveDefineXMLArgs struct {
+ Dom Domain
+ Dxml OptString
+ Flags DomainSaveRestoreFlags
+}
+
+// DomainSnapshotCreateXMLArgs is libvirt's remote_domain_snapshot_create_xml_args
+type DomainSnapshotCreateXMLArgs struct {
+ Dom Domain
+ XMLDesc string
+ Flags uint32
+}
+
+// DomainSnapshotCreateXMLRet is libvirt's remote_domain_snapshot_create_xml_ret
+type DomainSnapshotCreateXMLRet struct {
+ Snap DomainSnapshot
+}
+
+// DomainSnapshotGetXMLDescArgs is libvirt's remote_domain_snapshot_get_xml_desc_args
+type DomainSnapshotGetXMLDescArgs struct {
+ Snap DomainSnapshot
+ Flags uint32
+}
+
+// DomainSnapshotGetXMLDescRet is libvirt's remote_domain_snapshot_get_xml_desc_ret
+type DomainSnapshotGetXMLDescRet struct {
+ XML string
+}
+
+// DomainSnapshotNumArgs is libvirt's remote_domain_snapshot_num_args
+type DomainSnapshotNumArgs struct {
+ Dom Domain
+ Flags uint32
+}
+
+// DomainSnapshotNumRet is libvirt's remote_domain_snapshot_num_ret
+type DomainSnapshotNumRet struct {
+ Num int32
+}
+
+// DomainSnapshotListNamesArgs is libvirt's remote_domain_snapshot_list_names_args
+type DomainSnapshotListNamesArgs struct {
+ Dom Domain
+ Maxnames int32
+ Flags uint32
+}
+
+// DomainSnapshotListNamesRet is libvirt's remote_domain_snapshot_list_names_ret
+type DomainSnapshotListNamesRet struct {
+ Names []string
+}
+
+// DomainListAllSnapshotsArgs is libvirt's remote_domain_list_all_snapshots_args
+type DomainListAllSnapshotsArgs struct {
+ Dom Domain
+ NeedResults int32
+ Flags uint32
+}
+
+// DomainListAllSnapshotsRet is libvirt's remote_domain_list_all_snapshots_ret
+type DomainListAllSnapshotsRet struct {
+ Snapshots []DomainSnapshot
+ Ret int32
+}
+
+// DomainSnapshotNumChildrenArgs is libvirt's remote_domain_snapshot_num_children_args
+type DomainSnapshotNumChildrenArgs struct {
+ Snap DomainSnapshot
+ Flags uint32
+}
+
+// DomainSnapshotNumChildrenRet is libvirt's remote_domain_snapshot_num_children_ret
+type DomainSnapshotNumChildrenRet struct {
+ Num int32
+}
+
+// DomainSnapshotListChildrenNamesArgs is libvirt's remote_domain_snapshot_list_children_names_args
+type DomainSnapshotListChildrenNamesArgs struct {
+ Snap DomainSnapshot
+ Maxnames int32
+ Flags uint32
+}
+
+// DomainSnapshotListChildrenNamesRet is libvirt's remote_domain_snapshot_list_children_names_ret
+type DomainSnapshotListChildrenNamesRet struct {
+ Names []string
+}
+
+// DomainSnapshotListAllChildrenArgs is libvirt's remote_domain_snapshot_list_all_children_args
+type DomainSnapshotListAllChildrenArgs struct {
+ Snapshot DomainSnapshot
+ NeedResults int32
+ Flags uint32
+}
+
+// DomainSnapshotListAllChildrenRet is libvirt's remote_domain_snapshot_list_all_children_ret
+type DomainSnapshotListAllChildrenRet struct {
+ Snapshots []DomainSnapshot
+ Ret int32
+}
+
+// DomainSnapshotLookupByNameArgs is libvirt's remote_domain_snapshot_lookup_by_name_args
+type DomainSnapshotLookupByNameArgs struct {
+ Dom Domain
+ Name string
+ Flags uint32
+}
+
+// DomainSnapshotLookupByNameRet is libvirt's remote_domain_snapshot_lookup_by_name_ret
+type DomainSnapshotLookupByNameRet struct {
+ Snap DomainSnapshot
+}
+
+// DomainHasCurrentSnapshotArgs is libvirt's remote_domain_has_current_snapshot_args
+type DomainHasCurrentSnapshotArgs struct {
+ Dom Domain
+ Flags uint32
+}
+
+// DomainHasCurrentSnapshotRet is libvirt's remote_domain_has_current_snapshot_ret
+type DomainHasCurrentSnapshotRet struct {
+ Result int32
+}
+
+// DomainSnapshotGetParentArgs is libvirt's remote_domain_snapshot_get_parent_args
+type DomainSnapshotGetParentArgs struct {
+ Snap DomainSnapshot
+ Flags uint32
+}
+
+// DomainSnapshotGetParentRet is libvirt's remote_domain_snapshot_get_parent_ret
+type DomainSnapshotGetParentRet struct {
+ Snap DomainSnapshot
+}
+
+// DomainSnapshotCurrentArgs is libvirt's remote_domain_snapshot_current_args
+type DomainSnapshotCurrentArgs struct {
+ Dom Domain
+ Flags uint32
+}
+
+// DomainSnapshotCurrentRet is libvirt's remote_domain_snapshot_current_ret
+type DomainSnapshotCurrentRet struct {
+ Snap DomainSnapshot
+}
+
+// DomainSnapshotIsCurrentArgs is libvirt's remote_domain_snapshot_is_current_args
+type DomainSnapshotIsCurrentArgs struct {
+ Snap DomainSnapshot
+ Flags uint32
+}
+
+// DomainSnapshotIsCurrentRet is libvirt's remote_domain_snapshot_is_current_ret
+type DomainSnapshotIsCurrentRet struct {
+ Current int32
+}
+
+// DomainSnapshotHasMetadataArgs is libvirt's remote_domain_snapshot_has_metadata_args
+type DomainSnapshotHasMetadataArgs struct {
+ Snap DomainSnapshot
+ Flags uint32
+}
+
+// DomainSnapshotHasMetadataRet is libvirt's remote_domain_snapshot_has_metadata_ret
+type DomainSnapshotHasMetadataRet struct {
+ Metadata int32
+}
+
+// DomainRevertToSnapshotArgs is libvirt's remote_domain_revert_to_snapshot_args
+type DomainRevertToSnapshotArgs struct {
+ Snap DomainSnapshot
+ Flags uint32
+}
+
+// DomainSnapshotDeleteArgs is libvirt's remote_domain_snapshot_delete_args
+type DomainSnapshotDeleteArgs struct {
+ Snap DomainSnapshot
+ Flags DomainSnapshotDeleteFlags
+}
+
+// DomainOpenConsoleArgs is libvirt's remote_domain_open_console_args
+type DomainOpenConsoleArgs struct {
+ Dom Domain
+ DevName OptString
+ Flags uint32
+}
+
+// DomainOpenChannelArgs is libvirt's remote_domain_open_channel_args
+type DomainOpenChannelArgs struct {
+ Dom Domain
+ Name OptString
+ Flags DomainChannelFlags
+}
+
+// StorageVolUploadArgs is libvirt's remote_storage_vol_upload_args
+type StorageVolUploadArgs struct {
+ Vol StorageVol
+ Offset uint64
+ Length uint64
+ Flags StorageVolUploadFlags
+}
+
+// StorageVolDownloadArgs is libvirt's remote_storage_vol_download_args
+type StorageVolDownloadArgs struct {
+ Vol StorageVol
+ Offset uint64
+ Length uint64
+ Flags StorageVolDownloadFlags
+}
+
+// DomainGetStateArgs is libvirt's remote_domain_get_state_args
+type DomainGetStateArgs struct {
+ Dom Domain
+ Flags uint32
+}
+
+// DomainGetStateRet is libvirt's remote_domain_get_state_ret
+type DomainGetStateRet struct {
+ State int32
+ Reason int32
+}
+
+// DomainMigrateBegin3Args is libvirt's remote_domain_migrate_begin3_args
+type DomainMigrateBegin3Args struct {
+ Dom Domain
+ Xmlin OptString
+ Flags uint64
+ Dname OptString
+ Resource uint64
+}
+
+// DomainMigrateBegin3Ret is libvirt's remote_domain_migrate_begin3_ret
+type DomainMigrateBegin3Ret struct {
+ CookieOut []byte
+ XML string
+}
+
+// DomainMigratePrepare3Args is libvirt's remote_domain_migrate_prepare3_args
+type DomainMigratePrepare3Args struct {
+ CookieIn []byte
+ UriIn OptString
+ Flags uint64
+ Dname OptString
+ Resource uint64
+ DomXML string
+}
+
+// DomainMigratePrepare3Ret is libvirt's remote_domain_migrate_prepare3_ret
+type DomainMigratePrepare3Ret struct {
+ CookieOut []byte
+ UriOut OptString
+}
+
+// DomainMigratePrepareTunnel3Args is libvirt's remote_domain_migrate_prepare_tunnel3_args
+type DomainMigratePrepareTunnel3Args struct {
+ CookieIn []byte
+ Flags uint64
+ Dname OptString
+ Resource uint64
+ DomXML string
+}
+
+// DomainMigratePrepareTunnel3Ret is libvirt's remote_domain_migrate_prepare_tunnel3_ret
+type DomainMigratePrepareTunnel3Ret struct {
+ CookieOut []byte
+}
+
+// DomainMigratePerform3Args is libvirt's remote_domain_migrate_perform3_args
+type DomainMigratePerform3Args struct {
+ Dom Domain
+ Xmlin OptString
+ CookieIn []byte
+ Dconnuri OptString
+ Uri OptString
+ Flags uint64
+ Dname OptString
+ Resource uint64
+}
+
+// DomainMigratePerform3Ret is libvirt's remote_domain_migrate_perform3_ret
+type DomainMigratePerform3Ret struct {
+ CookieOut []byte
+}
+
+// DomainMigrateFinish3Args is libvirt's remote_domain_migrate_finish3_args
+type DomainMigrateFinish3Args struct {
+ Dname string
+ CookieIn []byte
+ Dconnuri OptString
+ Uri OptString
+ Flags uint64
+ Cancelled int32
+}
+
+// DomainMigrateFinish3Ret is libvirt's remote_domain_migrate_finish3_ret
+type DomainMigrateFinish3Ret struct {
+ Dom Domain
+ CookieOut []byte
+}
+
+// DomainMigrateConfirm3Args is libvirt's remote_domain_migrate_confirm3_args
+type DomainMigrateConfirm3Args struct {
+ Dom Domain
+ CookieIn []byte
+ Flags uint64
+ Cancelled int32
+}
+
+// DomainEventControlErrorMsg is libvirt's remote_domain_event_control_error_msg
+type DomainEventControlErrorMsg struct {
+ Dom Domain
+}
+
+// DomainEventCallbackControlErrorMsg is libvirt's remote_domain_event_callback_control_error_msg
+type DomainEventCallbackControlErrorMsg struct {
+ CallbackID int32
+ Msg DomainEventControlErrorMsg
+}
+
+// DomainGetControlInfoArgs is libvirt's remote_domain_get_control_info_args
+type DomainGetControlInfoArgs struct {
+ Dom Domain
+ Flags uint32
+}
+
+// DomainGetControlInfoRet is libvirt's remote_domain_get_control_info_ret
+type DomainGetControlInfoRet struct {
+ State uint32
+ Details uint32
+ StateTime uint64
+}
+
+// DomainOpenGraphicsArgs is libvirt's remote_domain_open_graphics_args
+type DomainOpenGraphicsArgs struct {
+ Dom Domain
+ Idx uint32
+ Flags DomainOpenGraphicsFlags
+}
+
+// DomainOpenGraphicsFdArgs is libvirt's remote_domain_open_graphics_fd_args
+type DomainOpenGraphicsFdArgs struct {
+ Dom Domain
+ Idx uint32
+ Flags DomainOpenGraphicsFlags
+}
+
+// NodeSuspendForDurationArgs is libvirt's remote_node_suspend_for_duration_args
+type NodeSuspendForDurationArgs struct {
+ Target uint32
+ Duration uint64
+ Flags uint32
+}
+
+// DomainShutdownFlagsArgs is libvirt's remote_domain_shutdown_flags_args
+type DomainShutdownFlagsArgs struct {
+ Dom Domain
+ Flags DomainShutdownFlagValues
+}
+
+// DomainGetDiskErrorsArgs is libvirt's remote_domain_get_disk_errors_args
+type DomainGetDiskErrorsArgs struct {
+ Dom Domain
+ Maxerrors uint32
+ Flags uint32
+}
+
+// DomainGetDiskErrorsRet is libvirt's remote_domain_get_disk_errors_ret
+type DomainGetDiskErrorsRet struct {
+ Errors []DomainDiskError
+ Nerrors int32
+}
+
+// ConnectListAllDomainsArgs is libvirt's remote_connect_list_all_domains_args
+type ConnectListAllDomainsArgs struct {
+ NeedResults int32
+ Flags ConnectListAllDomainsFlags
+}
+
+// ConnectListAllDomainsRet is libvirt's remote_connect_list_all_domains_ret
+type ConnectListAllDomainsRet struct {
+ Domains []Domain
+ Ret uint32
+}
+
+// ConnectListAllStoragePoolsArgs is libvirt's remote_connect_list_all_storage_pools_args
+type ConnectListAllStoragePoolsArgs struct {
+ NeedResults int32
+ Flags ConnectListAllStoragePoolsFlags
+}
+
+// ConnectListAllStoragePoolsRet is libvirt's remote_connect_list_all_storage_pools_ret
+type ConnectListAllStoragePoolsRet struct {
+ Pools []StoragePool
+ Ret uint32
+}
+
+// StoragePoolListAllVolumesArgs is libvirt's remote_storage_pool_list_all_volumes_args
+type StoragePoolListAllVolumesArgs struct {
+ Pool StoragePool
+ NeedResults int32
+ Flags uint32
+}
+
+// StoragePoolListAllVolumesRet is libvirt's remote_storage_pool_list_all_volumes_ret
+type StoragePoolListAllVolumesRet struct {
+ Vols []StorageVol
+ Ret uint32
+}
+
+// ConnectListAllNetworksArgs is libvirt's remote_connect_list_all_networks_args
+type ConnectListAllNetworksArgs struct {
+ NeedResults int32
+ Flags ConnectListAllNetworksFlags
+}
+
+// ConnectListAllNetworksRet is libvirt's remote_connect_list_all_networks_ret
+type ConnectListAllNetworksRet struct {
+ Nets []Network
+ Ret uint32
+}
+
+// ConnectListAllInterfacesArgs is libvirt's remote_connect_list_all_interfaces_args
+type ConnectListAllInterfacesArgs struct {
+ NeedResults int32
+ Flags ConnectListAllInterfacesFlags
+}
+
+// ConnectListAllInterfacesRet is libvirt's remote_connect_list_all_interfaces_ret
+type ConnectListAllInterfacesRet struct {
+ Ifaces []Interface
+ Ret uint32
+}
+
+// ConnectListAllNodeDevicesArgs is libvirt's remote_connect_list_all_node_devices_args
+type ConnectListAllNodeDevicesArgs struct {
+ NeedResults int32
+ Flags uint32
+}
+
+// ConnectListAllNodeDevicesRet is libvirt's remote_connect_list_all_node_devices_ret
+type ConnectListAllNodeDevicesRet struct {
+ Devices []NodeDevice
+ Ret uint32
+}
+
+// ConnectListAllNwfiltersArgs is libvirt's remote_connect_list_all_nwfilters_args
+type ConnectListAllNwfiltersArgs struct {
+ NeedResults int32
+ Flags uint32
+}
+
+// ConnectListAllNwfiltersRet is libvirt's remote_connect_list_all_nwfilters_ret
+type ConnectListAllNwfiltersRet struct {
+ Filters []Nwfilter
+ Ret uint32
+}
+
+// ConnectListAllSecretsArgs is libvirt's remote_connect_list_all_secrets_args
+type ConnectListAllSecretsArgs struct {
+ NeedResults int32
+ Flags ConnectListAllSecretsFlags
+}
+
+// ConnectListAllSecretsRet is libvirt's remote_connect_list_all_secrets_ret
+type ConnectListAllSecretsRet struct {
+ Secrets []Secret
+ Ret uint32
+}
+
+// NodeSetMemoryParametersArgs is libvirt's remote_node_set_memory_parameters_args
+type NodeSetMemoryParametersArgs struct {
+ Params []TypedParam
+ Flags uint32
+}
+
+// NodeGetMemoryParametersArgs is libvirt's remote_node_get_memory_parameters_args
+type NodeGetMemoryParametersArgs struct {
+ Nparams int32
+ Flags uint32
+}
+
+// NodeGetMemoryParametersRet is libvirt's remote_node_get_memory_parameters_ret
+type NodeGetMemoryParametersRet struct {
+ Params []TypedParam
+ Nparams int32
+}
+
+// NodeGetCPUMapArgs is libvirt's remote_node_get_cpu_map_args
+type NodeGetCPUMapArgs struct {
+ NeedMap int32
+ NeedOnline int32
+ Flags uint32
+}
+
+// NodeGetCPUMapRet is libvirt's remote_node_get_cpu_map_ret
+type NodeGetCPUMapRet struct {
+ Cpumap []byte
+ Online uint32
+ Ret int32
+}
+
+// DomainFstrimArgs is libvirt's remote_domain_fstrim_args
+type DomainFstrimArgs struct {
+ Dom Domain
+ MountPoint OptString
+ Minimum uint64
+ Flags uint32
+}
+
+// DomainGetTimeArgs is libvirt's remote_domain_get_time_args
+type DomainGetTimeArgs struct {
+ Dom Domain
+ Flags uint32
+}
+
+// DomainGetTimeRet is libvirt's remote_domain_get_time_ret
+type DomainGetTimeRet struct {
+ Seconds int64
+ Nseconds uint32
+}
+
+// DomainSetTimeArgs is libvirt's remote_domain_set_time_args
+type DomainSetTimeArgs struct {
+ Dom Domain
+ Seconds int64
+ Nseconds uint32
+ Flags DomainSetTimeFlags
+}
+
+// DomainMigrateBegin3ParamsArgs is libvirt's remote_domain_migrate_begin3_params_args
+type DomainMigrateBegin3ParamsArgs struct {
+ Dom Domain
+ Params []TypedParam
+ Flags uint32
+}
+
+// DomainMigrateBegin3ParamsRet is libvirt's remote_domain_migrate_begin3_params_ret
+type DomainMigrateBegin3ParamsRet struct {
+ CookieOut []byte
+ XML string
+}
+
+// DomainMigratePrepare3ParamsArgs is libvirt's remote_domain_migrate_prepare3_params_args
+type DomainMigratePrepare3ParamsArgs struct {
+ Params []TypedParam
+ CookieIn []byte
+ Flags uint32
+}
+
+// DomainMigratePrepare3ParamsRet is libvirt's remote_domain_migrate_prepare3_params_ret
+type DomainMigratePrepare3ParamsRet struct {
+ CookieOut []byte
+ UriOut OptString
+}
+
+// DomainMigratePrepareTunnel3ParamsArgs is libvirt's remote_domain_migrate_prepare_tunnel3_params_args
+type DomainMigratePrepareTunnel3ParamsArgs struct {
+ Params []TypedParam
+ CookieIn []byte
+ Flags uint32
+}
+
+// DomainMigratePrepareTunnel3ParamsRet is libvirt's remote_domain_migrate_prepare_tunnel3_params_ret
+type DomainMigratePrepareTunnel3ParamsRet struct {
+ CookieOut []byte
+}
+
+// DomainMigratePerform3ParamsArgs is libvirt's remote_domain_migrate_perform3_params_args
+type DomainMigratePerform3ParamsArgs struct {
+ Dom Domain
+ Dconnuri OptString
+ Params []TypedParam
+ CookieIn []byte
+ Flags DomainMigrateFlags
+}
+
+// DomainMigratePerform3ParamsRet is libvirt's remote_domain_migrate_perform3_params_ret
+type DomainMigratePerform3ParamsRet struct {
+ CookieOut []byte
+}
+
+// DomainMigrateFinish3ParamsArgs is libvirt's remote_domain_migrate_finish3_params_args
+type DomainMigrateFinish3ParamsArgs struct {
+ Params []TypedParam
+ CookieIn []byte
+ Flags uint32
+ Cancelled int32
+}
+
+// DomainMigrateFinish3ParamsRet is libvirt's remote_domain_migrate_finish3_params_ret
+type DomainMigrateFinish3ParamsRet struct {
+ Dom Domain
+ CookieOut []byte
+}
+
+// DomainMigrateConfirm3ParamsArgs is libvirt's remote_domain_migrate_confirm3_params_args
+type DomainMigrateConfirm3ParamsArgs struct {
+ Dom Domain
+ Params []TypedParam
+ CookieIn []byte
+ Flags uint32
+ Cancelled int32
+}
+
+// DomainEventDeviceRemovedMsg is libvirt's remote_domain_event_device_removed_msg
+type DomainEventDeviceRemovedMsg struct {
+ Dom Domain
+ DevAlias string
+}
+
+// DomainEventCallbackDeviceRemovedMsg is libvirt's remote_domain_event_callback_device_removed_msg
+type DomainEventCallbackDeviceRemovedMsg struct {
+ CallbackID int32
+ Msg DomainEventDeviceRemovedMsg
+}
+
+// DomainEventBlockJob2Msg is libvirt's remote_domain_event_block_job_2_msg
+type DomainEventBlockJob2Msg struct {
+ CallbackID int32
+ Dom Domain
+ Dst string
+ Type int32
+ Status int32
+}
+
+// DomainEventBlockThresholdMsg is libvirt's remote_domain_event_block_threshold_msg
+type DomainEventBlockThresholdMsg struct {
+ CallbackID int32
+ Dom Domain
+ Dev string
+ Path OptString
+ Threshold uint64
+ Excess uint64
+}
+
+// DomainEventCallbackTunableMsg is libvirt's remote_domain_event_callback_tunable_msg
+type DomainEventCallbackTunableMsg struct {
+ CallbackID int32
+ Dom Domain
+ Params []TypedParam
+}
+
+// DomainEventCallbackDeviceAddedMsg is libvirt's remote_domain_event_callback_device_added_msg
+type DomainEventCallbackDeviceAddedMsg struct {
+ CallbackID int32
+ Dom Domain
+ DevAlias string
+}
+
+// ConnectEventConnectionClosedMsg is libvirt's remote_connect_event_connection_closed_msg
+type ConnectEventConnectionClosedMsg struct {
+ Reason int32
+}
+
+// ConnectGetCPUModelNamesArgs is libvirt's remote_connect_get_cpu_model_names_args
+type ConnectGetCPUModelNamesArgs struct {
+ Arch string
+ NeedResults int32
+ Flags uint32
+}
+
+// ConnectGetCPUModelNamesRet is libvirt's remote_connect_get_cpu_model_names_ret
+type ConnectGetCPUModelNamesRet struct {
+ Models []string
+ Ret int32
+}
+
+// ConnectNetworkEventRegisterAnyArgs is libvirt's remote_connect_network_event_register_any_args
+type ConnectNetworkEventRegisterAnyArgs struct {
+ EventID int32
+ Net OptNetwork
+}
+
+// ConnectNetworkEventRegisterAnyRet is libvirt's remote_connect_network_event_register_any_ret
+type ConnectNetworkEventRegisterAnyRet struct {
+ CallbackID int32
+}
+
+// ConnectNetworkEventDeregisterAnyArgs is libvirt's remote_connect_network_event_deregister_any_args
+type ConnectNetworkEventDeregisterAnyArgs struct {
+ CallbackID int32
+}
+
+// NetworkEventLifecycleMsg is libvirt's remote_network_event_lifecycle_msg
+type NetworkEventLifecycleMsg struct {
+ CallbackID int32
+ Net Network
+ Event int32
+ Detail int32
+}
+
+// ConnectStoragePoolEventRegisterAnyArgs is libvirt's remote_connect_storage_pool_event_register_any_args
+type ConnectStoragePoolEventRegisterAnyArgs struct {
+ EventID int32
+ Pool OptStoragePool
+}
+
+// ConnectStoragePoolEventRegisterAnyRet is libvirt's remote_connect_storage_pool_event_register_any_ret
+type ConnectStoragePoolEventRegisterAnyRet struct {
+ CallbackID int32
+}
+
+// ConnectStoragePoolEventDeregisterAnyArgs is libvirt's remote_connect_storage_pool_event_deregister_any_args
+type ConnectStoragePoolEventDeregisterAnyArgs struct {
+ CallbackID int32
+}
+
+// StoragePoolEventLifecycleMsg is libvirt's remote_storage_pool_event_lifecycle_msg
+type StoragePoolEventLifecycleMsg struct {
+ CallbackID int32
+ Pool StoragePool
+ Event int32
+ Detail int32
+}
+
+// StoragePoolEventRefreshMsg is libvirt's remote_storage_pool_event_refresh_msg
+type StoragePoolEventRefreshMsg struct {
+ CallbackID int32
+ Pool StoragePool
+}
+
+// ConnectNodeDeviceEventRegisterAnyArgs is libvirt's remote_connect_node_device_event_register_any_args
+type ConnectNodeDeviceEventRegisterAnyArgs struct {
+ EventID int32
+ Dev OptNodeDevice
+}
+
+// ConnectNodeDeviceEventRegisterAnyRet is libvirt's remote_connect_node_device_event_register_any_ret
+type ConnectNodeDeviceEventRegisterAnyRet struct {
+ CallbackID int32
+}
+
+// ConnectNodeDeviceEventDeregisterAnyArgs is libvirt's remote_connect_node_device_event_deregister_any_args
+type ConnectNodeDeviceEventDeregisterAnyArgs struct {
+ CallbackID int32
+}
+
+// NodeDeviceEventLifecycleMsg is libvirt's remote_node_device_event_lifecycle_msg
+type NodeDeviceEventLifecycleMsg struct {
+ CallbackID int32
+ Dev NodeDevice
+ Event int32
+ Detail int32
+}
+
+// NodeDeviceEventUpdateMsg is libvirt's remote_node_device_event_update_msg
+type NodeDeviceEventUpdateMsg struct {
+ CallbackID int32
+ Dev NodeDevice
+}
+
+// DomainFsfreezeArgs is libvirt's remote_domain_fsfreeze_args
+type DomainFsfreezeArgs struct {
+ Dom Domain
+ Mountpoints []string
+ Flags uint32
+}
+
+// DomainFsfreezeRet is libvirt's remote_domain_fsfreeze_ret
+type DomainFsfreezeRet struct {
+ Filesystems int32
+}
+
+// DomainFsthawArgs is libvirt's remote_domain_fsthaw_args
+type DomainFsthawArgs struct {
+ Dom Domain
+ Mountpoints []string
+ Flags uint32
+}
+
+// DomainFsthawRet is libvirt's remote_domain_fsthaw_ret
+type DomainFsthawRet struct {
+ Filesystems int32
+}
+
+// NodeGetFreePagesArgs is libvirt's remote_node_get_free_pages_args
+type NodeGetFreePagesArgs struct {
+ Pages []uint32
+ StartCell int32
+ CellCount uint32
+ Flags uint32
+}
+
+// NodeGetFreePagesRet is libvirt's remote_node_get_free_pages_ret
+type NodeGetFreePagesRet struct {
+ Counts []uint64
+}
+
+// NodeAllocPagesArgs is libvirt's remote_node_alloc_pages_args
+type NodeAllocPagesArgs struct {
+ PageSizes []uint32
+ PageCounts []uint64
+ StartCell int32
+ CellCount uint32
+ Flags NodeAllocPagesFlags
+}
+
+// NodeAllocPagesRet is libvirt's remote_node_alloc_pages_ret
+type NodeAllocPagesRet struct {
+ Ret int32
+}
+
+// NetworkDhcpLease is libvirt's remote_network_dhcp_lease
+type NetworkDhcpLease struct {
+ Iface string
+ Expirytime int64
+ Type int32
+ Mac OptString
+ Iaid OptString
+ Ipaddr string
+ Prefix uint32
+ Hostname OptString
+ Clientid OptString
+}
+
+// NetworkGetDhcpLeasesArgs is libvirt's remote_network_get_dhcp_leases_args
+type NetworkGetDhcpLeasesArgs struct {
+ Net Network
+ Mac OptString
+ NeedResults int32
+ Flags uint32
+}
+
+// NetworkGetDhcpLeasesRet is libvirt's remote_network_get_dhcp_leases_ret
+type NetworkGetDhcpLeasesRet struct {
+ Leases []NetworkDhcpLease
+ Ret uint32
+}
+
+// DomainStatsRecord is libvirt's remote_domain_stats_record
+type DomainStatsRecord struct {
+ Dom Domain
+ Params []TypedParam
+}
+
+// ConnectGetAllDomainStatsArgs is libvirt's remote_connect_get_all_domain_stats_args
+type ConnectGetAllDomainStatsArgs struct {
+ Doms []Domain
+ Stats uint32
+ Flags ConnectGetAllDomainStatsFlags
+}
+
+// DomainEventCallbackAgentLifecycleMsg is libvirt's remote_domain_event_callback_agent_lifecycle_msg
+type DomainEventCallbackAgentLifecycleMsg struct {
+ CallbackID int32
+ Dom Domain
+ State int32
+ Reason int32
+}
+
+// ConnectGetAllDomainStatsRet is libvirt's remote_connect_get_all_domain_stats_ret
+type ConnectGetAllDomainStatsRet struct {
+ RetStats []DomainStatsRecord
+}
+
+// DomainFsinfo is libvirt's remote_domain_fsinfo
+type DomainFsinfo struct {
+ Mountpoint string
+ Name string
+ Fstype string
+ DevAliases []string
+}
+
+// DomainGetFsinfoArgs is libvirt's remote_domain_get_fsinfo_args
+type DomainGetFsinfoArgs struct {
+ Dom Domain
+ Flags uint32
+}
+
+// DomainGetFsinfoRet is libvirt's remote_domain_get_fsinfo_ret
+type DomainGetFsinfoRet struct {
+ Info []DomainFsinfo
+ Ret uint32
+}
+
+// DomainIPAddr is libvirt's remote_domain_ip_addr
+type DomainIPAddr struct {
+ Type int32
+ Addr string
+ Prefix uint32
+}
+
+// DomainInterface is libvirt's remote_domain_interface
+type DomainInterface struct {
+ Name string
+ Hwaddr OptString
+ Addrs []DomainIPAddr
+}
+
+// DomainInterfaceAddressesArgs is libvirt's remote_domain_interface_addresses_args
+type DomainInterfaceAddressesArgs struct {
+ Dom Domain
+ Source uint32
+ Flags uint32
+}
+
+// DomainInterfaceAddressesRet is libvirt's remote_domain_interface_addresses_ret
+type DomainInterfaceAddressesRet struct {
+ Ifaces []DomainInterface
+}
+
+// DomainSetUserPasswordArgs is libvirt's remote_domain_set_user_password_args
+type DomainSetUserPasswordArgs struct {
+ Dom Domain
+ User OptString
+ Password OptString
+ Flags DomainSetUserPasswordFlags
+}
+
+// DomainRenameArgs is libvirt's remote_domain_rename_args
+type DomainRenameArgs struct {
+ Dom Domain
+ NewName OptString
+ Flags uint32
+}
+
+// DomainRenameRet is libvirt's remote_domain_rename_ret
+type DomainRenameRet struct {
+ Retcode int32
+}
+
+// DomainEventCallbackMigrationIterationMsg is libvirt's remote_domain_event_callback_migration_iteration_msg
+type DomainEventCallbackMigrationIterationMsg struct {
+ CallbackID int32
+ Dom Domain
+ Iteration int32
+}
+
+// DomainEventCallbackJobCompletedMsg is libvirt's remote_domain_event_callback_job_completed_msg
+type DomainEventCallbackJobCompletedMsg struct {
+ CallbackID int32
+ Dom Domain
+ Params []TypedParam
+}
+
+// DomainMigrateStartPostCopyArgs is libvirt's remote_domain_migrate_start_post_copy_args
+type DomainMigrateStartPostCopyArgs struct {
+ Dom Domain
+ Flags uint32
+}
+
+// DomainEventCallbackDeviceRemovalFailedMsg is libvirt's remote_domain_event_callback_device_removal_failed_msg
+type DomainEventCallbackDeviceRemovalFailedMsg struct {
+ CallbackID int32
+ Dom Domain
+ DevAlias string
+}
+
+// DomainGetGuestVcpusArgs is libvirt's remote_domain_get_guest_vcpus_args
+type DomainGetGuestVcpusArgs struct {
+ Dom Domain
+ Flags uint32
+}
+
+// DomainGetGuestVcpusRet is libvirt's remote_domain_get_guest_vcpus_ret
+type DomainGetGuestVcpusRet struct {
+ Params []TypedParam
+}
+
+// DomainSetGuestVcpusArgs is libvirt's remote_domain_set_guest_vcpus_args
+type DomainSetGuestVcpusArgs struct {
+ Dom Domain
+ Cpumap string
+ State int32
+ Flags uint32
+}
+
+// DomainSetVcpuArgs is libvirt's remote_domain_set_vcpu_args
+type DomainSetVcpuArgs struct {
+ Dom Domain
+ Cpumap string
+ State int32
+ Flags DomainModificationImpact
+}
+
+// DomainEventCallbackMetadataChangeMsg is libvirt's remote_domain_event_callback_metadata_change_msg
+type DomainEventCallbackMetadataChangeMsg struct {
+ CallbackID int32
+ Dom Domain
+ Type int32
+ Nsuri OptString
+}
+
+// DomainEventMemoryFailureMsg is libvirt's remote_domain_event_memory_failure_msg
+type DomainEventMemoryFailureMsg struct {
+ CallbackID int32
+ Dom Domain
+ Recipient int32
+ Action int32
+ Flags uint32
+}
+
+// ConnectSecretEventRegisterAnyArgs is libvirt's remote_connect_secret_event_register_any_args
+type ConnectSecretEventRegisterAnyArgs struct {
+ EventID int32
+ OptSecret OptSecret
+}
+
+// ConnectSecretEventRegisterAnyRet is libvirt's remote_connect_secret_event_register_any_ret
+type ConnectSecretEventRegisterAnyRet struct {
+ CallbackID int32
+}
+
+// ConnectSecretEventDeregisterAnyArgs is libvirt's remote_connect_secret_event_deregister_any_args
+type ConnectSecretEventDeregisterAnyArgs struct {
+ CallbackID int32
+}
+
+// SecretEventLifecycleMsg is libvirt's remote_secret_event_lifecycle_msg
+type SecretEventLifecycleMsg struct {
+ CallbackID int32
+ OptSecret Secret
+ Event int32
+ Detail int32
+}
+
+// SecretEventValueChangedMsg is libvirt's remote_secret_event_value_changed_msg
+type SecretEventValueChangedMsg struct {
+ CallbackID int32
+ OptSecret Secret
+}
+
+// DomainSetBlockThresholdArgs is libvirt's remote_domain_set_block_threshold_args
+type DomainSetBlockThresholdArgs struct {
+ Dom Domain
+ Dev string
+ Threshold uint64
+ Flags uint32
+}
+
+// DomainSetLifecycleActionArgs is libvirt's remote_domain_set_lifecycle_action_args
+type DomainSetLifecycleActionArgs struct {
+ Dom Domain
+ Type uint32
+ Action uint32
+ Flags DomainModificationImpact
+}
+
+// ConnectCompareHypervisorCPUArgs is libvirt's remote_connect_compare_hypervisor_cpu_args
+type ConnectCompareHypervisorCPUArgs struct {
+ Emulator OptString
+ Arch OptString
+ Machine OptString
+ Virttype OptString
+ XMLCPU string
+ Flags uint32
+}
+
+// ConnectCompareHypervisorCPURet is libvirt's remote_connect_compare_hypervisor_cpu_ret
+type ConnectCompareHypervisorCPURet struct {
+ Result int32
+}
+
+// ConnectBaselineHypervisorCPUArgs is libvirt's remote_connect_baseline_hypervisor_cpu_args
+type ConnectBaselineHypervisorCPUArgs struct {
+ Emulator OptString
+ Arch OptString
+ Machine OptString
+ Virttype OptString
+ XMLCPUs []string
+ Flags uint32
+}
+
+// ConnectBaselineHypervisorCPURet is libvirt's remote_connect_baseline_hypervisor_cpu_ret
+type ConnectBaselineHypervisorCPURet struct {
+ CPU string
+}
+
+// NodeGetSevInfoArgs is libvirt's remote_node_get_sev_info_args
+type NodeGetSevInfoArgs struct {
+ Nparams int32
+ Flags uint32
+}
+
+// NodeGetSevInfoRet is libvirt's remote_node_get_sev_info_ret
+type NodeGetSevInfoRet struct {
+ Params []TypedParam
+ Nparams int32
+}
+
+// DomainGetLaunchSecurityInfoArgs is libvirt's remote_domain_get_launch_security_info_args
+type DomainGetLaunchSecurityInfoArgs struct {
+ Dom Domain
+ Flags uint32
+}
+
+// DomainGetLaunchSecurityInfoRet is libvirt's remote_domain_get_launch_security_info_ret
+type DomainGetLaunchSecurityInfoRet struct {
+ Params []TypedParam
+}
+
+// DomainSetLaunchSecurityStateArgs is libvirt's remote_domain_set_launch_security_state_args
+type DomainSetLaunchSecurityStateArgs struct {
+ Dom Domain
+ Params []TypedParam
+ Flags uint32
+}
+
+// NwfilterBindingLookupByPortDevArgs is libvirt's remote_nwfilter_binding_lookup_by_port_dev_args
+type NwfilterBindingLookupByPortDevArgs struct {
+ Name string
+}
+
+// NwfilterBindingLookupByPortDevRet is libvirt's remote_nwfilter_binding_lookup_by_port_dev_ret
+type NwfilterBindingLookupByPortDevRet struct {
+ OptNwfilter NwfilterBinding
+}
+
+// NwfilterBindingCreateXMLArgs is libvirt's remote_nwfilter_binding_create_xml_args
+type NwfilterBindingCreateXMLArgs struct {
+ XML string
+ Flags uint32
+}
+
+// NwfilterBindingCreateXMLRet is libvirt's remote_nwfilter_binding_create_xml_ret
+type NwfilterBindingCreateXMLRet struct {
+ OptNwfilter NwfilterBinding
+}
+
+// NwfilterBindingDeleteArgs is libvirt's remote_nwfilter_binding_delete_args
+type NwfilterBindingDeleteArgs struct {
+ OptNwfilter NwfilterBinding
+}
+
+// NwfilterBindingGetXMLDescArgs is libvirt's remote_nwfilter_binding_get_xml_desc_args
+type NwfilterBindingGetXMLDescArgs struct {
+ OptNwfilter NwfilterBinding
+ Flags uint32
+}
+
+// NwfilterBindingGetXMLDescRet is libvirt's remote_nwfilter_binding_get_xml_desc_ret
+type NwfilterBindingGetXMLDescRet struct {
+ XML string
+}
+
+// ConnectListAllNwfilterBindingsArgs is libvirt's remote_connect_list_all_nwfilter_bindings_args
+type ConnectListAllNwfilterBindingsArgs struct {
+ NeedResults int32
+ Flags uint32
+}
+
+// ConnectListAllNwfilterBindingsRet is libvirt's remote_connect_list_all_nwfilter_bindings_ret
+type ConnectListAllNwfilterBindingsRet struct {
+ Bindings []NwfilterBinding
+ Ret uint32
+}
+
+// ConnectGetStoragePoolCapabilitiesArgs is libvirt's remote_connect_get_storage_pool_capabilities_args
+type ConnectGetStoragePoolCapabilitiesArgs struct {
+ Flags uint32
+}
+
+// ConnectGetStoragePoolCapabilitiesRet is libvirt's remote_connect_get_storage_pool_capabilities_ret
+type ConnectGetStoragePoolCapabilitiesRet struct {
+ Capabilities string
+}
+
+// NetworkListAllPortsArgs is libvirt's remote_network_list_all_ports_args
+type NetworkListAllPortsArgs struct {
+ OptNetwork Network
+ NeedResults int32
+ Flags uint32
+}
+
+// NetworkListAllPortsRet is libvirt's remote_network_list_all_ports_ret
+type NetworkListAllPortsRet struct {
+ Ports []NetworkPort
+ Ret uint32
+}
+
+// NetworkPortLookupByUUIDArgs is libvirt's remote_network_port_lookup_by_uuid_args
+type NetworkPortLookupByUUIDArgs struct {
+ OptNetwork Network
+ UUID UUID
+}
+
+// NetworkPortLookupByUUIDRet is libvirt's remote_network_port_lookup_by_uuid_ret
+type NetworkPortLookupByUUIDRet struct {
+ Port NetworkPort
+}
+
+// NetworkPortCreateXMLArgs is libvirt's remote_network_port_create_xml_args
+type NetworkPortCreateXMLArgs struct {
+ OptNetwork Network
+ XML string
+ Flags uint32
+}
+
+// NetworkPortCreateXMLRet is libvirt's remote_network_port_create_xml_ret
+type NetworkPortCreateXMLRet struct {
+ Port NetworkPort
+}
+
+// NetworkPortSetParametersArgs is libvirt's remote_network_port_set_parameters_args
+type NetworkPortSetParametersArgs struct {
+ Port NetworkPort
+ Params []TypedParam
+ Flags uint32
+}
+
+// NetworkPortGetParametersArgs is libvirt's remote_network_port_get_parameters_args
+type NetworkPortGetParametersArgs struct {
+ Port NetworkPort
+ Nparams int32
+ Flags uint32
+}
+
+// NetworkPortGetParametersRet is libvirt's remote_network_port_get_parameters_ret
+type NetworkPortGetParametersRet struct {
+ Params []TypedParam
+ Nparams int32
+}
+
+// NetworkPortGetXMLDescArgs is libvirt's remote_network_port_get_xml_desc_args
+type NetworkPortGetXMLDescArgs struct {
+ Port NetworkPort
+ Flags uint32
+}
+
+// NetworkPortGetXMLDescRet is libvirt's remote_network_port_get_xml_desc_ret
+type NetworkPortGetXMLDescRet struct {
+ XML string
+}
+
+// NetworkPortDeleteArgs is libvirt's remote_network_port_delete_args
+type NetworkPortDeleteArgs struct {
+ Port NetworkPort
+ Flags uint32
+}
+
+// DomainCheckpointCreateXMLArgs is libvirt's remote_domain_checkpoint_create_xml_args
+type DomainCheckpointCreateXMLArgs struct {
+ Dom Domain
+ XMLDesc string
+ Flags uint32
+}
+
+// DomainCheckpointCreateXMLRet is libvirt's remote_domain_checkpoint_create_xml_ret
+type DomainCheckpointCreateXMLRet struct {
+ Checkpoint DomainCheckpoint
+}
+
+// DomainCheckpointGetXMLDescArgs is libvirt's remote_domain_checkpoint_get_xml_desc_args
+type DomainCheckpointGetXMLDescArgs struct {
+ Checkpoint DomainCheckpoint
+ Flags uint32
+}
+
+// DomainCheckpointGetXMLDescRet is libvirt's remote_domain_checkpoint_get_xml_desc_ret
+type DomainCheckpointGetXMLDescRet struct {
+ XML string
+}
+
+// DomainListAllCheckpointsArgs is libvirt's remote_domain_list_all_checkpoints_args
+type DomainListAllCheckpointsArgs struct {
+ Dom Domain
+ NeedResults int32
+ Flags uint32
+}
+
+// DomainListAllCheckpointsRet is libvirt's remote_domain_list_all_checkpoints_ret
+type DomainListAllCheckpointsRet struct {
+ Checkpoints []DomainCheckpoint
+ Ret int32
+}
+
+// DomainCheckpointListAllChildrenArgs is libvirt's remote_domain_checkpoint_list_all_children_args
+type DomainCheckpointListAllChildrenArgs struct {
+ Checkpoint DomainCheckpoint
+ NeedResults int32
+ Flags uint32
+}
+
+// DomainCheckpointListAllChildrenRet is libvirt's remote_domain_checkpoint_list_all_children_ret
+type DomainCheckpointListAllChildrenRet struct {
+ Checkpoints []DomainCheckpoint
+ Ret int32
+}
+
+// DomainCheckpointLookupByNameArgs is libvirt's remote_domain_checkpoint_lookup_by_name_args
+type DomainCheckpointLookupByNameArgs struct {
+ Dom Domain
+ Name string
+ Flags uint32
+}
+
+// DomainCheckpointLookupByNameRet is libvirt's remote_domain_checkpoint_lookup_by_name_ret
+type DomainCheckpointLookupByNameRet struct {
+ Checkpoint DomainCheckpoint
+}
+
+// DomainCheckpointGetParentArgs is libvirt's remote_domain_checkpoint_get_parent_args
+type DomainCheckpointGetParentArgs struct {
+ Checkpoint DomainCheckpoint
+ Flags uint32
+}
+
+// DomainCheckpointGetParentRet is libvirt's remote_domain_checkpoint_get_parent_ret
+type DomainCheckpointGetParentRet struct {
+ Parent DomainCheckpoint
+}
+
+// DomainCheckpointDeleteArgs is libvirt's remote_domain_checkpoint_delete_args
+type DomainCheckpointDeleteArgs struct {
+ Checkpoint DomainCheckpoint
+ Flags DomainCheckpointDeleteFlags
+}
+
+// DomainGetGuestInfoArgs is libvirt's remote_domain_get_guest_info_args
+type DomainGetGuestInfoArgs struct {
+ Dom Domain
+ Types uint32
+ Flags uint32
+}
+
+// DomainGetGuestInfoRet is libvirt's remote_domain_get_guest_info_ret
+type DomainGetGuestInfoRet struct {
+ Params []TypedParam
+}
+
+// ConnectSetIdentityArgs is libvirt's remote_connect_set_identity_args
+type ConnectSetIdentityArgs struct {
+ Params []TypedParam
+ Flags uint32
+}
+
+// DomainAgentSetResponseTimeoutArgs is libvirt's remote_domain_agent_set_response_timeout_args
+type DomainAgentSetResponseTimeoutArgs struct {
+ Dom Domain
+ Timeout int32
+ Flags uint32
+}
+
+// DomainAgentSetResponseTimeoutRet is libvirt's remote_domain_agent_set_response_timeout_ret
+type DomainAgentSetResponseTimeoutRet struct {
+ Result int32
+}
+
+// DomainBackupBeginArgs is libvirt's remote_domain_backup_begin_args
+type DomainBackupBeginArgs struct {
+ Dom Domain
+ BackupXML string
+ CheckpointXML OptString
+ Flags DomainBackupBeginFlags
+}
+
+// DomainBackupGetXMLDescArgs is libvirt's remote_domain_backup_get_xml_desc_args
+type DomainBackupGetXMLDescArgs struct {
+ Dom Domain
+ Flags uint32
+}
+
+// DomainBackupGetXMLDescRet is libvirt's remote_domain_backup_get_xml_desc_ret
+type DomainBackupGetXMLDescRet struct {
+ XML string
+}
+
+// DomainAuthorizedSshKeysGetArgs is libvirt's remote_domain_authorized_ssh_keys_get_args
+type DomainAuthorizedSshKeysGetArgs struct {
+ Dom Domain
+ User string
+ Flags uint32
+}
+
+// DomainAuthorizedSshKeysGetRet is libvirt's remote_domain_authorized_ssh_keys_get_ret
+type DomainAuthorizedSshKeysGetRet struct {
+ Keys []string
+}
+
+// DomainAuthorizedSshKeysSetArgs is libvirt's remote_domain_authorized_ssh_keys_set_args
+type DomainAuthorizedSshKeysSetArgs struct {
+ Dom Domain
+ User string
+ Keys []string
+ 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
+}
+
+// DomainStartDirtyRateCalcArgs is libvirt's remote_domain_start_dirty_rate_calc_args
+type DomainStartDirtyRateCalcArgs struct {
+ Dom Domain
+ Seconds int32
+ Flags uint32
+}
+
+// DomainEventMemoryDeviceSizeChangeMsg is libvirt's remote_domain_event_memory_device_size_change_msg
+type DomainEventMemoryDeviceSizeChangeMsg struct {
+ CallbackID int32
+ Dom Domain
+ Alias string
+ Size uint64
+}
+
+// TypedParamValue is a discriminated union.
+type TypedParamValue struct {
+ D uint32
+ I interface{}
+}
+
+// NewTypedParamValueInt creates a discriminated union value satisfying
+// the TypedParamValue interface.
+func NewTypedParamValueInt(v int32) *TypedParamValue {
+ return &TypedParamValue{D: 1, I: v}
+}
+
+// NewTypedParamValueUint creates a discriminated union value satisfying
+// the TypedParamValue interface.
+func NewTypedParamValueUint(v uint32) *TypedParamValue {
+ return &TypedParamValue{D: 2, I: v}
+}
+
+// NewTypedParamValueLlong creates a discriminated union value satisfying
+// the TypedParamValue interface.
+func NewTypedParamValueLlong(v int64) *TypedParamValue {
+ return &TypedParamValue{D: 3, I: v}
+}
+
+// NewTypedParamValueUllong creates a discriminated union value satisfying
+// the TypedParamValue interface.
+func NewTypedParamValueUllong(v uint64) *TypedParamValue {
+ return &TypedParamValue{D: 4, I: v}
+}
+
+// NewTypedParamValueDouble creates a discriminated union value satisfying
+// the TypedParamValue interface.
+func NewTypedParamValueDouble(v float64) *TypedParamValue {
+ return &TypedParamValue{D: 5, I: v}
+}
+
+// NewTypedParamValueBoolean creates a discriminated union value satisfying
+// the TypedParamValue interface.
+func NewTypedParamValueBoolean(v int32) *TypedParamValue {
+ return &TypedParamValue{D: 6, I: v}
+}
+
+// NewTypedParamValueString creates a discriminated union value satisfying
+// the TypedParamValue interface.
+func NewTypedParamValueString(v string) *TypedParamValue {
+ return &TypedParamValue{D: 7, I: v}
+}
+
+// ConnectOpen is the go wrapper for REMOTE_PROC_CONNECT_OPEN.
+func (l *Libvirt) ConnectOpen(Name OptString, Flags ConnectFlags) (err error) {
+ var buf []byte
+
+ args := ConnectOpenArgs{
+ Name: Name,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(1, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectClose is the go wrapper for REMOTE_PROC_CONNECT_CLOSE.
+func (l *Libvirt) ConnectClose() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(2, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectGetType is the go wrapper for REMOTE_PROC_CONNECT_GET_TYPE.
+func (l *Libvirt) ConnectGetType() (rType string, err error) {
+ var buf []byte
+
+ var r response
+ r, err = l.requestStream(3, 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)
+ // Type: string
+ _, err = dec.Decode(&rType)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectGetVersion is the go wrapper for REMOTE_PROC_CONNECT_GET_VERSION.
+func (l *Libvirt) ConnectGetVersion() (rHvVer uint64, err error) {
+ var buf []byte
+
+ var r response
+ r, err = l.requestStream(4, 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)
+ // HvVer: uint64
+ _, err = dec.Decode(&rHvVer)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectGetMaxVcpus is the go wrapper for REMOTE_PROC_CONNECT_GET_MAX_VCPUS.
+func (l *Libvirt) ConnectGetMaxVcpus(Type OptString) (rMaxVcpus int32, err error) {
+ var buf []byte
+
+ args := ConnectGetMaxVcpusArgs{
+ Type: Type,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(5, 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)
+ // MaxVcpus: int32
+ _, err = dec.Decode(&rMaxVcpus)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeGetInfo is the go wrapper for REMOTE_PROC_NODE_GET_INFO.
+func (l *Libvirt) NodeGetInfo() (rModel [32]int8, rMemory uint64, rCpus int32, rMhz int32, rNodes int32, rSockets int32, rCores int32, rThreads int32, err error) {
+ var buf []byte
+
+ var r response
+ r, err = l.requestStream(6, 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)
+ // Model: [32]int8
+ _, err = dec.Decode(&rModel)
+ if err != nil {
+ return
+ }
+ // Memory: uint64
+ _, err = dec.Decode(&rMemory)
+ if err != nil {
+ return
+ }
+ // Cpus: int32
+ _, err = dec.Decode(&rCpus)
+ if err != nil {
+ return
+ }
+ // Mhz: int32
+ _, err = dec.Decode(&rMhz)
+ if err != nil {
+ return
+ }
+ // Nodes: int32
+ _, err = dec.Decode(&rNodes)
+ if err != nil {
+ return
+ }
+ // Sockets: int32
+ _, err = dec.Decode(&rSockets)
+ if err != nil {
+ return
+ }
+ // Cores: int32
+ _, err = dec.Decode(&rCores)
+ if err != nil {
+ return
+ }
+ // Threads: int32
+ _, err = dec.Decode(&rThreads)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectGetCapabilities is the go wrapper for REMOTE_PROC_CONNECT_GET_CAPABILITIES.
+func (l *Libvirt) ConnectGetCapabilities() (rCapabilities string, err error) {
+ var buf []byte
+
+ var r response
+ r, err = l.requestStream(7, 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)
+ // Capabilities: string
+ _, err = dec.Decode(&rCapabilities)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainAttachDevice is the go wrapper for REMOTE_PROC_DOMAIN_ATTACH_DEVICE.
+func (l *Libvirt) DomainAttachDevice(Dom Domain, XML string) (err error) {
+ var buf []byte
+
+ args := DomainAttachDeviceArgs{
+ Dom: Dom,
+ XML: XML,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(8, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainCreate is the go wrapper for REMOTE_PROC_DOMAIN_CREATE.
+func (l *Libvirt) DomainCreate(Dom Domain) (err error) {
+ var buf []byte
+
+ args := DomainCreateArgs{
+ Dom: Dom,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(9, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainCreateXML is the go wrapper for REMOTE_PROC_DOMAIN_CREATE_XML.
+func (l *Libvirt) DomainCreateXML(XMLDesc string, Flags DomainCreateFlags) (rDom Domain, err error) {
+ var buf []byte
+
+ args := DomainCreateXMLArgs{
+ XMLDesc: XMLDesc,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(10, 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)
+ // Dom: Domain
+ _, err = dec.Decode(&rDom)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainDefineXML is the go wrapper for REMOTE_PROC_DOMAIN_DEFINE_XML.
+func (l *Libvirt) DomainDefineXML(XML string) (rDom Domain, err error) {
+ var buf []byte
+
+ args := DomainDefineXMLArgs{
+ XML: XML,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(11, 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)
+ // Dom: Domain
+ _, err = dec.Decode(&rDom)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainDestroy is the go wrapper for REMOTE_PROC_DOMAIN_DESTROY.
+func (l *Libvirt) DomainDestroy(Dom Domain) (err error) {
+ var buf []byte
+
+ args := DomainDestroyArgs{
+ Dom: Dom,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(12, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainDetachDevice is the go wrapper for REMOTE_PROC_DOMAIN_DETACH_DEVICE.
+func (l *Libvirt) DomainDetachDevice(Dom Domain, XML string) (err error) {
+ var buf []byte
+
+ args := DomainDetachDeviceArgs{
+ Dom: Dom,
+ XML: XML,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(13, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetXMLDesc is the go wrapper for REMOTE_PROC_DOMAIN_GET_XML_DESC.
+func (l *Libvirt) DomainGetXMLDesc(Dom Domain, Flags DomainXMLFlags) (rXML string, err error) {
+ var buf []byte
+
+ args := DomainGetXMLDescArgs{
+ Dom: Dom,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(14, 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)
+ // XML: string
+ _, err = dec.Decode(&rXML)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetAutostart is the go wrapper for REMOTE_PROC_DOMAIN_GET_AUTOSTART.
+func (l *Libvirt) DomainGetAutostart(Dom Domain) (rAutostart int32, err error) {
+ var buf []byte
+
+ args := DomainGetAutostartArgs{
+ Dom: Dom,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(15, 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)
+ // Autostart: int32
+ _, err = dec.Decode(&rAutostart)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetInfo is the go wrapper for REMOTE_PROC_DOMAIN_GET_INFO.
+func (l *Libvirt) DomainGetInfo(Dom Domain) (rState uint8, rMaxMem uint64, rMemory uint64, rNrVirtCPU uint16, rCPUTime uint64, err error) {
+ var buf []byte
+
+ args := DomainGetInfoArgs{
+ Dom: Dom,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(16, 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)
+ // State: uint8
+ _, err = dec.Decode(&rState)
+ if err != nil {
+ return
+ }
+ // MaxMem: uint64
+ _, err = dec.Decode(&rMaxMem)
+ if err != nil {
+ return
+ }
+ // Memory: uint64
+ _, err = dec.Decode(&rMemory)
+ if err != nil {
+ return
+ }
+ // NrVirtCPU: uint16
+ _, err = dec.Decode(&rNrVirtCPU)
+ if err != nil {
+ return
+ }
+ // CPUTime: uint64
+ _, err = dec.Decode(&rCPUTime)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetMaxMemory is the go wrapper for REMOTE_PROC_DOMAIN_GET_MAX_MEMORY.
+func (l *Libvirt) DomainGetMaxMemory(Dom Domain) (rMemory uint64, err error) {
+ var buf []byte
+
+ args := DomainGetMaxMemoryArgs{
+ Dom: Dom,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(17, 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)
+ // Memory: uint64
+ _, err = dec.Decode(&rMemory)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetMaxVcpus is the go wrapper for REMOTE_PROC_DOMAIN_GET_MAX_VCPUS.
+func (l *Libvirt) DomainGetMaxVcpus(Dom Domain) (rNum int32, err error) {
+ var buf []byte
+
+ args := DomainGetMaxVcpusArgs{
+ Dom: Dom,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(18, 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)
+ // Num: int32
+ _, err = dec.Decode(&rNum)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetOsType is the go wrapper for REMOTE_PROC_DOMAIN_GET_OS_TYPE.
+func (l *Libvirt) DomainGetOsType(Dom Domain) (rType string, err error) {
+ var buf []byte
+
+ args := DomainGetOsTypeArgs{
+ Dom: Dom,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(19, 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)
+ // Type: string
+ _, err = dec.Decode(&rType)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetVcpus is the go wrapper for REMOTE_PROC_DOMAIN_GET_VCPUS.
+func (l *Libvirt) DomainGetVcpus(Dom Domain, Maxinfo int32, Maplen int32) (rInfo []VcpuInfo, rCpumaps []byte, err error) {
+ var buf []byte
+
+ args := DomainGetVcpusArgs{
+ Dom: Dom,
+ Maxinfo: Maxinfo,
+ Maplen: Maplen,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(20, 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)
+ // Info: []VcpuInfo
+ _, err = dec.Decode(&rInfo)
+ if err != nil {
+ return
+ }
+ // Cpumaps: []byte
+ _, err = dec.Decode(&rCpumaps)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectListDefinedDomains is the go wrapper for REMOTE_PROC_CONNECT_LIST_DEFINED_DOMAINS.
+func (l *Libvirt) ConnectListDefinedDomains(Maxnames int32) (rNames []string, err error) {
+ var buf []byte
+
+ args := ConnectListDefinedDomainsArgs{
+ Maxnames: Maxnames,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(21, 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)
+ // Names: []string
+ _, err = dec.Decode(&rNames)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainLookupByID is the go wrapper for REMOTE_PROC_DOMAIN_LOOKUP_BY_ID.
+func (l *Libvirt) DomainLookupByID(ID int32) (rDom Domain, err error) {
+ var buf []byte
+
+ args := DomainLookupByIDArgs{
+ ID: ID,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(22, 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)
+ // Dom: Domain
+ _, err = dec.Decode(&rDom)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainLookupByName is the go wrapper for REMOTE_PROC_DOMAIN_LOOKUP_BY_NAME.
+func (l *Libvirt) DomainLookupByName(Name string) (rDom Domain, err error) {
+ var buf []byte
+
+ args := DomainLookupByNameArgs{
+ Name: Name,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(23, 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)
+ // Dom: Domain
+ _, err = dec.Decode(&rDom)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainLookupByUUID is the go wrapper for REMOTE_PROC_DOMAIN_LOOKUP_BY_UUID.
+func (l *Libvirt) DomainLookupByUUID(UUID UUID) (rDom Domain, err error) {
+ var buf []byte
+
+ args := DomainLookupByUUIDArgs{
+ UUID: UUID,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(24, 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)
+ // Dom: Domain
+ _, err = dec.Decode(&rDom)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectNumOfDefinedDomains is the go wrapper for REMOTE_PROC_CONNECT_NUM_OF_DEFINED_DOMAINS.
+func (l *Libvirt) ConnectNumOfDefinedDomains() (rNum int32, err error) {
+ var buf []byte
+
+ var r response
+ r, err = l.requestStream(25, 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)
+ // Num: int32
+ _, err = dec.Decode(&rNum)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainPinVcpu is the go wrapper for REMOTE_PROC_DOMAIN_PIN_VCPU.
+func (l *Libvirt) DomainPinVcpu(Dom Domain, Vcpu uint32, Cpumap []byte) (err error) {
+ var buf []byte
+
+ args := DomainPinVcpuArgs{
+ Dom: Dom,
+ Vcpu: Vcpu,
+ Cpumap: Cpumap,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(26, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainReboot is the go wrapper for REMOTE_PROC_DOMAIN_REBOOT.
+func (l *Libvirt) DomainReboot(Dom Domain, Flags DomainRebootFlagValues) (err error) {
+ var buf []byte
+
+ args := DomainRebootArgs{
+ Dom: Dom,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(27, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainResume is the go wrapper for REMOTE_PROC_DOMAIN_RESUME.
+func (l *Libvirt) DomainResume(Dom Domain) (err error) {
+ var buf []byte
+
+ args := DomainResumeArgs{
+ Dom: Dom,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(28, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSetAutostart is the go wrapper for REMOTE_PROC_DOMAIN_SET_AUTOSTART.
+func (l *Libvirt) DomainSetAutostart(Dom Domain, Autostart int32) (err error) {
+ var buf []byte
+
+ args := DomainSetAutostartArgs{
+ Dom: Dom,
+ Autostart: Autostart,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(29, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSetMaxMemory is the go wrapper for REMOTE_PROC_DOMAIN_SET_MAX_MEMORY.
+func (l *Libvirt) DomainSetMaxMemory(Dom Domain, Memory uint64) (err error) {
+ var buf []byte
+
+ args := DomainSetMaxMemoryArgs{
+ Dom: Dom,
+ Memory: Memory,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(30, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSetMemory is the go wrapper for REMOTE_PROC_DOMAIN_SET_MEMORY.
+func (l *Libvirt) DomainSetMemory(Dom Domain, Memory uint64) (err error) {
+ var buf []byte
+
+ args := DomainSetMemoryArgs{
+ Dom: Dom,
+ Memory: Memory,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(31, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSetVcpus is the go wrapper for REMOTE_PROC_DOMAIN_SET_VCPUS.
+func (l *Libvirt) DomainSetVcpus(Dom Domain, Nvcpus uint32) (err error) {
+ var buf []byte
+
+ args := DomainSetVcpusArgs{
+ Dom: Dom,
+ Nvcpus: Nvcpus,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(32, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainShutdown is the go wrapper for REMOTE_PROC_DOMAIN_SHUTDOWN.
+func (l *Libvirt) DomainShutdown(Dom Domain) (err error) {
+ var buf []byte
+
+ args := DomainShutdownArgs{
+ Dom: Dom,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(33, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSuspend is the go wrapper for REMOTE_PROC_DOMAIN_SUSPEND.
+func (l *Libvirt) DomainSuspend(Dom Domain) (err error) {
+ var buf []byte
+
+ args := DomainSuspendArgs{
+ Dom: Dom,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(34, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainUndefine is the go wrapper for REMOTE_PROC_DOMAIN_UNDEFINE.
+func (l *Libvirt) DomainUndefine(Dom Domain) (err error) {
+ var buf []byte
+
+ args := DomainUndefineArgs{
+ Dom: Dom,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(35, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectListDefinedNetworks is the go wrapper for REMOTE_PROC_CONNECT_LIST_DEFINED_NETWORKS.
+func (l *Libvirt) ConnectListDefinedNetworks(Maxnames int32) (rNames []string, err error) {
+ var buf []byte
+
+ args := ConnectListDefinedNetworksArgs{
+ Maxnames: Maxnames,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(36, 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)
+ // Names: []string
+ _, err = dec.Decode(&rNames)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectListDomains is the go wrapper for REMOTE_PROC_CONNECT_LIST_DOMAINS.
+func (l *Libvirt) ConnectListDomains(Maxids int32) (rIds []int32, err error) {
+ var buf []byte
+
+ args := ConnectListDomainsArgs{
+ Maxids: Maxids,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(37, 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)
+ // Ids: []int32
+ _, err = dec.Decode(&rIds)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectListNetworks is the go wrapper for REMOTE_PROC_CONNECT_LIST_NETWORKS.
+func (l *Libvirt) ConnectListNetworks(Maxnames int32) (rNames []string, err error) {
+ var buf []byte
+
+ args := ConnectListNetworksArgs{
+ Maxnames: Maxnames,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(38, 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)
+ // Names: []string
+ _, err = dec.Decode(&rNames)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NetworkCreate is the go wrapper for REMOTE_PROC_NETWORK_CREATE.
+func (l *Libvirt) NetworkCreate(Net Network) (err error) {
+ var buf []byte
+
+ args := NetworkCreateArgs{
+ Net: Net,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(39, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NetworkCreateXML is the go wrapper for REMOTE_PROC_NETWORK_CREATE_XML.
+func (l *Libvirt) NetworkCreateXML(XML string) (rNet Network, err error) {
+ var buf []byte
+
+ args := NetworkCreateXMLArgs{
+ XML: XML,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(40, 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)
+ // Net: Network
+ _, err = dec.Decode(&rNet)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NetworkDefineXML is the go wrapper for REMOTE_PROC_NETWORK_DEFINE_XML.
+func (l *Libvirt) NetworkDefineXML(XML string) (rNet Network, err error) {
+ var buf []byte
+
+ args := NetworkDefineXMLArgs{
+ XML: XML,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(41, 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)
+ // Net: Network
+ _, err = dec.Decode(&rNet)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NetworkDestroy is the go wrapper for REMOTE_PROC_NETWORK_DESTROY.
+func (l *Libvirt) NetworkDestroy(Net Network) (err error) {
+ var buf []byte
+
+ args := NetworkDestroyArgs{
+ Net: Net,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(42, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NetworkGetXMLDesc is the go wrapper for REMOTE_PROC_NETWORK_GET_XML_DESC.
+func (l *Libvirt) NetworkGetXMLDesc(Net Network, Flags uint32) (rXML string, err error) {
+ var buf []byte
+
+ args := NetworkGetXMLDescArgs{
+ Net: Net,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(43, 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)
+ // XML: string
+ _, err = dec.Decode(&rXML)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NetworkGetAutostart is the go wrapper for REMOTE_PROC_NETWORK_GET_AUTOSTART.
+func (l *Libvirt) NetworkGetAutostart(Net Network) (rAutostart int32, err error) {
+ var buf []byte
+
+ args := NetworkGetAutostartArgs{
+ Net: Net,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(44, 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)
+ // Autostart: int32
+ _, err = dec.Decode(&rAutostart)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NetworkGetBridgeName is the go wrapper for REMOTE_PROC_NETWORK_GET_BRIDGE_NAME.
+func (l *Libvirt) NetworkGetBridgeName(Net Network) (rName string, err error) {
+ var buf []byte
+
+ args := NetworkGetBridgeNameArgs{
+ Net: Net,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(45, 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)
+ // Name: string
+ _, err = dec.Decode(&rName)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NetworkLookupByName is the go wrapper for REMOTE_PROC_NETWORK_LOOKUP_BY_NAME.
+func (l *Libvirt) NetworkLookupByName(Name string) (rNet Network, err error) {
+ var buf []byte
+
+ args := NetworkLookupByNameArgs{
+ Name: Name,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(46, 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)
+ // Net: Network
+ _, err = dec.Decode(&rNet)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NetworkLookupByUUID is the go wrapper for REMOTE_PROC_NETWORK_LOOKUP_BY_UUID.
+func (l *Libvirt) NetworkLookupByUUID(UUID UUID) (rNet Network, err error) {
+ var buf []byte
+
+ args := NetworkLookupByUUIDArgs{
+ UUID: UUID,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(47, 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)
+ // Net: Network
+ _, err = dec.Decode(&rNet)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NetworkSetAutostart is the go wrapper for REMOTE_PROC_NETWORK_SET_AUTOSTART.
+func (l *Libvirt) NetworkSetAutostart(Net Network, Autostart int32) (err error) {
+ var buf []byte
+
+ args := NetworkSetAutostartArgs{
+ Net: Net,
+ Autostart: Autostart,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(48, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NetworkUndefine is the go wrapper for REMOTE_PROC_NETWORK_UNDEFINE.
+func (l *Libvirt) NetworkUndefine(Net Network) (err error) {
+ var buf []byte
+
+ args := NetworkUndefineArgs{
+ Net: Net,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(49, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectNumOfDefinedNetworks is the go wrapper for REMOTE_PROC_CONNECT_NUM_OF_DEFINED_NETWORKS.
+func (l *Libvirt) ConnectNumOfDefinedNetworks() (rNum int32, err error) {
+ var buf []byte
+
+ var r response
+ r, err = l.requestStream(50, 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)
+ // Num: int32
+ _, err = dec.Decode(&rNum)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectNumOfDomains is the go wrapper for REMOTE_PROC_CONNECT_NUM_OF_DOMAINS.
+func (l *Libvirt) ConnectNumOfDomains() (rNum int32, err error) {
+ var buf []byte
+
+ var r response
+ r, err = l.requestStream(51, 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)
+ // Num: int32
+ _, err = dec.Decode(&rNum)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectNumOfNetworks is the go wrapper for REMOTE_PROC_CONNECT_NUM_OF_NETWORKS.
+func (l *Libvirt) ConnectNumOfNetworks() (rNum int32, err error) {
+ var buf []byte
+
+ var r response
+ r, err = l.requestStream(52, 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)
+ // Num: int32
+ _, err = dec.Decode(&rNum)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainCoreDump is the go wrapper for REMOTE_PROC_DOMAIN_CORE_DUMP.
+func (l *Libvirt) DomainCoreDump(Dom Domain, To string, Flags DomainCoreDumpFlags) (err error) {
+ var buf []byte
+
+ args := DomainCoreDumpArgs{
+ Dom: Dom,
+ To: To,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(53, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainRestore is the go wrapper for REMOTE_PROC_DOMAIN_RESTORE.
+func (l *Libvirt) DomainRestore(From string) (err error) {
+ var buf []byte
+
+ args := DomainRestoreArgs{
+ From: From,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(54, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSave is the go wrapper for REMOTE_PROC_DOMAIN_SAVE.
+func (l *Libvirt) DomainSave(Dom Domain, To string) (err error) {
+ var buf []byte
+
+ args := DomainSaveArgs{
+ Dom: Dom,
+ To: To,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(55, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetSchedulerType is the go wrapper for REMOTE_PROC_DOMAIN_GET_SCHEDULER_TYPE.
+func (l *Libvirt) DomainGetSchedulerType(Dom Domain) (rType string, rNparams int32, err error) {
+ var buf []byte
+
+ args := DomainGetSchedulerTypeArgs{
+ Dom: Dom,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(56, 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)
+ // Type: string
+ _, err = dec.Decode(&rType)
+ if err != nil {
+ return
+ }
+ // Nparams: int32
+ _, err = dec.Decode(&rNparams)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetSchedulerParameters is the go wrapper for REMOTE_PROC_DOMAIN_GET_SCHEDULER_PARAMETERS.
+func (l *Libvirt) DomainGetSchedulerParameters(Dom Domain, Nparams int32) (rParams []TypedParam, err error) {
+ var buf []byte
+
+ args := DomainGetSchedulerParametersArgs{
+ Dom: Dom,
+ Nparams: Nparams,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(57, 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)
+ // Params: []TypedParam
+ _, err = dec.Decode(&rParams)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSetSchedulerParameters is the go wrapper for REMOTE_PROC_DOMAIN_SET_SCHEDULER_PARAMETERS.
+func (l *Libvirt) DomainSetSchedulerParameters(Dom Domain, Params []TypedParam) (err error) {
+ var buf []byte
+
+ args := DomainSetSchedulerParametersArgs{
+ Dom: Dom,
+ Params: Params,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(58, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectGetHostname is the go wrapper for REMOTE_PROC_CONNECT_GET_HOSTNAME.
+func (l *Libvirt) ConnectGetHostname() (rHostname string, err error) {
+ var buf []byte
+
+ var r response
+ r, err = l.requestStream(59, 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)
+ // Hostname: string
+ _, err = dec.Decode(&rHostname)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectSupportsFeature is the go wrapper for REMOTE_PROC_CONNECT_SUPPORTS_FEATURE.
+func (l *Libvirt) ConnectSupportsFeature(Feature int32) (rSupported int32, err error) {
+ var buf []byte
+
+ args := ConnectSupportsFeatureArgs{
+ Feature: Feature,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(60, 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)
+ // Supported: int32
+ _, err = dec.Decode(&rSupported)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainMigratePrepare is the go wrapper for REMOTE_PROC_DOMAIN_MIGRATE_PREPARE.
+func (l *Libvirt) DomainMigratePrepare(UriIn OptString, Flags uint64, Dname OptString, Resource uint64) (rCookie []byte, rUriOut OptString, err error) {
+ var buf []byte
+
+ args := DomainMigratePrepareArgs{
+ UriIn: UriIn,
+ Flags: Flags,
+ Dname: Dname,
+ Resource: Resource,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(61, 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)
+ // Cookie: []byte
+ _, err = dec.Decode(&rCookie)
+ if err != nil {
+ return
+ }
+ // UriOut: OptString
+ _, err = dec.Decode(&rUriOut)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainMigratePerform is the go wrapper for REMOTE_PROC_DOMAIN_MIGRATE_PERFORM.
+func (l *Libvirt) DomainMigratePerform(Dom Domain, Cookie []byte, Uri string, Flags uint64, Dname OptString, Resource uint64) (err error) {
+ var buf []byte
+
+ args := DomainMigratePerformArgs{
+ Dom: Dom,
+ Cookie: Cookie,
+ Uri: Uri,
+ Flags: Flags,
+ Dname: Dname,
+ Resource: Resource,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(62, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainMigrateFinish is the go wrapper for REMOTE_PROC_DOMAIN_MIGRATE_FINISH.
+func (l *Libvirt) DomainMigrateFinish(Dname string, Cookie []byte, Uri string, Flags uint64) (rDdom Domain, err error) {
+ var buf []byte
+
+ args := DomainMigrateFinishArgs{
+ Dname: Dname,
+ Cookie: Cookie,
+ Uri: Uri,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(63, 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)
+ // Ddom: Domain
+ _, err = dec.Decode(&rDdom)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainBlockStats is the go wrapper for REMOTE_PROC_DOMAIN_BLOCK_STATS.
+func (l *Libvirt) DomainBlockStats(Dom Domain, Path string) (rRdReq int64, rRdBytes int64, rWrReq int64, rWrBytes int64, rErrs int64, err error) {
+ var buf []byte
+
+ args := DomainBlockStatsArgs{
+ Dom: Dom,
+ Path: Path,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(64, 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)
+ // RdReq: int64
+ _, err = dec.Decode(&rRdReq)
+ if err != nil {
+ return
+ }
+ // RdBytes: int64
+ _, err = dec.Decode(&rRdBytes)
+ if err != nil {
+ return
+ }
+ // WrReq: int64
+ _, err = dec.Decode(&rWrReq)
+ if err != nil {
+ return
+ }
+ // WrBytes: int64
+ _, err = dec.Decode(&rWrBytes)
+ if err != nil {
+ return
+ }
+ // Errs: int64
+ _, err = dec.Decode(&rErrs)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainInterfaceStats is the go wrapper for REMOTE_PROC_DOMAIN_INTERFACE_STATS.
+func (l *Libvirt) DomainInterfaceStats(Dom Domain, Device string) (rRxBytes int64, rRxPackets int64, rRxErrs int64, rRxDrop int64, rTxBytes int64, rTxPackets int64, rTxErrs int64, rTxDrop int64, err error) {
+ var buf []byte
+
+ args := DomainInterfaceStatsArgs{
+ Dom: Dom,
+ Device: Device,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(65, 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)
+ // RxBytes: int64
+ _, err = dec.Decode(&rRxBytes)
+ if err != nil {
+ return
+ }
+ // RxPackets: int64
+ _, err = dec.Decode(&rRxPackets)
+ if err != nil {
+ return
+ }
+ // RxErrs: int64
+ _, err = dec.Decode(&rRxErrs)
+ if err != nil {
+ return
+ }
+ // RxDrop: int64
+ _, err = dec.Decode(&rRxDrop)
+ if err != nil {
+ return
+ }
+ // TxBytes: int64
+ _, err = dec.Decode(&rTxBytes)
+ if err != nil {
+ return
+ }
+ // TxPackets: int64
+ _, err = dec.Decode(&rTxPackets)
+ if err != nil {
+ return
+ }
+ // TxErrs: int64
+ _, err = dec.Decode(&rTxErrs)
+ if err != nil {
+ return
+ }
+ // TxDrop: int64
+ _, err = dec.Decode(&rTxDrop)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// AuthList is the go wrapper for REMOTE_PROC_AUTH_LIST.
+func (l *Libvirt) AuthList() (rTypes []AuthType, err error) {
+ var buf []byte
+
+ var r response
+ r, err = l.requestStream(66, 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)
+ // Types: []AuthType
+ _, err = dec.Decode(&rTypes)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// AuthSaslInit is the go wrapper for REMOTE_PROC_AUTH_SASL_INIT.
+func (l *Libvirt) AuthSaslInit() (rMechlist string, err error) {
+ var buf []byte
+
+ var r response
+ r, err = l.requestStream(67, 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)
+ // Mechlist: string
+ _, err = dec.Decode(&rMechlist)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// AuthSaslStart is the go wrapper for REMOTE_PROC_AUTH_SASL_START.
+func (l *Libvirt) AuthSaslStart(Mech string, Nil int32, Data []int8) (rComplete int32, rNil int32, rData []int8, err error) {
+ var buf []byte
+
+ args := AuthSaslStartArgs{
+ Mech: Mech,
+ Nil: Nil,
+ Data: Data,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(68, 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)
+ // Complete: int32
+ _, err = dec.Decode(&rComplete)
+ if err != nil {
+ return
+ }
+ // Nil: int32
+ _, err = dec.Decode(&rNil)
+ if err != nil {
+ return
+ }
+ // Data: []int8
+ _, err = dec.Decode(&rData)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// AuthSaslStep is the go wrapper for REMOTE_PROC_AUTH_SASL_STEP.
+func (l *Libvirt) AuthSaslStep(Nil int32, Data []int8) (rComplete int32, rNil int32, rData []int8, err error) {
+ var buf []byte
+
+ args := AuthSaslStepArgs{
+ Nil: Nil,
+ Data: Data,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(69, 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)
+ // Complete: int32
+ _, err = dec.Decode(&rComplete)
+ if err != nil {
+ return
+ }
+ // Nil: int32
+ _, err = dec.Decode(&rNil)
+ if err != nil {
+ return
+ }
+ // Data: []int8
+ _, err = dec.Decode(&rData)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// AuthPolkit is the go wrapper for REMOTE_PROC_AUTH_POLKIT.
+func (l *Libvirt) AuthPolkit() (rComplete int32, err error) {
+ var buf []byte
+
+ var r response
+ r, err = l.requestStream(70, 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)
+ // Complete: int32
+ _, err = dec.Decode(&rComplete)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectNumOfStoragePools is the go wrapper for REMOTE_PROC_CONNECT_NUM_OF_STORAGE_POOLS.
+func (l *Libvirt) ConnectNumOfStoragePools() (rNum int32, err error) {
+ var buf []byte
+
+ var r response
+ r, err = l.requestStream(71, 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)
+ // Num: int32
+ _, err = dec.Decode(&rNum)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectListStoragePools is the go wrapper for REMOTE_PROC_CONNECT_LIST_STORAGE_POOLS.
+func (l *Libvirt) ConnectListStoragePools(Maxnames int32) (rNames []string, err error) {
+ var buf []byte
+
+ args := ConnectListStoragePoolsArgs{
+ Maxnames: Maxnames,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(72, 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)
+ // Names: []string
+ _, err = dec.Decode(&rNames)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectNumOfDefinedStoragePools is the go wrapper for REMOTE_PROC_CONNECT_NUM_OF_DEFINED_STORAGE_POOLS.
+func (l *Libvirt) ConnectNumOfDefinedStoragePools() (rNum int32, err error) {
+ var buf []byte
+
+ var r response
+ r, err = l.requestStream(73, 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)
+ // Num: int32
+ _, err = dec.Decode(&rNum)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectListDefinedStoragePools is the go wrapper for REMOTE_PROC_CONNECT_LIST_DEFINED_STORAGE_POOLS.
+func (l *Libvirt) ConnectListDefinedStoragePools(Maxnames int32) (rNames []string, err error) {
+ var buf []byte
+
+ args := ConnectListDefinedStoragePoolsArgs{
+ Maxnames: Maxnames,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(74, 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)
+ // Names: []string
+ _, err = dec.Decode(&rNames)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectFindStoragePoolSources is the go wrapper for REMOTE_PROC_CONNECT_FIND_STORAGE_POOL_SOURCES.
+func (l *Libvirt) ConnectFindStoragePoolSources(Type string, SrcSpec OptString, Flags uint32) (rXML string, err error) {
+ var buf []byte
+
+ args := ConnectFindStoragePoolSourcesArgs{
+ Type: Type,
+ SrcSpec: SrcSpec,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(75, 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)
+ // XML: string
+ _, err = dec.Decode(&rXML)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StoragePoolCreateXML is the go wrapper for REMOTE_PROC_STORAGE_POOL_CREATE_XML.
+func (l *Libvirt) StoragePoolCreateXML(XML string, Flags StoragePoolCreateFlags) (rPool StoragePool, err error) {
+ var buf []byte
+
+ args := StoragePoolCreateXMLArgs{
+ XML: XML,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(76, 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)
+ // Pool: StoragePool
+ _, err = dec.Decode(&rPool)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StoragePoolDefineXML is the go wrapper for REMOTE_PROC_STORAGE_POOL_DEFINE_XML.
+func (l *Libvirt) StoragePoolDefineXML(XML string, Flags uint32) (rPool StoragePool, err error) {
+ var buf []byte
+
+ args := StoragePoolDefineXMLArgs{
+ XML: XML,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(77, 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)
+ // Pool: StoragePool
+ _, err = dec.Decode(&rPool)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StoragePoolCreate is the go wrapper for REMOTE_PROC_STORAGE_POOL_CREATE.
+func (l *Libvirt) StoragePoolCreate(Pool StoragePool, Flags StoragePoolCreateFlags) (err error) {
+ var buf []byte
+
+ args := StoragePoolCreateArgs{
+ Pool: Pool,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(78, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StoragePoolBuild is the go wrapper for REMOTE_PROC_STORAGE_POOL_BUILD.
+func (l *Libvirt) StoragePoolBuild(Pool StoragePool, Flags StoragePoolBuildFlags) (err error) {
+ var buf []byte
+
+ args := StoragePoolBuildArgs{
+ Pool: Pool,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(79, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StoragePoolDestroy is the go wrapper for REMOTE_PROC_STORAGE_POOL_DESTROY.
+func (l *Libvirt) StoragePoolDestroy(Pool StoragePool) (err error) {
+ var buf []byte
+
+ args := StoragePoolDestroyArgs{
+ Pool: Pool,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(80, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StoragePoolDelete is the go wrapper for REMOTE_PROC_STORAGE_POOL_DELETE.
+func (l *Libvirt) StoragePoolDelete(Pool StoragePool, Flags StoragePoolDeleteFlags) (err error) {
+ var buf []byte
+
+ args := StoragePoolDeleteArgs{
+ Pool: Pool,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(81, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StoragePoolUndefine is the go wrapper for REMOTE_PROC_STORAGE_POOL_UNDEFINE.
+func (l *Libvirt) StoragePoolUndefine(Pool StoragePool) (err error) {
+ var buf []byte
+
+ args := StoragePoolUndefineArgs{
+ Pool: Pool,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(82, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StoragePoolRefresh is the go wrapper for REMOTE_PROC_STORAGE_POOL_REFRESH.
+func (l *Libvirt) StoragePoolRefresh(Pool StoragePool, Flags uint32) (err error) {
+ var buf []byte
+
+ args := StoragePoolRefreshArgs{
+ Pool: Pool,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(83, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StoragePoolLookupByName is the go wrapper for REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_NAME.
+func (l *Libvirt) StoragePoolLookupByName(Name string) (rPool StoragePool, err error) {
+ var buf []byte
+
+ args := StoragePoolLookupByNameArgs{
+ Name: Name,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(84, 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)
+ // Pool: StoragePool
+ _, err = dec.Decode(&rPool)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StoragePoolLookupByUUID is the go wrapper for REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_UUID.
+func (l *Libvirt) StoragePoolLookupByUUID(UUID UUID) (rPool StoragePool, err error) {
+ var buf []byte
+
+ args := StoragePoolLookupByUUIDArgs{
+ UUID: UUID,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(85, 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)
+ // Pool: StoragePool
+ _, err = dec.Decode(&rPool)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StoragePoolLookupByVolume is the go wrapper for REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_VOLUME.
+func (l *Libvirt) StoragePoolLookupByVolume(Vol StorageVol) (rPool StoragePool, err error) {
+ var buf []byte
+
+ args := StoragePoolLookupByVolumeArgs{
+ Vol: Vol,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(86, 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)
+ // Pool: StoragePool
+ _, err = dec.Decode(&rPool)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StoragePoolGetInfo is the go wrapper for REMOTE_PROC_STORAGE_POOL_GET_INFO.
+func (l *Libvirt) StoragePoolGetInfo(Pool StoragePool) (rState uint8, rCapacity uint64, rAllocation uint64, rAvailable uint64, err error) {
+ var buf []byte
+
+ args := StoragePoolGetInfoArgs{
+ Pool: Pool,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(87, 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)
+ // State: uint8
+ _, err = dec.Decode(&rState)
+ if err != nil {
+ return
+ }
+ // Capacity: uint64
+ _, err = dec.Decode(&rCapacity)
+ if err != nil {
+ return
+ }
+ // Allocation: uint64
+ _, err = dec.Decode(&rAllocation)
+ if err != nil {
+ return
+ }
+ // Available: uint64
+ _, err = dec.Decode(&rAvailable)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StoragePoolGetXMLDesc is the go wrapper for REMOTE_PROC_STORAGE_POOL_GET_XML_DESC.
+func (l *Libvirt) StoragePoolGetXMLDesc(Pool StoragePool, Flags StorageXMLFlags) (rXML string, err error) {
+ var buf []byte
+
+ args := StoragePoolGetXMLDescArgs{
+ Pool: Pool,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(88, 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)
+ // XML: string
+ _, err = dec.Decode(&rXML)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StoragePoolGetAutostart is the go wrapper for REMOTE_PROC_STORAGE_POOL_GET_AUTOSTART.
+func (l *Libvirt) StoragePoolGetAutostart(Pool StoragePool) (rAutostart int32, err error) {
+ var buf []byte
+
+ args := StoragePoolGetAutostartArgs{
+ Pool: Pool,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(89, 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)
+ // Autostart: int32
+ _, err = dec.Decode(&rAutostart)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StoragePoolSetAutostart is the go wrapper for REMOTE_PROC_STORAGE_POOL_SET_AUTOSTART.
+func (l *Libvirt) StoragePoolSetAutostart(Pool StoragePool, Autostart int32) (err error) {
+ var buf []byte
+
+ args := StoragePoolSetAutostartArgs{
+ Pool: Pool,
+ Autostart: Autostart,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(90, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StoragePoolNumOfVolumes is the go wrapper for REMOTE_PROC_STORAGE_POOL_NUM_OF_VOLUMES.
+func (l *Libvirt) StoragePoolNumOfVolumes(Pool StoragePool) (rNum int32, err error) {
+ var buf []byte
+
+ args := StoragePoolNumOfVolumesArgs{
+ Pool: Pool,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(91, 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)
+ // Num: int32
+ _, err = dec.Decode(&rNum)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StoragePoolListVolumes is the go wrapper for REMOTE_PROC_STORAGE_POOL_LIST_VOLUMES.
+func (l *Libvirt) StoragePoolListVolumes(Pool StoragePool, Maxnames int32) (rNames []string, err error) {
+ var buf []byte
+
+ args := StoragePoolListVolumesArgs{
+ Pool: Pool,
+ Maxnames: Maxnames,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(92, 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)
+ // Names: []string
+ _, err = dec.Decode(&rNames)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StorageVolCreateXML is the go wrapper for REMOTE_PROC_STORAGE_VOL_CREATE_XML.
+func (l *Libvirt) StorageVolCreateXML(Pool StoragePool, XML string, Flags StorageVolCreateFlags) (rVol StorageVol, err error) {
+ var buf []byte
+
+ args := StorageVolCreateXMLArgs{
+ Pool: Pool,
+ XML: XML,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(93, 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)
+ // Vol: StorageVol
+ _, err = dec.Decode(&rVol)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StorageVolDelete is the go wrapper for REMOTE_PROC_STORAGE_VOL_DELETE.
+func (l *Libvirt) StorageVolDelete(Vol StorageVol, Flags StorageVolDeleteFlags) (err error) {
+ var buf []byte
+
+ args := StorageVolDeleteArgs{
+ Vol: Vol,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(94, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StorageVolLookupByName is the go wrapper for REMOTE_PROC_STORAGE_VOL_LOOKUP_BY_NAME.
+func (l *Libvirt) StorageVolLookupByName(Pool StoragePool, Name string) (rVol StorageVol, err error) {
+ var buf []byte
+
+ args := StorageVolLookupByNameArgs{
+ Pool: Pool,
+ Name: Name,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(95, 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)
+ // Vol: StorageVol
+ _, err = dec.Decode(&rVol)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StorageVolLookupByKey is the go wrapper for REMOTE_PROC_STORAGE_VOL_LOOKUP_BY_KEY.
+func (l *Libvirt) StorageVolLookupByKey(Key string) (rVol StorageVol, err error) {
+ var buf []byte
+
+ args := StorageVolLookupByKeyArgs{
+ Key: Key,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(96, 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)
+ // Vol: StorageVol
+ _, err = dec.Decode(&rVol)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StorageVolLookupByPath is the go wrapper for REMOTE_PROC_STORAGE_VOL_LOOKUP_BY_PATH.
+func (l *Libvirt) StorageVolLookupByPath(Path string) (rVol StorageVol, err error) {
+ var buf []byte
+
+ args := StorageVolLookupByPathArgs{
+ Path: Path,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(97, 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)
+ // Vol: StorageVol
+ _, err = dec.Decode(&rVol)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StorageVolGetInfo is the go wrapper for REMOTE_PROC_STORAGE_VOL_GET_INFO.
+func (l *Libvirt) StorageVolGetInfo(Vol StorageVol) (rType int8, rCapacity uint64, rAllocation uint64, err error) {
+ var buf []byte
+
+ args := StorageVolGetInfoArgs{
+ Vol: Vol,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(98, 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)
+ // Type: int8
+ _, err = dec.Decode(&rType)
+ if err != nil {
+ return
+ }
+ // Capacity: uint64
+ _, err = dec.Decode(&rCapacity)
+ if err != nil {
+ return
+ }
+ // Allocation: uint64
+ _, err = dec.Decode(&rAllocation)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StorageVolGetXMLDesc is the go wrapper for REMOTE_PROC_STORAGE_VOL_GET_XML_DESC.
+func (l *Libvirt) StorageVolGetXMLDesc(Vol StorageVol, Flags uint32) (rXML string, err error) {
+ var buf []byte
+
+ args := StorageVolGetXMLDescArgs{
+ Vol: Vol,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(99, 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)
+ // XML: string
+ _, err = dec.Decode(&rXML)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StorageVolGetPath is the go wrapper for REMOTE_PROC_STORAGE_VOL_GET_PATH.
+func (l *Libvirt) StorageVolGetPath(Vol StorageVol) (rName string, err error) {
+ var buf []byte
+
+ args := StorageVolGetPathArgs{
+ Vol: Vol,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(100, 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)
+ // Name: string
+ _, err = dec.Decode(&rName)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeGetCellsFreeMemory is the go wrapper for REMOTE_PROC_NODE_GET_CELLS_FREE_MEMORY.
+func (l *Libvirt) NodeGetCellsFreeMemory(StartCell int32, Maxcells int32) (rCells []uint64, err error) {
+ var buf []byte
+
+ args := NodeGetCellsFreeMemoryArgs{
+ StartCell: StartCell,
+ Maxcells: Maxcells,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(101, 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)
+ // Cells: []uint64
+ _, err = dec.Decode(&rCells)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeGetFreeMemory is the go wrapper for REMOTE_PROC_NODE_GET_FREE_MEMORY.
+func (l *Libvirt) NodeGetFreeMemory() (rFreeMem uint64, err error) {
+ var buf []byte
+
+ var r response
+ r, err = l.requestStream(102, 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)
+ // FreeMem: uint64
+ _, err = dec.Decode(&rFreeMem)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainBlockPeek is the go wrapper for REMOTE_PROC_DOMAIN_BLOCK_PEEK.
+func (l *Libvirt) DomainBlockPeek(Dom Domain, Path string, Offset uint64, Size uint32, Flags uint32) (rBuffer []byte, err error) {
+ var buf []byte
+
+ args := DomainBlockPeekArgs{
+ Dom: Dom,
+ Path: Path,
+ Offset: Offset,
+ Size: Size,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(103, 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)
+ // Buffer: []byte
+ _, err = dec.Decode(&rBuffer)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainMemoryPeek is the go wrapper for REMOTE_PROC_DOMAIN_MEMORY_PEEK.
+func (l *Libvirt) DomainMemoryPeek(Dom Domain, Offset uint64, Size uint32, Flags DomainMemoryFlags) (rBuffer []byte, err error) {
+ var buf []byte
+
+ args := DomainMemoryPeekArgs{
+ Dom: Dom,
+ Offset: Offset,
+ Size: Size,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(104, 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)
+ // Buffer: []byte
+ _, err = dec.Decode(&rBuffer)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectDomainEventRegister is the go wrapper for REMOTE_PROC_CONNECT_DOMAIN_EVENT_REGISTER.
+func (l *Libvirt) ConnectDomainEventRegister() (rCbRegistered int32, err error) {
+ var buf []byte
+
+ var r response
+ r, err = l.requestStream(105, 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)
+ // CbRegistered: int32
+ _, err = dec.Decode(&rCbRegistered)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectDomainEventDeregister is the go wrapper for REMOTE_PROC_CONNECT_DOMAIN_EVENT_DEREGISTER.
+func (l *Libvirt) ConnectDomainEventDeregister() (rCbRegistered int32, err error) {
+ var buf []byte
+
+ var r response
+ r, err = l.requestStream(106, 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)
+ // CbRegistered: int32
+ _, err = dec.Decode(&rCbRegistered)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventLifecycle is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_LIFECYCLE.
+func (l *Libvirt) DomainEventLifecycle() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(107, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainMigratePrepare2 is the go wrapper for REMOTE_PROC_DOMAIN_MIGRATE_PREPARE2.
+func (l *Libvirt) DomainMigratePrepare2(UriIn OptString, Flags uint64, Dname OptString, Resource uint64, DomXML string) (rCookie []byte, rUriOut OptString, err error) {
+ var buf []byte
+
+ args := DomainMigratePrepare2Args{
+ UriIn: UriIn,
+ Flags: Flags,
+ Dname: Dname,
+ Resource: Resource,
+ DomXML: DomXML,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(108, 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)
+ // Cookie: []byte
+ _, err = dec.Decode(&rCookie)
+ if err != nil {
+ return
+ }
+ // UriOut: OptString
+ _, err = dec.Decode(&rUriOut)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainMigrateFinish2 is the go wrapper for REMOTE_PROC_DOMAIN_MIGRATE_FINISH2.
+func (l *Libvirt) DomainMigrateFinish2(Dname string, Cookie []byte, Uri string, Flags uint64, Retcode int32) (rDdom Domain, err error) {
+ var buf []byte
+
+ args := DomainMigrateFinish2Args{
+ Dname: Dname,
+ Cookie: Cookie,
+ Uri: Uri,
+ Flags: Flags,
+ Retcode: Retcode,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(109, 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)
+ // Ddom: Domain
+ _, err = dec.Decode(&rDdom)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectGetUri is the go wrapper for REMOTE_PROC_CONNECT_GET_URI.
+func (l *Libvirt) ConnectGetUri() (rUri string, err error) {
+ var buf []byte
+
+ var r response
+ r, err = l.requestStream(110, 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)
+ // Uri: string
+ _, err = dec.Decode(&rUri)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeNumOfDevices is the go wrapper for REMOTE_PROC_NODE_NUM_OF_DEVICES.
+func (l *Libvirt) NodeNumOfDevices(Cap OptString, Flags uint32) (rNum int32, err error) {
+ var buf []byte
+
+ args := NodeNumOfDevicesArgs{
+ Cap: Cap,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(111, 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)
+ // Num: int32
+ _, err = dec.Decode(&rNum)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeListDevices is the go wrapper for REMOTE_PROC_NODE_LIST_DEVICES.
+func (l *Libvirt) NodeListDevices(Cap OptString, Maxnames int32, Flags uint32) (rNames []string, err error) {
+ var buf []byte
+
+ args := NodeListDevicesArgs{
+ Cap: Cap,
+ Maxnames: Maxnames,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(112, 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)
+ // Names: []string
+ _, err = dec.Decode(&rNames)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeDeviceLookupByName is the go wrapper for REMOTE_PROC_NODE_DEVICE_LOOKUP_BY_NAME.
+func (l *Libvirt) NodeDeviceLookupByName(Name string) (rDev NodeDevice, err error) {
+ var buf []byte
+
+ args := NodeDeviceLookupByNameArgs{
+ Name: Name,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(113, 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)
+ // Dev: NodeDevice
+ _, err = dec.Decode(&rDev)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeDeviceGetXMLDesc is the go wrapper for REMOTE_PROC_NODE_DEVICE_GET_XML_DESC.
+func (l *Libvirt) NodeDeviceGetXMLDesc(Name string, Flags uint32) (rXML string, err error) {
+ var buf []byte
+
+ args := NodeDeviceGetXMLDescArgs{
+ Name: Name,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(114, 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)
+ // XML: string
+ _, err = dec.Decode(&rXML)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeDeviceGetParent is the go wrapper for REMOTE_PROC_NODE_DEVICE_GET_PARENT.
+func (l *Libvirt) NodeDeviceGetParent(Name string) (rParentName OptString, err error) {
+ var buf []byte
+
+ args := NodeDeviceGetParentArgs{
+ Name: Name,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(115, 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)
+ // ParentName: OptString
+ _, err = dec.Decode(&rParentName)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeDeviceNumOfCaps is the go wrapper for REMOTE_PROC_NODE_DEVICE_NUM_OF_CAPS.
+func (l *Libvirt) NodeDeviceNumOfCaps(Name string) (rNum int32, err error) {
+ var buf []byte
+
+ args := NodeDeviceNumOfCapsArgs{
+ Name: Name,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(116, 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)
+ // Num: int32
+ _, err = dec.Decode(&rNum)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeDeviceListCaps is the go wrapper for REMOTE_PROC_NODE_DEVICE_LIST_CAPS.
+func (l *Libvirt) NodeDeviceListCaps(Name string, Maxnames int32) (rNames []string, err error) {
+ var buf []byte
+
+ args := NodeDeviceListCapsArgs{
+ Name: Name,
+ Maxnames: Maxnames,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(117, 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)
+ // Names: []string
+ _, err = dec.Decode(&rNames)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeDeviceDettach is the go wrapper for REMOTE_PROC_NODE_DEVICE_DETTACH.
+func (l *Libvirt) NodeDeviceDettach(Name string) (err error) {
+ var buf []byte
+
+ args := NodeDeviceDettachArgs{
+ Name: Name,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(118, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeDeviceReAttach is the go wrapper for REMOTE_PROC_NODE_DEVICE_RE_ATTACH.
+func (l *Libvirt) NodeDeviceReAttach(Name string) (err error) {
+ var buf []byte
+
+ args := NodeDeviceReAttachArgs{
+ Name: Name,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(119, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeDeviceReset is the go wrapper for REMOTE_PROC_NODE_DEVICE_RESET.
+func (l *Libvirt) NodeDeviceReset(Name string) (err error) {
+ var buf []byte
+
+ args := NodeDeviceResetArgs{
+ Name: Name,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(120, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetSecurityLabel is the go wrapper for REMOTE_PROC_DOMAIN_GET_SECURITY_LABEL.
+func (l *Libvirt) DomainGetSecurityLabel(Dom Domain) (rLabel []int8, rEnforcing int32, err error) {
+ var buf []byte
+
+ args := DomainGetSecurityLabelArgs{
+ Dom: Dom,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(121, 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)
+ // Label: []int8
+ _, err = dec.Decode(&rLabel)
+ if err != nil {
+ return
+ }
+ // Enforcing: int32
+ _, err = dec.Decode(&rEnforcing)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeGetSecurityModel is the go wrapper for REMOTE_PROC_NODE_GET_SECURITY_MODEL.
+func (l *Libvirt) NodeGetSecurityModel() (rModel []int8, rDoi []int8, err error) {
+ var buf []byte
+
+ var r response
+ r, err = l.requestStream(122, 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)
+ // Model: []int8
+ _, err = dec.Decode(&rModel)
+ if err != nil {
+ return
+ }
+ // Doi: []int8
+ _, err = dec.Decode(&rDoi)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeDeviceCreateXML is the go wrapper for REMOTE_PROC_NODE_DEVICE_CREATE_XML.
+func (l *Libvirt) NodeDeviceCreateXML(XMLDesc string, Flags uint32) (rDev NodeDevice, err error) {
+ var buf []byte
+
+ args := NodeDeviceCreateXMLArgs{
+ XMLDesc: XMLDesc,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(123, 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)
+ // Dev: NodeDevice
+ _, err = dec.Decode(&rDev)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeDeviceDestroy is the go wrapper for REMOTE_PROC_NODE_DEVICE_DESTROY.
+func (l *Libvirt) NodeDeviceDestroy(Name string) (err error) {
+ var buf []byte
+
+ args := NodeDeviceDestroyArgs{
+ Name: Name,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(124, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StorageVolCreateXMLFrom is the go wrapper for REMOTE_PROC_STORAGE_VOL_CREATE_XML_FROM.
+func (l *Libvirt) StorageVolCreateXMLFrom(Pool StoragePool, XML string, Clonevol StorageVol, Flags StorageVolCreateFlags) (rVol StorageVol, err error) {
+ var buf []byte
+
+ args := StorageVolCreateXMLFromArgs{
+ Pool: Pool,
+ XML: XML,
+ Clonevol: Clonevol,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(125, 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)
+ // Vol: StorageVol
+ _, err = dec.Decode(&rVol)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectNumOfInterfaces is the go wrapper for REMOTE_PROC_CONNECT_NUM_OF_INTERFACES.
+func (l *Libvirt) ConnectNumOfInterfaces() (rNum int32, err error) {
+ var buf []byte
+
+ var r response
+ r, err = l.requestStream(126, 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)
+ // Num: int32
+ _, err = dec.Decode(&rNum)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectListInterfaces is the go wrapper for REMOTE_PROC_CONNECT_LIST_INTERFACES.
+func (l *Libvirt) ConnectListInterfaces(Maxnames int32) (rNames []string, err error) {
+ var buf []byte
+
+ args := ConnectListInterfacesArgs{
+ Maxnames: Maxnames,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(127, 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)
+ // Names: []string
+ _, err = dec.Decode(&rNames)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// InterfaceLookupByName is the go wrapper for REMOTE_PROC_INTERFACE_LOOKUP_BY_NAME.
+func (l *Libvirt) InterfaceLookupByName(Name string) (rIface Interface, err error) {
+ var buf []byte
+
+ args := InterfaceLookupByNameArgs{
+ Name: Name,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(128, 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)
+ // Iface: Interface
+ _, err = dec.Decode(&rIface)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// InterfaceLookupByMacString is the go wrapper for REMOTE_PROC_INTERFACE_LOOKUP_BY_MAC_STRING.
+func (l *Libvirt) InterfaceLookupByMacString(Mac string) (rIface Interface, err error) {
+ var buf []byte
+
+ args := InterfaceLookupByMacStringArgs{
+ Mac: Mac,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(129, 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)
+ // Iface: Interface
+ _, err = dec.Decode(&rIface)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// InterfaceGetXMLDesc is the go wrapper for REMOTE_PROC_INTERFACE_GET_XML_DESC.
+func (l *Libvirt) InterfaceGetXMLDesc(Iface Interface, Flags uint32) (rXML string, err error) {
+ var buf []byte
+
+ args := InterfaceGetXMLDescArgs{
+ Iface: Iface,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(130, 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)
+ // XML: string
+ _, err = dec.Decode(&rXML)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// InterfaceDefineXML is the go wrapper for REMOTE_PROC_INTERFACE_DEFINE_XML.
+func (l *Libvirt) InterfaceDefineXML(XML string, Flags uint32) (rIface Interface, err error) {
+ var buf []byte
+
+ args := InterfaceDefineXMLArgs{
+ XML: XML,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(131, 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)
+ // Iface: Interface
+ _, err = dec.Decode(&rIface)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// InterfaceUndefine is the go wrapper for REMOTE_PROC_INTERFACE_UNDEFINE.
+func (l *Libvirt) InterfaceUndefine(Iface Interface) (err error) {
+ var buf []byte
+
+ args := InterfaceUndefineArgs{
+ Iface: Iface,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(132, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// InterfaceCreate is the go wrapper for REMOTE_PROC_INTERFACE_CREATE.
+func (l *Libvirt) InterfaceCreate(Iface Interface, Flags uint32) (err error) {
+ var buf []byte
+
+ args := InterfaceCreateArgs{
+ Iface: Iface,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(133, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// InterfaceDestroy is the go wrapper for REMOTE_PROC_INTERFACE_DESTROY.
+func (l *Libvirt) InterfaceDestroy(Iface Interface, Flags uint32) (err error) {
+ var buf []byte
+
+ args := InterfaceDestroyArgs{
+ Iface: Iface,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(134, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectDomainXMLFromNative is the go wrapper for REMOTE_PROC_CONNECT_DOMAIN_XML_FROM_NATIVE.
+func (l *Libvirt) ConnectDomainXMLFromNative(NativeFormat string, NativeConfig string, Flags uint32) (rDomainXML string, err error) {
+ var buf []byte
+
+ args := ConnectDomainXMLFromNativeArgs{
+ NativeFormat: NativeFormat,
+ NativeConfig: NativeConfig,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(135, 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)
+ // DomainXML: string
+ _, err = dec.Decode(&rDomainXML)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectDomainXMLToNative is the go wrapper for REMOTE_PROC_CONNECT_DOMAIN_XML_TO_NATIVE.
+func (l *Libvirt) ConnectDomainXMLToNative(NativeFormat string, DomainXML string, Flags uint32) (rNativeConfig string, err error) {
+ var buf []byte
+
+ args := ConnectDomainXMLToNativeArgs{
+ NativeFormat: NativeFormat,
+ DomainXML: DomainXML,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(136, 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)
+ // NativeConfig: string
+ _, err = dec.Decode(&rNativeConfig)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectNumOfDefinedInterfaces is the go wrapper for REMOTE_PROC_CONNECT_NUM_OF_DEFINED_INTERFACES.
+func (l *Libvirt) ConnectNumOfDefinedInterfaces() (rNum int32, err error) {
+ var buf []byte
+
+ var r response
+ r, err = l.requestStream(137, 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)
+ // Num: int32
+ _, err = dec.Decode(&rNum)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectListDefinedInterfaces is the go wrapper for REMOTE_PROC_CONNECT_LIST_DEFINED_INTERFACES.
+func (l *Libvirt) ConnectListDefinedInterfaces(Maxnames int32) (rNames []string, err error) {
+ var buf []byte
+
+ args := ConnectListDefinedInterfacesArgs{
+ Maxnames: Maxnames,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(138, 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)
+ // Names: []string
+ _, err = dec.Decode(&rNames)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectNumOfSecrets is the go wrapper for REMOTE_PROC_CONNECT_NUM_OF_SECRETS.
+func (l *Libvirt) ConnectNumOfSecrets() (rNum int32, err error) {
+ var buf []byte
+
+ var r response
+ r, err = l.requestStream(139, 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)
+ // Num: int32
+ _, err = dec.Decode(&rNum)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectListSecrets is the go wrapper for REMOTE_PROC_CONNECT_LIST_SECRETS.
+func (l *Libvirt) ConnectListSecrets(Maxuuids int32) (rUuids []string, err error) {
+ var buf []byte
+
+ args := ConnectListSecretsArgs{
+ Maxuuids: Maxuuids,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(140, 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)
+ // Uuids: []string
+ _, err = dec.Decode(&rUuids)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// SecretLookupByUUID is the go wrapper for REMOTE_PROC_SECRET_LOOKUP_BY_UUID.
+func (l *Libvirt) SecretLookupByUUID(UUID UUID) (rOptSecret Secret, err error) {
+ var buf []byte
+
+ args := SecretLookupByUUIDArgs{
+ UUID: UUID,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(141, 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)
+ // OptSecret: Secret
+ _, err = dec.Decode(&rOptSecret)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// SecretDefineXML is the go wrapper for REMOTE_PROC_SECRET_DEFINE_XML.
+func (l *Libvirt) SecretDefineXML(XML string, Flags uint32) (rOptSecret Secret, err error) {
+ var buf []byte
+
+ args := SecretDefineXMLArgs{
+ XML: XML,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(142, 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)
+ // OptSecret: Secret
+ _, err = dec.Decode(&rOptSecret)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// SecretGetXMLDesc is the go wrapper for REMOTE_PROC_SECRET_GET_XML_DESC.
+func (l *Libvirt) SecretGetXMLDesc(OptSecret Secret, Flags uint32) (rXML string, err error) {
+ var buf []byte
+
+ args := SecretGetXMLDescArgs{
+ OptSecret: OptSecret,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(143, 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)
+ // XML: string
+ _, err = dec.Decode(&rXML)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// SecretSetValue is the go wrapper for REMOTE_PROC_SECRET_SET_VALUE.
+func (l *Libvirt) SecretSetValue(OptSecret Secret, Value []byte, Flags uint32) (err error) {
+ var buf []byte
+
+ args := SecretSetValueArgs{
+ OptSecret: OptSecret,
+ Value: Value,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(144, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// SecretGetValue is the go wrapper for REMOTE_PROC_SECRET_GET_VALUE.
+func (l *Libvirt) SecretGetValue(OptSecret Secret, Flags uint32) (rValue []byte, err error) {
+ var buf []byte
+
+ args := SecretGetValueArgs{
+ OptSecret: OptSecret,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(145, 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)
+ // Value: []byte
+ _, err = dec.Decode(&rValue)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// SecretUndefine is the go wrapper for REMOTE_PROC_SECRET_UNDEFINE.
+func (l *Libvirt) SecretUndefine(OptSecret Secret) (err error) {
+ var buf []byte
+
+ args := SecretUndefineArgs{
+ OptSecret: OptSecret,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(146, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// SecretLookupByUsage is the go wrapper for REMOTE_PROC_SECRET_LOOKUP_BY_USAGE.
+func (l *Libvirt) SecretLookupByUsage(UsageType int32, UsageID string) (rOptSecret Secret, err error) {
+ var buf []byte
+
+ args := SecretLookupByUsageArgs{
+ UsageType: UsageType,
+ UsageID: UsageID,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(147, 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)
+ // OptSecret: Secret
+ _, err = dec.Decode(&rOptSecret)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainMigratePrepareTunnel is the go wrapper for REMOTE_PROC_DOMAIN_MIGRATE_PREPARE_TUNNEL.
+func (l *Libvirt) DomainMigratePrepareTunnel(Flags uint64, outStream io.Reader, Dname OptString, Resource uint64, DomXML string) (err error) {
+ var buf []byte
+
+ args := DomainMigratePrepareTunnelArgs{
+ Flags: Flags,
+ Dname: Dname,
+ Resource: Resource,
+ DomXML: DomXML,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(148, constants.Program, buf, outStream, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectIsSecure is the go wrapper for REMOTE_PROC_CONNECT_IS_SECURE.
+func (l *Libvirt) ConnectIsSecure() (rSecure int32, err error) {
+ var buf []byte
+
+ var r response
+ r, err = l.requestStream(149, 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)
+ // Secure: int32
+ _, err = dec.Decode(&rSecure)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainIsActive is the go wrapper for REMOTE_PROC_DOMAIN_IS_ACTIVE.
+func (l *Libvirt) DomainIsActive(Dom Domain) (rActive int32, err error) {
+ var buf []byte
+
+ args := DomainIsActiveArgs{
+ Dom: Dom,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(150, 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)
+ // Active: int32
+ _, err = dec.Decode(&rActive)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainIsPersistent is the go wrapper for REMOTE_PROC_DOMAIN_IS_PERSISTENT.
+func (l *Libvirt) DomainIsPersistent(Dom Domain) (rPersistent int32, err error) {
+ var buf []byte
+
+ args := DomainIsPersistentArgs{
+ Dom: Dom,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(151, 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)
+ // Persistent: int32
+ _, err = dec.Decode(&rPersistent)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NetworkIsActive is the go wrapper for REMOTE_PROC_NETWORK_IS_ACTIVE.
+func (l *Libvirt) NetworkIsActive(Net Network) (rActive int32, err error) {
+ var buf []byte
+
+ args := NetworkIsActiveArgs{
+ Net: Net,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(152, 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)
+ // Active: int32
+ _, err = dec.Decode(&rActive)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NetworkIsPersistent is the go wrapper for REMOTE_PROC_NETWORK_IS_PERSISTENT.
+func (l *Libvirt) NetworkIsPersistent(Net Network) (rPersistent int32, err error) {
+ var buf []byte
+
+ args := NetworkIsPersistentArgs{
+ Net: Net,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(153, 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)
+ // Persistent: int32
+ _, err = dec.Decode(&rPersistent)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StoragePoolIsActive is the go wrapper for REMOTE_PROC_STORAGE_POOL_IS_ACTIVE.
+func (l *Libvirt) StoragePoolIsActive(Pool StoragePool) (rActive int32, err error) {
+ var buf []byte
+
+ args := StoragePoolIsActiveArgs{
+ Pool: Pool,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(154, 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)
+ // Active: int32
+ _, err = dec.Decode(&rActive)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StoragePoolIsPersistent is the go wrapper for REMOTE_PROC_STORAGE_POOL_IS_PERSISTENT.
+func (l *Libvirt) StoragePoolIsPersistent(Pool StoragePool) (rPersistent int32, err error) {
+ var buf []byte
+
+ args := StoragePoolIsPersistentArgs{
+ Pool: Pool,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(155, 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)
+ // Persistent: int32
+ _, err = dec.Decode(&rPersistent)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// InterfaceIsActive is the go wrapper for REMOTE_PROC_INTERFACE_IS_ACTIVE.
+func (l *Libvirt) InterfaceIsActive(Iface Interface) (rActive int32, err error) {
+ var buf []byte
+
+ args := InterfaceIsActiveArgs{
+ Iface: Iface,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(156, 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)
+ // Active: int32
+ _, err = dec.Decode(&rActive)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectGetLibVersion is the go wrapper for REMOTE_PROC_CONNECT_GET_LIB_VERSION.
+func (l *Libvirt) ConnectGetLibVersion() (rLibVer uint64, err error) {
+ var buf []byte
+
+ var r response
+ r, err = l.requestStream(157, 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)
+ // LibVer: uint64
+ _, err = dec.Decode(&rLibVer)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectCompareCPU is the go wrapper for REMOTE_PROC_CONNECT_COMPARE_CPU.
+func (l *Libvirt) ConnectCompareCPU(XML string, Flags ConnectCompareCPUFlags) (rResult int32, err error) {
+ var buf []byte
+
+ args := ConnectCompareCPUArgs{
+ XML: XML,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(158, 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)
+ // Result: int32
+ _, err = dec.Decode(&rResult)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainMemoryStats is the go wrapper for REMOTE_PROC_DOMAIN_MEMORY_STATS.
+func (l *Libvirt) DomainMemoryStats(Dom Domain, MaxStats uint32, Flags uint32) (rStats []DomainMemoryStat, err error) {
+ var buf []byte
+
+ args := DomainMemoryStatsArgs{
+ Dom: Dom,
+ MaxStats: MaxStats,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(159, 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)
+ // Stats: []DomainMemoryStat
+ _, err = dec.Decode(&rStats)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainAttachDeviceFlags is the go wrapper for REMOTE_PROC_DOMAIN_ATTACH_DEVICE_FLAGS.
+func (l *Libvirt) DomainAttachDeviceFlags(Dom Domain, XML string, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainAttachDeviceFlagsArgs{
+ Dom: Dom,
+ XML: XML,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(160, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainDetachDeviceFlags is the go wrapper for REMOTE_PROC_DOMAIN_DETACH_DEVICE_FLAGS.
+func (l *Libvirt) DomainDetachDeviceFlags(Dom Domain, XML string, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainDetachDeviceFlagsArgs{
+ Dom: Dom,
+ XML: XML,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(161, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectBaselineCPU is the go wrapper for REMOTE_PROC_CONNECT_BASELINE_CPU.
+func (l *Libvirt) ConnectBaselineCPU(XMLCPUs []string, Flags ConnectBaselineCPUFlags) (rCPU string, err error) {
+ var buf []byte
+
+ args := ConnectBaselineCPUArgs{
+ XMLCPUs: XMLCPUs,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(162, 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)
+ // CPU: string
+ _, err = dec.Decode(&rCPU)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetJobInfo is the go wrapper for REMOTE_PROC_DOMAIN_GET_JOB_INFO.
+func (l *Libvirt) DomainGetJobInfo(Dom Domain) (rType int32, rTimeElapsed uint64, rTimeRemaining uint64, rDataTotal uint64, rDataProcessed uint64, rDataRemaining uint64, rMemTotal uint64, rMemProcessed uint64, rMemRemaining uint64, rFileTotal uint64, rFileProcessed uint64, rFileRemaining uint64, err error) {
+ var buf []byte
+
+ args := DomainGetJobInfoArgs{
+ Dom: Dom,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(163, 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)
+ // Type: int32
+ _, err = dec.Decode(&rType)
+ if err != nil {
+ return
+ }
+ // TimeElapsed: uint64
+ _, err = dec.Decode(&rTimeElapsed)
+ if err != nil {
+ return
+ }
+ // TimeRemaining: uint64
+ _, err = dec.Decode(&rTimeRemaining)
+ if err != nil {
+ return
+ }
+ // DataTotal: uint64
+ _, err = dec.Decode(&rDataTotal)
+ if err != nil {
+ return
+ }
+ // DataProcessed: uint64
+ _, err = dec.Decode(&rDataProcessed)
+ if err != nil {
+ return
+ }
+ // DataRemaining: uint64
+ _, err = dec.Decode(&rDataRemaining)
+ if err != nil {
+ return
+ }
+ // MemTotal: uint64
+ _, err = dec.Decode(&rMemTotal)
+ if err != nil {
+ return
+ }
+ // MemProcessed: uint64
+ _, err = dec.Decode(&rMemProcessed)
+ if err != nil {
+ return
+ }
+ // MemRemaining: uint64
+ _, err = dec.Decode(&rMemRemaining)
+ if err != nil {
+ return
+ }
+ // FileTotal: uint64
+ _, err = dec.Decode(&rFileTotal)
+ if err != nil {
+ return
+ }
+ // FileProcessed: uint64
+ _, err = dec.Decode(&rFileProcessed)
+ if err != nil {
+ return
+ }
+ // FileRemaining: uint64
+ _, err = dec.Decode(&rFileRemaining)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainAbortJob is the go wrapper for REMOTE_PROC_DOMAIN_ABORT_JOB.
+func (l *Libvirt) DomainAbortJob(Dom Domain) (err error) {
+ var buf []byte
+
+ args := DomainAbortJobArgs{
+ Dom: Dom,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(164, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StorageVolWipe is the go wrapper for REMOTE_PROC_STORAGE_VOL_WIPE.
+func (l *Libvirt) StorageVolWipe(Vol StorageVol, Flags uint32) (err error) {
+ var buf []byte
+
+ args := StorageVolWipeArgs{
+ Vol: Vol,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(165, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainMigrateSetMaxDowntime is the go wrapper for REMOTE_PROC_DOMAIN_MIGRATE_SET_MAX_DOWNTIME.
+func (l *Libvirt) DomainMigrateSetMaxDowntime(Dom Domain, Downtime uint64, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainMigrateSetMaxDowntimeArgs{
+ Dom: Dom,
+ Downtime: Downtime,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(166, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectDomainEventRegisterAny is the go wrapper for REMOTE_PROC_CONNECT_DOMAIN_EVENT_REGISTER_ANY.
+func (l *Libvirt) ConnectDomainEventRegisterAny(EventID int32) (err error) {
+ var buf []byte
+
+ args := ConnectDomainEventRegisterAnyArgs{
+ EventID: EventID,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(167, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectDomainEventDeregisterAny is the go wrapper for REMOTE_PROC_CONNECT_DOMAIN_EVENT_DEREGISTER_ANY.
+func (l *Libvirt) ConnectDomainEventDeregisterAny(EventID int32) (err error) {
+ var buf []byte
+
+ args := ConnectDomainEventDeregisterAnyArgs{
+ EventID: EventID,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(168, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventReboot is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_REBOOT.
+func (l *Libvirt) DomainEventReboot() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(169, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventRtcChange is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE.
+func (l *Libvirt) DomainEventRtcChange() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(170, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventWatchdog is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_WATCHDOG.
+func (l *Libvirt) DomainEventWatchdog() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(171, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventIOError is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_IO_ERROR.
+func (l *Libvirt) DomainEventIOError() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(172, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventGraphics is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_GRAPHICS.
+func (l *Libvirt) DomainEventGraphics() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(173, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainUpdateDeviceFlags is the go wrapper for REMOTE_PROC_DOMAIN_UPDATE_DEVICE_FLAGS.
+func (l *Libvirt) DomainUpdateDeviceFlags(Dom Domain, XML string, Flags DomainDeviceModifyFlags) (err error) {
+ var buf []byte
+
+ args := DomainUpdateDeviceFlagsArgs{
+ Dom: Dom,
+ XML: XML,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(174, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NwfilterLookupByName is the go wrapper for REMOTE_PROC_NWFILTER_LOOKUP_BY_NAME.
+func (l *Libvirt) NwfilterLookupByName(Name string) (rOptNwfilter Nwfilter, err error) {
+ var buf []byte
+
+ args := NwfilterLookupByNameArgs{
+ Name: Name,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(175, 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)
+ // OptNwfilter: Nwfilter
+ _, err = dec.Decode(&rOptNwfilter)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NwfilterLookupByUUID is the go wrapper for REMOTE_PROC_NWFILTER_LOOKUP_BY_UUID.
+func (l *Libvirt) NwfilterLookupByUUID(UUID UUID) (rOptNwfilter Nwfilter, err error) {
+ var buf []byte
+
+ args := NwfilterLookupByUUIDArgs{
+ UUID: UUID,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(176, 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)
+ // OptNwfilter: Nwfilter
+ _, err = dec.Decode(&rOptNwfilter)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NwfilterGetXMLDesc is the go wrapper for REMOTE_PROC_NWFILTER_GET_XML_DESC.
+func (l *Libvirt) NwfilterGetXMLDesc(OptNwfilter Nwfilter, Flags uint32) (rXML string, err error) {
+ var buf []byte
+
+ args := NwfilterGetXMLDescArgs{
+ OptNwfilter: OptNwfilter,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(177, 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)
+ // XML: string
+ _, err = dec.Decode(&rXML)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectNumOfNwfilters is the go wrapper for REMOTE_PROC_CONNECT_NUM_OF_NWFILTERS.
+func (l *Libvirt) ConnectNumOfNwfilters() (rNum int32, err error) {
+ var buf []byte
+
+ var r response
+ r, err = l.requestStream(178, 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)
+ // Num: int32
+ _, err = dec.Decode(&rNum)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectListNwfilters is the go wrapper for REMOTE_PROC_CONNECT_LIST_NWFILTERS.
+func (l *Libvirt) ConnectListNwfilters(Maxnames int32) (rNames []string, err error) {
+ var buf []byte
+
+ args := ConnectListNwfiltersArgs{
+ Maxnames: Maxnames,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(179, 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)
+ // Names: []string
+ _, err = dec.Decode(&rNames)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NwfilterDefineXML is the go wrapper for REMOTE_PROC_NWFILTER_DEFINE_XML.
+func (l *Libvirt) NwfilterDefineXML(XML string) (rOptNwfilter Nwfilter, err error) {
+ var buf []byte
+
+ args := NwfilterDefineXMLArgs{
+ XML: XML,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(180, 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)
+ // OptNwfilter: Nwfilter
+ _, err = dec.Decode(&rOptNwfilter)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NwfilterUndefine is the go wrapper for REMOTE_PROC_NWFILTER_UNDEFINE.
+func (l *Libvirt) NwfilterUndefine(OptNwfilter Nwfilter) (err error) {
+ var buf []byte
+
+ args := NwfilterUndefineArgs{
+ OptNwfilter: OptNwfilter,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(181, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainManagedSave is the go wrapper for REMOTE_PROC_DOMAIN_MANAGED_SAVE.
+func (l *Libvirt) DomainManagedSave(Dom Domain, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainManagedSaveArgs{
+ Dom: Dom,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(182, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainHasManagedSaveImage is the go wrapper for REMOTE_PROC_DOMAIN_HAS_MANAGED_SAVE_IMAGE.
+func (l *Libvirt) DomainHasManagedSaveImage(Dom Domain, Flags uint32) (rResult int32, err error) {
+ var buf []byte
+
+ args := DomainHasManagedSaveImageArgs{
+ Dom: Dom,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(183, 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)
+ // Result: int32
+ _, err = dec.Decode(&rResult)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainManagedSaveRemove is the go wrapper for REMOTE_PROC_DOMAIN_MANAGED_SAVE_REMOVE.
+func (l *Libvirt) DomainManagedSaveRemove(Dom Domain, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainManagedSaveRemoveArgs{
+ Dom: Dom,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(184, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSnapshotCreateXML is the go wrapper for REMOTE_PROC_DOMAIN_SNAPSHOT_CREATE_XML.
+func (l *Libvirt) DomainSnapshotCreateXML(Dom Domain, XMLDesc string, Flags uint32) (rSnap DomainSnapshot, err error) {
+ var buf []byte
+
+ args := DomainSnapshotCreateXMLArgs{
+ Dom: Dom,
+ XMLDesc: XMLDesc,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(185, 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)
+ // Snap: DomainSnapshot
+ _, err = dec.Decode(&rSnap)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSnapshotGetXMLDesc is the go wrapper for REMOTE_PROC_DOMAIN_SNAPSHOT_GET_XML_DESC.
+func (l *Libvirt) DomainSnapshotGetXMLDesc(Snap DomainSnapshot, Flags uint32) (rXML string, err error) {
+ var buf []byte
+
+ args := DomainSnapshotGetXMLDescArgs{
+ Snap: Snap,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(186, 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)
+ // XML: string
+ _, err = dec.Decode(&rXML)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSnapshotNum is the go wrapper for REMOTE_PROC_DOMAIN_SNAPSHOT_NUM.
+func (l *Libvirt) DomainSnapshotNum(Dom Domain, Flags uint32) (rNum int32, err error) {
+ var buf []byte
+
+ args := DomainSnapshotNumArgs{
+ Dom: Dom,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(187, 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)
+ // Num: int32
+ _, err = dec.Decode(&rNum)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSnapshotListNames is the go wrapper for REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_NAMES.
+func (l *Libvirt) DomainSnapshotListNames(Dom Domain, Maxnames int32, Flags uint32) (rNames []string, err error) {
+ var buf []byte
+
+ args := DomainSnapshotListNamesArgs{
+ Dom: Dom,
+ Maxnames: Maxnames,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(188, 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)
+ // Names: []string
+ _, err = dec.Decode(&rNames)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSnapshotLookupByName is the go wrapper for REMOTE_PROC_DOMAIN_SNAPSHOT_LOOKUP_BY_NAME.
+func (l *Libvirt) DomainSnapshotLookupByName(Dom Domain, Name string, Flags uint32) (rSnap DomainSnapshot, err error) {
+ var buf []byte
+
+ args := DomainSnapshotLookupByNameArgs{
+ Dom: Dom,
+ Name: Name,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(189, 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)
+ // Snap: DomainSnapshot
+ _, err = dec.Decode(&rSnap)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainHasCurrentSnapshot is the go wrapper for REMOTE_PROC_DOMAIN_HAS_CURRENT_SNAPSHOT.
+func (l *Libvirt) DomainHasCurrentSnapshot(Dom Domain, Flags uint32) (rResult int32, err error) {
+ var buf []byte
+
+ args := DomainHasCurrentSnapshotArgs{
+ Dom: Dom,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(190, 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)
+ // Result: int32
+ _, err = dec.Decode(&rResult)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSnapshotCurrent is the go wrapper for REMOTE_PROC_DOMAIN_SNAPSHOT_CURRENT.
+func (l *Libvirt) DomainSnapshotCurrent(Dom Domain, Flags uint32) (rSnap DomainSnapshot, err error) {
+ var buf []byte
+
+ args := DomainSnapshotCurrentArgs{
+ Dom: Dom,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(191, 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)
+ // Snap: DomainSnapshot
+ _, err = dec.Decode(&rSnap)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainRevertToSnapshot is the go wrapper for REMOTE_PROC_DOMAIN_REVERT_TO_SNAPSHOT.
+func (l *Libvirt) DomainRevertToSnapshot(Snap DomainSnapshot, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainRevertToSnapshotArgs{
+ Snap: Snap,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(192, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSnapshotDelete is the go wrapper for REMOTE_PROC_DOMAIN_SNAPSHOT_DELETE.
+func (l *Libvirt) DomainSnapshotDelete(Snap DomainSnapshot, Flags DomainSnapshotDeleteFlags) (err error) {
+ var buf []byte
+
+ args := DomainSnapshotDeleteArgs{
+ Snap: Snap,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(193, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetBlockInfo is the go wrapper for REMOTE_PROC_DOMAIN_GET_BLOCK_INFO.
+func (l *Libvirt) DomainGetBlockInfo(Dom Domain, Path string, Flags uint32) (rAllocation uint64, rCapacity uint64, rPhysical uint64, err error) {
+ var buf []byte
+
+ args := DomainGetBlockInfoArgs{
+ Dom: Dom,
+ Path: Path,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(194, 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)
+ // Allocation: uint64
+ _, err = dec.Decode(&rAllocation)
+ if err != nil {
+ return
+ }
+ // Capacity: uint64
+ _, err = dec.Decode(&rCapacity)
+ if err != nil {
+ return
+ }
+ // Physical: uint64
+ _, err = dec.Decode(&rPhysical)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventIOErrorReason is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_IO_ERROR_REASON.
+func (l *Libvirt) DomainEventIOErrorReason() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(195, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainCreateWithFlags is the go wrapper for REMOTE_PROC_DOMAIN_CREATE_WITH_FLAGS.
+func (l *Libvirt) DomainCreateWithFlags(Dom Domain, Flags uint32) (rDom Domain, err error) {
+ var buf []byte
+
+ args := DomainCreateWithFlagsArgs{
+ Dom: Dom,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(196, 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)
+ // Dom: Domain
+ _, err = dec.Decode(&rDom)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSetMemoryParameters is the go wrapper for REMOTE_PROC_DOMAIN_SET_MEMORY_PARAMETERS.
+func (l *Libvirt) DomainSetMemoryParameters(Dom Domain, Params []TypedParam, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainSetMemoryParametersArgs{
+ Dom: Dom,
+ Params: Params,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(197, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetMemoryParameters is the go wrapper for REMOTE_PROC_DOMAIN_GET_MEMORY_PARAMETERS.
+func (l *Libvirt) DomainGetMemoryParameters(Dom Domain, Nparams int32, Flags uint32) (rParams []TypedParam, rNparams int32, err error) {
+ var buf []byte
+
+ args := DomainGetMemoryParametersArgs{
+ Dom: Dom,
+ Nparams: Nparams,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(198, 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)
+ // Params: []TypedParam
+ _, err = dec.Decode(&rParams)
+ if err != nil {
+ return
+ }
+ // Nparams: int32
+ _, err = dec.Decode(&rNparams)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSetVcpusFlags is the go wrapper for REMOTE_PROC_DOMAIN_SET_VCPUS_FLAGS.
+func (l *Libvirt) DomainSetVcpusFlags(Dom Domain, Nvcpus uint32, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainSetVcpusFlagsArgs{
+ Dom: Dom,
+ Nvcpus: Nvcpus,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(199, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetVcpusFlags is the go wrapper for REMOTE_PROC_DOMAIN_GET_VCPUS_FLAGS.
+func (l *Libvirt) DomainGetVcpusFlags(Dom Domain, Flags uint32) (rNum int32, err error) {
+ var buf []byte
+
+ args := DomainGetVcpusFlagsArgs{
+ Dom: Dom,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(200, 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)
+ // Num: int32
+ _, err = dec.Decode(&rNum)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainOpenConsole is the go wrapper for REMOTE_PROC_DOMAIN_OPEN_CONSOLE.
+func (l *Libvirt) DomainOpenConsole(Dom Domain, DevName OptString, outStream io.Writer, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainOpenConsoleArgs{
+ Dom: Dom,
+ DevName: DevName,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(201, constants.Program, buf, nil, outStream)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainIsUpdated is the go wrapper for REMOTE_PROC_DOMAIN_IS_UPDATED.
+func (l *Libvirt) DomainIsUpdated(Dom Domain) (rUpdated int32, err error) {
+ var buf []byte
+
+ args := DomainIsUpdatedArgs{
+ Dom: Dom,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(202, 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)
+ // Updated: int32
+ _, err = dec.Decode(&rUpdated)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectGetSysinfo is the go wrapper for REMOTE_PROC_CONNECT_GET_SYSINFO.
+func (l *Libvirt) ConnectGetSysinfo(Flags uint32) (rSysinfo string, err error) {
+ var buf []byte
+
+ args := ConnectGetSysinfoArgs{
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(203, 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)
+ // Sysinfo: string
+ _, err = dec.Decode(&rSysinfo)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSetMemoryFlags is the go wrapper for REMOTE_PROC_DOMAIN_SET_MEMORY_FLAGS.
+func (l *Libvirt) DomainSetMemoryFlags(Dom Domain, Memory uint64, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainSetMemoryFlagsArgs{
+ Dom: Dom,
+ Memory: Memory,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(204, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSetBlkioParameters is the go wrapper for REMOTE_PROC_DOMAIN_SET_BLKIO_PARAMETERS.
+func (l *Libvirt) DomainSetBlkioParameters(Dom Domain, Params []TypedParam, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainSetBlkioParametersArgs{
+ Dom: Dom,
+ Params: Params,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(205, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetBlkioParameters is the go wrapper for REMOTE_PROC_DOMAIN_GET_BLKIO_PARAMETERS.
+func (l *Libvirt) DomainGetBlkioParameters(Dom Domain, Nparams int32, Flags uint32) (rParams []TypedParam, rNparams int32, err error) {
+ var buf []byte
+
+ args := DomainGetBlkioParametersArgs{
+ Dom: Dom,
+ Nparams: Nparams,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(206, 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)
+ // Params: []TypedParam
+ _, err = dec.Decode(&rParams)
+ if err != nil {
+ return
+ }
+ // Nparams: int32
+ _, err = dec.Decode(&rNparams)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainMigrateSetMaxSpeed is the go wrapper for REMOTE_PROC_DOMAIN_MIGRATE_SET_MAX_SPEED.
+func (l *Libvirt) DomainMigrateSetMaxSpeed(Dom Domain, Bandwidth uint64, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainMigrateSetMaxSpeedArgs{
+ Dom: Dom,
+ Bandwidth: Bandwidth,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(207, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StorageVolUpload is the go wrapper for REMOTE_PROC_STORAGE_VOL_UPLOAD.
+func (l *Libvirt) StorageVolUpload(Vol StorageVol, outStream io.Reader, Offset uint64, Length uint64, Flags StorageVolUploadFlags) (err error) {
+ var buf []byte
+
+ args := StorageVolUploadArgs{
+ Vol: Vol,
+ Offset: Offset,
+ Length: Length,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(208, constants.Program, buf, outStream, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StorageVolDownload is the go wrapper for REMOTE_PROC_STORAGE_VOL_DOWNLOAD.
+func (l *Libvirt) StorageVolDownload(Vol StorageVol, inStream io.Writer, Offset uint64, Length uint64, Flags StorageVolDownloadFlags) (err error) {
+ var buf []byte
+
+ args := StorageVolDownloadArgs{
+ Vol: Vol,
+ Offset: Offset,
+ Length: Length,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(209, constants.Program, buf, nil, inStream)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainInjectNmi is the go wrapper for REMOTE_PROC_DOMAIN_INJECT_NMI.
+func (l *Libvirt) DomainInjectNmi(Dom Domain, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainInjectNmiArgs{
+ Dom: Dom,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(210, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainScreenshot is the go wrapper for REMOTE_PROC_DOMAIN_SCREENSHOT.
+func (l *Libvirt) DomainScreenshot(Dom Domain, inStream io.Writer, Screen uint32, Flags uint32) (rMime OptString, err error) {
+ var buf []byte
+
+ args := DomainScreenshotArgs{
+ Dom: Dom,
+ Screen: Screen,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(211, constants.Program, buf, nil, inStream)
+ 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)
+ // Mime: OptString
+ _, err = dec.Decode(&rMime)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetState is the go wrapper for REMOTE_PROC_DOMAIN_GET_STATE.
+func (l *Libvirt) DomainGetState(Dom Domain, Flags uint32) (rState int32, rReason int32, err error) {
+ var buf []byte
+
+ args := DomainGetStateArgs{
+ Dom: Dom,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(212, 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)
+ // State: int32
+ _, err = dec.Decode(&rState)
+ if err != nil {
+ return
+ }
+ // Reason: int32
+ _, err = dec.Decode(&rReason)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainMigrateBegin3 is the go wrapper for REMOTE_PROC_DOMAIN_MIGRATE_BEGIN3.
+func (l *Libvirt) DomainMigrateBegin3(Dom Domain, Xmlin OptString, Flags uint64, Dname OptString, Resource uint64) (rCookieOut []byte, rXML string, err error) {
+ var buf []byte
+
+ args := DomainMigrateBegin3Args{
+ Dom: Dom,
+ Xmlin: Xmlin,
+ Flags: Flags,
+ Dname: Dname,
+ Resource: Resource,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(213, 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)
+ // CookieOut: []byte
+ _, err = dec.Decode(&rCookieOut)
+ if err != nil {
+ return
+ }
+ // XML: string
+ _, err = dec.Decode(&rXML)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainMigratePrepare3 is the go wrapper for REMOTE_PROC_DOMAIN_MIGRATE_PREPARE3.
+func (l *Libvirt) DomainMigratePrepare3(CookieIn []byte, UriIn OptString, Flags uint64, Dname OptString, Resource uint64, DomXML string) (rCookieOut []byte, rUriOut OptString, err error) {
+ var buf []byte
+
+ args := DomainMigratePrepare3Args{
+ CookieIn: CookieIn,
+ UriIn: UriIn,
+ Flags: Flags,
+ Dname: Dname,
+ Resource: Resource,
+ DomXML: DomXML,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(214, 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)
+ // CookieOut: []byte
+ _, err = dec.Decode(&rCookieOut)
+ if err != nil {
+ return
+ }
+ // UriOut: OptString
+ _, err = dec.Decode(&rUriOut)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainMigratePrepareTunnel3 is the go wrapper for REMOTE_PROC_DOMAIN_MIGRATE_PREPARE_TUNNEL3.
+func (l *Libvirt) DomainMigratePrepareTunnel3(CookieIn []byte, outStream io.Reader, Flags uint64, Dname OptString, Resource uint64, DomXML string) (rCookieOut []byte, err error) {
+ var buf []byte
+
+ args := DomainMigratePrepareTunnel3Args{
+ CookieIn: CookieIn,
+ Flags: Flags,
+ Dname: Dname,
+ Resource: Resource,
+ DomXML: DomXML,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(215, constants.Program, buf, outStream, 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)
+ // CookieOut: []byte
+ _, err = dec.Decode(&rCookieOut)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainMigratePerform3 is the go wrapper for REMOTE_PROC_DOMAIN_MIGRATE_PERFORM3.
+func (l *Libvirt) DomainMigratePerform3(Dom Domain, Xmlin OptString, CookieIn []byte, Dconnuri OptString, Uri OptString, Flags uint64, Dname OptString, Resource uint64) (rCookieOut []byte, err error) {
+ var buf []byte
+
+ args := DomainMigratePerform3Args{
+ Dom: Dom,
+ Xmlin: Xmlin,
+ CookieIn: CookieIn,
+ Dconnuri: Dconnuri,
+ Uri: Uri,
+ Flags: Flags,
+ Dname: Dname,
+ Resource: Resource,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(216, 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)
+ // CookieOut: []byte
+ _, err = dec.Decode(&rCookieOut)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainMigrateFinish3 is the go wrapper for REMOTE_PROC_DOMAIN_MIGRATE_FINISH3.
+func (l *Libvirt) DomainMigrateFinish3(Dname string, CookieIn []byte, Dconnuri OptString, Uri OptString, Flags uint64, Cancelled int32) (rDom Domain, rCookieOut []byte, err error) {
+ var buf []byte
+
+ args := DomainMigrateFinish3Args{
+ Dname: Dname,
+ CookieIn: CookieIn,
+ Dconnuri: Dconnuri,
+ Uri: Uri,
+ Flags: Flags,
+ Cancelled: Cancelled,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(217, 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)
+ // Dom: Domain
+ _, err = dec.Decode(&rDom)
+ if err != nil {
+ return
+ }
+ // CookieOut: []byte
+ _, err = dec.Decode(&rCookieOut)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainMigrateConfirm3 is the go wrapper for REMOTE_PROC_DOMAIN_MIGRATE_CONFIRM3.
+func (l *Libvirt) DomainMigrateConfirm3(Dom Domain, CookieIn []byte, Flags uint64, Cancelled int32) (err error) {
+ var buf []byte
+
+ args := DomainMigrateConfirm3Args{
+ Dom: Dom,
+ CookieIn: CookieIn,
+ Flags: Flags,
+ Cancelled: Cancelled,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(218, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSetSchedulerParametersFlags is the go wrapper for REMOTE_PROC_DOMAIN_SET_SCHEDULER_PARAMETERS_FLAGS.
+func (l *Libvirt) DomainSetSchedulerParametersFlags(Dom Domain, Params []TypedParam, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainSetSchedulerParametersFlagsArgs{
+ Dom: Dom,
+ Params: Params,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(219, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// InterfaceChangeBegin is the go wrapper for REMOTE_PROC_INTERFACE_CHANGE_BEGIN.
+func (l *Libvirt) InterfaceChangeBegin(Flags uint32) (err error) {
+ var buf []byte
+
+ args := InterfaceChangeBeginArgs{
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(220, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// InterfaceChangeCommit is the go wrapper for REMOTE_PROC_INTERFACE_CHANGE_COMMIT.
+func (l *Libvirt) InterfaceChangeCommit(Flags uint32) (err error) {
+ var buf []byte
+
+ args := InterfaceChangeCommitArgs{
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(221, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// InterfaceChangeRollback is the go wrapper for REMOTE_PROC_INTERFACE_CHANGE_ROLLBACK.
+func (l *Libvirt) InterfaceChangeRollback(Flags uint32) (err error) {
+ var buf []byte
+
+ args := InterfaceChangeRollbackArgs{
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(222, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetSchedulerParametersFlags is the go wrapper for REMOTE_PROC_DOMAIN_GET_SCHEDULER_PARAMETERS_FLAGS.
+func (l *Libvirt) DomainGetSchedulerParametersFlags(Dom Domain, Nparams int32, Flags uint32) (rParams []TypedParam, err error) {
+ var buf []byte
+
+ args := DomainGetSchedulerParametersFlagsArgs{
+ Dom: Dom,
+ Nparams: Nparams,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(223, 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)
+ // Params: []TypedParam
+ _, err = dec.Decode(&rParams)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventControlError is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_CONTROL_ERROR.
+func (l *Libvirt) DomainEventControlError() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(224, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainPinVcpuFlags is the go wrapper for REMOTE_PROC_DOMAIN_PIN_VCPU_FLAGS.
+func (l *Libvirt) DomainPinVcpuFlags(Dom Domain, Vcpu uint32, Cpumap []byte, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainPinVcpuFlagsArgs{
+ Dom: Dom,
+ Vcpu: Vcpu,
+ Cpumap: Cpumap,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(225, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSendKey is the go wrapper for REMOTE_PROC_DOMAIN_SEND_KEY.
+func (l *Libvirt) DomainSendKey(Dom Domain, Codeset uint32, Holdtime uint32, Keycodes []uint32, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainSendKeyArgs{
+ Dom: Dom,
+ Codeset: Codeset,
+ Holdtime: Holdtime,
+ Keycodes: Keycodes,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(226, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeGetCPUStats is the go wrapper for REMOTE_PROC_NODE_GET_CPU_STATS.
+func (l *Libvirt) NodeGetCPUStats(CPUNum int32, Nparams int32, Flags uint32) (rParams []NodeGetCPUStats, rNparams int32, err error) {
+ var buf []byte
+
+ args := NodeGetCPUStatsArgs{
+ CPUNum: CPUNum,
+ Nparams: Nparams,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(227, 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)
+ // Params: []NodeGetCPUStats
+ _, err = dec.Decode(&rParams)
+ if err != nil {
+ return
+ }
+ // Nparams: int32
+ _, err = dec.Decode(&rNparams)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeGetMemoryStats is the go wrapper for REMOTE_PROC_NODE_GET_MEMORY_STATS.
+func (l *Libvirt) NodeGetMemoryStats(Nparams int32, CellNum int32, Flags uint32) (rParams []NodeGetMemoryStats, rNparams int32, err error) {
+ var buf []byte
+
+ args := NodeGetMemoryStatsArgs{
+ Nparams: Nparams,
+ CellNum: CellNum,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(228, 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)
+ // Params: []NodeGetMemoryStats
+ _, err = dec.Decode(&rParams)
+ if err != nil {
+ return
+ }
+ // Nparams: int32
+ _, err = dec.Decode(&rNparams)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetControlInfo is the go wrapper for REMOTE_PROC_DOMAIN_GET_CONTROL_INFO.
+func (l *Libvirt) DomainGetControlInfo(Dom Domain, Flags uint32) (rState uint32, rDetails uint32, rStateTime uint64, err error) {
+ var buf []byte
+
+ args := DomainGetControlInfoArgs{
+ Dom: Dom,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(229, 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)
+ // State: uint32
+ _, err = dec.Decode(&rState)
+ if err != nil {
+ return
+ }
+ // Details: uint32
+ _, err = dec.Decode(&rDetails)
+ if err != nil {
+ return
+ }
+ // StateTime: uint64
+ _, err = dec.Decode(&rStateTime)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetVcpuPinInfo is the go wrapper for REMOTE_PROC_DOMAIN_GET_VCPU_PIN_INFO.
+func (l *Libvirt) DomainGetVcpuPinInfo(Dom Domain, Ncpumaps int32, Maplen int32, Flags uint32) (rCpumaps []byte, rNum int32, err error) {
+ var buf []byte
+
+ args := DomainGetVcpuPinInfoArgs{
+ Dom: Dom,
+ Ncpumaps: Ncpumaps,
+ Maplen: Maplen,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(230, 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)
+ // Cpumaps: []byte
+ _, err = dec.Decode(&rCpumaps)
+ if err != nil {
+ return
+ }
+ // Num: int32
+ _, err = dec.Decode(&rNum)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainUndefineFlags is the go wrapper for REMOTE_PROC_DOMAIN_UNDEFINE_FLAGS.
+func (l *Libvirt) DomainUndefineFlags(Dom Domain, Flags DomainUndefineFlagsValues) (err error) {
+ var buf []byte
+
+ args := DomainUndefineFlagsArgs{
+ Dom: Dom,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(231, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSaveFlags is the go wrapper for REMOTE_PROC_DOMAIN_SAVE_FLAGS.
+func (l *Libvirt) DomainSaveFlags(Dom Domain, To string, Dxml OptString, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainSaveFlagsArgs{
+ Dom: Dom,
+ To: To,
+ Dxml: Dxml,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(232, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainRestoreFlags is the go wrapper for REMOTE_PROC_DOMAIN_RESTORE_FLAGS.
+func (l *Libvirt) DomainRestoreFlags(From string, Dxml OptString, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainRestoreFlagsArgs{
+ From: From,
+ Dxml: Dxml,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(233, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainDestroyFlags is the go wrapper for REMOTE_PROC_DOMAIN_DESTROY_FLAGS.
+func (l *Libvirt) DomainDestroyFlags(Dom Domain, Flags DomainDestroyFlagsValues) (err error) {
+ var buf []byte
+
+ args := DomainDestroyFlagsArgs{
+ Dom: Dom,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(234, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSaveImageGetXMLDesc is the go wrapper for REMOTE_PROC_DOMAIN_SAVE_IMAGE_GET_XML_DESC.
+func (l *Libvirt) DomainSaveImageGetXMLDesc(File string, Flags uint32) (rXML string, err error) {
+ var buf []byte
+
+ args := DomainSaveImageGetXMLDescArgs{
+ File: File,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(235, 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)
+ // XML: string
+ _, err = dec.Decode(&rXML)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSaveImageDefineXML is the go wrapper for REMOTE_PROC_DOMAIN_SAVE_IMAGE_DEFINE_XML.
+func (l *Libvirt) DomainSaveImageDefineXML(File string, Dxml string, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainSaveImageDefineXMLArgs{
+ File: File,
+ Dxml: Dxml,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(236, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainBlockJobAbort is the go wrapper for REMOTE_PROC_DOMAIN_BLOCK_JOB_ABORT.
+func (l *Libvirt) DomainBlockJobAbort(Dom Domain, Path string, Flags DomainBlockJobAbortFlags) (err error) {
+ var buf []byte
+
+ args := DomainBlockJobAbortArgs{
+ Dom: Dom,
+ Path: Path,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(237, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetBlockJobInfo is the go wrapper for REMOTE_PROC_DOMAIN_GET_BLOCK_JOB_INFO.
+func (l *Libvirt) DomainGetBlockJobInfo(Dom Domain, Path string, Flags uint32) (rFound int32, rType int32, rBandwidth uint64, rCur uint64, rEnd uint64, err error) {
+ var buf []byte
+
+ args := DomainGetBlockJobInfoArgs{
+ Dom: Dom,
+ Path: Path,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(238, 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)
+ // Found: int32
+ _, err = dec.Decode(&rFound)
+ if err != nil {
+ return
+ }
+ // Type: int32
+ _, err = dec.Decode(&rType)
+ if err != nil {
+ return
+ }
+ // Bandwidth: uint64
+ _, err = dec.Decode(&rBandwidth)
+ if err != nil {
+ return
+ }
+ // Cur: uint64
+ _, err = dec.Decode(&rCur)
+ if err != nil {
+ return
+ }
+ // End: uint64
+ _, err = dec.Decode(&rEnd)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainBlockJobSetSpeed is the go wrapper for REMOTE_PROC_DOMAIN_BLOCK_JOB_SET_SPEED.
+func (l *Libvirt) DomainBlockJobSetSpeed(Dom Domain, Path string, Bandwidth uint64, Flags DomainBlockJobSetSpeedFlags) (err error) {
+ var buf []byte
+
+ args := DomainBlockJobSetSpeedArgs{
+ Dom: Dom,
+ Path: Path,
+ Bandwidth: Bandwidth,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(239, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainBlockPull is the go wrapper for REMOTE_PROC_DOMAIN_BLOCK_PULL.
+func (l *Libvirt) DomainBlockPull(Dom Domain, Path string, Bandwidth uint64, Flags DomainBlockPullFlags) (err error) {
+ var buf []byte
+
+ args := DomainBlockPullArgs{
+ Dom: Dom,
+ Path: Path,
+ Bandwidth: Bandwidth,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(240, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventBlockJob is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB.
+func (l *Libvirt) DomainEventBlockJob() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(241, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainMigrateGetMaxSpeed is the go wrapper for REMOTE_PROC_DOMAIN_MIGRATE_GET_MAX_SPEED.
+func (l *Libvirt) DomainMigrateGetMaxSpeed(Dom Domain, Flags uint32) (rBandwidth uint64, err error) {
+ var buf []byte
+
+ args := DomainMigrateGetMaxSpeedArgs{
+ Dom: Dom,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(242, 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)
+ // Bandwidth: uint64
+ _, err = dec.Decode(&rBandwidth)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainBlockStatsFlags is the go wrapper for REMOTE_PROC_DOMAIN_BLOCK_STATS_FLAGS.
+func (l *Libvirt) DomainBlockStatsFlags(Dom Domain, Path string, Nparams int32, Flags uint32) (rParams []TypedParam, rNparams int32, err error) {
+ var buf []byte
+
+ args := DomainBlockStatsFlagsArgs{
+ Dom: Dom,
+ Path: Path,
+ Nparams: Nparams,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(243, 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)
+ // Params: []TypedParam
+ _, err = dec.Decode(&rParams)
+ if err != nil {
+ return
+ }
+ // Nparams: int32
+ _, err = dec.Decode(&rNparams)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSnapshotGetParent is the go wrapper for REMOTE_PROC_DOMAIN_SNAPSHOT_GET_PARENT.
+func (l *Libvirt) DomainSnapshotGetParent(Snap DomainSnapshot, Flags uint32) (rSnap DomainSnapshot, err error) {
+ var buf []byte
+
+ args := DomainSnapshotGetParentArgs{
+ Snap: Snap,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(244, 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)
+ // Snap: DomainSnapshot
+ _, err = dec.Decode(&rSnap)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainReset is the go wrapper for REMOTE_PROC_DOMAIN_RESET.
+func (l *Libvirt) DomainReset(Dom Domain, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainResetArgs{
+ Dom: Dom,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(245, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSnapshotNumChildren is the go wrapper for REMOTE_PROC_DOMAIN_SNAPSHOT_NUM_CHILDREN.
+func (l *Libvirt) DomainSnapshotNumChildren(Snap DomainSnapshot, Flags uint32) (rNum int32, err error) {
+ var buf []byte
+
+ args := DomainSnapshotNumChildrenArgs{
+ Snap: Snap,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(246, 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)
+ // Num: int32
+ _, err = dec.Decode(&rNum)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSnapshotListChildrenNames is the go wrapper for REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_CHILDREN_NAMES.
+func (l *Libvirt) DomainSnapshotListChildrenNames(Snap DomainSnapshot, Maxnames int32, Flags uint32) (rNames []string, err error) {
+ var buf []byte
+
+ args := DomainSnapshotListChildrenNamesArgs{
+ Snap: Snap,
+ Maxnames: Maxnames,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(247, 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)
+ // Names: []string
+ _, err = dec.Decode(&rNames)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventDiskChange is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_DISK_CHANGE.
+func (l *Libvirt) DomainEventDiskChange() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(248, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainOpenGraphics is the go wrapper for REMOTE_PROC_DOMAIN_OPEN_GRAPHICS.
+func (l *Libvirt) DomainOpenGraphics(Dom Domain, Idx uint32, Flags DomainOpenGraphicsFlags) (err error) {
+ var buf []byte
+
+ args := DomainOpenGraphicsArgs{
+ Dom: Dom,
+ Idx: Idx,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(249, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeSuspendForDuration is the go wrapper for REMOTE_PROC_NODE_SUSPEND_FOR_DURATION.
+func (l *Libvirt) NodeSuspendForDuration(Target uint32, Duration uint64, Flags uint32) (err error) {
+ var buf []byte
+
+ args := NodeSuspendForDurationArgs{
+ Target: Target,
+ Duration: Duration,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(250, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainBlockResize is the go wrapper for REMOTE_PROC_DOMAIN_BLOCK_RESIZE.
+func (l *Libvirt) DomainBlockResize(Dom Domain, Disk string, Size uint64, Flags DomainBlockResizeFlags) (err error) {
+ var buf []byte
+
+ args := DomainBlockResizeArgs{
+ Dom: Dom,
+ Disk: Disk,
+ Size: Size,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(251, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSetBlockIOTune is the go wrapper for REMOTE_PROC_DOMAIN_SET_BLOCK_IO_TUNE.
+func (l *Libvirt) DomainSetBlockIOTune(Dom Domain, Disk string, Params []TypedParam, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainSetBlockIOTuneArgs{
+ Dom: Dom,
+ Disk: Disk,
+ Params: Params,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(252, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetBlockIOTune is the go wrapper for REMOTE_PROC_DOMAIN_GET_BLOCK_IO_TUNE.
+func (l *Libvirt) DomainGetBlockIOTune(Dom Domain, Disk OptString, Nparams int32, Flags uint32) (rParams []TypedParam, rNparams int32, err error) {
+ var buf []byte
+
+ args := DomainGetBlockIOTuneArgs{
+ Dom: Dom,
+ Disk: Disk,
+ Nparams: Nparams,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(253, 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)
+ // Params: []TypedParam
+ _, err = dec.Decode(&rParams)
+ if err != nil {
+ return
+ }
+ // Nparams: int32
+ _, err = dec.Decode(&rNparams)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSetNumaParameters is the go wrapper for REMOTE_PROC_DOMAIN_SET_NUMA_PARAMETERS.
+func (l *Libvirt) DomainSetNumaParameters(Dom Domain, Params []TypedParam, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainSetNumaParametersArgs{
+ Dom: Dom,
+ Params: Params,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(254, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetNumaParameters is the go wrapper for REMOTE_PROC_DOMAIN_GET_NUMA_PARAMETERS.
+func (l *Libvirt) DomainGetNumaParameters(Dom Domain, Nparams int32, Flags uint32) (rParams []TypedParam, rNparams int32, err error) {
+ var buf []byte
+
+ args := DomainGetNumaParametersArgs{
+ Dom: Dom,
+ Nparams: Nparams,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(255, 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)
+ // Params: []TypedParam
+ _, err = dec.Decode(&rParams)
+ if err != nil {
+ return
+ }
+ // Nparams: int32
+ _, err = dec.Decode(&rNparams)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSetInterfaceParameters is the go wrapper for REMOTE_PROC_DOMAIN_SET_INTERFACE_PARAMETERS.
+func (l *Libvirt) DomainSetInterfaceParameters(Dom Domain, Device string, Params []TypedParam, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainSetInterfaceParametersArgs{
+ Dom: Dom,
+ Device: Device,
+ Params: Params,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(256, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetInterfaceParameters is the go wrapper for REMOTE_PROC_DOMAIN_GET_INTERFACE_PARAMETERS.
+func (l *Libvirt) DomainGetInterfaceParameters(Dom Domain, Device string, Nparams int32, Flags DomainModificationImpact) (rParams []TypedParam, rNparams int32, err error) {
+ var buf []byte
+
+ args := DomainGetInterfaceParametersArgs{
+ Dom: Dom,
+ Device: Device,
+ Nparams: Nparams,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(257, 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)
+ // Params: []TypedParam
+ _, err = dec.Decode(&rParams)
+ if err != nil {
+ return
+ }
+ // Nparams: int32
+ _, err = dec.Decode(&rNparams)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainShutdownFlags is the go wrapper for REMOTE_PROC_DOMAIN_SHUTDOWN_FLAGS.
+func (l *Libvirt) DomainShutdownFlags(Dom Domain, Flags DomainShutdownFlagValues) (err error) {
+ var buf []byte
+
+ args := DomainShutdownFlagsArgs{
+ Dom: Dom,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(258, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StorageVolWipePattern is the go wrapper for REMOTE_PROC_STORAGE_VOL_WIPE_PATTERN.
+func (l *Libvirt) StorageVolWipePattern(Vol StorageVol, Algorithm uint32, Flags uint32) (err error) {
+ var buf []byte
+
+ args := StorageVolWipePatternArgs{
+ Vol: Vol,
+ Algorithm: Algorithm,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(259, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StorageVolResize is the go wrapper for REMOTE_PROC_STORAGE_VOL_RESIZE.
+func (l *Libvirt) StorageVolResize(Vol StorageVol, Capacity uint64, Flags StorageVolResizeFlags) (err error) {
+ var buf []byte
+
+ args := StorageVolResizeArgs{
+ Vol: Vol,
+ Capacity: Capacity,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(260, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainPmSuspendForDuration is the go wrapper for REMOTE_PROC_DOMAIN_PM_SUSPEND_FOR_DURATION.
+func (l *Libvirt) DomainPmSuspendForDuration(Dom Domain, Target uint32, Duration uint64, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainPmSuspendForDurationArgs{
+ Dom: Dom,
+ Target: Target,
+ Duration: Duration,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(261, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetCPUStats is the go wrapper for REMOTE_PROC_DOMAIN_GET_CPU_STATS.
+func (l *Libvirt) DomainGetCPUStats(Dom Domain, Nparams uint32, StartCPU int32, Ncpus uint32, Flags TypedParameterFlags) (rParams []TypedParam, rNparams int32, err error) {
+ var buf []byte
+
+ args := DomainGetCPUStatsArgs{
+ Dom: Dom,
+ Nparams: Nparams,
+ StartCPU: StartCPU,
+ Ncpus: Ncpus,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(262, 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)
+ // Params: []TypedParam
+ _, err = dec.Decode(&rParams)
+ if err != nil {
+ return
+ }
+ // Nparams: int32
+ _, err = dec.Decode(&rNparams)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetDiskErrors is the go wrapper for REMOTE_PROC_DOMAIN_GET_DISK_ERRORS.
+func (l *Libvirt) DomainGetDiskErrors(Dom Domain, Maxerrors uint32, Flags uint32) (rErrors []DomainDiskError, rNerrors int32, err error) {
+ var buf []byte
+
+ args := DomainGetDiskErrorsArgs{
+ Dom: Dom,
+ Maxerrors: Maxerrors,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(263, 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)
+ // Errors: []DomainDiskError
+ _, err = dec.Decode(&rErrors)
+ if err != nil {
+ return
+ }
+ // Nerrors: int32
+ _, err = dec.Decode(&rNerrors)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSetMetadata is the go wrapper for REMOTE_PROC_DOMAIN_SET_METADATA.
+func (l *Libvirt) DomainSetMetadata(Dom Domain, Type int32, Metadata OptString, Key OptString, Uri OptString, Flags DomainModificationImpact) (err error) {
+ var buf []byte
+
+ args := DomainSetMetadataArgs{
+ Dom: Dom,
+ Type: Type,
+ Metadata: Metadata,
+ Key: Key,
+ Uri: Uri,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(264, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetMetadata is the go wrapper for REMOTE_PROC_DOMAIN_GET_METADATA.
+func (l *Libvirt) DomainGetMetadata(Dom Domain, Type int32, Uri OptString, Flags DomainModificationImpact) (rMetadata string, err error) {
+ var buf []byte
+
+ args := DomainGetMetadataArgs{
+ Dom: Dom,
+ Type: Type,
+ Uri: Uri,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(265, 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)
+ // Metadata: string
+ _, err = dec.Decode(&rMetadata)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainBlockRebase is the go wrapper for REMOTE_PROC_DOMAIN_BLOCK_REBASE.
+func (l *Libvirt) DomainBlockRebase(Dom Domain, Path string, Base OptString, Bandwidth uint64, Flags DomainBlockRebaseFlags) (err error) {
+ var buf []byte
+
+ args := DomainBlockRebaseArgs{
+ Dom: Dom,
+ Path: Path,
+ Base: Base,
+ Bandwidth: Bandwidth,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(266, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainPmWakeup is the go wrapper for REMOTE_PROC_DOMAIN_PM_WAKEUP.
+func (l *Libvirt) DomainPmWakeup(Dom Domain, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainPmWakeupArgs{
+ Dom: Dom,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(267, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventTrayChange is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_TRAY_CHANGE.
+func (l *Libvirt) DomainEventTrayChange() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(268, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventPmwakeup is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_PMWAKEUP.
+func (l *Libvirt) DomainEventPmwakeup() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(269, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventPmsuspend is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_PMSUSPEND.
+func (l *Libvirt) DomainEventPmsuspend() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(270, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSnapshotIsCurrent is the go wrapper for REMOTE_PROC_DOMAIN_SNAPSHOT_IS_CURRENT.
+func (l *Libvirt) DomainSnapshotIsCurrent(Snap DomainSnapshot, Flags uint32) (rCurrent int32, err error) {
+ var buf []byte
+
+ args := DomainSnapshotIsCurrentArgs{
+ Snap: Snap,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(271, 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)
+ // Current: int32
+ _, err = dec.Decode(&rCurrent)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSnapshotHasMetadata is the go wrapper for REMOTE_PROC_DOMAIN_SNAPSHOT_HAS_METADATA.
+func (l *Libvirt) DomainSnapshotHasMetadata(Snap DomainSnapshot, Flags uint32) (rMetadata int32, err error) {
+ var buf []byte
+
+ args := DomainSnapshotHasMetadataArgs{
+ Snap: Snap,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(272, 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)
+ // Metadata: int32
+ _, err = dec.Decode(&rMetadata)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectListAllDomains is the go wrapper for REMOTE_PROC_CONNECT_LIST_ALL_DOMAINS.
+func (l *Libvirt) ConnectListAllDomains(NeedResults int32, Flags ConnectListAllDomainsFlags) (rDomains []Domain, rRet uint32, err error) {
+ var buf []byte
+
+ args := ConnectListAllDomainsArgs{
+ NeedResults: NeedResults,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(273, 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)
+ // Domains: []Domain
+ _, err = dec.Decode(&rDomains)
+ if err != nil {
+ return
+ }
+ // Ret: uint32
+ _, err = dec.Decode(&rRet)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainListAllSnapshots is the go wrapper for REMOTE_PROC_DOMAIN_LIST_ALL_SNAPSHOTS.
+func (l *Libvirt) DomainListAllSnapshots(Dom Domain, NeedResults int32, Flags uint32) (rSnapshots []DomainSnapshot, rRet int32, err error) {
+ var buf []byte
+
+ args := DomainListAllSnapshotsArgs{
+ Dom: Dom,
+ NeedResults: NeedResults,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(274, 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)
+ // Snapshots: []DomainSnapshot
+ _, err = dec.Decode(&rSnapshots)
+ if err != nil {
+ return
+ }
+ // Ret: int32
+ _, err = dec.Decode(&rRet)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSnapshotListAllChildren is the go wrapper for REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_ALL_CHILDREN.
+func (l *Libvirt) DomainSnapshotListAllChildren(Snapshot DomainSnapshot, NeedResults int32, Flags uint32) (rSnapshots []DomainSnapshot, rRet int32, err error) {
+ var buf []byte
+
+ args := DomainSnapshotListAllChildrenArgs{
+ Snapshot: Snapshot,
+ NeedResults: NeedResults,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(275, 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)
+ // Snapshots: []DomainSnapshot
+ _, err = dec.Decode(&rSnapshots)
+ if err != nil {
+ return
+ }
+ // Ret: int32
+ _, err = dec.Decode(&rRet)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventBalloonChange is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_BALLOON_CHANGE.
+func (l *Libvirt) DomainEventBalloonChange() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(276, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetHostname is the go wrapper for REMOTE_PROC_DOMAIN_GET_HOSTNAME.
+func (l *Libvirt) DomainGetHostname(Dom Domain, Flags DomainGetHostnameFlags) (rHostname string, err error) {
+ var buf []byte
+
+ args := DomainGetHostnameArgs{
+ Dom: Dom,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(277, 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)
+ // Hostname: string
+ _, err = dec.Decode(&rHostname)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetSecurityLabelList is the go wrapper for REMOTE_PROC_DOMAIN_GET_SECURITY_LABEL_LIST.
+func (l *Libvirt) DomainGetSecurityLabelList(Dom Domain) (rLabels []DomainGetSecurityLabelRet, rRet int32, err error) {
+ var buf []byte
+
+ args := DomainGetSecurityLabelListArgs{
+ Dom: Dom,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(278, 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)
+ // Labels: []DomainGetSecurityLabelRet
+ _, err = dec.Decode(&rLabels)
+ if err != nil {
+ return
+ }
+ // Ret: int32
+ _, err = dec.Decode(&rRet)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainPinEmulator is the go wrapper for REMOTE_PROC_DOMAIN_PIN_EMULATOR.
+func (l *Libvirt) DomainPinEmulator(Dom Domain, Cpumap []byte, Flags DomainModificationImpact) (err error) {
+ var buf []byte
+
+ args := DomainPinEmulatorArgs{
+ Dom: Dom,
+ Cpumap: Cpumap,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(279, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetEmulatorPinInfo is the go wrapper for REMOTE_PROC_DOMAIN_GET_EMULATOR_PIN_INFO.
+func (l *Libvirt) DomainGetEmulatorPinInfo(Dom Domain, Maplen int32, Flags DomainModificationImpact) (rCpumaps []byte, rRet int32, err error) {
+ var buf []byte
+
+ args := DomainGetEmulatorPinInfoArgs{
+ Dom: Dom,
+ Maplen: Maplen,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(280, 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)
+ // Cpumaps: []byte
+ _, err = dec.Decode(&rCpumaps)
+ if err != nil {
+ return
+ }
+ // Ret: int32
+ _, err = dec.Decode(&rRet)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectListAllStoragePools is the go wrapper for REMOTE_PROC_CONNECT_LIST_ALL_STORAGE_POOLS.
+func (l *Libvirt) ConnectListAllStoragePools(NeedResults int32, Flags ConnectListAllStoragePoolsFlags) (rPools []StoragePool, rRet uint32, err error) {
+ var buf []byte
+
+ args := ConnectListAllStoragePoolsArgs{
+ NeedResults: NeedResults,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(281, 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)
+ // Pools: []StoragePool
+ _, err = dec.Decode(&rPools)
+ if err != nil {
+ return
+ }
+ // Ret: uint32
+ _, err = dec.Decode(&rRet)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StoragePoolListAllVolumes is the go wrapper for REMOTE_PROC_STORAGE_POOL_LIST_ALL_VOLUMES.
+func (l *Libvirt) StoragePoolListAllVolumes(Pool StoragePool, NeedResults int32, Flags uint32) (rVols []StorageVol, rRet uint32, err error) {
+ var buf []byte
+
+ args := StoragePoolListAllVolumesArgs{
+ Pool: Pool,
+ NeedResults: NeedResults,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(282, 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)
+ // Vols: []StorageVol
+ _, err = dec.Decode(&rVols)
+ if err != nil {
+ return
+ }
+ // Ret: uint32
+ _, err = dec.Decode(&rRet)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectListAllNetworks is the go wrapper for REMOTE_PROC_CONNECT_LIST_ALL_NETWORKS.
+func (l *Libvirt) ConnectListAllNetworks(NeedResults int32, Flags ConnectListAllNetworksFlags) (rNets []Network, rRet uint32, err error) {
+ var buf []byte
+
+ args := ConnectListAllNetworksArgs{
+ NeedResults: NeedResults,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(283, 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)
+ // Nets: []Network
+ _, err = dec.Decode(&rNets)
+ if err != nil {
+ return
+ }
+ // Ret: uint32
+ _, err = dec.Decode(&rRet)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectListAllInterfaces is the go wrapper for REMOTE_PROC_CONNECT_LIST_ALL_INTERFACES.
+func (l *Libvirt) ConnectListAllInterfaces(NeedResults int32, Flags ConnectListAllInterfacesFlags) (rIfaces []Interface, rRet uint32, err error) {
+ var buf []byte
+
+ args := ConnectListAllInterfacesArgs{
+ NeedResults: NeedResults,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(284, 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)
+ // Ifaces: []Interface
+ _, err = dec.Decode(&rIfaces)
+ if err != nil {
+ return
+ }
+ // Ret: uint32
+ _, err = dec.Decode(&rRet)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectListAllNodeDevices is the go wrapper for REMOTE_PROC_CONNECT_LIST_ALL_NODE_DEVICES.
+func (l *Libvirt) ConnectListAllNodeDevices(NeedResults int32, Flags uint32) (rDevices []NodeDevice, rRet uint32, err error) {
+ var buf []byte
+
+ args := ConnectListAllNodeDevicesArgs{
+ NeedResults: NeedResults,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(285, 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)
+ // Devices: []NodeDevice
+ _, err = dec.Decode(&rDevices)
+ if err != nil {
+ return
+ }
+ // Ret: uint32
+ _, err = dec.Decode(&rRet)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectListAllNwfilters is the go wrapper for REMOTE_PROC_CONNECT_LIST_ALL_NWFILTERS.
+func (l *Libvirt) ConnectListAllNwfilters(NeedResults int32, Flags uint32) (rFilters []Nwfilter, rRet uint32, err error) {
+ var buf []byte
+
+ args := ConnectListAllNwfiltersArgs{
+ NeedResults: NeedResults,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(286, 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)
+ // Filters: []Nwfilter
+ _, err = dec.Decode(&rFilters)
+ if err != nil {
+ return
+ }
+ // Ret: uint32
+ _, err = dec.Decode(&rRet)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectListAllSecrets is the go wrapper for REMOTE_PROC_CONNECT_LIST_ALL_SECRETS.
+func (l *Libvirt) ConnectListAllSecrets(NeedResults int32, Flags ConnectListAllSecretsFlags) (rSecrets []Secret, rRet uint32, err error) {
+ var buf []byte
+
+ args := ConnectListAllSecretsArgs{
+ NeedResults: NeedResults,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(287, 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)
+ // Secrets: []Secret
+ _, err = dec.Decode(&rSecrets)
+ if err != nil {
+ return
+ }
+ // Ret: uint32
+ _, err = dec.Decode(&rRet)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeSetMemoryParameters is the go wrapper for REMOTE_PROC_NODE_SET_MEMORY_PARAMETERS.
+func (l *Libvirt) NodeSetMemoryParameters(Params []TypedParam, Flags uint32) (err error) {
+ var buf []byte
+
+ args := NodeSetMemoryParametersArgs{
+ Params: Params,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(288, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeGetMemoryParameters is the go wrapper for REMOTE_PROC_NODE_GET_MEMORY_PARAMETERS.
+func (l *Libvirt) NodeGetMemoryParameters(Nparams int32, Flags uint32) (rParams []TypedParam, rNparams int32, err error) {
+ var buf []byte
+
+ args := NodeGetMemoryParametersArgs{
+ Nparams: Nparams,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(289, 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)
+ // Params: []TypedParam
+ _, err = dec.Decode(&rParams)
+ if err != nil {
+ return
+ }
+ // Nparams: int32
+ _, err = dec.Decode(&rNparams)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainBlockCommit is the go wrapper for REMOTE_PROC_DOMAIN_BLOCK_COMMIT.
+func (l *Libvirt) DomainBlockCommit(Dom Domain, Disk string, Base OptString, Top OptString, Bandwidth uint64, Flags DomainBlockCommitFlags) (err error) {
+ var buf []byte
+
+ args := DomainBlockCommitArgs{
+ Dom: Dom,
+ Disk: Disk,
+ Base: Base,
+ Top: Top,
+ Bandwidth: Bandwidth,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(290, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NetworkUpdate is the go wrapper for REMOTE_PROC_NETWORK_UPDATE.
+func (l *Libvirt) NetworkUpdate(Net Network, Command uint32, Section uint32, ParentIndex int32, XML string, Flags NetworkUpdateFlags) (err error) {
+ var buf []byte
+
+ args := NetworkUpdateArgs{
+ Net: Net,
+ Command: Command,
+ Section: Section,
+ ParentIndex: ParentIndex,
+ XML: XML,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(291, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventPmsuspendDisk is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_PMSUSPEND_DISK.
+func (l *Libvirt) DomainEventPmsuspendDisk() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(292, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeGetCPUMap is the go wrapper for REMOTE_PROC_NODE_GET_CPU_MAP.
+func (l *Libvirt) NodeGetCPUMap(NeedMap int32, NeedOnline int32, Flags uint32) (rCpumap []byte, rOnline uint32, rRet int32, err error) {
+ var buf []byte
+
+ args := NodeGetCPUMapArgs{
+ NeedMap: NeedMap,
+ NeedOnline: NeedOnline,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(293, 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)
+ // Cpumap: []byte
+ _, err = dec.Decode(&rCpumap)
+ if err != nil {
+ return
+ }
+ // Online: uint32
+ _, err = dec.Decode(&rOnline)
+ if err != nil {
+ return
+ }
+ // Ret: int32
+ _, err = dec.Decode(&rRet)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainFstrim is the go wrapper for REMOTE_PROC_DOMAIN_FSTRIM.
+func (l *Libvirt) DomainFstrim(Dom Domain, MountPoint OptString, Minimum uint64, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainFstrimArgs{
+ Dom: Dom,
+ MountPoint: MountPoint,
+ Minimum: Minimum,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(294, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSendProcessSignal is the go wrapper for REMOTE_PROC_DOMAIN_SEND_PROCESS_SIGNAL.
+func (l *Libvirt) DomainSendProcessSignal(Dom Domain, PidValue int64, Signum uint32, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainSendProcessSignalArgs{
+ Dom: Dom,
+ PidValue: PidValue,
+ Signum: Signum,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(295, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainOpenChannel is the go wrapper for REMOTE_PROC_DOMAIN_OPEN_CHANNEL.
+func (l *Libvirt) DomainOpenChannel(Dom Domain, Name OptString, inStream io.Writer, Flags DomainChannelFlags) (err error) {
+ var buf []byte
+
+ args := DomainOpenChannelArgs{
+ Dom: Dom,
+ Name: Name,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(296, constants.Program, buf, nil, inStream)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeDeviceLookupScsiHostByWwn is the go wrapper for REMOTE_PROC_NODE_DEVICE_LOOKUP_SCSI_HOST_BY_WWN.
+func (l *Libvirt) NodeDeviceLookupScsiHostByWwn(Wwnn string, Wwpn string, Flags uint32) (rDev NodeDevice, err error) {
+ var buf []byte
+
+ args := NodeDeviceLookupScsiHostByWwnArgs{
+ Wwnn: Wwnn,
+ Wwpn: Wwpn,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(297, 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)
+ // Dev: NodeDevice
+ _, err = dec.Decode(&rDev)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetJobStats is the go wrapper for REMOTE_PROC_DOMAIN_GET_JOB_STATS.
+func (l *Libvirt) DomainGetJobStats(Dom Domain, Flags DomainGetJobStatsFlags) (rType int32, rParams []TypedParam, err error) {
+ var buf []byte
+
+ args := DomainGetJobStatsArgs{
+ Dom: Dom,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(298, 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)
+ // Type: int32
+ _, err = dec.Decode(&rType)
+ if err != nil {
+ return
+ }
+ // Params: []TypedParam
+ _, err = dec.Decode(&rParams)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainMigrateGetCompressionCache is the go wrapper for REMOTE_PROC_DOMAIN_MIGRATE_GET_COMPRESSION_CACHE.
+func (l *Libvirt) DomainMigrateGetCompressionCache(Dom Domain, Flags uint32) (rCacheSize uint64, err error) {
+ var buf []byte
+
+ args := DomainMigrateGetCompressionCacheArgs{
+ Dom: Dom,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(299, 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)
+ // CacheSize: uint64
+ _, err = dec.Decode(&rCacheSize)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainMigrateSetCompressionCache is the go wrapper for REMOTE_PROC_DOMAIN_MIGRATE_SET_COMPRESSION_CACHE.
+func (l *Libvirt) DomainMigrateSetCompressionCache(Dom Domain, CacheSize uint64, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainMigrateSetCompressionCacheArgs{
+ Dom: Dom,
+ CacheSize: CacheSize,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(300, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeDeviceDetachFlags is the go wrapper for REMOTE_PROC_NODE_DEVICE_DETACH_FLAGS.
+func (l *Libvirt) NodeDeviceDetachFlags(Name string, DriverName OptString, Flags uint32) (err error) {
+ var buf []byte
+
+ args := NodeDeviceDetachFlagsArgs{
+ Name: Name,
+ DriverName: DriverName,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(301, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainMigrateBegin3Params is the go wrapper for REMOTE_PROC_DOMAIN_MIGRATE_BEGIN3_PARAMS.
+func (l *Libvirt) DomainMigrateBegin3Params(Dom Domain, Params []TypedParam, Flags uint32) (rCookieOut []byte, rXML string, err error) {
+ var buf []byte
+
+ args := DomainMigrateBegin3ParamsArgs{
+ Dom: Dom,
+ Params: Params,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(302, 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)
+ // CookieOut: []byte
+ _, err = dec.Decode(&rCookieOut)
+ if err != nil {
+ return
+ }
+ // XML: string
+ _, err = dec.Decode(&rXML)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainMigratePrepare3Params is the go wrapper for REMOTE_PROC_DOMAIN_MIGRATE_PREPARE3_PARAMS.
+func (l *Libvirt) DomainMigratePrepare3Params(Params []TypedParam, CookieIn []byte, Flags uint32) (rCookieOut []byte, rUriOut OptString, err error) {
+ var buf []byte
+
+ args := DomainMigratePrepare3ParamsArgs{
+ Params: Params,
+ CookieIn: CookieIn,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(303, 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)
+ // CookieOut: []byte
+ _, err = dec.Decode(&rCookieOut)
+ if err != nil {
+ return
+ }
+ // UriOut: OptString
+ _, err = dec.Decode(&rUriOut)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainMigratePrepareTunnel3Params is the go wrapper for REMOTE_PROC_DOMAIN_MIGRATE_PREPARE_TUNNEL3_PARAMS.
+func (l *Libvirt) DomainMigratePrepareTunnel3Params(Params []TypedParam, CookieIn []byte, Flags uint32) (rCookieOut []byte, err error) {
+ var buf []byte
+
+ args := DomainMigratePrepareTunnel3ParamsArgs{
+ Params: Params,
+ CookieIn: CookieIn,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(304, 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)
+ // CookieOut: []byte
+ _, err = dec.Decode(&rCookieOut)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainMigratePerform3Params is the go wrapper for REMOTE_PROC_DOMAIN_MIGRATE_PERFORM3_PARAMS.
+func (l *Libvirt) DomainMigratePerform3Params(Dom Domain, Dconnuri OptString, Params []TypedParam, CookieIn []byte, Flags DomainMigrateFlags) (rCookieOut []byte, err error) {
+ var buf []byte
+
+ args := DomainMigratePerform3ParamsArgs{
+ Dom: Dom,
+ Dconnuri: Dconnuri,
+ Params: Params,
+ CookieIn: CookieIn,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(305, 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)
+ // CookieOut: []byte
+ _, err = dec.Decode(&rCookieOut)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainMigrateFinish3Params is the go wrapper for REMOTE_PROC_DOMAIN_MIGRATE_FINISH3_PARAMS.
+func (l *Libvirt) DomainMigrateFinish3Params(Params []TypedParam, CookieIn []byte, Flags uint32, Cancelled int32) (rDom Domain, rCookieOut []byte, err error) {
+ var buf []byte
+
+ args := DomainMigrateFinish3ParamsArgs{
+ Params: Params,
+ CookieIn: CookieIn,
+ Flags: Flags,
+ Cancelled: Cancelled,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(306, 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)
+ // Dom: Domain
+ _, err = dec.Decode(&rDom)
+ if err != nil {
+ return
+ }
+ // CookieOut: []byte
+ _, err = dec.Decode(&rCookieOut)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainMigrateConfirm3Params is the go wrapper for REMOTE_PROC_DOMAIN_MIGRATE_CONFIRM3_PARAMS.
+func (l *Libvirt) DomainMigrateConfirm3Params(Dom Domain, Params []TypedParam, CookieIn []byte, Flags uint32, Cancelled int32) (err error) {
+ var buf []byte
+
+ args := DomainMigrateConfirm3ParamsArgs{
+ Dom: Dom,
+ Params: Params,
+ CookieIn: CookieIn,
+ Flags: Flags,
+ Cancelled: Cancelled,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(307, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSetMemoryStatsPeriod is the go wrapper for REMOTE_PROC_DOMAIN_SET_MEMORY_STATS_PERIOD.
+func (l *Libvirt) DomainSetMemoryStatsPeriod(Dom Domain, Period int32, Flags DomainMemoryModFlags) (err error) {
+ var buf []byte
+
+ args := DomainSetMemoryStatsPeriodArgs{
+ Dom: Dom,
+ Period: Period,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(308, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainCreateXMLWithFiles is the go wrapper for REMOTE_PROC_DOMAIN_CREATE_XML_WITH_FILES.
+func (l *Libvirt) DomainCreateXMLWithFiles(XMLDesc string, Flags DomainCreateFlags) (rDom Domain, err error) {
+ var buf []byte
+
+ args := DomainCreateXMLWithFilesArgs{
+ XMLDesc: XMLDesc,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(309, 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)
+ // Dom: Domain
+ _, err = dec.Decode(&rDom)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainCreateWithFiles is the go wrapper for REMOTE_PROC_DOMAIN_CREATE_WITH_FILES.
+func (l *Libvirt) DomainCreateWithFiles(Dom Domain, Flags DomainCreateFlags) (rDom Domain, err error) {
+ var buf []byte
+
+ args := DomainCreateWithFilesArgs{
+ Dom: Dom,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(310, 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)
+ // Dom: Domain
+ _, err = dec.Decode(&rDom)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventDeviceRemoved is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_DEVICE_REMOVED.
+func (l *Libvirt) DomainEventDeviceRemoved() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(311, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectGetCPUModelNames is the go wrapper for REMOTE_PROC_CONNECT_GET_CPU_MODEL_NAMES.
+func (l *Libvirt) ConnectGetCPUModelNames(Arch string, NeedResults int32, Flags uint32) (rModels []string, rRet int32, err error) {
+ var buf []byte
+
+ args := ConnectGetCPUModelNamesArgs{
+ Arch: Arch,
+ NeedResults: NeedResults,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(312, 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)
+ // Models: []string
+ _, err = dec.Decode(&rModels)
+ if err != nil {
+ return
+ }
+ // Ret: int32
+ _, err = dec.Decode(&rRet)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectNetworkEventRegisterAny is the go wrapper for REMOTE_PROC_CONNECT_NETWORK_EVENT_REGISTER_ANY.
+func (l *Libvirt) ConnectNetworkEventRegisterAny(EventID int32, Net OptNetwork) (rCallbackID int32, err error) {
+ var buf []byte
+
+ args := ConnectNetworkEventRegisterAnyArgs{
+ EventID: EventID,
+ Net: Net,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(313, 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)
+ // CallbackID: int32
+ _, err = dec.Decode(&rCallbackID)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectNetworkEventDeregisterAny is the go wrapper for REMOTE_PROC_CONNECT_NETWORK_EVENT_DEREGISTER_ANY.
+func (l *Libvirt) ConnectNetworkEventDeregisterAny(CallbackID int32) (err error) {
+ var buf []byte
+
+ args := ConnectNetworkEventDeregisterAnyArgs{
+ CallbackID: CallbackID,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(314, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NetworkEventLifecycle is the go wrapper for REMOTE_PROC_NETWORK_EVENT_LIFECYCLE.
+func (l *Libvirt) NetworkEventLifecycle() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(315, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectDomainEventCallbackRegisterAny is the go wrapper for REMOTE_PROC_CONNECT_DOMAIN_EVENT_CALLBACK_REGISTER_ANY.
+func (l *Libvirt) ConnectDomainEventCallbackRegisterAny(EventID int32, Dom OptDomain) (rCallbackID int32, err error) {
+ var buf []byte
+
+ args := ConnectDomainEventCallbackRegisterAnyArgs{
+ EventID: EventID,
+ Dom: Dom,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(316, 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)
+ // CallbackID: int32
+ _, err = dec.Decode(&rCallbackID)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectDomainEventCallbackDeregisterAny is the go wrapper for REMOTE_PROC_CONNECT_DOMAIN_EVENT_CALLBACK_DEREGISTER_ANY.
+func (l *Libvirt) ConnectDomainEventCallbackDeregisterAny(CallbackID int32) (err error) {
+ var buf []byte
+
+ args := ConnectDomainEventCallbackDeregisterAnyArgs{
+ CallbackID: CallbackID,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(317, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventCallbackLifecycle is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_CALLBACK_LIFECYCLE.
+func (l *Libvirt) DomainEventCallbackLifecycle() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(318, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventCallbackReboot is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_CALLBACK_REBOOT.
+func (l *Libvirt) DomainEventCallbackReboot() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(319, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventCallbackRtcChange is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_CALLBACK_RTC_CHANGE.
+func (l *Libvirt) DomainEventCallbackRtcChange() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(320, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventCallbackWatchdog is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_CALLBACK_WATCHDOG.
+func (l *Libvirt) DomainEventCallbackWatchdog() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(321, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventCallbackIOError is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_CALLBACK_IO_ERROR.
+func (l *Libvirt) DomainEventCallbackIOError() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(322, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventCallbackGraphics is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_CALLBACK_GRAPHICS.
+func (l *Libvirt) DomainEventCallbackGraphics() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(323, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventCallbackIOErrorReason is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_CALLBACK_IO_ERROR_REASON.
+func (l *Libvirt) DomainEventCallbackIOErrorReason() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(324, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventCallbackControlError is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_CALLBACK_CONTROL_ERROR.
+func (l *Libvirt) DomainEventCallbackControlError() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(325, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventCallbackBlockJob is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_CALLBACK_BLOCK_JOB.
+func (l *Libvirt) DomainEventCallbackBlockJob() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(326, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventCallbackDiskChange is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DISK_CHANGE.
+func (l *Libvirt) DomainEventCallbackDiskChange() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(327, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventCallbackTrayChange is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_CALLBACK_TRAY_CHANGE.
+func (l *Libvirt) DomainEventCallbackTrayChange() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(328, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventCallbackPmwakeup is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_CALLBACK_PMWAKEUP.
+func (l *Libvirt) DomainEventCallbackPmwakeup() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(329, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventCallbackPmsuspend is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_CALLBACK_PMSUSPEND.
+func (l *Libvirt) DomainEventCallbackPmsuspend() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(330, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventCallbackBalloonChange is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_CALLBACK_BALLOON_CHANGE.
+func (l *Libvirt) DomainEventCallbackBalloonChange() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(331, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventCallbackPmsuspendDisk is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_CALLBACK_PMSUSPEND_DISK.
+func (l *Libvirt) DomainEventCallbackPmsuspendDisk() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(332, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventCallbackDeviceRemoved is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DEVICE_REMOVED.
+func (l *Libvirt) DomainEventCallbackDeviceRemoved() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(333, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainCoreDumpWithFormat is the go wrapper for REMOTE_PROC_DOMAIN_CORE_DUMP_WITH_FORMAT.
+func (l *Libvirt) DomainCoreDumpWithFormat(Dom Domain, To string, Dumpformat uint32, Flags DomainCoreDumpFlags) (err error) {
+ var buf []byte
+
+ args := DomainCoreDumpWithFormatArgs{
+ Dom: Dom,
+ To: To,
+ Dumpformat: Dumpformat,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(334, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainFsfreeze is the go wrapper for REMOTE_PROC_DOMAIN_FSFREEZE.
+func (l *Libvirt) DomainFsfreeze(Dom Domain, Mountpoints []string, Flags uint32) (rFilesystems int32, err error) {
+ var buf []byte
+
+ args := DomainFsfreezeArgs{
+ Dom: Dom,
+ Mountpoints: Mountpoints,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(335, 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)
+ // Filesystems: int32
+ _, err = dec.Decode(&rFilesystems)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainFsthaw is the go wrapper for REMOTE_PROC_DOMAIN_FSTHAW.
+func (l *Libvirt) DomainFsthaw(Dom Domain, Mountpoints []string, Flags uint32) (rFilesystems int32, err error) {
+ var buf []byte
+
+ args := DomainFsthawArgs{
+ Dom: Dom,
+ Mountpoints: Mountpoints,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(336, 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)
+ // Filesystems: int32
+ _, err = dec.Decode(&rFilesystems)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetTime is the go wrapper for REMOTE_PROC_DOMAIN_GET_TIME.
+func (l *Libvirt) DomainGetTime(Dom Domain, Flags uint32) (rSeconds int64, rNseconds uint32, err error) {
+ var buf []byte
+
+ args := DomainGetTimeArgs{
+ Dom: Dom,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(337, 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)
+ // Seconds: int64
+ _, err = dec.Decode(&rSeconds)
+ if err != nil {
+ return
+ }
+ // Nseconds: uint32
+ _, err = dec.Decode(&rNseconds)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSetTime is the go wrapper for REMOTE_PROC_DOMAIN_SET_TIME.
+func (l *Libvirt) DomainSetTime(Dom Domain, Seconds int64, Nseconds uint32, Flags DomainSetTimeFlags) (err error) {
+ var buf []byte
+
+ args := DomainSetTimeArgs{
+ Dom: Dom,
+ Seconds: Seconds,
+ Nseconds: Nseconds,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(338, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventBlockJob2 is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB_2.
+func (l *Libvirt) DomainEventBlockJob2() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(339, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeGetFreePages is the go wrapper for REMOTE_PROC_NODE_GET_FREE_PAGES.
+func (l *Libvirt) NodeGetFreePages(Pages []uint32, StartCell int32, CellCount uint32, Flags uint32) (rCounts []uint64, err error) {
+ var buf []byte
+
+ args := NodeGetFreePagesArgs{
+ Pages: Pages,
+ StartCell: StartCell,
+ CellCount: CellCount,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(340, 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)
+ // Counts: []uint64
+ _, err = dec.Decode(&rCounts)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NetworkGetDhcpLeases is the go wrapper for REMOTE_PROC_NETWORK_GET_DHCP_LEASES.
+func (l *Libvirt) NetworkGetDhcpLeases(Net Network, Mac OptString, NeedResults int32, Flags uint32) (rLeases []NetworkDhcpLease, rRet uint32, err error) {
+ var buf []byte
+
+ args := NetworkGetDhcpLeasesArgs{
+ Net: Net,
+ Mac: Mac,
+ NeedResults: NeedResults,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(341, 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)
+ // Leases: []NetworkDhcpLease
+ _, err = dec.Decode(&rLeases)
+ if err != nil {
+ return
+ }
+ // Ret: uint32
+ _, err = dec.Decode(&rRet)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectGetDomainCapabilities is the go wrapper for REMOTE_PROC_CONNECT_GET_DOMAIN_CAPABILITIES.
+func (l *Libvirt) ConnectGetDomainCapabilities(Emulatorbin OptString, Arch OptString, Machine OptString, Virttype OptString, Flags uint32) (rCapabilities string, err error) {
+ var buf []byte
+
+ args := ConnectGetDomainCapabilitiesArgs{
+ Emulatorbin: Emulatorbin,
+ Arch: Arch,
+ Machine: Machine,
+ Virttype: Virttype,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(342, 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)
+ // Capabilities: string
+ _, err = dec.Decode(&rCapabilities)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainOpenGraphicsFd is the go wrapper for REMOTE_PROC_DOMAIN_OPEN_GRAPHICS_FD.
+func (l *Libvirt) DomainOpenGraphicsFd(Dom Domain, Idx uint32, Flags DomainOpenGraphicsFlags) (err error) {
+ var buf []byte
+
+ args := DomainOpenGraphicsFdArgs{
+ Dom: Dom,
+ Idx: Idx,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(343, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectGetAllDomainStats is the go wrapper for REMOTE_PROC_CONNECT_GET_ALL_DOMAIN_STATS.
+func (l *Libvirt) ConnectGetAllDomainStats(Doms []Domain, Stats uint32, Flags ConnectGetAllDomainStatsFlags) (rRetStats []DomainStatsRecord, err error) {
+ var buf []byte
+
+ args := ConnectGetAllDomainStatsArgs{
+ Doms: Doms,
+ Stats: Stats,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(344, 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)
+ // RetStats: []DomainStatsRecord
+ _, err = dec.Decode(&rRetStats)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainBlockCopy is the go wrapper for REMOTE_PROC_DOMAIN_BLOCK_COPY.
+func (l *Libvirt) DomainBlockCopy(Dom Domain, Path string, Destxml string, Params []TypedParam, Flags DomainBlockCopyFlags) (err error) {
+ var buf []byte
+
+ args := DomainBlockCopyArgs{
+ Dom: Dom,
+ Path: Path,
+ Destxml: Destxml,
+ Params: Params,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(345, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventCallbackTunable is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_CALLBACK_TUNABLE.
+func (l *Libvirt) DomainEventCallbackTunable() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(346, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeAllocPages is the go wrapper for REMOTE_PROC_NODE_ALLOC_PAGES.
+func (l *Libvirt) NodeAllocPages(PageSizes []uint32, PageCounts []uint64, StartCell int32, CellCount uint32, Flags NodeAllocPagesFlags) (rRet int32, err error) {
+ var buf []byte
+
+ args := NodeAllocPagesArgs{
+ PageSizes: PageSizes,
+ PageCounts: PageCounts,
+ StartCell: StartCell,
+ CellCount: CellCount,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(347, 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)
+ // Ret: int32
+ _, err = dec.Decode(&rRet)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventCallbackAgentLifecycle is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_CALLBACK_AGENT_LIFECYCLE.
+func (l *Libvirt) DomainEventCallbackAgentLifecycle() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(348, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetFsinfo is the go wrapper for REMOTE_PROC_DOMAIN_GET_FSINFO.
+func (l *Libvirt) DomainGetFsinfo(Dom Domain, Flags uint32) (rInfo []DomainFsinfo, rRet uint32, err error) {
+ var buf []byte
+
+ args := DomainGetFsinfoArgs{
+ Dom: Dom,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(349, 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)
+ // Info: []DomainFsinfo
+ _, err = dec.Decode(&rInfo)
+ if err != nil {
+ return
+ }
+ // Ret: uint32
+ _, err = dec.Decode(&rRet)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainDefineXMLFlags is the go wrapper for REMOTE_PROC_DOMAIN_DEFINE_XML_FLAGS.
+func (l *Libvirt) DomainDefineXMLFlags(XML string, Flags DomainDefineFlags) (rDom Domain, err error) {
+ var buf []byte
+
+ args := DomainDefineXMLFlagsArgs{
+ XML: XML,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(350, 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)
+ // Dom: Domain
+ _, err = dec.Decode(&rDom)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetIothreadInfo is the go wrapper for REMOTE_PROC_DOMAIN_GET_IOTHREAD_INFO.
+func (l *Libvirt) DomainGetIothreadInfo(Dom Domain, Flags DomainModificationImpact) (rInfo []DomainIothreadInfo, rRet uint32, err error) {
+ var buf []byte
+
+ args := DomainGetIothreadInfoArgs{
+ Dom: Dom,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(351, 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)
+ // Info: []DomainIothreadInfo
+ _, err = dec.Decode(&rInfo)
+ if err != nil {
+ return
+ }
+ // Ret: uint32
+ _, err = dec.Decode(&rRet)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainPinIothread is the go wrapper for REMOTE_PROC_DOMAIN_PIN_IOTHREAD.
+func (l *Libvirt) DomainPinIothread(Dom Domain, IothreadsID uint32, Cpumap []byte, Flags DomainModificationImpact) (err error) {
+ var buf []byte
+
+ args := DomainPinIothreadArgs{
+ Dom: Dom,
+ IothreadsID: IothreadsID,
+ Cpumap: Cpumap,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(352, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainInterfaceAddresses is the go wrapper for REMOTE_PROC_DOMAIN_INTERFACE_ADDRESSES.
+func (l *Libvirt) DomainInterfaceAddresses(Dom Domain, Source uint32, Flags uint32) (rIfaces []DomainInterface, err error) {
+ var buf []byte
+
+ args := DomainInterfaceAddressesArgs{
+ Dom: Dom,
+ Source: Source,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(353, 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)
+ // Ifaces: []DomainInterface
+ _, err = dec.Decode(&rIfaces)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventCallbackDeviceAdded is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DEVICE_ADDED.
+func (l *Libvirt) DomainEventCallbackDeviceAdded() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(354, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainAddIothread is the go wrapper for REMOTE_PROC_DOMAIN_ADD_IOTHREAD.
+func (l *Libvirt) DomainAddIothread(Dom Domain, IothreadID uint32, Flags DomainModificationImpact) (err error) {
+ var buf []byte
+
+ args := DomainAddIothreadArgs{
+ Dom: Dom,
+ IothreadID: IothreadID,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(355, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainDelIothread is the go wrapper for REMOTE_PROC_DOMAIN_DEL_IOTHREAD.
+func (l *Libvirt) DomainDelIothread(Dom Domain, IothreadID uint32, Flags DomainModificationImpact) (err error) {
+ var buf []byte
+
+ args := DomainDelIothreadArgs{
+ Dom: Dom,
+ IothreadID: IothreadID,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(356, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSetUserPassword is the go wrapper for REMOTE_PROC_DOMAIN_SET_USER_PASSWORD.
+func (l *Libvirt) DomainSetUserPassword(Dom Domain, User OptString, Password OptString, Flags DomainSetUserPasswordFlags) (err error) {
+ var buf []byte
+
+ args := DomainSetUserPasswordArgs{
+ Dom: Dom,
+ User: User,
+ Password: Password,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(357, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainRename is the go wrapper for REMOTE_PROC_DOMAIN_RENAME.
+func (l *Libvirt) DomainRename(Dom Domain, NewName OptString, Flags uint32) (rRetcode int32, err error) {
+ var buf []byte
+
+ args := DomainRenameArgs{
+ Dom: Dom,
+ NewName: NewName,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(358, 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)
+ // Retcode: int32
+ _, err = dec.Decode(&rRetcode)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventCallbackMigrationIteration is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_CALLBACK_MIGRATION_ITERATION.
+func (l *Libvirt) DomainEventCallbackMigrationIteration() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(359, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectRegisterCloseCallback is the go wrapper for REMOTE_PROC_CONNECT_REGISTER_CLOSE_CALLBACK.
+func (l *Libvirt) ConnectRegisterCloseCallback() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(360, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectUnregisterCloseCallback is the go wrapper for REMOTE_PROC_CONNECT_UNREGISTER_CLOSE_CALLBACK.
+func (l *Libvirt) ConnectUnregisterCloseCallback() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(361, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectEventConnectionClosed is the go wrapper for REMOTE_PROC_CONNECT_EVENT_CONNECTION_CLOSED.
+func (l *Libvirt) ConnectEventConnectionClosed() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(362, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventCallbackJobCompleted is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_CALLBACK_JOB_COMPLETED.
+func (l *Libvirt) DomainEventCallbackJobCompleted() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(363, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainMigrateStartPostCopy is the go wrapper for REMOTE_PROC_DOMAIN_MIGRATE_START_POST_COPY.
+func (l *Libvirt) DomainMigrateStartPostCopy(Dom Domain, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainMigrateStartPostCopyArgs{
+ Dom: Dom,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(364, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetPerfEvents is the go wrapper for REMOTE_PROC_DOMAIN_GET_PERF_EVENTS.
+func (l *Libvirt) DomainGetPerfEvents(Dom Domain, Flags DomainModificationImpact) (rParams []TypedParam, err error) {
+ var buf []byte
+
+ args := DomainGetPerfEventsArgs{
+ Dom: Dom,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(365, 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)
+ // Params: []TypedParam
+ _, err = dec.Decode(&rParams)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSetPerfEvents is the go wrapper for REMOTE_PROC_DOMAIN_SET_PERF_EVENTS.
+func (l *Libvirt) DomainSetPerfEvents(Dom Domain, Params []TypedParam, Flags DomainModificationImpact) (err error) {
+ var buf []byte
+
+ args := DomainSetPerfEventsArgs{
+ Dom: Dom,
+ Params: Params,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(366, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventCallbackDeviceRemovalFailed is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DEVICE_REMOVAL_FAILED.
+func (l *Libvirt) DomainEventCallbackDeviceRemovalFailed() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(367, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectStoragePoolEventRegisterAny is the go wrapper for REMOTE_PROC_CONNECT_STORAGE_POOL_EVENT_REGISTER_ANY.
+func (l *Libvirt) ConnectStoragePoolEventRegisterAny(EventID int32, Pool OptStoragePool) (rCallbackID int32, err error) {
+ var buf []byte
+
+ args := ConnectStoragePoolEventRegisterAnyArgs{
+ EventID: EventID,
+ Pool: Pool,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(368, 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)
+ // CallbackID: int32
+ _, err = dec.Decode(&rCallbackID)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectStoragePoolEventDeregisterAny is the go wrapper for REMOTE_PROC_CONNECT_STORAGE_POOL_EVENT_DEREGISTER_ANY.
+func (l *Libvirt) ConnectStoragePoolEventDeregisterAny(CallbackID int32) (err error) {
+ var buf []byte
+
+ args := ConnectStoragePoolEventDeregisterAnyArgs{
+ CallbackID: CallbackID,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(369, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StoragePoolEventLifecycle is the go wrapper for REMOTE_PROC_STORAGE_POOL_EVENT_LIFECYCLE.
+func (l *Libvirt) StoragePoolEventLifecycle() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(370, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetGuestVcpus is the go wrapper for REMOTE_PROC_DOMAIN_GET_GUEST_VCPUS.
+func (l *Libvirt) DomainGetGuestVcpus(Dom Domain, Flags uint32) (rParams []TypedParam, err error) {
+ var buf []byte
+
+ args := DomainGetGuestVcpusArgs{
+ Dom: Dom,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(371, 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)
+ // Params: []TypedParam
+ _, err = dec.Decode(&rParams)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSetGuestVcpus is the go wrapper for REMOTE_PROC_DOMAIN_SET_GUEST_VCPUS.
+func (l *Libvirt) DomainSetGuestVcpus(Dom Domain, Cpumap string, State int32, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainSetGuestVcpusArgs{
+ Dom: Dom,
+ Cpumap: Cpumap,
+ State: State,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(372, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StoragePoolEventRefresh is the go wrapper for REMOTE_PROC_STORAGE_POOL_EVENT_REFRESH.
+func (l *Libvirt) StoragePoolEventRefresh() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(373, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectNodeDeviceEventRegisterAny is the go wrapper for REMOTE_PROC_CONNECT_NODE_DEVICE_EVENT_REGISTER_ANY.
+func (l *Libvirt) ConnectNodeDeviceEventRegisterAny(EventID int32, Dev OptNodeDevice) (rCallbackID int32, err error) {
+ var buf []byte
+
+ args := ConnectNodeDeviceEventRegisterAnyArgs{
+ EventID: EventID,
+ Dev: Dev,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(374, 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)
+ // CallbackID: int32
+ _, err = dec.Decode(&rCallbackID)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectNodeDeviceEventDeregisterAny is the go wrapper for REMOTE_PROC_CONNECT_NODE_DEVICE_EVENT_DEREGISTER_ANY.
+func (l *Libvirt) ConnectNodeDeviceEventDeregisterAny(CallbackID int32) (err error) {
+ var buf []byte
+
+ args := ConnectNodeDeviceEventDeregisterAnyArgs{
+ CallbackID: CallbackID,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(375, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeDeviceEventLifecycle is the go wrapper for REMOTE_PROC_NODE_DEVICE_EVENT_LIFECYCLE.
+func (l *Libvirt) NodeDeviceEventLifecycle() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(376, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeDeviceEventUpdate is the go wrapper for REMOTE_PROC_NODE_DEVICE_EVENT_UPDATE.
+func (l *Libvirt) NodeDeviceEventUpdate() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(377, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StorageVolGetInfoFlags is the go wrapper for REMOTE_PROC_STORAGE_VOL_GET_INFO_FLAGS.
+func (l *Libvirt) StorageVolGetInfoFlags(Vol StorageVol, Flags uint32) (rType int8, rCapacity uint64, rAllocation uint64, err error) {
+ var buf []byte
+
+ args := StorageVolGetInfoFlagsArgs{
+ Vol: Vol,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(378, 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)
+ // Type: int8
+ _, err = dec.Decode(&rType)
+ if err != nil {
+ return
+ }
+ // Capacity: uint64
+ _, err = dec.Decode(&rCapacity)
+ if err != nil {
+ return
+ }
+ // Allocation: uint64
+ _, err = dec.Decode(&rAllocation)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventCallbackMetadataChange is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_CALLBACK_METADATA_CHANGE.
+func (l *Libvirt) DomainEventCallbackMetadataChange() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(379, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectSecretEventRegisterAny is the go wrapper for REMOTE_PROC_CONNECT_SECRET_EVENT_REGISTER_ANY.
+func (l *Libvirt) ConnectSecretEventRegisterAny(EventID int32, OptSecret OptSecret) (rCallbackID int32, err error) {
+ var buf []byte
+
+ args := ConnectSecretEventRegisterAnyArgs{
+ EventID: EventID,
+ OptSecret: OptSecret,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(380, 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)
+ // CallbackID: int32
+ _, err = dec.Decode(&rCallbackID)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectSecretEventDeregisterAny is the go wrapper for REMOTE_PROC_CONNECT_SECRET_EVENT_DEREGISTER_ANY.
+func (l *Libvirt) ConnectSecretEventDeregisterAny(CallbackID int32) (err error) {
+ var buf []byte
+
+ args := ConnectSecretEventDeregisterAnyArgs{
+ CallbackID: CallbackID,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(381, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// SecretEventLifecycle is the go wrapper for REMOTE_PROC_SECRET_EVENT_LIFECYCLE.
+func (l *Libvirt) SecretEventLifecycle() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(382, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// SecretEventValueChanged is the go wrapper for REMOTE_PROC_SECRET_EVENT_VALUE_CHANGED.
+func (l *Libvirt) SecretEventValueChanged() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(383, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSetVcpu is the go wrapper for REMOTE_PROC_DOMAIN_SET_VCPU.
+func (l *Libvirt) DomainSetVcpu(Dom Domain, Cpumap string, State int32, Flags DomainModificationImpact) (err error) {
+ var buf []byte
+
+ args := DomainSetVcpuArgs{
+ Dom: Dom,
+ Cpumap: Cpumap,
+ State: State,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(384, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventBlockThreshold is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_BLOCK_THRESHOLD.
+func (l *Libvirt) DomainEventBlockThreshold() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(385, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSetBlockThreshold is the go wrapper for REMOTE_PROC_DOMAIN_SET_BLOCK_THRESHOLD.
+func (l *Libvirt) DomainSetBlockThreshold(Dom Domain, Dev string, Threshold uint64, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainSetBlockThresholdArgs{
+ Dom: Dom,
+ Dev: Dev,
+ Threshold: Threshold,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(386, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainMigrateGetMaxDowntime is the go wrapper for REMOTE_PROC_DOMAIN_MIGRATE_GET_MAX_DOWNTIME.
+func (l *Libvirt) DomainMigrateGetMaxDowntime(Dom Domain, Flags uint32) (rDowntime uint64, err error) {
+ var buf []byte
+
+ args := DomainMigrateGetMaxDowntimeArgs{
+ Dom: Dom,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(387, 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)
+ // Downtime: uint64
+ _, err = dec.Decode(&rDowntime)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainManagedSaveGetXMLDesc is the go wrapper for REMOTE_PROC_DOMAIN_MANAGED_SAVE_GET_XML_DESC.
+func (l *Libvirt) DomainManagedSaveGetXMLDesc(Dom Domain, Flags DomainXMLFlags) (rXML string, err error) {
+ var buf []byte
+
+ args := DomainManagedSaveGetXMLDescArgs{
+ Dom: Dom,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(388, 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)
+ // XML: string
+ _, err = dec.Decode(&rXML)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainManagedSaveDefineXML is the go wrapper for REMOTE_PROC_DOMAIN_MANAGED_SAVE_DEFINE_XML.
+func (l *Libvirt) DomainManagedSaveDefineXML(Dom Domain, Dxml OptString, Flags DomainSaveRestoreFlags) (err error) {
+ var buf []byte
+
+ args := DomainManagedSaveDefineXMLArgs{
+ Dom: Dom,
+ Dxml: Dxml,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(389, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSetLifecycleAction is the go wrapper for REMOTE_PROC_DOMAIN_SET_LIFECYCLE_ACTION.
+func (l *Libvirt) DomainSetLifecycleAction(Dom Domain, Type uint32, Action uint32, Flags DomainModificationImpact) (err error) {
+ var buf []byte
+
+ args := DomainSetLifecycleActionArgs{
+ Dom: Dom,
+ Type: Type,
+ Action: Action,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(390, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// StoragePoolLookupByTargetPath is the go wrapper for REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_TARGET_PATH.
+func (l *Libvirt) StoragePoolLookupByTargetPath(Path string) (rPool StoragePool, err error) {
+ var buf []byte
+
+ args := StoragePoolLookupByTargetPathArgs{
+ Path: Path,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(391, 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)
+ // Pool: StoragePool
+ _, err = dec.Decode(&rPool)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainDetachDeviceAlias is the go wrapper for REMOTE_PROC_DOMAIN_DETACH_DEVICE_ALIAS.
+func (l *Libvirt) DomainDetachDeviceAlias(Dom Domain, Alias string, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainDetachDeviceAliasArgs{
+ Dom: Dom,
+ Alias: Alias,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(392, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectCompareHypervisorCPU is the go wrapper for REMOTE_PROC_CONNECT_COMPARE_HYPERVISOR_CPU.
+func (l *Libvirt) ConnectCompareHypervisorCPU(Emulator OptString, Arch OptString, Machine OptString, Virttype OptString, XMLCPU string, Flags uint32) (rResult int32, err error) {
+ var buf []byte
+
+ args := ConnectCompareHypervisorCPUArgs{
+ Emulator: Emulator,
+ Arch: Arch,
+ Machine: Machine,
+ Virttype: Virttype,
+ XMLCPU: XMLCPU,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(393, 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)
+ // Result: int32
+ _, err = dec.Decode(&rResult)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectBaselineHypervisorCPU is the go wrapper for REMOTE_PROC_CONNECT_BASELINE_HYPERVISOR_CPU.
+func (l *Libvirt) ConnectBaselineHypervisorCPU(Emulator OptString, Arch OptString, Machine OptString, Virttype OptString, XMLCPUs []string, Flags uint32) (rCPU string, err error) {
+ var buf []byte
+
+ args := ConnectBaselineHypervisorCPUArgs{
+ Emulator: Emulator,
+ Arch: Arch,
+ Machine: Machine,
+ Virttype: Virttype,
+ XMLCPUs: XMLCPUs,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(394, 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)
+ // CPU: string
+ _, err = dec.Decode(&rCPU)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeGetSevInfo is the go wrapper for REMOTE_PROC_NODE_GET_SEV_INFO.
+func (l *Libvirt) NodeGetSevInfo(Nparams int32, Flags uint32) (rParams []TypedParam, rNparams int32, err error) {
+ var buf []byte
+
+ args := NodeGetSevInfoArgs{
+ Nparams: Nparams,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(395, 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)
+ // Params: []TypedParam
+ _, err = dec.Decode(&rParams)
+ if err != nil {
+ return
+ }
+ // Nparams: int32
+ _, err = dec.Decode(&rNparams)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetLaunchSecurityInfo is the go wrapper for REMOTE_PROC_DOMAIN_GET_LAUNCH_SECURITY_INFO.
+func (l *Libvirt) DomainGetLaunchSecurityInfo(Dom Domain, Flags uint32) (rParams []TypedParam, err error) {
+ var buf []byte
+
+ args := DomainGetLaunchSecurityInfoArgs{
+ Dom: Dom,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(396, 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)
+ // Params: []TypedParam
+ _, err = dec.Decode(&rParams)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NwfilterBindingLookupByPortDev is the go wrapper for REMOTE_PROC_NWFILTER_BINDING_LOOKUP_BY_PORT_DEV.
+func (l *Libvirt) NwfilterBindingLookupByPortDev(Name string) (rOptNwfilter NwfilterBinding, err error) {
+ var buf []byte
+
+ args := NwfilterBindingLookupByPortDevArgs{
+ Name: Name,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(397, 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)
+ // OptNwfilter: NwfilterBinding
+ _, err = dec.Decode(&rOptNwfilter)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NwfilterBindingGetXMLDesc is the go wrapper for REMOTE_PROC_NWFILTER_BINDING_GET_XML_DESC.
+func (l *Libvirt) NwfilterBindingGetXMLDesc(OptNwfilter NwfilterBinding, Flags uint32) (rXML string, err error) {
+ var buf []byte
+
+ args := NwfilterBindingGetXMLDescArgs{
+ OptNwfilter: OptNwfilter,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(398, 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)
+ // XML: string
+ _, err = dec.Decode(&rXML)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NwfilterBindingCreateXML is the go wrapper for REMOTE_PROC_NWFILTER_BINDING_CREATE_XML.
+func (l *Libvirt) NwfilterBindingCreateXML(XML string, Flags uint32) (rOptNwfilter NwfilterBinding, err error) {
+ var buf []byte
+
+ args := NwfilterBindingCreateXMLArgs{
+ XML: XML,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(399, 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)
+ // OptNwfilter: NwfilterBinding
+ _, err = dec.Decode(&rOptNwfilter)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NwfilterBindingDelete is the go wrapper for REMOTE_PROC_NWFILTER_BINDING_DELETE.
+func (l *Libvirt) NwfilterBindingDelete(OptNwfilter NwfilterBinding) (err error) {
+ var buf []byte
+
+ args := NwfilterBindingDeleteArgs{
+ OptNwfilter: OptNwfilter,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(400, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectListAllNwfilterBindings is the go wrapper for REMOTE_PROC_CONNECT_LIST_ALL_NWFILTER_BINDINGS.
+func (l *Libvirt) ConnectListAllNwfilterBindings(NeedResults int32, Flags uint32) (rBindings []NwfilterBinding, rRet uint32, err error) {
+ var buf []byte
+
+ args := ConnectListAllNwfilterBindingsArgs{
+ NeedResults: NeedResults,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(401, 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)
+ // Bindings: []NwfilterBinding
+ _, err = dec.Decode(&rBindings)
+ if err != nil {
+ return
+ }
+ // Ret: uint32
+ _, err = dec.Decode(&rRet)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSetIothreadParams is the go wrapper for REMOTE_PROC_DOMAIN_SET_IOTHREAD_PARAMS.
+func (l *Libvirt) DomainSetIothreadParams(Dom Domain, IothreadID uint32, Params []TypedParam, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainSetIothreadParamsArgs{
+ Dom: Dom,
+ IothreadID: IothreadID,
+ Params: Params,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(402, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectGetStoragePoolCapabilities is the go wrapper for REMOTE_PROC_CONNECT_GET_STORAGE_POOL_CAPABILITIES.
+func (l *Libvirt) ConnectGetStoragePoolCapabilities(Flags uint32) (rCapabilities string, err error) {
+ var buf []byte
+
+ args := ConnectGetStoragePoolCapabilitiesArgs{
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(403, 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)
+ // Capabilities: string
+ _, err = dec.Decode(&rCapabilities)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NetworkListAllPorts is the go wrapper for REMOTE_PROC_NETWORK_LIST_ALL_PORTS.
+func (l *Libvirt) NetworkListAllPorts(OptNetwork Network, NeedResults int32, Flags uint32) (rPorts []NetworkPort, rRet uint32, err error) {
+ var buf []byte
+
+ args := NetworkListAllPortsArgs{
+ OptNetwork: OptNetwork,
+ NeedResults: NeedResults,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(404, 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)
+ // Ports: []NetworkPort
+ _, err = dec.Decode(&rPorts)
+ if err != nil {
+ return
+ }
+ // Ret: uint32
+ _, err = dec.Decode(&rRet)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NetworkPortLookupByUUID is the go wrapper for REMOTE_PROC_NETWORK_PORT_LOOKUP_BY_UUID.
+func (l *Libvirt) NetworkPortLookupByUUID(OptNetwork Network, UUID UUID) (rPort NetworkPort, err error) {
+ var buf []byte
+
+ args := NetworkPortLookupByUUIDArgs{
+ OptNetwork: OptNetwork,
+ UUID: UUID,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(405, 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)
+ // Port: NetworkPort
+ _, err = dec.Decode(&rPort)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NetworkPortCreateXML is the go wrapper for REMOTE_PROC_NETWORK_PORT_CREATE_XML.
+func (l *Libvirt) NetworkPortCreateXML(OptNetwork Network, XML string, Flags uint32) (rPort NetworkPort, err error) {
+ var buf []byte
+
+ args := NetworkPortCreateXMLArgs{
+ OptNetwork: OptNetwork,
+ XML: XML,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(406, 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)
+ // Port: NetworkPort
+ _, err = dec.Decode(&rPort)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NetworkPortGetParameters is the go wrapper for REMOTE_PROC_NETWORK_PORT_GET_PARAMETERS.
+func (l *Libvirt) NetworkPortGetParameters(Port NetworkPort, Nparams int32, Flags uint32) (rParams []TypedParam, rNparams int32, err error) {
+ var buf []byte
+
+ args := NetworkPortGetParametersArgs{
+ Port: Port,
+ Nparams: Nparams,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(407, 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)
+ // Params: []TypedParam
+ _, err = dec.Decode(&rParams)
+ if err != nil {
+ return
+ }
+ // Nparams: int32
+ _, err = dec.Decode(&rNparams)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NetworkPortSetParameters is the go wrapper for REMOTE_PROC_NETWORK_PORT_SET_PARAMETERS.
+func (l *Libvirt) NetworkPortSetParameters(Port NetworkPort, Params []TypedParam, Flags uint32) (err error) {
+ var buf []byte
+
+ args := NetworkPortSetParametersArgs{
+ Port: Port,
+ Params: Params,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(408, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NetworkPortGetXMLDesc is the go wrapper for REMOTE_PROC_NETWORK_PORT_GET_XML_DESC.
+func (l *Libvirt) NetworkPortGetXMLDesc(Port NetworkPort, Flags uint32) (rXML string, err error) {
+ var buf []byte
+
+ args := NetworkPortGetXMLDescArgs{
+ Port: Port,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(409, 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)
+ // XML: string
+ _, err = dec.Decode(&rXML)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NetworkPortDelete is the go wrapper for REMOTE_PROC_NETWORK_PORT_DELETE.
+func (l *Libvirt) NetworkPortDelete(Port NetworkPort, Flags uint32) (err error) {
+ var buf []byte
+
+ args := NetworkPortDeleteArgs{
+ Port: Port,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(410, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainCheckpointCreateXML is the go wrapper for REMOTE_PROC_DOMAIN_CHECKPOINT_CREATE_XML.
+func (l *Libvirt) DomainCheckpointCreateXML(Dom Domain, XMLDesc string, Flags uint32) (rCheckpoint DomainCheckpoint, err error) {
+ var buf []byte
+
+ args := DomainCheckpointCreateXMLArgs{
+ Dom: Dom,
+ XMLDesc: XMLDesc,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(411, 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)
+ // Checkpoint: DomainCheckpoint
+ _, err = dec.Decode(&rCheckpoint)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainCheckpointGetXMLDesc is the go wrapper for REMOTE_PROC_DOMAIN_CHECKPOINT_GET_XML_DESC.
+func (l *Libvirt) DomainCheckpointGetXMLDesc(Checkpoint DomainCheckpoint, Flags uint32) (rXML string, err error) {
+ var buf []byte
+
+ args := DomainCheckpointGetXMLDescArgs{
+ Checkpoint: Checkpoint,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(412, 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)
+ // XML: string
+ _, err = dec.Decode(&rXML)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainListAllCheckpoints is the go wrapper for REMOTE_PROC_DOMAIN_LIST_ALL_CHECKPOINTS.
+func (l *Libvirt) DomainListAllCheckpoints(Dom Domain, NeedResults int32, Flags uint32) (rCheckpoints []DomainCheckpoint, rRet int32, err error) {
+ var buf []byte
+
+ args := DomainListAllCheckpointsArgs{
+ Dom: Dom,
+ NeedResults: NeedResults,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(413, 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)
+ // Checkpoints: []DomainCheckpoint
+ _, err = dec.Decode(&rCheckpoints)
+ if err != nil {
+ return
+ }
+ // Ret: int32
+ _, err = dec.Decode(&rRet)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainCheckpointListAllChildren is the go wrapper for REMOTE_PROC_DOMAIN_CHECKPOINT_LIST_ALL_CHILDREN.
+func (l *Libvirt) DomainCheckpointListAllChildren(Checkpoint DomainCheckpoint, NeedResults int32, Flags uint32) (rCheckpoints []DomainCheckpoint, rRet int32, err error) {
+ var buf []byte
+
+ args := DomainCheckpointListAllChildrenArgs{
+ Checkpoint: Checkpoint,
+ NeedResults: NeedResults,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(414, 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)
+ // Checkpoints: []DomainCheckpoint
+ _, err = dec.Decode(&rCheckpoints)
+ if err != nil {
+ return
+ }
+ // Ret: int32
+ _, err = dec.Decode(&rRet)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainCheckpointLookupByName is the go wrapper for REMOTE_PROC_DOMAIN_CHECKPOINT_LOOKUP_BY_NAME.
+func (l *Libvirt) DomainCheckpointLookupByName(Dom Domain, Name string, Flags uint32) (rCheckpoint DomainCheckpoint, err error) {
+ var buf []byte
+
+ args := DomainCheckpointLookupByNameArgs{
+ Dom: Dom,
+ Name: Name,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(415, 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)
+ // Checkpoint: DomainCheckpoint
+ _, err = dec.Decode(&rCheckpoint)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainCheckpointGetParent is the go wrapper for REMOTE_PROC_DOMAIN_CHECKPOINT_GET_PARENT.
+func (l *Libvirt) DomainCheckpointGetParent(Checkpoint DomainCheckpoint, Flags uint32) (rParent DomainCheckpoint, err error) {
+ var buf []byte
+
+ args := DomainCheckpointGetParentArgs{
+ Checkpoint: Checkpoint,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(416, 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)
+ // Parent: DomainCheckpoint
+ _, err = dec.Decode(&rParent)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainCheckpointDelete is the go wrapper for REMOTE_PROC_DOMAIN_CHECKPOINT_DELETE.
+func (l *Libvirt) DomainCheckpointDelete(Checkpoint DomainCheckpoint, Flags DomainCheckpointDeleteFlags) (err error) {
+ var buf []byte
+
+ args := DomainCheckpointDeleteArgs{
+ Checkpoint: Checkpoint,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(417, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainGetGuestInfo is the go wrapper for REMOTE_PROC_DOMAIN_GET_GUEST_INFO.
+func (l *Libvirt) DomainGetGuestInfo(Dom Domain, Types uint32, Flags uint32) (rParams []TypedParam, err error) {
+ var buf []byte
+
+ args := DomainGetGuestInfoArgs{
+ Dom: Dom,
+ Types: Types,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(418, 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)
+ // Params: []TypedParam
+ _, err = dec.Decode(&rParams)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// ConnectSetIdentity is the go wrapper for REMOTE_PROC_CONNECT_SET_IDENTITY.
+func (l *Libvirt) ConnectSetIdentity(Params []TypedParam, Flags uint32) (err error) {
+ var buf []byte
+
+ args := ConnectSetIdentityArgs{
+ Params: Params,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(419, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainAgentSetResponseTimeout is the go wrapper for REMOTE_PROC_DOMAIN_AGENT_SET_RESPONSE_TIMEOUT.
+func (l *Libvirt) DomainAgentSetResponseTimeout(Dom Domain, Timeout int32, Flags uint32) (rResult int32, err error) {
+ var buf []byte
+
+ args := DomainAgentSetResponseTimeoutArgs{
+ Dom: Dom,
+ Timeout: Timeout,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(420, 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)
+ // Result: int32
+ _, err = dec.Decode(&rResult)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainBackupBegin is the go wrapper for REMOTE_PROC_DOMAIN_BACKUP_BEGIN.
+func (l *Libvirt) DomainBackupBegin(Dom Domain, BackupXML string, CheckpointXML OptString, Flags DomainBackupBeginFlags) (err error) {
+ var buf []byte
+
+ args := DomainBackupBeginArgs{
+ Dom: Dom,
+ BackupXML: BackupXML,
+ CheckpointXML: CheckpointXML,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(421, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainBackupGetXMLDesc is the go wrapper for REMOTE_PROC_DOMAIN_BACKUP_GET_XML_DESC.
+func (l *Libvirt) DomainBackupGetXMLDesc(Dom Domain, Flags uint32) (rXML string, err error) {
+ var buf []byte
+
+ args := DomainBackupGetXMLDescArgs{
+ Dom: Dom,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(422, 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)
+ // XML: string
+ _, err = dec.Decode(&rXML)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventMemoryFailure is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_MEMORY_FAILURE.
+func (l *Libvirt) DomainEventMemoryFailure() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(423, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainAuthorizedSshKeysGet is the go wrapper for REMOTE_PROC_DOMAIN_AUTHORIZED_SSH_KEYS_GET.
+func (l *Libvirt) DomainAuthorizedSshKeysGet(Dom Domain, User string, Flags uint32) (rKeys []string, err error) {
+ var buf []byte
+
+ args := DomainAuthorizedSshKeysGetArgs{
+ Dom: Dom,
+ User: User,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(424, 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)
+ // Keys: []string
+ _, err = dec.Decode(&rKeys)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainAuthorizedSshKeysSet is the go wrapper for REMOTE_PROC_DOMAIN_AUTHORIZED_SSH_KEYS_SET.
+func (l *Libvirt) DomainAuthorizedSshKeysSet(Dom Domain, User string, Keys []string, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainAuthorizedSshKeysSetArgs{
+ Dom: Dom,
+ User: User,
+ Keys: Keys,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(425, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ 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
+}
+
+// DomainStartDirtyRateCalc is the go wrapper for REMOTE_PROC_DOMAIN_START_DIRTY_RATE_CALC.
+func (l *Libvirt) DomainStartDirtyRateCalc(Dom Domain, Seconds int32, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainStartDirtyRateCalcArgs{
+ Dom: Dom,
+ Seconds: Seconds,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(427, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeDeviceDefineXML is the go wrapper for REMOTE_PROC_NODE_DEVICE_DEFINE_XML.
+func (l *Libvirt) NodeDeviceDefineXML(XMLDesc string, Flags uint32) (rDev NodeDevice, err error) {
+ var buf []byte
+
+ args := NodeDeviceDefineXMLArgs{
+ XMLDesc: XMLDesc,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(428, 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)
+ // Dev: NodeDevice
+ _, err = dec.Decode(&rDev)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeDeviceUndefine is the go wrapper for REMOTE_PROC_NODE_DEVICE_UNDEFINE.
+func (l *Libvirt) NodeDeviceUndefine(Name string, Flags uint32) (err error) {
+ var buf []byte
+
+ args := NodeDeviceUndefineArgs{
+ Name: Name,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(429, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeDeviceCreate is the go wrapper for REMOTE_PROC_NODE_DEVICE_CREATE.
+func (l *Libvirt) NodeDeviceCreate(Name string, Flags uint32) (err error) {
+ var buf []byte
+
+ args := NodeDeviceCreateArgs{
+ Name: Name,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(430, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NwfilterDefineXMLFlags is the go wrapper for REMOTE_PROC_NWFILTER_DEFINE_XML_FLAGS.
+func (l *Libvirt) NwfilterDefineXMLFlags(XML string, Flags uint32) (rOptNwfilter Nwfilter, err error) {
+ var buf []byte
+
+ args := NwfilterDefineXMLFlagsArgs{
+ XML: XML,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(431, 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)
+ // OptNwfilter: Nwfilter
+ _, err = dec.Decode(&rOptNwfilter)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NetworkDefineXMLFlags is the go wrapper for REMOTE_PROC_NETWORK_DEFINE_XML_FLAGS.
+func (l *Libvirt) NetworkDefineXMLFlags(XML string, Flags uint32) (rNet Network, err error) {
+ var buf []byte
+
+ args := NetworkDefineXMLFlagsArgs{
+ XML: XML,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(432, 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)
+ // Net: Network
+ _, err = dec.Decode(&rNet)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeDeviceGetAutostart is the go wrapper for REMOTE_PROC_NODE_DEVICE_GET_AUTOSTART.
+func (l *Libvirt) NodeDeviceGetAutostart(Name string) (rAutostart int32, err error) {
+ var buf []byte
+
+ args := NodeDeviceGetAutostartArgs{
+ Name: Name,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(433, 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)
+ // Autostart: int32
+ _, err = dec.Decode(&rAutostart)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeDeviceSetAutostart is the go wrapper for REMOTE_PROC_NODE_DEVICE_SET_AUTOSTART.
+func (l *Libvirt) NodeDeviceSetAutostart(Name string, Autostart int32) (err error) {
+ var buf []byte
+
+ args := NodeDeviceSetAutostartArgs{
+ Name: Name,
+ Autostart: Autostart,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(434, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeDeviceIsPersistent is the go wrapper for REMOTE_PROC_NODE_DEVICE_IS_PERSISTENT.
+func (l *Libvirt) NodeDeviceIsPersistent(Name string) (rPersistent int32, err error) {
+ var buf []byte
+
+ args := NodeDeviceIsPersistentArgs{
+ Name: Name,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(435, 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)
+ // Persistent: int32
+ _, err = dec.Decode(&rPersistent)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NodeDeviceIsActive is the go wrapper for REMOTE_PROC_NODE_DEVICE_IS_ACTIVE.
+func (l *Libvirt) NodeDeviceIsActive(Name string) (rActive int32, err error) {
+ var buf []byte
+
+ args := NodeDeviceIsActiveArgs{
+ Name: Name,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(436, 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)
+ // Active: int32
+ _, err = dec.Decode(&rActive)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// NetworkCreateXMLFlags is the go wrapper for REMOTE_PROC_NETWORK_CREATE_XML_FLAGS.
+func (l *Libvirt) NetworkCreateXMLFlags(XML string, Flags uint32) (rNet Network, err error) {
+ var buf []byte
+
+ args := NetworkCreateXMLFlagsArgs{
+ XML: XML,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ var r response
+ r, err = l.requestStream(437, 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)
+ // Net: Network
+ _, err = dec.Decode(&rNet)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainEventMemoryDeviceSizeChange is the go wrapper for REMOTE_PROC_DOMAIN_EVENT_MEMORY_DEVICE_SIZE_CHANGE.
+func (l *Libvirt) DomainEventMemoryDeviceSizeChange() (err error) {
+ var buf []byte
+
+ _, err = l.requestStream(438, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+// DomainSetLaunchSecurityState is the go wrapper for REMOTE_PROC_DOMAIN_SET_LAUNCH_SECURITY_STATE.
+func (l *Libvirt) DomainSetLaunchSecurityState(Dom Domain, Params []TypedParam, Flags uint32) (err error) {
+ var buf []byte
+
+ args := DomainSetLaunchSecurityStateArgs{
+ Dom: Dom,
+ Params: Params,
+ Flags: Flags,
+ }
+
+ buf, err = encode(&args)
+ if err != nil {
+ return
+ }
+
+ _, err = l.requestStream(439, constants.Program, buf, nil, nil)
+ if err != nil {
+ return
+ }
+
+ return
+}
diff --git a/third_party/libvirt/rpc.go b/third_party/libvirt/rpc.go
new file mode 100644
index 0000000..5a3c6c8
--- /dev/null
+++ b/third_party/libvirt/rpc.go
@@ -0,0 +1,481 @@
+// 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"
+ "errors"
+ "fmt"
+ "io"
+ "reflect"
+ "strings"
+ "sync/atomic"
+
+ "github.com/projecteru2/yavirt/third_party/libvirt/internal/constants"
+ "github.com/projecteru2/yavirt/third_party/libvirt/internal/event"
+ xdr "github.com/projecteru2/yavirt/third_party/libvirt/internal/go-xdr/xdr2"
+ "github.com/projecteru2/yavirt/third_party/libvirt/socket"
+)
+
+// ErrUnsupported is returned if a procedure is not supported by libvirt
+var ErrUnsupported = errors.New("unsupported procedure requested")
+
+// ErrInterrupted is returned if the socket is closed while waiting for the
+// result of a procedure call.
+var ErrInterrupted = errors.New("procedure interrupted while awaiting response")
+
+// internal rpc response
+type response struct {
+ Payload []byte
+ Status uint32
+}
+
+// Error reponse from libvirt
+type Error struct {
+ Code uint32
+ Message 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 {
+ 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)
+}
+
+// callback sends RPC responses to respective callers.
+func (l *Libvirt) callback(id int32, res response) {
+ l.cmux.Lock()
+ defer l.cmux.Unlock()
+
+ c, ok := l.callbacks[id]
+ if !ok {
+ return
+ }
+
+ c <- res
+}
+
+// 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 h.Program {
+ case constants.QEMUProgram:
+ if h.Procedure != constants.QEMUProcDomainMonitorEvent {
+ break
+ }
+ event = &DomainEvent{}
+ case constants.Program:
+ event = eventFromProcedureID(h.Procedure)
+ }
+
+ if event != nil {
+ err := eventDecoder(buf, event)
+ if err != nil { // event was malformed, drop.
+ return
+ }
+
+ l.stream(event)
+ return
+ }
+
+ // send response to caller
+ l.callback(h.Serial, response{Payload: buf, Status: h.Status})
+}
+
+func eventFromProcedureID(procID uint32) event.Event {
+ switch procID {
+ case constants.ProcDomainEventCallbackLifecycle:
+ return &DomainEventCallbackLifecycleMsg{}
+ case constants.ProcDomainEventCallbackReboot:
+ return &DomainEventCallbackRebootMsg{}
+ case constants.ProcDomainEventCallbackRtcChange:
+ return &DomainEventCallbackRtcChangeMsg{}
+ case constants.ProcDomainEventCallbackWatchdog:
+ return &DomainEventCallbackWatchdogMsg{}
+ case constants.ProcDomainEventCallbackIOError:
+ return &DomainEventCallbackIOErrorMsg{}
+ case constants.ProcDomainEventCallbackIOErrorReason:
+ return &DomainEventCallbackIOErrorReasonMsg{}
+ case constants.ProcDomainEventCallbackGraphics:
+ return &DomainEventCallbackGraphicsMsg{}
+ case constants.ProcDomainEventCallbackBlockJob:
+ return &DomainEventCallbackBlockJobMsg{}
+ case constants.ProcDomainEventCallbackDiskChange:
+ return &DomainEventCallbackDiskChangeMsg{}
+ case constants.ProcDomainEventCallbackTrayChange:
+ return &DomainEventCallbackTrayChangeMsg{}
+ case constants.ProcDomainEventCallbackPmwakeup:
+ return &DomainEventCallbackPmwakeupMsg{}
+ case constants.ProcDomainEventCallbackPmsuspend:
+ return &DomainEventCallbackPmsuspendMsg{}
+ case constants.ProcDomainEventCallbackBalloonChange:
+ return &DomainEventCallbackBalloonChangeMsg{}
+ case constants.ProcDomainEventCallbackPmsuspendDisk:
+ return &DomainEventCallbackPmsuspendDiskMsg{}
+ case constants.ProcDomainEventCallbackControlError:
+ return &DomainEventCallbackControlErrorMsg{}
+ case constants.ProcDomainEventCallbackDeviceRemoved:
+ return &DomainEventCallbackDeviceRemovedMsg{}
+ case constants.ProcDomainEventCallbackTunable:
+ return &DomainEventCallbackTunableMsg{}
+ case constants.ProcDomainEventCallbackDeviceAdded:
+ return &DomainEventCallbackDeviceAddedMsg{}
+ case constants.ProcDomainEventCallbackAgentLifecycle:
+ return &DomainEventCallbackAgentLifecycleMsg{}
+ case constants.ProcDomainEventCallbackMigrationIteration:
+ return &DomainEventCallbackMigrationIterationMsg{}
+ case constants.ProcDomainEventCallbackJobCompleted:
+ return &DomainEventCallbackJobCompletedMsg{}
+ case constants.ProcDomainEventCallbackDeviceRemovalFailed:
+ return &DomainEventCallbackDeviceRemovalFailedMsg{}
+ case constants.ProcDomainEventCallbackMetadataChange:
+ return &DomainEventCallbackMetadataChangeMsg{}
+ }
+ return nil
+}
+
+// serial provides atomic access to the next sequential request serial number.
+func (l *Libvirt) serial() int32 {
+ return atomic.AddInt32(&l.s, 1)
+}
+
+// stream decodes and relays domain events to their respective listener.
+func (l *Libvirt) stream(e event.Event) {
+ l.emux.RLock()
+ defer l.emux.RUnlock()
+
+ q, ok := l.events[e.GetCallbackID()]
+ if !ok {
+ return
+ }
+
+ q.Push(e)
+}
+
+// addStream configures the routing for an event stream.
+func (l *Libvirt) addStream(s *event.Stream) {
+ l.emux.Lock()
+ defer l.emux.Unlock()
+
+ l.events[s.CallbackID] = s
+}
+
+// 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
+ 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()
+ defer l.cmux.Unlock()
+
+ l.callbacks[id] = c
+}
+
+// deregister destroys a method response callback. It is the responsibility of
+// the caller to manage locking (l.cmux) during this call.
+func (l *Libvirt) deregister(id int32) {
+ _, ok := l.callbacks[id]
+ if !ok {
+ return
+ }
+
+ close(l.callbacks[id])
+ delete(l.callbacks, id)
+}
+
+// deregisterAll closes all 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.cmux.Lock()
+ defer l.cmux.Unlock()
+
+ for id := range l.callbacks {
+ l.deregister(id)
+ }
+}
+
+// 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)
+}
+
+// requestStream performs a libvirt RPC request. The `out` and `in` parameters
+// are optional, and should be nil when RPC endpoints don't return a stream.
+func (l *Libvirt) requestStream(proc uint32, program uint32, payload []byte,
+ out io.Reader, in io.Writer) (response, error) {
+ serial := l.serial()
+ c := make(chan response)
+
+ l.register(serial, c)
+ defer func() {
+ l.cmux.Lock()
+ defer l.cmux.Unlock()
+
+ l.deregister(serial)
+ }()
+
+ err := l.socket.SendPacket(serial, proc, program, payload, socket.Call,
+ socket.StatusOK)
+ if err != nil {
+ return response{}, err
+ }
+
+ resp, err := l.getResponse(c)
+ if err != nil {
+ return resp, err
+ }
+
+ if out != nil {
+ abort := make(chan bool)
+ outErr := make(chan error)
+ go func() {
+ outErr <- l.socket.SendStream(serial, proc, program, out, abort)
+ }()
+
+ // Even without incoming stream server sends confirmation once all data is received
+ resp, err = l.processIncomingStream(c, in)
+ if err != nil {
+ abort <- true
+ return resp, err
+ }
+
+ err = <-outErr
+ if err != nil {
+ return response{}, err
+ }
+ }
+
+ switch in {
+ case nil:
+ return resp, nil
+ default:
+ return l.processIncomingStream(c, in)
+ }
+}
+
+// processIncomingStream is called once we've successfully sent a request to
+// libvirt. It writes the responses back to the stream passed by the caller
+// until libvirt sends a packet with statusOK or an error.
+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 indicates end of stream
+ if resp.Status == socket.StatusOK {
+ return resp, nil
+ }
+
+ // FIXME: this smells.
+ // StatusError is handled in getResponse, so this must be StatusContinue
+ // StatusContinue is only valid here for stream packets
+ // libvirtd breaks protocol and returns StatusContinue with an
+ // empty response Payload when the stream finishes
+ if len(resp.Payload) == 0 {
+ return resp, nil
+ }
+ if inStream != nil {
+ _, err = inStream.Write(resp.Payload)
+ if err != nil {
+ return response{}, err
+ }
+ }
+ }
+}
+
+func (l *Libvirt) getResponse(c chan response) (response, error) {
+ resp, ok := <-c
+
+ if !ok {
+ // The channel was closed before a response was received. This means
+ // that the socket was unexpectedly closed during the RPC call. In
+ // this case, we must assume the worst, such as libvirt crashed while
+ // attempting to execute the call.
+ return resp, ErrInterrupted
+ }
+
+ if resp.Status == socket.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 {
+ 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
+ }
+
+ if strings.Contains(e.Message, "unknown procedure") {
+ return ErrUnsupported
+ }
+
+ // if libvirt returns ERR_OK, ignore the error
+ if ErrorNumber(e.Code) == ErrOk {
+ return nil
+ }
+
+ return Error{Code: uint32(e.Code), Message: e.Message}
+}
+
+// eventDecoder decodes 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
+}
+
+type typedParamDecoder struct{}
+
+// Decode decodes a TypedParam. These are part of the libvirt spec, and not xdr
+// proper. TypedParams contain a name, which is called Field for some reason,
+// and a Value, which itself has a "discriminant" - an integer enum encoding the
+// actual type, and a value, the length of which varies based on the actual
+// type.
+func (tpd typedParamDecoder) Decode(d *xdr.Decoder, v reflect.Value) (int, error) {
+ // Get the name of the typed param first
+ name, n, err := d.DecodeString()
+ if err != nil {
+ return n, err
+ }
+ val, n2, err := tpd.decodeTypedParamValue(d)
+ n += n2
+ if err != nil {
+ return n, err
+ }
+ tp := &TypedParam{Field: name, Value: *val}
+ v.Set(reflect.ValueOf(*tp))
+
+ return n, nil
+}
+
+// decodeTypedParamValue decodes the Value part of a TypedParam.
+func (typedParamDecoder) decodeTypedParamValue(d *xdr.Decoder) (*TypedParamValue, int, error) {
+ // All TypedParamValues begin with a uint32 discriminant that tells us what
+ // type they are.
+ discriminant, n, err := d.DecodeUint()
+ if err != nil {
+ return nil, n, err
+ }
+ var n2 int
+ var tpv *TypedParamValue
+ switch discriminant {
+ case 1:
+ var val int32
+ n2, err = d.Decode(&val)
+ tpv = &TypedParamValue{D: discriminant, I: val}
+ case 2:
+ var val uint32
+ n2, err = d.Decode(&val)
+ tpv = &TypedParamValue{D: discriminant, I: val}
+ case 3:
+ var val int64
+ n2, err = d.Decode(&val)
+ tpv = &TypedParamValue{D: discriminant, I: val}
+ case 4:
+ var val uint64
+ n2, err = d.Decode(&val)
+ tpv = &TypedParamValue{D: discriminant, I: val}
+ case 5:
+ var val float64
+ n2, err = d.Decode(&val)
+ tpv = &TypedParamValue{D: discriminant, I: val}
+ case 6:
+ var val int32
+ n2, err = d.Decode(&val)
+ tpv = &TypedParamValue{D: discriminant, I: val}
+ case 7:
+ var val string
+ n2, err = d.Decode(&val)
+ tpv = &TypedParamValue{D: discriminant, I: val}
+
+ default:
+ err = fmt.Errorf("invalid parameter type %v", discriminant)
+ }
+ n += n2
+
+ return tpv, n, err
+}
diff --git a/third_party/libvirt/rpc_test.go b/third_party/libvirt/rpc_test.go
new file mode 100644
index 0000000..7016cb2
--- /dev/null
+++ b/third_party/libvirt/rpc_test.go
@@ -0,0 +1,500 @@
+// 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
+
+import (
+ "bytes"
+ "fmt"
+ "sync"
+ "testing"
+
+ "github.com/projecteru2/yavirt/third_party/libvirt/internal/constants"
+ "github.com/projecteru2/yavirt/third_party/libvirt/internal/event"
+ xdr "github.com/projecteru2/yavirt/third_party/libvirt/internal/go-xdr/xdr2"
+ "github.com/projecteru2/yavirt/third_party/libvirt/libvirttest"
+ "github.com/projecteru2/yavirt/third_party/libvirt/socket"
+ "github.com/stretchr/testify/assert"
+)
+
+var (
+ // dc229f87d4de47198cfd2e21c6105b01
+ testUUID = [UUIDBuflen]byte{
+ 0xdc, 0x22, 0x9f, 0x87, 0xd4, 0xde, 0x47, 0x19,
+ 0x8c, 0xfd, 0x2e, 0x21, 0xc6, 0x10, 0x5b, 0x01,
+ }
+
+ testEventHeader = []byte{
+ 0x00, 0x00, 0x00, 0xb0, // length
+ 0x20, 0x00, 0x80, 0x87, // program
+ 0x00, 0x00, 0x00, 0x01, // version
+ 0x00, 0x00, 0x00, 0x06, // procedure
+ 0x00, 0x00, 0x00, 0x01, // type
+ 0x00, 0x00, 0x00, 0x00, // serial
+ 0x00, 0x00, 0x00, 0x00, // status
+ }
+
+ testEvent = []byte{
+ 0x00, 0x00, 0x00, 0x01, // callback id
+
+ // domain name ("test")
+ 0x00, 0x00, 0x00, 0x04, 0x74, 0x65, 0x73, 0x74,
+
+ // uuid (dc229f87d4de47198cfd2e21c6105b01)
+ 0xdc, 0x22, 0x9f, 0x87, 0xd4, 0xde, 0x47, 0x19,
+ 0x8c, 0xfd, 0x2e, 0x21, 0xc6, 0x10, 0x5b, 0x01,
+
+ // domain id (14)
+ 0x00, 0x00, 0x00, 0x0e,
+
+ // event name (BLOCK_JOB_COMPLETED)
+ 0x00, 0x00, 0x00, 0x13, 0x42, 0x4c, 0x4f, 0x43,
+ 0x4b, 0x5f, 0x4a, 0x4f, 0x42, 0x5f, 0x43, 0x4f,
+ 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x00,
+
+ // seconds (1462211891)
+ 0x00, 0x00, 0x00, 0x00, 0x57, 0x27, 0x95, 0x33,
+
+ // microseconds (931791)
+ 0x00, 0x0e, 0x37, 0xcf,
+
+ // event json data
+ // ({"device":"drive-ide0-0-0","len":0,"offset":0,"speed":0,"type":"commit"})
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48,
+ 0x7b, 0x22, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
+ 0x22, 0x3a, 0x22, 0x64, 0x72, 0x69, 0x76, 0x65,
+ 0x2d, 0x69, 0x64, 0x65, 0x30, 0x2d, 0x30, 0x2d,
+ 0x30, 0x22, 0x2c, 0x22, 0x6c, 0x65, 0x6e, 0x22,
+ 0x3a, 0x30, 0x2c, 0x22, 0x6f, 0x66, 0x66, 0x73,
+ 0x65, 0x74, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x73,
+ 0x70, 0x65, 0x65, 0x64, 0x22, 0x3a, 0x30, 0x2c,
+ 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22,
+ 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x22, 0x7d,
+ }
+
+ testLifeCycle = []byte{
+ 0x00, 0x00, 0x00, 0x01, // callback id
+
+ // domain name ("test")
+ 0x00, 0x00, 0x00, 0x04, 0x74, 0x65, 0x73, 0x74,
+
+ // event data
+ 0x00, 0x00, 0x00, 0x50, 0xad, 0xf7, 0x3f, 0xbe, 0xca, 0x48, 0xac, 0x95,
+ 0x13, 0x8a, 0x31, 0xf4, 0xfe, 0x03, 0x2a, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01,
+ }
+
+ testErrorMessage = []byte{
+ 0x00, 0x00, 0x00, 0x37, // code (55, errOperationInvalid)
+ 0x00, 0x00, 0x00, 0x0a, // domain id
+
+ // message ("Requested operation is not valid: domain is not running")
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x37,
+ 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65,
+ 0x64, 0x20, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x6e,
+ 0x6f, 0x74, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64,
+ 0x3a, 0x20, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
+ 0x20, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20,
+ 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x00,
+
+ // error level
+ 0x00, 0x00, 0x00, 0x02,
+ }
+
+ testErrorNotFoundMessage = []byte{
+ 0x00, 0x00, 0x00, 0x2a, // code (42 errDoDmain)
+ 0x00, 0x00, 0x00, 0x0a, // domain id
+
+ // message
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x38,
+ 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x6e,
+ 0x6f, 0x74, 0x20, 0x66, 0x6f, 0x75, 0x6e, 0x64,
+ 0x3a, 0x20, 0x6e, 0x6f, 0x20, 0x64, 0x6f, 0x6d,
+ 0x61, 0x69, 0x6e, 0x20, 0x77, 0x69, 0x74, 0x68,
+ 0x20, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e,
+ 0x67, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x27,
+ 0x74, 0x65, 0x73, 0x74, 0x2d, 0x2d, 0x2d, 0x27,
+ 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
+
+ // error level
+ 0x00, 0x00, 0x00, 0x01,
+ }
+)
+
+func TestDecodeEvent(t *testing.T) {
+ var e DomainEvent
+ err := eventDecoder(testEvent, &e)
+ if err != nil {
+ t.Error(err)
+ }
+
+ expCbID := int32(1)
+ if e.CallbackID != expCbID {
+ t.Errorf("expected callback id %d, got %d", expCbID, e.CallbackID)
+ }
+
+ expName := "test"
+ if e.Domain.Name != expName {
+ t.Errorf("expected domain %s, got %s", expName, e.Domain.Name)
+ }
+
+ expUUID := testUUID
+ if !bytes.Equal(e.Domain.UUID[:], expUUID[:]) {
+ t.Errorf("expected uuid:\t%x, got\n\t\t\t%x", expUUID, e.Domain.UUID)
+ }
+
+ expID := int32(14)
+ if e.Domain.ID != expID {
+ t.Errorf("expected id %d, got %d", expID, e.Domain.ID)
+ }
+
+ expEvent := "BLOCK_JOB_COMPLETED"
+ if e.Event != expEvent {
+ t.Errorf("expected %s, got %s", expEvent, e.Event)
+ }
+
+ expSec := uint64(1462211891)
+ if e.Seconds != expSec {
+ t.Errorf("expected seconds to be %d, got %d", expSec, e.Seconds)
+ }
+
+ expMs := uint32(931791)
+ if e.Microseconds != expMs {
+ t.Errorf("expected microseconds to be %d, got %d", expMs, e.Microseconds)
+ }
+
+ expDetails := []byte(`{"device":"drive-ide0-0-0","len":0,"offset":0,"speed":0,"type":"commit"}`)
+ if e.Domain.ID != expID {
+ t.Errorf("expected data %s, got %s", expDetails, e.Details)
+ }
+}
+
+func TestDecodeError(t *testing.T) {
+ expectedMsg := "Requested operation is not valid: domain is not running"
+ expectedCode := ErrOperationInvalid
+
+ err := decodeError(testErrorMessage)
+ e := err.(Error)
+ if e.Message != expectedMsg {
+ t.Errorf("expected error message %s, got %s", expectedMsg, err.Error())
+ }
+ if e.Code != uint32(expectedCode) {
+ t.Errorf("expected code %d, got %d", expectedCode, e.Code)
+ }
+}
+
+func TestErrNotFound(t *testing.T) {
+ err := decodeError(testErrorNotFoundMessage)
+ ok := IsNotFound(err)
+ if !ok {
+ t.Errorf("expected true, got %t", ok)
+ }
+
+ err = fmt.Errorf("something went wrong: %w", err)
+ ok = IsNotFound(err)
+ if !ok {
+ t.Errorf("expected true, got %t", ok)
+ }
+}
+
+func TestEncode(t *testing.T) {
+ data := "test"
+ buf, err := encode(data)
+ if err != nil {
+ t.Error(err)
+ }
+
+ dec := xdr.NewDecoder(bytes.NewReader(buf))
+ res, _, err := dec.DecodeString()
+ if err != nil {
+ t.Error(err)
+ }
+
+ if res != data {
+ t.Errorf("expected %s, got %s", data, res)
+ }
+}
+
+func TestRegister(t *testing.T) {
+ l := &Libvirt{}
+ l.callbacks = make(map[int32]chan response)
+ id := int32(1)
+ c := make(chan response)
+
+ l.register(id, c)
+ if _, ok := l.callbacks[id]; !ok {
+ t.Error("expected callback to register")
+ }
+}
+
+func TestDeregister(t *testing.T) {
+ id := int32(1)
+
+ l := &Libvirt{}
+ l.callbacks = map[int32]chan response{
+ id: make(chan response),
+ }
+
+ l.deregister(id)
+ if _, ok := l.callbacks[id]; ok {
+ t.Error("expected callback to deregister")
+ }
+}
+
+func TestAddStream(t *testing.T) {
+ id := int32(1)
+
+ l := &Libvirt{}
+ l.events = make(map[int32]*event.Stream)
+
+ stream := event.NewStream(0, id)
+ defer stream.Shutdown()
+
+ l.addStream(stream)
+ if _, ok := l.events[id]; !ok {
+ t.Error("expected event stream to exist")
+ }
+}
+
+func TestRemoveStream(t *testing.T) {
+ id := int32(1)
+
+ dialer := libvirttest.New()
+ l := NewWithDialer(dialer)
+
+ err := l.Connect()
+ if err != nil {
+ t.Fatalf("connect failed: %v", err)
+ }
+ defer l.Disconnect()
+
+ stream := event.NewStream(constants.QEMUProgram, id)
+ defer stream.Shutdown()
+
+ l.addStream(stream)
+
+ fmt.Println("removing stream")
+ err = l.removeStream(id)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if _, ok := l.events[id]; ok {
+ t.Error("expected event stream to be removed")
+ }
+}
+
+func TestRemoveAllStreams(t *testing.T) {
+ id1 := int32(1)
+ id2 := int32(2)
+
+ dialer := libvirttest.New()
+ l := NewWithDialer(dialer)
+
+ err := l.Connect()
+ if err != nil {
+ t.Fatalf("connect failed: %v", err)
+ }
+ defer l.Disconnect()
+
+ // verify it's a successful no-op when no streams have been added
+ l.removeAllStreams()
+ if len(l.events) != 0 {
+ t.Fatal("expected no streams after remove all")
+ }
+
+ stream := event.NewStream(constants.QEMUProgram, id1)
+ defer stream.Shutdown()
+
+ l.addStream(stream)
+
+ stream2 := event.NewStream(constants.QEMUProgram, id2)
+ defer stream2.Shutdown()
+
+ l.addStream(stream2)
+
+ l.removeAllStreams()
+
+ if len(l.events) != 0 {
+ t.Error("expected all event streams to be removed")
+ }
+}
+
+func TestStream(t *testing.T) {
+ id := int32(1)
+ stream := event.NewStream(constants.Program, 1)
+ defer stream.Shutdown()
+
+ l := &Libvirt{}
+ l.events = map[int32]*event.Stream{
+ id: stream,
+ }
+
+ var streamEvent DomainEvent
+ err := eventDecoder(testEvent, &streamEvent)
+ if err != nil { // event was malformed, drop.
+ t.Error(err)
+ }
+
+ l.stream(streamEvent)
+ e := <-stream.Recv()
+
+ if e.(DomainEvent).Event != "BLOCK_JOB_COMPLETED" {
+ t.Error("expected event")
+ }
+}
+
+func TestSerial(t *testing.T) {
+ count := int32(10)
+ l := &Libvirt{}
+
+ var wg sync.WaitGroup
+ for i := 0; i < 10; i++ {
+ wg.Add(1)
+ go func() {
+ l.serial()
+ wg.Done()
+ }()
+ }
+
+ wg.Wait()
+
+ expected := count + int32(1)
+ actual := l.serial()
+ if expected != actual {
+ t.Errorf("expected serial to be %d, got %d", expected, actual)
+ }
+}
+
+func TestLookup(t *testing.T) {
+ name := "test"
+
+ dialer := libvirttest.New()
+ l := NewWithDialer(dialer)
+
+ err := l.Connect()
+ if err != nil {
+ t.Fatalf("connect failed: %v", err)
+ }
+ defer l.Disconnect()
+
+ d, err := l.lookup(name)
+ if err != nil {
+ t.Error(err)
+ }
+
+ if d.Name != name {
+ t.Errorf("expected domain %s, got %s", name, d.Name)
+ }
+}
+
+func TestDeregisterAll(t *testing.T) {
+ dialer := libvirttest.New()
+ c1 := make(chan response)
+ c2 := make(chan response)
+ l := NewWithDialer(dialer)
+ if len(l.callbacks) != 0 {
+ t.Error("expected callback map to be empty at test start")
+ }
+ l.register(1, c1)
+ l.register(2, c2)
+ if len(l.callbacks) != 2 {
+ t.Error("expected callback map to have 2 entries after inserts")
+ }
+ l.deregisterAll()
+ if len(l.callbacks) != 0 {
+ t.Error("expected callback map to be empty after deregisterAll")
+ }
+}
+
+// TestRouteDeadlock ensures that go-libvirt doesn't hang when trying to send
+// both an event and a response (to a request) at the same time.
+//
+// Events are inherently asynchronous - the client may not be ready to receive
+// an event when it arrives. We don't want that to prevent go-libvirt from
+// continuing to receive responses to outstanding requests. This test checks for
+// deadlocks where the client doesn't immediately consume incoming events.
+func TestRouteDeadlock(t *testing.T) {
+ id := int32(1)
+ rch := make(chan response, 1)
+
+ l := &Libvirt{
+ callbacks: map[int32]chan response{
+ id: rch,
+ },
+ events: make(map[int32]*event.Stream),
+ }
+ stream := event.NewStream(constants.Program, id)
+
+ l.addStream(stream)
+
+ respHeader := &socket.Header{
+ Program: constants.Program,
+ Serial: id,
+ Status: socket.StatusOK,
+ }
+ eventHeader := &socket.Header{
+ Program: constants.Program,
+ Procedure: constants.ProcDomainEventCallbackLifecycle,
+ Status: socket.StatusOK,
+ }
+
+ send := func(respCount, evCount int) {
+ // Send the events first
+ for i := 0; i < evCount; i++ {
+ l.Route(eventHeader, testLifeCycle)
+ }
+ // Now send the requests.
+ for i := 0; i < respCount; i++ {
+ l.Route(respHeader, []byte{})
+ }
+ }
+
+ cases := []struct{ rCount, eCount int }{
+ {2, 0},
+ {0, 2},
+ {1, 1},
+ {2, 2},
+ {50, 50},
+ }
+
+ for _, tc := range cases {
+ fmt.Printf("testing %d responses and %d events\n", tc.rCount, tc.eCount)
+ go send(tc.rCount, tc.eCount)
+
+ for i := 0; i < tc.rCount; i++ {
+ r := <-rch
+ assert.Equal(t, r.Status, uint32(socket.StatusOK))
+ }
+ for i := 0; i < tc.eCount; i++ {
+ e := <-stream.Recv()
+ fmt.Printf("event %v/%v received\n", i, len(cases))
+ assert.Equal(t, "test", e.(*DomainEventCallbackLifecycleMsg).Msg.Dom.Name)
+ }
+ }
+
+ // finally verify that canceling the context doesn't cause a deadlock.
+ fmt.Println("checking for deadlock after context cancellation")
+ send(0, 50)
+}
+
+func TestGetResponseInterrupted(t *testing.T) {
+ dialer := libvirttest.New()
+ l := NewWithDialer(dialer)
+ c := make(chan response)
+ close(c)
+ _, err := l.getResponse(c)
+ assert.Equal(t, ErrInterrupted, err)
+}
diff --git a/third_party/libvirt/scripts/gen-consts.sh b/third_party/libvirt/scripts/gen-consts.sh
new file mode 100755
index 0000000..c488058
--- /dev/null
+++ b/third_party/libvirt/scripts/gen-consts.sh
@@ -0,0 +1,42 @@
+#!/bin/bash
+#
+# This runs the first code generator used by go-libvirt: c-for-go. This script
+# is run from the 'go generate ./...' command, and only needs to be run when
+# changing to a different version of libvirt.
+if [ -z "${LIBVIRT_SOURCE}" ]; then
+ echo "Set LIBVIRT_SOURCE to the root of the libvirt sources you want to use first."
+ exit 1
+fi
+
+# Make sure c-for-go is installed
+if ! which c-for-go > /dev/null; then
+ echo "c-for-go not found. Attempting to install it..."
+ if ! go get github.com/xlab/c-for-go/...; then
+ echo "failed to install c-for-go. Please install it manually from https://github.com/xlab/c-for-go"
+ exit 1
+ fi
+fi
+
+# Make sure goyacc is installed (needed for the lvgen/ generator)
+if ! which goyacc > /dev/null; then
+ echo "goyacc not found. Attempting to install it..."
+ if ! go get golang.org/x/tools/cmd/goyacc/...; then
+ echo "failed to install goyacc. Please install it manually from https://golang.org/x/tools/cmd/goyacc"
+ exit 1
+ fi
+fi
+
+# Set DIR to the absolute path to the scripts/ directory.
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+
+# Temporarily symlink the libvirt sources to a subdirectory because c-for-go
+# lacks a mechanism for us to pass it a search path for header files.
+LVDIR=lv_source
+ln -sF ${LIBVIRT_SOURCE} ${LVDIR}
+if ! c-for-go -nostamp -nocgo -ccincl libvirt.yml; then
+ echo "c-for-go failed"
+ exit 1
+fi
+mv libvirt/const.go ${DIR}/../const.gen.go
+rm ${LVDIR}
+rm -rf libvirt/
diff --git a/third_party/libvirt/scripts/licensecheck.sh b/third_party/libvirt/scripts/licensecheck.sh
new file mode 100755
index 0000000..b3f0f77
--- /dev/null
+++ b/third_party/libvirt/scripts/licensecheck.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+# Verify that the correct license block is present in all Go source
+# files.
+read -r -d '' EXPECTED < 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
+ }
+ }
+}
diff --git a/third_party/libvirt/socket/socket_test.go b/third_party/libvirt/socket/socket_test.go
new file mode 100644
index 0000000..e7d96d0
--- /dev/null
+++ b/third_party/libvirt/socket/socket_test.go
@@ -0,0 +1,60 @@
+package socket
+
+import (
+ "bytes"
+ "testing"
+
+ "github.com/projecteru2/yavirt/third_party/libvirt/internal/constants"
+)
+
+var testHeader = []byte{
+ 0x20, 0x00, 0x80, 0x86, // program
+ 0x00, 0x00, 0x00, 0x01, // version
+ 0x00, 0x00, 0x00, 0x01, // procedure
+ 0x00, 0x00, 0x00, 0x00, // type
+ 0x00, 0x00, 0x00, 0x00, // serial
+ 0x00, 0x00, 0x00, 0x00, // status
+}
+
+func TestPktLen(t *testing.T) {
+ data := []byte{0x00, 0x00, 0x00, 0xa} // uint32:10
+ r := bytes.NewBuffer(data)
+
+ expected := uint32(10)
+ actual, err := pktlen(r)
+ if err != nil {
+ t.Error(err)
+ }
+
+ if expected != actual {
+ t.Errorf("expected packet length %q, got %q", expected, actual)
+ }
+}
+
+func TestExtractHeader(t *testing.T) {
+ r := bytes.NewBuffer(testHeader)
+ h, err := extractHeader(r)
+ if err != nil {
+ t.Error(err)
+ }
+
+ if h.Program != constants.Program {
+ t.Errorf("expected Program %q, got %q", constants.Program, h.Program)
+ }
+
+ if h.Version != constants.ProtocolVersion {
+ t.Errorf("expected version %q, got %q", constants.ProtocolVersion, h.Version)
+ }
+
+ if h.Procedure != constants.ProcConnectOpen {
+ t.Errorf("expected procedure %q, got %q", constants.ProcConnectOpen, h.Procedure)
+ }
+
+ if h.Type != Call {
+ t.Errorf("expected type %q, got %q", Call, h.Type)
+ }
+
+ if h.Status != StatusOK {
+ t.Errorf("expected status %q, got %q", StatusOK, h.Status)
+ }
+}
diff --git a/third_party/libvirt/socket/units.go b/third_party/libvirt/socket/units.go
new file mode 100644
index 0000000..1ad2c01
--- /dev/null
+++ b/third_party/libvirt/socket/units.go
@@ -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 socket
+
+const (
+ // B - byte
+ B = 1
+ // KiB - kibibyte
+ KiB = 1024 * B
+ // MiB - mebibyte
+ MiB = 1024 * KiB
+)
diff --git a/third_party/libvirt/testdata/test-domain.xml b/third_party/libvirt/testdata/test-domain.xml
new file mode 100644
index 0000000..ac0629e
--- /dev/null
+++ b/third_party/libvirt/testdata/test-domain.xml
@@ -0,0 +1,38 @@
+
+
+ test
+ 1024
+ 1024
+ afc2ef71-66e0-45a7-a5ec-d8ba1ea8177d
+
+ hvm
+
+
+
+
+
+
+ destroy
+ restart
+ restart
+ 1
+
+ /usr/bin/qemu-system-x86_64
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/third_party/libvirt/testdata/test-pool.xml b/third_party/libvirt/testdata/test-pool.xml
new file mode 100644
index 0000000..6bc47e7
--- /dev/null
+++ b/third_party/libvirt/testdata/test-pool.xml
@@ -0,0 +1,7 @@
+
+
+ test
+
+ /tmp
+
+
diff --git a/third_party/libvirt/testdata/test-secret.xml b/third_party/libvirt/testdata/test-secret.xml
new file mode 100644
index 0000000..bfe53a3
--- /dev/null
+++ b/third_party/libvirt/testdata/test-secret.xml
@@ -0,0 +1,7 @@
+
+ test
+ 19fdc2f2-fa64-46f3-bacf-42a8aafca6dd
+
+ /tmp
+
+
diff --git a/tools/hardware.py b/tools/hardware.py
new file mode 100644
index 0000000..f3c4eee
--- /dev/null
+++ b/tools/hardware.py
@@ -0,0 +1,57 @@
+import subprocess
+import json
+
+
+def run_lshw(cls=""):
+ cmd = "lshw -quiet -json"
+ if cls != "":
+ cmd += f" -C {cls}"
+ out = subprocess.run(cmd, shell=True, text=True,
+ stdout=subprocess.PIPE).stdout
+ return json.loads(out)
+
+
+def fetch_gpu_info():
+ items = run_lshw("display")
+ res = []
+ for item in items:
+ d = {
+ "address": item["businfo"].split("@")[1],
+ "product": item["product"],
+ "vendor": item["vendor"],
+ }
+ res.append(d)
+ return res
+
+
+def fetch_cpuinfo():
+ items = run_lshw("processor")
+ res = []
+ for item in items:
+ d = {
+ "address": item["businfo"].split("@")[1],
+ }
+ res.append(d)
+ return res
+
+
+def add_gpu_resource_to_eru(hostname):
+ gpus = fetch_gpu_info()
+ cmd_extra_args = {
+ "gpu": {
+ "gpu_map": {g["address"]: g for g in gpus},
+ }
+ }
+ cmd = f"/usr/local/bin/eru-cli node set --cpu 72 --memory 62G --storage 62G --extra-resources '{json.dumps(cmd_extra_args)}'"
+ print(cmd)
+
+ out = subprocess.run(cmd, shell=True, text=True,
+ stdout=subprocess.PIPE).stdout
+ print(out)
+
+
+if __name__ == "__main__":
+ # run_lshw()
+ # print(run_lshw())
+ # print(fetch_gpu_info())
+ add_gpu_resource_to_eru("192-168-68-14")
diff --git a/tools/qmp.py b/tools/qmp.py
new file mode 100644
index 0000000..a46bb49
--- /dev/null
+++ b/tools/qmp.py
@@ -0,0 +1,62 @@
+import sys
+import subprocess
+import json
+import time
+import base64
+from collections import namedtuple
+
+
+def parse_args():
+ Args = namedtuple('Args', ['domain', 'cmds'])
+
+ for i in range(len(sys.argv)):
+ if sys.argv[i] == "--domain":
+ domain = sys.argv[i+1]
+ cmds = sys.argv[i+2:]
+ return Args(domain, cmds)
+
+
+def run_qmp_cmd(domain, qmp_cmd):
+ cmd = ["virsh", "qemu-agent-command",
+ "--domain", domain, json.dumps(qmp_cmd)]
+ out = subprocess.run(cmd, capture_output=True, text=True).stdout
+
+ return json.loads(out)
+
+
+if __name__ == "__main__":
+ args = parse_args()
+ if args is None or len(args.cmds) == 0:
+ print("invalid domain or args")
+ sys.exit(-1)
+
+ qmp_cmd = {
+ "execute": "guest-exec",
+ "arguments": {
+ "path": args.cmds[0],
+ "arg": args.cmds[1:],
+ "capture-output": True
+ }
+ }
+ res = run_qmp_cmd(args.domain, qmp_cmd)
+ pid = res["return"]["pid"]
+
+ qmp_cmd = {
+ "execute": "guest-exec-status",
+ "arguments": {"pid": pid}
+ }
+ n = 180
+ exited = False
+ while (not exited) and n > 0:
+ time.sleep(2)
+ res = run_qmp_cmd(args.domain, qmp_cmd)
+ exited = res["return"]["exited"]
+ n -= 1
+
+ exitcode = res["return"]["exitcode"]
+ if exitcode != 0:
+ err_data = res["return"]["err-data"]
+ print(base64.b64decode(err_data).decode('utf-8'))
+ sys.exit(-1)
+ out_data = res["return"]["out-data"]
+ print(base64.b64decode(out_data).decode('utf-8'))
diff --git a/yavirtd.go b/yavirtd.go
index 63f587b..c16f556 100644
--- a/yavirtd.go
+++ b/yavirtd.go
@@ -1,6 +1,7 @@
package main
import (
+ "context"
"fmt"
"net/http"
_ "net/http/pprof" //nolint
@@ -8,31 +9,29 @@ import (
"os/signal"
"runtime"
"strings"
- "sync"
"syscall"
"time"
- cli "github.com/urfave/cli/v2"
-
+ "github.com/cockroachdb/errors"
+ "github.com/projecteru2/core/log"
+ coretypes "github.com/projecteru2/core/types"
"github.com/projecteru2/yavirt/configs"
+ "github.com/projecteru2/yavirt/internal/debug"
"github.com/projecteru2/yavirt/internal/metrics"
- "github.com/projecteru2/yavirt/internal/models"
- "github.com/projecteru2/yavirt/internal/server"
- grpcserver "github.com/projecteru2/yavirt/internal/server/grpc"
- httpserver "github.com/projecteru2/yavirt/internal/server/http"
+ grpcserver "github.com/projecteru2/yavirt/internal/rpc"
+ "github.com/projecteru2/yavirt/internal/service/boar"
+ "github.com/projecteru2/yavirt/internal/utils"
"github.com/projecteru2/yavirt/internal/ver"
"github.com/projecteru2/yavirt/internal/virt"
- "github.com/projecteru2/yavirt/internal/virt/guest"
- "github.com/projecteru2/yavirt/pkg/errors"
- "github.com/projecteru2/yavirt/pkg/idgen"
- "github.com/projecteru2/yavirt/pkg/log"
- "github.com/projecteru2/yavirt/pkg/store"
+ zerolog "github.com/rs/zerolog/log"
+ cli "github.com/urfave/cli/v2"
)
func main() {
runtime.GOMAXPROCS(runtime.NumCPU() * 2)
+ utils.EnforceRoot()
- cli.VersionPrinter = func(c *cli.Context) {
+ cli.VersionPrinter = func(_ *cli.Context) {
fmt.Println(ver.Version())
}
@@ -49,7 +48,7 @@ func main() {
},
&cli.StringFlag{
Name: "log-level",
- Value: "INFO",
+ Value: "",
Usage: "set log level",
EnvVars: []string{"ERU_YAVIRT_LOG_LEVEL"},
},
@@ -82,194 +81,102 @@ func main() {
}
if err := app.Run(os.Args); err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
+ log.Error(context.TODO(), err, "run failed")
os.Exit(1)
}
os.Exit(0)
}
+
func initConfig(c *cli.Context) error {
cfg := &configs.Conf
- if err := cfg.Load([]string{c.String("config")}); err != nil {
+ if err := cfg.Load(c.String("config")); err != nil {
return err
}
return cfg.Prepare(c)
}
+func startHTTPServer(cfg *configs.Config) {
+ http.Handle("/metrics", metrics.Handler())
+ http.HandleFunc("/debug", debug.Handler)
+ server := &http.Server{
+ Addr: cfg.BindHTTPAddr,
+ ReadHeaderTimeout: 5 * time.Second,
+ }
+ if err := server.ListenAndServe(); err != nil {
+ log.Errorf(context.TODO(), err, "start http failed")
+ }
+}
+
// Run .
func Run(c *cli.Context) error {
if err := initConfig(c); err != nil {
+ zerolog.Fatal().Err(err).Msg("invalid config")
return err
}
- defers, svc, err := setup()
- if err != nil {
- return errors.Trace(err)
+ svcLog := &coretypes.ServerLogConfig{
+ Level: configs.Conf.Log.Level,
+ UseJSON: configs.Conf.Log.UseJSON,
+ Filename: configs.Conf.Log.Filename,
+ MaxSize: configs.Conf.Log.MaxSize,
+ MaxAge: configs.Conf.Log.MaxAge,
+ MaxBackups: configs.Conf.Log.MaxBackups,
}
- defer defers()
- defer store.Close()
-
+ if err := log.SetupLog(c.Context, svcLog, configs.Conf.Log.SentryDSN); err != nil {
+ zerolog.Fatal().Err(err).Msg("failed to setup log")
+ return err
+ }
+ // log config
dump, err := configs.Conf.Dump()
if err != nil {
- return errors.Trace(err)
+ log.Error(c.Context, err, "failed to dump config")
+ return errors.Wrap(err, "")
}
- log.Infof("%s", dump)
+ log.Infof(c.Context, "%s", dump)
- if err := virt.Cleanup(); err != nil {
- return errors.Trace(err)
- }
+ // wait for unix signals and try to GracefulStop
+ ctx, cancel := signal.NotifyContext(c.Context, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
+ defer cancel()
- // setup epoller
- if err := guest.SetupEpoller(); err != nil {
- return errors.Trace(err)
+ br, err := boar.New(ctx, &configs.Conf, nil)
+ if err != nil {
+ return err
}
- defer guest.GetCurrentEpoller().Close()
+ defer br.Close()
- grpcSrv, err := grpcserver.Listen(svc)
- if err != nil {
- return errors.Trace(err)
+ if err := virt.Cleanup(); err != nil {
+ return errors.Wrap(err, "")
}
- httpSrv, err := httpserver.Listen(svc)
+ quit := make(chan struct{})
+ grpcSrv, err := grpcserver.New(&configs.Conf, br, quit)
if err != nil {
- return errors.Trace(err)
+ return err
}
+ errExitCh := make(chan struct{})
go prof(configs.Conf.ProfHTTPPort)
-
- run([]server.Serverable{grpcSrv, httpSrv})
-
- return nil
-}
-
-func run(servers []server.Serverable) {
- defer log.Warnf("[main] yavirtd proc exit")
-
- var wg sync.WaitGroup
- for _, srv := range servers {
- wg.Add(1)
-
- go handleSigns(srv)
-
- go func(server server.Serverable) {
- defer wg.Done()
- if err := server.Serve(); err != nil {
- log.ErrorStack(err)
- metrics.IncrError()
- }
- }(srv)
- }
-
- log.Infof("[main] all servers're running")
-
- go notify(servers)
-
- wg.Wait()
-}
-
-func notify(servers []server.Serverable) {
- defer log.Infof("[main] exit notify loop exit")
-
- var wg sync.WaitGroup
-
- for _, srv := range servers {
- wg.Add(1)
-
- go func(exitCh <-chan struct{}) {
- defer func() {
- log.Infof("[main] server exitCh %p monitor was stopped", exitCh)
- wg.Done()
- }()
-
- select {
- case <-exitCh:
- log.Infof("[main] recv from server exit ch %p", exitCh)
- closeExitNoti()
-
- case <-exitNoti:
- log.Infof("[main] recv exit notification: %p", exitCh)
- }
- }(srv.ExitCh())
- }
-
- wg.Wait()
-}
-
-func setup() (deferSentry func(), svc *server.Service, err error) {
- if deferSentry, err = log.Setup(configs.Conf.LogLevel, configs.Conf.LogFile, configs.Conf.LogSentry); err != nil {
- return
- }
-
- if err = store.Setup(configs.Conf.MetaType); err != nil {
- return
- }
-
- if svc, err = server.SetupYavirtdService(); err != nil {
- return
- }
-
- idgen.Setup(svc.Host.ID, time.Now())
-
- models.Setup()
-
- return
-}
-
-var signs = []os.Signal{
- syscall.SIGHUP,
- syscall.SIGINT,
- syscall.SIGTERM,
- syscall.SIGQUIT,
- syscall.SIGUSR2,
-}
-
-func handleSigns(srv server.Serverable) {
- defer func() {
- log.Warnf("[main] signal handler for %p exit", srv)
- srv.Close()
+ go startHTTPServer(&configs.Conf)
+ go func() {
+ defer close(errExitCh)
+ if err := grpcSrv.Serve(); err != nil {
+ log.Errorf(c.Context, err, "failed to start grpc server")
+ metrics.IncrError()
+ }
}()
+ log.Infof(c.Context, "[main] all servers are running")
- var signCh = make(chan os.Signal, 1)
- signal.Notify(signCh, signs...)
-
- var exit = srv.ExitCh()
-
- for {
- select {
- case sign := <-signCh:
- switch sign {
- case syscall.SIGUSR2:
- log.Warnf("[main] got sign USR2 to reload")
- log.ErrorStack(srv.Reload())
-
- case syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT:
- log.Warnf("[main] got sign %d to exit", sign)
- return
-
- default:
- log.Warnf("[main] got sign %d to ignore", sign)
- }
-
- case <-exitNoti:
- log.Warnf("[main] recv an exit notification: %p", srv)
- return
-
- case <-exit:
- log.Warnf("[main] recv from server %p exit ch", srv)
- return
- }
+ select {
+ case <-ctx.Done():
+ log.Infof(c.Context, "[main] interrupt by signal")
+ case <-errExitCh:
+ log.Warnf(c.Context, "[main] server exit abnormally.")
}
-}
+ close(quit)
-var (
- exitNoti = make(chan struct{}, 1)
- exitNotiOnce sync.Once
-)
+ grpcSrv.Stop(false)
-func closeExitNoti() {
- exitNotiOnce.Do(func() {
- close(exitNoti)
- })
+ return nil
}
func prof(port int) {