def main(): #print("Beginning: ", datetime.now()) nr = InitNornir(config_file="config.yaml") # info contains the output of the command info = nr.run(task=netmiko_send_command, command_string="show ip route | in 1.1.1.1") # Get hosts to use as argument in info['hosts'].result for dev in nr.inventory.hosts.keys(): output = info[dev].result #ip_addr = nr.inventory.hosts[dev].hostname if "1.1.1.1" not in output: device_list.append(dev) # Create one list with hostnames and one list with ip addresses for host in device_list: hostname.append(host) ip_addr.append(nr.inventory.hosts[host].hostname) # combine two lists into a dictionary output_dev = dict(zip(hostname,ip_addr)) nr.close_connections() #if output_dev not empty if output_dev: tmp = json.dumps(output_dev) mail_body = tmp.replace("\"","").replace(",","\n").strip("{").strip("}") my_sendmail(mail_body) return()
class NetmikoShowInterfaces(NetworkTestStrategyInterface): def __init__(self, test_definition): device_information = test_definition.get_test_devices() self.platform = device_information.get_platform() self.hostname = device_information.get_hostname() self.username = device_information.get_username() self.password = device_information.get_password() self.expected = test_definition.get_expected_result() self.test_name = test_definition.get_test_id() self.result = None self.nr = InitNornir(inventory={ "plugin": "nornir.plugins.inventory.simple.SimpleInventory", "options": { "hosts": { "host1": { "platform": str(self.platform), "hostname": str(self.hostname), "username": str(self.username), "password": str(self.password), } } } }, logging={"enabled": False}) def run_test(self): return self.nr.run(task=netmiko_send_command, command_string="show ip interface brief") def evaluate_result(self) -> bool: return self.result == self.expected def print_result(self, result): print(self.expected) print_result(result) def get_result(self): return self.result def set_result(self, result): self.result = {} result_collection = str(result["host1"][0]) array = result_collection.split() for i in range(6, len(array), 6): if array[i + 4] == "up": self.result.update({array[i]: True}) else: self.result.update({array[i]: False}) def get_expected_value(self): return self.expected def get_test_name(self): return self.test_name def close_connection(self): self.nr.close_connections()
class NetmikoPingTest(NetworkTestStrategyInterface): def __init__(self, test_definition): device_informations = test_definition.get_test_devices() self.test_name = test_definition.get_test_id() self.hostname = device_informations.get_hostname() self.username = device_informations.get_username() self.password = device_informations.get_password() self.platform = device_informations.get_platform() self.expected = test_definition.get_expected_result() self.destination = test_definition.get_target() self.result = None self.nr = InitNornir(inventory={ "plugin": "nornir.plugins.inventory.simple.SimpleInventory", "options": { "hosts": { "host1": { "platform": self.platform, "hostname": self.hostname, "username": self.username, "password": self.password, } } } }, logging={"enabled": False}) def run_test(self): return self.nr.run(task=netmiko_send_command, command_string=f"ping {self.destination}") def evaluate_result(self) -> bool: return self.expected == self.result def print_result(self, result): print(self.expected) print_result(result) def get_result(self): return self.result def set_result(self, result): for host_name, res_data in result.items(): mapped_result = res_data[0].result if "Success rate is 100 percent (5/5)" in mapped_result: self.result = "Success" else: self.result = "Failure" def get_expected_value(self): return self.expected def get_test_name(self): return self.test_name def close_connection(self): self.nr.close_connections()
class NapalmShowArpTables(NetworkTestStrategyInterface): def __init__(self, test_definition): device_information = test_definition.get_test_devices() self.hostname = device_information.get_hostname() self.username = device_information.get_username() self.password = device_information.get_password() self.expected = test_definition.get_expected_result() self.platform = device_information.get_platform() self.test_name = test_definition.get_test_id() self.result = None if self.platform in "cisco_ios": self.platform = "IOS" self.nr = InitNornir(inventory={ "plugin": "nornir.plugins.inventory.simple.SimpleInventory", "options": { "hosts": { "host1": { "platform": self.platform, "hostname": self.hostname, "username": self.username, "password": self.password } } } }, logging={"enabled": False}) def run_test(self): return self.nr.run(task=napalm_get, getters=["arp_table"]) def evaluate_result(self) -> bool: return self.expected == self.result def print_result(self, result): print(self.expected) print_result(result) def get_result(self): return self.result def set_result(self, result): self.result = [] result_collection = result["host1"][0].result["arp_table"] for i in range(0, len(result_collection)): del result_collection[i]["age"] self.result.append((result_collection[i])) def get_expected_value(self): return self.expected def get_test_name(self): return self.test_name def close_connection(self): self.nr.close_connections()
def main(): nr = InitNornir( inventory={"plugin": "nornir.plugins.inventory.csv_plugin.read_csv"}) result = nr.run(task=grab_mac, num_workers=500) nr.close_connections() print(result)
def nr(): current_dir = os.path.dirname(os.path.realpath(__file__)) nornir = InitNornir( inventory={ "plugin": "SimpleInventory", "options": { "host_file": f"{current_dir}/inventory/hosts.yml" } }) yield nornir nornir.close_connections()
def main(): #we read the hosts list from the excel file wbsites = openpyxl.load_workbook("sitelist.xlsx") ws = wbsites.active max_row = ws.max_row routers = [] for row in range(2, max_row + 1): router = dict() router['site'] = str(ws.cell(row=row, column=1).value).strip() router['ipaddress'] = str(ws.cell(row=row, column=2).value).strip() router['wandes'] = "MPLS-OTE (" + str( ws.cell(row=row, column=3).value).strip() + ") (" + str( ws.cell(row=row, column=4).value).strip() + ")" routers.append(router) wbsites.close() #Nornir is initialiazed and the inventory is formed nr = InitNornir(config_file="config.yaml") #ipdb.set_trace() #we append a new attribute to every host in the inventory, which comes from the excel file for router in routers: node = router['site'] nr.inventory.hosts[node]["expected_wan_int_description"] = router[ "wandes"] global changescount changescount = 0 global changedhostlist changedhostlist = [] #the custom task is run by calling the function result = nr.run(task=check_wan_int_description, num_workers=50) nr.close_connections() #we print the desired values, now part of the inventory for host in nr.inventory.hosts.values(): print(host.get("expected_wan_int_description")) #we print how many changes were made and where print("changes made:", changescount) for host in changedhostlist: print(host)
class NetmikoDriver: def __init__(self): InventoryPluginRegister.register("OdsDictInventory", OdsDictInventory) self.nr = None def open(self, hosts_dict, groups_dict, defaults_dict): if len(defaults_dict) == 0: defaults_dict = NETMIKO_EXTRAS else: defaults_dict.update(NETMIKO_EXTRAS) self.nr = InitNornir( runner={ "plugin": "threaded", "options": { "num_workers": 1, }, }, inventory={ "plugin": "OdsDictInventory", "options": { "hosts_dict": hosts_dict, "groups_dict": groups_dict, "defaults_dict": defaults_dict, }, }, ) print("Netmiko-open") return self.nr def close(self): print("Netmiko-close") self.nr.close_connections() def send_command(self, command: str) -> dict: """Send command and return results. Args: command (str): Command to run on device. """ print("Netmiko-send_command") result = self.nr.run(task=netmiko_send_command, command_string=command) return result
class NapalmPingTest(NetworkTestStrategyInterface): def __init__(self, test_definition): device_information = test_definition.get_test_devices() self.hostname = device_information.get_hostname() self.username = device_information.get_username() self.password = device_information.get_password() self.platform = device_information.get_platform() self.expected = test_definition.get_expected_result() self.destination = test_definition.get_target() self.loopback = device_information.get_loopback() self.test_name = test_definition.get_test_id() self.result = None if self.platform.lower() in "cisco_ios": self.platform = "IOS" self.nr = InitNornir(inventory={ "plugin": "nornir.plugins.inventory.simple.SimpleInventory", "options": { "hosts": { "host1": { "platform": self.platform, "hostname": self.hostname, "username": self.username, "password": self.password, } } } }, logging={"enabled": False}) def run_test(self): return self.nr.run(task=napalm_ping, dest=self.destination, source=self.loopback) def evaluate_result(self) -> bool: return self.expected == self.result def print_result(self, result): print(self.expected) print_result(result) def get_result(self): return self.result def set_result(self, result): result_collection = result["host1"][0].result["success"] packet_loss = result_collection["packet_loss"] if packet_loss == 0: self.result = "Success" else: self.result = "Failure" def get_expected_value(self): return self.expected def get_test_name(self): return self.test_name def close_connection(self): self.nr.close_connections()
# remove text_fsm # NET_TEXTFSM= results = nr.run(task=netmiko_send_command, command_string="show version", use_textfsm=True) print_result(results) from nornir.plugins.tasks.networking import napalm_get results = nr.run(task=napalm_get, getters=["facts", "interfaces"]) print_result(results) for host in nr.inventory.hosts.values(): print(f"{host.name} connections: {host.connections}") nr.close_connections() print(f"{Fore.RED}All connections have been closed{Fore.RESET}", end="\n\n") for host in nr.inventory.hosts.values(): print(f"{host.name} connections: {host.connections}") from nornir.core.filter import F print(list(nr.filter(F(locator="R1.New York")).inventory.hosts.keys())) print(list(nr.filter(F(groups__contains="London")).inventory.hosts.keys())) print( list( nr.filter( F(groups__contains="London") & F(tags__contains="isr4400")).inventory.hosts.keys())) print(
def os_upgrade(self, hostname, hostaddr): def get_output(agg_result): for k, multi_result in agg_result.items(): for result_obj in multi_result: return result_obj.result # 'sw_log' function sends syslog messages to the switch. def sw_log(logmsg): result = nr.run( task=netmiko_send_command, command_string=f'send log ZTP-Watcher: {logmsg}', ) return (result) # 'send_cmd' function sends commands to the host. def send_cmd(cmd): result = nr.run( task=netmiko_send_command, command_string=cmd, delay_factor=6, ) return (result) # 'send_config' function sends configuration commands to the host. def send_config(config): result = nr.run(task=netmiko_send_config, config_commands=config) return (result) # Instatiate an SNMP instance def get_SNMP(ip_addr, config): snmp = SNMP(ip_addr, version=3, username=config['snmp_username'], authproto=config['snmp_authproto'], authkey=config['snmp_authkey'], privproto=config['snmp_privproto'], privkey=config['snmp_privkey']) return snmp # Truncates new_ios & boot_ios to versions # That can be accurately compared # Readability > Clever def truncate_ios(new_ios, boot_ios, ios_xe): new_ios_split = new_ios.split('.') new_ios_rstrip = '.' + new_ios_split[-1] new_ios_lstrip = new_ios_split[0] + '.' new_ios = new_ios.rstrip(new_ios_rstrip) new_ios = new_ios.lstrip(new_ios_lstrip) if ios_xe: new_ios = new_ios.rstrip('.SPA') # Would break 03.03, but that is really old new_ios = new_ios.replace('0', '') else: new_ios = new_ios[:2] + '.' + new_ios[2:] boot_ios = boot_ios.replace('(', '-') boot_ios = boot_ios.replace(')', '.') return (boot_ios, new_ios) # Parse out 1.3.6.1.2.1.1.1.0 for version information # Also, determine if it is a 3850 # Help needed - do all IOS XE versions have a CAT3K in them? # Note: 1.3.6.1.2.1.16.19.6.0 boot file is not reliable for ios xe def fetch_ver(snmp): ios_xe = False sysDescr = str(snmp.get('1.3.6.1.2.1.1.1.0')) if 'CAT3K' in sysDescr: ios_xe = True ver = (sysDescr.split(',')) if 'Version' in ver[2]: ver = ver[2].lstrip(' Version ') else: ver = ver[3].lstrip(' Version ').split()[0] return ver, ios_xe # Archive = Run Before Bin = Run After def wr_mem(is_tar=True): sw_log('Writing config.') writemem = send_cmd('write mem') if is_tar: Logger(f'{hostname}: Config written, ready to upgrade.') sw_log('Config written, ready for upgrade.') else: Logger( f'{hostname}: Config written, ready to reload/power off.') sw_log('Config written, ready to reload/power off.') #result = get_output(writemem) # Logger(result) # Uncomment for TS # Only for .bin # This function should properly handle the setting of boot string def set_boot_var(new_ios): sw_log('Setting boot variable and writing config.') bootcmds = f'default boot sys\nboot system flash:{new_ios}' bootcmds_list = bootcmds.splitlines() bootvar = send_config(bootcmds_list) Logger(f'{hostname}: Boot variable set -> write config.') #result = get_output(bootvar) # Logger(result) # Uncomment for TS # IOS XE only - specifically 3850 # This does a software clean def ios_xe_upgrade(copy_method, tftpaddr, new_ios, old_xe=False): if old_xe: cmd = 'software clean' else: cmd = 'request platform software package clean switch all' #DEBUG #Logger(cmd) result = nr.run(task=netmiko_send_command, command_string=cmd, delay_factor=6, expect_string="Nothing|proceed") for device_name, multi_result in result.items(): #DEBUG #Logger(multi_result[0].result) if "proceed" in multi_result[0].result: Logger("Cleaning old software.") result = nr.run(task=netmiko_send_command, command_string='y', delay_factor=6, expect_string=r"\#") else: Logger("No software cleaning required.") Logger('Cleaner Done') ##result = get_output(result) ##Logger(result) # Uncomment for TS # FIXME: Figure out why it won't work without sleep time.sleep(1) cmd = f'copy {copy_method}{tftpaddr}/{new_ios} flash:' #DEBUG Logger(cmd) result = nr.run(task=netmiko_send_command, command_string=cmd, delay_factor=6, expect_string=r'Destination filename') #DEBUG result2 = get_output(result) Logger(result2) # Uncomment for TS for device_name, multi_result in result.items(): Logger(multi_result[0].result) if "Destination" in multi_result[0].result: result = nr.run(task=netmiko_send_command, command_string=new_ios, delay_factor=6, expect_string=r"\#") result2 = get_output(result) Logger(result2) # Uncomment for TS if old_xe: a = (f'software install file flash:{new_ios} on-reboot new') Logger(a) installer = send_cmd(a) else: a = ( 'request platform software package install switch all file ' f'flash:{new_ios} new auto-copy') installer = send_cmd(a) result = get_output(installer) Logger(result) # Uncomment for TS nr = InitNornir( #logging={"file": "debug.txt", "level": "debug"}, inventory={ 'options': { 'hosts': { hostname: { 'hostname': hostaddr, 'username': username, 'password': password, 'platform': 'ios' } } } }) Logger(f'{hostname}: Fetching boot variable via SNMP to compare.') # I need SNMP anyway, and can fetch this in a fraction of the time # it takes to get it via SSH snmp = get_SNMP(hostaddr, config) try: model_oid = str(snmp.get('1.3.6.1.2.1.1.2.0')) except: # FIXME - Maybe Good-er Exception handling and try again after wait Logger(f'{hostname}: Can not SNMP - BAILING!.') sw_log('Error: Can not SNMP.') nr.close_connections() return # Bit Ugly if model_oid in config: new_ios = config[model_oid] is_tar = new_ios.split('.')[-1] == 'tar' if is_tar: wr_mem() boot_ios, ios_xe = fetch_ver(snmp) boot_ios_tr, new_ios_tr = truncate_ios(new_ios, boot_ios, ios_xe) if boot_ios_tr == new_ios_tr: Logger( f'{hostname}: Up to date ({boot_ios_tr}), skipping transfer.' ) sw_log( f'Image file ({boot_ios_tr}) up to date, skipping transfer.' ) else: copy_method = config['copy_method'] Logger( f'{hostname}: Image old, starting {copy_method.split(":")[0]} transfer.' ) sw_log( f'Newer Version ({new_ios_tr}) exists, starting image transfer via {copy_method.split(":")[0]}.' ) copystart = time.time() if ios_xe: ios_xe_upgrade(copy_method, tftpaddr, new_ios, old_xe=boot_ios_tr.startswith('03')) copyduration = round(time.time() - copystart) Logger( f'{hostname}: Image transfer completed after {copyduration}s.' ) if not is_tar: # sw_log('Image transfer complete.') else: if is_tar: copyfile = send_cmd( f'archive download-sw /over /rel {copy_method}{tftpaddr}/{new_ios}' ) else: copyfile = send_cmd( f'copy {copy_method}{tftpaddr}/{boot_file} flash:') copyduration = round(time.time() - copystart) Logger( f'{hostname}: Image transfer completed after {copyduration}s.' ) if not is_tar: # sw_log('Image transfer complete.') #result = get_output(copyfile) # Logger(result) # Uncomment for TS else: Logger(f'{model_oid}: Not found in config - skipping IOS.') if not is_tar: if not ios_xe: set_boot_var(new_ios) wr_mem(is_tar) Logger(f'Configuration Finished.') sw_log('Config finished, ready to use.') nr.close_connections()
def os_upgrade(self, hostname, conn): def get_output(agg_result): for k, multi_result in agg_result.items(): for result_obj in multi_result: return result_obj.result # 'sw_log' function sends syslog messages to the switch. def sw_log(logmsg): result = nr.run( task=netmiko_send_command, command_string=f'send log ZTP-Watcher: {logmsg}', ) return(result) # 'send_cmd' function sends commands to the host. def send_cmd(cmd): result = nr.run( task=netmiko_send_command, command_string=cmd, delay_factor=6, ) return(result) # 'send_config' function sends configuration commands to the host. def send_config(config): result = nr.run( task=netmiko_send_config, config_commands=config ) return(result) # Initiate Nornir connection to switch. nr = InitNornir( inventory={ 'options': { 'hosts': { hostname: { 'hostname': conn, 'username': username, 'password': password, 'platform': 'ios' } } } } ) # Check flash: on switch for image file specified in ztpconfig.yaml. Logger(f'{hostname}: Connecting via SSH to check for image file on switch.') checkimg = send_cmd(f'dir flash:{imgfile}') output = get_output(checkimg) if '%Error' not in output: # Image file already in flash, skip transfer. Logger(f'{hostname}: Image file already present on switch ({imgfile}), skipping transfer.') sw_log(f'Image file already present ({imgfile}), skipping transfer.') else: # Image file not found, initiate TFTP transfer. Logger(f'{hostname}: Image file not found on switch ({imgfile}), starting TFTP transfer.') sw_log(f'Image file not found ({imgfile}), starting image transfer via TFTP.') copystart = time.time() copyfile = send_cmd(f'copy tftp://{tftpaddr}/{imgfile} flash:') copyduration = round(time.time() - copystart) copystatus = get_output(copyfile) if '%Error' not in copystatus: Logger(f'{hostname}: Image transfer completed after {copyduration}s -> set boot variable.') sw_log('Image transfer complete -> set boot variable.') # Set boot variable on switch. bootcmds = f'default boot sys\nboot system flash:{imgfile}' bootcmds_list = bootcmds.splitlines() send_config(bootcmds_list) Logger(f'{hostname}: Boot variable set -> write config.') sw_log('Boot variable set -> write config.') else: Logger(f'{hostname}: ***Image transfer failed after {copyduration}s; {copystatus}') sw_log('***Image transfer failed.') # Send post-provisioning configuration commands to switch. if post_cfg: Logger(f'{hostname}: Sending post provisioning configurations.') sw_log('Sending post provisioning configurations.') postcfg_list = postcfg.splitlines() send_config(postcfg_list) # Push final config back to TFTP server. if cfg_push: Logger(f'{hostname}: Pushing final running config to TFTP server ({tftpaddr}/{cfg_push}/{hostname}.cfg).') sw_log(f'Pushing final config to TFTP server ({tftpaddr}/{cfg_push}/{hostname}.cfg).') send_cmd(f'copy run tftp://{tftpaddr}/{cfg_push}/{hostname}.cfg') # Write configuration to switch. sw_log('Writing configuration to startup.') send_cmd('write mem') Logger(f'{hostname}: Config written, ready to reload/power off.') sw_log('Config written, ready to reload/power off.') # Close nornir connection to switch. nr.close_connections()
class NetmikoShowOspfNeighbor(NetworkTestStrategyInterface): def __init__(self, test_definition): device_information = test_definition.get_test_devices() self.platform = device_information.get_platform() self.hostname = device_information.get_hostname() self.username = device_information.get_username() self.password = device_information.get_password() self.expected = test_definition.get_expected_result() self.test_name = test_definition.get_test_id() self.result = None self.nr = InitNornir(inventory={ "plugin": "nornir.plugins.inventory.simple.SimpleInventory", "options": { "hosts": { "host1": { "platform": str(self.platform), "hostname": str(self.hostname), "username": str(self.username), "password": str(self.password), } } } }, logging={"enabled": False}) def run_test(self): return self.nr.run(task=netmiko_send_command, command_string="show ip ospf neighbor") def evaluate_result(self) -> bool: return self.result == self.expected def print_result(self, result): print(self.expected) print_result(result) def get_result(self): return self.result def set_result(self, result): self.result = [] result_collection = str(result["host1"][0]) array = result_collection.split() for i in range(8, len(array), 6): neighbor_dict = { "Neighbor-ID": array[i], "Priority": array[i + 1], "State": array[i + 2], "Address": array[i + 4], "Interface": array[i + 5] } self.result.append(neighbor_dict) def get_expected_value(self): return self.expected def get_test_name(self): return self.test_name def close_connection(self): self.nr.close_connections()
class NetmikoTraceroute(NetworkTestStrategyInterface): def __init__(self, test_definition): device_information = test_definition.get_test_devices() self.platform = device_information.get_platform() self.hostname = device_information.get_hostname() self.username = device_information.get_username() self.password = device_information.get_password() self.destination = test_definition.get_target() self.expected = test_definition.get_expected_result() self.test_name = test_definition.get_test_id() self.result = None self.nr = InitNornir( inventory={ "plugin": "nornir.plugins.inventory.simple.SimpleInventory", "options": { "hosts": { "host1": { "platform": self.platform, "hostname": self.hostname, "username": self.username, "password": self.password, } } } }, logging={"enabled": False} ) def run_test(self): return self.nr.run( task=netmiko_send_command, command_string=f"traceroute {self.destination}" ) def evaluate_result(self) -> bool: if len(self.result) != len(self.expected): return False i = 0 for line in self.result: array = line.split() if self.expected[i] != array[1]: return False i += 1 return True def print_result(self, result): print(self.expected) print_result(result) def get_result(self): return self.result def set_result(self, result): self.result = [] result_collection = str(result["host1"][0]) array = result_collection.splitlines() for line in array[3:]: self.result.append(line) def get_expected_value(self): return self.expected def get_test_name(self): return self.test_name def close_connection(self): self.nr.close_connections()
def _task_group_netmiko_send_commands(task, commands): # run commands for command in commands: task.run(task=netmiko_send_command, command_string=command, name=command) return Result(host=task.host) # run single task result1 = NornirObj.run(task=netmiko_send_command, command_string="show clock") # run grouped tasks result2 = NornirObj.run(task=_task_group_netmiko_send_commands, commands=["show clock", "show run | inc hostname"]) # run another single task result3 = NornirObj.run(task=netmiko_send_command, command_string="show run | inc hostname") NornirObj.close_connections() # Print results formed_result1 = ResultSerializer(result1, add_details=True) pprint.pprint(formed_result1, width=100) formed_result2 = ResultSerializer(result2, add_details=True) pprint.pprint(formed_result2, width=100) formed_result3 = ResultSerializer(result3, add_details=True) pprint.pprint(formed_result3, width=100)
class NetmikoShowArpTables(NetworkTestStrategyInterface): def __init__(self, test_definition): device_information = test_definition.get_test_devices() self.platform = device_information.get_platform() self.hostname = device_information.get_hostname() self.username = device_information.get_username() self.password = device_information.get_password() self.expected = test_definition.get_expected_result() self.test_name = test_definition.get_test_id() self.result = None self.nr = InitNornir(inventory={ "plugin": "nornir.plugins.inventory.simple.SimpleInventory", "options": { "hosts": { "host1": { "platform": str(self.platform), "hostname": str(self.hostname), "username": str(self.username), "password": str(self.password), } } } }, logging={"enabled": False}) def run_test(self): return self.nr.run(task=netmiko_send_command, command_string="show arp") def evaluate_result(self) -> bool: return self.result == self.expected def print_result(self, result): print(self.expected) print_result(result) def get_result(self): return self.result def set_result(self, result): self.result = [] array = result["host1"][0].result.split() for i in range(8, len(array), 6): arp_dict = { "interface": array[i + 5], "mac": self.parse_mac(array[i + 3]), "ip": array[i + 1] } self.result.append(arp_dict) def get_expected_value(self): return self.expected def get_test_name(self): return self.test_name def parse_mac(self, param): return f"{param[0:2]}:{param[2:4]}:{param[5:7]}:{param[7:9]}:{param[10:12]}:{param[12:14]}".upper( ) def close_connection(self): self.nr.close_connections()