- Implemented: Search pools available to import but not imported AND Fetch imported pool's current vdev tree
This commit is contained in:
parent
4f32480fa0
commit
b49a2715c2
|
@ -9,7 +9,9 @@ import (
|
|||
|
||||
func Test(t *testing.T) {
|
||||
zpoolTestPoolCreate(t)
|
||||
zpoolTestPoolVDevTree(t)
|
||||
zpoolTestExport(t)
|
||||
zpoolTestPoolImportSearch(t)
|
||||
zpoolTestImport(t)
|
||||
zpoolTestExportForce(t)
|
||||
zpoolTestImportByGUID(t)
|
||||
|
|
40
common.go
40
common.go
|
@ -57,6 +57,12 @@ type PoolStatus int
|
|||
// PoolState type representing pool state
|
||||
type PoolState uint64
|
||||
|
||||
// VDevState - vdev states tye
|
||||
type VDevState uint64
|
||||
|
||||
// VDevAux - vdev aux states
|
||||
type VDevAux uint64
|
||||
|
||||
// Property ZFS pool or dataset property value
|
||||
type Property struct {
|
||||
Value string
|
||||
|
@ -346,3 +352,37 @@ const (
|
|||
EPoolreadonly /* pool is in read-only mode */
|
||||
EUnknown
|
||||
)
|
||||
|
||||
// vdev states are ordered from least to most healthy.
|
||||
// A vdev that's VDevStateCantOpen or below is considered unusable.
|
||||
const (
|
||||
VDevStateUnknown VDevState = iota // Uninitialized vdev
|
||||
VDevStateClosed // Not currently open
|
||||
VDevStateOffline // Not allowed to open
|
||||
VDevStateRemoved // Explicitly removed from system
|
||||
VDevStateCantOpen // Tried to open, but failed
|
||||
VDevStateFaulted // External request to fault device
|
||||
VDevStateDegraded // Replicated vdev with unhealthy kids
|
||||
VDevStateHealthy // Presumed good
|
||||
)
|
||||
|
||||
// vdev aux states. When a vdev is in the VDevStateCantOpen state, the aux field
|
||||
// of the vdev stats structure uses these constants to distinguish why.
|
||||
const (
|
||||
VDevAuxNone VDevAux = iota // no error
|
||||
VDevAuxOpenFailed // ldi_open_*() or vn_open() failed
|
||||
VDevAuxCorruptData // bad label or disk contents
|
||||
VDevAuxNoReplicas // insufficient number of replicas
|
||||
VDevAuxBadGUIDSum // vdev guid sum doesn't match
|
||||
VDevAuxTooSmall // vdev size is too small
|
||||
VDevAuxBadLabel // the label is OK but invalid
|
||||
VDevAuxVersionNewer // on-disk version is too new
|
||||
VDevAuxVersionOlder // on-disk version is too old
|
||||
VDevAuxUnsupFeat // unsupported features
|
||||
VDevAuxSpared // hot spare used in another pool
|
||||
VDevAuxErrExceeded // too many errors
|
||||
VDevAuxIOFailure // experienced I/O failure
|
||||
VDevAuxBadLog // cannot read log chain(s)
|
||||
VDevAuxExternal // external diagnosis
|
||||
VDevAuxSplitPool // vdev was split off into another pool
|
||||
)
|
||||
|
|
14
zpool.c
14
zpool.c
|
@ -366,6 +366,16 @@ add_prop_list(const char *propname, char *propval, nvlist_t **props,
|
|||
return (0);
|
||||
}
|
||||
|
||||
int nvlist_lookup_uint64_array_vds(nvlist_t *nv, const char *p,
|
||||
vdev_stat_t **vds, uint_t *c) {
|
||||
return nvlist_lookup_uint64_array(nv, p, (uint64_t**)vds, c);
|
||||
}
|
||||
|
||||
int nvlist_lookup_uint64_array_ps(nvlist_t *nv, const char *p,
|
||||
pool_scan_stat_t **vds, uint_t *c) {
|
||||
return nvlist_lookup_uint64_array(nv, p, (uint64_t**)vds, c);
|
||||
}
|
||||
|
||||
nvlist_t** nvlist_alloc_array(int count) {
|
||||
return malloc(count*sizeof(nvlist_t*));
|
||||
}
|
||||
|
@ -381,3 +391,7 @@ void nvlist_free_array(nvlist_t **a) {
|
|||
void free_cstring(char *str) {
|
||||
free(str);
|
||||
}
|
||||
|
||||
nvlist_t *nvlist_array_at(nvlist_t **a, uint_t i) {
|
||||
return a[i];
|
||||
}
|
||||
|
|
333
zpool.go
333
zpool.go
|
@ -20,12 +20,94 @@ const (
|
|||
// PoolProperties type is map of pool properties name -> value
|
||||
type PoolProperties map[Prop]string
|
||||
|
||||
/*
|
||||
* ZIO types. Needed to interpret vdev statistics below.
|
||||
*/
|
||||
const (
|
||||
ZIOTypeNull = iota
|
||||
ZIOTypeRead
|
||||
ZIOTypeWrite
|
||||
ZIOTypeFree
|
||||
ZIOTypeClaim
|
||||
ZIOTypeIOCtl
|
||||
ZIOTypes
|
||||
)
|
||||
|
||||
// Scan states
|
||||
const (
|
||||
DSSNone = iota // No scan
|
||||
DSSScanning // Scanning
|
||||
DSSFinished // Scan finished
|
||||
DSSCanceled // Scan canceled
|
||||
DSSNumStates // Total number of scan states
|
||||
)
|
||||
|
||||
// Scan functions
|
||||
const (
|
||||
PoolScanNone = iota // No scan function
|
||||
PoolScanScrub // Pools is checked against errors
|
||||
PoolScanResilver // Pool is resilvering
|
||||
PoolScanFuncs // Number of scan functions
|
||||
)
|
||||
|
||||
// VDevStat - Vdev statistics. Note: all fields should be 64-bit because this
|
||||
// is passed between kernel and userland as an nvlist uint64 array.
|
||||
type VDevStat struct {
|
||||
Timestamp time.Duration /* time since vdev load (nanoseconds)*/
|
||||
State VDevState /* vdev state */
|
||||
Aux VDevAux /* see vdev_aux_t */
|
||||
Alloc uint64 /* space allocated */
|
||||
Space uint64 /* total capacity */
|
||||
DSpace uint64 /* deflated capacity */
|
||||
RSize uint64 /* replaceable dev size */
|
||||
ESize uint64 /* expandable dev size */
|
||||
Ops [ZIOTypes]uint64 /* operation count */
|
||||
Bytes [ZIOTypes]uint64 /* bytes read/written */
|
||||
ReadErrors uint64 /* read errors */
|
||||
WriteErrors uint64 /* write errors */
|
||||
ChecksumErrors uint64 /* checksum errors */
|
||||
SelfHealed uint64 /* self-healed bytes */
|
||||
ScanRemoving uint64 /* removing? */
|
||||
ScanProcessed uint64 /* scan processed bytes */
|
||||
Fragmentation uint64 /* device fragmentation */
|
||||
}
|
||||
|
||||
// PoolScanStat - Pool scan statistics
|
||||
type PoolScanStat struct {
|
||||
// Values stored on disk
|
||||
Func uint64 // Current scan function e.g. none, scrub ...
|
||||
State uint64 // Current scan state e.g. scanning, finished ...
|
||||
StartTime uint64 // Scan start time
|
||||
EndTime uint64 // Scan end time
|
||||
ToExamine uint64 // Total bytes to scan
|
||||
Examined uint64 // Total bytes scaned
|
||||
ToProcess uint64 // Total bytes to processed
|
||||
Processed uint64 // Total bytes processed
|
||||
Errors uint64 // Scan errors
|
||||
// Values not stored on disk
|
||||
PassExam uint64 // Examined bytes per scan pass
|
||||
PassStart uint64 // Start time of scan pass
|
||||
}
|
||||
|
||||
// VDevTree ZFS virtual device tree
|
||||
type VDevTree struct {
|
||||
Type VDevType
|
||||
Devices []VDevTree // groups other devices (e.g. mirror)
|
||||
Parity uint
|
||||
Path string
|
||||
Type VDevType
|
||||
Devices []VDevTree // groups other devices (e.g. mirror)
|
||||
Parity uint
|
||||
Path string
|
||||
Name string
|
||||
Stat VDevStat
|
||||
ScanStat PoolScanStat
|
||||
}
|
||||
|
||||
// ExportedPool is type representing ZFS pool available for import
|
||||
type ExportedPool struct {
|
||||
VDevs VDevTree
|
||||
Name string
|
||||
Comment string
|
||||
GUID uint64
|
||||
State PoolState
|
||||
Status PoolStatus
|
||||
}
|
||||
|
||||
// Pool object represents handler to single ZFS pool
|
||||
|
@ -56,6 +138,164 @@ func PoolOpen(name string) (pool Pool, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func poolGetConfig(name string, nv *C.nvlist_t) (vdevs VDevTree, err error) {
|
||||
var dtype *C.char
|
||||
var c, children C.uint_t
|
||||
var notpresent C.uint64_t
|
||||
var vs *C.vdev_stat_t
|
||||
var ps *C.pool_scan_stat_t
|
||||
var child **C.nvlist_t
|
||||
var vdev VDevTree
|
||||
if 0 != C.nvlist_lookup_string(nv, C.CString(C.ZPOOL_CONFIG_TYPE), &dtype) {
|
||||
err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_TYPE)
|
||||
return
|
||||
}
|
||||
vdevs.Name = name
|
||||
vdevs.Type = VDevType(C.GoString(dtype))
|
||||
if vdevs.Type == VDevTypeMissing || vdevs.Type == VDevTypeHole {
|
||||
return
|
||||
}
|
||||
|
||||
// Fetch vdev state
|
||||
if 0 != C.nvlist_lookup_uint64_array_vds(nv, C.CString(C.ZPOOL_CONFIG_VDEV_STATS),
|
||||
&vs, &c) {
|
||||
err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_VDEV_STATS)
|
||||
return
|
||||
}
|
||||
vdevs.Stat.Timestamp = time.Duration(vs.vs_timestamp)
|
||||
vdevs.Stat.State = VDevState(vs.vs_state)
|
||||
vdevs.Stat.Aux = VDevAux(vs.vs_aux)
|
||||
vdevs.Stat.Alloc = uint64(vs.vs_alloc)
|
||||
vdevs.Stat.Space = uint64(vs.vs_space)
|
||||
vdevs.Stat.DSpace = uint64(vs.vs_dspace)
|
||||
vdevs.Stat.RSize = uint64(vs.vs_rsize)
|
||||
vdevs.Stat.ESize = uint64(vs.vs_esize)
|
||||
for z := 0; z < ZIOTypes; z++ {
|
||||
vdev.Stat.Ops[z] = uint64(vs.vs_ops[z])
|
||||
vdev.Stat.Bytes[z] = uint64(vs.vs_bytes[z])
|
||||
}
|
||||
vdevs.Stat.ReadErrors = uint64(vs.vs_read_errors)
|
||||
vdevs.Stat.WriteErrors = uint64(vs.vs_write_errors)
|
||||
vdevs.Stat.ChecksumErrors = uint64(vs.vs_checksum_errors)
|
||||
vdevs.Stat.SelfHealed = uint64(vs.vs_self_healed)
|
||||
vdevs.Stat.ScanRemoving = uint64(vs.vs_scan_removing)
|
||||
vdevs.Stat.ScanProcessed = uint64(vs.vs_scan_processed)
|
||||
vdevs.Stat.Fragmentation = uint64(vs.vs_fragmentation)
|
||||
|
||||
// Fetch vdev scan stats
|
||||
if 0 == C.nvlist_lookup_uint64_array_ps(nv, C.CString(C.ZPOOL_CONFIG_SCAN_STATS),
|
||||
&ps, &c) {
|
||||
vdevs.ScanStat.Func = uint64(ps.pss_func)
|
||||
vdevs.ScanStat.State = uint64(ps.pss_state)
|
||||
vdevs.ScanStat.StartTime = uint64(ps.pss_start_time)
|
||||
vdevs.ScanStat.EndTime = uint64(ps.pss_end_time)
|
||||
vdevs.ScanStat.ToExamine = uint64(ps.pss_to_examine)
|
||||
vdevs.ScanStat.Examined = uint64(ps.pss_examined)
|
||||
vdevs.ScanStat.ToProcess = uint64(ps.pss_to_process)
|
||||
vdevs.ScanStat.Processed = uint64(ps.pss_processed)
|
||||
vdevs.ScanStat.Errors = uint64(ps.pss_errors)
|
||||
vdevs.ScanStat.PassExam = uint64(ps.pss_pass_exam)
|
||||
vdevs.ScanStat.PassStart = uint64(ps.pss_pass_start)
|
||||
}
|
||||
|
||||
// Fetch the children
|
||||
if C.nvlist_lookup_nvlist_array(nv, C.CString(C.ZPOOL_CONFIG_CHILDREN),
|
||||
&child, &children) != 0 {
|
||||
return
|
||||
}
|
||||
if children > 0 {
|
||||
vdevs.Devices = make([]VDevTree, 0, children)
|
||||
}
|
||||
if C.nvlist_lookup_uint64(nv, C.CString(C.ZPOOL_CONFIG_NOT_PRESENT),
|
||||
¬present) == 0 {
|
||||
var path *C.char
|
||||
if 0 != C.nvlist_lookup_string(nv, C.CString(C.ZPOOL_CONFIG_PATH), &path) {
|
||||
err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_PATH)
|
||||
return
|
||||
}
|
||||
vdevs.Path = C.GoString(path)
|
||||
}
|
||||
for c = 0; c < children; c++ {
|
||||
var islog = C.uint64_t(C.B_FALSE)
|
||||
|
||||
C.nvlist_lookup_uint64(C.nvlist_array_at(child, c),
|
||||
C.CString(C.ZPOOL_CONFIG_IS_LOG), &islog)
|
||||
if islog != C.B_FALSE {
|
||||
continue
|
||||
}
|
||||
vname := C.zpool_vdev_name(libzfsHandle, nil, C.nvlist_array_at(child, c),
|
||||
C.B_TRUE)
|
||||
vdev, err = poolGetConfig(C.GoString(vname),
|
||||
C.nvlist_array_at(child, c))
|
||||
C.free_cstring(vname)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
vdevs.Devices = append(vdevs.Devices, vdev)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// PoolImportSearch - Search pools available to import but not imported.
|
||||
// Returns array of found pools.
|
||||
func PoolImportSearch(searchpaths []string) (epools []ExportedPool, err error) {
|
||||
var config, nvroot *C.nvlist_t
|
||||
var cname, msgid, comment *C.char
|
||||
var poolState, guid C.uint64_t
|
||||
var reason C.zpool_status_t
|
||||
var errata C.zpool_errata_t
|
||||
config = nil
|
||||
var elem *C.nvpair_t
|
||||
numofp := len(searchpaths)
|
||||
cpaths := C.alloc_strings(C.int(numofp))
|
||||
for i, path := range searchpaths {
|
||||
C.strings_setat(cpaths, C.int(i), C.CString(path))
|
||||
}
|
||||
|
||||
pools := C.zpool_find_import(libzfsHandle, C.int(numofp), cpaths)
|
||||
defer C.nvlist_free(pools)
|
||||
elem = C.nvlist_next_nvpair(pools, elem)
|
||||
epools = make([]ExportedPool, 0, 1)
|
||||
for ; elem != nil; elem = C.nvlist_next_nvpair(pools, elem) {
|
||||
ep := ExportedPool{}
|
||||
if C.nvpair_value_nvlist(elem, &config) != 0 {
|
||||
err = LastError()
|
||||
return
|
||||
}
|
||||
if C.nvlist_lookup_uint64(config, C.CString(C.ZPOOL_CONFIG_POOL_STATE),
|
||||
&poolState) != 0 {
|
||||
err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_POOL_STATE)
|
||||
return
|
||||
}
|
||||
ep.State = PoolState(poolState)
|
||||
if C.nvlist_lookup_string(config, C.CString(C.ZPOOL_CONFIG_POOL_NAME), &cname) != 0 {
|
||||
err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_POOL_NAME)
|
||||
return
|
||||
}
|
||||
ep.Name = C.GoString(cname)
|
||||
if C.nvlist_lookup_uint64(config, C.CString(C.ZPOOL_CONFIG_POOL_GUID), &guid) != 0 {
|
||||
err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_POOL_GUID)
|
||||
return
|
||||
}
|
||||
ep.GUID = uint64(guid)
|
||||
reason = C.zpool_import_status(config, &msgid, &errata)
|
||||
ep.Status = PoolStatus(reason)
|
||||
|
||||
if C.nvlist_lookup_string(config, C.CString(C.ZPOOL_CONFIG_COMMENT), &comment) == 0 {
|
||||
ep.Comment = C.GoString(comment)
|
||||
}
|
||||
|
||||
if C.nvlist_lookup_nvlist(config, C.CString(C.ZPOOL_CONFIG_VDEV_TREE),
|
||||
&nvroot) != 0 {
|
||||
err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_VDEV_TREE)
|
||||
return
|
||||
}
|
||||
ep.VDevs, err = poolGetConfig(ep.Name, nvroot)
|
||||
epools = append(epools, ep)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func poolSearchImport(q string, searchpaths []string, guid bool) (name string,
|
||||
err error) {
|
||||
var config *C.nvlist_t
|
||||
|
@ -583,23 +823,8 @@ func PoolCreate(name string, vdevs []VDevTree, features map[string]string,
|
|||
return
|
||||
}
|
||||
|
||||
// It can happen that pool is not immediately available,
|
||||
// we know we just created it with success so lets wait and retry
|
||||
// but only in case EZFS_NOENT error
|
||||
retr := 0
|
||||
for pool, err = PoolOpen(name); err != nil && retr < 3; retr++ {
|
||||
errno := C.libzfs_errno(libzfsHandle)
|
||||
if errno == ENoent {
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
} else {
|
||||
err = errors.New(err.Error() + " (PoolOpen)")
|
||||
return
|
||||
}
|
||||
pool, err = PoolOpen(name)
|
||||
}
|
||||
if err != nil {
|
||||
err = errors.New(err.Error() + " (PoolOpen)")
|
||||
}
|
||||
// Open created pool and return handle
|
||||
pool, err = PoolOpen(name)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -654,3 +879,69 @@ func (pool *Pool) ExportForce(log string) (err error) {
|
|||
}
|
||||
return
|
||||
}
|
||||
|
||||
// VDevTree - Fetch pool's current vdev tree configuration, state and stats
|
||||
func (pool *Pool) VDevTree() (vdevs VDevTree, err error) {
|
||||
var nvroot *C.nvlist_t
|
||||
var poolName string
|
||||
config := C.zpool_get_config(pool.list.zph, nil)
|
||||
if config == nil {
|
||||
err = fmt.Errorf("Failed zpool_get_config")
|
||||
return
|
||||
}
|
||||
if C.nvlist_lookup_nvlist(config, C.CString(C.ZPOOL_CONFIG_VDEV_TREE),
|
||||
&nvroot) != 0 {
|
||||
err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_VDEV_TREE)
|
||||
return
|
||||
}
|
||||
if poolName, err = pool.Name(); err != nil {
|
||||
return
|
||||
}
|
||||
return poolGetConfig(poolName, nvroot)
|
||||
}
|
||||
|
||||
func (s PoolState) String() string {
|
||||
switch s {
|
||||
case PoolStateActive:
|
||||
return "ACTIVE"
|
||||
case PoolStateExported:
|
||||
return "EXPORTED"
|
||||
case PoolStateDestroyed:
|
||||
return "DESTROYED"
|
||||
case PoolStateSpare:
|
||||
return "SPARE"
|
||||
case PoolStateL2cache:
|
||||
return "L2CACHE"
|
||||
case PoolStateUninitialized:
|
||||
return "UNINITIALIZED"
|
||||
case PoolStateUnavail:
|
||||
return "UNAVAILABLE"
|
||||
case PoolStatePotentiallyActive:
|
||||
return "POTENTIALLYACTIVE"
|
||||
default:
|
||||
return "UNKNOWN"
|
||||
}
|
||||
}
|
||||
|
||||
func (s VDevState) String() string {
|
||||
switch s {
|
||||
case VDevStateUnknown:
|
||||
return "UNINITIALIZED"
|
||||
case VDevStateClosed:
|
||||
return "CLOSED"
|
||||
case VDevStateOffline:
|
||||
return "OFFLINE"
|
||||
case VDevStateRemoved:
|
||||
return "REMOVED"
|
||||
case VDevStateCantOpen:
|
||||
return "CANT_OPEN"
|
||||
case VDevStateFaulted:
|
||||
return "FAULTED"
|
||||
case VDevStateDegraded:
|
||||
return "DEGRADED"
|
||||
case VDevStateHealthy:
|
||||
return "ONLINE"
|
||||
default:
|
||||
return "UNKNOWN"
|
||||
}
|
||||
}
|
||||
|
|
7
zpool.h
7
zpool.h
|
@ -50,9 +50,16 @@ add_prop_list(const char *propname, char *propval, nvlist_t **props,
|
|||
nvlist_t** nvlist_alloc_array(int count);
|
||||
void nvlist_array_set(nvlist_t** a, int i, nvlist_t *item);
|
||||
void nvlist_free_array(nvlist_t **a);
|
||||
nvlist_t *nvlist_array_at(nvlist_t **a, uint_t i);
|
||||
|
||||
|
||||
void free_cstring(char *str);
|
||||
|
||||
int nvlist_lookup_uint64_array_vds(nvlist_t *nv, const char *p,
|
||||
vdev_stat_t **vds, uint_t *c);
|
||||
|
||||
int nvlist_lookup_uint64_array_ps(nvlist_t *nv, const char *p,
|
||||
pool_scan_stat_t **vds, uint_t *c);
|
||||
|
||||
#endif
|
||||
/* SERVERWARE_ZPOOL_H */
|
||||
|
|
|
@ -224,6 +224,36 @@ func zpoolTestImportByGUID(t *testing.T) {
|
|||
print("PASS\n\n")
|
||||
}
|
||||
|
||||
func printVDevTree(vt zfs.VDevTree, pref string) {
|
||||
first := pref + vt.Name
|
||||
fmt.Printf("%-30s | %-10s | %-10s | %s\n", first, vt.Type,
|
||||
vt.Stat.State.String(), vt.Path)
|
||||
for _, v := range vt.Devices {
|
||||
printVDevTree(v, " "+pref)
|
||||
}
|
||||
}
|
||||
|
||||
func zpoolTestPoolImportSearch(t *testing.T) {
|
||||
println("TEST PoolImportSearch")
|
||||
pools, err := zfs.PoolImportSearch([]string{"/tmp"})
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
return
|
||||
}
|
||||
for _, p := range pools {
|
||||
println()
|
||||
println("---------------------------------------------------------------")
|
||||
println("pool: ", p.Name)
|
||||
println("guid: ", p.GUID)
|
||||
println("state: ", p.State.String())
|
||||
fmt.Printf("%-30s | %-10s | %-10s | %s\n", "NAME", "TYPE", "STATE", "PATH")
|
||||
println("---------------------------------------------------------------")
|
||||
printVDevTree(p.VDevs, "")
|
||||
|
||||
}
|
||||
print("PASS\n\n")
|
||||
}
|
||||
|
||||
func zpoolTestPoolProp(t *testing.T) {
|
||||
println("TEST PoolProp on ", TSTPoolName, " ... ")
|
||||
if pool, err := zfs.PoolOpen(TSTPoolName); err == nil {
|
||||
|
@ -237,11 +267,19 @@ func zpoolTestPoolProp(t *testing.T) {
|
|||
}
|
||||
|
||||
// Test fetching property
|
||||
_, err := pool.GetProperty(zfs.PoolPropHealth)
|
||||
propHealth, err := pool.GetProperty(zfs.PoolPropHealth)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
println("Pool property health: ", propHealth.Value)
|
||||
|
||||
propGUID, err := pool.GetProperty(zfs.PoolPropGUID)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
println("Pool property GUID: ", propGUID.Value)
|
||||
|
||||
// this test pool should not be bootable
|
||||
prop, err := pool.GetProperty(zfs.PoolPropBootfs)
|
||||
|
@ -290,6 +328,26 @@ func zpoolTestPoolStatusAndState(t *testing.T) {
|
|||
print("PASS\n\n")
|
||||
}
|
||||
|
||||
func zpoolTestPoolVDevTree(t *testing.T) {
|
||||
var vdevs zfs.VDevTree
|
||||
println("TEST pool VDevTree ( ", TSTPoolName, " ) ... ")
|
||||
pool, err := zfs.PoolOpen(TSTPoolName)
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
return
|
||||
}
|
||||
defer pool.Close()
|
||||
vdevs, err = pool.VDevTree()
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
return
|
||||
}
|
||||
fmt.Printf("%-30s | %-10s | %-10s | %s\n", "NAME", "TYPE", "STATE", "PATH")
|
||||
println("---------------------------------------------------------------")
|
||||
printVDevTree(vdevs, "")
|
||||
print("PASS\n\n")
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
// EXAMPLES:
|
||||
|
||||
|
|
Loading…
Reference in New Issue