JSON output support for zpool list
This commit adds support for zpool list command to output the list of ZFS pools in JSON format using '-j' option.. Information about available pools is collected in nvlist which is later printed to stdout in JSON format. Existing options for zfs list command work with '-j' flag. man page for zpool list is updated accordingly. Reviewed-by: Tony Hutter <hutter2@llnl.gov> Reviewed-by: Ameer Hamza <ahamza@ixsystems.com> Signed-off-by: Umer Saleem <usaleem@ixsystems.com> Closes #16217
This commit is contained in:
parent
eb2b824bde
commit
4e6b3f7e1d
|
@ -403,8 +403,8 @@ get_usage(zpool_help_t idx)
|
|||
return (gettext("\tlabelclear [-f] <vdev>\n"));
|
||||
case HELP_LIST:
|
||||
return (gettext("\tlist [-gHLpPv] [-o property[,...]] "
|
||||
"[-T d|u] [pool] ... \n"
|
||||
"\t [interval [count]]\n"));
|
||||
"[-j [--json-int, --json-pool-key-guid]]\n"
|
||||
"\t [-T d|u] [pool] [interval [count]]\n"));
|
||||
case HELP_PREFETCH:
|
||||
return (gettext("\tprefetch -t <type> [<type opts>] <pool>\n"
|
||||
"\t -t ddt <pool>\n"));
|
||||
|
@ -968,13 +968,14 @@ fill_pool_info(nvlist_t *list, zpool_handle_t *zhp, boolean_t addtype,
|
|||
|
||||
static void
|
||||
fill_vdev_info(nvlist_t *list, zpool_handle_t *zhp, char *name,
|
||||
boolean_t as_int)
|
||||
boolean_t addtype, boolean_t as_int)
|
||||
{
|
||||
boolean_t spare, l2c, log;
|
||||
const char *path, *phys, *devid;
|
||||
nvlist_t *nvdev = zpool_find_vdev(zhp, name, &spare, &l2c, &log);
|
||||
|
||||
fnvlist_add_string(list, "name", name);
|
||||
if (addtype)
|
||||
fnvlist_add_string(list, "type", "VDEV");
|
||||
if (nvdev) {
|
||||
const char *type = fnvlist_lookup_string(nvdev,
|
||||
|
@ -6483,9 +6484,13 @@ typedef struct list_cbdata {
|
|||
boolean_t cb_verbose;
|
||||
int cb_name_flags;
|
||||
int cb_namewidth;
|
||||
boolean_t cb_json;
|
||||
boolean_t cb_scripted;
|
||||
zprop_list_t *cb_proplist;
|
||||
boolean_t cb_literal;
|
||||
nvlist_t *cb_jsobj;
|
||||
boolean_t cb_json_as_int;
|
||||
boolean_t cb_json_pool_key_guid;
|
||||
} list_cbdata_t;
|
||||
|
||||
|
||||
|
@ -6546,7 +6551,7 @@ print_header(list_cbdata_t *cb)
|
|||
* to the described layout. Used by zpool_do_list().
|
||||
*/
|
||||
static void
|
||||
print_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
|
||||
collect_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
|
||||
{
|
||||
zprop_list_t *pl = cb->cb_proplist;
|
||||
boolean_t first = B_TRUE;
|
||||
|
@ -6554,6 +6559,20 @@ print_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
|
|||
const char *propstr;
|
||||
boolean_t right_justify;
|
||||
size_t width;
|
||||
zprop_source_t sourcetype = ZPROP_SRC_NONE;
|
||||
nvlist_t *item, *d, *props;
|
||||
item = d = props = NULL;
|
||||
|
||||
if (cb->cb_json) {
|
||||
item = fnvlist_alloc();
|
||||
props = fnvlist_alloc();
|
||||
d = fnvlist_lookup_nvlist(cb->cb_jsobj, "pools");
|
||||
if (d == NULL) {
|
||||
fprintf(stderr, "pools obj not found.\n");
|
||||
exit(1);
|
||||
}
|
||||
fill_pool_info(item, zhp, B_TRUE, cb->cb_json_as_int);
|
||||
}
|
||||
|
||||
for (; pl != NULL; pl = pl->pl_next) {
|
||||
|
||||
|
@ -6566,7 +6585,7 @@ print_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
|
|||
width = cb->cb_namewidth;
|
||||
}
|
||||
|
||||
if (!first) {
|
||||
if (!cb->cb_json && !first) {
|
||||
if (cb->cb_scripted)
|
||||
(void) fputc('\t', stdout);
|
||||
else
|
||||
|
@ -6578,7 +6597,8 @@ print_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
|
|||
right_justify = B_FALSE;
|
||||
if (pl->pl_prop != ZPROP_USERPROP) {
|
||||
if (zpool_get_prop(zhp, pl->pl_prop, property,
|
||||
sizeof (property), NULL, cb->cb_literal) != 0)
|
||||
sizeof (property), &sourcetype,
|
||||
cb->cb_literal) != 0)
|
||||
propstr = "-";
|
||||
else
|
||||
propstr = property;
|
||||
|
@ -6589,33 +6609,61 @@ print_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
|
|||
zpool_prop_get_feature(zhp, pl->pl_user_prop, property,
|
||||
sizeof (property)) == 0) {
|
||||
propstr = property;
|
||||
sourcetype = ZPROP_SRC_LOCAL;
|
||||
} else if (zfs_prop_user(pl->pl_user_prop) &&
|
||||
zpool_get_userprop(zhp, pl->pl_user_prop, property,
|
||||
sizeof (property), NULL) == 0) {
|
||||
sizeof (property), &sourcetype) == 0) {
|
||||
propstr = property;
|
||||
} else {
|
||||
propstr = "-";
|
||||
}
|
||||
|
||||
if (cb->cb_json) {
|
||||
if (pl->pl_prop == ZPOOL_PROP_NAME)
|
||||
continue;
|
||||
(void) zprop_nvlist_one_property(
|
||||
zpool_prop_to_name(pl->pl_prop), propstr,
|
||||
sourcetype, NULL, NULL, props, cb->cb_json_as_int);
|
||||
} else {
|
||||
/*
|
||||
* If this is being called in scripted mode, or if this is the
|
||||
* last column and it is left-justified, don't include a width
|
||||
* format specifier.
|
||||
* If this is being called in scripted mode, or if this
|
||||
* is the last column and it is left-justified, don't
|
||||
* include a width format specifier.
|
||||
*/
|
||||
if (cb->cb_scripted || (pl->pl_next == NULL && !right_justify))
|
||||
if (cb->cb_scripted || (pl->pl_next == NULL &&
|
||||
!right_justify))
|
||||
(void) fputs(propstr, stdout);
|
||||
else if (right_justify)
|
||||
(void) printf("%*s", (int)width, propstr);
|
||||
else
|
||||
(void) printf("%-*s", (int)width, propstr);
|
||||
}
|
||||
}
|
||||
|
||||
if (cb->cb_json) {
|
||||
fnvlist_add_nvlist(item, "properties", props);
|
||||
if (cb->cb_json_pool_key_guid) {
|
||||
char pool_guid[256];
|
||||
uint64_t guid = fnvlist_lookup_uint64(
|
||||
zpool_get_config(zhp, NULL),
|
||||
ZPOOL_CONFIG_POOL_GUID);
|
||||
snprintf(pool_guid, 256, "%llu",
|
||||
(u_longlong_t)guid);
|
||||
fnvlist_add_nvlist(d, pool_guid, item);
|
||||
} else {
|
||||
fnvlist_add_nvlist(d, zpool_get_name(zhp),
|
||||
item);
|
||||
}
|
||||
fnvlist_free(props);
|
||||
fnvlist_free(item);
|
||||
} else
|
||||
(void) fputc('\n', stdout);
|
||||
}
|
||||
|
||||
static void
|
||||
print_one_column(zpool_prop_t prop, uint64_t value, const char *str,
|
||||
boolean_t scripted, boolean_t valid, enum zfs_nicenum_format format)
|
||||
collect_vdev_prop(zpool_prop_t prop, uint64_t value, const char *str,
|
||||
boolean_t scripted, boolean_t valid, enum zfs_nicenum_format format,
|
||||
boolean_t json, nvlist_t *nvl, boolean_t as_int)
|
||||
{
|
||||
char propval[64];
|
||||
boolean_t fixed;
|
||||
|
@ -6665,26 +6713,33 @@ print_one_column(zpool_prop_t prop, uint64_t value, const char *str,
|
|||
if (!valid)
|
||||
(void) strlcpy(propval, "-", sizeof (propval));
|
||||
|
||||
if (json) {
|
||||
zprop_nvlist_one_property(zpool_prop_to_name(prop), propval,
|
||||
ZPROP_SRC_NONE, NULL, NULL, nvl, as_int);
|
||||
} else {
|
||||
if (scripted)
|
||||
(void) printf("\t%s", propval);
|
||||
else
|
||||
(void) printf(" %*s", (int)width, propval);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* print static default line per vdev
|
||||
* not compatible with '-o' <proplist> option
|
||||
*/
|
||||
static void
|
||||
print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
|
||||
list_cbdata_t *cb, int depth, boolean_t isspare)
|
||||
collect_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
|
||||
list_cbdata_t *cb, int depth, boolean_t isspare, nvlist_t *item)
|
||||
{
|
||||
nvlist_t **child;
|
||||
vdev_stat_t *vs;
|
||||
uint_t c, children;
|
||||
uint_t c, children = 0;
|
||||
char *vname;
|
||||
boolean_t scripted = cb->cb_scripted;
|
||||
uint64_t islog = B_FALSE;
|
||||
nvlist_t *props, *ent, *ch, *obj, *l2c, *sp;
|
||||
props = ent = ch = obj = sp = l2c = NULL;
|
||||
const char *dashes = "%-*s - - - - "
|
||||
"- - - - -\n";
|
||||
|
||||
|
@ -6705,13 +6760,21 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
|
|||
if (strcmp(name, VDEV_TYPE_INDIRECT) == 0)
|
||||
return;
|
||||
|
||||
if (cb->cb_json) {
|
||||
props = fnvlist_alloc();
|
||||
ent = fnvlist_alloc();
|
||||
fill_vdev_info(ent, zhp, (char *)name, B_FALSE,
|
||||
cb->cb_json_as_int);
|
||||
} else {
|
||||
if (scripted)
|
||||
(void) printf("\t%s", name);
|
||||
else if (strlen(name) + depth > cb->cb_namewidth)
|
||||
(void) printf("%*s%s", depth, "", name);
|
||||
else
|
||||
(void) printf("%*s%s%*s", depth, "", name,
|
||||
(int)(cb->cb_namewidth - strlen(name) - depth), "");
|
||||
(int)(cb->cb_namewidth - strlen(name) -
|
||||
depth), "");
|
||||
}
|
||||
|
||||
/*
|
||||
* Print the properties for the individual vdevs. Some
|
||||
|
@ -6719,30 +6782,39 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
|
|||
* 'toplevel' boolean value is passed to the print_one_column()
|
||||
* to indicate that the value is valid.
|
||||
*/
|
||||
if (VDEV_STAT_VALID(vs_pspace, c) && vs->vs_pspace)
|
||||
print_one_column(ZPOOL_PROP_SIZE, vs->vs_pspace, NULL,
|
||||
scripted, B_TRUE, format);
|
||||
else
|
||||
print_one_column(ZPOOL_PROP_SIZE, vs->vs_space, NULL,
|
||||
scripted, toplevel, format);
|
||||
print_one_column(ZPOOL_PROP_ALLOCATED, vs->vs_alloc, NULL,
|
||||
scripted, toplevel, format);
|
||||
print_one_column(ZPOOL_PROP_FREE, vs->vs_space - vs->vs_alloc,
|
||||
NULL, scripted, toplevel, format);
|
||||
print_one_column(ZPOOL_PROP_CHECKPOINT,
|
||||
vs->vs_checkpoint_space, NULL, scripted, toplevel, format);
|
||||
print_one_column(ZPOOL_PROP_EXPANDSZ, vs->vs_esize, NULL,
|
||||
scripted, B_TRUE, format);
|
||||
print_one_column(ZPOOL_PROP_FRAGMENTATION,
|
||||
if (VDEV_STAT_VALID(vs_pspace, c) && vs->vs_pspace) {
|
||||
collect_vdev_prop(ZPOOL_PROP_SIZE, vs->vs_pspace, NULL,
|
||||
scripted, B_TRUE, format, cb->cb_json, props,
|
||||
cb->cb_json_as_int);
|
||||
} else {
|
||||
collect_vdev_prop(ZPOOL_PROP_SIZE, vs->vs_space, NULL,
|
||||
scripted, toplevel, format, cb->cb_json, props,
|
||||
cb->cb_json_as_int);
|
||||
}
|
||||
collect_vdev_prop(ZPOOL_PROP_ALLOCATED, vs->vs_alloc, NULL,
|
||||
scripted, toplevel, format, cb->cb_json, props,
|
||||
cb->cb_json_as_int);
|
||||
collect_vdev_prop(ZPOOL_PROP_FREE, vs->vs_space - vs->vs_alloc,
|
||||
NULL, scripted, toplevel, format, cb->cb_json, props,
|
||||
cb->cb_json_as_int);
|
||||
collect_vdev_prop(ZPOOL_PROP_CHECKPOINT,
|
||||
vs->vs_checkpoint_space, NULL, scripted, toplevel, format,
|
||||
cb->cb_json, props, cb->cb_json_as_int);
|
||||
collect_vdev_prop(ZPOOL_PROP_EXPANDSZ, vs->vs_esize, NULL,
|
||||
scripted, B_TRUE, format, cb->cb_json, props,
|
||||
cb->cb_json_as_int);
|
||||
collect_vdev_prop(ZPOOL_PROP_FRAGMENTATION,
|
||||
vs->vs_fragmentation, NULL, scripted,
|
||||
(vs->vs_fragmentation != ZFS_FRAG_INVALID && toplevel),
|
||||
format);
|
||||
format, cb->cb_json, props, cb->cb_json_as_int);
|
||||
cap = (vs->vs_space == 0) ? 0 :
|
||||
(vs->vs_alloc * 10000 / vs->vs_space);
|
||||
print_one_column(ZPOOL_PROP_CAPACITY, cap, NULL,
|
||||
scripted, toplevel, format);
|
||||
print_one_column(ZPOOL_PROP_DEDUPRATIO, 0, NULL,
|
||||
scripted, toplevel, format);
|
||||
collect_vdev_prop(ZPOOL_PROP_CAPACITY, cap, NULL,
|
||||
scripted, toplevel, format, cb->cb_json, props,
|
||||
cb->cb_json_as_int);
|
||||
collect_vdev_prop(ZPOOL_PROP_DEDUPRATIO, 0, NULL,
|
||||
scripted, toplevel, format, cb->cb_json, props,
|
||||
cb->cb_json_as_int);
|
||||
state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
|
||||
if (isspare) {
|
||||
if (vs->vs_aux == VDEV_AUX_SPARED)
|
||||
|
@ -6750,14 +6822,28 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
|
|||
else if (vs->vs_state == VDEV_STATE_HEALTHY)
|
||||
state = "AVAIL";
|
||||
}
|
||||
print_one_column(ZPOOL_PROP_HEALTH, 0, state, scripted,
|
||||
B_TRUE, format);
|
||||
collect_vdev_prop(ZPOOL_PROP_HEALTH, 0, state, scripted,
|
||||
B_TRUE, format, cb->cb_json, props, cb->cb_json_as_int);
|
||||
|
||||
if (cb->cb_json) {
|
||||
fnvlist_add_nvlist(ent, "properties", props);
|
||||
fnvlist_free(props);
|
||||
} else
|
||||
(void) fputc('\n', stdout);
|
||||
}
|
||||
|
||||
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
|
||||
&child, &children) != 0)
|
||||
&child, &children) != 0) {
|
||||
if (cb->cb_json) {
|
||||
fnvlist_add_nvlist(item, name, ent);
|
||||
fnvlist_free(ent);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (cb->cb_json) {
|
||||
ch = fnvlist_alloc();
|
||||
}
|
||||
|
||||
/* list the normal vdevs first */
|
||||
for (c = 0; c < children; c++) {
|
||||
|
@ -6776,14 +6862,28 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
|
|||
|
||||
vname = zpool_vdev_name(g_zfs, zhp, child[c],
|
||||
cb->cb_name_flags | VDEV_NAME_TYPE_ID);
|
||||
print_list_stats(zhp, vname, child[c], cb, depth + 2, B_FALSE);
|
||||
|
||||
if (name == NULL || cb->cb_json != B_TRUE)
|
||||
collect_list_stats(zhp, vname, child[c], cb, depth + 2,
|
||||
B_FALSE, item);
|
||||
else if (cb->cb_json) {
|
||||
collect_list_stats(zhp, vname, child[c], cb, depth + 2,
|
||||
B_FALSE, ch);
|
||||
}
|
||||
free(vname);
|
||||
}
|
||||
|
||||
if (cb->cb_json) {
|
||||
if (!nvlist_empty(ch))
|
||||
fnvlist_add_nvlist(ent, "vdevs", ch);
|
||||
fnvlist_free(ch);
|
||||
}
|
||||
|
||||
/* list the classes: 'logs', 'dedup', and 'special' */
|
||||
for (uint_t n = 0; n < ARRAY_SIZE(class_name); n++) {
|
||||
boolean_t printed = B_FALSE;
|
||||
|
||||
if (cb->cb_json)
|
||||
obj = fnvlist_alloc();
|
||||
for (c = 0; c < children; c++) {
|
||||
const char *bias = NULL;
|
||||
const char *type = NULL;
|
||||
|
@ -6802,7 +6902,7 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
|
|||
if (!islog && strcmp(type, VDEV_TYPE_INDIRECT) == 0)
|
||||
continue;
|
||||
|
||||
if (!printed) {
|
||||
if (!printed && !cb->cb_json) {
|
||||
/* LINTED E_SEC_PRINTF_VAR_FMT */
|
||||
(void) printf(dashes, cb->cb_namewidth,
|
||||
class_name[n]);
|
||||
|
@ -6810,36 +6910,64 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
|
|||
}
|
||||
vname = zpool_vdev_name(g_zfs, zhp, child[c],
|
||||
cb->cb_name_flags | VDEV_NAME_TYPE_ID);
|
||||
print_list_stats(zhp, vname, child[c], cb, depth + 2,
|
||||
B_FALSE);
|
||||
collect_list_stats(zhp, vname, child[c], cb, depth + 2,
|
||||
B_FALSE, obj);
|
||||
free(vname);
|
||||
}
|
||||
if (cb->cb_json) {
|
||||
if (!nvlist_empty(obj))
|
||||
fnvlist_add_nvlist(item, class_name[n], obj);
|
||||
fnvlist_free(obj);
|
||||
}
|
||||
}
|
||||
|
||||
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
|
||||
&child, &children) == 0 && children > 0) {
|
||||
if (cb->cb_json) {
|
||||
l2c = fnvlist_alloc();
|
||||
} else {
|
||||
/* LINTED E_SEC_PRINTF_VAR_FMT */
|
||||
(void) printf(dashes, cb->cb_namewidth, "cache");
|
||||
}
|
||||
for (c = 0; c < children; c++) {
|
||||
vname = zpool_vdev_name(g_zfs, zhp, child[c],
|
||||
cb->cb_name_flags);
|
||||
print_list_stats(zhp, vname, child[c], cb, depth + 2,
|
||||
B_FALSE);
|
||||
collect_list_stats(zhp, vname, child[c], cb, depth + 2,
|
||||
B_FALSE, l2c);
|
||||
free(vname);
|
||||
}
|
||||
if (cb->cb_json) {
|
||||
if (!nvlist_empty(l2c))
|
||||
fnvlist_add_nvlist(item, "l2cache", l2c);
|
||||
fnvlist_free(l2c);
|
||||
}
|
||||
}
|
||||
|
||||
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, &child,
|
||||
&children) == 0 && children > 0) {
|
||||
if (cb->cb_json) {
|
||||
sp = fnvlist_alloc();
|
||||
} else {
|
||||
/* LINTED E_SEC_PRINTF_VAR_FMT */
|
||||
(void) printf(dashes, cb->cb_namewidth, "spare");
|
||||
}
|
||||
for (c = 0; c < children; c++) {
|
||||
vname = zpool_vdev_name(g_zfs, zhp, child[c],
|
||||
cb->cb_name_flags);
|
||||
print_list_stats(zhp, vname, child[c], cb, depth + 2,
|
||||
B_TRUE);
|
||||
collect_list_stats(zhp, vname, child[c], cb, depth + 2,
|
||||
B_TRUE, sp);
|
||||
free(vname);
|
||||
}
|
||||
if (cb->cb_json) {
|
||||
if (!nvlist_empty(sp))
|
||||
fnvlist_add_nvlist(item, "spares", sp);
|
||||
fnvlist_free(sp);
|
||||
}
|
||||
}
|
||||
|
||||
if (name != NULL && cb->cb_json) {
|
||||
fnvlist_add_nvlist(item, name, ent);
|
||||
fnvlist_free(ent);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6849,17 +6977,44 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
|
|||
static int
|
||||
list_callback(zpool_handle_t *zhp, void *data)
|
||||
{
|
||||
nvlist_t *p, *d, *nvdevs;
|
||||
uint64_t guid;
|
||||
char pool_guid[256];
|
||||
const char *pool_name = zpool_get_name(zhp);
|
||||
list_cbdata_t *cbp = data;
|
||||
p = d = nvdevs = NULL;
|
||||
|
||||
print_pool(zhp, cbp);
|
||||
collect_pool(zhp, cbp);
|
||||
|
||||
if (cbp->cb_verbose) {
|
||||
nvlist_t *config, *nvroot;
|
||||
|
||||
config = zpool_get_config(zhp, NULL);
|
||||
verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
|
||||
&nvroot) == 0);
|
||||
print_list_stats(zhp, NULL, nvroot, cbp, 0, B_FALSE);
|
||||
if (cbp->cb_json) {
|
||||
d = fnvlist_lookup_nvlist(cbp->cb_jsobj,
|
||||
"pools");
|
||||
if (cbp->cb_json_pool_key_guid) {
|
||||
guid = fnvlist_lookup_uint64(config,
|
||||
ZPOOL_CONFIG_POOL_GUID);
|
||||
snprintf(pool_guid, 256, "%llu",
|
||||
(u_longlong_t)guid);
|
||||
p = fnvlist_lookup_nvlist(d, pool_guid);
|
||||
} else {
|
||||
p = fnvlist_lookup_nvlist(d, pool_name);
|
||||
}
|
||||
nvdevs = fnvlist_alloc();
|
||||
}
|
||||
collect_list_stats(zhp, NULL, nvroot, cbp, 0, B_FALSE, nvdevs);
|
||||
if (cbp->cb_json) {
|
||||
fnvlist_add_nvlist(p, "vdevs", nvdevs);
|
||||
if (cbp->cb_json_pool_key_guid)
|
||||
fnvlist_add_nvlist(d, pool_guid, p);
|
||||
else
|
||||
fnvlist_add_nvlist(d, pool_name, p);
|
||||
fnvlist_add_nvlist(cbp->cb_jsobj, "pools", d);
|
||||
fnvlist_free(nvdevs);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
@ -6899,6 +7054,9 @@ get_namewidth_list(zpool_handle_t *zhp, void *data)
|
|||
* -p Display values in parsable (exact) format.
|
||||
* -P Display full path for vdev name.
|
||||
* -T Display a timestamp in date(1) or Unix format
|
||||
* -j Display the output in JSON format
|
||||
* --json-int Display the numbers as integer instead of strings.
|
||||
* --json-pool-key-guid Set pool GUID as key for pool objects.
|
||||
*
|
||||
* List all pools in the system, whether or not they're healthy. Output space
|
||||
* statistics for each one, as well as health status summary.
|
||||
|
@ -6917,10 +7075,19 @@ zpool_do_list(int argc, char **argv)
|
|||
unsigned long count = 0;
|
||||
zpool_list_t *list;
|
||||
boolean_t first = B_TRUE;
|
||||
nvlist_t *data = NULL;
|
||||
current_prop_type = ZFS_TYPE_POOL;
|
||||
|
||||
struct option long_options[] = {
|
||||
{"json-int", no_argument, NULL, ZPOOL_OPTION_JSON_NUMS_AS_INT},
|
||||
{"json-pool-key-guid", no_argument, NULL,
|
||||
ZPOOL_OPTION_POOL_KEY_GUID},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
/* check options */
|
||||
while ((c = getopt(argc, argv, ":gHLo:pPT:v")) != -1) {
|
||||
while ((c = getopt_long(argc, argv, ":gjHLo:pPT:v", long_options,
|
||||
NULL)) != -1) {
|
||||
switch (c) {
|
||||
case 'g':
|
||||
cb.cb_name_flags |= VDEV_NAME_GUID;
|
||||
|
@ -6940,6 +7107,16 @@ zpool_do_list(int argc, char **argv)
|
|||
case 'p':
|
||||
cb.cb_literal = B_TRUE;
|
||||
break;
|
||||
case 'j':
|
||||
cb.cb_json = B_TRUE;
|
||||
break;
|
||||
case ZPOOL_OPTION_JSON_NUMS_AS_INT:
|
||||
cb.cb_json_as_int = B_TRUE;
|
||||
cb.cb_literal = B_TRUE;
|
||||
break;
|
||||
case ZPOOL_OPTION_POOL_KEY_GUID:
|
||||
cb.cb_json_pool_key_guid = B_TRUE;
|
||||
break;
|
||||
case 'T':
|
||||
get_timestamp_arg(*optarg);
|
||||
break;
|
||||
|
@ -6962,6 +7139,18 @@ zpool_do_list(int argc, char **argv)
|
|||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (!cb.cb_json && cb.cb_json_as_int) {
|
||||
(void) fprintf(stderr, gettext("'--json-int' only works with"
|
||||
" '-j' option\n"));
|
||||
usage(B_FALSE);
|
||||
}
|
||||
|
||||
if (!cb.cb_json && cb.cb_json_pool_key_guid) {
|
||||
(void) fprintf(stderr, gettext("'json-pool-key-guid' only"
|
||||
" works with '-j' option\n"));
|
||||
usage(B_FALSE);
|
||||
}
|
||||
|
||||
get_interval_count(&argc, argv, &interval, &count);
|
||||
|
||||
if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
|
||||
|
@ -6975,18 +7164,43 @@ zpool_do_list(int argc, char **argv)
|
|||
if (pool_list_count(list) == 0)
|
||||
break;
|
||||
|
||||
if (cb.cb_json) {
|
||||
cb.cb_jsobj = zpool_json_schema(0, 1);
|
||||
data = fnvlist_alloc();
|
||||
fnvlist_add_nvlist(cb.cb_jsobj, "pools", data);
|
||||
fnvlist_free(data);
|
||||
}
|
||||
|
||||
cb.cb_namewidth = 0;
|
||||
(void) pool_list_iter(list, B_FALSE, get_namewidth_list, &cb);
|
||||
|
||||
if (timestamp_fmt != NODATE)
|
||||
if (timestamp_fmt != NODATE) {
|
||||
if (cb.cb_json) {
|
||||
if (cb.cb_json_as_int) {
|
||||
fnvlist_add_uint64(cb.cb_jsobj, "time",
|
||||
time(NULL));
|
||||
} else {
|
||||
char ts[128];
|
||||
get_timestamp(timestamp_fmt, ts, 128);
|
||||
fnvlist_add_string(cb.cb_jsobj, "time",
|
||||
ts);
|
||||
}
|
||||
} else
|
||||
print_timestamp(timestamp_fmt);
|
||||
}
|
||||
|
||||
if (!cb.cb_scripted && (first || cb.cb_verbose)) {
|
||||
if (!cb.cb_scripted && (first || cb.cb_verbose) &&
|
||||
!cb.cb_json) {
|
||||
print_header(&cb);
|
||||
first = B_FALSE;
|
||||
}
|
||||
ret = pool_list_iter(list, B_TRUE, list_callback, &cb);
|
||||
|
||||
if (ret == 0 && cb.cb_json)
|
||||
zcmd_print_json(cb.cb_jsobj);
|
||||
else if (ret != 0 && cb.cb_json)
|
||||
nvlist_free(cb.cb_jsobj);
|
||||
|
||||
if (interval == 0)
|
||||
break;
|
||||
|
||||
|
@ -6999,7 +7213,8 @@ zpool_do_list(int argc, char **argv)
|
|||
(void) fsleep(interval);
|
||||
}
|
||||
|
||||
if (argc == 0 && !cb.cb_scripted && pool_list_count(list) == 0) {
|
||||
if (argc == 0 && !cb.cb_scripted && !cb.cb_json &&
|
||||
pool_list_count(list) == 0) {
|
||||
(void) printf(gettext("no pools available\n"));
|
||||
ret = 0;
|
||||
}
|
||||
|
@ -10886,7 +11101,7 @@ get_callback_vdev(zpool_handle_t *zhp, char *vdevname, void *data)
|
|||
if (cbp->cb_json) {
|
||||
if (!nvlist_empty(props)) {
|
||||
item = fnvlist_alloc();
|
||||
fill_vdev_info(item, zhp, vdevname,
|
||||
fill_vdev_info(item, zhp, vdevname, B_TRUE,
|
||||
cbp->cb_json_as_int);
|
||||
fnvlist_add_nvlist(item, "properties", props);
|
||||
fnvlist_add_nvlist(d, vdevname, item);
|
||||
|
|
|
@ -37,5 +37,7 @@
|
|||
|
||||
/* Print a timestamp in either Unix or standard format. */
|
||||
void print_timestamp(uint_t);
|
||||
/* Return timestamp in either Unix or standard format in provided buffer */
|
||||
void get_timestamp(uint_t, char *, int);
|
||||
|
||||
#endif /* _STATCOMMON_H */
|
||||
|
|
|
@ -62,3 +62,25 @@ print_timestamp(uint_t timestamp_fmt)
|
|||
(void) printf("%s\n", dstr);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return timestamp as decimal reprentation (in string) of time_t
|
||||
* value (-T u was specified) or in date(1) format (-T d was specified).
|
||||
*/
|
||||
void
|
||||
get_timestamp(uint_t timestamp_fmt, char *buf, int len)
|
||||
{
|
||||
time_t t = time(NULL);
|
||||
static const char *fmt = NULL;
|
||||
|
||||
/* We only need to retrieve this once per invocation */
|
||||
if (fmt == NULL)
|
||||
fmt = nl_langinfo(_DATE_FMT);
|
||||
|
||||
if (timestamp_fmt == UDATE) {
|
||||
(void) snprintf(buf, len, "%lld", (longlong_t)t);
|
||||
} else if (timestamp_fmt == DDATE) {
|
||||
struct tm tm;
|
||||
strftime(buf, len, fmt, localtime_r(&t, &tm));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
.Nm zpool
|
||||
.Cm list
|
||||
.Op Fl HgLpPv
|
||||
.Op Fl j Op Ar --json-int, --json-pool-key-guid
|
||||
.Op Fl o Ar property Ns Oo , Ns Ar property Oc Ns …
|
||||
.Op Fl T Sy u Ns | Ns Sy d
|
||||
.Oo Ar pool Oc Ns …
|
||||
|
@ -58,6 +59,14 @@ is specified, the command exits after
|
|||
.Ar count
|
||||
reports are printed.
|
||||
.Bl -tag -width Ds
|
||||
.It Fl j Op Ar --json-int, --json-pool-key-guid
|
||||
Display the list of pools in JSON format.
|
||||
Specify
|
||||
.Sy --json-int
|
||||
to display the numbers in integer format instead of strings.
|
||||
Specify
|
||||
.Sy --json-pool-key-guid
|
||||
to set pool GUID as key for pool objects instead of pool names.
|
||||
.It Fl g
|
||||
Display vdev GUIDs instead of the normal device names.
|
||||
These GUIDs can be used in place of device names for the zpool
|
||||
|
@ -139,6 +148,104 @@ data 23.9G 14.6G 9.30G - 48% 61% 1.00x ONLINE -
|
|||
sda - - - - -
|
||||
sdb - - - 10G -
|
||||
sdc - - - - -
|
||||
.Ed
|
||||
.
|
||||
.Ss Example 3 : No Displaying expanded space on a device
|
||||
The following command lists all available pools on the system in JSON
|
||||
format.
|
||||
.Bd -literal -compact -offset Ds
|
||||
.No # Nm zpool Cm list Fl j | Nm jq
|
||||
{
|
||||
"output_version": {
|
||||
"command": "zpool list",
|
||||
"vers_major": 0,
|
||||
"vers_minor": 1
|
||||
},
|
||||
"pools": {
|
||||
"tank": {
|
||||
"name": "tank",
|
||||
"type": "POOL",
|
||||
"state": "ONLINE",
|
||||
"guid": "15220353080205405147",
|
||||
"txg": "2671",
|
||||
"spa_version": "5000",
|
||||
"zpl_version": "5",
|
||||
"properties": {
|
||||
"size": {
|
||||
"value": "111G",
|
||||
"source": {
|
||||
"type": "NONE",
|
||||
"data": "-"
|
||||
}
|
||||
},
|
||||
"allocated": {
|
||||
"value": "30.8G",
|
||||
"source": {
|
||||
"type": "NONE",
|
||||
"data": "-"
|
||||
}
|
||||
},
|
||||
"free": {
|
||||
"value": "80.2G",
|
||||
"source": {
|
||||
"type": "NONE",
|
||||
"data": "-"
|
||||
}
|
||||
},
|
||||
"checkpoint": {
|
||||
"value": "-",
|
||||
"source": {
|
||||
"type": "NONE",
|
||||
"data": "-"
|
||||
}
|
||||
},
|
||||
"expandsize": {
|
||||
"value": "-",
|
||||
"source": {
|
||||
"type": "NONE",
|
||||
"data": "-"
|
||||
}
|
||||
},
|
||||
"fragmentation": {
|
||||
"value": "0%",
|
||||
"source": {
|
||||
"type": "NONE",
|
||||
"data": "-"
|
||||
}
|
||||
},
|
||||
"capacity": {
|
||||
"value": "27%",
|
||||
"source": {
|
||||
"type": "NONE",
|
||||
"data": "-"
|
||||
}
|
||||
},
|
||||
"dedupratio": {
|
||||
"value": "1.00x",
|
||||
"source": {
|
||||
"type": "NONE",
|
||||
"data": "-"
|
||||
}
|
||||
},
|
||||
"health": {
|
||||
"value": "ONLINE",
|
||||
"source": {
|
||||
"type": "NONE",
|
||||
"data": "-"
|
||||
}
|
||||
},
|
||||
"altroot": {
|
||||
"value": "-",
|
||||
"source": {
|
||||
"type": "DEFAULT",
|
||||
"data": "-"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.Ed
|
||||
.
|
||||
.Sh SEE ALSO
|
||||
|
|
Loading…
Reference in New Issue