diff --git a/.travis.yml b/.travis.yml index ee980de..f2b7967 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,9 +35,11 @@ install: before_script: - go get -d ./... + - sudo qemu-img create -f raw -o size=10M /var/lib/libvirt/images/test.raw + - sudo virsh define ./test-domain.xml + - sudo virsh start test script: - - virsh list - ./scripts/licensecheck.sh - go build ./... - golint -set_exit_status ./... diff --git a/internal/constants/constants.go b/internal/constants/constants.go index 13bd18b..5c9532d 100644 --- a/internal/constants/constants.go +++ b/internal/constants/constants.go @@ -38,6 +38,7 @@ const ( const ( ProcConnectOpen = 1 ProcConnectClose = 2 + ProcDomainGetXMLDesc = 14 ProcDomainLookupByName = 23 ProcAuthList = 66 ProcConnectGetLibVersion = 157 diff --git a/libvirt.go b/libvirt.go index c3833e7..784c1bc 100644 --- a/libvirt.go +++ b/libvirt.go @@ -78,6 +78,23 @@ type qemuError struct { } `json:"error"` } +// DomainXMLFlags specifies options for dumping a domain's XML. +type DomainXMLFlags uint32 + +const ( + // DomainXMLFlagSecure dumps XML with sensitive information included. + DomainXMLFlagSecure DomainXMLFlags = 1 << iota + + // DomainXMLFlagInactive dumps XML with inactive domain information. + DomainXMLFlagInactive + + // DomainXMLFlagUpdateCPU dumps XML with guest CPU requirements according to the host CPU. + DomainXMLFlagUpdateCPU + + // DomainXMLFlagMigratable dumps XML suitable for migration. + DomainXMLFlagMigratable +) + // MigrateFlags specifies options when performing a migration. type MigrateFlags uint32 @@ -496,6 +513,47 @@ func (l *Libvirt) Destroy(dom string, flags DestroyFlags) error { return nil } +// XML returns a domain's raw XML definition, akin to `virsh dumpxml `. +// See DomainXMLFlag* for optional flags. +func (l *Libvirt) XML(dom string, flags DomainXMLFlags) ([]byte, error) { + d, err := l.lookup(dom) + if err != nil { + return nil, err + } + + payload := struct { + Domain Domain + Flags DomainXMLFlags + }{ + Domain: *d, + Flags: flags, + } + + buf, err := encode(&payload) + if err != nil { + return nil, err + } + + resp, err := l.request(constants.ProcDomainGetXMLDesc, constants.ProgramRemote, &buf) + if err != nil { + return nil, err + } + + r := <-resp + if r.Status != StatusOK { + return nil, decodeError(r.Payload) + } + + pl := bytes.NewReader(r.Payload) + dec := xdr.NewDecoder(pl) + s, _, err := dec.DecodeString() + if err != nil { + return nil, err + } + + return []byte(s), nil +} + // Version returns the version of the libvirt daemon. func (l *Libvirt) Version() (string, error) { resp, err := l.request(constants.ProcConnectGetLibVersion, constants.ProgramRemote, nil) diff --git a/libvirt_integration_test.go b/libvirt_integration_test.go index 9b6c6a1..c1ce894 100644 --- a/libvirt_integration_test.go +++ b/libvirt_integration_test.go @@ -17,6 +17,7 @@ package libvirt import ( + "encoding/xml" "net" "testing" "time" @@ -40,6 +41,26 @@ func TestDisconnectIntegration(t *testing.T) { } } +func TestXMLIntegration(t *testing.T) { + l := New(testConn(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 testConn(t *testing.T) net.Conn { conn, err := net.DialTimeout("tcp", testAddr, time.Second*2) if err != nil { diff --git a/test-domain.xml b/test-domain.xml new file mode 100644 index 0000000..ac0629e --- /dev/null +++ b/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 + + + + + + + + + + + + + + + +