def process_mac_fields(vlan, mac, mac_type, interface): """Return proper data for mac address fields.""" if mac_type.lower() in ["self", "static", "system"]: static = True if vlan.lower() == "all": vlan = 0 elif vlan == "-": vlan = 0 if ( interface.lower() == "cpu" or re.search(r"router", interface.lower()) or re.search(r"switch", interface.lower()) ): interface = "" else: static = False if mac_type.lower() in ["dynamic"]: active = True else: active = False return { "mac": helpers.mac(mac), "interface": helpers.canonical_interface_name(interface), "vlan": int(vlan), "static": static, "active": active, "moves": -1, "last_move": -1.0, }
def get_lldp_neighbors_detail(self, interface=""): lldp = {} if interface: command = "show lldp remote_ports {} mode detailed".format( interface) else: command = "show lldp remote_ports mode detailed" lldp_entries = self._send_command(command) lldp_entries = textfsm_extractor(self, "show_lldp_remote_ports_detail", lldp_entries) if len(lldp_entries) == 0: return {} for idx, lldp_entry in enumerate(lldp_entries): local_intf = lldp_entry.pop("local_interface") # Add fields missing on Dlink lldp_entry["parent_interface"] = lldp_entry[ "remote_system_enable_capab"] = "" # Standarding "remote system capab" if lldp_entry["remote_system_capab"]: lldp_entry["remote_system_capab"] = sorted( lldp_entry["remote_system_capab"].strip().lower().split( ",")) else: lldp_entry["remote_system_capab"] = [] # Turn the interfaces into their long version local_intf = canonical_interface_name(local_intf) lldp.setdefault(local_intf, []) lldp[local_intf].append(lldp_entry) return lldp
def get_facts(self): """Return a set of facts from the devices.""" # default values. vendor = "Mellanox" uptime = -1 os_version, hostname, model = ("", ) * 3 # obtain output from device show_ver = self._send_command("show version") show_hosts = self._send_command("show hosts") show_int_status = self._send_command("show interface status") # uptime/serial_number/IOS version for line in show_ver.splitlines(): if "Uptime:" in line: _, uptime_str = line.split("Uptime:") uptime = self.parse_uptime(uptime_str) if "Product release:" in line: line = line.strip() os_version = line.split()[2] os_version = os_version.strip() if "Product model:" in line: line = line.strip() model = line.split()[2] for line in show_hosts.splitlines(): if "Hostname: " in line: _, hostname = line.split("Hostname: ") break interface_list = [] for line in show_int_status.splitlines(): if line == '': continue elif line.startswith('E') or line.startswith('m'): interface = line.split()[0] # Return canonical interface name interface_list.append( helpers.canonical_interface_name(interface)) return { "uptime": int(uptime), "vendor": vendor, "os_version": py23_compat.text_type(os_version), "model": py23_compat.text_type(model), "hostname": py23_compat.text_type(hostname), "interface_list": interface_list, }
def get_lldp_neighbors_detail(self, interface=""): """ get_lldp_neighbors_detail() implementation for s350 """ details = {} # First determine all interfaces with valid LLDP neighbors for local_port in self.get_lldp_neighbors().keys(): if interface: if interface == local_port: entry = self._get_lldp_neighbors_detail_parse(local_port) local_port = canonical_interface_name(local_port, s350_base_interfaces) details[local_port] = [ entry, ] else: entry = self._get_lldp_neighbors_detail_parse(local_port) local_port = canonical_interface_name(local_port, s350_base_interfaces) details[local_port] = [ entry, ] return details
def get_lldp_neighbors(self): """get_lldp_neighbors implementation for s350""" neighbors = {} output = self._send_command("show lldp neighbors") header = True # cycle trought header local_port = "" # keep previous context - multiline syname remote_port = "" remote_name = "" for line in output.splitlines(): if header: # last line of header match = re.match(r"^--------- -+ .*$", line) if match: header = False fields_end = self._get_lldp_neighbors_fields_end(line) continue line_elems = self._get_lldp_neighbors_line_to_fields(line, fields_end) # info owerflow to the other line if line_elems[0] == "" or line_elems[4] == "" or line_elems[5] == "": # complete owerflown fields local_port = local_port + line_elems[0] remote_port = remote_port + line_elems[2] remote_name = remote_name + line_elems[3] # then reuse old values na rewrite previous entry else: local_port = line_elems[0] remote_port = line_elems[2] remote_name = line_elems[3] local_port = canonical_interface_name(local_port, s350_base_interfaces) neighbor = { "hostname": remote_name, "port": remote_port, } neighbor_list = [ neighbor, ] neighbors[local_port] = neighbor_list return neighbors
def _get_lldp_neighbors_detail_parse(self, local_port): # Set defaults, just in case the remote fails to provide a field. ( remote_port_id, remote_port_description, remote_chassis_id, remote_system_name, remote_system_description, remote_system_capab, remote_system_enable_capab, ) = ("N/A",) * 7 output = self._send_command("show lldp neighbors {}".format(local_port)) for line in output.splitlines(): if line.startswith("Port ID"): remote_port_id = line.split()[-1] elif line.startswith("Device ID"): remote_chassis_id = line.split()[-1] elif line.startswith("Port description"): remote_port_description = self._get_lldp_line_value(line) elif line.startswith("System Name"): remote_system_name = self._get_lldp_line_value(line) elif line.startswith("System description"): remote_system_description = self._get_lldp_line_value(line) elif line.startswith("Capabilities"): caps = self._get_lldp_neighbors_detail_capabilities_parse(line) remote_port_id = canonical_interface_name(remote_port_id, s350_base_interfaces) entry = { "parent_interface": "N/A", "remote_port": remote_port_id, "remote_port_description": remote_port_description, "remote_chassis_id": remote_chassis_id, "remote_system_name": remote_system_name, "remote_system_description": remote_system_description, "remote_system_capab": caps, "remote_system_enable_capab": caps, } return entry
def get_interfaces_ip(self): """Returns all configured interface IP addresses.""" interfaces = {} show_ip_int = self._send_command("show ip interface") header = True # cycle trought header for line in show_ip_int.splitlines(): if header: # last line of first header match = re.match(r"^---+ -+ .*$", line) if match: header = False fields_end = self._get_ip_int_fields_end(line) continue # next header, stop processing text if re.match(r"^---+ -+ .*$", line): break line_elems = self._get_ip_int_line_to_fields(line, fields_end) # only valid interfaces # in diferent firmwares there is 'Status' field allwais on last place if line_elems[len(line_elems) - 1] != "Valid": continue cidr = line_elems[0] interface = line_elems[1] ip = netaddr.IPNetwork(cidr) family = "ipv{0}".format(ip.version) interface = canonical_interface_name(interface, s350_base_interfaces) interfaces[interface] = {family: {str(ip.ip): {"prefix_length": ip.prefixlen}}} return interfaces
def get_arp_table(self, vrf=""): """ Get the ARP table, the age isn't readily available so we leave that out for now. vrf is needed for test - no support on s350 """ arp_table = [] output = self._send_command("show arp") for line in output.splitlines(): # A VLAN may not be set for the entry if "vlan" not in line: continue if len(line.split()) == 4: interface, ip, mac, _ = line.split() elif len(line.split()) == 5: if1, if2, ip, mac, _ = line.split() interface = "{} {}".format(if1, if2) elif len(line.split()) == 6: _, _, interface, ip, mac, _ = line.split() else: raise ValueError("Unexpected output: {}".format(line.split())) interface = canonical_interface_name(interface, s350_base_interfaces) entry = { "interface": interface, "mac": napalm.base.helpers.mac(mac), "ip": ip, "age": 0.0, } arp_table.append(entry) return arp_table
def collect_transceivers_info( # pylint: disable=R0911 task: Task, update_cache=True, use_cache=False) -> Result: """ Collect transceiver informaton on all devices Supported Devices: Cisco IOS cisco_nxos Args: task: Task: update_cache: (Default value = True) use_cache: (Default value = False) Returns: """ cache_name = "transceivers" if use_cache: data = get_data_from_file(task.host.name, cache_name) return Result(host=task.host, result=data) transceivers_inventory = [] xcvr_model = { "interface": None, "manufacturer": None, "serial": None, "part_number": None, "type": None, } check_data_dir(task.host.name) if task.host.platform == "ios": try: results = task.run( task=netmiko_send_command, command_string="show inventory", use_textfsm=True, ) except: logger.debug("An exception occured while pulling the inventory", exc_info=True) return Result(host=task.host, failed=True) inventory = results[0].result cmd = "show interface transceiver" try: results = task.run( task=netmiko_send_command, command_string=cmd, use_textfsm=True, ) except: logger.debug( "An exception occured while pulling the transceiver info", exc_info=True) return Result(host=task.host, failed=True) transceivers = results[0].result if not isinstance(transceivers, list): logger.debug( f"{task.host.name}: command: {cmd} was not returned as a list, please check if the ntc-template are installed properly" # pylint: disable=C0301 ) return Result(host=task.host, result=transceivers_inventory) transceiver_names = [t["iface"] for t in transceivers] full_transceiver_names = [ canonical_interface_name(t) for t in transceiver_names ] # Check if the optic is in the inventory by matching on the interface name # Normalize the name of the interface before returning it for item in inventory: xcvr = copy.deepcopy(xcvr_model) if item.get("name", "") in transceiver_names: xcvr["interface"] = canonical_interface_name(item["name"]) elif item.get("name", "") in full_transceiver_names: xcvr["interface"] = item["name"] else: continue xcvr["serial"] = item["sn"] xcvr["type"] = item["descr"] transceivers_inventory.append(xcvr) elif task.host.platform == "nxos": cmd = "show interface transceiver" try: results = task.run(task=netmiko_send_command, command_string=cmd, use_textfsm=True) except: logger.debug( "An exception occured while pulling the transceiver info", exc_info=True) return Result(host=task.host, failed=True) transceivers = results[0].result if not isinstance(transceivers, list): logger.warning( f"command: {cmd} was not returned as a list, please check if the ntc-template are installed properly" ) return Result(host=task.host, result=transceivers_inventory) for tranceiver in transceivers: transceivers_inventory.append(tranceiver) elif task.host.platform == "eos": nr_device = task.host.get_connection("napalm", task.nornir.config) eos_device = nr_device.device results = eos_device.run_commands(["show transceiver status"]) transceivers = results[0]["ports"] for name, data in transceivers.items(): try: xcvr = copy.deepcopy(xcvr_model) xcvr["serial"] = data["serialNumber"]["state"] xcvr["interface"] = list(data["interfaces"].keys())[0] xcvr["type"] = data["mediaType"]["state"] xcvr["part_number"] = data["mediaType"]["state"] except: logger.warning( f"Unable to extract the transceiver information for {name} : {sys.exc_info()[0]}" ) continue transceivers_inventory.append(xcvr) else: logger.debug( f"{task.host.name} | collect_transceiver_info not supported yet for {task.host.platform}" ) if update_cache and transceivers_inventory: save_data_to_file(task.host.name, cache_name, transceivers_inventory) return Result(host=task.host, result=transceivers_inventory)
def get_interfaces(self): """ get_interfaces() implementation for S350 """ interfaces = {} show_status_output = self._send_command("show interfaces status") show_description_output = self._send_command("show interfaces description") # by documentation SG350 show_jumbo_frame = self._send_command("show ports jumbo-frame") match = re.search(r"Jumbo frames are enabled", show_jumbo_frame, re.M) if match: mtu = 9000 else: mtu = 1518 mac = "0" for status_line in show_status_output.splitlines(): if "Up" in status_line or "Down" in status_line: if "Po" in status_line: interface, _, _, speed, _, _, link_state = status_line.split() else: interface, _, _, speed, _, _, link_state, _, _ = status_line.split() # Since the MAC address for all the local ports are equal, get the address # from the first port and use it everywhere. if mac == "0": show_system_output = self._send_command("show lldp local " + interface) mac = show_system_output.splitlines()[0].split(":", maxsplit=1)[1].strip() if speed == "--": is_enabled = False speed = 0 else: is_enabled = True speed = int(speed) is_up = link_state == "Up" for descr_line in show_description_output.splitlines(): description = 0 if descr_line.startswith(interface): description = " ".join(descr_line.split()[1:]) break # last_flapped can not be get - setting to default entry = { "is_up": is_up, "is_enabled": is_enabled, "speed": speed, "mtu": mtu, "last_flapped": -1.0, "description": description, "mac_address": napalm.base.helpers.mac(mac), } interface = canonical_interface_name(interface, s350_base_interfaces) interfaces[interface] = entry return interfaces
def get_facts(self): """Return a set of facts from the device.""" serial_number, fqdn, os_version, hostname, domainname = ("Unknown",) * 5 # Submit commands to the device. show_ver = self._send_command("show version") show_sys = self._send_command("show system") show_inv = self._send_command("show inventory") show_hosts = self._send_command("show hosts") show_int_st = self._send_command("show interfaces status") os_version = self._get_facts_parse_os_version(show_ver) # hostname hostname = self._get_facts_hostname(show_sys) # special case for SG500 fw v1.4.x if hostname == "Unknown": hostname = self._get_facts_hostname_from_config( self._send_command("show running-config") ) # uptime uptime_str = self._get_facts_uptime(show_sys) uptime = self._parse_uptime(uptime_str) # serial_number and model inventory = self._get_facts_parse_inventory(show_inv)["1"] serial_number = inventory["sn"] model = inventory["pid"] # fqdn domainname = napalm.base.helpers.textfsm_extractor(self, "hosts", show_hosts)[0] domainname = domainname["domain_name"] if domainname == "Domain": domainname = "Unknown" if domainname != "Unknown" and hostname != "Unknown": fqdn = "{0}.{1}".format(hostname, domainname) # interface_list interfaces = [] show_int_st = show_int_st.strip() # remove the header information show_int_st = re.sub( r"(^-.*$|^Port .*$|^Ch .*$)|^\s.*$|^.*Flow.*$", "", show_int_st, flags=re.M ) for line in show_int_st.splitlines(): if not line: continue interface = line.split()[0] interface = canonical_interface_name(interface, s350_base_interfaces) interfaces.append(str(interface)) return { "fqdn": str(fqdn), "hostname": str(hostname), "interface_list": interfaces, "model": str(model), "os_version": str(os_version), "serial_number": str(serial_number), "uptime": uptime, "vendor": "Cisco", }
def get_facts(self): """Return a set of facts from the devices.""" # default values. vendor = "Cisco" uptime = -1 serial_number, fqdn, os_version, hostname, domain_name, model = ("",) * 6 # obtain output from device show_ver = self._send_command("show version") show_hosts = self._send_command("show hosts") show_int_status = self._send_command("show interface status") show_hostname = self._send_command("show hostname") # uptime/serial_number/IOS version for line in show_ver.splitlines(): if " uptime is " in line: _, uptime_str = line.split(" uptime is ") uptime = self.parse_uptime(uptime_str) if "Processor Board ID" in line: _, serial_number = line.split("Processor Board ID ") serial_number = serial_number.strip() if "system: " in line or "NXOS: " in line: line = line.strip() os_version = line.split()[2] os_version = os_version.strip() if "cisco" in line and "hassis" in line: match = re.search(r".cisco (.*) \(", line) if match: model = match.group(1).strip() match = re.search(r".cisco (.* [cC]hassis)", line) if match: model = match.group(1).strip() hostname = show_hostname.strip() # Determine domain_name and fqdn for line in show_hosts.splitlines(): if "Default domain" in line: _, domain_name = re.split(r".*Default domain.*is ", line) domain_name = domain_name.strip() break if hostname.count(".") >= 2: fqdn = hostname # Remove domain name from hostname if domain_name: hostname = re.sub(re.escape(domain_name) + "$", "", hostname) hostname = hostname.strip(".") elif domain_name: fqdn = "{}.{}".format(hostname, domain_name) # interface_list filter interface_list = [] show_int_status = show_int_status.strip() # Remove the header information show_int_status = re.sub( r"(?:^---------+$|^Port .*$|^ .*$)", "", show_int_status, flags=re.M ) for line in show_int_status.splitlines(): if not line: continue interface = line.split()[0] # Return canonical interface name interface_list.append(helpers.canonical_interface_name(interface)) return { "uptime": int(uptime), "vendor": vendor, "os_version": py23_compat.text_type(os_version), "serial_number": py23_compat.text_type(serial_number), "model": py23_compat.text_type(model), "hostname": py23_compat.text_type(hostname), "fqdn": fqdn, "interface_list": interface_list, }
def get_facts(self): """Return a set of facts from the devices.""" # default values. vendor = u'Cisco' uptime = -1 serial_number, fqdn, os_version, hostname, domain_name, model = ( '', ) * 6 # obtain output from device show_ver = self._send_command('show version') show_hosts = self._send_command('show hosts') show_int_status = self._send_command('show interface status') show_hostname = self._send_command('show hostname') # uptime/serial_number/IOS version for line in show_ver.splitlines(): if ' uptime is ' in line: _, uptime_str = line.split(' uptime is ') uptime = self.parse_uptime(uptime_str) if 'Processor Board ID' in line: _, serial_number = line.split("Processor Board ID ") serial_number = serial_number.strip() if 'system: ' in line or 'NXOS: ' in line: line = line.strip() os_version = line.split()[2] os_version = os_version.strip() if 'cisco' in line and 'hassis' in line: match = re.search(r'.cisco (.*) \(', line) if match: model = match.group(1).strip() match = re.search(r'.cisco (.* [cC]hassis)', line) if match: model = match.group(1).strip() hostname = show_hostname.strip() # Determine domain_name and fqdn for line in show_hosts.splitlines(): if 'Default domain' in line: _, domain_name = re.split(r".*Default domain.*is ", line) domain_name = domain_name.strip() break if hostname.count(".") >= 2: fqdn = hostname # Remove domain name from hostname if domain_name: hostname = re.sub(re.escape(domain_name) + '$', '', hostname) hostname = hostname.strip('.') elif domain_name: fqdn = '{}.{}'.format(hostname, domain_name) # interface_list filter interface_list = [] show_int_status = show_int_status.strip() # Remove the header information show_int_status = re.sub(r'(?:^---------+$|^Port .*$|^ .*$)', '', show_int_status, flags=re.M) for line in show_int_status.splitlines(): if not line: continue interface = line.split()[0] # Return canonical interface name interface_list.append(canonical_interface_name(interface)) return { 'uptime': int(uptime), 'vendor': vendor, 'os_version': py23_compat.text_type(os_version), 'serial_number': py23_compat.text_type(serial_number), 'model': py23_compat.text_type(model), 'hostname': py23_compat.text_type(hostname), 'fqdn': fqdn, 'interface_list': interface_list }