]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
client: add "json0" to the list of available formats
authorVincent Bernat <vincent@bernat.im>
Tue, 15 Aug 2017 17:22:00 +0000 (19:22 +0200)
committerVincent Bernat <vincent@bernat.im>
Tue, 15 Aug 2017 17:22:00 +0000 (19:22 +0200)
This enables a more verbose JSON output whose structure is kept
the same with one or several neighbors. It's easier to parse than the
current structure.

Fix #236

NEWS
src/client/json_writer.c
src/client/lldpcli.8.in
src/client/lldpcli.c
src/client/writer.h
tests/integration/test_lldpcli.py

diff --git a/NEWS b/NEWS
index 223bc0eb875dcb90d88e124097348cfe86f1defe..2ec8a224fa713ace2e1b2d6ce7199f87af3aee39 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,8 @@ lldpd (0.9.8)
       link information anymore.
     + Add "configure system hostname ." option to not use a FQDN
       for system name.
+    + Add "-f json0" to provide a more regular/machine-parsable output
+      to JSON output, even when not compiled with --enable-json0.
   * Fixes:
     + Handle team interfaces like a bond. Real MAC address cannot be
       retrieved yet.
index 7ab6d484d7a880a90060c11866a91fa2ef32fd13..163ae19cce66a4ea83027636f1bc38edf1c7c7eb 100644 (file)
@@ -49,6 +49,7 @@ struct element {
 
 struct json_writer_private {
        FILE *fh;
+       int variant;
        struct element *root;
        struct element *current; /* should always be an object */
 };
@@ -310,7 +311,8 @@ json_element_cleanup(struct element *el)
 static void
 json_cleanup(struct json_writer_private *p)
 {
-       json_element_cleanup(p->root);
+       if (p->variant != 0)
+               json_element_cleanup(p->root);
 }
 
 static void
@@ -346,7 +348,7 @@ json_finish(struct writer *w)
 }
 
 struct writer*
-json_init(FILE *fh)
+json_init(FILE *fh, int variant)
 {
        struct writer *result;
        struct json_writer_private *priv;
@@ -356,6 +358,7 @@ json_init(FILE *fh)
 
        priv->fh = fh;
        priv->root = priv->current = json_element_new(NULL, NULL, OBJECT);
+       priv->variant = variant;
 
        result = malloc(sizeof(*result));
        if (result == NULL) fatal(NULL, NULL);
index 5f064f03211eb5a666db0511b4cbbbccf0a30512..1a20fa8407f874ddd76238da0526d1175f34799b 100644 (file)
@@ -60,11 +60,18 @@ version. When repeated, show more build information.
 Choose the output format. Currently
 .Em plain ,
 .Em xml ,
-.Em json
+.Em json ,
+.Em json0
 and
 .Em keyvalue
 formats are available. The default is
 .Em plain .
+.Em json0
+is more verbose than
+.Em json
+but the structure of the JSON object is not affected by the number of
+interfaces or the number of neighbors. It is therefore easier to
+parse.
 .It Fl c Ar file
 Read the given configuration file. This option may be repeated several
 times. If a directory is provided, each file contained in it will be
index 7263483c53ce39ad36b8bc92820898a740edeec8..93da36a4082ffc43c08f7fd42c04242aa53c94dc 100644 (file)
@@ -272,7 +272,8 @@ cmd_exec(lldpctl_conn_t *conn, const char *fmt, int argc, const char **argv)
 
        if      (strcmp(fmt, "plain")    == 0) w = txt_init(stdout);
        else if (strcmp(fmt, "keyvalue") == 0) w = kv_init(stdout);
-       else if (strcmp(fmt, "json")     == 0) w = json_init(stdout);
+       else if (strcmp(fmt, "json")     == 0) w = json_init(stdout, 1);
+       else if (strcmp(fmt, "json0")    == 0) w = json_init(stdout, 0);
 #ifdef USE_XML
        else if (strcmp(fmt, "xml")      == 0) w = xml_init(stdout);
 #endif
index be9f96a6d1ca80c601aaa98d192e790b1256e9d9..e15b30e3c1cd761b9fd855a5275365481f50b50e 100644 (file)
@@ -37,7 +37,7 @@ struct writer {
 
 extern struct writer *txt_init(FILE *);
 extern struct writer *kv_init(FILE *);
-extern struct writer *json_init(FILE *);
+extern struct writer *json_init(FILE *, int);
 
 #ifdef USE_XML
 extern struct writer *xml_init(FILE *);
index d828c06bf3685ade182ab703a6392048c93db63c..dd5b2d718662759cdcbaf6c7f7f506079a51173c 100644 (file)
@@ -117,6 +117,60 @@ def test_json_output(lldpd1, lldpd, lldpcli, namespaces, uname):
         assert j == expected
 
 
+@pytest.mark.skipif('JSON' not in pytest.config.lldpcli.outputs,
+                    reason="JSON not supported")
+def test_json0_output(lldpd1, lldpd, lldpcli, namespaces, uname):
+    with namespaces(2):
+        lldpd()
+    with namespaces(1):
+        result = lldpcli("-f", "json0", "show", "neighbors", "details")
+        assert result.returncode == 0
+        out = result.stdout.decode('ascii')
+        j = json.loads(out)
+
+        eth0 = j['lldp'][0]['interface'][0]
+        del eth0['age']
+        del eth0['chassis'][0]['capability'][3]
+        del eth0['chassis'][0]['capability'][1]
+        expected = {"lldp": [{
+            "interface": [{
+                "name": "eth0",
+                "via": "LLDP",
+                "rid": "1",
+                "chassis": [{
+                    "id": [{
+                        "type": "mac",
+                        "value": "00:00:00:00:00:02"
+                    }],
+                    "name": [{"value": "ns-2.example.com"}],
+                    "descr": [{"value": "Spectacular GNU/Linux 2016 {}".format(uname)}],
+                    "mgmt-ip": [{"value": "fe80::200:ff:fe00:2"}],
+                    "capability": [
+                        {"type": "Bridge", "enabled": False},
+                        {"type": "Wlan", "enabled": False},
+                    ]}
+                ],
+                "port": [{
+                    "id": [{
+                        "type": "mac",
+                        "value": "00:00:00:00:00:02"
+                    }],
+                    "descr": [{"value": "eth1"}],
+                    "ttl": [{"value": "120"}]
+                }]
+            }]}
+        ]}
+
+        if 'Dot3' in pytest.config.lldpd.features:
+            expected['lldp'][0]['interface'][0]['port'][0]['auto-negotiation'] = [{
+                "enabled": False,
+                "supported": False,
+                "current": [{"value":
+                             "10GigBaseCX4 - X copper over 8 pair 100-Ohm balanced cable"}]
+            }]
+        assert j == expected
+
+
 @pytest.mark.skipif('XML' not in pytest.config.lldpcli.outputs,
                     reason="XML not supported")
 def test_xml_output(lldpd1, lldpd, lldpcli, namespaces, uname):