<div dir="ltr">Hi,<div><br></div><div>the json choice over xml is fine for me, so I'm ready to merge.</div><div><br></div><div>Before I do so, is there a second round of review pending ?</div><div><br></div><div>Are wannabe users of this new output happy with some fields being merged (like vendor/product/rev) ?</div><div><br></div><div>Best regards,</div><div>Christophe Varoqui</div><div>OpenSVC</div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, May 10, 2016 at 9:05 PM, Todd Gill <span dir="ltr"><<a href="mailto:tgill@redhat.com" target="_blank">tgill@redhat.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">The patch add these commands:<br>
<br>
multipathd show maps json<br>
multipathd show map $map json<br>
<br>
Each command will output the requested map(s) in JSON.<br>
<br>
For the "show maps json" command, the patch pre-allocates<br>
INITIAL_REPLY_LEN * PRINT_JSON_MULTIPLIER(5).  The JSON text<br>
is about 5x the size of the "show maps topology" text.<br>
<br>
Signed-off-by: Todd Gill <<a href="mailto:tgill@redhat.com">tgill@redhat.com</a>><br>
---<br>
 libmultipath/print.c      | 163 ++++++++++++++++++++++++++++++++++++++++++++++<br>
 libmultipath/print.h      |  63 ++++++++++++++++++<br>
 multipathd/cli.c          |   3 +<br>
 multipathd/cli.h          |   2 +<br>
 multipathd/cli_handlers.c |  93 ++++++++++++++++++++++++++<br>
 multipathd/cli_handlers.h |   2 +<br>
 multipathd/main.c         |   2 +<br>
 7 files changed, 328 insertions(+)<br>
<br>
diff --git a/libmultipath/print.c b/libmultipath/print.c<br>
index 7fec6e9..e92b534 100644<br>
--- a/libmultipath/print.c<br>
+++ b/libmultipath/print.c<br>
@@ -1000,6 +1000,169 @@ snprint_multipath_topology (char * buff, int len, struct multipath * mpp,<br>
 }<br>
<br>
 static int<br>
+snprint_json (char * line, int len, int indent, char *json_str)<br>
+{<br>
+       int fwd = 0, i;<br>
+<br>
+       for (i = 0; i < indent; i++) {<br>
+               fwd += snprintf(line + fwd, len - fwd, PRINT_JSON_INDENT);<br>
+               if (fwd > len)<br>
+                       return fwd;<br>
+       }<br>
+<br>
+       fwd += snprintf(line + fwd, len - fwd, "%s", json_str);<br>
+       return fwd;<br>
+}<br>
+<br>
+static int<br>
+snprint_json_header (char * line, int len)<br>
+{<br>
+       int fwd = 0;<br>
+<br>
+       fwd +=  snprint_json(line + fwd, len, 0, PRINT_JSON_START_ELEM);<br>
+       if (fwd > len)<br>
+               return fwd;<br>
+<br>
+       fwd +=  snprintf(line + fwd, len  - fwd, PRINT_JSON_START_VERSION,<br>
+                       PRINT_JSON_MAJOR_VERSION, PRINT_JSON_MINOR_VERSION);<br>
+       return fwd;<br>
+}<br>
+<br>
+static int<br>
+snprint_json_elem_footer (char * line, int len, int indent, int last)<br>
+{<br>
+       int fwd = 0, i;<br>
+<br>
+       for (i = 0; i < indent; i++) {<br>
+               fwd += snprintf(line + fwd, len - fwd, PRINT_JSON_INDENT);<br>
+               if (fwd > len)<br>
+                       return fwd;<br>
+       }<br>
+<br>
+       if (last == 1)<br>
+               fwd += snprintf(line + fwd, len - fwd, "%s",<br>
+                               PRINT_JSON_END_LAST);<br>
+       else<br>
+               fwd += snprintf(line + fwd, len - fwd, "%s",<br>
+                               PRINT_JSON_END_ELEM);<br>
+       return fwd;<br>
+}<br>
+<br>
+static int<br>
+snprint_multipath_fields_json (char * buff, int len,<br>
+               struct multipath * mpp, int last)<br>
+{<br>
+       int i, j, fwd = 0;<br>
+       struct path *pp;<br>
+       struct pathgroup *pgp;<br>
+<br>
+       fwd += snprint_multipath(buff + fwd, len - fwd, PRINT_JSON_MAP, mpp, 0);<br>
+       if (fwd > len)<br>
+               return fwd;<br>
+<br>
+       fwd += snprint_json(buff + fwd, len - fwd, 2, PRINT_JSON_START_GROUPS);<br>
+       if (fwd > len)<br>
+               return fwd;<br>
+<br>
+       vector_foreach_slot (mpp->pg, pgp, i) {<br>
+<br>
+               pgp->selector = mpp->selector;<br>
+               fwd += snprint_pathgroup(buff + fwd, len - fwd, PRINT_JSON_GROUP, pgp);<br>
+               if (fwd > len)<br>
+                       return fwd;<br>
+<br>
+               fwd += snprint_json(buff + fwd, len - fwd, 3, PRINT_JSON_START_PATHS);<br>
+               if (fwd > len)<br>
+                       return fwd;<br>
+<br>
+               vector_foreach_slot (pgp->paths, pp, j) {<br>
+<br>
+                       fwd += snprint_path(buff + fwd,<br>
+                                       len - fwd, PRINT_JSON_PATH, pp, 0);<br>
+                       if (fwd > len)<br>
+                               return fwd;<br>
+<br>
+                       fwd += snprint_json_elem_footer(buff + fwd,<br>
+                                       len - fwd, 3, j + 1 == VECTOR_SIZE(pgp->paths));<br>
+                       if (fwd > len)<br>
+                               return fwd;<br>
+               }<br>
+<br>
+               fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY);<br>
+               if (fwd > len)<br>
+                       return fwd;<br>
+<br>
+               fwd +=  snprint_json_elem_footer(buff + fwd,<br>
+                       len - fwd, 2, i + 1 == VECTOR_SIZE(mpp->pg));<br>
+               if (fwd > len)<br>
+                       return fwd;<br>
+       }<br>
+<br>
+       fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY);<br>
+       if (fwd > len)<br>
+               return fwd;<br>
+<br>
+       fwd += snprint_json_elem_footer(buff + fwd, len - fwd, 1, last);<br>
+       return fwd;<br>
+}<br>
+<br>
+int<br>
+snprint_multipath_map_json (char * buff, int len,<br>
+               struct multipath * mpp, int last){<br>
+       int fwd = 0;<br>
+<br>
+       memset(buff, 0, len);<br>
+       fwd +=  snprint_json_header(buff + fwd, len);<br>
+       if (fwd > len)<br>
+               return len;<br>
+<br>
+       fwd +=  snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_START_MAP);<br>
+       if (fwd > len)<br>
+               return len;<br>
+<br>
+       fwd += snprint_multipath_fields_json(buff + fwd, len - fwd, mpp, 1);<br>
+       if (fwd > len)<br>
+               return len;<br>
+<br>
+       fwd +=  snprint_json(buff + fwd, len - fwd, 0, "\n"PRINT_JSON_END_LAST);<br>
+       if (fwd > len)<br>
+               return len;<br>
+       return fwd;<br>
+}<br>
+<br>
+int<br>
+snprint_multipath_topology_json (char * buff, int len, struct vectors * vecs)<br>
+{<br>
+       int i, fwd = 0;<br>
+       struct multipath * mpp;<br>
+<br>
+       memset(buff, 0, len);<br>
+       fwd +=  snprint_json_header(buff + fwd, len);<br>
+       if (fwd > len)<br>
+               return len;<br>
+<br>
+       fwd +=  snprint_json(buff + fwd, len  - fwd, 1, PRINT_JSON_START_MAPS);<br>
+       if (fwd > len)<br>
+               return len;<br>
+<br>
+       vector_foreach_slot(vecs->mpvec, mpp, i) {<br>
+               fwd += snprint_multipath_fields_json(buff + fwd, len - fwd,<br>
+                               mpp, i + 1 == VECTOR_SIZE(vecs->mpvec));<br>
+               if (fwd > len)<br>
+                       return len;<br>
+       }<br>
+<br>
+       fwd +=  snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY);<br>
+       if (fwd > len)<br>
+               return len;<br>
+<br>
+       fwd +=  snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_LAST);<br>
+       if (fwd > len)<br>
+               return len;<br>
+       return fwd;<br>
+}<br>
+<br>
+static int<br>
 snprint_hwentry (char * buff, int len, struct hwentry * hwe)<br>
 {<br>
        int i;<br>
diff --git a/libmultipath/print.h b/libmultipath/print.h<br>
index 8bd0bbc..f8a383d 100644<br>
--- a/libmultipath/print.h<br>
+++ b/libmultipath/print.h<br>
@@ -7,6 +7,65 @@<br>
 #define PRINT_MAP_PROPS      "size=%S features='%f' hwhandler='%h' wp=%r"<br>
 #define PRINT_PG_INDENT      "policy='%s' prio=%p status=%t"<br>
<br>
+#define PRINT_JSON_MULTIPLIER     5<br>
+#define PRINT_JSON_MAJOR_VERSION  0<br>
+#define PRINT_JSON_MINOR_VERSION  1<br>
+#define PRINT_JSON_START_VERSION  "   \"major_version \": %d,\n" \<br>
+                                  "   \"minor_version \": %d,\n"<br>
+#define PRINT_JSON_START_ELEM     "{\n"<br>
+#define PRINT_JSON_START_MAP      "   \"map\":"<br>
+#define PRINT_JSON_START_MAPS     "\"maps\": ["<br>
+#define PRINT_JSON_START_PATHS    "\"paths\": ["<br>
+#define PRINT_JSON_START_GROUPS   "\"path_groups\": ["<br>
+#define PRINT_JSON_END_ELEM       "},"<br>
+#define PRINT_JSON_END_LAST       "}"<br>
+#define PRINT_JSON_END_ARRAY      "]\n"<br>
+#define PRINT_JSON_INDENT    "   "<br>
+#define PRINT_JSON_MAP       "{\n" \<br>
+                             "      \"name\" : \"%n\",\n" \<br>
+                             "      \"uuid\" : \"%w\",\n" \<br>
+                             "      \"sysfs\" : \"%d\",\n" \<br>
+                             "      \"failback\" : \"%F\",\n" \<br>
+                             "      \"queueing\" : \"%Q\",\n" \<br>
+                             "      \"paths\" : %N,\n" \<br>
+                             "      \"write_prot\" : \"%r\",\n" \<br>
+                             "      \"dm-st\" : \"%t\",\n" \<br>
+                             "      \"size\" : \"%S\",\n" \<br>
+                             "      \"features\" : \"%f\",\n" \<br>
+                             "      \"hwhandler\" : \"%h\",\n" \<br>
+                             "      \"action\" : \"%A\",\n" \<br>
+                             "      \"path_faults\" : %0,\n" \<br>
+                             "      \"vend/prod/rev\" : \"%s\",\n" \<br>
+                             "      \"switch_grp\" : %1,\n" \<br>
+                             "      \"map_loads\" : %2,\n" \<br>
+                             "      \"total_q_time\" : %3,\n" \<br>
+                             "      \"q_timeouts\" : %4,"<br>
+<br>
+#define PRINT_JSON_GROUP     "{\n" \<br>
+                             "         \"selector\" : \"%s\",\n" \<br>
+                             "         \"pri\" : %p,\n" \<br>
+                             "         \"dm_st\" : \"%t\","<br>
+<br>
+#define PRINT_JSON_PATH      "{\n" \<br>
+                             "            \"uuid\" : \"%w\",\n" \<br>
+                             "            \"hcil\" : \"%i\",\n" \<br>
+                             "            \"dev\" : \"%d\",\n"\<br>
+                             "            \"dev_t\" : \"%D\",\n" \<br>
+                             "            \"dm_st\" : \"%t\",\n" \<br>
+                             "            \"dev_st\" : \"%o\",\n" \<br>
+                             "            \"chk_st\" : \"%T\",\n" \<br>
+                             "            \"vend/prod/rev\" : \"%s\",\n" \<br>
+                             "            \"checker\" : \"%c\",\n" \<br>
+                             "            \"next_check\" : \"%C\",\n" \<br>
+                             "            \"pri\" : %p,\n" \<br>
+                             "            \"size\" : \"%S\",\n" \<br>
+                             "            \"serial\" : \"%z\",\n" \<br>
+                             "            \"host WWNN\" : \"%N\",\n" \<br>
+                             "            \"target WWNN\" : \"%n\",\n" \<br>
+                             "            \"host WWPN\" : \"%R\",\n" \<br>
+                             "            \"target WWPN\" : \"%r\",\n" \<br>
+                             "            \"host adapter\" : \"%a\""<br>
+<br>
 #define MAX_LINE_LEN  80<br>
 #define MAX_LINES     64<br>
 #define MAX_FIELD_LEN 64<br>
@@ -41,6 +100,10 @@ int snprint_path (char *, int, char *, struct path *, int);<br>
 int snprint_multipath (char *, int, char *, struct multipath *, int);<br>
 int snprint_multipath_topology (char *, int, struct multipath * mpp,<br>
                                int verbosity);<br>
+int snprint_multipath_topology_json (char * buff, int len,<br>
+                               struct vectors * vecs);<br>
+int snprint_multipath_map_json (char * buff, int len,<br>
+                               struct multipath * mpp, int last);<br>
 int snprint_defaults (char *, int);<br>
 int snprint_blacklist (char *, int);<br>
 int snprint_blacklist_except (char *, int);<br>
diff --git a/multipathd/cli.c b/multipathd/cli.c<br>
index d991cd0..20ee3db 100644<br>
--- a/multipathd/cli.c<br>
+++ b/multipathd/cli.c<br>
@@ -207,6 +207,7 @@ load_keys (void)<br>
        r += add_key(keys, "setprstatus", SETPRSTATUS, 0);<br>
        r += add_key(keys, "unsetprstatus", UNSETPRSTATUS, 0);<br>
        r += add_key(keys, "format", FMT, 1);<br>
+       r += add_key(keys, "json", JSON, 0);<br>
<br>
        if (r) {<br>
                free_keys(keys);<br>
@@ -537,8 +538,10 @@ cli_init (void) {<br>
        add_handler(LIST+MAPS+FMT, NULL);<br>
        add_handler(LIST+MAPS+RAW+FMT, NULL);<br>
        add_handler(LIST+MAPS+TOPOLOGY, NULL);<br>
+       add_handler(LIST+MAPS+JSON, NULL);<br>
        add_handler(LIST+TOPOLOGY, NULL);<br>
        add_handler(LIST+MAP+TOPOLOGY, NULL);<br>
+       add_handler(LIST+MAP+JSON, NULL);<br>
        add_handler(LIST+MAP+FMT, NULL);<br>
        add_handler(LIST+MAP+RAW+FMT, NULL);<br>
        add_handler(LIST+CONFIG, NULL);<br>
diff --git a/multipathd/cli.h b/multipathd/cli.h<br>
index 84ca40f..92cb41b 100644<br>
--- a/multipathd/cli.h<br>
+++ b/multipathd/cli.h<br>
@@ -36,6 +36,7 @@ enum {<br>
        __SETPRSTATUS,<br>
        __UNSETPRSTATUS,<br>
        __FMT,<br>
+       __JSON,<br>
 };<br>
<br>
 #define LIST           (1 << __LIST)<br>
@@ -74,6 +75,7 @@ enum {<br>
 #define SETPRSTATUS    (1ULL << __SETPRSTATUS)<br>
 #define UNSETPRSTATUS  (1ULL << __UNSETPRSTATUS)<br>
 #define FMT            (1ULL << __FMT)<br>
+#define JSON           (1ULL << __JSON)<br>
<br>
 #define INITIAL_REPLY_LEN      1200<br>
<br>
diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c<br>
index 8b3cb9d..19cf2ff 100644<br>
--- a/multipathd/cli_handlers.c<br>
+++ b/multipathd/cli_handlers.c<br>
@@ -156,6 +156,70 @@ show_maps_topology (char ** r, int * len, struct vectors * vecs)<br>
 }<br>
<br>
 int<br>
+show_maps_json (char ** r, int * len, struct vectors * vecs)<br>
+{<br>
+       int i;<br>
+       struct multipath * mpp;<br>
+       char * c;<br>
+       char * reply;<br>
+       unsigned int maxlen = INITIAL_REPLY_LEN * PRINT_JSON_MULTIPLIER;<br>
+       int again = 1;<br>
+<br>
+       vector_foreach_slot(vecs->mpvec, mpp, i) {<br>
+               if (update_multipath(vecs, mpp->alias, 0)) {<br>
+                       return 1;<br>
+               }<br>
+       }<br>
+<br>
+       reply = MALLOC(maxlen);<br>
+<br>
+       while (again) {<br>
+               if (!reply)<br>
+                       return 1;<br>
+<br>
+               c = reply;<br>
+<br>
+               c += snprint_multipath_topology_json(c, reply + maxlen - c,<br>
+                               vecs);<br>
+               again = ((c - reply) == maxlen);<br>
+<br>
+               REALLOC_REPLY(reply, again, maxlen);<br>
+       }<br>
+       *r = reply;<br>
+       *len = (int)(c - reply + 1);<br>
+       return 0;<br>
+}<br>
+<br>
+int<br>
+show_map_json (char ** r, int * len, struct multipath * mpp,<br>
+                  struct vectors * vecs)<br>
+{<br>
+       char * c;<br>
+       char * reply;<br>
+       unsigned int maxlen = INITIAL_REPLY_LEN;<br>
+       int again = 1;<br>
+<br>
+       if (update_multipath(vecs, mpp->alias, 0))<br>
+               return 1;<br>
+       reply = MALLOC(maxlen);<br>
+<br>
+       while (again) {<br>
+               if (!reply)<br>
+                       return 1;<br>
+<br>
+               c = reply;<br>
+<br>
+               c += snprint_multipath_map_json(c, reply + maxlen - c, mpp, 1);<br>
+               again = ((c - reply) == maxlen);<br>
+<br>
+               REALLOC_REPLY(reply, again, maxlen);<br>
+       }<br>
+       *r = reply;<br>
+       *len = (int)(c - reply + 1);<br>
+       return 0;<br>
+}<br>
+<br>
+int<br>
 show_config (char ** r, int * len)<br>
 {<br>
        char * c;<br>
@@ -291,6 +355,35 @@ cli_list_maps_topology (void * v, char ** reply, int * len, void * data)<br>
 }<br>
<br>
 int<br>
+cli_list_map_json (void * v, char ** reply, int * len, void * data)<br>
+{<br>
+       struct multipath * mpp;<br>
+       struct vectors * vecs = (struct vectors *)data;<br>
+       char * param = get_keyparam(v, MAP);<br>
+<br>
+       param = convert_dev(param, 0);<br>
+       get_path_layout(vecs->pathvec, 0);<br>
+       mpp = find_mp_by_str(vecs->mpvec, param);<br>
+<br>
+       if (!mpp)<br>
+               return 1;<br>
+<br>
+       condlog(3, "list multipath json %s (operator)", param);<br>
+<br>
+       return show_map_json(reply, len, mpp, vecs);<br>
+}<br>
+<br>
+int<br>
+cli_list_maps_json (void * v, char ** reply, int * len, void * data)<br>
+{<br>
+       struct vectors * vecs = (struct vectors *)data;<br>
+<br>
+       condlog(3, "list multipaths json (operator)");<br>
+<br>
+       return show_maps_json(reply, len, vecs);<br>
+}<br>
+<br>
+int<br>
 cli_list_wildcards (void * v, char ** reply, int * len, void * data)<br>
 {<br>
        char * c;<br>
diff --git a/multipathd/cli_handlers.h b/multipathd/cli_handlers.h<br>
index 5d51018..e838f19 100644<br>
--- a/multipathd/cli_handlers.h<br>
+++ b/multipathd/cli_handlers.h<br>
@@ -13,6 +13,8 @@ int cli_list_maps_status (void * v, char ** reply, int * len, void * data);<br>
 int cli_list_maps_stats (void * v, char ** reply, int * len, void * data);<br>
 int cli_list_map_topology (void * v, char ** reply, int * len, void * data);<br>
 int cli_list_maps_topology (void * v, char ** reply, int * len, void * data);<br>
+int cli_list_map_json (void * v, char ** reply, int * len, void * data);<br>
+int cli_list_maps_json (void * v, char ** reply, int * len, void * data);<br>
 int cli_list_config (void * v, char ** reply, int * len, void * data);<br>
 int cli_list_blacklist (void * v, char ** reply, int * len, void * data);<br>
 int cli_list_devices (void * v, char ** reply, int * len, void * data);<br>
diff --git a/multipathd/main.c b/multipathd/main.c<br>
index 58e8854..33f38cd 100644<br>
--- a/multipathd/main.c<br>
+++ b/multipathd/main.c<br>
@@ -1120,9 +1120,11 @@ uxlsnrloop (void * ap)<br>
        set_handler_callback(LIST+MAPS+RAW+FMT, cli_list_maps_raw);<br>
        set_handler_callback(LIST+MAPS+TOPOLOGY, cli_list_maps_topology);<br>
        set_handler_callback(LIST+TOPOLOGY, cli_list_maps_topology);<br>
+       set_handler_callback(LIST+MAPS+JSON, cli_list_maps_json);<br>
        set_handler_callback(LIST+MAP+TOPOLOGY, cli_list_map_topology);<br>
        set_handler_callback(LIST+MAP+FMT, cli_list_map_fmt);<br>
        set_handler_callback(LIST+MAP+RAW+FMT, cli_list_map_fmt);<br>
+       set_handler_callback(LIST+MAP+JSON, cli_list_map_json);<br>
        set_unlocked_handler_callback(LIST+CONFIG, cli_list_config);<br>
        set_unlocked_handler_callback(LIST+BLACKLIST, cli_list_blacklist);<br>
        set_handler_callback(LIST+DEVICES, cli_list_devices);<br>
<span class="HOEnZb"><font color="#888888">--<br>
2.5.5<br>
<br>
--<br>
dm-devel mailing list<br>
<a href="mailto:dm-devel@redhat.com">dm-devel@redhat.com</a><br>
<a href="https://www.redhat.com/mailman/listinfo/dm-devel" rel="noreferrer" target="_blank">https://www.redhat.com/mailman/listinfo/dm-devel</a><br>
</font></span></blockquote></div><br></div>