コード例 #1
0
ファイル: conftest.py プロジェクト: ogenstad/netmiko
def scp_fixture_get(request):
    """
    Create an FileTransfer object (direction=get)

    Return a tuple (ssh_conn, scp_handle)
    """
    device_under_test = request.config.getoption('test_device')
    test_devices = parse_yaml(PWD + "/etc/test_devices.yml")
    device = test_devices[device_under_test]
    device['verbose'] = False
    ssh_conn = ConnectHandler(**device)

    dest_file_system = 'flash:'
    source_file = 'test9.txt'
    local_file = 'testx.txt'
    dest_file = local_file
    direction = 'get'

    scp_transfer = FileTransfer(ssh_conn, source_file=source_file, dest_file=dest_file,
                                file_system=dest_file_system, direction=direction)
    scp_transfer.establish_scp_conn()

    # Make sure SCP is enabled
    scp_transfer.enable_scp()

    # Delete the test transfer files
    if os.path.exists(local_file):
        os.remove(local_file)

    return (ssh_conn, scp_transfer)
コード例 #2
0
ファイル: conftest.py プロジェクト: ktbyers/netmiko
def scp_file_transfer(request):
    """
    Testing file_transfer

    Return the netmiko connection object
    """
    platform_args = get_platform_args()

    # Create the files
    with open("test9.txt", "w") as f:
        # Not important what it is in the file
        f.write("no logging console\n")

    with open("test2_src.txt", "w") as f:
        # Not important what it is in the file
        f.write("no logging console\n")
        f.write("logging buffered 10000\n")

    device_under_test = request.config.getoption("test_device")
    test_devices = parse_yaml(PWD + "/etc/test_devices.yml")
    device = test_devices[device_under_test]
    device["verbose"] = False
    ssh_conn = ConnectHandler(**device)

    platform = device["device_type"]
    file_system = platform_args[platform]["file_system"]
    source_file = "test9.txt"
    dest_file = "test9.txt"
    local_file = "testx.txt"
    alt_file = "test2.txt"
    direction = "put"

    scp_transfer = FileTransfer(
        ssh_conn,
        source_file=source_file,
        dest_file=dest_file,
        file_system=file_system,
        direction=direction,
    )
    scp_transfer.establish_scp_conn()

    # Delete the test transfer files
    if scp_transfer.check_file_exists():
        func = platform_args[platform]["delete_file"]
        func(ssh_conn, file_system, dest_file)
    if os.path.exists(local_file):
        os.remove(local_file)
    if os.path.exists(alt_file):
        os.remove(alt_file)

    return (ssh_conn, file_system)
コード例 #3
0
ファイル: conftest.py プロジェクト: ysnrgtslash/netmiko
def scp_file_transfer(request):
    """
    Testing file_transfer

    Return the netmiko connection object
    """
    platform_args = get_platform_args()

    # Create the files
    with open("test9.txt", "w") as f:
        # Not important what it is in the file
        f.write("no logging console\n")

    with open("test2_src.txt", "w") as f:
        # Not important what it is in the file
        f.write("no logging console\n")
        f.write("logging buffered 10000\n")

    device_under_test = request.config.getoption('test_device')
    test_devices = parse_yaml(PWD + "/etc/test_devices.yml")
    device = test_devices[device_under_test]
    device['verbose'] = False
    ssh_conn = ConnectHandler(**device)

    platform = device['device_type']
    file_system = platform_args[platform]['file_system']
    source_file = 'test9.txt'
    dest_file = 'test9.txt'
    local_file = 'testx.txt'
    alt_file = 'test2.txt'
    direction = 'put'

    scp_transfer = FileTransfer(ssh_conn,
                                source_file=source_file,
                                dest_file=dest_file,
                                file_system=file_system,
                                direction=direction)
    scp_transfer.establish_scp_conn()

    # Delete the test transfer files
    if scp_transfer.check_file_exists():
        func = platform_args[platform]['delete_file']
        func(ssh_conn, file_system, dest_file)
    if os.path.exists(local_file):
        os.remove(local_file)
    if os.path.exists(alt_file):
        os.remove(alt_file)

    return (ssh_conn, file_system)
コード例 #4
0
def scp_fixture(request):
    """
    Create an FileTransfer object.

    Return a tuple (ssh_conn, scp_handle)
    """
    device_under_test = request.config.getoption('test_device')
    test_devices = parse_yaml(PWD + "/etc/test_devices.yml")
    device = test_devices[device_under_test]
    device['verbose'] = False
    ssh_conn = ConnectHandler(**device)

    dest_file_system = 'flash:'
    source_file = 'test9.txt'
    dest_file = 'test9.txt'
    local_file = 'testx.txt'
    direction = 'put'

    scp_transfer = FileTransfer(ssh_conn,
                                source_file=source_file,
                                dest_file=dest_file,
                                file_system=dest_file_system,
                                direction=direction)
    scp_transfer.establish_scp_conn()

    # Make sure SCP is enabled
    scp_transfer.enable_scp()

    # Delete the test transfer files
    if scp_transfer.check_file_exists():
        delete_file_ios(ssh_conn, dest_file_system, dest_file)
    if os.path.exists(local_file):
        os.remove(local_file)

    return (ssh_conn, scp_transfer)
コード例 #5
0
ファイル: conftest.py プロジェクト: ysnrgtslash/netmiko
def scp_fixture_get(request):
    """
    Create an FileTransfer object (direction=get)

    Return a tuple (ssh_conn, scp_handle)
    """
    platform_args = get_platform_args()
    device_under_test = request.config.getoption('test_device')
    test_devices = parse_yaml(PWD + "/etc/test_devices.yml")
    device = test_devices[device_under_test]
    device['verbose'] = False
    ssh_conn = ConnectHandler(**device)

    platform = device['device_type']
    dest_file_system = platform_args[platform]['file_system']
    source_file = 'test9.txt'
    local_file = 'testx.txt'
    dest_file = local_file
    direction = 'get'

    scp_transfer = FileTransfer(ssh_conn,
                                source_file=source_file,
                                dest_file=dest_file,
                                file_system=dest_file_system,
                                direction=direction)
    scp_transfer.establish_scp_conn()

    # Make sure SCP is enabled
    if platform_args[platform]['enable_scp']:
        scp_transfer.enable_scp()

    # Delete the test transfer files
    if os.path.exists(local_file):
        os.remove(local_file)
    return (ssh_conn, scp_transfer)
コード例 #6
0
def scp_fixture(request):
    """
    Create an FileTransfer object.

    Return a tuple (ssh_conn, scp_handle)
    """
    platform_args = get_platform_args()

    # Create the files
    with open("test9.txt", "w") as f:
        # Not important what it is in the file
        f.write("no logging console\n")

    with open("test2_src.txt", "w") as f:
        # Not important what it is in the file
        f.write("no logging console\n")
        f.write("logging buffered 10000\n")

    device_under_test = request.config.getoption("test_device")
    test_devices = parse_yaml(PWD + "/etc/test_devices.yml")
    device = test_devices[device_under_test]
    device["verbose"] = False
    ssh_conn = ConnectHandler(**device)

    platform = device["device_type"]
    dest_file_system = platform_args[platform]["file_system"]
    if "ciena_saos" in platform and ssh_conn.username:
        dest_file_system = f"/tmp/users/{ssh_conn.username}"

    source_file = "test9.txt"
    dest_file = "test9.txt"
    local_file = "testx.txt"
    direction = "put"

    scp_transfer = FileTransfer(
        ssh_conn,
        source_file=source_file,
        dest_file=dest_file,
        file_system=dest_file_system,
        direction=direction,
    )
    scp_transfer.establish_scp_conn()

    # Make sure SCP is enabled
    if platform_args[platform]["enable_scp"]:
        scp_transfer.enable_scp()

    # Delete the test transfer files
    if scp_transfer.check_file_exists():
        func = platform_args[platform]["delete_file"]
        func(ssh_conn, dest_file_system, dest_file)
    if os.path.exists(local_file):
        os.remove(local_file)
    return (ssh_conn, scp_transfer)
コード例 #7
0
ファイル: conftest.py プロジェクト: ktbyers/netmiko
def scp_fixture_get(request):
    """
    Create an FileTransfer object (direction=get)

    Return a tuple (ssh_conn, scp_handle)
    """
    platform_args = get_platform_args()
    device_under_test = request.config.getoption("test_device")
    test_devices = parse_yaml(PWD + "/etc/test_devices.yml")
    device = test_devices[device_under_test]
    device["verbose"] = False
    ssh_conn = ConnectHandler(**device)

    platform = device["device_type"]
    dest_file_system = platform_args[platform]["file_system"]
    source_file = "test9.txt"
    local_file = "testx.txt"
    dest_file = local_file
    direction = "get"

    scp_transfer = FileTransfer(
        ssh_conn,
        source_file=source_file,
        dest_file=dest_file,
        file_system=dest_file_system,
        direction=direction,
    )
    scp_transfer.establish_scp_conn()

    # Make sure SCP is enabled
    if platform_args[platform]["enable_scp"]:
        scp_transfer.enable_scp()

    # Delete the test transfer files
    if os.path.exists(local_file):
        os.remove(local_file)
    return (ssh_conn, scp_transfer)
コード例 #8
0
def scp_copy(customer, device, sourcefile, destfile, direction):
    ssh_conn = netmiko_connect(customer, device)
    dest_file_system = 'disk0:'
    scp_transfer = FileTransfer(
            ssh_conn = ssh_conn,
            source_file=sourcefile,
            dest_file=destfile,
            file_system=dest_file_system,
            direction=direction,
        )
    if direction == "put":
        if not scp_transfer.check_file_exists():
            if not scp_transfer.verify_space_available():
                raise ValueError("Insufficient space available on remote device")
    else:
        if not scp_transfer.verify_space_available():
            raise ValueError("Insufficient space available on remote device")
# Enable scp on ASA
    ssh_conn.send_config_set("ssh scopy enable")
# Transfer the file
    print("Transferring file:", sourcefile)
    try:
        scp_transfer.establish_scp_conn()
        scp_transfer.transfer_file()
# in case of a get ASA close the scp connection and we get EOFError
    except (Exception, socket.error, EOFError) as err:
        print(err)
# Disable scp on ASA
    ssh_conn.send_config_set("no ssh scopy enable")
# File verification
    print("Verifying file")
    if scp_transfer.verify_file():
        print("Source and destination MD5 matches")
    else:
        raise ValueError("MD5 failure between source and destination files")
    return
コード例 #9
0
    def transfer_file(self, file):

        with FileTransfer(self.device_connection,
                          source_file=file,
                          dest_file=file) as scp_transfer:
            if scp_transfer.check_file_exists():
                return file + ' already exists!'
            else:
                if not scp_transfer.verify_space_available():
                    return 'Insufficient space available!'
                scp_transfer.transfer_file()  # Transfer file
                if scp_transfer.verify_file():
                    return 'Transfer complete! \nsrc and dst MD5 match!'
                else:
                    return 'Transfer failed! \nMD5 mismatch on src and dst!'
コード例 #10
0
ファイル: netm.py プロジェクト: mattymorgan/pytestx
def main():
    net_device = {
        'device_type': 'cisco_ios',
        'ip': '192.168.56.105',
        'username': '******',
        'password': '******',
    }

    print("\nLogging in to Router")
    ssh_conn = ConnectHandler(**net_device)
    print()

    # GET OPERATION
    source_file = 'config_backup.txt'
    dest_file = 'config_backup.txt'
    dest_file_system = 'flash:'
    with FileTransfer(ssh_conn,
                      source_file=source_file,
                      dest_file=dest_file,
                      file_system=dest_file_system,
                      direction='get') as scp_transfer:
        scp_transfer.get_file()
        print("File transfer completed\n\n")
コード例 #11
0
ファイル: asa_scp.py プロジェクト: eilbronb/example
def main():
    net_device = {
        'device_type': 'cisco_asa',
        'ip': ASA_IP,
        'username': ASA_USER,
        'password': ASA_USER,
        'secret': ASA_ENABLE,
        'port': 22,
    }

    ssh_conn = ConnectHandler(**net_device)

    dest_file_system = 'disk0:'
    source_file = BACKUP_FILE
    dest_file = 'backup.cfg'

    with FileTransfer(ssh_conn,
                      source_file=source_file,
                      dest_file=dest_file,
                      file_system=dest_file_system) as scp_transfer:

        if scp_transfer.check_file_exists():
            ssh_conn.send_command(
                f'delete /noconfirm {dest_file_system}:/{dest_file}')

        if not scp_transfer.verify_space_available():
            raise ValueError("Insufficient space available on remote device")

        asa_scp_handler(ssh_conn, mode='enable')

        scp_transfer.transfer_file()

        asa_scp_handler(ssh_conn, mode='disable')

        if not scp_transfer.verify_file():
            raise ValueError(
                "MD5 failure between source and destination files")
コード例 #12
0
def scp_file_transfer(request):
    """
    Testing file_transfer

    Return the netmiko connection object
    """
    platform_args = {
        'cisco_ios': {
            'file_system': 'flash:',
            'enable_scp': True,
            'delete_file': delete_file_ios,
        },
        'juniper_junos': {
            'file_system': '/var/tmp',
            'enable_scp': False,
            'delete_file': delete_file_generic,
        },
        'arista_eos': {
            'file_system': '/mnt/flash',
            'enable_scp': False,
            'delete_file': delete_file_generic,
        },
        'cisco_nxos': {
            'file_system': 'bootflash:',
            'enable_scp': False,
            'delete_file': delete_file_nxos,
        },
        'cisco_xr': {
            'file_system': 'disk0:',
            'enable_scp': False,
            # Delete pattern is the same on IOS-XR
            'delete_file': delete_file_ios,
        },
    }

    # Create the files
    with open("test9.txt", "w") as f:
        # Not important what it is in the file
        f.write("no logging console\n")

    with open("test2_src.txt", "w") as f:
        # Not important what it is in the file
        f.write("no logging console\n")
        f.write("logging buffered 10000\n")

    device_under_test = request.config.getoption('test_device')
    test_devices = parse_yaml(PWD + "/etc/test_devices.yml")
    device = test_devices[device_under_test]
    device['verbose'] = False
    ssh_conn = ConnectHandler(**device)

    platform = device['device_type']
    file_system = platform_args[platform]['file_system']
    source_file = 'test9.txt'
    dest_file = 'test9.txt'
    local_file = 'testx.txt'
    alt_file = 'test2.txt'
    direction = 'put'

    scp_transfer = FileTransfer(ssh_conn,
                                source_file=source_file,
                                dest_file=dest_file,
                                file_system=file_system,
                                direction=direction)
    scp_transfer.establish_scp_conn()

    # Delete the test transfer files
    if scp_transfer.check_file_exists():
        func = platform_args[platform]['delete_file']
        func(ssh_conn, file_system, dest_file)
    if os.path.exists(local_file):
        os.remove(local_file)
    if os.path.exists(alt_file):
        os.remove(alt_file)

    return (ssh_conn, file_system)
コード例 #13
0
def scp_fixture_get(request):
    """
    Create an FileTransfer object (direction=get)

    Return a tuple (ssh_conn, scp_handle)
    """
    platform_args = {
        'cisco_ios': {
            'file_system': 'flash:',
            'enable_scp': True,
            'delete_file': delete_file_ios,
        },
        'juniper_junos': {
            'file_system': '/var/tmp',
            'enable_scp': False,
            'delete_file': delete_file_generic,
        },
        'arista_eos': {
            'file_system': '/mnt/flash',
            'enable_scp': False,
            'delete_file': delete_file_generic,
        },
        'cisco_nxos': {
            'file_system': 'bootflash:',
            'enable_scp': False,
            'delete_file': delete_file_nxos,
        },
        'cisco_xr': {
            'file_system': 'disk0:',
            'enable_scp': False,
            # Delete pattern is the same on IOS-XR
            'delete_file': delete_file_ios,
        },
    }

    device_under_test = request.config.getoption('test_device')
    test_devices = parse_yaml(PWD + "/etc/test_devices.yml")
    device = test_devices[device_under_test]
    device['verbose'] = False
    ssh_conn = ConnectHandler(**device)

    platform = device['device_type']
    dest_file_system = platform_args[platform]['file_system']
    source_file = 'test9.txt'
    local_file = 'testx.txt'
    dest_file = local_file
    direction = 'get'

    scp_transfer = FileTransfer(ssh_conn,
                                source_file=source_file,
                                dest_file=dest_file,
                                file_system=dest_file_system,
                                direction=direction)
    scp_transfer.establish_scp_conn()

    # Make sure SCP is enabled
    if platform_args[platform]['enable_scp']:
        scp_transfer.enable_scp()

    # Delete the test transfer files
    if os.path.exists(local_file):
        os.remove(local_file)
    return (ssh_conn, scp_transfer)
コード例 #14
0
class iosfw(object):
    def __init__(
        self,
        hostname=None,
        username=None,
        password=None,
        timeout=60,
        driver="ios",
        optional_args=None,
        config_file="./config/config.yaml",
        image_file="./config/images.yaml",
    ):
        """ Initializes connection and file transfer """

        # Config
        self.config_file = config_file
        self.config = self._read_yaml_file(config_file)
        self.image_file = image_file
        self.image_info = self._read_yaml_file(image_file)

        # Logging
        self.log_method = self.config["log_method"]
        self.log_file = self.config["log_file"]
        self.file_log_level = self.config["file_log_level"]
        self.console_log_level = self.config["console_log_level"]
        file_level = getattr(logging, self.file_log_level.upper(), None)
        console_level = getattr(logging, self.console_log_level.upper(), None)
        self.log = logging.getLogger(__name__)
        self.log.setLevel(logging.DEBUG)
        if self.log_method == "tee" or self.log_method == "file":
            fmt_str = "%(asctime)s [%(levelname)s] %(message)s"
            formatter = logging.Formatter(fmt_str)
            fh = logging.FileHandler(self.log_file)
            fh.setLevel(file_level)
            fh.setFormatter(formatter)
            self.log.addHandler(fh)
        if self.log_method == "tee" or self.log_method == "console":
            formatter = logging.Formatter("%(message)s")
            ch = logging.StreamHandler()
            ch.setLevel(console_level)
            ch.setFormatter(formatter)
            self.log.addHandler(ch)
        self.log.debug("Config file: {}".format(self.config_file))
        self.log.debug("Config parameters: {}".format(self.config))
        self.log.debug("Image file: {}".format(self.image_file))
        self.log.debug("Image info: {}".format(self.image_info))

        # Set up connection
        if hostname is None:
            hostname = str(input("Hostname or IP: "))
        if username is None:
            whoami = getpass.getuser()
            username = str(input("Username [{}]: ".format(whoami))) or whoami
        if password is None:
            password = getpass.getpass()
        if optional_args is None:
            optional_args = {}
            secret = getpass.getpass("Enable secret: ")
            optional_args.update({"secret": secret})
            if self.config["ssh_config_file"]:
                optional_args.update(
                    {"ssh_config_file": self.config["ssh_config_file"]})
        napalm_driver = napalm.get_network_driver(driver)
        self.napalm = napalm_driver(
            hostname=hostname,
            username=username,
            password=password,
            timeout=timeout,
            optional_args=optional_args,
        )
        self.log.info("===============================================")
        self.log.info("Opening connection to {}...".format(hostname))
        self.napalm.open()

        # Aliases and info
        self.device = self.napalm.device  # Netmiko session
        self.facts = self.napalm.get_facts()  # NAPALM facts
        self.os_version = self.facts["os_version"]
        self.model = self.facts["model"]
        self.hostname = self.facts["hostname"]
        self.fqdn = self.facts["fqdn"]
        self.transport = self.napalm.transport  # ssh or telnet
        self.upgrade_image_exists = False
        self.upgrade_image_valid = False
        self.upgrade_space_available = False
        self.transfer_proto = self.config["transfer_proto"]
        self.transfer_source = self.config["transfer_source"]
        self.exec_timeout = self.get_exec_timeout()
        self.running_image_path = self.get_running_image()
        self.running_image_name = self._get_basename(self.running_image_path)
        self.running_image_feature_set = self._get_image_feature_set(
            self.running_image_name)
        self.upgrade_image_name = self.get_upgrade_image_name()
        self.upgrade_version = self.get_upgrade_version()
        self.running_version = self.get_running_version()
        self.upgrade_image_src_path = self._get_src_path(
            self.upgrade_image_name, local=True)
        self.upgrade_image_dest_path = self._get_dest_path(
            self.upgrade_image_name)
        self.boot_image_path = self.get_boot_image()
        self.firmware_installed = self.check_firmware_installed()
        self.needs_upgrade = self.check_needs_upgrade()
        self.upgrade_cmd = self._get_upgrade_cmd()
        self.upgrade_method = self._get_upgrade_method()
        self.transfer_proto = self.config["transfer_proto"]
        self.needs_reload = self.check_needs_reload()
        self.reload_scheduled = self.check_reload_scheduled()
        self.old_images = self.get_old_images()
        if self.config["delete_running_image"] != "never":
            self.can_delete_running_image = True
        else:
            self.can_delete_running_image = False
        if self.config["delete_old_images"] != "never":
            self.can_delete_old_images = True
        else:
            self.can_delete_old_images = False
        self.log.info("Connected to {} ({}) as {} via {}".format(
            self.hostname, self.model, self.device.username, self.transport))
        self.log_upgrade_state()

    def log_upgrade_state(self, refresh=False):
        """ Logs upgrade-related facts about device """
        if refresh:
            self.refresh_upgrade_state()
        self.log.info("Running version: {}".format(self.running_version))
        self.log.info("Upgrade version: {}".format(self.upgrade_version))
        if self.firmware_installed:
            if self.needs_reload:
                self.log.info("Upgrade status: FIRMWARE INSTALLED")
                if self.reload_scheduled:
                    t = self.reload_scheduled["absolute_time"]
                    msg = "Reload status: RELOAD SCHEDULED for {}".format(t)
                    self.log.info(msg)
                else:
                    self.log.info("Reload status: NEEDS RELOAD")
            else:
                self.log.info("Upgrade status: COMPLETE")
        else:
            self.log.info("Upgrade status: NEEDS UPGRADE")

    def refresh_upgrade_state(self, log=False):
        """ Updates device status """
        self.running_image_path = self.get_running_image()
        self.boot_image_path = self.get_boot_image()
        self.firmware_installed = self.check_firmware_installed()
        self.needs_reload = self.check_needs_reload()
        self.reload_scheduled = self.check_reload_scheduled()
        self.old_images = self.get_old_images()
        if log:
            self.log_upgrade_state()

    def __del__(self):
        # Proxied SSH connections generate a harmless ProcessLookupError
        # on exit
        try:
            self.napalm.__del__()
        except OSError.ProcessLookupError:
            pass

    def _get_upgrade_cmd(self):
        """ Returns a command string for auto-upgrade, if supported """
        flags = " "
        image_src = self._get_src_path()
        image_dest = self._get_dest_path()
        if self.transfer_source == "localhost":
            img = image_dest
        else:
            img = image_src
        cmds = ["request", "software install", "archive download-sw", "copy"]
        for cmd in cmds:
            output = self.device.send_command(cmd + " ?")
            if "Incomplete command" in output:
                method = cmd
                if ("allow-feature-upgrade" in output
                        and not self.config["match_feature_set"]):
                    flags += "/allow-feature-upgrade "
                break
        if method == "request":
            if "ISR" in self.model:
                target = "node"
            else:
                target = "switch all"
            return ("request platform software package install {} "
                    "file {} new auto-copy".format(target, img))
        if method == "software install":
            return "software install file {} new on-reboot".format(img)
        if method == "archive download-sw":
            if self.config["delete_running_image"] == "never":
                flags += "/safe /leave-old-sw "
            else:
                flags += "/overwrite "
            return "archive download-sw{}{}".format(flags, img)
        if method == "copy":
            return "copy {} {}".format(image_src, image_dest)

    def _get_upgrade_method(self):
        """ Checks whether IOS supports automatic or manual upgrade """
        if re.search(r"^copy", self.upgrade_cmd):
            return "manual"
        else:
            return "auto"

    def _strip_extension(self, file_name=None):
        """ Returns a file name without the extension """
        if file_name is None:
            file_name = self.upgrade_image_name
        split = self.upgrade_image_name.split(".")
        del split[-1]
        return ".".join(split)

    def _get_src_path(self, file_name=None, local=False):
        """ Returns full source file path """
        proto = self.config["transfer_proto"]
        un = self.config["transfer_username"] or ""
        pw = self.config["transfer_password"] or ""
        path = self.config["transfer_path"]
        src = self.config["transfer_source"]
        if file_name is None:
            file_name = self.upgrade_image_name
        if proto == "scp" or local:
            path = self.config["src_image_path"]
            return "{}/{}".format(path, file_name)
        elif proto == "ftp":
            return "{}://{}:{}@{}{}{}".format(proto, un, pw, src, path,
                                              file_name)
        else:
            return "{}://{}{}{}".format(proto, src, path, file_name)

    def _get_dest_path(self, file_name=None, absolute=True):
        """ Returns full destination file path
            absolute (bool):
                True = path includes dest_filesystem
                False = path does not include dest_filesystem
        """
        if file_name is None:
            file_name = self.upgrade_image_name
        full_path = ""
        if absolute:
            full_path += self.config["dest_filesystem"]
        full_path += "{}{}".format(self.config["dest_image_path"], file_name)
        return full_path

    def _read_yaml_file(self, file_name):
        """ Reads and parses YAML file """
        with open(file_name, "r") as f:
            file_contents = f.read()
            parsed_yaml = yaml.load(file_contents, Loader=yaml.FullLoader)
        return parsed_yaml

    def _file_md5(self, file_name):
        """ Compute MD5 hash of local file_name """
        with open(file_name, "rb") as f:
            file_contents = f.read()
            file_hash = hashlib.md5(file_contents).hexdigest()
        return file_hash

    def _check_remote_file_exists(self, file_path):
        """ Checks if a file exists on the remote filesystem """
        cmd = "dir {}".format(file_path)
        output = self.device.send_command(cmd)
        if "No such file" in output:
            return False
        elif "Directory of" in output:
            return True
        else:
            self.log.critical("Unexpected output from "
                              "_check_remote_file_exists(): \n"
                              "{}".format(output))
            return False

    def _get_image_feature_set(self, file_name):
        """ Parses the feature set string from an IOS file name

            e.g.: ipbasek9, universalk9, ipservicesk9
        """
        split = re.split(r"[-\.]", file_name)
        if split:
            if len(split) > 1:
                return split[1]
            else:
                return False
        else:
            return False

    def _check_image_feature_set(self, file_name):
        """ Checks if a given image's feature set matches the running
            image's feature set.

            Ignores K9 in the feature set string, so 'ipbasek9'
            matches 'ipbase'

        """
        regex = r"[Kk]9"
        set1 = re.sub(regex, "", self.running_image_feature_set)
        set2 = re.sub(regex, "", self._get_image_feature_set(file_name))
        return set1 == set2

    def _scp_tqdm(self, t):
        """ Provides progress bar """
        # https://github.com/tqdm/tqdm/blob/master/examples/tqdm_wget.py
        last_b = [0]

        def update_to(filename, size, sent):
            t.total = size
            t.desc = filename
            t.update(sent - last_b[0])
            last_b[0] = sent

        return update_to

    def _write_config(self):
        """ Writes running configuration to NVRAM """
        cmd = "write memory"
        output = self.device.send_command_expect(cmd)
        if "OK" in output or output == "#":
            return True
        else:
            self.log.warning("Unexpected output from `write memory`: \n"
                             "{}".format(output))
            return False

    def _send_write_config_set(self, config_set):
        """ Sends configuration set to device and writes to NVRAM """
        output = self.device.send_config_set(config_set)
        if "Invalid input" not in output:
            self._write_config()
            return True
        else:
            self.log.critical("Device reports invalid configuration "
                              "commands.\nCommands: {}\nOutput: "
                              "{}\n".format(config_set, output))
            return False

    def close(self):
        """ Closes all connections to device and logs """
        # Proxied SSH connections generate a harmless ProcessLookupError
        # on exit
        try:
            self.napalm.close()
        except OSError.ProcessLookupError:
            pass
        handlers = self.log.handlers[:]
        for h in handlers:
            h.close()
            self.log.removeHandler(h)

    def _ensure_enable_not_config(self):
        """ Places device in enable mode and takes out of config mode """
        if not self.device.check_enable_mode():
            self.device.enable()
        if self.device.check_config_mode():
            self.device.exit_config_mode()

    def get_upgrade_image_name(self):
        """ Returns the file name of the device's upgrade image  """
        for file_name, attrs in self.image_info.items():
            if self.model in attrs["models"]:
                if self.config["match_feature_set"]:
                    if not self._check_image_feature_set(file_name):
                        continue
                upgrade_image_path = self._get_src_path(file_name)
                if self.config["transfer_source"] != "localhost":
                    return file_name
                elif os.path.exists(upgrade_image_path):
                    upgrade_image_md5 = self._file_md5(upgrade_image_path)
                    if upgrade_image_md5.lower() == attrs["md5"].lower():
                        return file_name
                    else:
                        msg = ("MD5 for image {} "
                               "does not match MD5 in "
                               "config.\nImage MD5: {} "
                               "\nConfig MD5: {}\n".format(
                                   file_name, attrs["md5"], upgrade_image_md5))
                        self.log.critical(msg)
                        return False
                else:
                    self.log.critical("Image file does not exist: "
                                      "{}".format(upgrade_image_path))
                    return False
        self.log.critical("Could not find upgrade image for model "
                          "{} in image file "
                          "{}.".format(self.model, self.image_file))
        return False

    def _get_basename(self, file_path):
        """ Returns a file name from a file path

            Example input: 'flash:/c3750-ipbase-mz.122-25.SEE1.bin'
            Example output: 'c3750-ipbase-mz.122-25.SEE1.bin'

        """
        return re.split(r"[:/]", file_path)[-1]

    def _get_path(self, file_path, include_trailing_slash=False):
        """ Returns a file's path, not including the file itself """
        basename = self._get_basename(file_path)
        if not include_trailing_slash:
            basename = "/{}".format(basename)
        return file_path.replace(basename, "")

    def _get_version_from_file(self, file_name, raw=False):
        """ Returns a version string from a file name """
        # c2900-universalk9-mz.SPA.157-3.M4b.bin
        # c2960s-universalk9-tar.152-2.E9.tar
        # c2960x-universalk9-tar.152-4.E8.tar
        # c3550-ipbase-tar.122-44.SE6.tar
        # c3550-ipbasek9-mz.122-44.SE6.bin
        # c3560-ipbasek9-mz.122-55.SE12.bin
        # c3560-ipbasek9-tar.122-55.SE12.tar
        # c3560e-ipbasek9-mz.150-2.SE11.bin
        # c3560e-ipbasek9-tar.150-2.SE11.tar
        # c3560e-universalk9-mz.152-4.E8.bin
        # c3560e-universalk9-tar.152-4.E8.tar
        # c3750-ipbaselmk9-tar.122-55.SE12.tar
        # c3750e-ipbasek9-mz.150-2.SE11.bin
        # c3750e-universalk9-tar.152-4.E8.tar
        # cat3k_caa-universalk9.16.03.08.SPA.bin
        # cat9k_iosxe.16.11.01.SPA.bin
        pattern = r"(\d+\.\d+\.\d+)\.SPA"
        match = re.search(pattern, file_name)
        if match:
            if raw:
                return match.group(1)
            else:
                return re.sub(r"\.0", ".", match.group(1))

        pattern = r"(\d{3})-(\d+)\.(\w+)"
        match = re.search(pattern, file_name)
        if match:
            if raw:
                return match.group(0)
            else:
                train = "{}.{}".format(match.group(1)[:2], match.group(1)[2:])
                throttle = match.group(2)
                rebuild = match.group(3)
                return "{}({}){}".format(train, throttle, rebuild)

    def get_upgrade_version(self, raw=False):
        """ Parses image name to return IOS version string """
        return self._get_version_from_file(self.upgrade_image_name, raw)

    def get_running_version(self):
        """ Parses self.os_version for IOS version string """
        pattern = r"ersion ([^,]+),"
        match = re.search(pattern, self.os_version)
        if match:
            return match.group(1)
        else:
            return False

    def get_running_image(self):
        """ Returns the remote path of the image running in memory """
        search_string = "System image file is "
        cmd = "show ver | i {}".format(search_string)
        output = self.device.send_command(cmd)
        if search_string in output:
            return output.replace(search_string, "").replace('"', "")
        else:
            self.log.critical("Could not find running image. "
                              "Last output:\n{}".format(output))
            return False

    def get_boot_image(self):
        """ Returns the remote path of the image used on next reload """
        cmd = "show boot | include BOOT"
        output = self.device.send_command(cmd)
        if "Invalid input" in output:
            self.log.debug("Device does not support `show boot`. "
                           "Checking running config...")
            cmd = "show run | i boot"
            output = self.device.send_command(cmd)
            self.log.debug("Output from `{}`: \n{}".format(cmd, output))
            if "boot system" in output:
                match = re.search(r"boot system ([^\n]+)\n", output)
                self.log.debug("Found boot image {}".format(match.group(1)))
                return match.group(1)
            else:
                self.log.debug("No `boot system` directives found in config. "
                               "Inferring first image in dest_fs.")
                return self.get_installed_images()[0]
        else:
            return output.split(": ")[-1].strip()

    def get_installed_images(self):
        """ Returns list of images installed on dest_fs """
        results = []
        dest_fs = self.config["dest_filesystem"]
        cmd = "dir {}".format(dest_fs)
        output = self.device.send_command_timing(cmd)
        for line in output.split("\n"):
            file_name = re.split(r"\s+", line)[-1]
            # c3560e-universalk9-mz.152-4.E8
            # c3560-ipbasek9-mz.122-55.SE12
            # c2900-universalk9-mz.SPA.152-4.M4.bin
            # pattern = r'\w+-\w+-\w+.\d+-\w+\.\w+'
            pattern = r"\d+-\w+\.\w+"
            match = re.search(pattern, file_name)
            if match:
                results.append("{}/{}".format(dest_fs, file_name))
        return results

    def get_old_images(self):
        """ Checks dest_filesystem for old image files """
        results = []
        installed_images = self.get_installed_images()
        for image in installed_images:
            img_version = self._get_version_from_file(image)
            if (img_version != self.running_version
                    and img_version != self.upgrade_version):
                results.append(image)
        return results

    def get_exec_timeout(self):
        """ Returns config line for line vty exec-timeout, if exists """
        cmd = "sh run | i exec-timeout"
        self.log.debug("Executing command `{}`...".format(cmd))
        output = self.device.send_command(cmd)
        self.log.debug("Command output:\n{}".format(output))
        if output:
            output = output.split("\n")
            return output[-1]

    def disable_exec_timeout(self):
        """ Disables line vty exec-timeout """
        config_set = ["line vty 0 15", "no exec-timeout"]
        self.log.info("Disabling line vty exec-timeout...")
        return self._send_write_config_set(config_set)

    def ensure_exec_timeout_disabled(self):
        """ Disables line vty exec timeout, if not already disabled """
        if self.exec_timeout:
            return self.disable_exec_timeout()
        else:
            return True

    def restore_exec_timeout(self):
        """ Restores line vty exec-timeout """
        if self.exec_timeout != " exec-timeout 0 0":
            config_set = ["line vty 0 15", self.exec_timeout]
            self.log.info("Restoring line vty exec-timeout...")
            return self._send_write_config_set(config_set)
        else:
            return True

    def ensure_exec_timeout_restored(self):
        """ Restores line vty exec-timeout, if needed """
        if self.exec_timeout != " exec-timeout 0 0":
            return self.restore_exec_timeout()
        else:
            return True

    def set_boot_image(self, new_boot_image_path=None):
        """ Configures device to boot given image on next reload """
        if new_boot_image_path is None:
            new_boot_image_path = self.upgrade_image_dest_path
        config_set = [
            "no boot system", "boot system {}".format(new_boot_image_path)
        ]
        return self._send_write_config_set(config_set)

    def ensure_boot_image(self, new_boot_image_path=None):
        """ Ensures the given image is set to boot, if not already.

            new_boot_image_path (str): full destination path to boot image,
                including filesystem

            Does nothing if already set.
        """
        if new_boot_image_path is None:
            new_boot_image_path = self.upgrade_image_dest_path
        self.log.info("Checking boot image...")
        current_boot_image_path = self.get_boot_image()
        if current_boot_image_path != new_boot_image_path:
            self.log.info(
                "Setting boot image to {}...".format(new_boot_image_path))
            if self.set_boot_image(new_boot_image_path):
                confirm = self.get_boot_image()
                if confirm == new_boot_image_path:
                    self.log.info(
                        "Success! New boot image set to {}.".format(confirm))
                    return True
        else:
            self.log.info(
                "Boot image already set to {}.".format(new_boot_image_path))
            return True

    def check_scp(self):
        """ Checks if SCP is enabled """
        # I could find no more "correct" way of verifying SCP is running
        cmd = "show run | include scp"
        output = self.napalm.device.send_command_expect(cmd)
        if "ip scp server enable" in output:
            return True
        else:
            return False

    def fix_scp(self):
        """ Attempts to enable/fix SCP """
        config_set = self.config["fix_scp"]
        if config_set:
            output = self.device.send_config_set(config_set)
            if "Invalid input" not in output:
                output += self.device.send_command_expect("write memory")
                return True
            else:
                self.log.critical("Problem fixing SCP config. Last output: "
                                  "\n{}".format(output))
                return False
        else:
            self.log.critical(
                "No 'fix_scp' values found in {}. Cannot proceed.".format(
                    self.config_file))
            return False

    def fix_ntp(self):
        """ Fixes NTP if possible """
        fix_ntp_cmds = self.config["fix_ntp"]
        cmd = "show run | i ntp"
        ntp_config = self.device.send_command(cmd).split("\n")
        null_ntp_cmds = []
        for line in ntp_config:
            null_ntp_cmds.append("no {}".format(line))
        self.log.debug(
            "Removing existing NTP config: \n{}".format(null_ntp_cmds))
        output = self.device.send_config_set(null_ntp_cmds)
        self.log.debug("Output: \n{}".format(output))
        self.log.debug("Sending new NTP config: \n{}".format(fix_ntp_cmds))
        output += self.device.send_config_set(fix_ntp_cmds)
        self.log.debug("Output: \n{}".format(output))

    def ensure_scp(self):
        """ Enables SCP if it is not already running properly. """
        self.log.info("Checking SCP...")
        check = self.check_scp()
        if check:
            self.log.info("SCP already enabled and running.")
        else:
            self.log.info("SCP not running. Enabling now...")
            fixed = self.fix_scp()
            if fixed:
                self.log.info("SCP enabled successfully!")

    def check_upgrade_image_running(self):
        """ Check if running image is the current version """
        if self.upgrade_version == self.running_version:
            return True
        else:
            return False

    def check_needs_upgrade(self):
        """ Inverse of check_upgrade_image_running() """
        if self.check_upgrade_image_running():
            return False
        else:
            return True

    def check_firmware_installed(self):
        """ Checks if upgrade package is already installed """
        version = self.get_upgrade_version(raw=True)
        dest_fs = self.config["dest_filesystem"]
        files = self.device.send_command("dir {}".format(dest_fs))
        if "packages.conf" in self.boot_image_path:
            conf = self.device.send_command("more flash:packages.conf")
            if version in conf:
                return True
            else:
                return False
        if version in files:
            return True
        else:
            return False

    def check_needs_reload(self):
        """ Check if running image does not equal boot image """
        if self.upgrade_method == "auto":
            if self.check_needs_upgrade() and self.check_firmware_installed():
                return True
            else:
                return False
        else:
            if self.running_image_path != self.boot_image_path:
                return True
            else:
                return False

    def check_reload_scheduled(self):
        """ Check if a reload is scheduled """
        self._ensure_enable_not_config()
        output = self.device.send_command("show reload")
        pattern = r"Reload scheduled for (.+?) \(in (.+?)\)"
        match = re.search(pattern, output)
        if match:
            return {
                "absolute_time": match.group(1),
                "relative_time": match.group(2)
            }
        else:
            return False

    def cancel_reload(self):
        """ Cancels pending reload, if any """
        cmd = "reload cancel"
        output = self.device.send_command_timing(cmd)
        if "ABORTED" in output:
            # strange, we need an [enter] to get our prompt back
            # after `reload cancel`
            output += self.device.send_command_timing("\n")
            return True
        elif "No reload is scheduled" in output:
            return True
        else:
            self.log.critical("Unexpected output from `{}`:"
                              "\n{}".format(cmd, output))
            return False

    def schedule_reload(self,
                        reload_at=None,
                        reload_in=None,
                        save_modified_config=True):
        """ Schedules reload
            Overwrites pending reload, if already scheduled
            Defaults to midnight tonight (technically, 00:00 tomorrow)

            reload_at (str)
                Absolute time to reload device at in 'hh:mm' format
            reload_in (str)
                Relative time (delay from now) before reloading
                device in 'mmm' or 'hhh:mm' format
            save_modified_config (bool)
                Whether or not to save outstanding config changes,
                if any
        """
        # Should be hh:mm, but h:mm is valid; IOS prepends 0
        # e.g.: `reload at 7:35` schedules reload at 07:35 (7:35am)
        reload_at_pattern = r"^\d{1,2}:\d{2}$"
        reload_in_pattern = r"^\d{1,3}$|^\d{1,3}:\d{2}$"

        if reload_at is None:
            reload_at = self.config["reload_at"]
        if reload_in is None:
            reload_in = self.config["reload_in"]

        # Validate inputs
        if reload_at is str and reload_in is str:
            raise ValueError("Use either reload_in or reload_at, not both")
        if reload_at is not str and reload_in is not str:
            reload_at = "00:00"
        if reload_at:
            reload_at = str(reload_at).strip()
            if re.match(reload_at_pattern, reload_at):
                cmd = "reload at {}".format(reload_at)
            else:
                self.log.critical("reload_at must be 'hh:mm' or "
                                  "'h:mm' ('{}' given)".format(reload_at))
                return False
        if reload_in:
            reload_in = str(reload_in).strip()
            if re.match(reload_in_pattern, reload_in):
                cmd = "reload in {}".format(reload_in)
            else:
                self.log.critical("reload_in must be 'mmm' or 'hhh:mm' "
                                  "('{}' given)".format(reload_in))
                return False

        # Schedule the reload
        self._ensure_enable_not_config()
        e = r"(Save|Proceed|\#)"
        output = self.device.send_command(cmd, expect_string=e)
        if "The date and time must be set first" in output:
            self.log.debug("Clock not set.")
            if self.config["fix_ntp"]:
                self.log.debug("Attempting NTP fix...")
                self.fix_ntp()
                self.log.debug("Waiting 30 seconds for NTP to sync...")
                sleep(30)
                return self.schedule_reload()
            else:
                self.log.critical("No fix_ntp parameters given. "
                                  "Cannot continue with reload.")
                return False

        if "Save?" in output:
            if save_modified_config:
                response = "yes"
            else:
                response = "no"
            output += self.device.send_command(response,
                                               expect_string=r"Proceed",
                                               delay_factor=2)
        if "Proceed" in output:
            output += self.device.send_command_timing("\n")
        else:
            self.log.critical("Unexpected output from `{}`:"
                              "\n{}".format(cmd, output))
            return False
        check_reload_scheduled = self.check_reload_scheduled()
        if check_reload_scheduled:
            return check_reload_scheduled
        else:
            msg = ("Tried to schedule reload with `{}`, "
                   "but check_reload_scheduled() failed. "
                   "Output:\n{}".format(cmd, output))
            self.log.critical(msg)
            return False

    def ensure_reload_scheduled(self):
        """ Schedules a reload, if not already scheduled. """
        scheduled = self.check_reload_scheduled()
        if not scheduled:
            self.log.info("Scheduling reload...")
            return self.schedule_reload()
        else:
            return scheduled
        self.log.info("Reload scheduled for {} ({} away)".format(
            scheduled["absolute_time"], scheduled["relative_time"]))

    def _delete_file(self, file_name):
        """ Deletes a remote file from device """
        cmd = "del /recursive /force {}".format(file_name)
        output = self.device.send_command_timing(cmd)
        # Successful command returns no output
        if output:
            self.log.critical(
                "Unexpected output from `del`: \n{}".format(output))
            return False
        else:
            return True

    def ensure_file_removed(self, file_name, delete_path=True):
        """ Deletes a remote file from device only if it exists.
            Optionally deletes the full path (any parent folders).

        """
        if delete_path:
            path = self._get_path(file_name)
            if path != self.config["dest_filesystem"]:
                self.log.info("Removing {}...".format(path))
                return self._delete_file(path)
            else:
                self.log.info("Removing {}...".format(file_name))
                return self._delete_file(file_name)
        else:
            return self._delete_file(file_name)

    def delete_running_image(self):
        """ Deletes currently running image, including folder """
        self.ensure_file_removed(self.running_image_path)
        self.log.info("Running image deleted.")

    def remove_old_images(self):
        """ Deletes images on dest_filesystem that are not running """
        cmd = "request platform software package clean switch all"
        output = self.device.send_command(cmd, expect_string=r"(proceed|\#)")
        self.log.debug(output)
        if "Nothing to " in output:
            self.log.info("Found no old images to remove.")
            return True
        elif "proceed" in output:
            self.log.debug("Proceeding with package clean...")
            output += self.device.send_command("y", expect_string=r"\#")
            if "Files deleted" in output:
                self.log.info("Removed old images.")
                return True
            else:
                self.log.warning("Unexpected output from remove_old_images():"
                                 "\n{}".format(output))
                return False
        elif "Invalid input" in output:
            if self.old_images:
                for image in self.old_images:
                    if self._check_remote_file_exists(image):
                        if self.ensure_file_removed(image):
                            self.log.info("Removed successfully.")
        else:
            self.log.critical(
                "Unexpected output from remove_old_images():\n{}".format(
                    output))
            return False

    def _init_transfer(self, src_file=None, dest_file=None):
        """ Sets up file transfer session.

            Even if we don't use scp to copy
            the image, the class is still useful for checking image
            existence, free space, etc.

        """
        if src_file is None:
            src_file = self.upgrade_image_src_path
        if dest_file is None:
            dest_file = self._get_dest_path(absolute=False)
        if self.transport == "ssh":
            ft_args = {
                "ssh_conn": self.device,
                "source_file": src_file,
                "dest_file": self._get_dest_path(dest_file, absolute=False),
                "file_system": self.config["dest_filesystem"],
            }
            self.ft = FileTransfer(**ft_args)
        elif self.transport == "telnet":
            self.ft = None
            raise NotImplementedError
        else:
            raise ValueError("Transport must be ssh or telnet.")

    def request_scp_transfer(self):
        """ Begins SCP file transfer with progress """
        self.ensure_scp()
        self._init_transfer()
        source = self.upgrade_image_src_path
        dest = self.upgrade_image_dest_path
        ssh_connect_params = self.ft.ssh_ctl_chan._connect_params_dict()
        self.ft.scp_conn = self.ft.ssh_ctl_chan._build_ssh_client()
        self.ft.scp_conn.connect(**ssh_connect_params)
        with tqdm(unit="b", unit_scale=True, ascii=True) as t:
            self.progress = self._scp_tqdm(t)
            self.ft.scp_client = scp.SCPClient(
                self.ft.scp_conn.get_transport(), progress=self.progress)
            self.ft.scp_client.put(source, dest)

    def request_transfer(self):
        """ Starts file transfer and upgrade process """
        if self.transfer_proto == "scp":
            self.request_scp_transfer()
        else:
            cmd = self.upgrade_cmd
            self.log.debug("Transferring image with: {}".format(cmd))
            output = self.device.send_command(cmd, expect_string=r"filename")
            output += self.device.send_command("\n",
                                               delay_factor=100,
                                               expect_string=r"copied")
            self.device.find_prompt()

    def request_install(self):
        """ Requests automated upgrade """
        cmd = self.upgrade_cmd
        self.log.info("Installing new firmware...")
        self.log.debug("Upgrade command: {}".format(cmd))
        if self.upgrade_method == "manual":
            if self.copy_validate_image():
                self.ensure_boot_image()
                return True
            else:
                return False
        else:
            self.log.info("NOTE: No status updates possible during install. "
                          "Expect this to take about 10 minutes, and in some "
                          "cases, significantly longer.")
            output = self.device.send_command(cmd, delay_factor=100)
            self.log.debug(output)
            if "Error" in output:
                self.log.critical("Install failed:")
                for line in output.split("\n"):
                    if "Error" in line:
                        self.log.critical(line)
                return False
            elif "All software images installed" in output or "SUCCESS" in output:
                self.log.info("Install successful!")
                return True
            else:
                self.log.critical("Unexpected output from "
                                  "request_install():\n"
                                  "{}".format(output))
                return False

    def ensure_install(self):
        """ Checks if firmware install is necessary, requesting if so """
        src_file = self._get_src_path(local=True)
        self._init_transfer(src_file)
        if not self.firmware_installed:
            if self.ensure_free_space():
                if self.transfer_source == "localhost":
                    if self.request_transfer():
                        self.request_install()
                return self.request_install()
        else:
            self.log.info("New firmware already installed!")
            return True

    def ensure_free_space(self):
        """ Checks for available free space, clearing if possible """
        self.log.info("Checking free space...")
        self.upgrade_file_size = os.stat(self.upgrade_image_src_path).st_size
        # Estimate 10% decompression overhead
        comp_overhead = self.upgrade_file_size * 1.1
        if self.ft.remote_space_available() >= comp_overhead:
            self.log.info("Found enough free space!")
            return True
        else:
            self.log.info("Not enough space.")
            if self.old_images and self.can_delete_old_images:
                self.log.info("Removing old images...")
                self.remove_old_images()
                # Need to wait after deleting image before checking
                # free space, or we get an exception
                sleep(30)
                if self.ft.verify_space_available():
                    return True
            else:
                if self.can_delete_running_image:
                    self.log.info("Removing running image...")
                    self.delete_running_image()
                    sleep(30)
                    if self.ft.verify_space_available():
                        return True
                    else:
                        self.log.critical("Still not enough space."
                                          "Cannot continue.")
                        return False
                else:
                    self.log.critical("Still not enough space."
                                      "Cannot continue.")
                    return False

    def copy_validate_image(self):
        """ Copies and validates image file """
        if self.ft.verify_space_available():
            msg = "Starting transfer. Expect this to take several minutes..."
            self.log.info(msg)
            self.request_transfer()
            self.log.info("Transfer complete! Verifying hash...")
            if self.ft.verify_file():
                self.log.info("Hash verified!")
                return True
            else:
                self.log.critical(
                    "Failed hash check after transfer. Can't continue.")
                return False
        else:
            self.log.critical(
                "Not enough space for upgrade image. Can't continue.")
            return False

    def ensure_image_state(self):
        """ If possible, transfers and verifies image on device """
        self._init_transfer()
        self.log.info("Checking device for upgrade image {}...".format(
            self.upgrade_image_dest_path))
        self.upgrade_image_exists = self.ft.check_file_exists()
        if self.upgrade_image_exists:
            self.log.info("Found! Verifying hash...")
            self.upgrade_image_valid = self.ft.verify_file()
            if self.upgrade_image_valid:
                self.log.info("Hash verified!")
                return True
            else:
                self.log.warning("Failed hash check. Re-copying image.")
                return self.copy_validate_image()
        else:
            self.log.info("Not found.")
            self.ensure_free_space()
            return self.copy_validate_image()

    def ensure_old_image_removal(self):
        """ Deletes old images if requested """
        if self.config["delete_old_images"] == "always":
            return self.remove_old_images()

    def ensure_running_image_removal(self):
        """ Removes running image if requested """
        if self.config["delete_running_image"] == "always":
            if self._check_remote_file_exists(self.running_image_path):
                self.log.info("Removing running image...")
                return self.delete_running_image()

    def upgrade(self):
        """ Performs firmware upgrade """
        start_t = datetime.now()
        start = start_t.strftime("%X %Y-%m-%d")
        if self.needs_upgrade and not self.firmware_installed:
            self.log.info("Starting upgrade on {} "
                          "at {}...".format(self.hostname, start))
            if self.config["disable_exec_timeout"]:
                self.ensure_exec_timeout_disabled()
            if self.ensure_install():
                self.refresh_upgrade_state()
                self.ensure_old_image_removal()
                self.ensure_running_image_removal()
                self.ensure_reload_scheduled()
                status = "completed"
            else:
                status = "failed"
            if self.config["disable_exec_timeout"]:
                self.ensure_exec_timeout_restored()
            end_t = datetime.now()
            end = end_t.strftime("%X %Y-%m-%d")
            self.log.info("Upgrade on {} {} at {}".format(
                self.hostname, status, end))
        elif self.needs_reload and not self.reload_scheduled:
            self.ensure_reload_scheduled()
        else:
            self.log.info("No action needed.")
        end_t = datetime.now()
        self.log.info("Total time elapsed: {}".format(end_t - start_t))
コード例 #15
0
import sys

# ADJUST TO REQUIRED VALUES
target_version = '16.9.5'
image_filename = "imagetest.txt"
verification_commands = ['show run', 'show ip int br', 'show version']

def verify_version(ssh):
    show_version = ssh.send_command('show version')
    for line in show_version.splitlines():
        if line.startswith('Cisco IOS Software'):
            current_version = line.split(',')[2].split()[1]
    return current_version

def image_transfer(ssh, image_filename)
    with FileTransfer(ssh,source_file=image_filename,dest_file=image_filename) as scp_transfer:
        if scp_transfer.check_file_exists():
            print(f"File {image_filename} already exists on device.")
        else:
            if not scp_transfer.verify_space_available():
                raise ValueError("Insufficient free space available on device")
            else:
                print("Enabling SCP")
                scp_transfer.enable_scp()
                print("Transferring file...")
                scp_transfer.transfer_file()
                print("Disabling SCP")
                scp_transfer.disable_scp()

                print("Verifying file")
                if scp_transfer.verify_file():
コード例 #16
0
    def _file_copy_instance(self, src, dest=None, file_system="flash:"):
        if dest is None:
            dest = os.path.basename(src)

        fc = FileTransfer(self.native_ssh, src, dest, file_system=file_system)
        return fc
コード例 #17
0
def main():
    """Script to upgrade a Cisco ASA."""
    ip_addr = raw_input("Enter ASA IP address: ")
    my_pass = getpass()
    start_time = datetime.now()
    print ">>>> {}".format(start_time)

    #CREATE DEVICE_DICT
    net_device = {
        'device_type': 'cisco_asa',
        'ip': ip_addr,
        'username': '******',
        'password': my_pass,
        'secret': my_pass,
        'port': 22,
    }

    #CONNECT TO DEVIC_DICT
    print "\nLogging in to ASA"
    ssh_conn = ConnectHandler(**net_device)
    print

    #INITIAL ADJUSTMENT TO TRANSFER IMAGE FILE
    dest_file_system = 'disk0:'
    source_file = 'test1.txt'
    dest_file = 'test1.txt'
    alt_dest_file = 'asa825-59-k8.bin'
    scp_changed = False

    with FileTransfer(ssh_conn,
                      source_file=source_file,
                      dest_file=dest_file,
                      file_system=dest_file_system) as scp_transfer:

        #CHECK FOR IF ALREADY EXISTS AND SUFFICIENT SPACE
        if not scp_transfer.check_file_exists():
            if not scp_transfer.verify_space_available():
                raise ValueError(
                    "Insufficient space available on remote device")

            print "Enabling SCP"
            output = asa_scp_handler(ssh_conn, mode='enable')
            print output

            print "\nTransferring file\n"
            scp_transfer.transfer_file()

            print "Disabling SCP"
            output = asa_scp_handler(ssh_conn, mode='disable')
            print output

        print "\nVerifying file"
        if scp_transfer.verify_file():
            print "Source and destination MD5 matches"
        else:
            raise ValueError(
                "MD5 failure between source and destination files")

    print "\nSending boot commands"
    full_file_name = "{}/{}".format(dest_file_system, alt_dest_file)
    boot_cmd = 'boot system {}'.format(full_file_name)
    output = ssh_conn.send_config_set([boot_cmd])
    print output

    print "\nVerifying state"
    output = ssh_conn.send_command('show boot')
    print output

    #UNCOMMENT TO PERFORM WR MEM AND RELOAD
    print "\nWrite mem and reload"
    output = ssh_conn.send_command_expect('write mem')
    output += ssh_conn.send_command('reload')
    output += ssh_conn.send_command('y')
    print output

    #TIME TO EXECUTE
    print "\n>>>> {}".format(datetime.now() - start_time)
    print
コード例 #18
0
def upgrade_asa(device,
                image_type,
                image_location,
                dest_drive="disk0:",
                reboot=False,
                backup_config=False,
                backup_location=None):
    """
    Method to upgrade a Cisco ASA OS version or ASDM Version

    :param device: Device to upgrade
    :type device: Device
    :param image_type: Image file to be uploaded - ASDM or ASA
    :type image_type: str
    :param image_location: location of the source image file on local computer
    :type image_location: str
    :param dest_drive: destination drive that the image file will be uploaded. Default: "Disk0:"
    :type dest_drive: str
    :param reboot: indicates if a reboot is required
    :type reboot: bool
    :param backup_config: indicates if a config backup is required
    :type backup_config: bool
    :param backup_location: location to save backups
    :type backup_location: str
    :return: Device with updated attributes
    """

    try:

        connection = DeviceHelper.connect_to_device(
            ipaddr=device.ip_address,
            credentials=device.credentials,
            enable_mode=True,
            device_type=["cisco_asa"])

        device.connected = True

        prompt = connection.find_prompt()

        device.name = prompt[0:(len(prompt) - 1)]

        # Backup config
        if backup_config:
            _logger.info(f"{device.ip_address} - Starting Config Backup")

            config = connection.send_command("sh run")
            DeviceHelper.backup_config(config, backup_location, device.name)

            _logger.info(f"{device.ip_address} - Completed Config")

        image_file_name = Path(image_location).name

        # Check if scp is enabled
        output = connection.send_command("sh run | i ssh scopy enable")

        if output.lower() is "ssh copy enable":
            _logger.debug(f"{device.ip_address} - SCP enabled")
            scp_enabled = True
        else:
            _logger.debug(f"{device.ip_address} - SCP not enabled. Enabling")
            scp_enabled = False
            # enable SCP
            connection.send_config_set(["ssh scopy enable"])

        with FileTransfer(connection,
                          source_file=image_location,
                          dest_file=image_file_name,
                          file_system=dest_drive) as scp:
            _logger.debug(
                f"{device.ip_address} - Starting to copy image to device")
            # check if there is free space
            if scp.verify_space_available():
                # Transfer file
                scp.transfer_file()

                # verify file
                if not scp.verify_file():
                    device.error = "File transfer verifier failed"
                    _logger.info(f"{device.ip_address} - file verifier failed")
                else:
                    device.file_uploaded = True
                    _logger.info(
                        f"{device.ip_address} - Not enough space to image")

            else:
                device.error = "Not enough space to upload file"

        # disable scp if it was not enabled originally
        if not scp_enabled:
            connection.send_config_set(["no ssh scopy enable"])
            _logger.debug(f"{device.ip_address} - Disabling SCP")

        # if file was uploaded set it as the new image
        if device.file_uploaded:

            asa_file_path = f"{dest_drive}/{image_file_name}"

            if image_type.lower() == "asa":
                config = f"boot system {asa_file_path}"
                _logger.debug(
                    f"{device.ip_address} - setting ASA boot image to : {asa_file_path}"
                )
                connection.send_config_set([config])
            elif image_type.lower() == "asdm":
                config = f"asdm image {asa_file_path}"
                _logger.debug(
                    f"{device.ip_address} - setting ASDM image to : {asa_file_path}"
                )
                connection.send_config_set([config])

            # save config
            _logger.debug(f"{device.ip_address} - Saving Config")
            connection.save_config()

            # reboot if set
            if reboot:
                _logger.info(f"{device.ip_address} - Rebooting device")
                connection.send_confg_set(["reboot"])
                connection.send_confg_set(["y"])

                # wait 5 mins to and check
                time.sleep(300)

                device.successfully_rebooted = DeviceHelper.ping(
                    device.ip_address)

                if device.successfully_rebooted:
                    _logger.info(f"{device.ip_address} - Device Rebooted")
                else:
                    _logger.warning(
                        f"{device.ip_address} - Device not rebooted")
                return device

    except ConnectionException as e:
        device.connected = False
        _logger.error(f"{device.ip_address} - Connection Exception")
        _logger.error(f"{e}")
        return device
    except ValueError as e:
        device.connected = False
        _logger.error(f"{device.ip_address} - Value Error")
        _logger.error(f"{e}")
        return device
コード例 #19
0
def main():
    '''
    Ansible module to transfer files to Cisco IOS devices.
    '''

    module = AnsibleModule(
        argument_spec=dict(
            host=dict(required=True),
            port=dict(default=22, required=False),
            username=dict(required=True),
            password=dict(required=True),
            source_file=dict(required=True),
            dest_file=dict(required=True),
            dest_file_system=dict(required=False, default='flash:'),
            enable_scp=dict(required=False, default=False, choices=BOOLEANS),
            overwrite=dict(required=False, default=True, choices=BOOLEANS),
        ),
        supports_check_mode=True
    )

    net_device = {
        'device_type': 'cisco_ios',
        'ip': module.params['host'],
        'username': module.params['username'],
        'password': module.params['password'],
        'port': int(module.params['port']),
        'verbose': False,
    }

    ssh_conn = ConnectHandler(**net_device)
    source_file = module.params['source_file']
    dest_file = module.params['dest_file']
    dest_file_system = module.params['dest_file_system']
    enable_scp = module.boolean(module.params['enable_scp'])
    overwrite = module.boolean(module.params['overwrite'])
    check_mode = module.check_mode
    scp_changed = False

    with FileTransfer(ssh_conn, source_file, dest_file, file_system=dest_file_system) as scp_transfer:

        # Check if file already exists and has correct MD5
        if scp_transfer.check_file_exists() and scp_transfer.compare_md5():
            module.exit_json(msg="File exists and has correct MD5", changed=False)

        if not overwrite and scp_transfer.check_file_exists():
            module.fail_json(msg="File already exists and overwrite set to false")

        if check_mode:
            if not scp_transfer.verify_space_available():
                module.fail_json(msg="Insufficient space available on remote device")

            module.exit_json(msg="Check mode: file would be changed on the remote device",
                             changed=True)

        # Verify space available on remote file system
        if not scp_transfer.verify_space_available():
            module.fail_json(msg="Insufficient space available on remote device")

        # Transfer file
        if enable_scp:
            scp_transfer.enable_scp()
            scp_changed = True

        scp_transfer.transfer_file()
        if scp_transfer.verify_file():
            if scp_changed:
                scp_transfer.disable_scp()
            module.exit_json(msg="File successfully transferred to remote device",
                             changed=True)

        module.fail_json(msg="File transfer to remote device failed")
コード例 #20
0
def main():
    """Script to upgrade a Cisco ASA."""
    try:
        ip_addr = raw_input("Enter ASA IP address: ")
    except NameError:
        ip_addr = input("Enter ASA IP address: ")
    my_pass = getpass()
    start_time = datetime.now()
    print(">>>> {}".format(start_time))

    net_device = {
        'device_type': 'cisco_asa',
        'ip': ip_addr,
        'username': '******',
        'password': my_pass,
        'secret': my_pass,
        'port': 22,
    }

    print("\nLogging in to ASA")
    ssh_conn = ConnectHandler(**net_device)
    print()

    # ADJUST TO TRANSFER IMAGE FILE
    dest_file_system = 'disk0:'
    source_file = 'test1.txt'
    dest_file = 'test1.txt'
    alt_dest_file = 'asa825-59-k8.bin'

    with FileTransfer(ssh_conn,
                      source_file=source_file,
                      dest_file=dest_file,
                      file_system=dest_file_system) as scp_transfer:

        if not scp_transfer.check_file_exists():
            if not scp_transfer.verify_space_available():
                raise ValueError(
                    "Insufficient space available on remote device")

            print("Enabling SCP")
            output = asa_scp_handler(ssh_conn, mode='enable')
            print(output)

            print("\nTransferring file\n")
            scp_transfer.transfer_file()

            print("Disabling SCP")
            output = asa_scp_handler(ssh_conn, mode='disable')
            print(output)

        print("\nVerifying file")
        if scp_transfer.verify_file():
            print("Source and destination MD5 matches")
        else:
            raise ValueError(
                "MD5 failure between source and destination files")

    print("\nSending boot commands")
    full_file_name = "{}/{}".format(dest_file_system, alt_dest_file)
    boot_cmd = 'boot system {}'.format(full_file_name)
    output = ssh_conn.send_config_set([boot_cmd])
    print(output)

    print("\nVerifying state")
    output = ssh_conn.send_command('show boot')
    print(output)

    # UNCOMMENT TO PERFORM WR MEM AND RELOAD
    # print("\nWrite mem and reload")
    # output = ssh_conn.send_command_expect('write mem')
    # output += ssh_conn.send_command('reload')
    # output += ssh_conn.send_command('y')
    # print(output)

    print("\n>>>> {}".format(datetime.now() - start_time))
    print()
コード例 #21
0
def main():
    arch = raw_input(
        "Is this a standalone or pair of ASAs [standalone|pair]? ")

    #gather variables and run upgrade for standalone architecture
    if arch == "standalone":
        ip_addr = raw_input(
            "Please enter the IP address or hostname of the ASA: ")
        user = "******"
        my_pass = getpass()
        start_time = datetime.now()
        image_location = 'disk0:'
        image_location = raw_input(
            "Enter the image location [disk0:]: ") or "disk0:"
        source_image = raw_input("Enter the image file name: ")
        dest_image = source_image
        dest_image = raw_input("Enter the destination image [" + dest_image +
                               "]: ") or dest_image
        print ">>>> {}".format(start_time)

        standalone_asa = {
            'device_type': 'cisco_asa',
            'ip': ip_addr,
            'username': user,
            'password': my_pass,
            'secret': my_pass,
            'port': 22,
        }

        #connect and login to ASA
        print "\nConnecting and logging in to %s " % ip_addr
        ssh_conn = ConnectHandler(**standalone_asa)

        #verify there is enough space to transfer file, if not prompt for deletion
        with FileTransfer(ssh_conn,
                          source_file=source_image,
                          dest_file=dest_image,
                          file_system=image_location) as scp_transfer:

            if scp_transfer.check_file_exists() == False:
                while scp_transfer.verify_space_available() == False:
                    make_space = raw_input(
                        "Insufficient space available on disk0:, "
                        "would you like to make more? [yes|no] [yes]: "
                    ) or 'yes'
                    if make_space == 'yes':
                        dir_disk = ssh_conn.send_command('dir disk0:')
                        print "\nOutput from dir disk0:"
                        print dir_disk
                        file_to_delete = raw_input(
                            "Enter file to be deleted: ")
                        ssh_conn.send_command('delete disk0:/%s' %
                                              file_to_delete)

                    if make_space == 'no':
                        sys.exit(
                            "\nExiting script, please go make space on the ASA "
                            "before proceeding")

                    scp_transfer.verify_space_available()

                #Verify SCP is enabled, if not enable it
                print "\nEnabling SCP..."
                output = asa_scp_handler(ssh_conn, mode='enable')
                print output

                #transfer the file to the ASA
                print "\nTransferring file to ASA..."
                scp_transfer.transfer_file()

                #Disable SCP
                print "\nDisabling SCP..."
                output = asa_scp_handler(ssh_conn, mode='disable')
                print output

                #Verify the file
                print "\Verifying the file..."
                if scp_transfer.verify_file():
                    print "\nSource and Destination File MD5 match!"
                else:
                    raise ValueError(
                        "\nMD5 failure between source and destination file!")

                full_file_name = "{}/{}".format(image_location, dest_image)
                boot_cmd = 'boot system {}'.format(full_file_name)
                output = ssh_conn.send_config_set([boot_cmd])
                print output

                #Verify "show boot"
                print "\nVerifying boot variables..."
                output = ssh_conn.send_command('show boot')
                print output

                #write mem and reload the ASA
                print "\nWrite mem and reload"
                output = ssh_conn.send_command_expect('write mem')
                output += ssh_conn.send_command('reload')
                output += ssh_conn.send_command('y')
                print output

            elif scp_transfer.check_file_exists() == True:
                #Set boot commands
                full_file_name = "{}/{}".format(image_location, dest_image)
                boot_cmd = 'boot system {}'.format(full_file_name)
                output = ssh_conn.send_config_set([boot_cmd])
                print output

                #Verify "show boot"
                print "\nVerifying boot variables..."
                output = ssh_conn.send_command('show boot')
                print output

                #write mem and reload the ASA
                print "\nWrite mem and reload"
                output = ssh_conn.send_command_expect('write mem')
                output += ssh_conn.send_command('reload')
                output += ssh_conn.send_command('y')
                print output

        #wait for 5 minutes and verify the system is running on the new code
        time.sleep(300)
        ssh_conn = ConnectHandler(**standalone_asa)
        show_ver = ssh_conn.send_command('show_version')
        show_ver_lines = show_ver.split("\n")
        for line in show_ver_lines:
            if "System image" in line:
                print "\n" + line

        print "\n>>>> {}".format(datetime.now() - start_time)
        print

    if arch == "pair":
        ip_addr_pri = raw_input(
            "Please enter the IP address or hostname of the primary ASA: ")
        ip_addr_sec = raw_input(
            "Please enter the IP address or hostname of the secondary ASA: ")
        user = getuser()
        my_pass = getpass()
        start_time = datetime.now()
        image_location = 'disk0:'
        image_location = raw_input(
            "Enter the image location [disk0:]: ") or "disk0:"
        source_image = raw_input("Enter the image file name: ")
        dest_image = source_image
        dest_image = raw_input("Enter the destination image [" + dest_image +
                               "]: ") or dest_image
        print ">>>> {}".format(start_time)

        #primary_asa = {
        #    'device_type': 'cisco_asa',
        #    'ip': ip_addr_pri,
        #    'username': user,
        #    'password': my_pass,
        #    'secret': my_pass,
        #    'port': 22,
        #}

        secondary_asa = {
            'device_type': 'cisco_asa',
            'ip': ip_addr_sec,
            'username': user,
            'password': my_pass,
            'secret': my_pass,
            'port': 22,
        }

        asa_pair = [secondary_asa, secondary_asa]

        for asa in asa_pair:

            #connect and login to secondary ASA
            print "\nConnecting and logging in to %s " % asa
            ssh_conn = ConnectHandler(**asa)

            #verify that this is the secondary ASA
            print "\nVerifying this is the secondary ASA..."
            failover = ssh_conn.send_command("show failover")
            failover_lines = failover.split("\n")
            for line in failover_lines:
                if ("This host:" in line) and ("Standby Ready" in line):
                    print "\nSecondary host verified"
                elif ("This host:" in line) and ("Active" in line):
                    print "\n This is the primary ASA, failing over..."
                    ssh_conn.send_command('failover active')

            #verify there is enough space to transfer file, if not prompt for deletion
            with FileTransfer(ssh_conn,
                              source_file=source_image,
                              dest_file=dest_image,
                              file_system=image_location) as scp_transfer:

                if scp_transfer.check_file_exists() == False:
                    while scp_transfer.verify_space_available() == False:
                        make_space = raw_input(
                            "Insufficient space available on disk0:, "
                            "would you like to make more? [yes|no] [yes]: "
                        ) or 'yes'
                        if make_space == 'yes':
                            dir_disk = ssh_conn.send_command('dir disk0:')
                            print "\nOutput from dir disk0:"
                            print dir_disk
                            file_to_delete = raw_input(
                                "Enter file to be deleted: ")
                            ssh_conn.send_command('delete disk0:/%s' %
                                                  file_to_delete)

                        if make_space == 'no':
                            sys.exit(
                                "\nExiting script, please go make space on the ASA "
                                "before proceeding")

                        scp_transfer.verify_space_available()

                    #Verify SCP is enabled, if not enable it
                    print "\nEnabling SCP..."
                    output = asa_scp_handler(ssh_conn, mode='enable')
                    print output

                    #transfer the file to the ASA
                    print "\nTransferring file to ASA..."
                    scp_transfer.transfer_file()

                    #Disable SCP
                    print "\nDisabling SCP..."
                    output = asa_scp_handler(ssh_conn, mode='disable')
                    print output

                    #Verify the file
                    print "\Verifying the file..."
                    if scp_transfer.verify_file():
                        print "\nSource and Destination File MD5 match!"
                    else:
                        raise ValueError(
                            "\nMD5 failure between source and destination file!"
                        )

                elif scp_transfer.check_file_exists() == True:
                    #Set boot commands
                    full_file_name = "{}/{}".format(image_location, dest_image)
                    boot_cmd = 'boot system {}'.format(full_file_name)
                    output = ssh_conn.send_config_set([boot_cmd])
                    print output

                    #Verify "show boot"
                    print "\nVerifying boot variables..."
                    output = ssh_conn.send_command('show boot')
                    print output

                    #write mem and reload the ASA
                    print "\nWrite mem and reload"
                    output = ssh_conn.send_command_expect('write mem')
                    output += ssh_conn.send_command('reload')
                    output += ssh_conn.send_command('y')
                    print output

            #wait for 5 minutes and verify the system is running on the new code
            time.sleep(300)
            ssh_conn = ConnectHandler(**asa)
            show_ver = ssh_conn.send_command('show_version')
            show_ver_lines = show_ver.split("\n")
            for line in show_ver_lines:
                if "System image" in line:
                    print "\n" + line

            #Make the secondary ASA primary and verify
            print "\nFailing over ASA pair..."
            ssh_conn.send_command('failover active')
            print "\nVerifying this is the primary ASA..."
            failover = ssh_conn.send_command("show failover")
            failover_lines = failover.split("\n")
            for line in failover_lines:
                if ("This host:" in line) and ("Active" in line):
                    print("\nFailover successful...")

        print "\n>>>> {}".format(datetime.now() - start_time)
        print
コード例 #22
0
ファイル: ios_upgrade.py プロジェクト: yongkim/netmiko
def main():
    # Script to login to a Cisco IOS device
    ip_addr = input("Enter Cisco device IP address: ")
    my_pass = getpass()
    start_time = datetime.now()

    log_file = open("logging.txt", "w")

    log_file.write("Starting...")

    print(">>>> {}".format(start_time))

    net_device = {
        'device_type': 'cisco_ios',
        'ip': ip_addr,
        'username': '******',
        'password': my_pass,
        'secret': my_pass,
        'port': 22,
    }

    print("\nLogging in to Cisco Device")
    ssh_conn = ConnectHandler(**net_device)
    print

    # Show current version of the software
    print("\nView software version")
    output = ssh_conn.send_command('show ver')
    print(output)

    # This can be used to send any command/configs
    """output = ssh_conn.send_command ('show run | inc logging')
        print(output)

        buffer_number = input("Enter logging buffer amount: ")
        config_commands = 'logging buffered {}'.format(buffer_number)
        output = ssh_conn.send_config_set([config_commands])
        print(output)

        output = ssh_conn.send_command('show run | inc logging')
        print(output)"""

    # Image file settings
    dest_file_system = 'bootflash:'
    source_file = 'C:\\Users\\yongk\\Documents\\Images\\Cisco\\asr1000-universalk9.16.04.01.SPA.bin'  # Use absolute path
    dest_file = 'asr1000-universalk9.16.04.01.SPA.bin'

    with FileTransfer(ssh_conn,
                      source_file=source_file,
                      dest_file=dest_file,
                      file_system=dest_file_system) as scp_transfer:
        if not scp_transfer.check_file_exists():
            if not scp_transfer.verify_space_available():
                raise ValuError(
                    "Insufficient space available on remote device")

            print("Transferring file\n")
            scp_transfer.transfer_file()

        print("\nVerifying file")
        if scp_transfer.verify_file():
            print("Source and destination MD5 hash match")
        else:
            raise ValueError(
                "MD5 hash between source and destination do not match")

    # Set the boot configuration
    print("\nSending boot commands")
    full_file_name = "{}/{}".format(dest_file_system, dest_file)
    boot_cmd = "boot system flash {}".format(full_file_name)
    output = ssh_conn.send_config_set([boot_cmd])
    print(output)

    # Save the configuration
    print("\nWrite mem")
    output = ssh_conn.send_command('write mem')
    print(output)

    # Verify boot parameters
    print("\nVerifying state")
    output = ssh_conn.send_command('show boot')
    print(output)

    # Reboot
    print("\nReload")
    output = ssh_conn.send_command_timing('reload')
    output += ssh_conn.send_command_timing('y')
    print(output)

    print("\n>>>> Time taken: {}".format(datetime.now() - start_time))
    print("\n")

    log_file.close()
コード例 #23
0
from getpass import getpass
from netmiko import ConnectHandler, FileTransfer
def main():
	net_device = {
        'device_type': 'cisco_ios',
        'ip': '10.101.14.1',
        'username': '******',
        'password': '******',
    }

    print("Logging in to Router\n")
    ssh_conn = ConnectHandler(**net_device)
    print()
    # GET OPERATION
    source_file = 'config_backup.txt'
    dest_file = 'config_backup.txt'
	dest_file_system = 'flash:'
    with FileTransfer(ssh_conn,
                 source_file=source_file,
                 dest_file=dest_file,
                 file_system=dest_file_system,
                 direction='get') as scp_transfer:
        scp_transfer.get_file()
        print("File transfer completed\n\n")

if __name__ == "__main__":
    main()
コード例 #24
0
    def update_ios(self):
        # Test if active image is already the compliant image for this model and update the compliance variable
        if self.current_image == self.compliant_image:
            self.compliant = True

        if self.compliant:
            print "Device %s is already compliant, skipping...." % self.hostname

        elif self.username == None:
            print "No saved password for %s, skipping..." % self.hostname

        else:
            print "Device %s is not compliant, begin uploading file" % self.hostname

            # Initiate SSH Connection to device
            device = {
                'device_type': 'cisco_ios',
                'ip': self.ip_address,
                'username': self.username,
                'password': self.password
            }
            ssh_conn = ConnectHandler(**device)

            with FileTransfer(ssh_conn,
                              source_file=self.compliant_image,
                              dest_file=self.compliant_image,
                              file_system=self.filesystem) as scp_transfer:

                if not scp_transfer.check_file_exists():
                    if not scp_transfer.verify_space_available():
                        raise ValueError(
                            "Insufficient space available on remote device")

                    print "Enabling SCP for device %s" % self.hostname
                    output = ios_scp_handler(ssh_conn, mode='enable')
                    output += ssh_conn.send_config_set(
                        ['line vty 0 4', 'exec-timeout 0 0'])
                    print output

                    print "\nTransferring file to device %s\n" % self.hostname
                    scp_transfer.transfer_file()

                    # print "Disabling SCP"
                    # output = ios_scp_handler(ssh_conn, mode='disable')
                    # print output

                print "\nVerifying file on device %s" % self.hostname
                if scp_transfer.verify_file():
                    print "Source and destination MD5 matches"
                    self.compliant = True
                    self.reload_pending = True
                else:
                    raise ValueError(
                        "MD5 failure between source and destination files")

            print "\nSending boot commands & saving configuration"
            # Clear existing Boot Variable
            output = ssh_conn.send_config_set(['no boot system'])
            full_file_name = "{}{}".format(self.filesystem,
                                           self.compliant_image)
            boot_cmd = 'boot system {}'.format(full_file_name)
            output += ssh_conn.send_config_set([boot_cmd])
            output += ssh_conn.send_command('wr')
            print output

            ssh_conn.send_command('show run | inc boot system')

            print "Boot variable set for device %s - %s" % (self.hostname,
                                                            output)

            # If IOS Upload has succeeded, mark the device as compliant to prevent future upgrades prior to device rebooting and the active image being compliant.
            if self.compliant_image in output:
                self.compliance = True
                self.reload_pending = True
コード例 #25
0
    def scp_file(self, source_file, dest_file, file_system):
        '''
        SCP file to remote device

        Return (status, msg)
        status = boolean
        msg = details on what happened
        '''
        # Will automaticall enable SCP on remote device
        enable_scp = True
        debug = False

        with FileTransfer(self.device,
                          source_file=source_file,
                          dest_file=dest_file,
                          file_system=file_system) as scp_transfer:

            if debug:
                base_time = datetime.now()
                print("check1: {}".format(base_time))
            # Check if file already exists and has correct MD5
            if scp_transfer.check_file_exists() and scp_transfer.compare_md5():
                msg = "File already exists and has correct MD5: no SCP needed"
                return (True, msg)
            if not scp_transfer.verify_space_available():
                msg = "Insufficient space available on remote device"
                return (False, msg)

            if debug:
                print(
                    "check2 (file already exists, correct md5, space available)"
                )
                print("Time delta: {}".format(datetime.now() - base_time))
                base_time = datetime.now()
            if enable_scp:
                scp_transfer.enable_scp()

            if debug:
                print("check3 (enable_scp)")
                print("Time delta: {}".format(datetime.now() - base_time))
                base_time = datetime.now()
            # Transfer file
            scp_transfer.transfer_file()
            if debug:
                print("check4 (transfer_file)")
                print("Time delta: {}".format(datetime.now() - base_time))
                base_time = datetime.now()

            # Compares MD5 between local-remote files
            if scp_transfer.verify_file():
                msg = "File successfully transferred to remote device"
                if debug:
                    print("check5: {}".format(datetime.now()))
                return (True, msg)
            else:
                msg = "File transfer to remote device failed"
                return (False, msg)
            if debug:
                print("check5 (verify_file)")
                print("Time delta: {}".format(datetime.now() - base_time))

            return (False, '')
コード例 #26
0
ファイル: upload.py プロジェクト: sourjp/lab-network
#!/usr/bin/env python3
from netmiko import ConnectHandler, FileTransfer


def create_conn(port: str) -> dict:
    return {
        "device_type": "juniper_junos_ssh",
        "host": "localhost",
        "username": "******",
        "password": "******",
        "port": port,
    }


if __name__ == "__main__":
    vsrx1 = create_conn("2201")
    vsrx1_conn = ConnectHandler(**vsrx1)

    with FileTransfer(vsrx1_conn,
                      source_file="load_conf.conf",
                      dest_file="load_conf.conf") as scp_transfer:
        if not scp_transfer.check_file_exists():
            if not scp_transfer.verify_space_available():
                raise ValueError(
                    "Insufficient space available on remote device")

            scp_transfer.transfer_file()