[Tooling update] health_checks

* Added:
- contrail_mesh_check: Check if contrail elements are connected
  to each other.

Prod-Related: PROD-31970
Change-Id: Id92fe188154c088ae110afa16be3aa02f6f6e964
diff --git a/_modules/health_checks.py b/_modules/health_checks.py
index ea34371..97d1703 100644
--- a/_modules/health_checks.py
+++ b/_modules/health_checks.py
@@ -1710,6 +1710,99 @@
     return vr_info
 
 
+def contrail_mesh_check(target='I@opencontrail:control', target_type='compound', ignore_dead=False, strict=False, **kwargs):
+
+    ''' Check if contrail elements are connected to each other '''
+
+    agent = "contrail mesh check"
+    out = __salt__['saltutil.cmd']( tgt=target,
+                                    tgt_type=target_type,
+                                    fun='health_checks.contrail_control_peer_status',
+                                    timeout=3
+                                  ) or None
+
+    if not _minions_output(out, agent, ignore_dead):
+        __context__['retcode'] = 2
+        return False
+
+
+    minions = []
+    for node in out:
+        if strict:
+            minions.append(node)
+        else:
+            minions.append(node.split('.')[0])
+
+    elements = {}
+    for node in out:
+        peer_elem = out[node]["ret"]
+        for elem in peer_elem:
+            if not strict:
+                elem = elem.split('.')[0]
+            if elem in elements:
+                continue
+            elements[elem] = {}
+            elements[elem]["peers"] = []
+            elements[elem]["my_address"] = peer_elem[elem]["peer_address"]
+            if peer_elem[elem]["encoding"] == "XMPP":
+                elements[elem]["type"] = "COMPUTE"
+            elif peer_elem[elem]["encoding"] == "BGP":
+                if elem in minions:
+                    elements[elem]["type"] = "CONTROLLER"
+                else:
+                    elements[elem]["type"] = "EDGE-ROUTER"
+
+    for node in out:
+        if strict:
+            peer_name = node
+        else:
+            peer_name = node.split('.')[0]
+        peer_elem = out[node]["ret"]
+        for elem in peer_elem:
+            if not strict:
+                elem = elem.split('.')[0]
+            peer_elem[elem]["peer"] = peer_name
+            del(peer_elem[elem]["peer_address"])
+            elements[elem]["peers"].append(peer_elem[elem])
+
+    failed_peers = []
+    for elem_name in elements:
+        elem = elements[elem_name]
+        if elem["type"] == "COMPUTE":
+            if len(elem["peers"]) < 2:
+                if elem not in failed_peers:
+                    failed_peers.append(elem)
+        if elem["type"] == "CONTROLLER":
+            if len(elem["peers"]) < len(minions)-1:
+                if elem not in failed_peers:
+                    failed_peers.append(elem)
+        if elem["type"] == "EDGE-ROUTER":
+            if not len(elem["peers"]) == len(minions):
+                if elem not in failed_peers:
+                    failed_peers.append(elem)
+        for peer in elem["peers"]:
+            if not peer["state"] == "Established":
+                if elem not in failed_peers:
+                    failed_peers.append(elem)
+
+    if len(failed_peers) > 0:
+        logger.error("%s check FAILED" % agent)
+        if strict:
+            logger.error("Strict mode is on. Check DNS names in output")
+            logger.error("Minions output:")
+            logger.error(json.dumps(out, indent=4))
+        else:
+            logger.error("Failed peers:")
+            logger.error(json.dumps(failed_peers, indent=4))
+        __context__['retcode'] = 2
+        return False
+
+    if kwargs.get("debug", False):
+        logger.info(json.dumps(elements, indent=4))
+
+    return True
+
+
 def kafka_brokers_ids():
 
     ''' Retrieve kafka brokers ids '''