def main(): inputfile, config_commands = get_cmd_line() print("Switch configuration updater. Please provide login information.\n") # Get username and password information. username = input("Username: "******"Password: "******"Enable Secret: ") print("{}{:<20}{:<40}{:<20}".format( "\n", "IP Address", "Name", "Results"), end="") for switchip in inputfile: ciscosw = { "device_type": "cisco_ios", "ip": switchip.strip(), "username": username.strip(), "password": password.strip(), "secret": enasecret.strip(), } print() print("{:<20}".format(switchip.strip()), end="", flush=True) try: # Connect to switch and enter enable mode. net_connect = ConnectHandler(**ciscosw) except Exception: print("** Failed to connect.", end="", flush=True) continue prompt = net_connect.find_prompt() # Print out the prompt/hostname of the device print("{:<40}".format(prompt), end="", flush=True) try: # Ensure we are in enable mode and can make changes. if "#" not in prompt[-1]: net_connect.enable() print("#", end="", flush=True) except Exception: print("Unable to enter enable mode.", end="", flush=True) continue else: for cmd in config_commands: # Make requested configuration changes. try: if cmd in ("w", "wr"): output = net_connect.save_config() print("w", end="", flush=True) else: output = net_connect.send_config_set(cmd) if "Invalid input" in output: # Unsupported command in this IOS version. print("Invalid input: ", cmd, end="", flush=True) print("*", end="", flush=True) except Exception: # Command failed! Stop processing further commands. print("!") break net_connect.disconnect()
if ssh_connect: print("\nSSH Connection Established Successfully to host:", connection["host"]) # Tell python to load all external files from the current directory env = Environment(loader=FileSystemLoader('.')) template = env.get_template("configure-interfaces-template.j2") interfaces = ["G1/0", "G1/1", "G1/2", "G1/3"] # Define which configuration you would like to use Jinja for for interface in interfaces: interface_dict = { "name": interface.strip(), "description": "Server Port", "vlan": "10", } # Combine between dictionary attributes with Jinja templates variables output = template.render(interface=interface_dict) # print(output) # Write result configuration to external file and take those configuration and send it back to the device with open('Host {}-config.txt'.format(connection['host']), "a") as f: f.write(output) ssh_connect.send_config_set(output, cmd_verify=False) ssh_connect.save_config() print("Finish sending configuration to", connection["host"]) print("-----------------------------------------------------\n")
def upgrade_device(net_device): start_time = datetime.now() print() print("Upgrading OS on device: {}".format(net_device['host'])) print("-" * 50) # Extract file and file system variables file_system = net_device.pop('file_system') source_file = net_device.pop('source_file') dest_file = net_device.pop('dest_file') # Establish SSH control channel print(".establishing SSH connection.") ssh_conn = ConnectHandler(**net_device) # SCP new image file print(".transferring image file.") enable_transfer = True if enable_transfer: transfer_dict = file_transfer(ssh_conn, source_file=source_file, dest_file=dest_file, file_system=file_system, direction='put', overwrite_file=False) else: transfer_dict = {} # Check the file exists and the MD5 matches the source file if not transfer_dict.get('file_exists') or not transfer_dict.get('file_verified'): raise ValueError("File doesn't exist or MD5 doesn't match on the remote system") print(".verifying new image file.") file_size = '42628912' verify_image(ssh_conn, file_system, dest_file, file_size) print() print(".checking current boot commands") boot_cmd = check_boot_var(ssh_conn) print(".constructing new boot commands") if boot_cmd: boot_commands = [ "no {}".format(boot_cmd), 'boot system flash {}'.format(dest_file), boot_cmd, ] else: boot_commands = [ 'boot system flash {}'.format(dest_file), ] print() print(">>>>>") print("Boot commands to send to the remote device:") print(boot_commands) print(">>>>>") print() hit_any_key() print() print(".sending new boot commands to remote device.") output = ssh_conn.send_config_set(boot_commands) print() print() print("Current boot variable: ") print(">>>>>") current_boot = ssh_conn.send_command("show run | inc boot") print(current_boot) print(">>>>>") print() # Reload the device print() try: response = raw_input("Do you want to reload the device(y/n): ") except NameError: response = input("Do you want to reload the device(y/n): ") if response.lower() != 'y': sys.exit("Boot commands staged, but device not reloaded!\n\n") else: print("Saving running-config to startup-config") ssh_conn.save_config() print("Reloading device with new image!") output = ssh_conn.send_command_timing("reload") print(output) if 'confirm' in output: output = ssh_conn.send_command_timing("y") end_time = datetime.now() print("File transfer time: {}".format(end_time - start_time))
def main(): # Collect input details ip_addr = input("Enter Device IP address: ") user = input("Enter login username: "******"Source file: ") md5 = input("md5: ") ftp = input("ftp server ip: ") ftp_user = input("ftp_username: "******"ftp_password: "******">>>> {}".format(start_time)) net_device = { "device_type": "cisco_ios", "ip": ip_addr, "username": user, "password": my_pass, "secret": my_pass, "port": 22, } # Initiate Netmiko Connection print("\nLogging in to Device...") try: ssh_conn = ConnectHandler(**net_device) except (AuthenticationException): print('Authentication failure: ' + ip_addr) sys.exit(1) except (NetMikoTimeoutException): print('Timeout to device: ' + ip_addr) sys.exit(1) except (EOFError): print("End of file while attempting device " + ip_addr) sys.exit(1) except (SSHException): print('SSH Issue. Are you sure SSH is enabled? ' + ip_addr) sys.exit(1) except Exception as unknown_error: print('Some other error: ' + str(unknown_error)) sys.exit(1) # Check current software version print("\nChecking the current software version...\n") current_version = ssh_conn.send_command("sh version | in System image") print(current_version) # Check whether software upgrade required or not if source_file in current_version: print("-" * 80) print("Device already running on latest version. No update required.") print("-" * 80) else: print("-" * 80) print( "Device not running on target software version. Starting Upgrade process." ) print("-" * 80) print("\nInitiate file transfer...") output = ssh_conn.send_command("dir | in {}".format(source_file)) # Check whether upgrade image already exists in filesystem if source_file in output: print("File already exists. No file transfer required.") else: # Identify file_system details flash or disk0 or bootflash dir_output = ssh_conn.send_command("dir | in Directory") dir_output = dir_output.strip().split() file_system = dir_output[2] file_system = file_system[:-1] print("Identifying file_system: {}".format(file_system)) # Initiate file transfer via FTP print("Copying file via FTP...") cmd = "copy ftp://{}:{}@{}/{} {}".format(ftp_user, ftp_pass, ftp, source_file, file_system) output = ssh_conn.send_command( cmd, expect_string=r'Destination filename') output += ssh_conn.send_command('\n', expect_string=r'#', delay_factor=2) print(output) # Verify file properly copied and MD5 hash print("\nCollecting flash details and Verifying MD5...") output = ssh_conn.send_command("dir | in {}".format(source_file)) print(output) hash_output = ssh_conn.send_command("verify /md5 {}{} {}".format( file_system, source_file, md5), delay_factor=2) if source_file in output and "Verified" in hash_output: print("\nFile successfully copied. MD5 hash verified...") # Change boot statement commands print("\nChanging boot statements...") output = ssh_conn.send_command("sh run | in boot system ") boot_cmd = [ 'no ' + output, 'boot system flash0:' + source_file, ] output = ssh_conn.send_config_set(boot_cmd) print(output) # Change boot statement properly configured print("\nVerifying boot statement...") output = ssh_conn.send_command("sh run | in boot system") print(output) # Save config ssh_conn.save_config() print("\nSaving config...") # Reload device and sleep for 7mins print("\nReloading Device...\n") request_reload = ssh_conn.send_command( "reload in 1\n", expect_string=r'Proceed with reload?') request_reload += ssh_conn.send_command('y\n', expect_string=r'#') print(request_reload) print("\nWaiting for device upgrade and reboot...\n") print("\n>>>> {}".format(datetime.now())) time.sleep(420) print("\n>>>> {}".format(datetime.now())) # Login into device again and verify current software version print("\nLogging in to Device...") ssh_conn = ConnectHandler(**net_device) print() print("\nVerifying Upgrade...") output = ssh_conn.send_command("sh version | in System image") print(output) # If device running on updated version, print message if source_file in output: print("-" * 80) print("Python sucessfully upgraded the software image.") print("-" * 80) else: print("Upgrade failed") print("\n>>>> Total time taken: {}".format(datetime.now() - start_time)) print()
device_type = 'cisco_ios' for device in devices: connection = ConnectHandler(ip=device, device_type=device_type, username=username, password=password) interfaces = connection.send_command('show interface switchport', use_textfsm=True) config_commands = ['vlan '+ vlan, 'name '+ vlanname] output = connection.send_config_set(config_commands) print (output) for interface in interfaces: if interface['admin_mode'] == 'static access' and interface['access_vlan'] == 'none': config_commands = 'interface ' + interface['interface'] ,'switchport voice vlan ' + vlan output = connection.send_config_set(config_commands) print (output) #the switch I have in the lab has a port channel and did not want to break it. #I just want to add the vlan to trunks that are port channels and not the physical interfrace elif interface['admin_mode'] == 'trunk' and not "trunk (member of bundle" in interface['mode']: config_commands = 'interface ' + interface['interface'],'switchport trunk allowed vlan add ' + vlan output1 = connection.send_config_set(config_commands) print (output1) #Saves the config print('\n Saving the Switch configuration\n') output = connection.save_config() print(output) #print(json.dumps(interfaces, indent=2))
class AIREOSDevice(BaseDevice): """Cisco AIREOS Device Implementation.""" vendor = "cisco" def __init__(self, host, username, password, secret="", port=22, **kwargs): super().__init__(host, username, password, device_type="cisco_aireos_ssh") self.native = None self.secret = secret self.port = int(port) self.global_delay_factor = kwargs.get("global_delay_factor", 1) self.delay_factor = kwargs.get("delay_factor", 1) self._connected = False self.open() def _ap_images_match_expected(self, image_option, image, ap_boot_options=None): """ Test that all AP images have the ``image_option`` matching ``image``. Args: image_option (str): The boot_option dict key ("primary", "backup") to validate. image (str): The image that the ``image_option`` should match. ap_boot_options (dict): The results from Returns: bool: True if all APs have ``image_option`` equal to ``image``, else False. Example: >>> device = AIREOSDevice(**connection_args) >>> device.ap_boot_options() { 'ap1': {'primary': {'8.10.105.0', 'secondary': '8.10.103.0'}, 'ap2': {'primary': {'8.10.105.0', 'secondary': '8.10.103.0'}, } >>> device._ap_images_match_expected("primary", "8.10.105.0") True >>> """ if ap_boot_options is None: ap_boot_options = self.ap_boot_options return all([ boot_option[image_option] == image for boot_option in ap_boot_options.values() ]) def _enter_config(self): """Enter into config mode.""" self.enable() self.native.config_mode() def _image_booted(self, image_name, **vendor_specifics): """ Check if ``image_name`` is the currently booted image. Args: image_name (str): The version to check if image is booted. Returns: bool: True if ``image_name`` is the current boot version, else False. Example: >>> device = AIREOSDevice(**connection_args) >>> device._image_booted("8.10.105.0") True >>> """ re_version = r"^Product\s+Version\s*\.+\s*(\S+)" sysinfo = self.show("show sysinfo") booted_image = re.search(re_version, sysinfo, re.M) if booted_image.group(1) == image_name: return True return False def _send_command(self, command, expect=False, expect_string=""): """ Send single command to device. Args: command (str): The command to send to the device. expect (bool): Whether to send a different expect string than normal prompt. expect_string (str): The expected prompt after running the command. Returns: str: The response from the device after issuing the ``command``. Raises: CommandError: When the returned data indicates the command failed. Example: >>> device = AIREOSDevice(**connection_args) >>> sysinfo = device._send_command("show sysinfo") >>> print(sysinfo) Product Version.....8.2.170.0 System Up Time......3 days 2 hrs 20 mins 30 sec ... >>> """ if expect: if expect_string: response = self.native.send_command_expect( command, expect_string=expect_string) else: response = self.native.send_command_expect(command) else: response = self.native.send_command_timing(command) if "Incorrect usage" in response or "Error:" in response: raise CommandError(command, response) return response def _uptime_components(self): """ Retrieve days, hours, and minutes device has been up. Returns: tuple: The days, hours, and minutes device has been up as integers. Example: >>> device = AIREOSDevice(**connection_args) >>> days, hours, minutes = device._uptime_components >>> print(days) 83 >>> """ sysinfo = self.show("show sysinfo") re_uptime = r"^System\s+Up\s+Time\.+\s*(.+?)\s*$" uptime = re.search(re_uptime, sysinfo, re.M) uptime_string = uptime.group() match_days = re.search(r"(\d+) days?", uptime_string) match_hours = re.search(r"(\d+) hrs?", uptime_string) match_minutes = re.search(r"(\d+) mins?", uptime_string) days = int(match_days.group(1)) if match_days else 0 hours = int(match_hours.group(1)) if match_hours else 0 minutes = int(match_minutes.group(1)) if match_minutes else 0 return days, hours, minutes def _wait_for_ap_image_download(self, timeout=3600): """ Wait for all APs have completed downloading the image. Args: timeout (int): The max time to wait for all APs to download the image. Raises: FileTransferError: When an AP is unable to properly retrieve the image or ``timeout`` is reached. Example: >>> device = AIREOSDevice(**connection_args) >>> device.ap_image_stats() { "count": 2, "downloaded": 0, "unsupported": 0, "failed": 0, } >>> device._wait_for_ap_image_download() >>> device.ap_image_stats() { "count": 2, "downloaded": 2, "unsupported": 0, "failed": 0, } >>> TODO: Change timeout to be a multiplier for number of APs attached to controller """ start = time.time() ap_image_stats = self.ap_image_stats ap_count = ap_image_stats["count"] downloaded = 0 while downloaded < ap_count: ap_image_stats = self.ap_image_stats downloaded = ap_image_stats["downloaded"] unsupported = ap_image_stats["unsupported"] failed = ap_image_stats["failed"] # TODO: When adding logging, send log message of current stats if unsupported or failed: raise FileTransferError("Failed transferring image to AP\n" f"Unsupported: {unsupported}\n" f"Failed: {failed}\n") elapsed_time = time.time() - start if elapsed_time > timeout: raise FileTransferError( "Failed waiting for AP image to be transferred to all devices:\n" f"Total: {ap_count}\nDownloaded: {downloaded}") def _wait_for_device_reboot(self, timeout=3600): """ Wait for the device to finish reboot process and become accessible. Args: timeout (int): The length of time before considering the device unreachable. Raises: RebootTimeoutError: When a connection to the device is not established within the ``timeout`` period. Example: >>> device = AIREOSDevice(**connection_args): >>> device.reboot() >>> device._wait_for_device_reboot() >>> device.connected() True >>> """ start = time.time() while time.time() - start < timeout: try: self.open() return except: # noqa E722 pass # TODO: Get proper hostname parameter raise RebootTimeoutError(hostname=self.host, wait_time=timeout) @property def ap_boot_options(self): """ Boot Options for all APs associated with the controller. Returns: dict: The name of each AP are the keys, and the values are the primary and backup values. Example: >>> device = AIREOSDevice(**connection_args) >>> device.ap_boot_options { 'ap1': { 'backup': '8.8.125.0', 'primary': '8.9.110.0', 'status': 'complete' }, 'ap2': { 'backup': '8.8.125.0', 'primary': '8.9.110.0', 'status': 'complete' }, } >>> """ ap_images = self.show("show ap image all") ap_boot_options = RE_AP_BOOT_OPTIONS.finditer(ap_images) boot_options_by_ap = { ap["name"]: { "primary": ap.group("primary"), "backup": ap.group("backup"), "status": ap.group("status").lower(), } for ap in ap_boot_options } return boot_options_by_ap @property def ap_image_stats(self): """ The stats of downloading the the image to all APs. Returns: dict: The AP count, and the downloaded, unsupported, and failed APs. Example: >>> device = AIREOSDevice(**connection_args) >>> device.ap_image_stats { 'count': 2, 'downloaded': 2, 'unsupported': 0, 'failed': 0 } >>> """ ap_images = self.show("show ap image all") count = RE_AP_IMAGE_COUNT.search(ap_images).group(1) downloaded = RE_AP_IMAGE_DOWNLOADED.search(ap_images).group(1) unsupported = RE_AP_IMAGE_UNSUPPORTED.search(ap_images).group(1) failed = RE_AP_IMAGE_FAILED.search(ap_images).group(1) return { "count": int(count), "downloaded": int(downloaded), "unsupported": int(unsupported), "failed": int(failed), } def backup_running_config(self, filename): raise NotImplementedError @property def boot_options(self): """ The images that are candidates for booting on reload. Returns: dict: The boot options on the device. The "sys" key is the expected image on reload. Example: >>> device = AIREOSDevice(**connection_args) >>> device.boot_options { 'backup': '8.8.125.0', 'primary': '8.9.110.0', 'sys': '8.9.110.0' } >>> """ show_boot_out = self.show("show boot") re_primary_path = r"^Primary\s+Boot\s+Image\s*\.+\s*(?P<primary>\S+)(?P<status>.*)$" re_backup_path = r"^Backup\s+Boot\s+Image\s*\.+\s*(?P<backup>\S+)(?P<status>.*)$" primary = re.search(re_primary_path, show_boot_out, re.M) backup = re.search(re_backup_path, show_boot_out, re.M) if primary: result = primary.groupdict() primary_status = result.pop("status") result.update(backup.groupdict()) backup_status = result.pop("status") if "default" in primary_status: result["sys"] = result["primary"] elif "default" in backup_status: result["sys"] = result["backup"] else: result["sys"] = None else: result = {"sys": None} return result def checkpoint(self, filename): raise NotImplementedError def close(self): """Close the SSH connection to the device.""" if self._connected: self.native.disconnect() self._connected = False def config(self, command): """ Configure the device with a single command. Args: command (str): The configuration command to send to the device. The command should not include the "config" keyword. Example: >>> device = AIREOSDevice(**connection_args) >>> device.config("boot primary") >>> Raises: CommandError: When the device's response indicates the command failed. """ self._enter_config() self._send_command(command) self.native.exit_config_mode() def config_list(self, commands): """ Send multiple configuration commands to the device. Args: commands (list): The list of commands to send to the device. The commands should not include the "config" keyword. Example: >>> device = AIREOSDevice(**connection_args) >>> device.config_list(["interface hostname virtual wlc1.site.com", "config interface vlan airway 20"]) >>> Raises: COmmandListError: When the device's response indicates an error from sending one of the commands. """ self._enter_config() entered_commands = [] for command in commands: entered_commands.append(command) try: self._send_command(command) except CommandError as e: self.native.exit_config_mode() raise CommandListError(entered_commands, command, e.cli_error_msg) self.native.exit_config_mode() @property def connected(self): """ The connection status of the device. Returns: bool: True if the device is connected, else False. """ return self._connected @connected.setter def connected(self, value): self._connected = value def enable(self): """ Ensure device is in enable mode. Returns: None: Device prompt is set to enable mode. """ # Netmiko reports enable and config mode as being enabled if not self.native.check_enable_mode(): self.native.enable() # Ensure device is not in config mode if self.native.check_config_mode(): self.native.exit_config_mode() @property def facts(self): raise NotImplementedError def file_copy( self, username, password, server, filepath, protocol="sftp", filetype="code", delay_factor=3, ): """ Copy a file from server to Controller. Args: username (str): The username to authenticate with the ``server``. password (str): The password to authenticate with the ``server``. server (str): The address of the file server. filepath (str): The full path to the file on the ``server``. protocol (str): The transfer protocol to use to transfer the file. filetype (str): The type of file per aireos definitions. delay_factor (int): The Netmiko delay factor to wait for device to complete transfer. Returns: bool: True when the file was transferred, False when the file is deemed to already be on the device. Raises: FileTransferError: When an error is detected in transferring the file. Example: >>> device = AIREOSDevice(**connection_args) >>> device.boot_options { 'backup': '8.8.125.0', 'primary': '8.9.100.0', 'sys': '8.9.100.0' } >>> device.file_copy("user", "password", "10.1.1.1", "/images/aireos/AIR-CT5500-K9-8-10-105-0.aes") >>> device.boot_options { 'backup': '8.9.100.0', 'primary': '8.10.105.0', 'sys': '8.10.105.0' } >>> """ self.enable() filedir, filename = os.path.split(filepath) if filetype == "code": version = convert_filename_to_version(filename) if version in self.boot_options.values(): return False try: self.show_list([ f"transfer download datatype {filetype}", f"transfer download mode {protocol}", f"transfer download username {username}", f"transfer download password {password}", f"transfer download serverip {server}", f"transfer download path {filedir}/", f"transfer download filename {filename}", ]) response = self.native.send_command_timing( "transfer download start") if "Are you sure you want to start? (y/N)" in response: response = self.native.send_command( "y", expect_string="File transfer is successful.", delay_factor=delay_factor) except: # noqa E722 raise FileTransferError return True def file_copy_remote_exists(self, src, dest=None, **kwargs): raise NotImplementedError def install_os(self, image_name, controller="both", save_config=True, **vendor_specifics): """ Install an operating system on the controller. Args: image_name (str): The version to install on the device. controller (str): The controller(s) to reboot for install (only applies to HA device). save_config (bool): Whether the config should be saved to the device before reboot. Returns: bool: True when the install is successful, False when the version is deemed to already be running. Raises: OSInstallError: When the device is not booted with the specified image after reload. RebootTimeoutError: When the device is unreachable longer than the reboot timeout value. Example: >>> device = AIREOSDevice(**connection_args) >>> device.boot_options { 'backup': '8.8.125.0', 'primary': '8.9.100.0', 'sys': '8.9.100.0' } >>> device.file_copy("user", "password", "10.1.1.1", "/images/aireos/AIR-CT5500-K9-8-10-105-0.aes") >>> device.boot_options { 'backup': '8.9.100.0', 'primary': '8.10.105.0', 'sys': '8.10.105.0' } >>> device.install_os("8.10.105.0") >>> """ timeout = vendor_specifics.get("timeout", 3600) if not self._image_booted(image_name): peer_redundancy = self.peer_redundancy_state self.set_boot_options(image_name, **vendor_specifics) self.reboot(confirm=True, controller=controller, save_config=save_config) self._wait_for_device_reboot(timeout=timeout) if not self._image_booted(image_name): raise OSInstallError(hostname=self.host, desired_boot=image_name) if not self.peer_redundancy_state == peer_redundancy: raise OSInstallError(hostname=f"{self.host}-standby", desired_boot=image_name) return True return False def open(self): """ Open a connection to the controller. This method will close the connection if it is determined that it is the standby controller. """ if self.connected: try: self.native.find_prompt() except: # noqa E722 self.connected = False if not self.connected: self.native = ConnectHandler( device_type="cisco_wlc", ip=self.host, username=self.username, password=self.password, port=self.port, global_delay_factor=self.global_delay_factor, secret=self.secret, verbose=False, ) self.connected = True # This prevents open sessions from connecting to STANDBY WLC if not self.redundancy_state: self.close() @property def peer_redundancy_state(self): """ Determine the state of the peer device. Returns: str: The Peer State from the local device's perspective. Example: >>> device = AIREOSDevice(**connection_args) >>> device.peer_redundancy_state 'standby hot' >>> """ ha = self.show("show redundancy summary") ha_peer_state = re.search(r"^\s*Peer\s+State\s*=\s*(.+?)\s*$", ha, re.M) return ha_peer_state.group(1).lower() def reboot(self, timer=0, confirm=False, controller="self", save_config=True): """ Reload the controller or controller pair. Args: timer (int): The time to wait before reloading. confirm (bool): Whether to reboot the device or not. controller (str): Which controller(s) to reboot (only applies to HA pairs). save_config (bool): Whether the configuraion should be saved before reload. Raises: ReloadTimeoutError: When the device is still unreachable after the timeout period. Example: >>> device = AIREOSDevice(**connection_args) >>> device.reboot(confirm=True) >>> """ if confirm: def handler(signum, frame): raise RebootSignal("Interrupting after reload") signal.signal(signal.SIGALRM, handler) if self.redundancy_mode != "sso disabled": reboot_command = f"reset system {controller}" else: reboot_command = "reset system" if timer: reboot_command += f" in {timer}" if save_config: self.save() signal.alarm(20) try: response = self.native.send_command_timing(reboot_command) if "save" in response: if not save_config: response = self.native.send_command_timing("n") else: response = self.native.send_command_timing("y") if "reset" in response: self.native.send_command_timing("y") except RebootSignal: signal.alarm(0) signal.alarm(0) else: print("Need to confirm reboot with confirm=True") @property def redundancy_mode(self): """ The oprating redundancy mode of the controller. Returns: str: The redundancy mode the device is operating in. Example: >>> device = AIREOSDevice(**connection_args) >>> device.redundancy_mode 'sso enabled' >>> """ ha = self.show("show redundancy summary") ha_mode = re.search(r"^\s*Redundancy\s+Mode\s*=\s*(.+?)\s*$", ha, re.M) return ha_mode.group(1).lower() @property def redundancy_state(self): """ Determine if device is currently the active device. Returns: bool: True if the device is active, False if the device is standby. Example: >>> device = AIREOSDevice(**connection_args) >>> device.redundancy_state True >>> """ ha = self.show("show redundancy summary") ha_state = re.search(r"^\s*Local\s+State\s*=\s*(.+?)\s*$", ha, re.M) if ha_state.group(1).lower() == "active": return True else: return False def rollback(self): raise NotImplementedError @property def running_config(self): raise NotImplementedError def save(self): """ Save the configuration on the device. Returns: bool: True if the save command did not fail. Example: >>> device = AIREOSDevice(**connection_args) >>> device.save() >>> """ self.native.save_config() return True def set_boot_options(self, image_name, **vendor_specifics): """ Set the version to boot on the device. Args: image_name (str): The version to boot into on next reload. Raises: NTCFileNotFoundError: When the version is not listed in ``boot_options``. Example: >>> device = AIREOSDevice(**connection_args) >>> device.boot_options { 'backup': '8.8.125.0', 'primary': '8.9.100.0', 'sys': '8.9.100.0' } >>> device.set_boot_options("8.8.125.0") >>> device.boot_options { 'backup': '8.8.125.0', 'primary': '8.9.100.0', 'sys': '8.8.125.0' } """ if self.boot_options["primary"] == image_name: boot_command = "boot primary" elif self.boot_options["backup"] == image_name: boot_command = "boot backup" else: raise NTCFileNotFoundError(image_name, "'show boot'", self.host) self.config(boot_command) self.save() if not self.boot_options["sys"] == image_name: raise CommandError( command=boot_command, message="Setting boot command did not yield expected results", ) def show(self, command, expect=False, expect_string=""): """ Send an operational command to the device. Args: command (str): The command to send to the device. expect (bool): Whether to send a different expect string than normal prompt. expect_string (str): The expected prompt after running the command. Returns: str: The data returned from the device Raises: CommandError: When the returned data indicates the command failed. Example: >>> device = AIREOSDevice(**connection_args) >>> sysinfo = device._send_command("show sysinfo") >>> print(sysinfo) Product Version.....8.2.170.0 System Up Time......3 days 2 hrs 20 mins 30 sec ... >>> """ self.enable() return self._send_command(command, expect=expect, expect_string=expect_string) def show_list(self, commands): """ Send an operational command to the device. Args: commands (list): The list of commands to send to the device. expect (bool): Whether to send a different expect string than normal prompt. expect_string (str): The expected prompt after running the command. Returns: list: The data returned from the device for all commands. Raises: CommandListError: When the returned data indicates one of the commands failed. Example: >>> device = AIREOSDevice(**connection_args) >>> command_data = device._send_command(["show sysinfo", "show boot"]) >>> print(command_data[0]) Product Version.....8.2.170.0 System Up Time......3 days 2 hrs 20 mins 30 sec ... >>> print(command_data[1]) Primary Boot Image............................... 8.2.170.0 (default) (active) Backup Boot Image................................ 8.5.110.0 >>> """ self.enable() responses = [] entered_commands = [] for command in commands: entered_commands.append(command) try: responses.append(self._send_command(command)) except CommandError as e: raise CommandListError(entered_commands, command, e.cli_error_msg) return responses @property def startup_config(self): raise NotImplementedError def transfer_image_to_ap(self, image, timeout=None): """ Transfer ``image`` file to all APs connected to the WLC. Args: image (str): The image that should be sent to the APs. timeout (int): The max time to wait for all APs to download the image. Returns: bool: True if AP images are transferred or swapped, False otherwise. Example: >>> device = AIREOSDevice(**connection_args) >>> device.ap_boot_options { 'ap1': { 'backup': '8.8.125.0', 'primary': '8.9.110.0', 'status': 'complete' }, 'ap2': { 'backup': '8.8.125.0', 'primary': '8.9.110.0', 'status': 'complete' }, } >>> device.transfer_image_to_ap("8.10.1.0") >>> device.ap_boot_options { 'ap1': { 'backup': '8.9.110.0', 'primary': '8.10.1.0', 'status': 'complete' }, 'ap2': { 'backup': '8.9.110.0', 'primary': '8.10.1.0', 'status': 'complete' }, } >>> """ boot_options = ["primary", "backup"] ap_boot_options = self.ap_boot_options changed = False if self._ap_images_match_expected("primary", image, ap_boot_options): return changed if not any( self._ap_images_match_expected(option, image, ap_boot_options) for option in boot_options): changed = True download_image = None for option in boot_options: if self.boot_options[option] == image: download_image = option break if download_image is None: raise FileTransferError( f"Unable to find {image} on {self.host}") self.config(f"ap image predownload {option} all") self._wait_for_ap_image_download() if self._ap_images_match_expected("backup", image): changed = True self.config("ap image swap all") # testing showed delay in reflecting changes when issuing `show ap image all` time.sleep(1) if not self._ap_images_match_expected("primary", image): raise FileTransferError(f"Unable to set all APs to use {image}") return changed @property def uptime(self): """ The uptime of the device in seconds. Returns: int: The number of seconds the device has been up. Example: >>> device = AIREOSDevice(**connection_args) >>> device.uptime 109303 >>> """ days, hours, minutes = self._uptime_components() hours += days * 24 minutes += hours * 60 seconds = minutes * 60 return seconds @property def uptime_string(self): """ The uptime of the device as a string. The format is dd::hh::mm Returns: str: The uptime of the device. Example: >>> device = AIREOSDevice(**connection_args) >>> device.uptime_string 22:04:39 >>> """ days, hours, minutes = self._uptime_components() return "%02d:%02d:%02d:00" % (days, hours, minutes)
# pip install netmiko from netmiko import ConnectHandler from my_devices_2 import device_list as devices with open('config_file') as f: config_list = f.read().splitlines() for a_device in devices: session = ConnectHandler(**a_device) output = session.send_config_set(config_list) output += session.save_config() print(output)
"username": "******", "password": "******", "device_type": "cisco_nxos", } nxos2 = { "host": "nxos2.lasthop.io", "username": "******", "password": "******", "device_type": "cisco_nxos", } nxos1_connect = ConnectHandler(**nxos1) nxos2_connect = ConnectHandler(**nxos2) week2_exercise5_txt = [] with open('week2_exercise5.txt') as txt: week2_exercise5_txt = txt.readlines() # print(week2_exercise5_txt) nxos1_output_1 = (nxos1_connect.send_config_from_file( config_file='week2_exercise5.txt')) nxos1_output_2 = (nxos1_connect.save_config()) print(nxos1_output_1, nxos1_output_2) nxos1_output_3 = (nxos1_connect.send_command('show vlan brief')) print(nxos1_output_3)
from netmiko import ConnectHandler import os ciscoasa = { 'device_type': 'cisco_asa', 'ip': '192.168.1.76', 'username': '******', 'password': os.getenv('ciscopass'), } conn = ConnectHandler(**ciscoasa) config_commands = ['pager 0', 'logging permit-hostdown'] output = conn.send_config_set(config_commands) wr = conn.save_config() conn.disconnect() print(output) print(wr)
class CiscoIOSDevice: def __init__(self, ip, connection_parameters): self.ip = ip self.connection_parameters = connection_parameters self.connection_parameters.ip = self.ip self.hostname = None self.registered = False self.dlc = False self.__session = None self.dlc_supported = False def connect(self): try: self.__session = ConnectHandler( **self.connection_parameters.__dict__) self.__session.enable() if not self.hostname: self.hostname = self.__session.find_prompt().replace('#', '') logging.info( f'{self.hostname} :: {self.ip} :: Connected :: {datetime.now()}' ) return self.__session except Exception as e: logging.error(f'{self.ip} :: {e} :: {datetime.now()}') def disconnect(self): self.__session.disconnect() logging.info( f'{self.hostname} :: {self.ip} :: Disconnected :: {datetime.now()}' ) self.__session = None def show_run(self): return self.__session.send_command('show run').splitlines() def check_status(self): show_license = self.__session.send_command('show license status') status = [] for line in show_license.splitlines(): if 'Status:' in line: status.append(line.strip()[8:]) status.pop(0) registration_status = status[0] if registration_status == 'REGISTERED': logging.info( f'{self.hostname} :: {self.ip} :: Device is registered :: {datetime.now()}' ) self.registered = True if len(status) == 3: self.dlc_supported = True dlc_status = status[2] if dlc_status != 'Not started': logging.info( f'{self.hostname} :: {self.ip} :: DLC started :: {datetime.now()}' ) self.dlc = True def register(self, token): pre_check = self.show_run() self.__session.send_config_from_file( config_file='smart_license_config.txt') logging.info( f'{self.hostname} :: {self.ip} :: Configuration for Smart License is done :: {datetime.now()}' ) post_check = self.show_run() with open(f'{self.hostname}.html', 'w') as diff_file: diff = difflib.HtmlDiff() diff_file.write(diff.make_file(pre_check, post_check)) self.__session.save_config() logging.info( f'{self.hostname} :: {self.ip} :: Configuration is saved :: {datetime.now()}' ) self.__session.send_command(f'license smart register idtoken {token}') logging.info( f'{self.hostname} :: {self.ip} :: Smart License registration has started :: {datetime.now()}' ) def wait_for_registration(self, seconds): for i in range(int(seconds) + 1): time.sleep(1) if i % 10 == 0: self.check_status() if self.registered: logging.info( f'{self.hostname} :: {self.ip} :: Devices has been registered :: {datetime.now()}' ) break if not self.registered: for line in self.__session.send_command( 'show license status').splitlines(): if line.strip().startswith('Failure reason:'): registration_error = line.strip()[16:] logging.warning( f'{self.hostname} :: {self.ip} :: {registration_error} :: {datetime.now()}' ) def run_dlc(self): self.__session.send_command('license smart conversion start') logging.info( f'{self.hostname} :: {self.ip} :: DLC Started :: {datetime.now()}') def ping(self): ping_result = self.__session.send_command('ping IP') return True if '64 bytes' in ping_result else False
connect = ConnectHandler(**device_information) connect.enable() # Creating a list of all Vlan's vlan_names = [ 'Management', 'Staff', 'Guest', 'HR-Office', 'Administation', 'Finance' ] a = 10 while a <= 60: for i in vlan_names: print(" *** Creating Vlan " + str(a) + " *** ") vlan_num = ['Vlan ' + str(a), 'name ' + str(i)] a += 10 send_conf = connect.send_config_set(vlan_num, cmd_verify=False) if vlan_names == 'Finance': break print(send_conf) print("\n ##### Saving the configuration ##### ") save = connect.save_config() print(save) print("#" * 80, "\n *** show vlan brief *** ") sh_vlan = connect.send_command('show vlan brief') print(sh_vlan) print("\n * * * Closing connection * * * ") connect.disconnect()
def connect_to_device(remote_device, interface, ip_name): if remote_device['device_type'] == 'arista_eos': netconnect = ConnectHandler(**remote_device) cname = netconnect.find_prompt() device_name = cname.replace('>', ' ') print('') cprint('Connected to {}'.format(device_name), 'yellow', 'on_red') cprint('...Performing PRE-CHECK...', 'yellow', 'on_red') print('') shint = netconnect.send_command( 'show interface {} | in ip|Desc|Et'.format(interface)) rprint(shint) netconnect.enable() # print(netconnect.find_prompt()) time.sleep(5) print( colored('Checking interface description if port is a TAP', 'white', 'on_red', attrs=['reverse', 'blink'])) print('') x = [] intf_conf = netconnect.send_command( 'show run int {} | in desc'.format(interface)) x = intf_conf.strip() result = x.find('TAP') if result != -1: print( colored('PORT IS A TAP', 'white', 'on_red', attrs=['reverse', 'blink'])) else: print( colored('PORT IS NOT A TAP', 'white', 'on_red', attrs=['reverse', 'blink'])) rprint('[red]...Disconnecting[red]') netconnect.disconnect() # matching = [s for s in tap if "TAP" in s] # print(matching) print('') shrun = netconnect.send_command( 'show run interface {}'.format(interface)) rprint(shrun) print('') print( colored('##########################################', 'white', 'on_red', attrs=['reverse', 'blink'])) print('ARE YOU SURE YOU WANT TO BOUNCE THIS PORT?') print( colored('##########################################', 'white', 'on_red', attrs=['reverse', 'blink'])) rprint('') user_input = input('ENTER [Y]es or [N]o: ') select = user_input.lower().strip() if select == 'y' and select: commands = [ 'int {}'.format(interface), 'shutdown', 'do show run diff', 'no shut', 'do show run int {}'.format(interface), 'do show run diff' ] print('') output = netconnect.send_config_set(commands) output += netconnect.save_config() rprint(output) print('') time.sleep(10) netconnect.disconnect() rprint('[red]..Disconnecting to {} [red]'.format(device_name)) elif select == 'n' and select: print('..Try again..') netconnect.disconnect() else: rprint('.Try Again..') else: print( colored('This script is only for Arista AGG device', 'white', 'on_red', attrs=['reverse', 'blink']))
from netmiko import ConnectHandler from getpass import getpass password = getpass(prompt="Bitte Passwort eingeben : ") cisco_nxos1 = {"host": "nxos1.lasthop.io", "username": "******", "password": password, "device_type": "cisco_nxos", "session_log": "my_session1.txt"} cisco_nxos2 = {"host": "nxos2.lasthop.io", "username": "******", "password": password, "device_type": "cisco_nxos", "session_log": "my_session2.txt"} device_list = [cisco_nxos1, cisco_nxos2] for device in device_list: nxos_connect = ConnectHandler(**device) print(nxos_connect.find_prompt()) output = nxos_connect.send_config_from_file("vlan.txt") output += nxos_connect.save_config() #print(output) nxos_connect.disconnect()
'password': '******', 'secret': 'cisco' } try: ssh_connection = ConnectHandler(**ios_l2_accesslayer1) print("connection success\n") ssh_connection.enable() print(ssh_connection.find_prompt()) ports = ["gig 0/0", "gig 0/1 ", "gig1/0"] for com in ports: commands = ['int' + " " + str(com), 'switchport trunk encapsulation dot1q', 'switchport mode trunk', 'exit'] out = ssh_connection.send_config_set(commands) time.sleep(5) ssh_connection.save_config(self, 'write mem', False, '') print(out) except: print("login failure\n") sys.exit() try: ssh_connection = ConnectHandler(**ios_l2_distlayer1) print("connection success\n") ssh_connection.enable() print(ssh_connection.find_prompt()) ports = ["gig 0/0", "gig 0/1 ", "gig 0/2", "gig 2/1", "gig 2/0", "gig 1/0", "gig 1/1"]
def configuration(): start_time = datetime.now() #Ouverture du fichier de configuration et du fichier contenant les IP des commutateurs. with open('CONFIGURATION_L2') as f: lines_l2 = f.read().splitlines() with open('switch.list') as f: ip_sw = f.read().splitlines() #Boucle autant de fois qu'il y a de ligne dans le fichier 'switch.list'. for ip in ip_sw: device = { 'device_type': 'cisco_ios', 'ip': ip, 'username': username, 'password': password, } net_connect = ConnectHandler(**device) #Vérifie la présence d'une ligne de configuration issu du fichier 'CONFIGURATION_L2', si résultat positif: n'envoie rien. #Sauvegarde la 'running-config' dans la 'startup-config' dans les 2 cas. try: result = net_connect.send_command( "show running-config | inc ip access-list standard SSH") except (NetMikoTimeoutException): print("Délai d'attente dépassé. " + ip) if "ip access-list standard SSH" in result: net_connect.save_config() time.sleep(0.5) net_connect.disconnect() #Envoie l'intégralité du contenu du fichier de configuration. else: output = net_connect.send_config_set(lines_l2) time.sleep(1) net_connect.save_config() time.sleep(0.5) net_connect.disconnect() print(output) #Ouverture du fichier de configuration et du fichier contenant les IP des routeurs. with open('CONFIGURATION_L3') as f: lines = f.read().splitlines() with open('router.list') as f: ip_rtr = f.read().splitlines() #Boucle autant de fois qu'il y a de ligne dans 'router.list'. for ip in ip_rtr: device = { 'device_type': 'cisco_ios', 'ip': ip, 'username': username, 'password': password, } net_connect = ConnectHandler(**device) #Vérifie la présence d'une ligne de configuration issue de 'CONFIGURATION_L3', si résultat positif; n'envoie rien. #Sauvegarde la 'running-config' dans la 'startup-config' dans les 2 cas. try: result = net_connect.send_command( "show running-config | inc ip access-list standard SSH") except (NetMikoTimeoutException): print("Délai d'attente dépassé. " + ip) if "ip access-list standard SSH" in result: net_connect.save_config() time.sleep(0.5) net_connect.disconnect() #Envoie l'intégralité du contenu du fichier de configuration else: output = net_connect.send_config_set(lines) time.sleep(1) net_connect.save_config() time.sleep(0.5) net_connect.disconnect() print(output) end_time = datetime.now() total_time = end_time - start_time print("Durée de la configuration: " + str(total_time) + "\n")
'''On both the NXOS1 and NXOS2 switches configure five VLANs including VLAN names (just pick 5 VLAN numbers between 100 - 999). Use Netmiko's send_config_from_file() method to accomplish this. Also use Netmiko's save_config() method to save the changes to the startup-config.''' from netmiko import ConnectHandler from getpass import getpass password = getpass() nxos1_dict = { "host": "nxos1.lasthop.io", "username": "******", "password": password, "device_type": "cisco_nxos" } nxos2_dict = { "host": "nxos2.lasthop.io", "username": "******", "password": password, "device_type": "cisco_nxos" } for dev in (nxos1_dict, nxos2_dict): dev_conn = ConnectHandler(**dev) op = dev_conn.find_prompt() op += dev_conn.send_config_from_file("vlans.txt") dev_conn.save_config() print(op) print("*" * 60) dev_conn.disconnect()
class ConnectToDevice(object): """ This class pretend to establish a connection to a network device. It has 4 functions (static methods): - configure_add_raw_commands : send a cisco command to a device. it not run on privileged mode - configure_add_raw_commands_not_privileged: send a cisco command to a device on privileged mode. - configures_add_commands_list: send a list of cisco commands to device: it runs on privileged mode. (it puts the CLI prompt on: device_name<config> ) - save_running_config - save running configurations on cisco network devices We could build this code as functions because we don't change anything in the instance object properties of the class This clas dont validate any data passed to the class. we are assuming that the data is ok. :param data: <dict> keys: "ip" - device ip to establish a connection :param connection_type <string> WE are expecting "SSH" or "TELNET" as strings for this parameter ** THIS OPTIONAL PARAMETER :param port <int> a port to connect ** THIS PARAMETER IS OPTIONAL :return , check each method, since each one can export different types of data ==================================================================================================================== ## NETMIKO SUPPORTS THIS CISCO DEVICES: (in 2019 Was different) ## CISCO DEVICES DRIVERS SUPORTED BY NETMIKO in 2020: ## ["cisco_asa", "cisco_ios", "cisco_nxos", "cisco_s300", "cisco_tp", "cisco_wlc", "cisco_xe", "cisco_xr"] ## WE suppose, (but not confirmed) that NETMIKO 2020 uses Cisco pyATS and Cisco Gennie 'capabilities' to connect to the new Cisco operating systems running on new devices. (e.g. nexos) ** We may want to automate configurations on network devices directly through Python pyATS and gennie or Ansible source: https://developer.cisco.com/docs/pyats/#!introduction/cisco-pyats-network-test--automation-solution # NETMIKO SOURCE LINKS: - source: https://ktbyers.github.io/netmiko/docs/netmiko/cisco_base_connection.html - source: https://ktbyers.github.io/netmiko/docs/netmiko/index.html - source: https://pynet.twb-tech.com/blog/automation/netmiko.html - source: https://github.com/ktbyers/netmiko ## DEVELOPMENT ENVIRONMENT In 2019, we were using 'cisco_ios' driver for ssh connections. and "cisco_ios_telnet" for telnet connections It proved to work properly on the devices that we test. We have implemented netmiko new feature SSHdiscover that tries to guess which operating system is running on device and choose for us the the correspondent device_driver for better interaction. We don't know which NETWORK device, CLIENTS WANT TO CONNECT, JUST THE IP. NOTE: May consider to be mandatory in future requests, that clients send us the OS Device Type instead of just telnet or ssh. Or have access to a database table or a file with a mapping between "ip">> "OS type". We have tested on these 2 Cisco devices: Cisco device 1: - Model: WS-C3560-48PS - IOS VERSION: 12.2(53)SE2 Cisco device 2: - Model: WS-C2950T-24 - IOS VERSION: 12.1(22)EA14 -------------------------------------------------------------------------------------------------------------------- NOTE: if we run problems when connecting to devices(slow networks, slow equipment , etc.) we may consider in adjusting and override global_delay_factor for connections.) We can pass as« a key,value pair when we call the ConnectHandler method. Rationale: netmiko send_command << will wait 100 seconds by default, which corresponds to default, global_delay_factor=1, if set to: gobal_delay_factor=2 it will duplicate the amount of time goblal_delay_factor=3 will triplicate and so on ... -------------------------------------------------------------------------------------------------------------------- Methods in MODULE netmiko.cisco_base_connection. THEY ARE USEFUL IF WE NEED TO BUILD MORE functionalities - check_config_mode--> Checks if the device is in configuration mode or not. - check_enable_mode--> Check if in enable mode. Return boolean. - cleanup: Gracefully--> exit the SSH session. - config_mode--> Enter into configuration mode on remote device. - enable--> Enter enable mode. - exit_config_mode--> Exit from configuration mode. - exit_enable_mode--> Exits enable (privileged exec) mode. - save_config--> Saves Config. - serial_login - telnet_login ### ### LAST NOTE: Since one of the goals of the development of this application was to present me (the processes of writing an app) And i had no knowledge of the oop programming paradigm, I think this class could be better constructed using python class inheritance. e.g. class ConnectToDevice(Netmiko): """ # init method def __init__(self, data, connection_type, port=None): # class attributes # TODO: # WE SHOULD CONSIDER TO USE THIS credenctiasl as an(APLICATION ENV) decrypted # from disk WHENEVER OUR APP STARTS self.device_credentials = { "device_username": current_app.config["DEVICE_USERNAME"], "device_password": current_app.config["DEVICE_PASSWORD"], "device_secret": current_app.config["DEVICE_SECRET"] } self.data = data self.connection_type = connection_type self.port = port print("=" * 79) print("OUTPUT - port: ", port) print("OUTPUT - connection_type: ", connection_type) print("=" * 79) if self.connection_type == "TELNET": self.connection_type = "cisco_ios_telnet" if port is None: self.port = 23 if self.connection_type == "SSH": # FOR SSH WE WILL TRY TO GUESS FIRST THE BEST MATCH if port is None: self.port = 22 # INSERT TEST GUESS HERE ssh_device_driver = guess_device(ip=self.data["ip"], port=self.port) print( "OUTPUT - -----------------------------------------------------------------" ) print("OUTPUT - GUESSING THE SSH DEVICE DRIVER") print("OUTPUT - ssh device driver best match is :", ssh_device_driver) if isinstance(ssh_device_driver, dict): if "STATUS" in ssh_device_driver: if ssh_device_driver["STATUS"] == "Failure": print(" WE COULDNT GUESS THE DEVICE DRIVER FOR SSH") # LETS USE DEFAULT DEVICE DRIVER self.connection_type = "cisco_ios" else: self.connection_type = ssh_device_driver print("OUTPUT - ---------------------") print("OUPTUT - INSTANCE OBJECT- ConnectToDevice - __INIT__ METHOD") print("OUTPUT - Preparing to connect to device with this setup:") print("OUTPUT - device ip: ", self.data["ip"]) print("OUTPUT - connection_type: ", self.connection_type) print("OUTPUT - port: ", self.port) # (STANDARD FAILURE DICTIONARY) AND SET VALUES FOR THIS OPERATION ERROR self.error_dictionary = { "STATUS": "Failure", "ERROR": "4", "TYPE": {}, "MESSAGE": {} } def configure_add_raw_commands(self, command_to_send): """ THIS FUNCTION send a command to a cisco network device in privileged mode :param command_to_send: <string> :return: <tupple> a tuple with 2 items. one item is a structured result if netmiko could parse the data The second item will be unparsed data, result of the command output in the network device CLI """ print( "OUTPUT - Entering... configure_add_raw_commands --> METHOD " ) try: # ESTABLISH A CONNECTION TO DEVICE USING NETMIKO self.net_connect = ConnectHandler( device_type=self.connection_type, ip=self.data["ip"], username=self.device_credentials["device_username"], password=self.device_credentials["device_password"], secret=self.device_credentials["device_secret"], port=self.port) # ENTER PRIVILEGED MODE -- like we put enable in the cisco console. self.net_connect.enable() # ELIMINATES DE "MORE" WORD ON CISCO TERMINAL - USER DOESN'T HAVE TO PRESS A KEY TO CONTINUE self.net_connect.send_command('terminal length 0') # WE want to try to get structured data from the cli output but it is only possible # TEXTFSM - ntc templates were installed try: output_structured = self.net_connect.send_command( command_to_send, use_textfsm=True) # DESEINTALAR O PATH OU ALTERAR PARA OUTRA LOCALIZACAO NAO EXISTENTE E VER O TIPO DE ERRO QUE DA_ # Esta excepcao não é a melhor forma de apanhar errors except Exception: output_structured = None output_unstructured = self.net_connect.send_command( command_to_send, use_textfsm=False) self.net_connect.send_command('terminal length 24') # disconnect from device self.net_connect.disconnect() return output_structured, output_unstructured # CATCH ERRORS AND RETURN THEM except AuthenticationException as e: self.error_dictionary["STATUS"] = "Failure" self.error_dictionary["TYPE"] = "AuthenticationException" self.error_dictionary["MESSAGE"] = str(e) # SEND ERROR MESSAGE TO CLIENT return self.error_dictionary except NetMikoTimeoutException as e: self.error_dictionary["STATUS"] = "Failure" self.error_dictionary["TYPE"] = "NetMikoTimeoutException" self.error_dictionary["MESSAGE"] = str(e) # SEND ERROR MESSAGE TO CLIENT return self.error_dictionary except SSHException as e: self.error_dictionary["STATUS"] = "Failure" self.error_dictionary["TYPE"] = "SSH_exception" if "Error reading SSH protocol banner" in str(e): self.error_dictionary[ "MESSAGE"] = "Error while connecting to device. Check port and connection type." else: self.error_dictionary["MESSAGE"] = str(e) # SEND ERROR MESSAGE TO CLIENT return self.error_dictionary except EOFError as e: self.error_dictionary["STATUS"] = "Failure" self.error_dictionary["TYPE"] = "EOFError" self.error_dictionary["MESSAGE"] = str(e) # SEND ERROR MESSAGE TO CLIENT return self.error_dictionary except Exception as unknown_error: self.error_dictionary["STATUS"] = "Failure" self.error_dictionary["TYPE"] = "unknown error" self.error_dictionary["MESSAGE"] = str(unknown_error) # SEND ERROR MESSAGE TO CLIENT return self.error_dictionary def configure_add_raw_commands_not_privileged(self, command_to_send): """ THIS FUNCTION send a command to a cisco network device not in privileged mode. :param command_to_send: <string> :return: <tupple> a tuple with 2 items. one item is a structured result if netmiko could parse the data The second item will be unparsed data, result of the command output in the network device CLI """ print( "OUTPUT - Entering... configure_add_raw_commands_not_privileged --> METHOD " ) try: # ESTABLISH A CONNECTION TO DEVICE USING NETMIKO self.net_connect = ConnectHandler( device_type=self.connection_type, ip=self.data["ip"], username=self.device_credentials["device_username"], password=self.device_credentials["device_password"], secret=self.device_credentials["device_secret"], port=self.port) # ENTER PRIVILEGED MODE -- like we put enable in the cisco console. # self.net_connect.enable() # WE CAN RUN COMMANDS not in privileged mode on the cisco cli: # EXAMPLE : WE can run --> show version and it will output the result # But, if we run a show run : # switchTelnet > show run # ^ # % Invalid input detected at '^' marker. # because we are not in privileged mode # ELIMINATES DE "MORE" WORD ON CISCO TERMINAL - USER DOESN'T HAVE TO PRESS A KEY TO CONTINUE self.net_connect.send_command('terminal length 0') # WE want to try to get structured data from the cli output but it is only possible # TEXTFSM - ntc templates were installed try: output_structured = self.net_connect.send_command( command_to_send, use_textfsm=True) # DESEINTALAR O PATH OU ALTERAR PARA OUTRA LOCALIZACAO NAO EXISTENTE E VER O TIPO DE ERRO QUE DA_ # Esta excepcao não é a melhor forma de apanhar errors except Exception: output_structured = None output_unstructured = self.net_connect.send_command( command_to_send, use_textfsm=False) self.net_connect.send_command('terminal length 24') # disconnect from device self.net_connect.disconnect() return output_structured, output_unstructured # CATCH ERRORS AND RETURN THEM except AuthenticationException as e: self.error_dictionary["STATUS"] = "Failure" self.error_dictionary["TYPE"] = "AuthenticationException" self.error_dictionary["MESSAGE"] = str(e) # SEND ERROR MESSAGE TO CLIENT return self.error_dictionary except NetMikoTimeoutException as e: self.error_dictionary["STATUS"] = "Failure" self.error_dictionary["TYPE"] = "NetMikoTimeoutException" self.error_dictionary["MESSAGE"] = str(e) # SEND ERROR MESSAGE TO CLIENT return self.error_dictionary except SSHException as e: self.error_dictionary["STATUS"] = "Failure" self.error_dictionary["TYPE"] = "SSH_exception" if "Error reading SSH protocol banner" in str(e): self.error_dictionary[ "MESSAGE"] = "Error while connecting to device. Check port and connection type." else: self.error_dictionary["MESSAGE"] = str(e) # SEND ERROR MESSAGE TO CLIENT return self.error_dictionary except EOFError as e: self.error_dictionary["STATUS"] = "Failure" self.error_dictionary["TYPE"] = "EOFError" self.error_dictionary["MESSAGE"] = str(e) # SEND ERROR MESSAGE TO CLIENT return self.error_dictionary except Exception as unknown_error: self.error_dictionary["STATUS"] = "Failure" self.error_dictionary["TYPE"] = "unknown error" self.error_dictionary["MESSAGE"] = str(unknown_error) # SEND ERROR MESSAGE TO CLIENT return self.error_dictionary def configure_add_commands_list(self, commands_list): """ THIS FUNCTION RECEIVE A LIST WITH CISCO CLI COMMNANDS , AND SEND ThEM TO A NETWORK DEVICE :param commands_list: list of command to sento to device NOTE. EACH ITEM SHOUD BE A STRING :return: <string> with all the cli device captured by netmiko """ print( "OUTPUT - HERE--------------------configure_add_commands_list method----------------" ) try: # ESTABLISH A CONNECTION TO DEVICE USING NETMIKO self.net_connect = ConnectHandler( device_type=self.connection_type, ip=self.data["ip"], username=self.device_credentials["device_username"], password=self.device_credentials["device_password"], secret=self.device_credentials["device_secret"], port=self.port) # enter user exec mode self.net_connect.enable() # ELIMINATES DE "MORE" WORD ON CISCO TERMINAL - USER DOESN'T HAVE TO PRESS A KEY TO CONTINUE self.net_connect.send_command('terminal length 0') #output_list= [] #for command in commands_list: # output = self.net_connect.send_command(command, use_textfsm=True) # output_list.append(output) # WE COULD SEND ALL THE COMMANDS ONE ONE TIME. output = self.net_connect.send_config_set(commands_list) # SET CONSOLE TO DEFAULTS 24 LINES - IT WILL SHOW AGAIN "MORE" WHEN USER RUN COMMANDS LIKE "SHOW VLAN" self.net_connect.send_command('terminal length 24') # DISCONNECT FROM DEVICE self.net_connect.disconnect() return output # CATCH ERRORS AND RETURN THEM except AuthenticationException as e: self.error_dictionary["STATUS"] = "Failure" self.error_dictionary["TYPE"] = "AuthenticationException" self.error_dictionary["MESSAGE"] = str(e) # SEND ERROR MESSAGE TO CLIENT return self.error_dictionary except NetMikoTimeoutException as e: self.error_dictionary["STATUS"] = "Failure" self.error_dictionary["TYPE"] = "NetMikoTimeoutException" self.error_dictionary["MESSAGE"] = str(e) # SEND ERROR MESSAGE TO CLIENT return self.error_dictionary except SSHException as e: self.error_dictionary["STATUS"] = "Failure" self.error_dictionary["TYPE"] = "SSH_exception" if "Error reading SSH protocol banner" in str(e): self.error_dictionary[ "MESSAGE"] = "Error while connecting to device. Check port and connection type." else: self.error_dictionary["MESSAGE"] = str(e) # SEND ERROR MESSAGE TO CLIENT return self.error_dictionary except EOFError as e: self.error_dictionary["STATUS"] = "Failure" self.error_dictionary["TYPE"] = "EOFError" self.error_dictionary["MESSAGE"] = str(e) # SEND ERROR MESSAGE TO CLIENT return self.error_dictionary except Exception as unknown_error: self.error_dictionary["STATUS"] = "Failure" self.error_dictionary["TYPE"] = "unknown error" self.error_dictionary["MESSAGE"] = str(unknown_error) # SEND ERROR MESSAGE TO CLIENT return self.error_dictionary def save_running_config(self): """ THIS FUNCTION save the running configurations in the start up configuration file :return: <string> with all the cli device captured by netmiko rationale: They essentially achieve the same things by saving the running configuration to the memory so that after a reload it retains the same configuration. Write memory is the "ancient" way, and copy running-config startup-config is the "newer way". Some newer platforms do not accept write memory, the Nexus platforms for instance. The workaround is to create an alias using cli alias name wr copy run start in global configuration mode. The "copy run start" command is just a variation of the "copy" command. The copy command can be used to copy any files in or out of the flash etc. - as opposed to just saving the configuration. Just remember though, if you are in the wrong configuration register "wr" will lose your configuration after a reload/when you change the configuration register whereas "copy run start" will just copy the contents of the running configuration to the start-up configuration. When doing CCNA exams, the command "write" is not allowed. It has to be the official "copy running-config startup-config". The reason why the "wr" or "write" command is very popular are: - A minimum of two characters to save a config; - It is easy to confuse "copy start run" with "copy run start". # SOURCE: https://ktbyers.github.io/netmiko/docs/netmiko/cisco_base_connection.html#netmiko.cisco_base_connection.CiscoBaseConnection.save_config """ print( "OUTPUT - HERE--------------------save_running_config method----------------" ) try: # ESTABLISH A CONNECTION TO DEVICE USING NETMIKO self.net_connect = ConnectHandler( device_type=self.connection_type, ip=self.data["ip"], username=self.device_credentials["device_username"], password=self.device_credentials["device_password"], secret=self.device_credentials["device_secret"], port=self.port) #SOURCE: https://github.com/ktbyers/netmiko/blob/develop/examples/enable/enable.py # Enter enable mode self.net_connect.enable() #print(self.net_connect.find_prompt()) # SEND SAVE COMMAND TO DEVICE output = self.net_connect.save_config( cmd="copy running-config startup-config", confirm=True, confirm_response="") # DISCONNECT FROM DEVICE self.net_connect.disconnect() # RETURN THE OUTPUT OF THE CONSOLE OUT return output # CATCH ERRORS AND RETURN THEM except AuthenticationException as e: self.error_dictionary["STATUS"] = "Failure" self.error_dictionary["TYPE"] = "AuthenticationException" self.error_dictionary["MESSAGE"] = str(e) # SEND ERROR MESSAGE TO CLIENT return self.error_dictionary except NetMikoTimeoutException as e: self.error_dictionary["STATUS"] = "Failure" self.error_dictionary["TYPE"] = "NetMikoTimeoutException" self.error_dictionary["MESSAGE"] = str(e) # SEND ERROR MESSAGE TO CLIENT return self.error_dictionary except SSHException as e: self.error_dictionary["STATUS"] = "Failure" self.error_dictionary["TYPE"] = "SSH_exception" if "Error reading SSH protocol banner" in str(e): self.error_dictionary[ "MESSAGE"] = "Error while connecting to device. Check port and connection type." else: self.error_dictionary["MESSAGE"] = str(e) # SEND ERROR MESSAGE TO CLIENT return self.error_dictionary except EOFError as e: self.error_dictionary["STATUS"] = "Failure" self.error_dictionary["TYPE"] = "EOFError" self.error_dictionary["MESSAGE"] = str(e) # SEND ERROR MESSAGE TO CLIENT return self.error_dictionary except Exception as unknown_error: self.error_dictionary["STATUS"] = "Failure" self.error_dictionary["TYPE"] = "unknown error" self.error_dictionary["MESSAGE"] = str(unknown_error) # SEND ERROR MESSAGE TO CLIENT return self.error_dictionary
from netmiko import ConnectHandler from netmiko.ssh_exception import NetMikoAuthenticationException #router = { "host":"192.168.0.7", "port":22, "username":"******", "password":"******", "device_type":"cisco_ios" } configurar = ["no interface loopback 11"] try: A = ConnectHandler(**router) A.enable() A.send_config_set(configurar) respuesta = A.send_command("show ip int brief") save = A.save_config() print("saving running config......") A.disconnect() print("user has exited tty session...") except Exception as ex: print(ex) else: print(respuesta)
from netmiko import ConnectHandler from getpass import getpass ''' 5. On both the NXOS1 and NXOS2 switches configure five VLANs including VLAN names (just pick 5 VLAN numbers between 100 - 999). Use Netmiko's send_config_from_file() method to accomplish this. Also use Netmiko's save_config() method to save the changes to the startup-config. ''' password = getpass() routers = ["nxos1.lasthop.io", "nxos2.lasthop.io"] for router in routers: device = { "device_type": "cisco_nxos", "host": router, "username": "******", "password": password, "fast_cli": True, } net_connect = ConnectHandler(**device) output = net_connect.send_config_from_file("config_set2.txt") net_connect.save_config() print(output) print("*" * 40) net_connect.disconnect()
from netmiko import ConnectHandler import getpass import os username = input('Username: '******'Switch_ips.txt') as file: devices_list = file.read().splitlines() #connecting to Switchs for devices in devices_list: print('Connecting to device: ' + devices) ip_address_of_device = devices iosv_l2 = { 'device_type': 'cisco_ios', 'ip': ip_address_of_device, 'username': username, 'password': password, } # Add account with priv 15 net_connect = ConnectHandler(**iosv_l2) output = net_connect.send_config_set( 'username USERNAME privilege 15 secret 0 PASSWORD') output += net_connect.save_config() print(output) print()
from netmiko import ConnectHandler from getpass import getpass device1 = { "host": 'cisco3.lasthop.io', "username": '******', "password": getpass(), "device_type": 'cisco_ios', } net_connect = ConnectHandler(**device1) print(net_connect.find_prompt()) output = net_connect.send_config_from_file(config_file="my_changes.txt") print(output) save_out = net_connect.save_config() print(save_out)
"fast_cli": True } nxos2 = { "host": "nxos2", 'username': '******', 'password': getpass(), 'device_type': 'cisco_nxos', 'session_log': 'nxos2_5.txt', 'fast_cli': True } device = [nxos1, nxos2] t0 = datetime.now() for d in device: t1 = datetime.now() ssh_con = ConnectHandler(**d) ssh_con.send_config_from_file('ex5_commands.txt') ssh_con.save_config() ssh_con.disconnect() t2 = datetime.now() t3 = t2 - t1 print("\nINICIO: ", t1) print('\nFIN: ', t2) print('\nDuracion ejecucion comando: ', t3) tf = datetime.now() print('\nDuracion configuracion equipos: ', tf - t0)