def _handleThread(self): while not self._deviceQueue.empty(): try: results = [] device = self._deviceQueue.get_nowait() # print('Handling ' + device) device_type = self._detect(device) if device_type: net_connect = { 'device_type': device_type, 'host': device, 'username': self._username, 'password': self._password } if self._global_delay_factor: net_connect[ 'global_delay_factor'] = self._global_delay_factor connection = ConnectHandler(**net_connect) for command in self._commandList: output = connection.send_command(command) results.append((command, output)) connection.disconnect() self._outputQueue.put({ 'device': device, 'results': results, 'connected': True }) else: self._outputQueue.put({ 'device': device, 'results': None, 'connected': False }) except Exception as e: self._outputQueue.put({ 'device': device, 'results': None, 'connected': False }) finally: self._show_progress(self._outputQueue.qsize(), self._deviceCount)
class SSHDetect(object): """ The SSHDetect class tries to automatically guess the device type running on the SSH remote end. Be careful that the kwargs 'device_type' must be set to 'autodetect', otherwise it won't work at all. Parameters ---------- *args : list The same *args that you might provide to the netmiko.ssh_dispatcher.ConnectHandler. *kwargs : dict The same *kwargs that you might provide to the netmiko.ssh_dispatcher.ConnectHandler. Attributes ---------- connection : netmiko.terminal_server.TerminalServer A basic connection to the remote SSH end. potential_matches: dict Dict of (device_type, accuracy) that is populated through an interaction with the remote end. Methods ------- autodetect() Try to determine the device type. """ def __init__(self, *args, **kwargs): """ Constructor of the SSHDetect class """ if kwargs["device_type"] != "autodetect": raise ValueError("The connection device_type must be 'autodetect'") self.connection = ConnectHandler(*args, **kwargs) # Call the _test_channel_read() in base to clear initial data output = BaseConnection._test_channel_read(self.connection) self.initial_buffer = output self.potential_matches = {} self._results_cache = {} def autodetect(self): """ Try to guess the best 'device_type' based on patterns defined in SSH_MAPPER_BASE Returns ------- best_match : str or None The device type that is currently the best to use to interact with the device """ for device_type, autodetect_dict in SSH_MAPPER_BASE.items(): tmp_dict = autodetect_dict.copy() call_method = tmp_dict.pop("dispatch") autodetect_method = getattr(self, call_method) accuracy = autodetect_method(**tmp_dict) if accuracy: self.potential_matches[device_type] = accuracy if accuracy >= 99: # Stop the loop as we are sure of our match best_match = sorted(self.potential_matches.items(), key=lambda t: t[1], reverse=True) self.connection.disconnect() return best_match[0][0] if not self.potential_matches: self.connection.disconnect() return None best_match = sorted(self.potential_matches.items(), key=lambda t: t[1], reverse=True) self.connection.disconnect() return best_match[0][0] def _send_command(self, cmd=""): """ Handle reading/writing channel directly. It is also sanitizing the output received. Parameters ---------- cmd : str, optional The command to send to the remote device (default : "", just send a new line) Returns ------- output : str The output from the command sent """ self.connection.write_channel(cmd + "\n") time.sleep(1) output = self.connection._read_channel_timing() output = self.connection.strip_ansi_escape_codes(output) output = self.connection.strip_backspaces(output) return output def _send_command_wrapper(self, cmd): """ Send command to the remote device with a caching feature to avoid sending the same command twice based on the SSH_MAPPER_BASE dict cmd key. Parameters ---------- cmd : str The command to send to the remote device after checking cache. Returns ------- response : str The response from the remote device. """ cached_results = self._results_cache.get(cmd) if not cached_results: response = self._send_command(cmd) self._results_cache[cmd] = response return response else: return cached_results def _autodetect_std(self, cmd="", search_patterns=None, re_flags=re.I, priority=99): """ Standard method to try to auto-detect the device type. This method will be called for each device_type present in SSH_MAPPER_BASE dict ('dispatch' key). It will attempt to send a command and match some regular expression from the ouput for each entry in SSH_MAPPER_BASE ('cmd' and 'search_pattern' keys). Parameters ---------- cmd : str The command to send to the remote device after checking cache. search_patterns : list A list of regular expression to look for in the command's output (default: None). re_flags: re.flags, optional Any flags from the python re module to modify the regular expression (default: re.I). priority: int, optional The confidence the match is right between 0 and 99 (default: 99). """ invalid_responses = [ r'% Invalid input detected', r'syntax error, expecting', r'Error: Unrecognized command', r'%Error' ] if not cmd or not search_patterns: return 0 try: response = self._send_command_wrapper(cmd) # Look for error conditions in output for pattern in invalid_responses: match = re.search(pattern, response, flags=re.I) if match: return 0 for pattern in search_patterns: match = re.search(pattern, response, flags=re_flags) if match: return priority except Exception: return 0 return 0
class SSHDetect(object): """ The SSHDetect class tries to automatically guess the device type running on the SSH remote end. Be careful that the kwargs 'device_type' must be set to 'autodetect', otherwise it won't work at all. Parameters ---------- *args : list The same *args that you might provide to the netmiko.ssh_dispatcher.ConnectHandler. *kwargs : dict The same *kwargs that you might provide to the netmiko.ssh_dispatcher.ConnectHandler. Attributes ---------- connection : netmiko.terminal_server.TerminalServerSSH A basic connection to the remote SSH end. potential_matches: dict Dict of (device_type, accuracy) that is populated through an interaction with the remote end. Methods ------- autodetect() Try to determine the device type. """ def __init__(self, *args: Any, **kwargs: Any) -> None: """ Constructor of the SSHDetect class """ if kwargs["device_type"] != "autodetect": raise ValueError("The connection device_type must be 'autodetect'") # Always set cmd_verify to False for autodetect kwargs["global_cmd_verify"] = False self.connection = ConnectHandler(*args, **kwargs) # Call the _test_channel_read() in base to clear initial data output = BaseConnection._test_channel_read(self.connection) self.initial_buffer = output self.potential_matches: Dict[str, int] = {} self._results_cache: Dict[str, str] = {} def autodetect(self) -> Union[str, None]: """ Try to guess the best 'device_type' based on patterns defined in SSH_MAPPER_BASE Returns ------- best_match : str or None The device type that is currently the best to use to interact with the device """ for device_type, autodetect_dict in SSH_MAPPER_BASE: tmp_dict = autodetect_dict.copy() call_method = tmp_dict.pop("dispatch") assert isinstance(call_method, str) autodetect_method = getattr(self, call_method) accuracy = autodetect_method(**tmp_dict) if accuracy: self.potential_matches[device_type] = accuracy if accuracy >= 99: # Stop the loop as we are sure of our match best_match = sorted(self.potential_matches.items(), key=lambda t: t[1], reverse=True) # WLC needs two different auto-dectect solutions if "cisco_wlc_85" in best_match[0]: best_match[0] = ("cisco_wlc", 99) self.connection.disconnect() return best_match[0][0] if not self.potential_matches: self.connection.disconnect() return None best_match = sorted(self.potential_matches.items(), key=lambda t: t[1], reverse=True) self.connection.disconnect() return best_match[0][0] def _send_command(self, cmd: str = "") -> str: """ Handle reading/writing channel directly. It is also sanitizing the output received. Parameters ---------- cmd : str, optional The command to send to the remote device (default : "", just send a new line) Returns ------- output : str The output from the command sent """ self.connection.write_channel(cmd + "\n") time.sleep(1) output = self.connection.read_channel_timing() output = self.connection.strip_backspaces(output) return output def _send_command_wrapper(self, cmd: str) -> str: """ Send command to the remote device with a caching feature to avoid sending the same command twice based on the SSH_MAPPER_BASE dict cmd key. Parameters ---------- cmd : str The command to send to the remote device after checking cache. Returns ------- response : str The response from the remote device. """ cached_results = self._results_cache.get(cmd) if not cached_results: response = self._send_command(cmd) self._results_cache[cmd] = response return response else: return cached_results def _autodetect_remote_version(self, search_patterns: Optional[List[str]] = None, re_flags: int = re.IGNORECASE, priority: int = 99, **kwargs: Any) -> int: """ Method to try auto-detect the device type, by matching a regular expression on the reported remote version of the SSH server. Parameters ---------- search_patterns : list A list of regular expression to look for in the reported remote SSH version (default: None). re_flags: re.flags, optional Any flags from the python re module to modify the regular expression (default: re.I). priority: int, optional The confidence the match is right between 0 and 99 (default: 99). """ invalid_responses = [r"^$"] if not search_patterns: return 0 try: remote_conn = self.connection.remote_conn assert isinstance(remote_conn, paramiko.Channel) assert remote_conn.transport is not None remote_version = remote_conn.transport.remote_version for pattern in invalid_responses: match = re.search(pattern, remote_version, flags=re.I) if match: return 0 for pattern in search_patterns: match = re.search(pattern, remote_version, flags=re_flags) if match: return priority except Exception: return 0 return 0 def _autodetect_std( self, cmd: str = "", search_patterns: Optional[List[str]] = None, re_flags: int = re.IGNORECASE, priority: int = 99, ) -> int: """ Standard method to try to auto-detect the device type. This method will be called for each device_type present in SSH_MAPPER_BASE dict ('dispatch' key). It will attempt to send a command and match some regular expression from the ouput for each entry in SSH_MAPPER_BASE ('cmd' and 'search_pattern' keys). Parameters ---------- cmd : str The command to send to the remote device after checking cache. search_patterns : list A list of regular expression to look for in the command's output (default: None). re_flags: re.flags, optional Any flags from the python re module to modify the regular expression (default: re.I). priority: int, optional The confidence the match is right between 0 and 99 (default: 99). """ invalid_responses = [ r"% Invalid input detected", r"syntax error, expecting", r"Error: Unrecognized command", r"%Error", r"command not found", r"Syntax Error: unexpected argument", r"% Unrecognized command found at", ] if not cmd or not search_patterns: return 0 try: # _send_command_wrapper will use already cached results if available response = self._send_command_wrapper(cmd) # Look for error conditions in output for pattern in invalid_responses: match = re.search(pattern, response, flags=re.I) if match: return 0 for pattern in search_patterns: match = re.search(pattern, response, flags=re_flags) if match: return priority except Exception: return 0 return 0
from netmiko.ssh_autodetect import SSHDetect from netmiko.ssh_dispatcher import ConnectHandler remote_device = { 'device_type': 'f5_ltm', 'host': '172.31.200.211', 'username': '******', 'password': '******' } #guesser = SSHDetect(**remote_device) #best_match = guesser.autodetect() #print("device_type: " + best_match) #remote_device['device_type'] = best_match connection = ConnectHandler(**remote_device) file = open('/root/venv/egw-bigip/file/config.scf', 'w') string = connection.send_command('show running-config ltm data-group') file.write(string) connection.disconnect()
def find_mac_address(remote_device, mac_address, results_list): """Updates list of interfaces that have learnt the specified MAC address""" try: # Auto-detect device type & establish correct SSH connection best_match = guess_device_type(remote_device) if best_match is None: return else: remote_device["device_type"] = best_match device = ConnectHandler(**remote_device) except NetMikoAuthenticationException: print( f"Failed to execute CLI on {remote_device['host']} due to incorrect credentials." ) return except (NetMikoTimeoutException, SSHException): print( f"Failed to execute CLI on {remote_device['host']} due to timeout or SSH not enabled." ) return except ValueError: print( f"Unsupported platform {remote_device['host']}, {remote_device['device_type']}." ) return else: # IOS, IOS XE & NX-OS if (best_match == "cisco_ios" or best_match == "cisco_xe" or best_match == "cisco_nxos"): # Grab MAC address table & extract information cli_output = device.send_command( f"show mac address-table | include {mac_address}") if cli_output is None or len(cli_output) == 0: device.disconnect() return cli_output = cli_output.split("\n") # Iterate through results for cli_line in cli_output: cli_items = cli_line.split() # Skip empty result lines if not cli_items: continue cli_output2 = device.send_command( f"show interface {cli_items[-1]}") int_description = re.search(r"Description: (.+)", cli_output2) int_description = (int_description.group(1).rstrip() if int_description else "") if best_match == "cisco_nxos": results_list.append([ remote_device["host"], cli_items[-1], int_description, cli_items[1], ]) else: results_list.append([ remote_device["host"], cli_items[-1], int_description, cli_items[0], ]) device.disconnect() # JunOS elif best_match == "juniper" or best_match == "juniper_junos": # Switch MAC address format from aaaa.bbbb.cccc to aa:aa:bb:bb:cc:cc junos_mac_address = mac_address for digit in junos_mac_address: if digit in ".:-": junos_mac_address = junos_mac_address.replace(digit, "") junos_mac_address = ( f"{junos_mac_address[0:2]}:{junos_mac_address[2:4]}:{junos_mac_address[4:6]}" f":{junos_mac_address[6:8]}:{junos_mac_address[8:10]}:{junos_mac_address[10:12]}" ) # Grab MAC address table & extract information cli_output = device.send_command( f"show ethernet-switching table brief | match {junos_mac_address}" ) if cli_output is None or len(cli_output) <= 1: device.disconnect() return cli_output = cli_output.split("\n") # Iterate through results for cli_line in cli_output: # Skip empty result lines if cli_line is None or len(cli_line) <= 1: continue cli_items = cli_line.split() if not cli_items: continue int_name = re.search(r"(\w.+)\.\d+", cli_items[-1]) if int_name: int_name = int_name.group(1) cli_output2 = device.send_command( f"show interfaces {int_name}") int_description = re.search(r"Description: (.+)", cli_output2) int_description = (int_description.group(1).rstrip() if int_description else "") else: continue results_list.append([ remote_device["host"], cli_items[-1], int_description, cli_items[0], ]) device.disconnect() # Arista EOS elif best_match == "arista_eos": # Grab MAC address table & extract information cli_output = device.send_command( f"show mac address-table | include {mac_address}") if cli_output is None or len(cli_output) == 0: device.disconnect() return cli_output = cli_output.split("\n") # Iterate through results for cli_line in cli_output: cli_items = cli_line.split() # Skip empty result lines if not cli_items: continue cli_output2 = device.send_command( f"show interfaces {cli_items[3]}") int_description = re.search(r"Description: (.+)", cli_output2) int_description = (int_description.group(1).rstrip() if int_description else "") results_list.append([ remote_device["host"], cli_items[3], int_description, cli_items[0] ]) device.disconnect() # Unsupported, disconnect else: device.disconnect()
'ip': '10.108.16.104', 'username': '******', 'password': '******', # 'global_delay_factor':2 } print("Connecting %s" % jumpserver) net_connect = ConnectHandler(**jumpserver) print(net_connect.find_prompt()) filewrite = open("output1.txt", "a") file_obj = open("officeDevice.txt", "r") for line in file_obj: print("Connecting ***** %s" % line) net_connect.write_channel("mtrad " + line) time.sleep(1) net_connect.read_channel() redispatch(net_connect, device_type='cisco_ios_telnet') output = net_connect.send_command("show version | i IOS") output = net_connect.send_command("show mod | i 10GE") print(output) net_connect.send_command("exit", expect_string="mobboss2") filewrite.write("\n \n" + line + "\n") filewrite.write("-------------------------- \n") filewrite.write(output) net_connect.disconnect() filewrite.close()