Add Secrets() (#29)

This adds the `Secrets()` method, used to retrieve all secrets managed
by the libvirt daemon.
This commit is contained in:
Ben LeMasurier 2017-01-19 20:40:31 -06:00 committed by GitHub
parent cfa567708b
commit 2609dd2697
7 changed files with 177 additions and 0 deletions

View File

@ -39,6 +39,7 @@ before_script:
- sudo virsh define .travis/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 - sudo virsh pool-create .travis/test-pool.xml
- sudo virsh secret-define .travis/test-secret.xml
script: script:
- ./scripts/licensecheck.sh - ./scripts/licensecheck.sh

7
.travis/test-secret.xml Normal file
View File

@ -0,0 +1,7 @@
<secret ephemeral='no' private='yes'>
<description>test</description>
<uuid>19fdc2f2-fa64-46f3-bacf-42a8aafca6dd</uuid>
<usage type='volume'>
<volume>/tmp</volume>
</usage>
</secret>

View File

@ -51,6 +51,7 @@ const (
ProcDomainDestroyFlags = 234 ProcDomainDestroyFlags = 234
ProcConnectListAllDomains = 273 ProcConnectListAllDomains = 273
ProcConnectListAllStoragePools = 281 ProcConnectListAllStoragePools = 281
ProcConnectListAllSecrets = 287
ProcMigratePerformParams = 305 ProcMigratePerformParams = 305
ProcDomainDefineXMLFlags = 350 ProcDomainDefineXMLFlags = 350
) )

View File

@ -70,6 +70,13 @@ type DomainEvent struct {
Details []byte Details []byte
} }
// Secret represents a secret managed by the libvirt daemon.
type Secret struct {
UUID [constants.UUIDSize]byte
UsageType SecretUsageType
UsageID string
}
// StoragePool represents a storage pool as seen by libvirt. // StoragePool represents a storage pool as seen by libvirt.
type StoragePool struct { type StoragePool struct {
Name string Name string
@ -209,6 +216,20 @@ const (
DomainStateLast DomainStateLast
) )
// SecretUsageType specifies the usage for a libvirt secret.
type SecretUsageType uint32
const (
// SecretUsageTypeNone specifies no usage.
SecretUsageTypeNone SecretUsageType = iota
// SecretUsageTypeVolume specifies a volume secret.
SecretUsageTypeVolume
// SecretUsageTypeCeph specifies secrets for ceph devices.
SecretUsageTypeCeph
// SecretUsageTypeISCSI specifies secrets for ISCSI devices.
SecretUsageTypeISCSI
)
// StoragePoolsFlags specifies storage pools to list. // StoragePoolsFlags specifies storage pools to list.
type StoragePoolsFlags uint32 type StoragePoolsFlags uint32
@ -572,6 +593,45 @@ func (l *Libvirt) Run(dom string, cmd []byte) ([]byte, error) {
return bytes.TrimRight(data[4:], "\x00"), nil return bytes.TrimRight(data[4:], "\x00"), nil
} }
// Secrets returns all secrets managed by the libvirt daemon.
func (l *Libvirt) Secrets() ([]Secret, error) {
req := struct {
NeedResults uint32
Flags uint32
}{
NeedResults: 1,
Flags: 0, // unused per libvirt source, callers should pass 0
}
buf, err := encode(&req)
if err != nil {
return nil, err
}
resp, err := l.request(constants.ProcConnectListAllSecrets, constants.ProgramRemote, &buf)
if err != nil {
return nil, err
}
r := <-resp
if r.Status != StatusOK {
return nil, decodeError(r.Payload)
}
result := struct {
Secrets []Secret
Count uint32
}{}
dec := xdr.NewDecoder(bytes.NewReader(r.Payload))
_, err = dec.Decode(&result)
if err != nil {
return nil, err
}
return result.Secrets, nil
}
// StoragePool returns the storage pool associated with the provided name. // StoragePool returns the storage pool associated with the provided name.
// An error is returned if the requested storage pool is not found. // An error is returned if the requested storage pool is not found.
func (l *Libvirt) StoragePool(name string) (*StoragePool, error) { func (l *Libvirt) StoragePool(name string) (*StoragePool, error) {

View File

@ -21,6 +21,8 @@ import (
"net" "net"
"testing" "testing"
"time" "time"
"github.com/digitalocean/go-libvirt/internal/constants"
) )
const testAddr = "127.0.0.1:16509" const testAddr = "127.0.0.1:16509"
@ -70,6 +72,47 @@ func TestCapabilities(t *testing.T) {
} }
} }
func TestSecretsIntegration(t *testing.T) {
l := New(testConn(t))
defer l.Disconnect()
if err := l.Connect(); err != nil {
t.Fatal(err)
}
secrets, err := l.Secrets()
if err != nil {
t.Fatal(err)
}
wantLen := 1
gotLen := len(secrets)
if gotLen != wantLen {
t.Fatal("expected %d secrets, got %d", wantLen, gotLen)
}
s := secrets[0]
wantType := SecretUsageTypeVolume
if s.UsageType != wantType {
t.Error("expected usage type: %d, got %d", wantType, s.UsageType)
}
wantID := "/tmp"
if s.UsageID != wantID {
t.Error("expected usage id: %q, got %q", wantID, s.UsageID)
}
// 19fdc2f2-fa64-46f3-bacf-42a8aafca6dd
wantUUID := [constants.UUIDSize]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) { func TestStoragePoolIntegration(t *testing.T) {
l := New(testConn(t)) l := New(testConn(t))
defer l.Disconnect() defer l.Disconnect()

View File

@ -221,6 +221,42 @@ func TestRunFail(t *testing.T) {
} }
} }
func TestSecrets(t *testing.T) {
conn := libvirttest.New()
l := New(conn)
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 != 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 := [constants.UUIDSize]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) { func TestStoragePool(t *testing.T) {
conn := libvirttest.New() conn := libvirttest.New()
l := New(conn) l := New(conn)

View File

@ -217,6 +217,33 @@ var testDomainStateReply = []byte{
0x00, 0x00, 0x00, 0x01, // reason 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{ var testStoragePoolLookup = []byte{
0x00, 0x00, 0x00, 0x38, // length 0x00, 0x00, 0x00, 0x38, // length
0x20, 0x00, 0x80, 0x86, // program 0x20, 0x00, 0x80, 0x86, // program
@ -377,6 +404,8 @@ func (m *MockLibvirt) handleRemote(procedure uint32, conn net.Conn) {
conn.Write(m.reply(testDomainsReply)) conn.Write(m.reply(testDomainsReply))
case constants.ProcConnectListAllStoragePools: case constants.ProcConnectListAllStoragePools:
conn.Write(m.reply(testListPoolsReply)) conn.Write(m.reply(testListPoolsReply))
case constants.ProcConnectListAllSecrets:
conn.Write(m.reply(testSecretsReply))
case constants.ProcDomainGetState: case constants.ProcDomainGetState:
conn.Write(m.reply(testDomainStateReply)) conn.Write(m.reply(testDomainStateReply))
case constants.ProcDomainMigrateSetMaxSpeed: case constants.ProcDomainMigrateSetMaxSpeed: