- 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) {
|
func Test(t *testing.T) {
|
||||||
zpoolTestPoolCreate(t)
|
zpoolTestPoolCreate(t)
|
||||||
|
zpoolTestPoolVDevTree(t)
|
||||||
zpoolTestExport(t)
|
zpoolTestExport(t)
|
||||||
|
zpoolTestPoolImportSearch(t)
|
||||||
zpoolTestImport(t)
|
zpoolTestImport(t)
|
||||||
zpoolTestExportForce(t)
|
zpoolTestExportForce(t)
|
||||||
zpoolTestImportByGUID(t)
|
zpoolTestImportByGUID(t)
|
||||||
|
|
40
common.go
40
common.go
|
@ -57,6 +57,12 @@ type PoolStatus int
|
||||||
// PoolState type representing pool state
|
// PoolState type representing pool state
|
||||||
type PoolState uint64
|
type PoolState uint64
|
||||||
|
|
||||||
|
// VDevState - vdev states tye
|
||||||
|
type VDevState uint64
|
||||||
|
|
||||||
|
// VDevAux - vdev aux states
|
||||||
|
type VDevAux uint64
|
||||||
|
|
||||||
// Property ZFS pool or dataset property value
|
// Property ZFS pool or dataset property value
|
||||||
type Property struct {
|
type Property struct {
|
||||||
Value string
|
Value string
|
||||||
|
@ -346,3 +352,37 @@ const (
|
||||||
EPoolreadonly /* pool is in read-only mode */
|
EPoolreadonly /* pool is in read-only mode */
|
||||||
EUnknown
|
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);
|
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) {
|
nvlist_t** nvlist_alloc_array(int count) {
|
||||||
return malloc(count*sizeof(nvlist_t*));
|
return malloc(count*sizeof(nvlist_t*));
|
||||||
}
|
}
|
||||||
|
@ -381,3 +391,7 @@ void nvlist_free_array(nvlist_t **a) {
|
||||||
void free_cstring(char *str) {
|
void free_cstring(char *str) {
|
||||||
free(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
|
// PoolProperties type is map of pool properties name -> value
|
||||||
type PoolProperties map[Prop]string
|
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
|
// VDevTree ZFS virtual device tree
|
||||||
type VDevTree struct {
|
type VDevTree struct {
|
||||||
Type VDevType
|
Type VDevType
|
||||||
Devices []VDevTree // groups other devices (e.g. mirror)
|
Devices []VDevTree // groups other devices (e.g. mirror)
|
||||||
Parity uint
|
Parity uint
|
||||||
Path string
|
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
|
// Pool object represents handler to single ZFS pool
|
||||||
|
@ -56,6 +138,164 @@ func PoolOpen(name string) (pool Pool, err error) {
|
||||||
return
|
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,
|
func poolSearchImport(q string, searchpaths []string, guid bool) (name string,
|
||||||
err error) {
|
err error) {
|
||||||
var config *C.nvlist_t
|
var config *C.nvlist_t
|
||||||
|
@ -583,23 +823,8 @@ func PoolCreate(name string, vdevs []VDevTree, features map[string]string,
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// It can happen that pool is not immediately available,
|
// Open created pool and return handle
|
||||||
// we know we just created it with success so lets wait and retry
|
pool, err = PoolOpen(name)
|
||||||
// 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)")
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -654,3 +879,69 @@ func (pool *Pool) ExportForce(log string) (err error) {
|
||||||
}
|
}
|
||||||
return
|
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);
|
nvlist_t** nvlist_alloc_array(int count);
|
||||||
void nvlist_array_set(nvlist_t** a, int i, nvlist_t *item);
|
void nvlist_array_set(nvlist_t** a, int i, nvlist_t *item);
|
||||||
void nvlist_free_array(nvlist_t **a);
|
void nvlist_free_array(nvlist_t **a);
|
||||||
|
nvlist_t *nvlist_array_at(nvlist_t **a, uint_t i);
|
||||||
|
|
||||||
|
|
||||||
void free_cstring(char *str);
|
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
|
#endif
|
||||||
/* SERVERWARE_ZPOOL_H */
|
/* SERVERWARE_ZPOOL_H */
|
||||||
|
|
|
@ -224,6 +224,36 @@ func zpoolTestImportByGUID(t *testing.T) {
|
||||||
print("PASS\n\n")
|
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) {
|
func zpoolTestPoolProp(t *testing.T) {
|
||||||
println("TEST PoolProp on ", TSTPoolName, " ... ")
|
println("TEST PoolProp on ", TSTPoolName, " ... ")
|
||||||
if pool, err := zfs.PoolOpen(TSTPoolName); err == nil {
|
if pool, err := zfs.PoolOpen(TSTPoolName); err == nil {
|
||||||
|
@ -237,11 +267,19 @@ func zpoolTestPoolProp(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test fetching property
|
// Test fetching property
|
||||||
_, err := pool.GetProperty(zfs.PoolPropHealth)
|
propHealth, err := pool.GetProperty(zfs.PoolPropHealth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
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
|
// this test pool should not be bootable
|
||||||
prop, err := pool.GetProperty(zfs.PoolPropBootfs)
|
prop, err := pool.GetProperty(zfs.PoolPropBootfs)
|
||||||
|
@ -290,6 +328,26 @@ func zpoolTestPoolStatusAndState(t *testing.T) {
|
||||||
print("PASS\n\n")
|
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:
|
// EXAMPLES:
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue