Skip to content

Commit db1df99

Browse files
author
Umer Saleem
committed
JSON output support for zpool get
This commit adds support for zpool get command to output the list of properties for ZFS Pools and VDEVS in JSON format using '-j' option. Man page for zpool get is updated to include '-j' option. Signed-off-by: Umer Saleem <[email protected]>
1 parent d92325e commit db1df99

File tree

5 files changed

+198
-60
lines changed

5 files changed

+198
-60
lines changed

cmd/zfs/zfs_main.c

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1962,25 +1962,6 @@ fill_dataset_info(nvlist_t *list, zfs_handle_t *zhp)
19621962
}
19631963
}
19641964

1965-
static int
1966-
zprop_collect_property(const char *name, zprop_get_cbdata_t *cbp,
1967-
const char *propname, const char *value, zprop_source_t sourcetype,
1968-
const char *source, const char *recvd_value, nvlist_t *nvl)
1969-
{
1970-
if (cbp->cb_json) {
1971-
if ((sourcetype & cbp->cb_sources) == 0)
1972-
return (0);
1973-
else {
1974-
return (zprop_nvlist_one_property(propname, value,
1975-
sourcetype, source, recvd_value, nvl));
1976-
}
1977-
} else {
1978-
zprop_print_one_property(name, cbp,
1979-
propname, value, sourcetype, source, recvd_value);
1980-
return (0);
1981-
}
1982-
}
1983-
19841965
/*
19851966
* zfs get [-rjHp] [-o all | field[,field]...] [-s source[,source]...]
19861967
* < all | property[,property]... > < fs | snap | vol > ...

cmd/zpool/zpool_main.c

Lines changed: 167 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ get_usage(zpool_help_t idx)
434434
case HELP_EVENTS:
435435
return (gettext("\tevents [-vHf [pool] | -c]\n"));
436436
case HELP_GET:
437-
return (gettext("\tget [-Hp] [-o \"all\" | field[,...]] "
437+
return (gettext("\tget [-jHp] [-o \"all\" | field[,...]] "
438438
"<\"all\" | property[,...]> <pool> ...\n"));
439439
case HELP_SET:
440440
return (gettext("\tset <property=value> <pool>\n"
@@ -892,6 +892,89 @@ print_spare_list(nvlist_t *nv, int indent)
892892
}
893893
}
894894

895+
/*
896+
* Generates an nvlist with output version for every command based on params.
897+
* Purpose of this is to add a version of JSON output, considering the schema
898+
* format might be updated for each command in future.
899+
*
900+
* Schema:
901+
*
902+
* "output_version": {
903+
* "command": string,
904+
* "vers_major": integer,
905+
* "vers_minor": integer,
906+
* }
907+
*/
908+
static nvlist_t *
909+
zpool_json_schema(int maj_v, int min_v)
910+
{
911+
char cmd[MAX_CMD_LEN];
912+
nvlist_t *sch = fnvlist_alloc();
913+
nvlist_t *ov = fnvlist_alloc();
914+
915+
snprintf(cmd, MAX_CMD_LEN, "zpool %s", current_command->name);
916+
fnvlist_add_string(ov, "command", cmd);
917+
fnvlist_add_uint32(ov, "vers_major", maj_v);
918+
fnvlist_add_uint32(ov, "vers_minor", min_v);
919+
fnvlist_add_nvlist(sch, "output_version", ov);
920+
fnvlist_free(ov);
921+
return (sch);
922+
}
923+
924+
static void
925+
fill_pool_info(nvlist_t *list, zpool_handle_t *zhp, boolean_t addtype)
926+
{
927+
char value[ZFS_MAXPROPLEN];
928+
uint64_t txg;
929+
nvlist_t *config = zpool_get_config(zhp, NULL);
930+
uint64_t guid = fnvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID);
931+
932+
fnvlist_add_string(list, "name", zpool_get_name(zhp));
933+
if (addtype)
934+
fnvlist_add_string(list, "type", "POOL");
935+
fnvlist_add_string(list, "state", zpool_get_state_str(zhp));
936+
snprintf(value, ZFS_MAXPROPLEN, "%llu", (u_longlong_t)guid);
937+
fnvlist_add_string(list, "guid", value);
938+
if (nvlist_lookup_uint64(config, "txg", &txg) == 0) {
939+
snprintf(value, ZFS_MAXPROPLEN, "%llu", (u_longlong_t)txg);
940+
fnvlist_add_string(list, "txg", value);
941+
}
942+
fnvlist_add_string(list, "spa_version", SPA_VERSION_STRING);
943+
fnvlist_add_string(list, "zpl_version", ZPL_VERSION_STRING);
944+
}
945+
946+
static void
947+
fill_vdev_info(nvlist_t *list, zpool_handle_t *zhp, char *name)
948+
{
949+
boolean_t spare, l2c, log;
950+
const char *path, *phys, *devid;
951+
nvlist_t *nvdev = zpool_find_vdev(zhp, name, &spare, &l2c, &log);
952+
953+
fnvlist_add_string(list, "name", name);
954+
fnvlist_add_string(list, "type", "VDEV");
955+
if (nvdev) {
956+
const char *type = fnvlist_lookup_string(nvdev,
957+
ZPOOL_CONFIG_TYPE);
958+
if (type)
959+
fnvlist_add_string(list, "vdev_type", type);
960+
uint64_t guid = fnvlist_lookup_uint64(nvdev, ZPOOL_CONFIG_GUID);
961+
if (guid) {
962+
char buf[ZFS_MAXPROPLEN];
963+
snprintf(buf, ZFS_MAXPROPLEN, "%llu", (u_longlong_t)guid);
964+
fnvlist_add_string(list, "guid", buf);
965+
}
966+
967+
if (nvlist_lookup_string(nvdev, ZPOOL_CONFIG_PATH, &path) == 0)
968+
fnvlist_add_string(list, "path", path);
969+
if (nvlist_lookup_string(nvdev, ZPOOL_CONFIG_PHYS_PATH,
970+
&phys) == 0)
971+
fnvlist_add_string(list, "phys_path", phys);
972+
if (nvlist_lookup_string(nvdev, ZPOOL_CONFIG_DEVID,
973+
&devid) == 0)
974+
fnvlist_add_string(list, "devid", devid);
975+
}
976+
}
977+
895978
static boolean_t
896979
prop_list_contains_feature(nvlist_t *proplist)
897980
{
@@ -10243,35 +10326,6 @@ zpool_do_history(int argc, char **argv)
1024310326
return (ret);
1024410327
}
1024510328

10246-
/*
10247-
* Generates an nvlist with output version for every command based on params.
10248-
* Purpose of this is to add a version of JSON output, considering the schema
10249-
* format might be updated for each command in future.
10250-
*
10251-
* Schema:
10252-
*
10253-
* "output_version": {
10254-
* "command": string,
10255-
* "vers_major": integer,
10256-
* "vers_minor": integer,
10257-
* }
10258-
*/
10259-
static nvlist_t *
10260-
zpool_json_schema(int maj_v, int min_v)
10261-
{
10262-
char cmd[MAX_CMD_LEN];
10263-
nvlist_t *sch = fnvlist_alloc();
10264-
nvlist_t *ov = fnvlist_alloc();
10265-
10266-
snprintf(cmd, MAX_CMD_LEN, "zpool %s", current_command->name);
10267-
fnvlist_add_string(ov, "command", cmd);
10268-
fnvlist_add_uint32(ov, "vers_major", maj_v);
10269-
fnvlist_add_uint32(ov, "vers_minor", min_v);
10270-
fnvlist_add_nvlist(sch, "output_version", ov);
10271-
10272-
return (sch);
10273-
}
10274-
1027510329
typedef struct ev_opts {
1027610330
int verbose;
1027710331
int scripted;
@@ -10666,6 +10720,17 @@ get_callback_vdev(zpool_handle_t *zhp, char *vdevname, void *data)
1066610720
zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data;
1066710721
char value[ZFS_MAXPROPLEN];
1066810722
zprop_source_t srctype;
10723+
nvlist_t *props, *item, *d;
10724+
props = item = d = NULL;
10725+
10726+
if (cbp->cb_json) {
10727+
d = fnvlist_lookup_nvlist(cbp->cb_jsobj, "data");
10728+
if (d == NULL) {
10729+
fprintf(stderr, "data obj not found.\n");
10730+
exit(1);
10731+
}
10732+
props = fnvlist_alloc();
10733+
}
1066910734

1067010735
for (zprop_list_t *pl = cbp->cb_proplist; pl != NULL;
1067110736
pl = pl->pl_next) {
@@ -10687,9 +10752,21 @@ get_callback_vdev(zpool_handle_t *zhp, char *vdevname, void *data)
1068710752
if (zpool_get_vdev_prop(zhp, vdevname, pl->pl_prop,
1068810753
prop_name, value, sizeof (value), &srctype,
1068910754
cbp->cb_literal) == 0) {
10690-
zprop_print_one_property(vdevname, cbp, prop_name,
10691-
value, srctype, NULL, NULL);
10755+
zprop_collect_property(vdevname, cbp, prop_name,
10756+
value, srctype, NULL, NULL, props);
10757+
}
10758+
}
10759+
10760+
if (cbp->cb_json) {
10761+
if (!nvlist_empty(props)) {
10762+
item = fnvlist_alloc();
10763+
fill_vdev_info(item, zhp, vdevname);
10764+
fnvlist_add_nvlist(item, "properties", props);
10765+
fnvlist_add_nvlist(d, vdevname, item);
10766+
fnvlist_add_nvlist(cbp->cb_jsobj, "data", d);
10767+
fnvlist_free(item);
1069210768
}
10769+
fnvlist_free(props);
1069310770
}
1069410771

1069510772
return (0);
@@ -10733,8 +10810,18 @@ get_callback(zpool_handle_t *zhp, void *data)
1073310810
zprop_source_t srctype;
1073410811
zprop_list_t *pl;
1073510812
int vid;
10813+
int err = 0;
10814+
nvlist_t *props, *item, *d;
10815+
props = item = d = NULL;
1073610816

1073710817
if (cbp->cb_type == ZFS_TYPE_VDEV) {
10818+
if (cbp->cb_json) {
10819+
nvlist_t *pool = fnvlist_alloc();
10820+
fill_pool_info(pool, zhp, B_FALSE);
10821+
fnvlist_add_nvlist(cbp->cb_jsobj, "pool", pool);
10822+
fnvlist_free(pool);
10823+
}
10824+
1073810825
if (strcmp(cbp->cb_vdevs.cb_names[0], "all-vdevs") == 0) {
1073910826
for_each_vdev(zhp, get_callback_vdev_cb, data);
1074010827
} else {
@@ -10754,6 +10841,14 @@ get_callback(zpool_handle_t *zhp, void *data)
1075410841
}
1075510842
} else {
1075610843
assert(cbp->cb_type == ZFS_TYPE_POOL);
10844+
if (cbp->cb_json) {
10845+
d = fnvlist_lookup_nvlist(cbp->cb_jsobj, "data");
10846+
if (d == NULL) {
10847+
fprintf(stderr, "data obj not found.\n");
10848+
exit(1);
10849+
}
10850+
props = fnvlist_alloc();
10851+
}
1075710852
for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
1075810853
/*
1075910854
* Skip the special fake placeholder. This will also
@@ -10771,9 +10866,9 @@ get_callback(zpool_handle_t *zhp, void *data)
1077110866
value, sizeof (value), &srctype) != 0)
1077210867
continue;
1077310868

10774-
zprop_print_one_property(zpool_get_name(zhp),
10775-
cbp, pl->pl_user_prop, value, srctype,
10776-
NULL, NULL);
10869+
err = zprop_collect_property(
10870+
zpool_get_name(zhp), cbp, pl->pl_user_prop,
10871+
value, srctype, NULL, NULL, props);
1077710872
} else if (pl->pl_prop == ZPROP_INVAL &&
1077810873
(zpool_prop_feature(pl->pl_user_prop) ||
1077910874
zpool_prop_unsupported(pl->pl_user_prop))) {
@@ -10782,21 +10877,41 @@ get_callback(zpool_handle_t *zhp, void *data)
1078210877
if (zpool_prop_get_feature(zhp,
1078310878
pl->pl_user_prop, value,
1078410879
sizeof (value)) == 0) {
10785-
zprop_print_one_property(
10880+
err = zprop_collect_property(
1078610881
zpool_get_name(zhp), cbp,
1078710882
pl->pl_user_prop, value, srctype,
10788-
NULL, NULL);
10883+
NULL, NULL, props);
1078910884
}
1079010885
} else {
1079110886
if (zpool_get_prop(zhp, pl->pl_prop, value,
1079210887
sizeof (value), &srctype,
1079310888
cbp->cb_literal) != 0)
1079410889
continue;
1079510890

10796-
zprop_print_one_property(zpool_get_name(zhp),
10797-
cbp, zpool_prop_to_name(pl->pl_prop),
10798-
value, srctype, NULL, NULL);
10891+
err = zprop_collect_property(
10892+
zpool_get_name(zhp), cbp,
10893+
zpool_prop_to_name(pl->pl_prop),
10894+
value, srctype, NULL, NULL, props);
10895+
}
10896+
if (err != 0)
10897+
return (err);
10898+
}
10899+
10900+
if (cbp->cb_json) {
10901+
if (!nvlist_empty(props)) {
10902+
char buf[256];
10903+
item = fnvlist_alloc();
10904+
fill_pool_info(item, zhp, B_TRUE);
10905+
fnvlist_add_nvlist(item, "properties", props);
10906+
uint64_t guid = fnvlist_lookup_uint64(
10907+
zpool_get_config(zhp, NULL),
10908+
ZPOOL_CONFIG_POOL_GUID);
10909+
snprintf(buf, 256, "%llu", (u_longlong_t)guid);
10910+
fnvlist_add_nvlist(d, buf, item);
10911+
fnvlist_add_nvlist(cbp->cb_jsobj, "data", d);
10912+
fnvlist_free(item);
1079910913
}
10914+
fnvlist_free(props);
1080010915
}
1080110916
}
1080210917

@@ -10824,6 +10939,7 @@ zpool_do_get(int argc, char **argv)
1082410939
int c, i;
1082510940
char *propstr = NULL;
1082610941
char *vdev = NULL;
10942+
nvlist_t *data;
1082710943

1082810944
cb.cb_first = B_TRUE;
1082910945

@@ -10840,14 +10956,21 @@ zpool_do_get(int argc, char **argv)
1084010956
current_prop_type = cb.cb_type;
1084110957

1084210958
/* check options */
10843-
while ((c = getopt(argc, argv, ":Hpo:")) != -1) {
10959+
while ((c = getopt(argc, argv, ":jHpo:")) != -1) {
1084410960
switch (c) {
1084510961
case 'p':
1084610962
cb.cb_literal = B_TRUE;
1084710963
break;
1084810964
case 'H':
1084910965
cb.cb_scripted = B_TRUE;
1085010966
break;
10967+
case 'j':
10968+
cb.cb_json = B_TRUE;
10969+
cb.cb_jsobj = zpool_json_schema(0, 1);
10970+
data = fnvlist_alloc();
10971+
fnvlist_add_nvlist(cb.cb_jsobj, "data", data);
10972+
fnvlist_free(data);
10973+
break;
1085110974
case 'o':
1085210975
memset(&cb.cb_columns, 0, sizeof (cb.cb_columns));
1085310976
i = 0;
@@ -10970,6 +11093,9 @@ zpool_do_get(int argc, char **argv)
1097011093
ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist, cb.cb_type,
1097111094
cb.cb_literal, get_callback, &cb);
1097211095

11096+
if (cb.cb_json)
11097+
zcmd_print_json(cb.cb_jsobj);
11098+
1097311099
if (cb.cb_proplist == &fake_name)
1097411100
zprop_free_list(fake_name.pl_next);
1097511101
else

include/libzfs.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,10 @@ _LIBZFS_H void zprop_print_one_property(const char *, zprop_get_cbdata_t *,
678678
_LIBZFS_H int zprop_nvlist_one_property(const char *, const char *,
679679
zprop_source_t, const char *, const char *, nvlist_t *);
680680

681+
_LIBZFS_H int zprop_collect_property(const char *, zprop_get_cbdata_t *,
682+
const char *, const char *, zprop_source_t, const char *,
683+
const char *, nvlist_t *);
684+
681685
/*
682686
* Iterator functions.
683687
*/

lib/libzfs/libzfs_util.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1580,6 +1580,25 @@ zprop_print_one_property(const char *name, zprop_get_cbdata_t *cbp,
15801580
(void) printf("\n");
15811581
}
15821582

1583+
int
1584+
zprop_collect_property(const char *name, zprop_get_cbdata_t *cbp,
1585+
const char *propname, const char *value, zprop_source_t sourcetype,
1586+
const char *source, const char *recvd_value, nvlist_t *nvl)
1587+
{
1588+
if (cbp->cb_json) {
1589+
if ((sourcetype & cbp->cb_sources) == 0)
1590+
return (0);
1591+
else {
1592+
return (zprop_nvlist_one_property(propname, value,
1593+
sourcetype, source, recvd_value, nvl));
1594+
}
1595+
} else {
1596+
zprop_print_one_property(name, cbp,
1597+
propname, value, sourcetype, source, recvd_value);
1598+
return (0);
1599+
}
1600+
}
1601+
15831602
/*
15841603
* Given a numeric suffix, convert the value into a number of bits that the
15851604
* resulting value must be shifted.

0 commit comments

Comments
 (0)