Adds StoragePools() (#27)
* Adds StoragePools() This adds the ability to list storage pools.
This commit is contained in:
		| @@ -36,8 +36,9 @@ 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 qemu-img create -f raw -o size=10M /var/lib/libvirt/images/test.raw | ||||||
|   - sudo virsh define ./test-domain.xml |   - sudo virsh define .travis/test-domain.xml | ||||||
|   - sudo virsh start test |   - sudo virsh start test | ||||||
|  |   - sudo virsh pool-create .travis/test-pool.xml | ||||||
|  |  | ||||||
| script: | script: | ||||||
|   - ./scripts/licensecheck.sh |   - ./scripts/licensecheck.sh | ||||||
|   | |||||||
							
								
								
									
										7
									
								
								.travis/test-pool.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								.travis/test-pool.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | <!-- storage pool used for CI testing --> | ||||||
|  | <pool type="dir"> | ||||||
|  |   <name>test</name> | ||||||
|  |   <target> | ||||||
|  |     <path>/tmp</path> | ||||||
|  |   </target> | ||||||
|  | </pool> | ||||||
| @@ -36,20 +36,21 @@ const ( | |||||||
| // See: | // See: | ||||||
| // https://libvirt.org/git/?p=libvirt.git;a=blob_plain;f=src/remote/remote_protocol.x;hb=HEAD | // https://libvirt.org/git/?p=libvirt.git;a=blob_plain;f=src/remote/remote_protocol.x;hb=HEAD | ||||||
| const ( | const ( | ||||||
| 	ProcConnectOpen              = 1 | 	ProcConnectOpen                = 1 | ||||||
| 	ProcConnectClose             = 2 | 	ProcConnectClose               = 2 | ||||||
| 	ProcConnectGetCapabilties    = 7 | 	ProcConnectGetCapabilties      = 7 | ||||||
| 	ProcDomainGetXMLDesc         = 14 | 	ProcDomainGetXMLDesc           = 14 | ||||||
| 	ProcDomainLookupByName       = 23 | 	ProcDomainLookupByName         = 23 | ||||||
| 	ProcAuthList                 = 66 | 	ProcAuthList                   = 66 | ||||||
| 	ProcConnectGetLibVersion     = 157 | 	ProcConnectGetLibVersion       = 157 | ||||||
| 	ProcDomainMigrateSetMaxSpeed = 207 | 	ProcDomainMigrateSetMaxSpeed   = 207 | ||||||
| 	ProcDomainGetState           = 212 | 	ProcDomainGetState             = 212 | ||||||
| 	ProcDomainUndefineFlags      = 231 | 	ProcDomainUndefineFlags        = 231 | ||||||
| 	ProcDomainDestroyFlags       = 234 | 	ProcDomainDestroyFlags         = 234 | ||||||
| 	ProcConnectListAllDomains    = 273 | 	ProcConnectListAllDomains      = 273 | ||||||
| 	ProcMigratePerformParams     = 305 | 	ProcConnectListAllStoragePools = 281 | ||||||
| 	ProcDomainDefineXMLFlags     = 350 | 	ProcMigratePerformParams       = 305 | ||||||
|  | 	ProcDomainDefineXMLFlags       = 350 | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // qemu procedure identifiers | // qemu procedure identifiers | ||||||
|   | |||||||
							
								
								
									
										76
									
								
								libvirt.go
									
									
									
									
									
								
							
							
						
						
									
										76
									
								
								libvirt.go
									
									
									
									
									
								
							| @@ -70,6 +70,12 @@ type DomainEvent struct { | |||||||
| 	Details      []byte | 	Details      []byte | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // StoragePool represents a storage pool as seen by libvirt. | ||||||
|  | type StoragePool struct { | ||||||
|  | 	Name string | ||||||
|  | 	UUID [constants.UUIDSize]byte | ||||||
|  | } | ||||||
|  |  | ||||||
| // qemuError represents a QEMU process error. | // qemuError represents a QEMU process error. | ||||||
| type qemuError struct { | type qemuError struct { | ||||||
| 	Error struct { | 	Error struct { | ||||||
| @@ -203,6 +209,36 @@ const ( | |||||||
| 	DomainStateLast | 	DomainStateLast | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | // StoragePoolsFlags specifies storage pools to list. | ||||||
|  | type StoragePoolsFlags uint32 | ||||||
|  |  | ||||||
|  | // These flags come in groups; if all bits from a group are 0, | ||||||
|  | // then that group is not used to filter results. | ||||||
|  | const ( | ||||||
|  | 	StoragePoolsFlagInactive = 1 << iota | ||||||
|  | 	StoragePoolsFlagActive | ||||||
|  |  | ||||||
|  | 	StoragePoolsFlagPersistent | ||||||
|  | 	StoragePoolsFlagTransient | ||||||
|  |  | ||||||
|  | 	StoragePoolsFlagAutostart | ||||||
|  | 	StoragePoolsFlagNoAutostart | ||||||
|  |  | ||||||
|  | 	// pools by type | ||||||
|  | 	StoragePoolsFlagDir | ||||||
|  | 	StoragePoolsFlagFS | ||||||
|  | 	StoragePoolsFlagNETFS | ||||||
|  | 	StoragePoolsFlagLogical | ||||||
|  | 	StoragePoolsFlagDisk | ||||||
|  | 	StoragePoolsFlagISCSI | ||||||
|  | 	StoragePoolsFlagSCSI | ||||||
|  | 	StoragePoolsFlagMPATH | ||||||
|  | 	StoragePoolsFlagRBD | ||||||
|  | 	StoragePoolsFlagSheepdog | ||||||
|  | 	StoragePoolsFlagGluster | ||||||
|  | 	StoragePoolsFlagZFS | ||||||
|  | ) | ||||||
|  |  | ||||||
| // Capabilities returns an XML document describing the host's capabilties. | // Capabilities returns an XML document describing the host's capabilties. | ||||||
| func (l *Libvirt) Capabilities() ([]byte, error) { | func (l *Libvirt) Capabilities() ([]byte, error) { | ||||||
| 	resp, err := l.request(constants.ProcConnectGetCapabilties, constants.ProgramRemote, nil) | 	resp, err := l.request(constants.ProcConnectGetCapabilties, constants.ProgramRemote, nil) | ||||||
| @@ -536,6 +572,46 @@ func (l *Libvirt) Run(dom string, cmd []byte) ([]byte, error) { | |||||||
| 	return bytes.TrimRight(data[4:], "\x00"), nil | 	return bytes.TrimRight(data[4:], "\x00"), nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // StoragePools returns a list of defined storage pools. Pools are filtered by | ||||||
|  | // the provided flags. See StoragePools*. | ||||||
|  | func (l *Libvirt) StoragePools(flags StoragePoolsFlags) ([]StoragePool, error) { | ||||||
|  | 	req := struct { | ||||||
|  | 		NeedResults uint32 | ||||||
|  | 		Flags       StoragePoolsFlags | ||||||
|  | 	}{ | ||||||
|  | 		NeedResults: 1, | ||||||
|  | 		Flags:       flags, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	buf, err := encode(&req) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	resp, err := l.request(constants.ProcConnectListAllStoragePools, constants.ProgramRemote, &buf) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	r := <-resp | ||||||
|  | 	if r.Status != StatusOK { | ||||||
|  | 		return nil, decodeError(r.Payload) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	result := struct { | ||||||
|  | 		Pools []StoragePool | ||||||
|  | 		Count uint32 | ||||||
|  | 	}{} | ||||||
|  |  | ||||||
|  | 	dec := xdr.NewDecoder(bytes.NewReader(r.Payload)) | ||||||
|  | 	_, err = dec.Decode(&result) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return result.Pools, nil | ||||||
|  | } | ||||||
|  |  | ||||||
| // Undefine undefines the domain specified by dom, e.g., 'prod-lb-01'. | // Undefine undefines the domain specified by dom, e.g., 'prod-lb-01'. | ||||||
| // The flags argument allows additional options to be specified such as | // The flags argument allows additional options to be specified such as | ||||||
| // cleaning up snapshot metadata. For more information on available | // cleaning up snapshot metadata. For more information on available | ||||||
|   | |||||||
| @@ -70,6 +70,52 @@ func TestCapabilities(t *testing.T) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func TestStoragePoolsIntegration(t *testing.T) { | ||||||
|  | 	l := New(testConn(t)) | ||||||
|  | 	defer l.Disconnect() | ||||||
|  |  | ||||||
|  | 	if err := l.Connect(); err != nil { | ||||||
|  | 		t.Fatal(err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	pools, err := l.StoragePools(StoragePoolsFlagActive) | ||||||
|  | 	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 := New(testConn(t)) | ||||||
|  | 	defer l.Disconnect() | ||||||
|  |  | ||||||
|  | 	if err := l.Connect(); err != nil { | ||||||
|  | 		t.Fatal(err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	pools, err := l.StoragePools(StoragePoolsFlagAutostart) | ||||||
|  | 	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 TestXMLIntegration(t *testing.T) { | func TestXMLIntegration(t *testing.T) { | ||||||
| 	l := New(testConn(t)) | 	l := New(testConn(t)) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -20,6 +20,7 @@ import ( | |||||||
| 	"testing" | 	"testing" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
|  | 	"github.com/digitalocean/go-libvirt/internal/constants" | ||||||
| 	"github.com/digitalocean/go-libvirt/libvirttest" | 	"github.com/digitalocean/go-libvirt/libvirttest" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -220,6 +221,38 @@ func TestRunFail(t *testing.T) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func TestStoragePools(t *testing.T) { | ||||||
|  | 	conn := libvirttest.New() | ||||||
|  | 	l := New(conn) | ||||||
|  |  | ||||||
|  | 	pools, err := l.StoragePools(StoragePoolsFlagActive) | ||||||
|  | 	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 := [constants.UUIDSize]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 TestUndefine(t *testing.T) { | func TestUndefine(t *testing.T) { | ||||||
| 	conn := libvirttest.New() | 	conn := libvirttest.New() | ||||||
| 	l := New(conn) | 	l := New(conn) | ||||||
|   | |||||||
| @@ -217,6 +217,28 @@ var testDomainStateReply = []byte{ | |||||||
| 	0x00, 0x00, 0x00, 0x01, // reason | 	0x00, 0x00, 0x00, 0x01, // reason | ||||||
| } | } | ||||||
|  |  | ||||||
|  | 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{ | var testUndefineReply = []byte{ | ||||||
| 	0x00, 0x00, 0x00, 0x1c, // length | 	0x00, 0x00, 0x00, 0x1c, // length | ||||||
| 	0x20, 0x00, 0x80, 0x86, // program | 	0x20, 0x00, 0x80, 0x86, // program | ||||||
| @@ -321,6 +343,8 @@ func (m *MockLibvirt) handleRemote(procedure uint32, conn net.Conn) { | |||||||
| 		conn.Write(m.reply(testDomainResponse)) | 		conn.Write(m.reply(testDomainResponse)) | ||||||
| 	case constants.ProcConnectListAllDomains: | 	case constants.ProcConnectListAllDomains: | ||||||
| 		conn.Write(m.reply(testDomainsReply)) | 		conn.Write(m.reply(testDomainsReply)) | ||||||
|  | 	case constants.ProcConnectListAllStoragePools: | ||||||
|  | 		conn.Write(m.reply(testListPoolsReply)) | ||||||
| 	case constants.ProcDomainGetState: | 	case constants.ProcDomainGetState: | ||||||
| 		conn.Write(m.reply(testDomainStateReply)) | 		conn.Write(m.reply(testDomainStateReply)) | ||||||
| 	case constants.ProcDomainMigrateSetMaxSpeed: | 	case constants.ProcDomainMigrateSetMaxSpeed: | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user