- Improved existing tests.
Test implementation is separated per datasets and pools to avoid one big complex file. Tests are dependent so order of execution is forced by adding a_test.go running test with sub tests in required order.
This commit is contained in:
parent
65eb260be4
commit
c0b415fe50
|
@ -0,0 +1,23 @@
|
||||||
|
package zfs_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
// TESTS ARE DEPENDED AND MUST RUN IN DEPENDENT ORDER
|
||||||
|
|
||||||
|
func Test(t *testing.T) {
|
||||||
|
zpoolTestPoolCreate(t)
|
||||||
|
zpoolTestPoolOpenAll(t)
|
||||||
|
zpoolTestFailPoolOpen(t)
|
||||||
|
|
||||||
|
zfsTestDatasetCreate(t)
|
||||||
|
zfsTestDatasetOpen(t)
|
||||||
|
zfsTestDatasetSnapshot(t)
|
||||||
|
zfsTestDatasetOpenAll(t)
|
||||||
|
|
||||||
|
zfsTestDatasetDestroy(t)
|
||||||
|
|
||||||
|
zpoolTestPoolDestroy(t)
|
||||||
|
}
|
|
@ -0,0 +1,171 @@
|
||||||
|
package zfs_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/bicomsystems/go-libzfs"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
// HELPERS:
|
||||||
|
var TST_DATASET_PATH = TST_POOL_NAME + "/DATASET"
|
||||||
|
var TST_VOLUME_PATH = TST_DATASET_PATH + "/VOLUME"
|
||||||
|
var TST_DATASET_PATH_SNAP = TST_DATASET_PATH + "@test"
|
||||||
|
|
||||||
|
func printDatasets(ds []zfs.Dataset) error {
|
||||||
|
for _, d := range ds {
|
||||||
|
|
||||||
|
path, err := d.Path()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p, err := d.GetProperty(zfs.ZFSPropType)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Printf(" %30s | %10s\n", path,
|
||||||
|
p.Value)
|
||||||
|
if len(d.Children) > 0 {
|
||||||
|
printDatasets(d.Children)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
// TESTS:
|
||||||
|
|
||||||
|
func zfsTestDatasetCreate(t *testing.T) {
|
||||||
|
// reinit names used in case TESTPOOL was in conflict
|
||||||
|
TST_DATASET_PATH = TST_POOL_NAME + "/DATASET"
|
||||||
|
TST_VOLUME_PATH = TST_DATASET_PATH + "/VOLUME"
|
||||||
|
TST_DATASET_PATH_SNAP = TST_DATASET_PATH + "@test"
|
||||||
|
|
||||||
|
println("TEST DatasetCreate(", TST_DATASET_PATH, ") (filesystem) ... ")
|
||||||
|
props := make(map[zfs.ZFSProp]zfs.Property)
|
||||||
|
d, err := zfs.DatasetCreate(TST_DATASET_PATH, zfs.DatasetTypeFilesystem, props)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
d.Close()
|
||||||
|
println("PASS\n")
|
||||||
|
|
||||||
|
strSize := "536870912" // 512M
|
||||||
|
|
||||||
|
println("TEST DatasetCreate(", TST_VOLUME_PATH, ") (volume) ... ")
|
||||||
|
props[zfs.ZFSPropVolsize] = zfs.Property{Value: strSize}
|
||||||
|
// In addition I explicitly choose some more properties to be set.
|
||||||
|
props[zfs.ZFSPropVolblocksize] = zfs.Property{Value: "4096"}
|
||||||
|
props[zfs.ZFSPropReservation] = zfs.Property{Value: strSize}
|
||||||
|
d, err = zfs.DatasetCreate(TST_VOLUME_PATH, zfs.DatasetTypeVolume, props)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
d.Close()
|
||||||
|
println("PASS\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func zfsTestDatasetOpen(t *testing.T) {
|
||||||
|
println("TEST DatasetOpen(", TST_DATASET_PATH, ") ... ")
|
||||||
|
d, err := zfs.DatasetOpen(TST_DATASET_PATH)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
d.Close()
|
||||||
|
println("PASS\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func zfsTestDatasetOpenAll(t *testing.T) {
|
||||||
|
println("TEST DatasetOpenAll()/DatasetCloseAll() ... ")
|
||||||
|
ds, err := zfs.DatasetOpenAll()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = printDatasets(ds); err != nil {
|
||||||
|
zfs.DatasetCloseAll(ds)
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
zfs.DatasetCloseAll(ds)
|
||||||
|
println("PASS\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func zfsTestDatasetSnapshot(t *testing.T) {
|
||||||
|
println("TEST DatasetSnapshot(", TST_DATASET_PATH, ", true, ...) ... ")
|
||||||
|
props := make(map[zfs.ZFSProp]zfs.Property)
|
||||||
|
d, err := zfs.DatasetSnapshot(TST_DATASET_PATH_SNAP, true, props)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer d.Close()
|
||||||
|
println("PASS\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func zfsTestDatasetDestroy(t *testing.T) {
|
||||||
|
println("TEST DATASET Destroy( ", TST_DATASET_PATH, " ) ... ")
|
||||||
|
d, err := zfs.DatasetOpen(TST_DATASET_PATH)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer d.Close()
|
||||||
|
if err = d.DestroyRecursive(); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
println("PASS\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
// EXAMPLES:
|
||||||
|
|
||||||
|
// Example of creating ZFS volume
|
||||||
|
func ExampleDatasetCreate() {
|
||||||
|
// Create map to represent ZFS dataset properties. This is equivalent to
|
||||||
|
// list of properties you can get from ZFS CLI tool, and some more
|
||||||
|
// internally used by libzfs.
|
||||||
|
props := make(map[zfs.ZFSProp]zfs.Property)
|
||||||
|
|
||||||
|
// I choose to create (block) volume 1GiB in size. Size is just ZFS dataset
|
||||||
|
// property and this is done as map of strings. So, You have to either
|
||||||
|
// specify size as base 10 number in string, or use strconv package or
|
||||||
|
// similar to convert in to string (base 10) from numeric type.
|
||||||
|
strSize := "1073741824"
|
||||||
|
|
||||||
|
props[zfs.ZFSPropVolsize] = zfs.Property{Value: strSize}
|
||||||
|
// In addition I explicitly choose some more properties to be set.
|
||||||
|
props[zfs.ZFSPropVolblocksize] = zfs.Property{Value: "4096"}
|
||||||
|
props[zfs.ZFSPropReservation] = zfs.Property{Value: strSize}
|
||||||
|
|
||||||
|
// Lets create desired volume
|
||||||
|
d, err := zfs.DatasetCreate("TESTPOOL/VOLUME1", zfs.DatasetTypeVolume, props)
|
||||||
|
if err != nil {
|
||||||
|
println(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Dataset have to be closed for memory cleanup
|
||||||
|
defer d.Close()
|
||||||
|
|
||||||
|
println("Created zfs volume TESTPOOL/VOLUME1")
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleDatasetOpen() {
|
||||||
|
// Open dataset and read its available space
|
||||||
|
d, err := zfs.DatasetOpen("TESTPOOL/DATASET1")
|
||||||
|
if err != nil {
|
||||||
|
panic(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer d.Close()
|
||||||
|
var p zfs.Property
|
||||||
|
if p, err = d.GetProperty(zfs.ZFSPropAvailable); err != nil {
|
||||||
|
panic(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
println(d.PropertyToName(zfs.ZFSPropAvailable), " = ", p.Value)
|
||||||
|
}
|
261
zpool_test.go
261
zpool_test.go
|
@ -1,17 +1,17 @@
|
||||||
package zfs
|
package zfs_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/bicomsystems/go-libzfs"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
/* ------------------------------------------------------------------------- */
|
||||||
TST_POOL_NAME = "TESTPOOL"
|
// HELPERS:
|
||||||
TST_DATASET_PATH = "TESTPOOL/DATASET"
|
|
||||||
)
|
var TST_POOL_NAME = "TESTPOOL"
|
||||||
|
|
||||||
func CreateTmpSparse(prefix string, size int64) (path string, err error) {
|
func CreateTmpSparse(prefix string, size int64) (path string, err error) {
|
||||||
sf, err := ioutil.TempFile("/tmp", prefix)
|
sf, err := ioutil.TempFile("/tmp", prefix)
|
||||||
|
@ -26,9 +26,24 @@ func CreateTmpSparse(prefix string, size int64) (path string, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create 3 sparse file 5G in /tmp directory each 5G size, and use them to create mirror TESTPOOL with one spare "disk"
|
/* ------------------------------------------------------------------------- */
|
||||||
func TestPoolCreate(t *testing.T) {
|
// TESTS:
|
||||||
print("TEST PoolCreate ... ")
|
|
||||||
|
// Create 3 sparse file in /tmp directory each 5G size, and use them to create
|
||||||
|
// mirror TESTPOOL with one spare "disk"
|
||||||
|
func zpoolTestPoolCreate(t *testing.T) {
|
||||||
|
println("TEST PoolCreate ... ")
|
||||||
|
// first check if pool with same name already exist
|
||||||
|
// we don't want conflict
|
||||||
|
for {
|
||||||
|
p, err := zfs.PoolOpen(TST_POOL_NAME)
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
p.Close()
|
||||||
|
TST_POOL_NAME += "0"
|
||||||
|
}
|
||||||
|
|
||||||
var s1path, s2path, s3path string
|
var s1path, s2path, s3path string
|
||||||
var err error
|
var err error
|
||||||
if s1path, err = CreateTmpSparse("zfs_test_", 0x140000000); err != nil {
|
if s1path, err = CreateTmpSparse("zfs_test_", 0x140000000); err != nil {
|
||||||
|
@ -50,27 +65,27 @@ func TestPoolCreate(t *testing.T) {
|
||||||
}
|
}
|
||||||
disks := [2]string{s1path, s2path}
|
disks := [2]string{s1path, s2path}
|
||||||
|
|
||||||
var vdevs, mdevs, sdevs []VDevSpec
|
var vdevs, mdevs, sdevs []zfs.VDevSpec
|
||||||
for _, d := range disks {
|
for _, d := range disks {
|
||||||
mdevs = append(mdevs,
|
mdevs = append(mdevs,
|
||||||
VDevSpec{Type: VDevTypeFile, Path: d})
|
zfs.VDevSpec{Type: zfs.VDevTypeFile, Path: d})
|
||||||
}
|
}
|
||||||
sdevs = []VDevSpec{
|
sdevs = []zfs.VDevSpec{
|
||||||
{Type: VDevTypeFile, Path: s3path}}
|
{Type: zfs.VDevTypeFile, Path: s3path}}
|
||||||
vdevs = []VDevSpec{
|
vdevs = []zfs.VDevSpec{
|
||||||
VDevSpec{Type: VDevTypeMirror, Devices: mdevs},
|
zfs.VDevSpec{Type: zfs.VDevTypeMirror, Devices: mdevs},
|
||||||
VDevSpec{Type: VDevTypeSpare, Devices: sdevs},
|
zfs.VDevSpec{Type: zfs.VDevTypeSpare, Devices: sdevs},
|
||||||
}
|
}
|
||||||
|
|
||||||
props := make(map[PoolProp]string)
|
props := make(map[zfs.PoolProp]string)
|
||||||
fsprops := make(map[ZFSProp]string)
|
fsprops := make(map[zfs.ZFSProp]string)
|
||||||
features := make(map[string]string)
|
features := make(map[string]string)
|
||||||
fsprops[ZFSPropMountpoint] = "none"
|
fsprops[zfs.ZFSPropMountpoint] = "none"
|
||||||
features["async_destroy"] = "enabled"
|
features["async_destroy"] = "enabled"
|
||||||
features["empty_bpobj"] = "enabled"
|
features["empty_bpobj"] = "enabled"
|
||||||
features["lz4_compress"] = "enabled"
|
features["lz4_compress"] = "enabled"
|
||||||
|
|
||||||
pool, err := PoolCreate(TST_POOL_NAME, vdevs, features, props, fsprops)
|
pool, err := zfs.PoolCreate(TST_POOL_NAME, vdevs, features, props, fsprops)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
// try cleanup
|
// try cleanup
|
||||||
|
@ -84,15 +99,15 @@ func TestPoolCreate(t *testing.T) {
|
||||||
os.Remove(s1path)
|
os.Remove(s1path)
|
||||||
os.Remove(s2path)
|
os.Remove(s2path)
|
||||||
os.Remove(s3path)
|
os.Remove(s3path)
|
||||||
println("PASS")
|
println("PASS\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open and list all pools and them state on the system
|
// Open and list all pools and them state on the system
|
||||||
// Then list properties of last pool in the list
|
// Then list properties of last pool in the list
|
||||||
func TestPoolOpenAll(t *testing.T) {
|
func zpoolTestPoolOpenAll(t *testing.T) {
|
||||||
println("TEST PoolOpenAll() ... ")
|
println("TEST PoolOpenAll() ... ")
|
||||||
var pname string
|
var pname string
|
||||||
pools, err := PoolOpenAll()
|
pools, err := zfs.PoolOpenAll()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
|
@ -114,123 +129,12 @@ func TestPoolOpenAll(t *testing.T) {
|
||||||
println("\tPool: ", pname, " state: ", pstate)
|
println("\tPool: ", pname, " state: ", pstate)
|
||||||
p.Close()
|
p.Close()
|
||||||
}
|
}
|
||||||
if len(pname) > 0 {
|
println("PASS\n")
|
||||||
// test open on last pool
|
|
||||||
println("\tTry to open pool ", pname)
|
|
||||||
p, err := PoolOpen(pname)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
println("\tOpen pool: ", pname, " success")
|
|
||||||
println("\t", pname, " PROPERTIES:")
|
|
||||||
|
|
||||||
pc, _ := strconv.Atoi(p.Properties[PoolNumProps].Value)
|
|
||||||
if len(p.Properties) != (pc + 1) {
|
|
||||||
p.Close()
|
|
||||||
t.Error(fmt.Sprint("Number of zpool properties does not match ",
|
|
||||||
len(p.Properties), " != ", pc+1))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for key, value := range p.Properties {
|
|
||||||
pkey := PoolProp(key)
|
|
||||||
println("\t\t", p.PropertyToName(pkey), " = ", value.Value, " <- ", value.Source)
|
|
||||||
}
|
|
||||||
for key, value := range p.Features {
|
|
||||||
fmt.Printf("\t feature@%s = %s <- local\n", key, value)
|
|
||||||
}
|
|
||||||
if p.Properties[PoolPropListsnaps].Value == "off" {
|
|
||||||
println("\tlistsnapshots to on")
|
|
||||||
if err = p.SetProperty(PoolPropListsnaps, "on"); err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println("\tlistsnapshots to off")
|
|
||||||
if err = p.SetProperty(PoolPropListsnaps, "off"); err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err == nil {
|
|
||||||
println("\tlistsnapshots", "is changed to ",
|
|
||||||
p.Properties[PoolPropListsnaps].Value, " <- ",
|
|
||||||
p.Properties[PoolPropListsnaps].Source)
|
|
||||||
}
|
|
||||||
p.Close()
|
|
||||||
}
|
|
||||||
println("PASS")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDatasetCreate(t *testing.T) {
|
func zpoolTestPoolDestroy(t *testing.T) {
|
||||||
print("TEST DatasetCreate(", TST_DATASET_PATH, ") ... ")
|
println("TEST POOL Destroy( ", TST_POOL_NAME, " ) ... ")
|
||||||
props := make(map[ZFSProp]Property)
|
p, err := zfs.PoolOpen(TST_POOL_NAME)
|
||||||
d, err := DatasetCreate(TST_DATASET_PATH, DatasetTypeFilesystem, props)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
d.Close()
|
|
||||||
println("PASS")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDatasetOpen(t *testing.T) {
|
|
||||||
print("TEST DatasetOpen(", TST_DATASET_PATH, ") ... ")
|
|
||||||
d, err := DatasetOpen(TST_DATASET_PATH)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
d.Close()
|
|
||||||
println("PASS")
|
|
||||||
}
|
|
||||||
|
|
||||||
func printDatasets(ds []Dataset) error {
|
|
||||||
for _, d := range ds {
|
|
||||||
path, err := d.Path()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
println("\t", path)
|
|
||||||
if len(d.Children) > 0 {
|
|
||||||
printDatasets(d.Children)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDatasetOpenAll(t *testing.T) {
|
|
||||||
println("TEST DatasetOpenAll()/DatasetCloseAll() ... ")
|
|
||||||
ds, err := DatasetOpenAll()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err = printDatasets(ds); err != nil {
|
|
||||||
DatasetCloseAll(ds)
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
DatasetCloseAll(ds)
|
|
||||||
println("PASS")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDatasetDestroy(t *testing.T) {
|
|
||||||
print("TEST DATASET Destroy()", TST_DATASET_PATH, " ... ")
|
|
||||||
d, err := DatasetOpen(TST_DATASET_PATH)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer d.Close()
|
|
||||||
if err = d.Destroy(false); err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
println("PASS")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPoolDestroy(t *testing.T) {
|
|
||||||
print("TEST POOL Destroy()", TST_POOL_NAME, " ... ")
|
|
||||||
p, err := PoolOpen(TST_POOL_NAME)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
|
@ -240,15 +144,15 @@ func TestPoolDestroy(t *testing.T) {
|
||||||
t.Error(err.Error())
|
t.Error(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
println("PASS")
|
println("PASS\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFailPoolOpen(t *testing.T) {
|
func zpoolTestFailPoolOpen(t *testing.T) {
|
||||||
print("TEST failing to open pool ... ")
|
println("TEST open of non existing pool ... ")
|
||||||
pname := "fail to open this pool"
|
pname := "fail to open this pool"
|
||||||
p, err := PoolOpen(pname)
|
p, err := zfs.PoolOpen(pname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
println("PASS")
|
println("PASS\n")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
t.Error("PoolOpen pass when it should fail")
|
t.Error("PoolOpen pass when it should fail")
|
||||||
|
@ -256,19 +160,22 @@ func TestFailPoolOpen(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExamplePoolProp() {
|
func ExamplePoolProp() {
|
||||||
if pool, err := PoolOpen("SSD"); err == nil {
|
if pool, err := zfs.PoolOpen("SSD"); err == nil {
|
||||||
print("Pool size is: ", pool.Properties[PoolPropSize].Value)
|
print("Pool size is: ", pool.Properties[zfs.PoolPropSize].Value)
|
||||||
// Turn on snapshot listing for pool
|
// Turn on snapshot listing for pool
|
||||||
pool.SetProperty(PoolPropListsnaps, "on")
|
pool.SetProperty(zfs.PoolPropListsnaps, "on")
|
||||||
} else {
|
} else {
|
||||||
print("Error: ", err)
|
print("Error: ", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
// EXAMPLES:
|
||||||
|
|
||||||
// Open and list all pools on system with them properties
|
// Open and list all pools on system with them properties
|
||||||
func ExamplePoolOpenAll() {
|
func ExamplePoolOpenAll() {
|
||||||
// Lets open handles to all active pools on system
|
// Lets open handles to all active pools on system
|
||||||
pools, err := PoolOpenAll()
|
pools, err := zfs.PoolOpenAll()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
println(err)
|
println(err)
|
||||||
}
|
}
|
||||||
|
@ -277,15 +184,15 @@ func ExamplePoolOpenAll() {
|
||||||
for _, p := range pools {
|
for _, p := range pools {
|
||||||
// Print fancy header
|
// Print fancy header
|
||||||
fmt.Printf("\n -----------------------------------------------------------\n")
|
fmt.Printf("\n -----------------------------------------------------------\n")
|
||||||
fmt.Printf(" POOL: %49s \n", p.Properties[PoolPropName].Value)
|
fmt.Printf(" POOL: %49s \n", p.Properties[zfs.PoolPropName].Value)
|
||||||
fmt.Printf("|-----------------------------------------------------------|\n")
|
fmt.Printf("|-----------------------------------------------------------|\n")
|
||||||
fmt.Printf("| PROPERTY | VALUE | SOURCE |\n")
|
fmt.Printf("| PROPERTY | VALUE | SOURCE |\n")
|
||||||
fmt.Printf("|-----------------------------------------------------------|\n")
|
fmt.Printf("|-----------------------------------------------------------|\n")
|
||||||
|
|
||||||
// Iterate pool properties and print name, value and source
|
// Iterate pool properties and print name, value and source
|
||||||
for key, prop := range p.Properties {
|
for key, prop := range p.Properties {
|
||||||
pkey := PoolProp(key)
|
pkey := zfs.PoolProp(key)
|
||||||
if pkey == PoolPropName {
|
if pkey == zfs.PoolPropName {
|
||||||
continue // Skip name its already printed above
|
continue // Skip name its already printed above
|
||||||
}
|
}
|
||||||
fmt.Printf("|%14s | %20s | %15s |\n", p.PropertyToName(pkey),
|
fmt.Printf("|%14s | %20s | %15s |\n", p.PropertyToName(pkey),
|
||||||
|
@ -302,33 +209,33 @@ func ExamplePoolOpenAll() {
|
||||||
func ExamplePoolCreate() {
|
func ExamplePoolCreate() {
|
||||||
disks := [2]string{"/dev/disk/by-id/ATA-123", "/dev/disk/by-id/ATA-456"}
|
disks := [2]string{"/dev/disk/by-id/ATA-123", "/dev/disk/by-id/ATA-456"}
|
||||||
|
|
||||||
var vdevs, mdevs, sdevs []VDevSpec
|
var vdevs, mdevs, sdevs []zfs.VDevSpec
|
||||||
|
|
||||||
// build mirror devices specs
|
// build mirror devices specs
|
||||||
for _, d := range disks {
|
for _, d := range disks {
|
||||||
mdevs = append(mdevs,
|
mdevs = append(mdevs,
|
||||||
VDevSpec{Type: VDevTypeDisk, Path: d})
|
zfs.VDevSpec{Type: zfs.VDevTypeDisk, Path: d})
|
||||||
}
|
}
|
||||||
|
|
||||||
// spare device specs
|
// spare device specs
|
||||||
sdevs = []VDevSpec{
|
sdevs = []zfs.VDevSpec{
|
||||||
{Type: VDevTypeDisk, Path: "/dev/disk/by-id/ATA-789"}}
|
{Type: zfs.VDevTypeDisk, Path: "/dev/disk/by-id/ATA-789"}}
|
||||||
|
|
||||||
// pool specs
|
// pool specs
|
||||||
vdevs = []VDevSpec{
|
vdevs = []zfs.VDevSpec{
|
||||||
VDevSpec{Type: VDevTypeMirror, Devices: mdevs},
|
zfs.VDevSpec{Type: zfs.VDevTypeMirror, Devices: mdevs},
|
||||||
VDevSpec{Type: VDevTypeSpare, Devices: sdevs},
|
zfs.VDevSpec{Type: zfs.VDevTypeSpare, Devices: sdevs},
|
||||||
}
|
}
|
||||||
|
|
||||||
// pool properties
|
// pool properties
|
||||||
props := make(map[PoolProp]string)
|
props := make(map[zfs.PoolProp]string)
|
||||||
// root dataset filesystem properties
|
// root dataset filesystem properties
|
||||||
fsprops := make(map[ZFSProp]string)
|
fsprops := make(map[zfs.ZFSProp]string)
|
||||||
// pool features
|
// pool features
|
||||||
features := make(map[string]string)
|
features := make(map[string]string)
|
||||||
|
|
||||||
// Turn off auto mounting by ZFS
|
// Turn off auto mounting by ZFS
|
||||||
fsprops[ZFSPropMountpoint] = "none"
|
fsprops[zfs.ZFSPropMountpoint] = "none"
|
||||||
|
|
||||||
// Enable some features
|
// Enable some features
|
||||||
features["async_destroy"] = "enabled"
|
features["async_destroy"] = "enabled"
|
||||||
|
@ -337,7 +244,7 @@ func ExamplePoolCreate() {
|
||||||
|
|
||||||
// Based on specs formed above create test pool as 2 disk mirror and
|
// Based on specs formed above create test pool as 2 disk mirror and
|
||||||
// one spare disk
|
// one spare disk
|
||||||
pool, err := PoolCreate("TESTPOOL", vdevs, features, props, fsprops)
|
pool, err := zfs.PoolCreate("TESTPOOL", vdevs, features, props, fsprops)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
println("Error: ", err.Error())
|
println("Error: ", err.Error())
|
||||||
return
|
return
|
||||||
|
@ -349,7 +256,7 @@ func ExamplePool_Destroy() {
|
||||||
pname := "TESTPOOL"
|
pname := "TESTPOOL"
|
||||||
|
|
||||||
// Need handle to pool at first place
|
// Need handle to pool at first place
|
||||||
p, err := PoolOpen(pname)
|
p, err := zfs.PoolOpen(pname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
println("Error: ", err.Error())
|
println("Error: ", err.Error())
|
||||||
return
|
return
|
||||||
|
@ -363,33 +270,3 @@ func ExamplePool_Destroy() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Example of creating ZFS volume
|
|
||||||
func ExampleDatasetCreate() {
|
|
||||||
// Create map to represent ZFS dataset properties. This is equivalent to
|
|
||||||
// list of properties you can get from ZFS CLI tool, and some more
|
|
||||||
// internally used by libzfs.
|
|
||||||
props := make(map[ZFSProp]Property)
|
|
||||||
|
|
||||||
// I choose to create (block) volume 1GiB in size. Size is just ZFS dataset
|
|
||||||
// property and this is done as map of strings. So, You have to either
|
|
||||||
// specify size as base 10 number in string, or use strconv package or
|
|
||||||
// similar to convert in to string (base 10) from numeric type.
|
|
||||||
strSize := "1073741824"
|
|
||||||
|
|
||||||
props[ZFSPropVolsize] = Property{Value: strSize}
|
|
||||||
// In addition I explicitly choose some more properties to be set.
|
|
||||||
props[ZFSPropVolblocksize] = Property{Value: "4096"}
|
|
||||||
props[ZFSPropReservation] = Property{Value: strSize}
|
|
||||||
|
|
||||||
// Lets create desired volume
|
|
||||||
d, err := DatasetCreate("TESTPOOL/VOLUME1", DatasetTypeVolume, props)
|
|
||||||
if err != nil {
|
|
||||||
println(err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Dataset have to be closed for memory cleanup
|
|
||||||
defer d.Close()
|
|
||||||
|
|
||||||
println("Created zfs volume TESTPOOL/VOLUME1")
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue