def delete_ifaz(connection, index): try: value = int(index) if value < 0: raise DataError("Invalid loopback interface index") except ValueError as e: raise DataError("Invalid loopback interface index") from e data = """ <config> <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"> <interface operation="delete"> <name>Loopback""" + str(index) + """</name> </interface> </interfaces> </config> """ reply = edit_config(connection, data) try: if "ok" in reply["rpc-reply"]: print("OK response received to interface removal request") except KeyError as e: raise DataError( "Cannot parse data received as response to interface removal request" ) from e
def get_interfaces(endpoint, device_id=""): interfaces = [] try: device_list = get_devices(endpoint, device_id) if device_id == "": response = apicem.get(endpoint, "interface") else: response = apicem.get( endpoint, "interface/network-device/{}".format(device_id)) i = 0 for data in response[1]["response"]: device = None for dev in device_list: if dev[1] == data["deviceId"]: device = dev info = [ i, device[2] if device is not None else "", data["portName"], data["status"], data["adminStatus"], data["interfaceType"], data["portMode"], data["ipv4Address"], data["ipv4Mask"] ] i += 1 interfaces.append(info) except KeyError as e: raise DataError("Cannot parse interfaces info") from e return interfaces
def get_reachability_info(endpoint, addr=""): reachability_info = [] try: if addr == "": response = apicem.get(endpoint, "reachability-info") i = 0 for data in response[1]["response"]: info = [ i, data["mgmtIp"], data["discoveryStartTime"], data["reachabilityStatus"], data["reachabilityFailureReason"] if "reachabilityFailureReason" in data else "" ] i += 1 reachability_info.append(info) else: response = apicem.get( endpoint, "reachability-info/ip-address/{}".format(addr)) info = [ 0, response[1]["response"]["mgmtIp"], response[1]["response"]["discoveryStartTime"], response[1]["response"]["reachabilityStatus"], response[1]["response"]["reachabilityFailureReason"] if "reachabilityFailureReason" in response[1]["response"] else "" ] reachability_info.append(info) except KeyError as e: raise DataError("Cannot parse reachability info") from e return reachability_info
def get_hosts(endpoint, host_id=""): host_list = [] try: if host_id == "": response = apicem.get(endpoint, "host") i = 0 for item in response[1]["response"]: host = [ i, item["id"], item["hostType"], item["hostIp"], item["hostMac"] ] i += 1 host_list.append(host) else: response = apicem.get(endpoint, "host/{}".format(host_id)) host = [ 0, response[1]["response"]["id"], response[1]["response"]["hostType"], response[1]["response"]["hostIp"], response[1]["response"]["hostMac"] ] host_list.append(host) except KeyError as e: raise DataError("Cannot parse host info") from e return host_list
def get_devices(endpoint, device_id=""): dev_list = [] try: if device_id == "": response = apicem.get(endpoint, "network-device") i = 0 for item in response[1]["response"]: dev = [ i, item["id"], item["hostname"], item["type"], item["managementIpAddress"], item["macAddress"] ] i += 1 dev_list.append(dev) else: response = apicem.get(endpoint, "network-device/{}".format(device_id)) dev = [ 0, response[1]["response"]["id"], response[1]["response"]["hostname"], response[1]["response"]["type"], response[1]["response"]["managementIpAddress"], response[1]["response"]["macAddress"] ] dev_list.append(dev) except KeyError as e: raise DataError("Cannot parse network-device info") from e return dev_list
def get_memory_usage(connection): filter_get_config = """ <filter> <memory-usage-processes xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-process-memory-oper"> <memory-usage-process/> </memory-usage-processes> </filter> """ get_res = get(connection, filter_get_config) try: mem_usage = [] i = 0 data = get_res["rpc-reply"]["data"]["memory-usage-processes"][ "memory-usage-process"] if type(data) != list: data = [data] for usage in data: item = { "index": i, "pid": usage["pid"], "name": usage["name"], "alloc": usage["allocated-memory"], "freed": usage["freed-memory"], "hold": usage["holding-memory"] } i += 1 mem_usage.append(item) except (TypeError, KeyError) as e: raise DataError("Error parsing netconf statistics") from e return mem_usage
def get(connection, filter): try: reply = connection.get(filter=filter) data = xmltodict.parse(reply.xml) except ncclient.operations.RPCError as e: raise RequestError("Netconf get request returned an error") from e except ExpatError as e: raise DataError("Malformed response") from e return data
def edit_config(connection, config): try: reply = connection.edit_config(target="running", config=config) data = xmltodict.parse(reply.xml) except ncclient.operations.RPCError as e: raise RequestError( "Netconf edit-config request returned an error") from e except ExpatError as e: raise DataError("Malformed response") from e return data
def create_ifaz(connection, index, address, mask="255.255.255.0", description=""): try: value = int(index) if value < 0: raise DataError("Invalid loopback interface index") except ValueError as e: raise DataError("Invalid loopback interface index") from e data = """<config> <native xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-native"> <interface> <Loopback> <name>""" + str(index) + """</name> """ if description != "": data += """<description>""" + str(description) + """</description> """ data += """<ip> <address> <primary> <address>""" + str(address) + """</address> <mask>""" + str(mask) + """</mask> </primary> </address> </ip> </Loopback> </interface> </native> </config> """ reply = edit_config(connection, data) try: if "ok" in reply["rpc-reply"]: print("OK response received to interface creation request") except KeyError as e: raise DataError( "Cannot parse data received as response to interface creation request" ) from e
def get_session_stats(connection): filter_get_config = """ <filter> <netconf-state xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring" > <sessions/> <statistics/> </netconf-state> </filter> """ get_res = get(connection, filter_get_config) try: sessions = [] i = 0 data = get_res["rpc-reply"]["data"]["netconf-state"]["sessions"][ "session"] if type(data) != list: data = [data] for session in data: item = { "index": i, "id": session["session-id"], "host": session["source-host"], "time": session["login-time"] } i += 1 sessions.append(item) stats = { "active_sessions": sessions, "sessions_total": get_res["rpc-reply"]["data"]["netconf-state"]["statistics"] ["in-sessions"], "req_total": get_res["rpc-reply"]["data"]["netconf-state"]["statistics"] ["in-rpcs"], "req_fail": get_res["rpc-reply"]["data"]["netconf-state"]["statistics"] ["in-bad-rpcs"], "res_fail": get_res["rpc-reply"]["data"]["netconf-state"]["statistics"] ["out-rpc-errors"] } except (TypeError, KeyError) as e: raise DataError("Error parsing netconf statistics") from e return stats
def print_apic_endpoints(endpoints): i = 0 err = False for endpoint in endpoints: try: print(i, ": ", endpoint["name"], " (", endpoint["host"], ")", sep="") i += 1 except KeyError: print("Malformed endpoint entry, ignoring it") err = True if i == 0 and err: raise DataError("All entries are malformed")
def get_ifaz_ip(connection): resp = connection.send_command("show ip int brief") try: resp_data = resp.split("\n")[1:] i = 0 interfaces = [] for data in resp_data: interface = data.split() ifaz = { "index": i, "name": interface[0], "ip": interface[1], } i += 1 interfaces.append(ifaz) except (IndexError, TypeError, AttributeError) as e: raise DataError("Error obtaining interfaces IP") from e return interfaces
def post(endpoint, path, headers=None, body=None, with_ticket=True): if headers is None: headers = {} if body is None: body = {} try: url = create_url(endpoint["host"], path) except KeyError as e: raise ConnectionError( "Invalid endpoint data, some fields are missing") from e headers["Content-Type"] = "application/json" if with_ticket: headers["X-Auth-Token"] = get_ticket(endpoint) try: resp = requests.post(url, json.dumps(body), headers=headers, verify=False) if resp.status_code == 401: if with_ticket: raise TicketError("Invalid ticket: {}".format( headers["X-Auth-Token"])) else: raise AuthError("Invalid username or password") resp.raise_for_status() response = [resp.status_code, resp.json()] except requests.exceptions.HTTPError as e: raise RequestError("POST returned an error") from e except requests.exceptions.RequestException as e: raise ConnectionError("An error occurred while trying to POST to " + url) from e except json.decoder.JSONDecodeError as e: raise DataError("Malformed response") from e print("Response code:", resp.status_code) print("Response body:\n", resp.text) return response
def get_routing(connection): filter_get_config = """ <filter> <routing-state xmlns="urn:ietf:params:xml:ns:yang:ietf-routing"> <routing-instance> <ribs> <rib> <routes/> </rib> </ribs> </routing-instance> </routing-state> </filter> """ get_res = get(connection, filter_get_config) try: routing_table = [] i = 0 data = get_res["rpc-reply"]["data"]["routing-state"][ "routing-instance"]["ribs"]["rib"]["routes"]["route"] if type(data) != list: data = [data] for route in data: item = {"index": i, "dest_net": route["destination-prefix"]} try: item["egress_ifaz"] = route["next-hop"]["outgoing-interface"] except KeyError: print("Cannot obtain output interface for network ", route["destination-prefix"], ". Adding it anyway...", sep="") i += 1 routing_table.append(item) except (TypeError, KeyError) as e: raise DataError("Error parsing routing table") from e return routing_table
def get_ifaz_ip(connection): filter_get_config = """ <filter> <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"> <interface> <name/> <ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip"/> <ipv6 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip"/> </interface> </interfaces> </filter> """ get_res = get_config(connection, filter_get_config) try: interfaces = [] i = 0 data = get_res["rpc-reply"]["data"]["interfaces"]["interface"] if type(data) != list: data = [data] for interface in data: item = {} try: item["index"] = i item["name"] = interface["name"] item["ip"] = interface["ipv4"]["address"]["ip"] item["mask"] = interface["ipv4"]["address"]["netmask"] except KeyError: pass if "ip" not in item: print("Cannot obtain IP for " + item["name"] + " interface using netconf") i += 1 interfaces.append(item) except (TypeError, KeyError) as e: raise DataError("Error parsing interface IPs") from e return interfaces
def get_ifaz_mac(connection): # Get-config not working for this filter. It just works with <get> command filter_get = """ <filter> <interfaces-state xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"> <interface> <name/> <type/> <if-index/> <phys-address/> </interface> </interfaces-state> </filter> """ get_res = get(connection, filter_get) try: interfaces = [] i = 0 data = get_res["rpc-reply"]["data"]["interfaces-state"]["interface"] if type(data) != list: data = [data] for interface in data: item = { "index": i, "name": interface["name"], "mac": interface["phys-address"], "if-index": interface["if-index"], "type": interface["type"]["#text"], } i += 1 interfaces.append(item) except (TypeError, KeyError) as e: raise DataError("Error parsing interface info") from e return interfaces