On Fri, May 13, 2016 at 10:39:00AM -0400, Todd Gill wrote: ACK -Ben > The patch adds these commands: > > multipathd show maps json > multipathd show map $map json > > Each command will output the requested map(s) in JSON. > > For the "show maps json" command, the patch pre-allocates > INITIAL_REPLY_LEN * PRINT_JSON_MULTIPLIER(5). The JSON text > is about 5x the size of the "show maps topology" text. > > v3: > > Added format specifiers at the map level to split out > vend/prod/rev. > > A user can now specify the following with: > > multipathd show map(s) format > > %v - vend > %p - prod > %e - rev > > Signed-off-by: Todd Gill <tgill@xxxxxxxxxx> > --- > libmultipath/print.c | 220 ++++++++++++++++++++++++++++++++++++++++++++++ > libmultipath/print.h | 65 ++++++++++++++ > multipathd/cli.c | 3 + > multipathd/cli.h | 2 + > multipathd/cli_handlers.c | 93 ++++++++++++++++++++ > multipathd/cli_handlers.h | 2 + > multipathd/main.c | 2 + > 7 files changed, 387 insertions(+) > > diff --git a/libmultipath/print.c b/libmultipath/print.c > index 7fec6e9..5d668bb 100644 > --- a/libmultipath/print.c > +++ b/libmultipath/print.c > @@ -274,6 +274,61 @@ snprint_multipath_vpr (char * buff, size_t len, struct multipath * mpp) > return snprintf(buff, len, "##,##"); > } > > + > +static int > +snprint_multipath_vend (char * buff, size_t len, struct multipath * mpp) > +{ > + struct pathgroup * pgp; > + struct path * pp; > + int i, j; > + > + vector_foreach_slot(mpp->pg, pgp, i) { > + if (!pgp) > + continue; > + vector_foreach_slot(pgp->paths, pp, j) { > + if (strlen(pp->vendor_id)) > + return snprintf(buff, len, "%s", pp->vendor_id); > + } > + } > + return snprintf(buff, len, "##"); > +} > + > +static int > +snprint_multipath_prod (char * buff, size_t len, struct multipath * mpp) > +{ > + struct pathgroup * pgp; > + struct path * pp; > + int i, j; > + > + vector_foreach_slot(mpp->pg, pgp, i) { > + if (!pgp) > + continue; > + vector_foreach_slot(pgp->paths, pp, j) { > + if (strlen(pp->product_id)) > + return snprintf(buff, len, "%s", pp->product_id); > + } > + } > + return snprintf(buff, len, "##"); > +} > + > +static int > +snprint_multipath_rev (char * buff, size_t len, struct multipath * mpp) > +{ > + struct pathgroup * pgp; > + struct path * pp; > + int i, j; > + > + vector_foreach_slot(mpp->pg, pgp, i) { > + if (!pgp) > + continue; > + vector_foreach_slot(pgp->paths, pp, j) { > + if (strlen(pp->rev)) > + return snprintf(buff, len, "%s", pp->rev); > + } > + } > + return snprintf(buff, len, "##"); > +} > + > static int > snprint_action (char * buff, size_t len, struct multipath * mpp) > { > @@ -577,6 +632,9 @@ struct multipath_data mpd[] = { > {'3', "total_q_time", 0, snprint_total_q_time}, > {'4', "q_timeouts", 0, snprint_q_timeouts}, > {'s', "vend/prod/rev", 0, snprint_multipath_vpr}, > + {'v', "vend", 0, snprint_multipath_vend}, > + {'p', "prod", 0, snprint_multipath_prod}, > + {'e', "rev", 0, snprint_multipath_rev}, > {0, NULL, 0 , NULL} > }; > > @@ -1000,6 +1058,168 @@ snprint_multipath_topology (char * buff, int len, struct multipath * mpp, > } > > static int > +snprint_json (char * buff, int len, int indent, char *json_str) > +{ > + int fwd = 0, i; > + > + for (i = 0; i < indent; i++) { > + fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_INDENT); > + if (fwd > len) > + return fwd; > + } > + > + fwd += snprintf(buff + fwd, len - fwd, "%s", json_str); > + return fwd; > +} > + > +static int > +snprint_json_header (char * buff, int len) > +{ > + int fwd = 0; > + > + fwd += snprint_json(buff, len, 0, PRINT_JSON_START_ELEM); > + if (fwd > len) > + return fwd; > + > + fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_START_VERSION, > + PRINT_JSON_MAJOR_VERSION, PRINT_JSON_MINOR_VERSION); > + return fwd; > +} > + > +static int > +snprint_json_elem_footer (char * buff, int len, int indent, int last) > +{ > + int fwd = 0, i; > + > + for (i = 0; i < indent; i++) { > + fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_INDENT); > + if (fwd > len) > + return fwd; > + } > + > + if (last == 1) > + fwd += snprintf(buff + fwd, len - fwd, "%s", PRINT_JSON_END_LAST_ELEM); > + else > + fwd += snprintf(buff + fwd, len - fwd, "%s", PRINT_JSON_END_ELEM); > + return fwd; > +} > + > +static int > +snprint_multipath_fields_json (char * buff, int len, > + struct multipath * mpp, int last) > +{ > + int i, j, fwd = 0; > + struct path *pp; > + struct pathgroup *pgp; > + > + fwd += snprint_multipath(buff, len, PRINT_JSON_MAP, mpp, 0); > + if (fwd > len) > + return fwd; > + > + fwd += snprint_json(buff + fwd, len - fwd, 2, PRINT_JSON_START_GROUPS); > + if (fwd > len) > + return fwd; > + > + vector_foreach_slot (mpp->pg, pgp, i) { > + > + pgp->selector = mpp->selector; > + fwd += snprint_pathgroup(buff + fwd, len - fwd, PRINT_JSON_GROUP, pgp); > + if (fwd > len) > + return fwd; > + > + fwd += snprint_json(buff + fwd, len - fwd, 3, PRINT_JSON_START_PATHS); > + if (fwd > len) > + return fwd; > + > + vector_foreach_slot (pgp->paths, pp, j) { > + fwd += snprint_path(buff + fwd, len - fwd, PRINT_JSON_PATH, pp, 0); > + if (fwd > len) > + return fwd; > + > + fwd += snprint_json_elem_footer(buff + fwd, > + len - fwd, 3, j + 1 == VECTOR_SIZE(pgp->paths)); > + if (fwd > len) > + return fwd; > + } > + fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY); > + if (fwd > len) > + return fwd; > + > + fwd += snprint_json_elem_footer(buff + fwd, > + len - fwd, 2, i + 1 == VECTOR_SIZE(mpp->pg)); > + if (fwd > len) > + return fwd; > + } > + > + fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY); > + if (fwd > len) > + return fwd; > + > + fwd += snprint_json_elem_footer(buff + fwd, len - fwd, 1, last); > + return fwd; > +} > + > +int > +snprint_multipath_map_json (char * buff, int len, > + struct multipath * mpp, int last){ > + int fwd = 0; > + > + memset(buff, 0, len); > + fwd += snprint_json_header(buff, len); > + if (fwd > len) > + return len; > + > + fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_START_MAP); > + if (fwd > len) > + return len; > + > + fwd += snprint_multipath_fields_json(buff + fwd, len - fwd, mpp, 1); > + if (fwd > len) > + return len; > + > + fwd += snprint_json(buff + fwd, len - fwd, 0, "\n"); > + if (fwd > len) > + return len; > + > + fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_LAST); > + if (fwd > len) > + return len; > + return fwd; > +} > + > +int > +snprint_multipath_topology_json (char * buff, int len, struct vectors * vecs) > +{ > + int i, fwd = 0; > + struct multipath * mpp; > + > + memset(buff, 0, len); > + fwd += snprint_json_header(buff, len); > + if (fwd > len) > + return len; > + > + fwd += snprint_json(buff + fwd, len - fwd, 1, PRINT_JSON_START_MAPS); > + if (fwd > len) > + return len; > + > + vector_foreach_slot(vecs->mpvec, mpp, i) { > + fwd += snprint_multipath_fields_json(buff + fwd, len - fwd, > + mpp, i + 1 == VECTOR_SIZE(vecs->mpvec)); > + if (fwd > len) > + return len; > + } > + > + fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY); > + if (fwd > len) > + return len; > + > + fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_LAST); > + if (fwd > len) > + return len; > + return fwd; > +} > + > +static int > snprint_hwentry (char * buff, int len, struct hwentry * hwe) > { > int i; > diff --git a/libmultipath/print.h b/libmultipath/print.h > index 8bd0bbc..92ade7e 100644 > --- a/libmultipath/print.h > +++ b/libmultipath/print.h > @@ -7,6 +7,67 @@ > #define PRINT_MAP_PROPS "size=%S features='%f' hwhandler='%h' wp=%r" > #define PRINT_PG_INDENT "policy='%s' prio=%p status=%t" > > +#define PRINT_JSON_MULTIPLIER 5 > +#define PRINT_JSON_MAJOR_VERSION 0 > +#define PRINT_JSON_MINOR_VERSION 1 > +#define PRINT_JSON_START_VERSION " \"major_version \": %d,\n" \ > + " \"minor_version \": %d,\n" > +#define PRINT_JSON_START_ELEM "{\n" > +#define PRINT_JSON_START_MAP " \"map\":" > +#define PRINT_JSON_START_MAPS "\"maps\": [" > +#define PRINT_JSON_START_PATHS "\"paths\": [" > +#define PRINT_JSON_START_GROUPS "\"path_groups\": [" > +#define PRINT_JSON_END_ELEM "}," > +#define PRINT_JSON_END_LAST_ELEM "}" > +#define PRINT_JSON_END_LAST "}\n" > +#define PRINT_JSON_END_ARRAY "]\n" > +#define PRINT_JSON_INDENT " " > +#define PRINT_JSON_MAP "{\n" \ > + " \"name\" : \"%n\",\n" \ > + " \"uuid\" : \"%w\",\n" \ > + " \"sysfs\" : \"%d\",\n" \ > + " \"failback\" : \"%F\",\n" \ > + " \"queueing\" : \"%Q\",\n" \ > + " \"paths\" : %N,\n" \ > + " \"write_prot\" : \"%r\",\n" \ > + " \"dm-st\" : \"%t\",\n" \ > + " \"size\" : \"%S\",\n" \ > + " \"features\" : \"%f\",\n" \ > + " \"hwhandler\" : \"%h\",\n" \ > + " \"action\" : \"%A\",\n" \ > + " \"path_faults\" : %0,\n" \ > + " \"vend\" : \"%v\",\n" \ > + " \"prod\" : \"%p\",\n" \ > + " \"rev\" : \"%e\",\n" \ > + " \"switch_grp\" : %1,\n" \ > + " \"map_loads\" : %2,\n" \ > + " \"total_q_time\" : %3,\n" \ > + " \"q_timeouts\" : %4," > + > +#define PRINT_JSON_GROUP "{\n" \ > + " \"selector\" : \"%s\",\n" \ > + " \"pri\" : %p,\n" \ > + " \"dm_st\" : \"%t\"," > + > +#define PRINT_JSON_PATH "{\n" \ > + " \"uuid\" : \"%w\",\n" \ > + " \"hcil\" : \"%i\",\n" \ > + " \"dev\" : \"%d\",\n"\ > + " \"dev_t\" : \"%D\",\n" \ > + " \"dm_st\" : \"%t\",\n" \ > + " \"dev_st\" : \"%o\",\n" \ > + " \"chk_st\" : \"%T\",\n" \ > + " \"checker\" : \"%c\",\n" \ > + " \"next_check\" : \"%C\",\n" \ > + " \"pri\" : %p,\n" \ > + " \"size\" : \"%S\",\n" \ > + " \"serial\" : \"%z\",\n" \ > + " \"host WWNN\" : \"%N\",\n" \ > + " \"target WWNN\" : \"%n\",\n" \ > + " \"host WWPN\" : \"%R\",\n" \ > + " \"target WWPN\" : \"%r\",\n" \ > + " \"host adapter\" : \"%a\"" > + > #define MAX_LINE_LEN 80 > #define MAX_LINES 64 > #define MAX_FIELD_LEN 64 > @@ -41,6 +102,10 @@ int snprint_path (char *, int, char *, struct path *, int); > int snprint_multipath (char *, int, char *, struct multipath *, int); > int snprint_multipath_topology (char *, int, struct multipath * mpp, > int verbosity); > +int snprint_multipath_topology_json (char * buff, int len, > + struct vectors * vecs); > +int snprint_multipath_map_json (char * buff, int len, > + struct multipath * mpp, int last); > int snprint_defaults (char *, int); > int snprint_blacklist (char *, int); > int snprint_blacklist_except (char *, int); > diff --git a/multipathd/cli.c b/multipathd/cli.c > index d991cd0..20ee3db 100644 > --- a/multipathd/cli.c > +++ b/multipathd/cli.c > @@ -207,6 +207,7 @@ load_keys (void) > r += add_key(keys, "setprstatus", SETPRSTATUS, 0); > r += add_key(keys, "unsetprstatus", UNSETPRSTATUS, 0); > r += add_key(keys, "format", FMT, 1); > + r += add_key(keys, "json", JSON, 0); > > if (r) { > free_keys(keys); > @@ -537,8 +538,10 @@ cli_init (void) { > add_handler(LIST+MAPS+FMT, NULL); > add_handler(LIST+MAPS+RAW+FMT, NULL); > add_handler(LIST+MAPS+TOPOLOGY, NULL); > + add_handler(LIST+MAPS+JSON, NULL); > add_handler(LIST+TOPOLOGY, NULL); > add_handler(LIST+MAP+TOPOLOGY, NULL); > + add_handler(LIST+MAP+JSON, NULL); > add_handler(LIST+MAP+FMT, NULL); > add_handler(LIST+MAP+RAW+FMT, NULL); > add_handler(LIST+CONFIG, NULL); > diff --git a/multipathd/cli.h b/multipathd/cli.h > index 84ca40f..92cb41b 100644 > --- a/multipathd/cli.h > +++ b/multipathd/cli.h > @@ -36,6 +36,7 @@ enum { > __SETPRSTATUS, > __UNSETPRSTATUS, > __FMT, > + __JSON, > }; > > #define LIST (1 << __LIST) > @@ -74,6 +75,7 @@ enum { > #define SETPRSTATUS (1ULL << __SETPRSTATUS) > #define UNSETPRSTATUS (1ULL << __UNSETPRSTATUS) > #define FMT (1ULL << __FMT) > +#define JSON (1ULL << __JSON) > > #define INITIAL_REPLY_LEN 1200 > > diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c > index 8b3cb9d..19cf2ff 100644 > --- a/multipathd/cli_handlers.c > +++ b/multipathd/cli_handlers.c > @@ -156,6 +156,70 @@ show_maps_topology (char ** r, int * len, struct vectors * vecs) > } > > int > +show_maps_json (char ** r, int * len, struct vectors * vecs) > +{ > + int i; > + struct multipath * mpp; > + char * c; > + char * reply; > + unsigned int maxlen = INITIAL_REPLY_LEN * PRINT_JSON_MULTIPLIER; > + int again = 1; > + > + vector_foreach_slot(vecs->mpvec, mpp, i) { > + if (update_multipath(vecs, mpp->alias, 0)) { > + return 1; > + } > + } > + > + reply = MALLOC(maxlen); > + > + while (again) { > + if (!reply) > + return 1; > + > + c = reply; > + > + c += snprint_multipath_topology_json(c, reply + maxlen - c, > + vecs); > + again = ((c - reply) == maxlen); > + > + REALLOC_REPLY(reply, again, maxlen); > + } > + *r = reply; > + *len = (int)(c - reply + 1); > + return 0; > +} > + > +int > +show_map_json (char ** r, int * len, struct multipath * mpp, > + struct vectors * vecs) > +{ > + char * c; > + char * reply; > + unsigned int maxlen = INITIAL_REPLY_LEN; > + int again = 1; > + > + if (update_multipath(vecs, mpp->alias, 0)) > + return 1; > + reply = MALLOC(maxlen); > + > + while (again) { > + if (!reply) > + return 1; > + > + c = reply; > + > + c += snprint_multipath_map_json(c, reply + maxlen - c, mpp, 1); > + again = ((c - reply) == maxlen); > + > + REALLOC_REPLY(reply, again, maxlen); > + } > + *r = reply; > + *len = (int)(c - reply + 1); > + return 0; > +} > + > +int > show_config (char ** r, int * len) > { > char * c; > @@ -291,6 +355,35 @@ cli_list_maps_topology (void * v, char ** reply, int * len, void * data) > } > > int > +cli_list_map_json (void * v, char ** reply, int * len, void * data) > +{ > + struct multipath * mpp; > + struct vectors * vecs = (struct vectors *)data; > + char * param = get_keyparam(v, MAP); > + > + param = convert_dev(param, 0); > + get_path_layout(vecs->pathvec, 0); > + mpp = find_mp_by_str(vecs->mpvec, param); > + > + if (!mpp) > + return 1; > + > + condlog(3, "list multipath json %s (operator)", param); > + > + return show_map_json(reply, len, mpp, vecs); > +} > + > +int > +cli_list_maps_json (void * v, char ** reply, int * len, void * data) > +{ > + struct vectors * vecs = (struct vectors *)data; > + > + condlog(3, "list multipaths json (operator)"); > + > + return show_maps_json(reply, len, vecs); > +} > + > +int > cli_list_wildcards (void * v, char ** reply, int * len, void * data) > { > char * c; > diff --git a/multipathd/cli_handlers.h b/multipathd/cli_handlers.h > index 5d51018..e838f19 100644 > --- a/multipathd/cli_handlers.h > +++ b/multipathd/cli_handlers.h > @@ -13,6 +13,8 @@ int cli_list_maps_status (void * v, char ** reply, int * len, void * data); > int cli_list_maps_stats (void * v, char ** reply, int * len, void * data); > int cli_list_map_topology (void * v, char ** reply, int * len, void * data); > int cli_list_maps_topology (void * v, char ** reply, int * len, void * data); > +int cli_list_map_json (void * v, char ** reply, int * len, void * data); > +int cli_list_maps_json (void * v, char ** reply, int * len, void * data); > int cli_list_config (void * v, char ** reply, int * len, void * data); > int cli_list_blacklist (void * v, char ** reply, int * len, void * data); > int cli_list_devices (void * v, char ** reply, int * len, void * data); > diff --git a/multipathd/main.c b/multipathd/main.c > index 58e8854..33f38cd 100644 > --- a/multipathd/main.c > +++ b/multipathd/main.c > @@ -1120,9 +1120,11 @@ uxlsnrloop (void * ap) > set_handler_callback(LIST+MAPS+RAW+FMT, cli_list_maps_raw); > set_handler_callback(LIST+MAPS+TOPOLOGY, cli_list_maps_topology); > set_handler_callback(LIST+TOPOLOGY, cli_list_maps_topology); > + set_handler_callback(LIST+MAPS+JSON, cli_list_maps_json); > set_handler_callback(LIST+MAP+TOPOLOGY, cli_list_map_topology); > set_handler_callback(LIST+MAP+FMT, cli_list_map_fmt); > set_handler_callback(LIST+MAP+RAW+FMT, cli_list_map_fmt); > + set_handler_callback(LIST+MAP+JSON, cli_list_map_json); > set_unlocked_handler_callback(LIST+CONFIG, cli_list_config); > set_unlocked_handler_callback(LIST+BLACKLIST, cli_list_blacklist); > set_handler_callback(LIST+DEVICES, cli_list_devices); > -- > 2.5.5 > > -- > dm-devel mailing list > dm-devel@xxxxxxxxxx > https://www.redhat.com/mailman/listinfo/dm-devel -- dm-devel mailing list dm-devel@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/dm-devel