Exemple #1
0
def device_recovery(start,
                    device,
                    console_activity_pattern,
                    golden_image=None,
                    break_count=10,
                    timeout=600,
                    recovery_password=None,
                    tftp_boot=None,
                    item=None,
                    **kwargs):
    ''' A method for starting Spawns and handling the device statements during recovery
        Args:
            device ('obj'): Device object
            start ('obj'): Start method under device object
            console_activity_pattern ('str'): Pattern to send the break at
            golden_image ('dict'): information to load golden image on the device
            break_count ('int'): Number of sending break times
            timeout ('int'): Recovery process timeout
            recovery_password ('str'): Device password after recovery
        Returns:
            None
    '''

    # Set a target for each recovery session
    # so it's easier to distinguish expect debug logs on the console.
    device.instantiate(connection_timeout=timeout)

    # Get device console port information
    last_word_in_start_match = re.match('.*\s(\S+)$', start)
    last_word_in_start = last_word_in_start_match.group(1) \
        if last_word_in_start_match else ""

    # Set target
    target = "{}_{}".format(device.hostname, last_word_in_start)

    logfile = log.handlers[1].logfile if len(log.handlers) >= 2 else None
    spawn = Spawn(spawn_command=start,
                  settings=device.cli.settings,
                  target=target,
                  log=log,
                  logfile=logfile)

    break_dialog = BreakBootDialog()
    break_dialog.add_statement(Statement(pattern=console_activity_pattern,
                                         action=sendbrk_handler,
                                         args={'break_count': break_count},
                                         loop_continue=True,
                                         continue_timer=False),
                               pos=0)
    break_dialog.dialog.process(spawn, timeout=timeout)

    dialog = RommonDialog()
    dialog.dialog.process(spawn,
                          timeout=timeout,
                          context={
                              'boot_image': golden_image[0],
                              'break_count': break_count,
                              'password': recovery_password
                          })
    spawn.close()
Exemple #2
0
def golden_recovery(start,
                    device,
                    console_activity_pattern,
                    golden_image=None,
                    break_count=10,
                    timeout=600,
                    recovery_password=None,
                    tftp_boot=None,
                    item=None):
    ''' A method for starting Spawns and handling the device statements during recovery
        Args:
            device ('obj'): Device object
            start ('obj'): Start method under device object
            console_activity_pattern ('str'): Pattern to send the break at
            golden_image ('str'): Image to load the device with
            break_count ('int'): Number of sending break times
            timeout ('int'): Recovery process timeout
            recovery_password ('str'): Device password after recovery
        Returns:
            None
    '''

    break_dialog = BreakBootDialog()
    break_dialog.add_statement(Statement(pattern=console_activity_pattern,
                                         action=sendbrk_handler,
                                         args={'break_count': break_count},
                                         loop_continue=True,
                                         continue_timer=False),
                               pos=0)

    # Set a target for each recovery session
    # so it's easier to distinguish expect debug logs on the console.
    device.instantiate(connection_timeout=timeout)

    # Get device console port information
    last_word_in_start_match = re.match('.*\s(\S+)$', start)
    last_word_in_start = last_word_in_start_match.group(1) \
        if last_word_in_start_match else ""

    # Set target
    target = "{}_{}".format(device.hostname, last_word_in_start)

    spawn = Spawn(start,
                  settings=device.cli.settings,
                  target=target,
                  log=log,
                  logfile=log.handlers[1].logfile)

    if 'system' not in golden_image:
        raise Exception("System image has not been provided in the "
                        "'device_recovery' section of the clean YAML")

    dialog = RommonDialog()
    dialog.dialog.process(spawn,
                          context={
                              'sys': golden_image.get('system'),
                              'password': recovery_password
                          },
                          timeout=timeout)
    spawn.close()
def tftp_recovery_worker(start, device, console_activity_pattern, tftp_boot=None,
                         break_count=10, timeout=600, recovery_password=None,
                         golden_image=None, item=None):
    ''' A method for starting Spawns and handling the device statements during recovery
        Args:
            device ('obj'): Device object
            start ('obj'): Start method under device object
            console_activity_pattern ('str'): Pattern to send the break at
            tftp_boot ('dict'): Tftp boot information
            break_count ('int'): Number of sending break times
            timeout ('int'): Recovery process timeout
            recovery_password ('str'): Device password after recovery
        Returns:
            None
    '''

    log.info('Set the device in rommon and load the device with tftp boot')
    break_dialog = BreakBootDialog()
    break_dialog.add_statement(Statement(pattern=console_activity_pattern,
                                         action=sendbrk_handler,
                                         args={'break_count':break_count},
                                         loop_continue=True,
                                         continue_timer=False), pos=0)

    # Set a target for each recovery session
    # so it's easier to distinguish expect debug logs on the console.
    device.instantiate(connection_timeout=timeout)

    # Get device console port information
    last_word_in_start_match = re.match('.*\s(\S+)$', start)
    last_word_in_start = last_word_in_start_match.group(1) \
        if last_word_in_start_match else ""

    # Set target
    target = "{}_{}".format(device.hostname, last_word_in_start)

    spawn = Spawn(spawn_command=start,
                  settings=device.cli.settings,
                  target=target,
                  log=log,
                  logfile=log.handlers[1].logfile)

    rommon_dialog = TftpRommonDialog()
    rommon_dialog.hostname_statement(device.hostname)
    rommon_dialog.dialog.process(spawn, timeout=timeout,
                                 context={'device_name': device.name,
                                          'ip': tftp_boot['ip_address'][item],
                                          'password': recovery_password,
                                          'subnet_mask': tftp_boot['subnet_mask'],
                                          'gateway': tftp_boot['gateway'],
                                          'image': tftp_boot['image'],
                                          'tftp_server': tftp_boot['tftp_server'],
                                          'hostname': device.hostname})

    spawn.close()
Exemple #4
0
def recovery_worker(start,
                    device,
                    console_activity_pattern,
                    break_count=10,
                    timeout=600,
                    *args,
                    **kwargs):
    """ Starts a Spawn and processes device dialogs during recovery of a device

        Args:
            start (obj): Start method under device object
            device (obj): Device object
            console_activity_pattern (str): Pattern to send the break at
            break_count (int, optional): Number of break commands to send. Defaults to 10.
            timeout (int, optional): Recovery process timeout. Defaults to 600.

        Returns:
            None
    """
    def breakboot(spawn, break_count):
        """ Breaks the booting process on a device

            Args:
                spawn (obj): Spawn connection object
                break_count (int): Number of break commands to send

            Returns:
                None
        """

        log.info("Found the console_activity_pattern! "
                 "Breaking the boot process")

        for _ in range(break_count):
            # '\x03' == <ctrl>+C
            spawn.send("\x03")
            time.sleep(1)

    # Set a target for each recovery session
    # so it's easier to distinguish expect debug logs on the console.
    device.instantiate(connection_timeout=timeout)

    # Get device console port information
    last_word_in_start_match = re.match('.*\s(\S+)$', start)
    last_word_in_start = last_word_in_start_match.group(1) \
        if last_word_in_start_match else ""

    # Set target
    target = "{}_{}".format(device.hostname, last_word_in_start)

    if len(log.handlers) >= 2:
        logfile = log.handlers[1].logfile
    else:
        logfile = None

    spawn = Spawn(spawn_command=start,
                  settings=device.cli.settings,
                  target=target,
                  log=log,
                  logfile=logfile)

    # Stop the device from booting
    break_dialog = BreakBootDialog()
    break_dialog.add_statement(Statement(pattern=console_activity_pattern,
                                         action=breakboot,
                                         args={'break_count': break_count},
                                         loop_continue=True,
                                         continue_timer=False),
                               pos=0)
    break_dialog.dialog.process(spawn, timeout=timeout)

    # Recover the device using the specified method
    if kwargs.get('golden_image'):
        device_recovery(spawn, timeout, *args, **kwargs)
    elif kwargs.get('tftp_boot'):
        tftp_device_recovery(spawn, timeout, device, *args, **kwargs)

    spawn.close()
        # this is first entry hence we need to send login password.
        session.flag = True
        spawn.sendline(loginpw)
    else:
        # if we come here that means it is second entry and here.
        # we need to send the enable password.
        spawn.sendline(enablepw)


# construct the dialog.
# here we see how shorthand notation can make the code look leaner.
d = Dialog([
    [r'enter to continue \.\.\.', 'sendline()', None, True, False],
    [r'username:\s?$', "sendline(admin)", None, True, False],
    [
        r'password:\s?$', send_passwd, {
            'enablepw': 'lablab',
            'loginpw': 'lab'
        }, True, False
    ],
    [disable_prompt, 'sendline(enable)', None, True, False],
    [enable_prompt, None, None, False, False],
])

s = Spawn(router_command)

# at this stage we are anticipating the program to wait for a new line
d.process(s)

s.close()
def is_available(host, port, user=DEFAULT_USERNAME, pwd=DEFAULT_PASSWORD,
                 prompt='firepower login:'******'telnet'):
    """Checks whether device is available.

    :param host: Ip of the device/console
    :param port: console port
    :param user: username
    :param pwd: password
    :param prompt: expected prompt
    :param access: type of access: telnet or ssh
    :return: True if device is available, False if it's not

    """

    if user == DEFAULT_USERNAME:
        user = get_username(user)
    if pwd == DEFAULT_PASSWORD:
        pwd = get_password(pwd)

    VALID_PROMPTS.append(prompt)
    if access == 'telnet':
        spawn_id = Spawn('telnet {} {}\n'.format(host, port))
        try:
            spawn_id.expect(
                "Connected to.*Escape character is '\^\]'\..*Username: "******"Connected to.*Escape character is '\^\]'\..*Username: "******"Password: "******"Password OK.*")
        except TimeoutError:
            LOGGER.debug("'Password OK' message did not appear ... continue")
        spawn_id.sendline('')
        try:
            __wait_for_rommon(spawn_id, 900)
        except:
            LOGGER.info("\nFailed to get a valid prompt")
            spawn_id.close()
            return False
        LOGGER.info('%s on port %d is available' % (host, port))
        spawn_id.close()
    elif access == 'ssh':
        try:
            if port is not 22:
                clear_line(host=host, port=port % 100, access='ssh', user=user, pwd=pwd, en_password=pwd)
            spawn_id = Spawn('ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -l {} -p {} {}'.
                             format(user, port, host))
            d1 = Dialog([
                ['continue connecting (yes/no)?', 'sendline(yes)', None, True, False],
                ['(P|p)assword:', 'sendline({})'.format(pwd), None, False, False],
                ['Connection refused', None, None, False, False],
            ])
            d1.process(spawn_id, timeout=60)
            try:
                spawn_id.expect("Password OK.*")
            except:
                pass
            spawn_id.sendline()
            time.sleep(10)
            try:
                __wait_for_rommon(spawn_id, 900)
            except:
                LOGGER.info("\nFailed to get a valid prompt")
                spawn_id.close()
                return False
            LOGGER.info('%s on port %d is available' % (host, port))
            spawn_id.close()
        except:
            return False
    else:
        raise RuntimeError('Device can be accessed only by telnet or ssh')

    return True
def clear_line(host, port, user=DEFAULT_USERNAME, pwd=DEFAULT_PASSWORD, prompt='#',
               access='telnet', en_password=DEFAULT_ENPASSWORD, timeout=None):
    """Clear line corresponding to a device; this is required because only a
    single console connection is available.

    If somebody or some process failed to close the connection, it
    should be cleared explicitly.
    
    This function accepts only ssh and telnet connections.

    :param host: ip address of terminal server
    :param port: device line number in terminal server to be cleared
                for example, if port 2005 is mapped to line 5, port=5
    :param user: username
    :param pwd: password
    :param prompt: expected prompt after logging in
    :param access: ssh or telnet; default is set to telnet
    :param en_password: enable password to switch to line configuration mode
    :param timeout: how long the connection and authentication would take in seconds;
                    if not provided, default is 60s
    :return: None
    
    """

    if user == DEFAULT_USERNAME:
        user = get_username(user)
    if pwd == DEFAULT_PASSWORD:
        pwd = get_password(pwd)
    if en_password == DEFAULT_ENPASSWORD:
        en_password = get_password(en_password)

    if not timeout:
        timeout = DEFAULT_TIMEOUT

    d1 = None
    spawn = None

    # establish a connection to the terminal server
    if access == 'telnet':
        spawn = Spawn('telnet {} {}'.format(host, '23'))
        d1 = Dialog([
            ["Connected to.*Escape character is '\^\]'\.", 'sendline()', None, True, False],
            ['.*Username:'******'sendline({})'.format(user), None, True, False],
            ['(p|P)assword:', 'sendline({})'.format(pwd), None, True, True],
            [prompt, 'sendline()', None, False, False],
            ['>', 'sendline()', None, False, False],
        ])

    elif access == 'ssh':
        spawn = Spawn('ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no '
                      '-l {} -p {} {}'.format(user, '22', host))
        d1 = Dialog([
            ['continue connecting (yes/no)?', 'sendline(yes)', None, True, False],
            ['(p|P)assword:', 'sendline({})'.format(pwd), None, False, False],
        ])

    else:
        LOGGER.error('Unknown protocol: Telnet or ssh supported only')

    try:
        LOGGER.info('Trying to connect to {}'.format(host))
        d1.process(spawn, timeout=timeout)
        try:
            spawn.expect("Password OK.*")
        except TimeoutError:
            LOGGER.info("'Password OK' message didn't appear")
            pass
        spawn.sendline()
    except TimeoutError:
        LOGGER.error('Failed to connect to terminal server')
        raise Exception('Failed to connect to terminal server')

    # clear port section
    try:
        spawn.expect('#')
    except:
        # expect >
        spawn.sendline('en')
        try:
            spawn.expect('Password:'******'detected line number for clearing: {} from port {}'.
                    format(line_id, port))
        if line_id:
            spawn.sendline('clear line {}'.format(line_id))
            spawn.expect('[confirm]')
            spawn.sendline('')
            spawn.expect('[OK]')
            LOGGER.info('line: {} was cleared'.format(port))
        spawn.close()
    except TimeoutError:
        spawn.close()
        LOGGER.error('Line: {} was not cleared'.format(port))
        raise Exception('Line {} was NOT cleared'.format(port))