Commit 55cd7253 authored by dorzheh's avatar dorzheh Committed by alexzorin

VirStorageVol implementation

VirStorageVol implementation.Adding StorageVolCreateXMLFromFile, StorageVolCreateXML,Delete ,Free and appropriate tests

Adding GetInfo and test

Adding VirStorageVolGetKey, VirStorageVolGetName and appropriate tests

Adding VirStorageVolGetPath and appropriate test

Adding VirStorageVolGetXMLDesc and appropriate test

Adding VirStorageVolLookupByKey,VirStorageVolLookupByName, VirStorageVolLookupByPath and appropriate tests

Adding Resize,Wipe and WipePattern plus appropriate integration tests
parent 1f08b779
......@@ -84,3 +84,43 @@ const (
VIR_DOMAIN_DEVICE_MODIFY_LIVE = C.VIR_DOMAIN_AFFECT_LIVE
VIR_DOMAIN_DEVICE_MODIFY_FORCE = C.VIR_DOMAIN_DEVICE_MODIFY_FORCE
)
// virStorageVolCreateFlags
const (
VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA = C.VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA
)
// virStorageVolDeleteFlags
const (
VIR_STORAGE_VOL_DELETE_NORMAL = C.VIR_STORAGE_VOL_DELETE_NORMAL // Delete metadata only (fast)
VIR_STORAGE_VOL_DELETE_ZEROED = C.VIR_STORAGE_VOL_DELETE_ZEROED // Clear all data to zeros (slow)
)
// virStorageVolResizeFlags
const (
VIR_STORAGE_VOL_RESIZE_ALLOCATE = C.VIR_STORAGE_VOL_RESIZE_ALLOCATE // force allocation of new size
VIR_STORAGE_VOL_RESIZE_DELTA = C.VIR_STORAGE_VOL_RESIZE_DELTA // size is relative to current
VIR_STORAGE_VOL_RESIZE_SHRINK = C.VIR_STORAGE_VOL_RESIZE_SHRINK // allow decrease in capacity
)
// virStorageVolType
const (
VIR_STORAGE_VOL_FILE = C.VIR_STORAGE_VOL_FILE // Regular file based volumes
VIR_STORAGE_VOL_BLOCK = C.VIR_STORAGE_VOL_BLOCK // Block based volumes
VIR_STORAGE_VOL_DIR = C.VIR_STORAGE_VOL_DIR // Directory-passthrough based volume
VIR_STORAGE_VOL_NETWORK = C.VIR_STORAGE_VOL_NETWORK //Network volumes like RBD (RADOS Block Device)
VIR_STORAGE_VOL_NETDIR = C.VIR_STORAGE_VOL_NETDIR // Network accessible directory that can contain other network volumes
)
// virStorageVolWipeAlgorithm
const (
VIR_STORAGE_VOL_WIPE_ALG_ZERO = C.VIR_STORAGE_VOL_WIPE_ALG_ZERO // 1-pass, all zeroes
VIR_STORAGE_VOL_WIPE_ALG_NNSA = C.VIR_STORAGE_VOL_WIPE_ALG_NNSA // 4-pass NNSA Policy Letter NAP-14.1-C (XVI-8)
VIR_STORAGE_VOL_WIPE_ALG_DOD = C.VIR_STORAGE_VOL_WIPE_ALG_DOD // 4-pass DoD 5220.22-M section 8-306 procedure
VIR_STORAGE_VOL_WIPE_ALG_BSI = C.VIR_STORAGE_VOL_WIPE_ALG_BSI // 9-pass method recommended by the German Center of Security in Information Technologies
VIR_STORAGE_VOL_WIPE_ALG_GUTMANN = C.VIR_STORAGE_VOL_WIPE_ALG_GUTMANN // The canonical 35-pass sequence
VIR_STORAGE_VOL_WIPE_ALG_SCHNEIER = C.VIR_STORAGE_VOL_WIPE_ALG_SCHNEIER // 7-pass method described by Bruce Schneier in "Applied Cryptography" (1996)
VIR_STORAGE_VOL_WIPE_ALG_PFITZNER7 = C.VIR_STORAGE_VOL_WIPE_ALG_PFITZNER7 // 7-pass random
VIR_STORAGE_VOL_WIPE_ALG_PFITZNER33 = C.VIR_STORAGE_VOL_WIPE_ALG_PFITZNER33 // 33-pass random
VIR_STORAGE_VOL_WIPE_ALG_RANDOM = C.VIR_STORAGE_VOL_WIPE_ALG_RANDOM // 1-pass random
)
......@@ -3,6 +3,8 @@
package libvirt
import (
"io/ioutil"
"os"
"strings"
"testing"
"time"
......@@ -344,3 +346,133 @@ func TestIntegrationDomainAttachDetachDevice(t *testing.T) {
return
}
}
func TestStorageVolResize(t *testing.T) {
conn, err := NewVirConnection("lxc:///")
if err != nil {
t.Error(err)
return
}
defer conn.CloseConnection()
poolPath, err := ioutil.TempDir("", "default-pool-test-1")
if err != nil {
t.Error(err)
return
}
defer os.RemoveAll(poolPath)
pool, err := conn.StoragePoolDefineXML(`<pool type='dir'>
<name>default-pool-test-1</name>
<target>
<path>`+poolPath+`</path>
</target>
</pool>`, 0)
defer func() {
pool.Undefine()
pool.Free()
}()
if err := pool.Create(0); err != nil {
t.Error(err)
return
}
defer pool.Destroy()
vol, err := pool.StorageVolCreateXML(testStorageVolXML("", poolPath), 0)
if err != nil {
t.Error(err)
return
}
defer func() {
vol.Delete(VIR_STORAGE_VOL_DELETE_NORMAL)
vol.Free()
}()
const newCapacityInBytes = 12582912
if err := vol.Resize(newCapacityInBytes, VIR_STORAGE_VOL_RESIZE_ALLOCATE); err != nil {
t.Fatal(err)
}
}
func TestStorageVolWipe(t *testing.T) {
conn, err := NewVirConnection("lxc:///")
if err != nil {
t.Error(err)
return
}
defer conn.CloseConnection()
poolPath, err := ioutil.TempDir("", "default-pool-test-1")
if err != nil {
t.Error(err)
return
}
defer os.RemoveAll(poolPath)
pool, err := conn.StoragePoolDefineXML(`<pool type='dir'>
<name>default-pool-test-1</name>
<target>
<path>`+poolPath+`</path>
</target>
</pool>`, 0)
defer func() {
pool.Undefine()
pool.Free()
}()
if err := pool.Create(0); err != nil {
t.Error(err)
return
}
defer pool.Destroy()
vol, err := pool.StorageVolCreateXML(testStorageVolXML("", poolPath), 0)
if err != nil {
t.Error(err)
return
}
defer func() {
vol.Delete(VIR_STORAGE_VOL_DELETE_NORMAL)
vol.Free()
}()
if err := vol.Wipe(0); err != nil {
t.Fatal(err)
}
}
func TestStorageVolWipePattern(t *testing.T) {
conn, err := NewVirConnection("lxc:///")
if err != nil {
t.Error(err)
return
}
defer conn.CloseConnection()
poolPath, err := ioutil.TempDir("", "default-pool-test-1")
if err != nil {
t.Error(err)
return
}
defer os.RemoveAll(poolPath)
pool, err := conn.StoragePoolDefineXML(`<pool type='dir'>
<name>default-pool-test-1</name>
<target>
<path>`+poolPath+`</path>
</target>
</pool>`, 0)
defer func() {
pool.Undefine()
pool.Free()
}()
if err := pool.Create(0); err != nil {
t.Error(err)
return
}
defer pool.Destroy()
vol, err := pool.StorageVolCreateXML(testStorageVolXML("", poolPath), 0)
if err != nil {
t.Error(err)
return
}
defer func() {
vol.Delete(VIR_STORAGE_VOL_DELETE_NORMAL)
vol.Free()
}()
if err := vol.WipePattern(VIR_STORAGE_VOL_WIPE_ALG_ZERO, 0); err != nil {
t.Fatal(err)
}
}
......@@ -559,3 +559,23 @@ func (c *VirConnection) LookupNWFilterByUUIDString(uuid string) (VirNWFilter, er
}
return VirNWFilter{ptr: ptr}, nil
}
func (c *VirConnection) LookupStorageVolByKey(key string) (VirStorageVol, error) {
cKey := C.CString(key)
defer C.free(unsafe.Pointer(cKey))
ptr := C.virStorageVolLookupByKey(c.ptr, cKey)
if ptr == nil {
return VirStorageVol{}, errors.New(GetLastError())
}
return VirStorageVol{ptr: ptr}, nil
}
func (c *VirConnection) LookupStorageVolByPath(path string) (VirStorageVol, error) {
cPath := C.CString(path)
defer C.free(unsafe.Pointer(cPath))
ptr := C.virStorageVolLookupByPath(c.ptr, cPath)
if ptr == nil {
return VirStorageVol{}, errors.New(GetLastError())
}
return VirStorageVol{ptr: ptr}, nil
}
......@@ -568,3 +568,81 @@ func TestLookupStoragePoolByUUIDString(t *testing.T) {
t.Fatalf("fetching by UUID: expected storage pool name: %s ,got: %s", name, poolName)
}
}
func TestLookupStorageVolByKey(t *testing.T) {
pool, conn := buildTestStoragePool()
defer func() {
pool.Undefine()
pool.Free()
conn.CloseConnection()
}()
if err := pool.Create(0); err != nil {
t.Error(err)
return
}
defer pool.Destroy()
defPoolPath := "default-pool"
defVolName := time.Now().String()
defVolKey := "/" + defPoolPath + "/" + defVolName
vol, err := pool.StorageVolCreateXML(testStorageVolXML(defVolName, defPoolPath), 0)
if err != nil {
t.Error(err)
return
}
defer func() {
vol.Delete(VIR_STORAGE_VOL_DELETE_NORMAL)
vol.Free()
}()
vol, err = conn.LookupStorageVolByKey(defVolKey)
if err != nil {
t.Error(err)
return
}
key, err := vol.GetKey()
if err != nil {
t.Error(err)
return
}
if key != defVolKey {
t.Fatalf("expected storage volume key: %s ,got: %s", defVolKey, key)
}
}
func TestLookupStorageVolByPath(t *testing.T) {
pool, conn := buildTestStoragePool()
defer func() {
pool.Undefine()
pool.Free()
conn.CloseConnection()
}()
if err := pool.Create(0); err != nil {
t.Error(err)
return
}
defer pool.Destroy()
defPoolPath := "default-pool"
defVolName := time.Now().String()
defVolPath := "/" + defPoolPath + "/" + defVolName
vol, err := pool.StorageVolCreateXML(testStorageVolXML(defVolName, defPoolPath), 0)
if err != nil {
t.Error(err)
return
}
defer func() {
vol.Delete(VIR_STORAGE_VOL_DELETE_NORMAL)
vol.Free()
}()
vol, err = conn.LookupStorageVolByPath(defVolPath)
if err != nil {
t.Error(err)
return
}
path, err := vol.GetPath()
if err != nil {
t.Error(err)
return
}
if path != defVolPath {
t.Fatalf("expected storage volume path: %s ,got: %s", defVolPath, path)
}
}
......@@ -69,4 +69,3 @@ func (f *VirNWFilter) GetXMLDesc(flags uint32) (string, error) {
C.free(unsafe.Pointer(result))
return xml, nil
}
......@@ -10,6 +10,7 @@ import "C"
import (
"errors"
"io/ioutil"
"unsafe"
)
......@@ -180,3 +181,31 @@ func (i *VirStoragePoolInfo) GetAllocationInBytes() uint64 {
func (i *VirStoragePoolInfo) GetAvailableInBytes() uint64 {
return uint64(i.ptr.available)
}
func (p *VirStoragePool) StorageVolCreateXMLFromFile(xmlFile string, flags uint32) (VirStorageVol, error) {
xmlConfig, err := ioutil.ReadFile(xmlFile)
if err != nil {
return VirStorageVol{}, err
}
return p.StorageVolCreateXML(string(xmlConfig), flags)
}
func (p *VirStoragePool) StorageVolCreateXML(xmlConfig string, flags uint32) (VirStorageVol, error) {
cXml := C.CString(string(xmlConfig))
defer C.free(unsafe.Pointer(cXml))
ptr := C.virStorageVolCreateXML(p.ptr, cXml, C.uint(flags))
if ptr == nil {
return VirStorageVol{}, errors.New(GetLastError())
}
return VirStorageVol{ptr: ptr}, nil
}
func (p *VirStoragePool) LookupStorageVolByName(name string) (VirStorageVol, error) {
cName := C.CString(name)
defer C.free(unsafe.Pointer(cName))
ptr := C.virStorageVolLookupByName(p.ptr, cName)
if ptr == nil {
return VirStorageVol{}, errors.New(GetLastError())
}
return VirStorageVol{ptr: ptr}, nil
}
......@@ -2,6 +2,7 @@ package libvirt
import (
"testing"
"time"
)
func buildTestStoragePool() (VirStoragePool, VirConnection) {
......@@ -224,3 +225,62 @@ func TestStoragePoolIsActive(t *testing.T) {
t.Fatal("Storage pool should be inactive")
}
}
func TestStorageVolCreateDelete(t *testing.T) {
pool, conn := buildTestStoragePool()
defer func() {
pool.Undefine()
pool.Free()
conn.CloseConnection()
}()
if err := pool.Create(0); err != nil {
t.Error(err)
return
}
defer pool.Destroy()
vol, err := pool.StorageVolCreateXML(testStorageVolXML("", "default-pool"), 0)
if err != nil {
t.Fatal(err)
}
defer vol.Free()
if err := vol.Delete(VIR_STORAGE_VOL_DELETE_NORMAL); err != nil {
t.Fatal(err)
}
}
func TestLookupStorageVolByName(t *testing.T) {
pool, conn := buildTestStoragePool()
defer func() {
pool.Undefine()
pool.Free()
conn.CloseConnection()
}()
if err := pool.Create(0); err != nil {
t.Error(err)
return
}
defer pool.Destroy()
defVolName := time.Now().String()
vol, err := pool.StorageVolCreateXML(testStorageVolXML(defVolName, "default-pool"), 0)
if err != nil {
t.Error(err)
return
}
defer func() {
vol.Delete(VIR_STORAGE_VOL_DELETE_NORMAL)
vol.Free()
}()
vol, err = pool.LookupStorageVolByName(defVolName)
if err != nil {
t.Error(err)
return
}
name, err := vol.GetName()
if err != nil {
t.Error(err)
return
}
if name != defVolName {
t.Fatalf("expected storage volume name: %s ,got: %s", defVolName, name)
}
}
package libvirt
/*
#cgo LDFLAGS: -lvirt -ldl
#include <libvirt/libvirt.h>
#include <libvirt/virterror.h>
#include <stdlib.h>
*/
import "C"
import (
"errors"
"unsafe"
)
type VirStorageVol struct {
ptr C.virStorageVolPtr
}
type VirStorageVolInfo struct {
ptr C.virStorageVolInfo
}
func (v *VirStorageVol) Delete(flags uint32) error {
result := C.virStorageVolDelete(v.ptr, C.uint(flags))
if result == -1 {
return errors.New(GetLastError())
}
return nil
}
func (v *VirStorageVol) Free() error {
if result := C.virStorageVolFree(v.ptr); result != 0 {
return errors.New(GetLastError())
}
return nil
}
func (v *VirStorageVol) GetInfo() (VirStorageVolInfo, error) {
vi := VirStorageVolInfo{}
var ptr C.virStorageVolInfo
result := C.virStorageVolGetInfo(v.ptr, (*C.virStorageVolInfo)(unsafe.Pointer(&ptr)))
if result == -1 {
return vi, errors.New(GetLastError())
}
vi.ptr = ptr
return vi, nil
}
func (i *VirStorageVolInfo) GetType() int {
return int(i.ptr._type)
}
func (i *VirStorageVolInfo) GetCapacityInBytes() uint64 {
return uint64(i.ptr.capacity)
}
func (i *VirStorageVolInfo) GetAllocationInBytes() uint64 {
return uint64(i.ptr.allocation)
}
func (v *VirStorageVol) GetKey() (string, error) {
key := C.virStorageVolGetKey(v.ptr)
if key == nil {
return "", errors.New(GetLastError())
}
return C.GoString(key), nil
}
func (v *VirStorageVol) GetName() (string, error) {
name := C.virStorageVolGetName(v.ptr)
if name == nil {
return "", errors.New(GetLastError())
}
return C.GoString(name), nil
}
func (v *VirStorageVol) GetPath() (string, error) {
result := C.virStorageVolGetPath(v.ptr)
if result == nil {
return "", errors.New(GetLastError())
}
path := C.GoString(result)
C.free(unsafe.Pointer(result))
return path, nil
}
func (v *VirStorageVol) GetXMLDesc(flags uint32) (string, error) {
result := C.virStorageVolGetXMLDesc(v.ptr, C.uint(flags))
if result == nil {
return "", errors.New(GetLastError())
}
xml := C.GoString(result)
C.free(unsafe.Pointer(result))
return xml, nil
}
func (v *VirStorageVol) Resize(capacity uint64, flags uint32) error {
result := C.virStorageVolResize(v.ptr, C.ulonglong(capacity), C.uint(flags))
if result == -1 {
return errors.New(GetLastError())
}
return nil
}
func (v *VirStorageVol) Wipe(flags uint32) error {
result := C.virStorageVolWipe(v.ptr, C.uint(flags))
if result == -1 {
return errors.New(GetLastError())
}
return nil
}
func (v *VirStorageVol) WipePattern(algorithm uint32, flags uint32) error {
result := C.virStorageVolWipePattern(v.ptr, C.uint(algorithm), C.uint(flags))
if result == -1 {
return errors.New(GetLastError())
}
return nil
}
package libvirt
import (
"testing"
"time"
)
func testStorageVolXML(volName, poolPath string) string {
defName := volName
if defName == "" {
defName = time.Now().String()
}
return `<volume>
<name>` + defName + `</name>
<allocation>0</allocation>
<capacity unit="M">10</capacity>
<target>
<path>` + "/" + poolPath + "/" + defName + `</path>
<permissions>
<owner>107</owner>
<group>107</group>
<mode>0744</mode>
<label>testLabel0</label>
</permissions>
</target>
</volume>`
}
func TestStorageVolGetInfo(t *testing.T) {
pool, conn := buildTestStoragePool()
defer func() {
pool.Undefine()
pool.Free()
conn.CloseConnection()
}()
if err := pool.Create(0); err != nil {
t.Error(err)
return
}
defer pool.Destroy()
vol, err := pool.StorageVolCreateXML(testStorageVolXML("", "default-pool"), 0)
if err != nil {
t.Error(err)
return
}
defer func() {
vol.Delete(VIR_STORAGE_VOL_DELETE_NORMAL)
vol.Free()
}()
if _, err := vol.GetInfo(); err != nil {
t.Fatal(err)
}
}
func TestStorageVolGetKey(t *testing.T) {
pool, conn := buildTestStoragePool()
defer func() {
pool.Undefine()
pool.Free()
conn.CloseConnection()
}()
if err := pool.Create(0); err != nil {
t.Error(err)
return
}
defer pool.Destroy()
vol, err := pool.StorageVolCreateXML(testStorageVolXML("", "default-pool"), 0)
if err != nil {
t.Error(err)
return
}
defer func() {
vol.Delete(VIR_STORAGE_VOL_DELETE_NORMAL)
vol.Free()
}()
if _, err := vol.GetKey(); err != nil {
t.Fatal(err)
}
}
func TestStorageVolGetName(t *testing.T) {
pool, conn := buildTestStoragePool()
defer func() {
pool.Undefine()
pool.Free()
conn.CloseConnection()
}()
if err := pool.Create(0); err != nil {
t.Error(err)
return
}
defer pool.Destroy()
vol, err := pool.StorageVolCreateXML(testStorageVolXML("", "default-pool"), 0)
if err != nil {
t.Error(err)
return
}
defer func() {
vol.Delete(VIR_STORAGE_VOL_DELETE_NORMAL)
vol.Free()
}()
if _, err := vol.GetName(); err != nil {
t.Fatal(err)
}
}
func TestStorageVolGetPath(t *testing.T) {
pool, conn := buildTestStoragePool()
defer func() {
pool.Undefine()
pool.Free()
conn.CloseConnection()
}()
if err := pool.Create(0); err != nil {
t.Error(err)
return
}
defer pool.Destroy()
vol, err := pool.StorageVolCreateXML(testStorageVolXML("", "default-pool"), 0)
if err != nil {
t.Error(err)
return
}
defer func() {
vol.Delete(VIR_STORAGE_VOL_DELETE_NORMAL)
vol.Free()
}()
if _, err := vol.GetPath(); err != nil {
t.Fatal(err)
}
}
func TestStorageVolGetXMLDesc(t *testing.T) {
pool, conn := buildTestStoragePool()
defer func() {
pool.Undefine()
pool.Free()
conn.CloseConnection()
}()
if err := pool.Create(0); err != nil {
t.Error(err)
return
}
defer pool.Destroy()
vol, err := pool.StorageVolCreateXML(testStorageVolXML("", "default-pool"), 0)
if err != nil {
t.Error(err)
return
}
defer func() {
vol.Delete(VIR_STORAGE_VOL_DELETE_NORMAL)
vol.Free()
}()
if _, err := vol.GetXMLDesc(0); err != nil {
t.Fatal(err)
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment