def backup_config(host, user, password, port): cisco_device = { 'device_type': 'cisco_ios', 'ip': host, 'username': str(user), 'password': str(password), 'port': port, 'secret': str(password), 'verbose': True, } try: net_connect = ConnectHandler(**cisco_device) output = net_connect.send_command("show configuration", delay_factor=2) net_connect.exit_enable_mode() filename = host + '--' + '{0:%Y-%m-%d-%H-%M-%S}'.format( datetime.datetime.now()) + '.txt' f = open(backup_dir + host + '/' + filename, 'w') f.write(output) f.close() except: net_connect = ConnectHandler(**cisco_device) net_connect.enable() output = net_connect.send_command("show running-config") net_connect.exit_enable_mode() filename = host + '--' + '{0:%Y-%m-%d-%H-%M-%S}'.format( datetime.datetime.now()) + '.txt' f = open(backup_dir + host + '/' + filename, 'w') f.write(output) f.close() f.write(output) f.close()
def detect_epc_tap_capabilities(host, user, password): #USE ONLY ON YOUR OWN DEVICES #this allows you to check for tapping capabillities cisco_device = { 'device_type': 'cisco_ios', 'ip': host, 'username': str(user), 'password': str(password), 'port': 22, # optional, defaults to 22 'secret': str(password), # optional, defaults to '' 'verbose': True, # optional, defaults to False } try: net_connect = ConnectHandler(**cisco_device) output = net_connect.send_config_set("do monitor capture buffer ?") if "% Incomplete command." in output: print(output) print( "Target:" + host + " is Vulnerable To EPC Tapping See Mimosa Framework for POC\n") net_connect.exit_enable_mode() net_connect.disconnect() return True except: return False
def execute(opts, net_cmd, net_config, device_commit, use_textfsm): """ This function setups up a netmiko connection and performs the different commands. The results are returned in a json document :param opts: :param net_cmd: :param net_config: :param device_commit: used with net_config cmds :param use_textfsm: used with net_cmd to specify the results should be formatted through TextFSM :return: json results such as: { 'status': 'success'|'failure', 'reason': xx, 'send_command': xx, 'send_result': xx, 'config_command': xx, 'config_result': xx } """ result = {} connection = None try: # if secret is specified, use enable_mode bEnable_mode = len(opts.get('secret', '')) > 0 connection = ConnectHandler(**opts) if bEnable_mode: connection.enable() # standard commands to execute if net_cmd: result['send_command'] = net_cmd send_result = connection.send_command(net_cmd, use_textfsm=use_textfsm) result['send_result'] = send_result # configuration commands to execute if net_config: result['config_command'] = net_config config_result = connection.send_config_set(net_config.split("\n")) result['config_result'] = config_result if device_commit: connection.commit() result['status'] = 'success' except Exception as err: result['status'] = 'failure' result['reason'] = str(err) finally: if connection: if bEnable_mode: connection.exit_enable_mode() connection.disconnect() return result
def get_info(device, username, password): dev_config = 'none' try: net_connect = ConnectHandler(device_type='cisco_ios', ip=device, username=username, password=password, secret=password) net_connect.enable() net_connect.send_command('terminal length 0') dev_config = net_connect.send_command('show run') net_connect.exit_enable_mode() net_connect.disconnect() return dev_config except: with open("error_devices.txt", '+a') as errlog: errlog.write("error connecting to " + device + "\n") return dev_config
def ssh_establisher(host, user, password): #USE ONLY ON YOUR OWN DEVICES #THIS ALLWOS YOU TO PATCH THE SMI VECTOR cisco_device = { 'device_type': 'cisco_ios', 'ip': host, 'username': str(user), 'password': str(password), 'port': 22, # optional, defaults to 22 'secret': str(password), # optional, defaults to '' 'verbose': True, # optional, defaults to False } try: net_connect = ConnectHandler(**cisco_device) #net_connect.find_prompt() output = net_connect.send_config_set("no vstack") if output: print(output) net_connect.exit_enable_mode() net_connect.disconnect() return output.split() except: pass
#Definindo Connect Handler router_connect=ConnectHandler(device_type=router['so'],ip=router['ip'],username=router['user'],password=router['pass'],secret=router['secret'],timeout=10) #Se o roteador eh ios, mudo para enable if router['so'] == 'cisco_ios' : router_connect.enable() #Envio o comando output=router_connect.send_command('sh version') #Crio o arquivo e armazeno o resultado arquivosaida=router['ip'] + '_show_version.txt' with open(arquivosaida,'w') as fh: fh.write(output) #Configurando os roteadores e imprime a saida da configuracao output=router_connect.send_config_set(router['configure']) print(output) #Saio do enable se o roteador eh ios if router['so'] == 'cisco_ios' : output=router_connect.send_command('wr') print(output) #Saio do modo enable router_connect.exit_enable_mode() else: # Se o roteador eh Juniper mando um commit output=router_connect.commit(and_quit=True) print(output) #Fecho a conexao router_connect.disconnect()
'password': '******', 'secret': 'enablesecret', } try: net_connect = ConnectHandler(**cisco_asa) except: print >> sys.stderr, "Unable to connec to ASA." sys.exit(1) net_connect.enable() backup_command = "backup location ftp:" result = net_connect.send_command_timing(backup_command) ftp_url = 'ftp://*****:*****@192.168.100.100/' + backup_filename if 'Press return to continue or enter a backup location' in result: result += net_connect.send_command_timing(ftp_url) net_connect.exit_enable_mode() net_connect.disconnect() file_path = ftp_location + backup_filename while not os.path.exists(file_path): time.sleep(10) if os.path.isfile(file_path): shutil.move(file_path, backup_location)
from getpass import getpass # load the json file as a dictionary. with open('vms.json') as f: data = json.load(f) # Get pod information for connecting. pod = input("Enter pod id: ") podinfo = data['vms'][f"pod" + pod.lower()] print(f"Connecting to pod {podinfo['id']} with the ip {podinfo['ip']}") username = input("Username: "******"Password: "******"Secret (Most likely the same as your password): ") # Make a connection handler with the information provided plus the json. virtualmachine = { 'device_type': 'linux', 'host': podinfo['ip'], 'username': username, 'password': password, 'port': 22, 'secret': secret } connection = ConnectHandler(**virtualmachine) # Use the information to connect, run command, and print it out. Then close connection. connection.enable() output = connection.send_command('dpkg --get-selections python3') print(output) connection.exit_enable_mode()
def main(): try: hostname = raw_input("Enter remote host to test: ") username = raw_input("Enter remote username: "******"Enter remote host to test: ") username = input("Enter remote username: "******"username": username, "use_keys": True, "ip": hostname, "device_type": "ovs_linux", "key_file": "/home/{}/.ssh/test_rsa".format(username), "verbose": False, } net_connect = ConnectHandler(**linux_test) print() print(net_connect.find_prompt()) # Test enable mode print() print("***** Testing enable mode *****") net_connect.enable() if net_connect.check_enable_mode(): print("Success: in enable mode") else: print("Fail...") print(net_connect.find_prompt()) net_connect.exit_enable_mode() print("Out of enable mode") print(net_connect.find_prompt()) # Test config mode print() print("***** Testing config mode *****") net_connect.config_mode() if net_connect.check_config_mode(): print("Success: in config mode") else: print("Fail...") print(net_connect.find_prompt()) net_connect.exit_config_mode() print("Out of config mode") print(net_connect.find_prompt()) # Test config mode (when already at root prompt) print() print("***** Testing config mode when already root *****") net_connect.enable() if net_connect.check_enable_mode(): print("Success: in enable mode") else: print("Fail...") print(net_connect.find_prompt()) print("Test config_mode while already at root prompt") net_connect.config_mode() if net_connect.check_config_mode(): print("Success: still at root prompt") else: print("Fail...") net_connect.exit_config_mode() # Should do nothing net_connect.exit_enable_mode() print("Out of config/enable mode") print(net_connect.find_prompt()) # Send config commands print() print("***** Testing send_config_set *****") print(net_connect.find_prompt()) output = net_connect.send_config_set(["ls -al"]) print(output) print()
def main(): try: hostname = raw_input("Enter remote host to test: ") username = raw_input("Enter remote username: "******"Enter remote host to test: ") username = input("Enter remote username: "******"***** Testing enable mode *****") net_connect.enable() if net_connect.check_enable_mode(): print("Success: in enable mode") else: print("Fail...") print(net_connect.find_prompt()) net_connect.exit_enable_mode() print("Out of enable mode") print(net_connect.find_prompt()) # Test config mode print() print("***** Testing config mode *****") net_connect.config_mode() if net_connect.check_config_mode(): print("Success: in config mode") else: print("Fail...") print(net_connect.find_prompt()) net_connect.exit_config_mode() print("Out of config mode") print(net_connect.find_prompt()) # Test config mode (when already at root prompt) print() print("***** Testing config mode when already root *****") net_connect.enable() if net_connect.check_enable_mode(): print("Success: in enable mode") else: print("Fail...") print(net_connect.find_prompt()) print("Test config_mode while already at root prompt") net_connect.config_mode() if net_connect.check_config_mode(): print("Success: still at root prompt") else: print("Fail...") net_connect.exit_config_mode() # Should do nothing net_connect.exit_enable_mode() print("Out of config/enable mode") print(net_connect.find_prompt()) # Send config commands print() print("***** Testing send_config_set *****") print(net_connect.find_prompt()) output = net_connect.send_config_set(['ls -al']) print(output) print()
# Import the connect handler module from netmiko import ConnectHandler # Create a dictionary representing the device. testrouter = { 'device_type': 'cisco_ios', 'ip': '134.86.133.30', 'username': '******', 'password': '******', 'secret': 'cisco', } # Connect to the device net_connect = ConnectHandler(**testrouter) # Elevate to enable mode net_connect.enable() # Import all configured routes into a variable output = net_connect.send_command('show run | include ip route') # Print the results for the variable "output" print output # exit enable mode net_connect.exit_enable_mode() # close the ssh session net_connect.disconnect() # end of the program # stored at /usr/bin/route_scrape
class NetworkDeviceIOS(NetworkDevice): #--------------------------------------------------------------------------- def __init__(self, name, ip, user='******', pw='cisco', secret=''): NetworkDevice.__init__(self, name, ip, user, pw) self.secret = secret self.device = { 'device_type': 'cisco_ios', 'ip': self.ip_address, 'username': self.username, 'password': self.password, 'secret': self.secret, 'port': 22, } self.session = None logger.info('devclass: created IOS device: %s %s', name, ip) #--------------------------------------------------------------------------- def connect(self): try: print('--- connecting IOS: telnet: ' + self.ip_address + ' for: ' + self.username) self.session = ConnectHandler(**self.device) logger.info('devclass: successful login at: %s for user: %s', self.ip_address, self.username) return self.session except Exception as err: logger.error('devclass: Erro no login at: %s for user: %s', self.ip_address, self.username) print('Ocorreu um Erro: ' + str(err)) raise Exception('Erro em devclass.connect') #--------------------------------------------------------------------------- def disconnect(self): if self.esta_connectado(): print('--- disconnecting IOS: telnet: ' + self.ip_address + ' for: ' + self.username) self.session.disconnect() logger.info('devclass: successful logoff at: %s for user: %s', self.ip_address, self.username) else: logger.warn('devclass: --- Erro ao desconectar.') print("Não há sessão para desconectar!") #--------------------------------------------------------------------------- def get_interfaces(self): if self.esta_connectado(): self.interfaces = self.session.send_command("show int status") logger.info( 'devclass: successful get_interfaces at: %s for user: %s', self.ip_address, self.username) return self.interfaces else: logger.error( 'devclass: Erro ao executar devclass.get_interfaces() - Sessão não estabelecida. at: %s for user: %s', self.ip_address, self.username) raise Exception( 'Erro ao executar devclass.get_interfaces() - Sessao nao estabelecida.' ) return "Erro " #--------------------------------------------------------------------------- def get_int_connected(self): if self.esta_connectado(): output = self.session.send_command("show int status | i cted") logger.info( 'devclass: successful get_int_connected at: %s for user: %s', self.ip_address, self.username) return output else: logger.error( 'devclass: Erro ao executar devclass.get_int_connected() - Sessão não estabelecida. at: %s for user: %s', self.ip_address, self.username) raise Exception( 'Erro ao executar devclass.get_int_connected() - Sessao nao estabelecida.' ) return "erro" #--------------------------------------------------------------------------- def do_wr(self): if self.esta_connectado(): output = self.session.send_command('write memory') logger.info('devclass: successful do_wr at: %s for user: %s', self.ip_address, self.username) return output else: logger.error( 'devclass: Erro ao executar devclass.do_wr() - Sessão não estabelecida. at: %s for user: %s', self.ip_address, self.username) raise Exception( 'Erro ao executar devclass.do_wr() - Sessao nao estabelecida.') #--------------------------------------------------------------------------- def config_mode(self): if self.esta_connectado(): output = self.session.config_mode() logger.info( 'devclass: successful config_mode() at: %s for user: %s', self.ip_address, self.username) return output else: logger.error( 'devclass: Erro ao executar devclass.config_mode() - Sessão não estabelecida. at: %s for user: %s', self.ip_address, self.username) raise Exception( 'Erro ao executar devclass.config_mode() - Sessao nao estabelecida.' ) #--------------------------------------------------------------------------- def exit_config_mode(self): if self.esta_connectado(): output = self.sessionc.exit_config_mode() logger.info( 'devclass: successful exit_config_mode() at: %s for user: %s', self.ip_address, self.username) return output else: logger.error( 'devclass: Erro ao executar devclass.exit_config_mode() - Sessão não estabelecida. at: %s for user: %s', self.ip_address, self.username) raise Exception( 'Erro ao executar devclass.exit_config_mode() - Sessao nao estabelecida.' ) #--------------------------------------------------------------------------- def check_config_mode(self): if self.esta_connectado(): output = self.session.check_config_mode() logger.info( 'devclass: successful check_config_mode() at: %s for user: %s', self.ip_address, self.username) return output else: logger.error( 'devclass: Erro ao executar devclass.check_config_mode() - Sessão não estabelecida. at: %s for user: %s', self.ip_address, self.username) raise Exception( 'Erro ao executar devclass.check_config_mode() - Sessao nao estabelecida.' ) #--------------------------------------------------------------------------- def enable(self): if self.esta_connectado(): output = self.session.enable() logger.info('devclass: successful enable() at: %s for user: %s', self.ip_address, self.username) return output else: logger.error( 'devclass: Erro ao executar devclass.enable() - Sessão não estabelecida. at: %s for user: %s', self.ip_address, self.username) raise Exception( 'Erro ao executar devclass.enable() - Sessao nao estabelecida.' ) #--------------------------------------------------------------------------- def exit_enable_mode(self): if self.esta_connectado(): output = self.session.exit_enable_mode() logger.info( 'devclass: successful exit_enable_mode() at: %s for user: %s', self.ip_address, self.username) return output else: logger.error( 'devclass: Erro ao executar devclass.exit_enable_mode() - Sessão não estabelecida. at: %s for user: %s', self.ip_address, self.username) raise Exception( 'Erro ao executar devclass.exit_enable_mode() - Sessao nao estabelecida.' ) #--------------------------------------------------------------------------- def find_prompt(self): if self.esta_connectado(): output = self.session.find_prompt() logger.info( 'devclass: successful find_prompt() at: %s for user: %s', self.ip_address, self.username) return output else: logger.error( 'devclass: Erro ao executar devclass.find_prompt() - Sessão não estabelecida. at: %s for user: %s', self.ip_address, self.username) raise Exception( 'Erro ao executar devclass.find_prompt() - Sessao nao estabelecida.' ) #--------------------------------------------------------------------------- def send_command(self, arguments): if self.esta_connectado(): output = self.session.send_command(arguments) logger.info( 'devclass: successful send_command() at: %s for user: %s', self.ip_address, self.username) return output else: logger.error( 'devclass: Erro ao executar devclass.send_command() - Sessão não estabelecida. at: %s for user: %s', self.ip_address, self.username) raise Exception( 'Erro ao executar devclass.send_command() - Sessao nao estabelecida.' ) #--------------------------------------------------------------------------- def send_config_set(self, arguments_list): if self.esta_connectado(): output = self.session.send_config_set(arguments_list) logger.info( 'devclass: successful send_config_set() at: %s for user: %s', self.ip_address, self.username) return output else: logger.error( 'devclass: Erro ao executar devclass.send_config_set() - Sessão não estabelecida. at: %s for user: %s', self.ip_address, self.username) raise Exception( 'Erro ao executar devclass.send_config_set() - Sessao nao estabelecida.' ) #--------------------------------------------------------------------------- def send_config_from_file(self, file): if self.esta_connectado(): output = self.session.send_config_from_file(file) logger.info( 'devclass: successful send_config_from_file() at: %s for user: %s', self.ip_address, self.username) return output else: logger.error( 'devclass: Erro ao executar devclass.send_config_from_file() - Sessão não estabelecida. at: %s for user: %s', self.ip_address, self.username) raise Exception( 'Erro ao executar devclass.send_config_from_file() - Sessao nao estabelecida.' ) #--------------------------------------------------------------------------- def esta_connectado(self): if self.session != None: return True else: return False #--------------------------------------------------------------------------- def debug_devclass(self): filename_log = self.ip_address + '_.log' logging.basicConfig(filename=filename_log, format='%(asctime)s - %(levelname)s - %(message)s', level=logging.DEBUG) debugClass = logging.getLogger("netmiko") #--------------------------------------------------------------------------- def get_hostname(self): if self.esta_connectado(): output = self.session.send_command("show conf | i hostname") logger.info( 'devclass: successful get_hostname at: %s for user: %s', self.ip_address, self.username) hostname = (output.split())[1] return hostname else: logger.error( 'devclass: Erro ao executar devclass.get_hostname() - Sessão não estabelecida. at: %s for user: %s', self.ip_address, self.username) raise Exception( 'Erro ao executar devclass.get_hostname() - Sessao nao estabelecida.' ) return "Erro " #--------------------------------------------------------------------------- def get_nbem(self): if self.esta_connectado(): output = self.session.send_command("show run | i chassis") logger.info('devclass: successful get_nbem at: %s for user: %s', self.ip_address, self.username) output = (output.split())[2] return output else: logger.error( 'devclass: Erro ao executar devclass.get_nbem() - Sessão não estabelecida. at: %s for user: %s', self.ip_address, self.username) raise Exception( 'Erro ao executar devclass.get_nbem() - Sessao nao estabelecida.' ) #--------------------------------------------------------------------------- def get_serial(self): if self.esta_connectado(): output = self.session.send_command( "show version | i System [s,S]erial") logger.info('devclass: successful get_serial at: %s for user: %s', self.ip_address, self.username) outputlines = output.splitlines() serial = [] for line in outputlines: serial.append((line.split(": "))[1]) return serial else: logger.error( 'devclass: Erro ao executar devclass.get_serial() - Sessão não estabelecida. at: %s for user: %s', self.ip_address, self.username) raise Exception( 'Erro ao executar devclass.get_serial() - Sessao nao estabelecida.' ) #--------------------------------------------------------------------------- #retorna o MAC pelo IP def busca_mac(self, end_ip): if self.esta_connectado(): output = self.session.send_command("show arp | i %s" % end_ip) logger.info('devclass: successful busca_mac at: %s for user: %s', self.ip_address, self.username) #output = (output.split())[2] return output else: logger.error( 'devclass: Erro ao executar devclass.busca_mac() - Sessão não estabelecida. at: %s for user: %s', self.ip_address, self.username) raise Exception( 'Erro ao executar devclass.busca_mac() - Sessao nao estabelecida.' ) #---------------------------------------------------------------------------
class NetCom: def __init__(self, hostname, user, devtype, command): self.hostname = hostname self.user = user self.devtype = devtype self.passwd = getpass() try: self.conn = ConnectHandler(device_type=self.devtype, host=self.hostname, username=self.user, password=self.passwd, secret=self.passwd, ssh_config_file="~/.ssh/config") except (EOFError, SSHException, ProxyCommandFailure, NetMikoTimeoutException, Exception): print('SSH is not enabled for this device ' + self.hostname + '\n') sys.exit() self.outdict = {} self.multi_commands = [] if command: self.command = command else: self.command = '' def __enter__(self): if self.command: self.netmiko_send_single() else: sys.exit('no commands entered') def __exit__(self, type, value, traceback): # make sure the ssh connection is closed. #print(self.outdict()) self.conn.disconnect() def netmiko_close_conn(self): self.conn.disconnect() def netmiko_findp(self): # Check connection is still valid if self.conn.find_prompt(): # print('#######SUCCESSFULL##########') return True else: # print('########FAILED##############') print('Connection failed to node: ' + host + '\n') return False def sanitise_input(self): # search the comm_list of any instances of bad commands i.e. conf t, set, delete etc returns bolean! sanitise_list = [ 'conf', 'set', 'delete', 'modify' ] # add to list for additional commands to be excluded for line in sanitise_list: for com in self.multi_commands: if line in com: return True return False def netmiko_send(self): # check connection is still valid print(self.conn) if self.netmiko_findp(): if self.sanitise_input: output = [] self.conn.enable() for item in self.multi_commands: print('***Executing command: ' + item + '\n') com_return = self.conn.send_command(item) output.append(com_return) print('***Success\n') self.outdict = dict(zip(com_list, output)) self.conn.exit_enable_mode() def netmiko_send_single(self): #sends a single command and prints if self.netmiko_findp(): print(self.conn.send_command(self.command))
class CumulusDriver(NetworkDriver): """Napalm driver for Cumulus.""" def __init__(self, hostname, username, password, timeout=60, optional_args=None): """Constructor.""" self.device = None self.hostname = hostname self.username = username self.password = password self.timeout = timeout self.loaded = False self.changed = False if optional_args is None: optional_args = {} # Netmiko possible arguments netmiko_argument_map = { "port": None, "verbose": False, "global_delay_factor": 1, "use_keys": False, "key_file": None, "ssh_strict": False, "system_host_keys": False, "alt_host_keys": False, "alt_key_file": "", "ssh_config_file": None, "secret": password, "allow_agent": False, } # Build dict of any optional Netmiko args self.netmiko_optional_args = { k: optional_args.get(k, v) for k, v in netmiko_argument_map.items() } self.port = optional_args.get("port", 22) self.sudo_pwd = optional_args.get("sudo_pwd", self.password) def open(self): try: self.device = ConnectHandler( device_type="linux", host=self.hostname, username=self.username, password=self.password, **self.netmiko_optional_args ) except NetMikoTimeoutException: raise ConnectionException("Cannot connect to {}".format(self.hostname)) def close(self): self.device.disconnect() def is_alive(self): """Returns a flag with the state of the SSH connection.""" null = chr(0) if self.device is None: return {'is_alive': False} try: # Try sending ASCII null byte to maintain the connection alive self.device.write_channel(null) return {'is_alive': self.device.remote_conn.transport.is_active()} except (socket.error, EOFError): # If unable to send, we can tell for sure that the connection is unusable return {'is_alive': False} return { 'is_alive': self.device.remote_conn.transport.is_active() } def load_merge_candidate(self, filename=None, config=None): if not filename and not config: raise MergeConfigException("filename or config param must be provided.") self.loaded = True if filename is not None: with open(filename, "r") as f: candidate = f.readlines() else: candidate = config if not isinstance(candidate, list): candidate = [candidate] candidate = [line for line in candidate if line] for command in candidate: output = self._send_command(command) if "error" in output or "not found" in output: raise MergeConfigException( "Command '{0}' cannot be applied.".format(command) ) def discard_config(self): if self.loaded: self._send_command("net abort") self.loaded = False def compare_config(self): if self.loaded: diff = self._send_command("net pending") return re.sub(r"\x1b\[\d+m", "", diff) return "" def commit_config(self, message=""): if self.loaded: self._send_command("net commit") self.changed = True self.loaded = False def rollback(self): if self.changed: self._send_command("net rollback last") self.changed = False def _send_command(self, command): if command.startswith("sudo"): self.device.enable() response = self.device.send_command(command) if command.startswith("sudo"): self.device.exit_enable_mode() return response def get_facts(self): facts = {} # Get "net show system" output. system = json.loads(self._send_command("net show system json")) facts = { "uptime": string_parsers.convert_uptime_string_seconds(system["uptime"]), "vendor": system["eeprom"]["tlv"]["Vendor Name"]["value"], "model": system["eeprom"]["tlv"]["Product Name"]["value"], "hostname": system["hostname"], "os_version": system["os-version"], "serial_number": system["eeprom"]["tlv"]["Serial Number"]["value"] } facts["fqdn"] = facts["hostname"] # Get "net show interface all json" output. interfaces = self._send_command("net show interface all json") # Handling bad send_command_timing return output. try: interfaces = json.loads(interfaces) except ValueError: interfaces = json.loads( self.device.send_command("net show interface all json") ) facts["interface_list"] = string_parsers.sorted_nicely(interfaces.keys()) return facts def get_arp_table(self, vrf=""): """ TODO replace with ip neighbor command since arp is being deprecated 'show arp' output example: Address HWtype HWaddress Flags Mask Iface 10.129.2.254 ether 00:50:56:97:af:b1 C eth0 192.168.1.134 (incomplete) eth1 192.168.1.1 ether 00:50:56:ba:26:7f C eth1 10.129.2.97 ether 00:50:56:9f:64:09 C eth0 192.168.1.3 ether 00:50:56:86:7b:06 C eth1 """ if vrf: raise NotImplementedError output = self._send_command("arp -n") output = output.split("\n") output = output[1:] arp_table = list() for line in output: line = line.split() if "incomplete" in line[1]: macaddr = "00:00:00:00:00:00" else: macaddr = line[2] arp_table.append( {"interface": line[-1], "mac": macaddr, "ip": line[0], "age": 0.0} ) return arp_table def get_ntp_stats(self): """ 'ntpq -np' output example remote refid st t when poll reach delay offset jitter ============================================================================== 116.91.118.97 133.243.238.244 2 u 51 64 377 5.436 987971. 1694.82 219.117.210.137 .GPS. 1 u 17 64 377 17.586 988068. 1652.00 133.130.120.204 133.243.238.164 2 u 46 64 377 7.717 987996. 1669.77 """ output = self._send_command("ntpq -np") output = output.split("\n")[2:] ntp_stats = list() for ntp_info in output: if len(ntp_info) > 0: remote, refid, st, t, when, hostpoll, reachability, delay, offset, jitter = ( ntp_info.split() ) # 'remote' contains '*' if the machine synchronized with NTP server synchronized = "*" in remote match = re.search(r"(\d+\.\d+\.\d+\.\d+)", remote) ip = match.group(1) when = when if when != "-" else 0 ntp_stats.append( { "remote": ip, "referenceid": refid, "synchronized": bool(synchronized), "stratum": int(st), "type": t, "when": when, "hostpoll": int(hostpoll), "reachability": int(reachability), "delay": float(delay), "offset": float(offset), "jitter": float(jitter), } ) return ntp_stats def ping( self, destination, source=C.PING_SOURCE, ttl=C.PING_TTL, timeout=C.PING_TIMEOUT, size=C.PING_SIZE, count=C.PING_COUNT, vrf=C.PING_VRF, ): deadline = timeout * count command = "ping %s " % destination command += "-t %d " % int(ttl) command += "-w %d " % int(deadline) command += "-s %d " % int(size) command += "-c %d " % int(count) if source != "": command += "interface %s " % source ping_result = dict() output_ping = self._send_command(command) if "Unknown host" in output_ping: err = "Unknown host" else: err = "" if err != "": ping_result["error"] = err else: # 'packet_info' example: # ['5', 'packets', 'transmitted,' '5', 'received,' '0%', 'packet', # 'loss,', 'time', '3997ms'] packet_info = output_ping.split("\n") if "transmitted" in packet_info[-2]: packet_info = packet_info[-2] else: packet_info = packet_info[-3] packet_info = [x.strip() for x in packet_info.split()] sent = int(packet_info[0]) received = int(packet_info[3]) lost = sent - received # 'rtt_info' example: # ["0.307/0.396/0.480/0.061"] rtt_info = output_ping.split("\n") if len(rtt_info[-1]) > 0: rtt_info = rtt_info[-1] else: rtt_info = rtt_info[-2] match = re.search(r"([\d\.]+)/([\d\.]+)/([\d\.]+)/([\d\.]+)", rtt_info) if match is not None: rtt_min = float(match.group(1)) rtt_avg = float(match.group(2)) rtt_max = float(match.group(3)) rtt_stddev = float(match.group(4)) else: rtt_min = None rtt_avg = None rtt_max = None rtt_stddev = None ping_responses = list() response_info = output_ping.split("\n") for res in response_info: match_res = re.search(r"from\s([\d\.]+).*time=([\d\.]+)", res) if match_res is not None: ping_responses.append( { "ip_address": match_res.group(1), "rtt": float(match_res.group(2)), } ) ping_result["success"] = dict() ping_result["success"] = { "probes_sent": sent, "packet_loss": lost, "rtt_min": rtt_min, "rtt_max": rtt_max, "rtt_avg": rtt_avg, "rtt_stddev": rtt_stddev, "results": ping_responses, } return ping_result def _get_interface_neighbors(self, neighbors_list): neighbors = [] for neighbor in neighbors_list: temp = {} temp["hostname"] = neighbor["adj_hostname"] temp["port"] = neighbor["adj_port"] neighbors.append(temp) return neighbors def get_lldp_neighbors(self): """Cumulus get_lldp_neighbors.""" lldp = {} command = "net show interface all json" try: intf_output = json.loads(self._send_command(command)) except ValueError: intf_output = json.loads(self.device.send_command(command)) for interface in intf_output: if intf_output[interface]["iface_obj"]["lldp"] is not None: lldp[interface] = self._get_interface_neighbors( intf_output[interface]["iface_obj"]["lldp"] ) return lldp def get_interfaces(self): def _convert_speed(speed): if speed.endswith("M") and speed.strip("M").isdigit(): return int(speed.strip("M")) elif speed.endswith("G") and speed.strip("G").isdigit(): return int(speed.strip("G")) * 1000 return -1 interfaces = {} # Get 'net show interface all json' output. output = self._send_command("net show interface all json") # Handling bad send_command_timing return output. try: output_json = json.loads(output) except ValueError: output_json = json.loads( self.device.send_command("net show interface all json") ) # Determine the current time on the system, to be used when determining the last flap date_format = "%Y/%m/%d %H:%M:%S" current_time = self._send_command("date '+{}'".format(date_format)) current_time = datetime.strptime(current_time.strip(), date_format) for interface, iface_data in output_json.items(): interfaces[interface] = { "description": iface_data["iface_obj"]["description"], "is_enabled": False if iface_data["linkstate"] == "ADMDN" else True, "is_up": True if iface_data["linkstate"] == "UP" else False, "mac_address": iface_data["iface_obj"]["mac"], "mtu": iface_data["iface_obj"]["mtu"], "speed": _convert_speed(iface_data["speed"]), } # Calculate last interface flap time. Dependent on router daemon # Send command to determine if router daemon is running. Not dependent on quagga or frr daemon_check = self._send_command("sudo vtysh -c 'show version'") if "Exiting: failed to connect to any daemons." in daemon_check: for interface in interfaces.keys(): interfaces[interface]["last_flapped"] = -1.0 return interfaces show_int_output = self._send_command("sudo vtysh -c 'show interface'") split_int_output = list( filter(None, re.split("(?!Interface Type)Interface", show_int_output)) ) for block in split_int_output: lines = block.splitlines() last_down = None last_up = None iface = None for l in lines: if "is up" in l or "is down" in l: iface = l.split()[0].lower() # Grab the last two elements and make them a string elif "Link ups: " in l: last_up = " ".join(l.split()[-2:]) elif "Link downs: " in l: last_down = " ".join(l.split()[-2:]) break # If we don't have the interface already move on if not interfaces.get(iface): continue # If we are unable to find either the up or the down message return -1 if not (last_down or last_up): interfaces[iface]["last_flapped"] = -1.0 # If both interfaces have never flapped return -1 elif all(["never" in i for i in [last_up, last_down]]): interfaces[iface]["last_flapped"] = -1.0 else: # Convert to datetime while not choking on the never last_down = ( datetime(1970, 1, 1) if "never" in last_down else datetime.strptime(last_down, "%Y/%m/%d %H:%M:%S.%f") ) last_up = ( datetime(1970, 1, 1) if "never" in last_up else datetime.strptime(last_up, "%Y/%m/%d %H:%M:%S.%f") ) # figure out which is the most recent most_recent = last_up if last_up > last_down else last_down last_flap = current_time - most_recent interfaces[iface]["last_flapped"] = float(last_flap.seconds) return interfaces def get_interfaces_ip(self): interfaces_ip = defaultdict(lambda: defaultdict(lambda: defaultdict())) # Get net show interface all json output. output = self._send_command("net show interface all json") # Handling bad send_command_timing return output. try: output_json = json.loads(output) except ValueError: output_json = json.loads( self.device.send_command("net show interface all json") ) for interface in output_json: if not output_json[interface]["iface_obj"]["ip_address"]["allentries"]: continue for ip_address in output_json[interface]["iface_obj"]["ip_address"][ "allentries" ]: ip_ver = ipaddress.ip_interface(ip_address).version ip_ver = "ipv{}".format(ip_ver) ip, prefix = ip_address.split("/") interfaces_ip[interface][ip_ver][ip] = {"prefix_length": int(prefix)} return interfaces_ip def get_config(self, retrieve="all", full=False, sanitized=False): # Initialise the configuration dictionary configuration = {"startup": "", "running": "", "candidate": ""} if retrieve in ("running", "all"): # Get net show configuration output. output = self._send_command("net show configuration") configuration["running"] = output if retrieve in ("candidate", "all"): # Get net pending output. output = self._send_command("net pending json") configuration["candidate"] = output return configuration def get_bgp_neighbors(self): vrf = "global" bgp_neighbors = {vrf: {}} bgp_neighbor = {} supported_afis = ["ipv4 unicast", "ipv6 unicast"] bgp_summary_output = self._send_command("net show bgp summary json") dev_bgp_summary = json.loads(bgp_summary_output) bgp_neighbors_output = self._send_command("net show bgp neighbor json") dev_bgp_neighbors = json.loads(bgp_neighbors_output) for afi in dev_bgp_summary: if not (afi.lower() in supported_afis) or not dev_bgp_summary[afi]: continue bgp_neighbors[vrf]["router_id"] = dev_bgp_summary[afi]["routerId"] bgp_neighbors[vrf].setdefault("peers", {}) for peer in dev_bgp_summary[afi]["peers"]: bgp_neighbor = {} bgp_neighbor["local_as"] = dev_bgp_neighbors[peer]["localAs"] bgp_neighbor["remote_as"] = dev_bgp_neighbors[peer]["remoteAs"] bgp_neighbor["remote_id"] = dev_bgp_neighbors[peer]["remoteRouterId"] uptime = dev_bgp_neighbors[peer].get("bgpTimerUpMsec", "") bgp_neighbor["description"] = dev_bgp_neighbors[peer].get("nbrDesc", "") if dev_bgp_neighbors[peer]["bgpState"] == "Established": is_up = True else: is_up = False uptime = -1 if dev_bgp_neighbors[peer].get("adminShutDown", False): is_enabled = False else: is_enabled = True bgp_neighbor["is_up"] = is_up bgp_neighbor["is_enabled"] = is_enabled bgp_neighbor["uptime"] = int(uptime / 1000) bgp_neighbor.setdefault("address_family", {}) for af, af_details in dev_bgp_neighbors[peer][ "addressFamilyInfo" ].items(): af = af.lower() if not (af in supported_afis): continue route_info = {} bgp_peer_advertised_routes = self._send_command( "net show bgp {} neighbor {} " "advertised-routes json".format(af, peer) ) dev_bgp_peer_advertised_routes = json.loads( bgp_peer_advertised_routes.replace("n\n", "") ) peer_advertised_routes = dev_bgp_peer_advertised_routes[ "totalPrefixCounter" ] if not is_enabled: dev_bgp_summary[af]["peers"][peer]["prefixReceivedCount"] = -1 peer_advertised_routes = -1 af_details["acceptedPrefixCounter"] = -1 route_info["received_prefixes"] = dev_bgp_summary[af]["peers"][ peer ]["prefixReceivedCount"] route_info["sent_prefixes"] = int(peer_advertised_routes) route_info["accepted_prefixes"] = af_details[ "acceptedPrefixCounter" ] bgp_neighbor["address_family"][af.split()[0]] = route_info bgp_neighbors[vrf]["peers"][peer] = bgp_neighbor return bgp_neighbors def get_snmp_information(self): snmp_config_output = self._send_command("net show configuration snmp-server") contact = system_name = location = "" snmp_information = {} snmp_values = {} community_list = [] snmp_values.setdefault("community", {}) for parse_snmp_value in snmp_config_output.splitlines(): if ( "readonly-community" in parse_snmp_value or "readonly-community-v6" in parse_snmp_value ): community_value = parse_snmp_value.strip().split()[1] acl = parse_snmp_value.lstrip().split()[3] if acl == "any": acl = "N/A" if community_value in community_list: """ Unlike other routers that use ACL for snmp access-control, Cumulus directly defines authorized hosts as part of SNMP config. E.g: snmp-server listening-address all readonly-community private_multi_host access 10.10.10.1 system-contact NOC system-location LAB system-name cumulus-rtr-1 This creates a problem as NAPALM snmp object shows access-list name as key of community string. To best present the authorized-host info in the SNMP object, we show comma separate string of them as key of SNMP community. """ acl = snmp_values["community"][community_value]["acl"] + "," + acl snmp_values["community"][community_value] = { "acl": acl, "mode": "ro", } else: community_list.append(community_value) snmp_values["community"][community_value] = { "acl": acl, "mode": "ro", } system_contact_parse = re.search( r".*system-contact.(\D.*)", parse_snmp_value.strip() ) if system_contact_parse: contact = system_contact_parse.groups()[0] system_location_parse = re.search( r".*system-location.(\D.*)", parse_snmp_value.strip() ) if system_location_parse: location = system_location_parse.groups()[0] system_name_parse = re.search( r".*system-name.(\D.*)", parse_snmp_value.strip() ) if system_name_parse: system_name = system_name_parse.groups()[0] snmp_information = snmp_values snmp_information["contact"] = contact snmp_information["chassis_id"] = system_name snmp_information["location"] = location return snmp_information def cli(self, commands): cli_output = {} if type(commands) is not list: raise TypeError('Please enter a valid list of commands!') for command in commands: output = self.device.send_command(command) cli_output[command] = output return cli_output def get_vlans(self): """Cumulus get_vlans.""" result = {} command = "net show bridge vlan json" try: output = json.loads(self._send_command(command)) except ValueError: output = json.loads(self.device.send_command(command)) for intf, data in output.items(): for elem in data: if "vlanEnd" in elem: start = elem["vlan"] end = elem["vlanEnd"] + 1 vlans = range(start, end) else: vlans = [elem["vlan"], ] for vlan in vlans: if vlan not in result: result[vlan] = { "name": f"vlan{vlan}", "interfaces": [intf, ] } else: result[vlan]["interfaces"].append(intf) return result def get_mac_address_table(self): result = [] command = "net show bridge macs json" try: output = json.loads(self._send_command(command)) except ValueError: output = json.loads(self.device.send_command(command)) for entry in output: static = False if "state" in entry: if entry["state"] == "static": static = True else: continue result.append({ "mac": entry["mac"], "interface": entry["dev"], "vlan": entry["vlan"], "static": static, "active": True, "moves": 0, "last_move": 0.0 }) return result
class NetmikoSSH(object): """Contains methods for managing and using SSH connections for Network Devices using Netmiko""" __MAX_RECV_BUF = 10 * 1024 * 1024 __existing_connections = {} def __init__(self): self._session = None self._node = None self._device = {} @staticmethod def _node_hash(node, port): """Get IP address and port hash from node dictionary. :param node: Node in topology. :param port: :type node: dict :return: IP address and port for the specified node. :rtype: int """ return hash(frozenset([node['mgmt_ip'], port])) @staticmethod def _get_device_type(node): device_os = node['os'] if str(device_os) in os_netmiko_map.keys(): return os_netmiko_map[str(device_os)] return None def net_connect(self, node): """Connect to node using Netmiko's inbuilt libraries. :param node: The node to disconnect from. :type node: dict """ self._node = node ssh_port = Topology.get_ssh_port_from_node(node) node_hash = NetmikoSSH._node_hash(node, ssh_port) if node_hash in NetmikoSSH.__existing_connections: self._session = NetmikoSSH.__existing_connections[node_hash] logger.debug('reusing ssh: {0}'.format(self._session)) else: start = time() self._device = { 'device_type': NetmikoSSH._get_device_type(node), 'ip': node['mgmt_ip'], 'username': node['username'], 'password': node['password'], 'port': ssh_port } self._session = ConnectHandler(**self._device) NetmikoSSH.__existing_connections[node_hash] = self._session logger.trace('connect took {} seconds'.format(time() - start)) logger.debug('new connection: {0}'.format(self._session)) logger.debug('Connections: {0}'.format( str(NetmikoSSH.__existing_connections))) def net_disconnect(self, node): """Close SSH connection to the node. :param node: The node to disconnect from. :type node: dict """ ssh_port = Topology.get_ssh_port_from_node(node) node_hash = NetmikoSSH._node_hash(node, ssh_port) if node_hash in NetmikoSSH.__existing_connections: logger.debug('Disconnecting peer: {}, {}'.format( node['name'], ssh_port)) ssh = NetmikoSSH.__existing_connections.pop(node_hash) self._session.disconnect() def _reconnect(self): """Close the SSH connection and open it again.""" node = self._node self.net_disconnect(node) self.net_connect(node) def config_mode(self): """Enter into config mode """ self.net_connect(self._node) self._session.config_mode() def check_config_mode(self): """ Check if session is currently in config mode""" self.net_connect(self._node) return self._session.check_config_mode() def exit_config_mode(self): """Exit config mode""" self.net_connect(self._node) self._session.exit_config_mode() def clear_buffer(self): """ Clear logging buffer """ self.net_connect(self._node) self._session.clear_buffer() def enable(self): """ Enter Enable Mode""" self.net_connect(self._node) self._session.enable() def exit_enable_mode(self): """ Exit enable mode """ self.net_connect(self._node) self._session.exit_enable_mode() def find_prompt(self): """Return the current router prompt""" self.net_connect(self._node) self._session.find_prompt() def send_command(self, cmd): """Send command down the SSH channel and return output back :param cmd :type cmd: str """ if cmd is None: raise TypeError('Command parameter is None') if len(cmd) == 0: raise ValueError('Empty command parameter') self.net_connect(self._node) return self._session.send_command(cmd) def send_config_set(self, config_cmds): """Send a set of configuration commands to remote device :param config_cmds :type config_cmds: str """ if config_cmds is None: raise TypeError('Config Cmds parameter is None') self.net_connect(self._node) print "Netmiko NODE !!!\n\n" print self._node return self._session.send_config_set(config_cmds) def send_config_from_file(self, cfg_file): """Send a set of configuration commands loaded from a file :param cfg_file :type cfg_file: file """ if not os.path.isfile(cfg_file): raise TypeError('Config file does not exist') self.net_connect(self._node) self._session.send_config_from_file(cfg_file)