Rework ovs_parge_bridge to use ovsdbapp

+ switch to python3

Change-Id: I5833b6e075420ca964287f61639d70b721565fb0
Related-bug: PROD-34478
diff --git a/telegraf/files/script/ovs_parse_bridge.py b/telegraf/files/script/ovs_parse_bridge.py
index c694dfd..76c34ca 100644
--- a/telegraf/files/script/ovs_parse_bridge.py
+++ b/telegraf/files/script/ovs_parse_bridge.py
@@ -1,79 +1,106 @@
-#!/usr/bin/env python2
-import subprocess
-import json
+#!/usr/bin/env python3
+
+'''
+Check status description:
+
+# General
+
+## Check failed
+ovs_bridge check=0
+
+## Check succeeded
+ovs_bridge check=1
+
+# Interface, port, bridge
+
+## Interface is down
+ovs_bridge,interface=xxx,type=zzz,bridge=yyy,port=aaa status=0
+
+## Interface is up
+ovs_bridge,interface=xxx,type=zzz,bridge=yyy,port=aaa status=1
+
+## Interface error
+ovs_bridge,interface=xxx,type=zzz,bridge=yyy,port=aaa status=2
+
+# Special errors tracking
+
+## Bridge has no ports
+ovs_bridge_port,bridge=yyy count=0
+
+## Bridge port has no interface
+ovs_bridge_port_iface,bridge=yyy,port=aaa count=0
+'''
+
+import sys
+
+from ovsdbapp.backend.ovs_idl import connection
+from ovsdbapp.schema.ovn_northbound import impl_idl
 
 
-def call_process(cmd):
-    p = subprocess.Popen(
-        cmd.split(),
-        stdout=subprocess.PIPE,
-        stderr=subprocess.PIPE)
-    output = p.communicate()
-    return output
+SOCKET_PATH = 'unix:/run/openvswitch/db.sock'
+DB_NAME = 'Open_vSwitch'
+CONN_TIMEOUT = 5
+
+CHK_TMPL = 'ovs_bridge check={}'
+BR_CHK_TMPL = '{},{} status={}'
+BR_CNT_TMPL = '{},{} count={}'
 
 
-def ovsctl_json(cmd):
-    cmd = "ovs-vsctl -f json " + cmd
-    result = call_process(cmd)
-    headings = json.loads(result[0])["headings"]
-    datas = json.loads(result[0])["data"]
-
-    uuid_index = headings.index("_uuid")
-
-    obj = {}
-
-    for data in datas:
-        obj_data = {}
-        for d, h in zip(data, headings):
-            if isinstance(d, list):
-                _type, value = d[0], d[1]
-                if _type == "uuid":
-                    obj_data[h] = [d]
-                elif _type == "map":
-                    obj_data[h] = {v[0]: v[1] for v in value}
-                elif _type == "set":
-                    obj_data[h] = value
-            else:
-                obj_data[h] = d
-        obj[data[uuid_index][1]] = obj_data
-    return obj
+def format_labels(bridge, port=None, interface=None):
+    label_obj = {
+        'bridge': bridge.name
+    }
+    if port is not None:
+        label_obj.update({
+            'port': port.name
+        })
+    if interface is not None:
+        label_obj.update({
+            'interface': interface.name,
+            'type': interface.type,
+            'peer': interface.options.get('peer')
+        })
+    labels = ','.join(['{}={}'.format(key, value)
+                       for key, value in label_obj.iteritems()
+                       if not (value is None or len(value) == 0)])
+    return labels
 
 
 def gather():
-    bridges = ovsctl_json("list bridge")
-    ports = ovsctl_json("list port")
-    interfaces = ovsctl_json("list interface")
+    idl = connection.OvsdbIdl.from_server(SOCKET_PATH, DB_NAME)
+    conn = connection.Connection(idl=idl, timeout=CONN_TIMEOUT)
 
-    for bridge_uuid, bridge in bridges.iteritems():
-        for bridge_port in bridge['ports']:
-            port = ports[bridge_port[1]]
-            interface = interfaces[port['interfaces'][0][1]]
+    api = impl_idl.OvnNbApiIdlImpl(conn)
 
-            label_obj = {
-                "bridge": bridge.get('name'),
-                "port": port.get('name'),
-                "interface": interface.get('name'),
-                "type": interface.get('type'),
-                "peer": interface.get('options', {}).get('peer'),
-            }
+    for br_id, bridge in api.tables['Bridge'].rows.items():
 
-            labels = ','.join(["{}={}".format(key, value)
-                               for key, value in label_obj.iteritems()
-                               if not (value is None or len(value) == 0)])
+        print(BR_CNT_TMPL.format('ovs_bridge_port',
+                                 format_labels(bridge),
+                                 len(bridge.ports)))
 
-            if interface['link_state'] == "up":
-                status = 1
-                if len(interface['error']) > 0:
-                    status = 2
-            else:
-                status = 0
+        for port in bridge.ports:
+            print(BR_CNT_TMPL.format('ovs_bridge_port_iface',
+                                     format_labels(bridge, port),
+                                     len(port.interfaces)))
 
-            print "ovs_bridge,{} status={}".format(labels, status)
+            for iface in port.interfaces:
+                labels = format_labels(bridge, port, iface)
+
+                if iface.link_state == 'up':
+                    status = 1
+                    if len(iface.error) > 0:
+                        status = 2
+                else:
+                    status = 0
+
+                print(BR_CHK_TMPL.format('ovs_bridge', labels, status))
 
 
 if __name__ == "__main__":
     try:
         gather()
-        print "ovs_bridge check=1"
-    except Exception:
-        print "ovs_bridge check=0"
+        print(CHK_TMPL.format(1))
+    except Exception as e:
+        print(CHK_TMPL.format(0))
+        sys.stderr.write(str(e))
+        sys.exit(1)