add parent_type to switch pnics, =switch 65/39065/1
authorYaron Yogev <yaronyogev@gmail.com>
Thu, 10 Aug 2017 12:59:31 +0000 (15:59 +0300)
committerYaron Yogev <yaronyogev@gmail.com>
Thu, 10 Aug 2017 12:59:31 +0000 (15:59 +0300)
Change-Id: I9eec8d6901ef1564b49ad97c79e0888fabc75cb8
Signed-off-by: Yaron Yogev <yaronyogev@gmail.com>
app/discover/fetchers/aci/aci_fetch_leaf_to_spine_pnics.py
app/discover/fetchers/aci/aci_fetch_switch_pnic.py

index c556459..463d4d8 100644 (file)
-###############################################################################
-# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems)   #
-# and others                                                                  #
-#                                                                             #
-# All rights reserved. This program and the accompanying materials            #
-# are made available under the terms of the Apache License, Version 2.0       #
-# which accompanies this distribution, and is available at                    #
-# http://www.apache.org/licenses/LICENSE-2.0                                  #
-###############################################################################
-import re
-
-from discover.fetchers.aci.aci_access import AciAccess, aci_config_required
-from utils.inventory_mgr import InventoryMgr
-from utils.util import decode_aci_dn, encode_aci_dn, get_object_path_part
-
-
-# Fetches and adds to database:
-# 1. ACI Switches with role "spine"
-#
-# Returns:
-# 1. ACI Switch uplink pnics that belong to the "leaf" switch
-# 2. ACI Switch downlink pnics that belong to "spine" switches mentioned above
-# and are connected to the "leaf" switch
-class AciFetchLeafToSpinePnics(AciAccess):
-
-    def __init__(self):
-        super().__init__()
-        self.inv = InventoryMgr()
-
-    def fetch_switches_by_role(self, role_name):
-        query_filter = {"query-target-filter":
-                        "eq(fabricNode.role, \"{}\")".format(role_name)}
-        switches = self.fetch_objects_by_class("fabricNode", query_filter)
-        return [switch["attributes"] for switch in switches]
-
-    def fetch_adjacent_connections(self, device_id):
-        dn = "/".join((device_id, "sys"))
-
-        response = self.fetch_mo_data(dn,
-                                      {"query-target": "subtree",
-                                       "target-subtree-class": "lldpAdjEp"})
-
-        connections = self.get_objects_by_field_names(response,
-                                                      "lldpAdjEp", "attributes")
-        return connections
-
-    # Returns:
-    # List of:
-    # 1. Switches with role "spine"
-    # 2. Downlink pnic id for spine switch
-    # 3. Uplink pnic id for leaf switch
-    def fetch_spines_and_pnics_by_leaf_id(self, leaf_id):
-        spine_switches = self.fetch_switches_by_role("spine")
-        adjacent_devices = self.fetch_adjacent_connections(leaf_id)
-        spines = []
-        for spine in spine_switches:
-            # Check if spine switch is connected to current leaf switch
-            connection = next((d for d in adjacent_devices
-                               if spine["name"] == d["sysName"]),
-                              None)
-            if connection:
-                try:
-                    # Extract pnics from adjacency data
-                    uplink_pnic = re.match(".*\[(.+?)\].*",
-                                           connection["dn"]).group(1)
-                    downlink_pnic = re.match(".*\[(.+?)\].*",
-                                             connection["portDesc"]).group(1)
-                    spines.append({
-                        "device": spine,
-                        "downlink_pnic": downlink_pnic,
-                        "uplink_pnic": uplink_pnic
-                    })
-                except AttributeError:
-                    continue  # TODO: probably raise an exception
-
-        return spines
-
-    @aci_config_required(default=[])
-    def get(self, db_leaf_pnic_id):
-        environment = self.get_env()
-        leaf_pnic = self.inv.get_by_id(environment=environment,
-                                       item_id=db_leaf_pnic_id)
-        leaf_switch_id = leaf_pnic['switch']
-
-        # Decode aci leaf switch id from db format
-        aci_leaf_pnic_id = decode_aci_dn(db_leaf_pnic_id)
-        aci_leaf_id = re.match("switch-(.+?)-leaf", aci_leaf_pnic_id).group(1)
-
-        # Fetch all leaf-to-spine connectivity data
-        spines_with_pnics = self.fetch_spines_and_pnics_by_leaf_id(aci_leaf_id)
-        pnics = []
-        for spine_with_pnic in spines_with_pnics:
-            spine = spine_with_pnic["device"]
-            downlink_pnic_id = spine_with_pnic["downlink_pnic"]
-            uplink_pnic_id = spine_with_pnic["uplink_pnic"]
-
-            # Add spine switch to db if it's not there yet
-            spine_id_match = re.match("topology/(.+)", spine["dn"])
-            if not spine_id_match:
-                raise ValueError("Failed to fetch spine switch id "
-                                 "from switch dn: {}".format(spine["dn"]))
-
-            aci_spine_id = spine_id_match.group(1)
-            db_spine_id = "-".join(("switch", encode_aci_dn(aci_spine_id),
-                                    spine["role"]))
-            if not self.inv.get_by_id(environment, db_spine_id):
-                spine_json = {
-                    "id": db_spine_id,
-                    "type": "switch",
-                    "aci_document": spine
-                }
-                # Region name is the same as region id
-                region_id = get_object_path_part(leaf_pnic["name_path"],
-                                                 "Regions")
-                region = self.inv.get_by_id(environment, region_id)
-                self.inv.save_inventory_object(o=spine_json, parent=region,
-                                               environment=environment)
-
-            # Add downlink and uplink pnics to results list,
-            # including their mutual connection data
-            # (see "connected_to" field).
-            db_downlink_pnic_id = "-".join((db_spine_id,
-                                            encode_aci_dn(downlink_pnic_id)))
-            db_uplink_pnic_id = "-".join((leaf_pnic["switch"],
-                                          encode_aci_dn(uplink_pnic_id)))
-
-            downlink_pnic_json = {
-                "id": db_downlink_pnic_id,
-                "type": "pnic",
-                "role": "downlink",
-                "pnic_type": "switch",
-                "connected_to": db_uplink_pnic_id,
-                "switch": db_spine_id,
-                "parent_id": db_spine_id,
-                "aci_document": {}  # TODO: what can we add here?
-            }
-
-            uplink_pnic_json = {
-                "id": db_uplink_pnic_id,
-                "type": "pnic",
-                "role": "uplink",
-                "pnic_type": "switch",
-                "connected_to": db_downlink_pnic_id,
-                "switch": leaf_switch_id,
-                "parent_id": leaf_switch_id,
-                "aci_document": {}  # TODO: what can we add here?
-            }
-
-            pnics.extend([downlink_pnic_json, uplink_pnic_json])
-
-        return pnics
+###############################################################################\r
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems)   #\r
+# and others                                                                  #\r
+#                                                                             #\r
+# All rights reserved. This program and the accompanying materials            #\r
+# are made available under the terms of the Apache License, Version 2.0       #\r
+# which accompanies this distribution, and is available at                    #\r
+# http://www.apache.org/licenses/LICENSE-2.0                                  #\r
+###############################################################################\r
+import re\r
+\r
+from discover.fetchers.aci.aci_access import AciAccess, aci_config_required\r
+from utils.inventory_mgr import InventoryMgr\r
+from utils.util import decode_aci_dn, encode_aci_dn, get_object_path_part\r
+\r
+\r
+# Fetches and adds to database:\r
+# 1. ACI Switches with role "spine"\r
+#\r
+# Returns:\r
+# 1. ACI Switch uplink pnics that belong to the "leaf" switch\r
+# 2. ACI Switch downlink pnics that belong to "spine" switches mentioned above\r
+# and are connected to the "leaf" switch\r
+class AciFetchLeafToSpinePnics(AciAccess):\r
+\r
+    def __init__(self):\r
+        super().__init__()\r
+        self.inv = InventoryMgr()\r
+\r
+    def fetch_switches_by_role(self, role_name):\r
+        query_filter = {"query-target-filter":\r
+                        "eq(fabricNode.role, \"{}\")".format(role_name)}\r
+        switches = self.fetch_objects_by_class("fabricNode", query_filter)\r
+        return [switch["attributes"] for switch in switches]\r
+\r
+    def fetch_adjacent_connections(self, device_id):\r
+        dn = "/".join((device_id, "sys"))\r
+\r
+        response = self.fetch_mo_data(dn,\r
+                                      {"query-target": "subtree",\r
+                                       "target-subtree-class": "lldpAdjEp"})\r
+\r
+        connections = self.get_objects_by_field_names(response,\r
+                                                      "lldpAdjEp", "attributes")\r
+        return connections\r
+\r
+    # Returns:\r
+    # List of:\r
+    # 1. Switches with role "spine"\r
+    # 2. Downlink pnic id for spine switch\r
+    # 3. Uplink pnic id for leaf switch\r
+    def fetch_spines_and_pnics_by_leaf_id(self, leaf_id):\r
+        spine_switches = self.fetch_switches_by_role("spine")\r
+        adjacent_devices = self.fetch_adjacent_connections(leaf_id)\r
+        spines = []\r
+        for spine in spine_switches:\r
+            # Check if spine switch is connected to current leaf switch\r
+            connection = next((d for d in adjacent_devices\r
+                               if spine["name"] == d["sysName"]),\r
+                              None)\r
+            if connection:\r
+                try:\r
+                    # Extract pnics from adjacency data\r
+                    uplink_pnic = re.match(".*\[(.+?)\].*",\r
+                                           connection["dn"]).group(1)\r
+                    downlink_pnic = re.match(".*\[(.+?)\].*",\r
+                                             connection["portDesc"]).group(1)\r
+                    spines.append({\r
+                        "device": spine,\r
+                        "downlink_pnic": downlink_pnic,\r
+                        "uplink_pnic": uplink_pnic\r
+                    })\r
+                except AttributeError:\r
+                    continue  # TODO: probably raise an exception\r
+\r
+        return spines\r
+\r
+    @aci_config_required(default=[])\r
+    def get(self, db_leaf_pnic_id):\r
+        environment = self.get_env()\r
+        leaf_pnic = self.inv.get_by_id(environment=environment,\r
+                                       item_id=db_leaf_pnic_id)\r
+        leaf_switch_id = leaf_pnic['switch']\r
+\r
+        # Decode aci leaf switch id from db format\r
+        aci_leaf_pnic_id = decode_aci_dn(db_leaf_pnic_id)\r
+        aci_leaf_id = re.match("switch-(.+?)-leaf", aci_leaf_pnic_id).group(1)\r
+\r
+        # Fetch all leaf-to-spine connectivity data\r
+        spines_with_pnics = self.fetch_spines_and_pnics_by_leaf_id(aci_leaf_id)\r
+        pnics = []\r
+        for spine_with_pnic in spines_with_pnics:\r
+            spine = spine_with_pnic["device"]\r
+            downlink_pnic_id = spine_with_pnic["downlink_pnic"]\r
+            uplink_pnic_id = spine_with_pnic["uplink_pnic"]\r
+\r
+            # Add spine switch to db if it's not there yet\r
+            spine_id_match = re.match("topology/(.+)", spine["dn"])\r
+            if not spine_id_match:\r
+                raise ValueError("Failed to fetch spine switch id "\r
+                                 "from switch dn: {}".format(spine["dn"]))\r
+\r
+            aci_spine_id = spine_id_match.group(1)\r
+            db_spine_id = "-".join(("switch", encode_aci_dn(aci_spine_id),\r
+                                    spine["role"]))\r
+            if not self.inv.get_by_id(environment, db_spine_id):\r
+                spine_json = {\r
+                    "id": db_spine_id,\r
+                    "type": "switch",\r
+                    "aci_document": spine\r
+                }\r
+                # Region name is the same as region id\r
+                region_id = get_object_path_part(leaf_pnic["name_path"],\r
+                                                 "Regions")\r
+                region = self.inv.get_by_id(environment, region_id)\r
+                self.inv.save_inventory_object(o=spine_json, parent=region,\r
+                                               environment=environment)\r
+\r
+            # Add downlink and uplink pnics to results list,\r
+            # including their mutual connection data\r
+            # (see "connected_to" field).\r
+            db_downlink_pnic_id = "-".join((db_spine_id,\r
+                                            encode_aci_dn(downlink_pnic_id)))\r
+            db_uplink_pnic_id = "-".join((leaf_pnic["switch"],\r
+                                          encode_aci_dn(uplink_pnic_id)))\r
+\r
+            downlink_pnic_json = {\r
+                "id": db_downlink_pnic_id,\r
+                "type": "pnic",\r
+                "role": "downlink",\r
+                "pnic_type": "switch",\r
+                "connected_to": db_uplink_pnic_id,\r
+                "switch": db_spine_id,\r
+                "parent_id": db_spine_id,\r
+                "parent_type": "switch",\r
+                "aci_document": {}  # TODO: what can we add here?\r
+            }\r
+\r
+            uplink_pnic_json = {\r
+                "id": db_uplink_pnic_id,\r
+                "type": "pnic",\r
+                "role": "uplink",\r
+                "pnic_type": "switch",\r
+                "connected_to": db_downlink_pnic_id,\r
+                "switch": leaf_switch_id,\r
+                "parent_id": leaf_switch_id,\r
+                "parent_type": "switch",\r
+                "aci_document": {}  # TODO: what can we add here?\r
+            }\r
+\r
+            pnics.extend([downlink_pnic_json, uplink_pnic_json])\r
+\r
+        return pnics\r
index f0cf6b1..09157b6 100644 (file)
-###############################################################################
-# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems)   #
-# and others                                                                  #
-#                                                                             #
-# All rights reserved. This program and the accompanying materials            #
-# are made available under the terms of the Apache License, Version 2.0       #
-# which accompanies this distribution, and is available at                    #
-# http://www.apache.org/licenses/LICENSE-2.0                                  #
-###############################################################################
-import re
-
-from discover.fetchers.aci.aci_access import AciAccess, aci_config_required
-from utils.inventory_mgr import InventoryMgr
-from utils.util import encode_aci_dn, get_object_path_part
-
-
-# Fetches and adds to database:
-# 1. ACI Switch
-#
-# Returns:
-# 1. ACI Switch pnic that belongs to the ACI Switch (mentioned above)
-# and is connected to Calipso host pnic.
-class AciFetchSwitchPnic(AciAccess):
-
-    def __init__(self):
-        super().__init__()
-        self.inv = InventoryMgr()
-
-    def fetch_pnics_by_mac_address(self, mac_address):
-        mac_filter = "eq(epmMacEp.addr,\"{}\")".format(mac_address)
-        # We are only interested in Ethernet interfaces
-        pnic_filter = "wcard(epmMacEp.ifId, \"eth\")"
-        query_filter = {"query-target-filter":
-                        "and({},{})".format(mac_filter, pnic_filter)}
-
-        pnics = self.fetch_objects_by_class("epmMacEp", query_filter)
-
-        return [pnic["attributes"] for pnic in pnics]
-
-    def fetch_switch_by_id(self, switch_id):
-        dn = "/".join((switch_id, "sys"))
-        response = self.fetch_mo_data(dn)
-        # Unwrap switches
-        switch_data = self.get_objects_by_field_names(response, "topSystem",
-                                                      "attributes")
-        return switch_data[0] if switch_data else None
-
-    @aci_config_required(default=[])
-    def get(self, pnic_id):
-        environment = self.get_env()
-        pnic = self.inv.get_by_id(environment=environment, item_id=pnic_id)
-        if not pnic:
-            return []
-        mac_address = pnic.get("mac_address")
-        if not mac_address:
-            return []
-
-        # Query ACI for related switch pnic
-        leaf_pnics = self.fetch_pnics_by_mac_address(mac_address)
-        if not leaf_pnics:
-            return []
-        leaf_pnic = leaf_pnics[0]
-
-        # Prepare and save switch data in inventory
-        leaf_id_match = re.match("topology/(.+)/sys", leaf_pnic["dn"])
-        if not leaf_id_match:
-            raise ValueError("Failed to fetch leaf switch id from pnic dn: {}"
-                             .format(leaf_pnic["dn"]))
-
-        aci_leaf_id = leaf_id_match.group(1)
-        leaf_data = self.fetch_switch_by_id(aci_leaf_id)
-        if not leaf_data:
-            self.log.warning("No switch found for switch pnic dn: {}"
-                             .format(leaf_pnic["dn"]))
-            return []
-
-        db_leaf_id = "-".join(("switch", encode_aci_dn(aci_leaf_id),
-                               leaf_data["role"]))
-        if not self.inv.get_by_id(environment, db_leaf_id):
-            leaf_json = {
-                "id": db_leaf_id,
-                "ip_address": leaf_data["address"],
-                "type": "switch",
-                "host": db_leaf_id,
-                "aci_document": leaf_data
-            }
-            # Region name is the same as region id
-            region_id = get_object_path_part(pnic["name_path"], "Regions")
-            region = self.inv.get_by_id(environment, region_id)
-            self.inv.save_inventory_object(o=leaf_json, parent=region,
-                                           environment=environment)
-
-        # Prepare pnic json for results list
-        db_pnic_id = "-".join((db_leaf_id,
-                               encode_aci_dn(leaf_pnic["ifId"]),
-                               mac_address))
-        pnic_json = {
-            "id": db_pnic_id,
-            "type": "pnic",
-            "role": "hostlink",
-            "parent_id": db_leaf_id,
-            "pnic_type": "switch",
-            "mac_address": mac_address,
-            "switch": db_leaf_id,
-            "aci_document": leaf_pnic
-        }
-        return [pnic_json]
+###############################################################################\r
+# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems)   #\r
+# and others                                                                  #\r
+#                                                                             #\r
+# All rights reserved. This program and the accompanying materials            #\r
+# are made available under the terms of the Apache License, Version 2.0       #\r
+# which accompanies this distribution, and is available at                    #\r
+# http://www.apache.org/licenses/LICENSE-2.0                                  #\r
+###############################################################################\r
+import re\r
+\r
+from discover.fetchers.aci.aci_access import AciAccess, aci_config_required\r
+from utils.inventory_mgr import InventoryMgr\r
+from utils.util import encode_aci_dn, get_object_path_part\r
+\r
+\r
+# Fetches and adds to database:\r
+# 1. ACI Switch\r
+#\r
+# Returns:\r
+# 1. ACI Switch pnic that belongs to the ACI Switch (mentioned above)\r
+# and is connected to Calipso host pnic.\r
+class AciFetchSwitchPnic(AciAccess):\r
+\r
+    def __init__(self):\r
+        super().__init__()\r
+        self.inv = InventoryMgr()\r
+\r
+    def fetch_pnics_by_mac_address(self, mac_address):\r
+        mac_filter = "eq(epmMacEp.addr,\"{}\")".format(mac_address)\r
+        # We are only interested in Ethernet interfaces\r
+        pnic_filter = "wcard(epmMacEp.ifId, \"eth\")"\r
+        query_filter = {"query-target-filter":\r
+                        "and({},{})".format(mac_filter, pnic_filter)}\r
+\r
+        pnics = self.fetch_objects_by_class("epmMacEp", query_filter)\r
+\r
+        return [pnic["attributes"] for pnic in pnics]\r
+\r
+    def fetch_switch_by_id(self, switch_id):\r
+        dn = "/".join((switch_id, "sys"))\r
+        response = self.fetch_mo_data(dn)\r
+        # Unwrap switches\r
+        switch_data = self.get_objects_by_field_names(response, "topSystem",\r
+                                                      "attributes")\r
+        return switch_data[0] if switch_data else None\r
+\r
+    @aci_config_required(default=[])\r
+    def get(self, pnic_id):\r
+        environment = self.get_env()\r
+        pnic = self.inv.get_by_id(environment=environment, item_id=pnic_id)\r
+        if not pnic:\r
+            return []\r
+        mac_address = pnic.get("mac_address")\r
+        if not mac_address:\r
+            return []\r
+\r
+        # Query ACI for related switch pnic\r
+        leaf_pnics = self.fetch_pnics_by_mac_address(mac_address)\r
+        if not leaf_pnics:\r
+            return []\r
+        leaf_pnic = leaf_pnics[0]\r
+\r
+        # Prepare and save switch data in inventory\r
+        leaf_id_match = re.match("topology/(.+)/sys", leaf_pnic["dn"])\r
+        if not leaf_id_match:\r
+            raise ValueError("Failed to fetch leaf switch id from pnic dn: {}"\r
+                             .format(leaf_pnic["dn"]))\r
+\r
+        aci_leaf_id = leaf_id_match.group(1)\r
+        leaf_data = self.fetch_switch_by_id(aci_leaf_id)\r
+        if not leaf_data:\r
+            self.log.warning("No switch found for switch pnic dn: {}"\r
+                             .format(leaf_pnic["dn"]))\r
+            return []\r
+\r
+        db_leaf_id = "-".join(("switch", encode_aci_dn(aci_leaf_id),\r
+                               leaf_data["role"]))\r
+        if not self.inv.get_by_id(environment, db_leaf_id):\r
+            leaf_json = {\r
+                "id": db_leaf_id,\r
+                "ip_address": leaf_data["address"],\r
+                "type": "switch",\r
+                "host": db_leaf_id,\r
+                "aci_document": leaf_data\r
+            }\r
+            # Region name is the same as region id\r
+            region_id = get_object_path_part(pnic["name_path"], "Regions")\r
+            region = self.inv.get_by_id(environment, region_id)\r
+            self.inv.save_inventory_object(o=leaf_json, parent=region,\r
+                                           environment=environment)\r
+\r
+        # Prepare pnic json for results list\r
+        db_pnic_id = "-".join((db_leaf_id,\r
+                               encode_aci_dn(leaf_pnic["ifId"]),\r
+                               mac_address))\r
+        pnic_json = {\r
+            "id": db_pnic_id,\r
+            "type": "pnic",\r
+            "role": "hostlink",\r
+            "parent_id": db_leaf_id,\r
+            "parent_type": "switch",\r
+            "pnic_type": "switch",\r
+            "mac_address": mac_address,\r
+            "switch": db_leaf_id,\r
+            "aci_document": leaf_pnic\r
+        }\r
+        return [pnic_json]\r