From 591f6798f1465fe3f33c8b61cba55f101c7e3a02 Mon Sep 17 00:00:00 2001 From: Ben LeMasurier Date: Fri, 6 Jan 2017 15:58:27 -0600 Subject: [PATCH] Adds StoragePools() (#27) * Adds StoragePools() This adds the ability to list storage pools. --- .travis.yml | 3 +- test-domain.xml => .travis/test-domain.xml | 0 .travis/test-pool.xml | 7 ++ internal/constants/constants.go | 29 +++++---- libvirt.go | 76 ++++++++++++++++++++++ libvirt_integration_test.go | 46 +++++++++++++ libvirt_test.go | 33 ++++++++++ libvirttest/libvirt.go | 24 +++++++ 8 files changed, 203 insertions(+), 15 deletions(-) rename test-domain.xml => .travis/test-domain.xml (100%) create mode 100644 .travis/test-pool.xml diff --git a/.travis.yml b/.travis.yml index f2b7967..fbe69a2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,8 +36,9 @@ 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 define .travis/test-domain.xml - sudo virsh start test + - sudo virsh pool-create .travis/test-pool.xml script: - ./scripts/licensecheck.sh diff --git a/test-domain.xml b/.travis/test-domain.xml similarity index 100% rename from test-domain.xml rename to .travis/test-domain.xml diff --git a/.travis/test-pool.xml b/.travis/test-pool.xml new file mode 100644 index 0000000..6bc47e7 --- /dev/null +++ b/.travis/test-pool.xml @@ -0,0 +1,7 @@ + + + test + + /tmp + + diff --git a/internal/constants/constants.go b/internal/constants/constants.go index e19b3b7..50d2745 100644 --- a/internal/constants/constants.go +++ b/internal/constants/constants.go @@ -36,20 +36,21 @@ const ( // See: // https://libvirt.org/git/?p=libvirt.git;a=blob_plain;f=src/remote/remote_protocol.x;hb=HEAD const ( - ProcConnectOpen = 1 - ProcConnectClose = 2 - ProcConnectGetCapabilties = 7 - ProcDomainGetXMLDesc = 14 - ProcDomainLookupByName = 23 - ProcAuthList = 66 - ProcConnectGetLibVersion = 157 - ProcDomainMigrateSetMaxSpeed = 207 - ProcDomainGetState = 212 - ProcDomainUndefineFlags = 231 - ProcDomainDestroyFlags = 234 - ProcConnectListAllDomains = 273 - ProcMigratePerformParams = 305 - ProcDomainDefineXMLFlags = 350 + ProcConnectOpen = 1 + ProcConnectClose = 2 + ProcConnectGetCapabilties = 7 + ProcDomainGetXMLDesc = 14 + ProcDomainLookupByName = 23 + ProcAuthList = 66 + ProcConnectGetLibVersion = 157 + ProcDomainMigrateSetMaxSpeed = 207 + ProcDomainGetState = 212 + ProcDomainUndefineFlags = 231 + ProcDomainDestroyFlags = 234 + ProcConnectListAllDomains = 273 + ProcConnectListAllStoragePools = 281 + ProcMigratePerformParams = 305 + ProcDomainDefineXMLFlags = 350 ) // qemu procedure identifiers diff --git a/libvirt.go b/libvirt.go index 19996ef..d94b009 100644 --- a/libvirt.go +++ b/libvirt.go @@ -70,6 +70,12 @@ type DomainEvent struct { 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. type qemuError struct { Error struct { @@ -203,6 +209,36 @@ const ( 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. func (l *Libvirt) Capabilities() ([]byte, error) { 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 } +// 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'. // The flags argument allows additional options to be specified such as // cleaning up snapshot metadata. For more information on available diff --git a/libvirt_integration_test.go b/libvirt_integration_test.go index 8079a69..73080c4 100644 --- a/libvirt_integration_test.go +++ b/libvirt_integration_test.go @@ -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) { l := New(testConn(t)) diff --git a/libvirt_test.go b/libvirt_test.go index d734308..f06cc09 100644 --- a/libvirt_test.go +++ b/libvirt_test.go @@ -20,6 +20,7 @@ import ( "testing" "time" + "github.com/digitalocean/go-libvirt/internal/constants" "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) { conn := libvirttest.New() l := New(conn) diff --git a/libvirttest/libvirt.go b/libvirttest/libvirt.go index 192a726..0d9742e 100644 --- a/libvirttest/libvirt.go +++ b/libvirttest/libvirt.go @@ -217,6 +217,28 @@ var testDomainStateReply = []byte{ 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{ 0x00, 0x00, 0x00, 0x1c, // length 0x20, 0x00, 0x80, 0x86, // program @@ -321,6 +343,8 @@ func (m *MockLibvirt) handleRemote(procedure uint32, conn net.Conn) { conn.Write(m.reply(testDomainResponse)) case constants.ProcConnectListAllDomains: conn.Write(m.reply(testDomainsReply)) + case constants.ProcConnectListAllStoragePools: + conn.Write(m.reply(testListPoolsReply)) case constants.ProcDomainGetState: conn.Write(m.reply(testDomainStateReply)) case constants.ProcDomainMigrateSetMaxSpeed: