Adds support for dumping domain XML
This adds support for dumping a domain's XML definition, akin to `virsh dumpxml <domain>`. The returned data is quite large so I've included an integration test rather than adding a huge blob of hex to `libvirttest`.
This commit is contained in:
		| @@ -35,9 +35,11 @@ install: | |||||||
|  |  | ||||||
| before_script: | before_script: | ||||||
|   - go get -d ./... |   - 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: | script: | ||||||
|   - virsh list |  | ||||||
|   - ./scripts/licensecheck.sh |   - ./scripts/licensecheck.sh | ||||||
|   - go build ./... |   - go build ./... | ||||||
|   - golint -set_exit_status ./... |   - golint -set_exit_status ./... | ||||||
|   | |||||||
| @@ -38,6 +38,7 @@ const ( | |||||||
| const ( | const ( | ||||||
| 	ProcConnectOpen              = 1 | 	ProcConnectOpen              = 1 | ||||||
| 	ProcConnectClose             = 2 | 	ProcConnectClose             = 2 | ||||||
|  | 	ProcDomainGetXMLDesc         = 14 | ||||||
| 	ProcDomainLookupByName       = 23 | 	ProcDomainLookupByName       = 23 | ||||||
| 	ProcAuthList                 = 66 | 	ProcAuthList                 = 66 | ||||||
| 	ProcConnectGetLibVersion     = 157 | 	ProcConnectGetLibVersion     = 157 | ||||||
|   | |||||||
							
								
								
									
										58
									
								
								libvirt.go
									
									
									
									
									
								
							
							
						
						
									
										58
									
								
								libvirt.go
									
									
									
									
									
								
							| @@ -78,6 +78,23 @@ type qemuError struct { | |||||||
| 	} `json:"error"` | 	} `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. | // MigrateFlags specifies options when performing a migration. | ||||||
| type MigrateFlags uint32 | type MigrateFlags uint32 | ||||||
|  |  | ||||||
| @@ -496,6 +513,47 @@ func (l *Libvirt) Destroy(dom string, flags DestroyFlags) error { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // XML returns a domain's raw XML definition, akin to `virsh dumpxml <domain>`. | ||||||
|  | // 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. | // Version returns the version of the libvirt daemon. | ||||||
| func (l *Libvirt) Version() (string, error) { | func (l *Libvirt) Version() (string, error) { | ||||||
| 	resp, err := l.request(constants.ProcConnectGetLibVersion, constants.ProgramRemote, nil) | 	resp, err := l.request(constants.ProcConnectGetLibVersion, constants.ProgramRemote, nil) | ||||||
|   | |||||||
| @@ -17,6 +17,7 @@ | |||||||
| package libvirt | package libvirt | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"encoding/xml" | ||||||
| 	"net" | 	"net" | ||||||
| 	"testing" | 	"testing" | ||||||
| 	"time" | 	"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 { | func testConn(t *testing.T) net.Conn { | ||||||
| 	conn, err := net.DialTimeout("tcp", testAddr, time.Second*2) | 	conn, err := net.DialTimeout("tcp", testAddr, time.Second*2) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|   | |||||||
							
								
								
									
										38
									
								
								test-domain.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								test-domain.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | |||||||
|  | <!-- simple integration test domain for go-libvirt --> | ||||||
|  | <domain type="qemu"> | ||||||
|  |   <name>test</name> | ||||||
|  |   <currentMemory>1024</currentMemory> | ||||||
|  |   <memory>1024</memory> | ||||||
|  |   <uuid>afc2ef71-66e0-45a7-a5ec-d8ba1ea8177d</uuid> | ||||||
|  |   <os> | ||||||
|  |     <type arch='x86_64'>hvm</type> | ||||||
|  |     <boot dev='hd'/> | ||||||
|  |   </os> | ||||||
|  |   <features> | ||||||
|  |     <acpi/><apic/><pae/> | ||||||
|  |   </features> | ||||||
|  |   <clock offset="utc"/> | ||||||
|  |   <on_poweroff>destroy</on_poweroff> | ||||||
|  |   <on_reboot>restart</on_reboot> | ||||||
|  |   <on_crash>restart</on_crash> | ||||||
|  |   <vcpu>1</vcpu> | ||||||
|  |   <devices> | ||||||
|  |     <emulator>/usr/bin/qemu-system-x86_64</emulator> | ||||||
|  |     <disk type='file' device='disk'> | ||||||
|  |       <driver name='qemu' type='raw'/> | ||||||
|  |       <source file='/var/lib/libvirt/images/test.raw'/> | ||||||
|  |       <target dev='vda' bus='virtio'/> | ||||||
|  |     </disk> | ||||||
|  |     <disk type='block' device='cdrom'> | ||||||
|  |       <target dev='hdc' bus='ide'/> | ||||||
|  |       <readonly/> | ||||||
|  |     </disk> | ||||||
|  |     <input type='tablet' bus='usb'/> | ||||||
|  |     <graphics type='vnc' port='-1'/> | ||||||
|  |     <console type='pty'/> | ||||||
|  |     <sound model='ac97'/> | ||||||
|  |     <video> | ||||||
|  |       <model type='cirrus'/> | ||||||
|  |     </video> | ||||||
|  |   </devices> | ||||||
|  | </domain> | ||||||
		Reference in New Issue
	
	Block a user