예제 #1
0
    def get_redundancy_details(self, connection, timeout=None, who='my'):
        """
        :arg  connection:  device connection object
        :return: device role and redundancy mode of the device
        """
        timeout = timeout or connection.settings.EXEC_TIMEOUT

        show_red_out = connection.execute("show redundancy", timeout=timeout)

        # Redundancy information for node 0/RSP0/CPU0:
        # Node 0/RSP0/CPU0 is in ACTIVE role
        p1 = re.compile(
            r'[Nn]ode +(?P<master>\S+) +is +in +(?P<state>[A-Z\s]+) +role')
        m1 = p1.search(show_red_out)
        if m1:
            master = AttributeDict()
            state = m1.groupdict().get('state', '')
            master.update({'role': state.lower(), 'state': state})

        # Node Redundancy Partner (0/RSP1/CPU0) is in STANDBY role
        p2 = re.compile(
            r'[Nn]ode +[Rr]edundancy +[Pp]artner +\((?P<peer>\S+)\) '
            r'+is +in +(?P<state>[A-Z\s]+) +role')
        m2 = p2.search(show_red_out)
        if m2:
            peer = AttributeDict()
            state = m2.groupdict().get('state', '')
            peer.update({'role': state.lower(), 'state': state})

        return master if who == 'my' else peer
예제 #2
0
 def retry_state_machine_go_to(self,
                               state_machine,
                               to_state,
                               spawn,
                               retries,
                               retry_sleep,
                               context=AttributeDict(),
                               dialog=None,
                               timeout=None,
                               hop_wise=False,
                               prompt_recovery=False):
     for index in range(retries + 1):
         try:
             state_machine.go_to(to_state,
                                 spawn,
                                 context=context,
                                 dialog=dialog,
                                 timeout=timeout,
                                 hop_wise=hop_wise,
                                 prompt_recovery=prompt_recovery)
             break
         except Exception as err:
             if index == retries:
                 raise SubCommandFailure(err, spawn.buffer)
             time.sleep(retry_sleep)
예제 #3
0
    def get_redundancy_details(self, connection, timeout=None, who='my'):
        """
        :arg  connection:  device connection object
        :return: device role and redundancy mode of the device
        """
        timeout = timeout or connection.settings.EXEC_TIMEOUT
        redundancy_details = AttributeDict()
        if who == "peer":
            show_red_out = connection.execute("show redundancy sta |  in peer",
                                              timeout=timeout)
        else:
            show_red_out = connection.execute("show redundancy sta |  in my",
                                              timeout=timeout)

        if re.search("ACTIVE|active", show_red_out):
            redundancy_details['role'] = "active"
            redundancy_details['state'] =\
                show_red_out[show_red_out.find('-') + 1:].strip()
        elif re.search("standby|STANDBY", show_red_out):
            redundancy_details['role'] = "standby"
            redundancy_details['state'] =\
                show_red_out[show_red_out.find('-') + 1:].strip()
        elif re.search("DISABLED|disabled", show_red_out):
            redundancy_details['role'] = "disabled"
            redundancy_details['state'] =\
                show_red_out[show_red_out.find('-') + 1:].strip()
        show_red_out = connection.execute(
            "show redundancy sta | inc Redundancy State")
        redundancy_details['mode'] =\
            show_red_out[show_red_out.find("=") + 1:].strip()
        return redundancy_details
예제 #4
0
    def ssh_vty(self,
                ip,
                port,
                username='******',
                password='******',
                timeout=None,
                line_type='ssh',
                rsa_key=None):
        """Set up an ssh connection to device's interface.

        This goes into device's ip address, not console.

        :param ip: ip address of terminal server
        :param port: port of device on terminal server
        :param username: usually "admin"
        :param password: usually "Admin123"
        :param line_type: ssh line type
        :param timeout: in seconds
        :param rsa_key: identity file (full path)
        :return: a line object (where users can call execute(), for example)

        """

        graphite.publish_kick_metric('device.basic.ssh_vty', 1)
        if not timeout:
            timeout = self.default_timeout

        if rsa_key:
            resp = subprocess.getoutput('chmod 400 {}'.format(rsa_key))
            if 'No such file or directory' in resp:
                raise RuntimeError(
                    'The identity file {} you provided does not exist'.format(
                        rsa_key))
            spawn_id = NewSpawn(
                'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no '
                '-i {} -l {} -p {} {} \n'.format(rsa_key, username, port, ip))
        else:
            spawn_id = NewSpawn(
                'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no '
                '-l {} -p {} {} \n'.format(username, port, ip))

        ctx = AttributeDict({'password': password})
        d = Dialog([
            [
                'continue connecting (yes/no)?', 'sendline(yes)', None, True,
                False
            ],
            ['(p|P)assword:', 'sendline_ctx(password)', None, True, False],
            ['Password OK', 'sendline()', None, False, False],
            ['[.*>#$]+.*\s', 'sendline()', None, False, False],
        ])
        d.process(spawn_id, context=ctx, timeout=timeout)

        ssh_line = self.line_class(spawn_id, self.sm, line_type, timeout)
        logger.debug('ssh_vty() finished successfully')

        return ssh_line
예제 #5
0
    def download_image(self,
                       protocol,
                       server,
                       image_path,
                       dst,
                       port=None,
                       noconfirm=True,
                       overwrite=True,
                       usr=None,
                       pwd=None,
                       timeout=600):
        """Download a required image from the source to the destination

        :param protocol: protocol going to be used
        :param server: server address
        :param image_path: image path
        :param dst: destination path on ASA
        :param noconfirm: flag to skip download dialog
        :param usr: username
        :param pwd: password
        :return: None

        """
        cmd = 'copy '
        if noconfirm:
            cmd += '/noconfirm '

        cmd += '{protocol}://'.format(protocol=protocol)

        if usr:
            cmd += '{usr}:{pwd}@'.format(usr=usr, pwd=pwd)

        cmd += '{server}'.format(server=server)

        if port:
            cmd += ':{port}'.format(port=port)

        cmd += '/{image_path} {dst}'.format(image_path=image_path, dst=dst)

        if noconfirm:
            self.execute(cmd, timeout=timeout, exception_on_bad_command=True)
        else:
            overwrite = '' if overwrite is True else 'q'
            args = AttributeDict({'overwrite': overwrite})

            self.spawn_id.sendline(cmd)
            dialog = AsaDialog.download_dialog
            output = dialog.process(self.spawn_id,
                                    context=args,
                                    timeout=timeout)

            if 'Error' in output.last_match.string:
                raise RuntimeError('bad command: {cmd}'.format(cmd=cmd))
예제 #6
0
    def get_redundancy_details(self, connection, timeout=None):
        """ Get redundancy details from stack device

        Args:
            connection (`obj`): connection object
            timeout (`int`): execute timeout
        Returns:
            redundancy_details (`dict`): redundancy details of all peers
                eg: 
                    {'1': {'mac': 'bcc4.9346.7880',
                        'role': 'Member',
                        'state': 'Ready',
                        'sw_num': '1'},
                    '2': {'mac': 'bcc4.9346.9180',
                        'role': 'Standby',
                        'state': 'Ready',
                        'sw_num': '2'},
                    '3': {'mac': 'bcc4.9346.7280',
                        'role': 'Active',
                        'state': 'Ready',
                        'sw_num': '3'}}
        """
        timeout = timeout or connection.settings.EXEC_TIMEOUT
        redundancy_details = AttributeDict()

        #  1       Member   bcc4.9346.7880     1      V01     Ready
        # *2       Active   bcc4.9346.9180     3      V04     Ready
        #  4       Standby  d8b1.9009.bf80     1      V01     HA sync in progress
        p = re.compile(r'^(\*)?(?P<sw_num>[0-9])\s+(?P<role>Member|Active|Standby)\s+'
                       r'(?P<mac>[\w\.]+)\s+\d+\s+\w+\s+(?P<state>[\S\s]+)$')

        output = connection.execute("show switch", timeout=timeout)

        for line in output.splitlines():
            m = p.search(line.strip())
            if m:
                group = m.groupdict()
                redundancy_details.update({group['sw_num']: group})

        return redundancy_details
예제 #7
0
 def setUpClass(cls):
     """create a connection with the device"""
     cls.con = Connection(hostname=device.hostname,
                          start=device.start,
                          os=device.os,
                          tacacs_username=device.tacacs_username,
                          tacacs_password=device.tacacs_password)
     cls.con.connect()
     cls.con.configure("license grace-period")
     cls.vdcs = AttributeDict({
         "vdc1": "vdc1",
         "vdc2": "vdc2",
         "vdc3": "vdc3"
     })
예제 #8
0
    def recreate_connection_spawn(self, timeout):
        logger.info('Recreating connection spawn ...')
        new_spawn_id = NewSpawn(self.spawn_command)

        ctx = AttributeDict(
            {'password': self.sm.patterns.login_password})
        d = Dialog([
            ['continue connecting (yes/no)?', 'sendline(yes)', None,
             True,
             False],
            ['(p|P)assword:', 'sendline_ctx(password)', None, True,
             False],
            ['Password OK', 'sendline()', None, False, False],
            ['[.*>#$] ', 'sendline()', None, False, False],
        ])

        d.process(new_spawn_id, context=ctx, timeout=timeout)
        self.spawn_id.close()
        self.spawn_id = new_spawn_id
예제 #9
0
 def retry_handle_state_machine_go_to(self,
                                      handle,
                                      to_state,
                                      retries,
                                      retry_sleep,
                                      context=AttributeDict(),
                                      dialog=None,
                                      timeout=None,
                                      hop_wise=False,
                                      prompt_recovery=False):
     self.retry_state_machine_go_to(handle.state_machine,
                                    to_state,
                                    handle.spawn,
                                    retries,
                                    retry_sleep,
                                    context=context,
                                    dialog=dialog,
                                    timeout=timeout,
                                    hop_wise=hop_wise,
                                    prompt_recovery=prompt_recovery)
예제 #10
0
    def get_redundancy_details(self, connection, timeout=None, who='my'):
        """
        :arg  connection:  device connection object
        :return: device role and redundancy mode of the device
        """
        timeout = timeout or connection.settings.EXEC_TIMEOUT
        redundancy_details = AttributeDict()

        show_red_out = connection.execute("show redundancy status",
                                          timeout=timeout)
        if who == "peer":
            block = 'Other supervisor'
        else:
            block = "This supervisor"
        output = self.output_block_extract(data=show_red_out, block=block)
        redundancy_details['role'] = ""
        output = output.split("\n")
        for line in output:
            if re.search("Redundancy state", line):
                redundancy_details['role'] =\
                    line[line.find(":") + 1:].strip().lower()

            if redundancy_details['role'] == "not present":
                redundancy_details['state'] = 'DISABLED'

            if re.search("Internal state", line):
                mode = line[line.find(":") + 1:].strip()
                if mode == "HA standby":
                    redundancy_details['mode'] = 'sso'
                    redundancy_details['state'] = 'STANDBY HOT'
                elif mode == "Active with HA standby":
                    redundancy_details['mode'] = 'sso'
                    redundancy_details['state'] = 'STANDBY HOT'
                elif mode == "Active with no standby":
                    redundancy_details['mode'] = 'rpr'
                    redundancy_details['state'] = 'STANDBY COLD'
                else:
                    redundancy_details['mode'] = 'unknown'
                    redundancy_details['state'] = 'unknown'
        return redundancy_details
예제 #11
0
    def detect_state(self, spawn, context=AttributeDict()):
        """ Detect the device state and glean the actual state if multiple matches are found.
        """
        state_matches = []
        result = spawn.match
        if result:
            prompt = result.match_output.splitlines()[-1]
            for state in self.states:
                if re.search(state.pattern, prompt):
                    state_matches.append(state)

        spawn.log.debug(
            'statemachine detected state(s): {}'.format(state_matches))
        if len(state_matches) > 1:
            # If the current state is in the detected states, assume we can keep the same state
            # If not, try to glean the actual state
            if self.current_state not in [s.name for s in state_matches]:
                self.glean_state(spawn, state_matches)
        elif len(state_matches) == 1:
            self.update_cur_state(state_matches[0].name)
        else:
            spawn.sendline()
            super().go_to('any', spawn, context)
예제 #12
0
    def call_service(self, lsp, timeout=20, **kwargs):
        # Stringify the command in case it is an object
        ping_str = str('ping mpls rsvp lsp {lsp}'.format(lsp=lsp))
        con = self.connection
        con.log.debug('+++ mpls ping +++')

        mpls_ping_context = AttributeDict({})
        for key in kwargs:
            mpls_ping_context[key] = str(kwargs[key])

        dialog = self.service_dialog(service_dialog=self.dialog)
        spawn = self.get_spawn()
        sm = self.get_sm()

        spawn.sendline(ping_str)
        try:
            dialog_match = dialog.process(spawn,
                                          context=mpls_ping_context,
                                          timeout=timeout)
        except TimeoutError:
            # Recover prompt and re-raise
            # Ctrl+shift+6
            spawn.send('\x1E')
            # Empty buffer
            spawn.expect(".+", trim_buffer=True)
            raise
        except Exception as err:
            raise SubCommandFailure("MPLS Ping failed", err) from err

        self.result = dialog_match.match_output
        if self.result:
            output = self.utils.truncate_trailing_prompt(
                sm.get_state(sm.current_state),
                self.result,
                hostname=con.hostname,
                result_match=dialog_match,
            )
예제 #13
0
class FxosStateMachine(StateMachine):

    STATE_GLEAN = AttributeDict({
        'fxos':
        AttributeDict(
            dict(command='show version | inc Version',
                 pattern=patterns.fxos_glean_pattern)),
        'enable':
        AttributeDict(
            dict(command='show version | inc Version',
                 pattern=patterns.asa_glean_pattern))
    })

    def __init__(self, hostname=None):
        super().__init__(hostname)

    def create(self):
        ftd = State('ftd', patterns.ftd_prompt)
        ftd_expert = State('expert', patterns.ftd_expert_prompt)
        ftd_expert_root = State('sudo', patterns.ftd_expert_root_prompt)
        fxos = State('fxos', patterns.fxos_prompt)
        fxos_scope = State('fxos_scope', patterns.fxos_scope_prompt)
        fxos_local_mgmt = State('fxos_mgmt', patterns.fxos_local_mgmt_prompt)
        enable = State('enable', patterns.enable_prompt)
        disable = State('disable', patterns.disable_prompt)
        config = State('config', patterns.config_prompt)
        rommon = State('rommon', patterns.rommon_prompt)

        ftd_to_ftd_expert = Path(ftd, ftd_expert, 'expert', None)
        ftd_expert_to_ftd = Path(ftd_expert, ftd, 'exit', None)

        ftd_expert_to_ftd_expert_root = Path(
            ftd_expert, ftd_expert_root, 'sudo su -',
            Dialog([
                Statement(generic_patterns.password, sudo_password_handler,
                          None, True, False),
                Statement(patterns.sudo_incorrect_password_pattern,
                          sudo_failed)
            ]))
        ftd_expert_root_to_ftd_expert = Path(ftd_expert_root, ftd_expert,
                                             'exit', None)

        enable_to_disable = Path(enable, disable, 'disable', None)
        enable_to_config = Path(
            enable, config, 'config term',
            Dialog([fxos_statements.config_call_home_stmt]))

        disable_to_enable = Path(
            disable, enable, 'enable',
            Dialog([fxos_statements.enable_password_stmt]))

        config_to_enable = Path(config, enable, 'end', None)

        ftd_to_fxos = Path(ftd, fxos, ftd_fxos_transition, None)
        fxos_to_ftd = Path(fxos, ftd, fxos_ftd_transition, None)
        fxos_scope_to_fxos = Path(fxos_scope, fxos, 'top', None)
        fxos_to_fxos_scope = Path(fxos, fxos_scope, change_fxos_scope, None)

        ftd_to_disable = Path(ftd, disable, ftd_to_disable_transition,
                              Dialog([fxos_statements.enable_password_stmt]))

        ftd_to_enable = Path(ftd, enable, ftd_to_enable_transition,
                             Dialog([fxos_statements.enable_password_stmt]))

        ftd_to_config = Path(ftd, config, ftd_to_config_transition,
                             Dialog([fxos_statements.enable_password_stmt]))

        disable_to_ftd = Path(disable, ftd, send_ctrl_a_d, None)
        enable_to_ftd = Path(enable, ftd, send_ctrl_a_d, None)
        config_to_ftd = Path(config, ftd, send_ctrl_a_d, None)

        fxos_to_local_mgmt = Path(fxos, fxos_local_mgmt, 'connect local-mgmt',
                                  None)
        local_mgmt_to_fxos = Path(fxos_local_mgmt, fxos, 'exit', None)

        local_mgmt_to_rommon = Path(fxos_local_mgmt, rommon, 'reboot',
                                    Dialog(boot_to_rommon_statements))
        ftd_to_rommon = Path(ftd, rommon, 'reboot',
                             Dialog(boot_to_rommon_statements))

        rommon_to_fxos = Path(rommon, fxos, boot_fxos, None)

        self.add_state(enable)
        self.add_state(disable)
        self.add_state(config)
        self.add_state(ftd)
        self.add_state(ftd_expert)
        self.add_state(ftd_expert_root)
        self.add_state(fxos)
        self.add_state(fxos_scope)
        self.add_state(fxos_local_mgmt)
        self.add_state(rommon)

        self.add_path(enable_to_disable)
        self.add_path(enable_to_config)
        self.add_path(config_to_enable)
        self.add_path(disable_to_enable)
        self.add_path(ftd_to_ftd_expert)
        self.add_path(ftd_expert_to_ftd)
        self.add_path(ftd_expert_to_ftd_expert_root)
        self.add_path(ftd_expert_root_to_ftd_expert)
        self.add_path(ftd_to_fxos)
        self.add_path(fxos_to_ftd)
        self.add_path(fxos_to_fxos_scope)
        self.add_path(fxos_scope_to_fxos)
        self.add_path(ftd_to_enable)
        self.add_path(enable_to_ftd)
        self.add_path(ftd_to_disable)
        self.add_path(ftd_to_config)
        self.add_path(disable_to_ftd)
        self.add_path(config_to_ftd)
        self.add_path(fxos_to_local_mgmt)
        self.add_path(local_mgmt_to_fxos)
        self.add_path(local_mgmt_to_rommon)
        self.add_path(ftd_to_rommon)
        self.add_path(rommon_to_fxos)

        self.add_default_statements(default_statement_list)

    def detect_state(self, spawn):
        """ Detect the device state and glean the actual state if multiple matches are found.
        """
        state_matches = []
        result = spawn.match
        if result:
            prompt = result.match_output.splitlines()[-1]
            for state in self.states:
                if re.search(state.pattern, prompt):
                    state_matches.append(state)

        spawn.log.debug(
            'statemachine detected state(s): {}'.format(state_matches))
        if len(state_matches) > 1:
            # If the current state is in the detected states, assume we can keep the same state
            # If not, try to glean the actual state
            if self.current_state not in [s.name for s in state_matches]:
                self.glean_state(spawn, state_matches)
        elif len(state_matches) == 1:
            self.update_cur_state(state_matches[0].name)
        else:
            spawn.sendline()
            super().go_to('any', spawn)

    def glean_state(self, spawn, possible_states):
        """ Try to figure out the state by sending commands and verifying the matches against known output.
        """
        # Create list of commands to execute
        glean_command_map = {}
        state_patterns = []
        for state in possible_states:
            state_patterns.append(state.pattern)
            glean_data = self.STATE_GLEAN.get(state.name, None)
            if glean_data:
                if glean_data.command in glean_command_map:
                    glean_command_map[glean_data.command][
                        glean_data.pattern] = state
                else:
                    glean_command_map[glean_data.command] = {}
                    glean_command_map[glean_data.command][
                        glean_data.pattern] = state

        if not glean_command_map:
            raise StateMachineError(
                'Unable to detect state, multiple states possible and no glean data available'
            )

        # Execute each glean commnd and check for pattern match
        for glean_cmd in glean_command_map:
            glean_pattern_map = glean_command_map[glean_cmd]
            dialog = Dialog(default_statement_list +
                            [Statement(p) for p in state_patterns])

            spawn.sendline(glean_cmd)
            result = dialog.process(spawn)
            if result:
                output = result.match_output
                for glean_pattern in glean_pattern_map:
                    if re.search(glean_pattern, output):
                        self.update_cur_state(glean_pattern_map[glean_pattern])
                        return

    def go_to(self, to_state, spawn, **kwargs):
        spawn.log.debug('statemachine goto: {} -> {}'.format(
            self.current_state, to_state))
        super().go_to(to_state, spawn, **kwargs)
        if to_state == 'any' and self.current_state in self.STATE_GLEAN:
            glean_states = [self.get_state(name) for name in self.STATE_GLEAN]
            self.glean_state(spawn, glean_states)
예제 #14
0
    def ssh_vty(self, ip, port, username='******', password=KickConsts.DEFAULT_PASSWORD,
                timeout=None, line_type='ssh', rsa_key=None):
        """Set up an ssh connection to device's interface.

        This goes into device's ip address, not console.

        :param ip: ip address of terminal server
        :param port: port of device on terminal server
        :param username: usually "admin"
        :param password: usually "Admin123"
        :param line_type: ssh line type
        :param timeout: in seconds
        :param rsa_key: identity file (full path)
        :return: a line object (where users can call execute(), for example)

        """

        graphite.publish_kick_metric('device.basic.ssh_vty', 1)
        ssh_line = None

        if not timeout:
            timeout = self.default_timeout

        if rsa_key:
            resp = subprocess.getoutput('chmod 400 {}'.format(rsa_key))
            if 'No such file or directory' in resp:
                raise RuntimeError(
                    'The identity file {} you provided does not exist'.format(
                        rsa_key))
            spawn_id = NewSpawn(
                'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no '
                '-i {} -l {} -p {} {} \n'.format(rsa_key, username, port, ip))
        else:
            spawn_id = NewSpawn(
                'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no '
                '-l {} -p {} {} \n'.format(username, port, ip))

        ctx = AttributeDict({'password': password})
        d = Dialog([
            ['continue connecting (yes/no)?', 'sendline(yes)', None, True,
             False],
            ['(p|P)assword:', 'sendline_ctx(password)', None, False, False],
            ['[>#$] ', 'sendline()', None, False, False]
        ])

        output = d.process(spawn_id, context=ctx, timeout=timeout)
        logger.info('Output from login dialog is: {}'.format(output.match_output.replace(
            '\n', '[LF]').replace('\r', '[CR]')))
        try:
            ssh_line = self._accept_configuration_and_change_password(spawn_id, line_type, username, password, timeout)
        except TimeoutError:
            logger.info("Device initialization has failed")
            logger.info('Spawn_id.buffer content is: {}'.format(spawn_id.buffer))
            raise
        except OSError:
            logger.info(
                "Failed to login with user provided details: user: {}, password: {}".format(
                    username, password))
            raise

        logger.debug('ssh_vty() finished successfully')

        if not ssh_line:
            ssh_line = self.line_class(spawn_id, self.sm, line_type, timeout=timeout)

        return ssh_line
예제 #15
0
    def ssh_console(self, ip, port, username=DEFAULT_USERNAME, password=DEFAULT_PASSWORD,
                    timeout=None, en_password=DEFAULT_ENPASSWORD):
        """Set up an ssh console connection.

        This goes into device's console port, through a terminal server.

        :param ip: ip address of terminal server
        :param port: port of device on terminal server
        :param username: username
        :param password: password
        :param timeout: in seconds
        :param en_password: enable password to switch to line configuration mode
        :return: a line object (where users can call execute(), for example)

        """

        if username == DEFAULT_USERNAME:
            username = get_username(username)
        if password == DEFAULT_PASSWORD:
            password = get_password(password)
        if en_password == DEFAULT_ENPASSWORD:
            en_password = get_en_password(en_password)

        graphite.publish_kick_metric('device.basic.ssh_console', 1)
        if not timeout:
            timeout = self.default_timeout

        spawn_id = NewSpawn(
            'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no '
            '-l {} -p {} {} \n'.format(username, port, ip))

        ctx = AttributeDict({'password': password})
        d = Dialog([
            ['continue connecting (yes/no)?', 'sendline(yes)', None, True,
             False],
            ['(p|P)assword:', 'sendline_ctx(password)', None, False, False],
        ])
        try:
            d.process(spawn_id, context=ctx, timeout=timeout)
        except OSError:
            spawn_id.close()
            clear_line(ip, int(port) % 100, user=username, pwd=password,
                       prompt='#', access='ssh', en_password=en_password,
                       timeout=timeout)
            spawn_id = NewSpawn(
                'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no '
                '-l {} -p {} {} \n'.format(username, port, ip))
            try:
                d.process(spawn_id, context=ctx, timeout=timeout)
            except:
                spawn_id.close()
                raise

        d1 = Dialog([
            ['Password OK', 'sendline()', None, False, False],
            ['[.*>#] ', 'sendline()', None, False, False],
        ])
        try:
            d1.process(spawn_id, timeout=timeout)
        except:
            spawn_id.sendline()
        logger.debug('ssh_console() finished successfully')

        try:
            ssh_line = self.line_class(spawn_id, self.sm, 'ssh',
                                       timeout=timeout)
        except:
            spawn_id.close()
            raise

        return ssh_line
    def go_to(self, to_state, spawn,
              context=AttributeDict(),
              dialog=None,
              timeout=None,
              hop_wise=False,
              prompt_recovery=False):
        # get the composed full (slot_<slot>_<app>) state name
        to_state = self.get_full_state_name(to_state)

        # when a connection is made to the device and the device
        # is left in a random state we need to try to detect the
        # state or signal failure because going to 'any' state
        # can lead to circular transitions which go on in a loop
        # indefinetely
        if self.current_state == 'generic' and to_state is 'any':
            # try to detect in which state we are right now or fail
            # send a newline to initialize the prompt
            spawn.sendline('')
            # wait 10 seconds for the prompt to populate
            time.sleep(10)
            # match everything in the output buffer
            output = spawn.expect('.*', timeout=30).match_output
            for state_name, state_data in self.states_dict.items():
                pattern = state_data.pattern
                if isinstance(pattern, str):
                    if re.match(pattern, output.split('\r\n')[-1]):
                        self.update_cur_state(state_name)
                        return output
                if isinstance(pattern, list):
                    for pat in pattern:
                        if re.match(pat, output.split('\r\n')[-1]):
                            self.update_cur_state(state_name)
                            return output
            raise RuntimeError('Could not detect current state. Please ' +
                               'connect to the chassis and bring it to ' +
                               'the mio state prompt. Output is:' + output)
        elif (self.current_state != 'generic' and to_state is 'any') or \
                isinstance(to_state, list):
            expected_state = to_state
            transition = AnyStateTransition(state_machine=self,
                                            to_state=to_state,
                                            spawn=spawn,
                                            dialog=dialog,
                                            timeout=timeout,
                                            context=context,
                                            prompt_recovery=prompt_recovery)
        else:
            if not isinstance(to_state, State):
                to_state = self.get_state(to_state)
            expected_state = to_state.name

            # Get the current state from SM
            current_state = self.get_state(self.current_state)

            # If the current and to_state state are same
            # we are already there so just return
            if to_state == current_state:
                return

            # If hop_wise is enabled then do step by step state transition
            if hop_wise:
                transition = HopWiseStateTransition(state_machine=self,
                                                    to_state=to_state,
                                                    spawn=spawn,
                                                    dialog=dialog,
                                                    timeout=timeout,
                                                    context=context,
                                                    prompt_recovery=prompt_recovery)
            else:
                transition = StateTransition(state_machine=self,
                                             to_state=to_state,
                                             spawn=spawn,
                                             dialog=dialog,
                                             timeout=timeout,
                                             context=context,
                                             prompt_recovery=prompt_recovery)
        # Start the state transition
        try:
            output = transition.do_transitions()

        except Exception as err:
            raise StateMachineError('Failed while bringing device to ' +
                                    '"%s" state' % \
                                    str(expected_state)) from err
        finally:
            if transition.current_state is not 'generic':
                self.update_cur_state(transition.current_state)

        # If the current_state and to_state are not matching
        # the probably whe landed somewhere wrong, so raise exception
        if expected_state is not 'any' \
                and self.current_state not in expected_state:
            raise StateMachineError(
                'Changing state to %s failed\n'
                'current_state: %s\n'
                'last command: %s\n'
                'buffer: %s\n'
                'last match: %s' %
                (
                    expected_state,
                    self.current_state,
                    repr(spawn.last_sent),
                    repr(spawn.buffer),
                    repr(spawn.match.match_output)
                )
            )

        return output
    def call_service(self,
                     reload_command='reload',
                     dialog=Dialog([]),
                     timeout=None,
                     return_output=False,
                     *args, **kwargs):
        con = self.connection
        timeout = timeout or self.timeout
        assert isinstance(dialog,
                          Dialog), "dialog passed must be an instance of Dialog"
        dialog += self.dialog

        con.log.debug(
            "+++ reloading  {}  with reload_command {} and timeout is {} +++"
            .format(self.connection.hostname, reload_command, timeout))

        context = AttributeDict(self.context)
        if "image_to_boot" in kwargs:
            context["image_to_boot"] = kwargs["image_to_boot"]
        con.state_machine.go_to(self.start_state, con.spawn, context=context)
        dialog = self.service_dialog(service_dialog=dialog)
        con.spawn.sendline(reload_command)
        try:
            reload_op=dialog.process(con.spawn, context=context, timeout=timeout,
                prompt_recovery=self.prompt_recovery)
            con.state_machine.go_to(['disable', 'enable'], con.spawn,
                                    context=context,
                                    timeout=con.connection_timeout,
                                    prompt_recovery=self.prompt_recovery)
        except Exception as err:
            raise SubCommandFailure("Reload failed : {}".format(err))


        # Issue init commands to disable console logging and perform
        # initial configuration (in case "write erase" was done before reload).
        #
        # This logic is shared with the generic plugin's HAReloadService.
        exec_commands = self.connection.settings.HA_INIT_EXEC_COMMANDS

        for command in exec_commands:
            con.execute(command, prompt_recovery=self.prompt_recovery)
        config_commands = self.connection.settings.HA_INIT_CONFIG_COMMANDS
        config_retry = 0
        while config_retry < \
                self.connection.settings.CONFIG_POST_RELOAD_MAX_RETRIES:
            try:
                con.configure(config_commands, timeout=60,
                    prompt_recovery=self.prompt_recovery)
            except Exception as err:
                if re.search("Config mode locked out", str(err)):
                    sleep(self.connection.settings.\
                        CONFIG_POST_RELOAD_RETRY_DELAY_SEC)
                    con.spawn.sendline()
                    config_retry += 1
            else:
                break

        con.log.debug("+++ Reload Completed Successfully +++")
        self.result = True
        if return_output:
            self.result = ReloadResult(self.result, reload_op.match_output.replace(reload_command, '', 1))
예제 #18
0
    The tests are from black-box perspective and requires a device.

    Few tests are being tested implicitly.
    - Creation of VDC
"""
import unittest
from unicon.utils import AttributeDict
from unicon import Connection
from unicon.core.errors import SubCommandFailure

device = AttributeDict({
    'start': ['telnet 10.64.70.24 2020', 'telnet 10.64.70.24 2019'],
    'hostname':
    'step-n7k-2',
    'tacacs_username':
    '******',
    'tacacs_password':
    r'Cscats123!',
    'os':
    'nxos'
})


class TestVdc(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        """create a connection with the device"""
        cls.con = Connection(hostname=device.hostname,
                             start=device.start,
                             os=device.os,
                             tacacs_username=device.tacacs_username,
    print(session.check)
    session.num *= session.num
    print('number is %s' % session.num)

s_list = [
    Statement(pattern=pattern, action=cb1),
    Statement(pattern=pattern, action=cb2),
    Statement(pattern=pattern, action=cb3, args={'name': 'person1'}),
    Statement(pattern=pattern, action=cb4),
    Statement(pattern=pattern, action=cb5, args={'name': 'person1', 'country': 'country1'}),
    Statement(pattern=pattern, action=None)
]

d = Dialog(s_list)

context = AttributeDict(dict(username='******', password='******'))

dp1 = DialogProcessor(d, s1, context)

dp1.process(context)



print('-- After dp1')
for st in d.statements:
    if st._action is not None:
        st._action()
for st in d.statements:
    if st._action is not None:
        st._action()
    def call_service(self, addr, command="ping", **kwargs):
        if not addr:
            raise SubCommandFailure("Address is not specified")

        if 'error_pattern' in kwargs:
            self.error_pattern = kwargs['error_pattern']
            if self.error_pattern is None:
                self.error_pattern = []
            if not isinstance(self.error_pattern, list):
                raise ValueError('error pattern must be a list')
            kwargs.pop('error_pattern')
        else:
            self.error_pattern = self.default_error_pattern

        con = self.connection
        # Default value setting
        timeout = self.timeout

        ping_options = AttributeDict({})
        ping_options['c'] = '5'  # default to 5 packets

        # Read input values passed
        # Convert to string in case users passes non-string types
        for key in kwargs.copy():
            if key in self._ping_option_long_to_short:
                new_key = self._ping_option_long_to_short[key]
                kwargs[new_key] = kwargs[key]
                kwargs.pop(key)
                key = new_key
            if key == 'options':
                for o in str(kwargs['options']):
                    if o in self.ping_boolean_options:
                        ping_options[o] = ""  # Boolean options
                    else:
                        log.warning('Uknown ping option - %s, ignoring' % o)
            elif key in self.ping_arg_options:
                ping_options[key] = str(kwargs[key])
            else:
                log.warning('Uknown ping option - %s, ignoring' % key)

        if not 'options' in kwargs:
            ping_options['A'] = ""  # Default to adaptive ping

        ipaddr = ipaddress.ip_address(addr)
        if isinstance(ipaddr, ipaddress.IPv6Address):
            ping_str = 'ping6'
        elif isinstance(ipaddr, ipaddress.IPv4Address):
            ping_str = 'ping'
        else:
            # Stringify the command in case it is an object.
            ping_str = str(command)

        for ping_option in sorted(ping_options):
            ping_str += ' -%s%s' % (ping_option, ping_options[ping_option])

        ping_str += ' %s' % addr

        p = LinuxPatterns()
        dialog = Dialog()
        dialog.append(Statement(pattern=p.prompt))

        spawn = con.spawn
        spawn.sendline(ping_str)
        try:
            self.result = dialog.process(spawn, timeout=timeout)
        except Exception as err:
            raise SubCommandFailure("Ping failed", err)

        # Remove command and hostname from output.
        if self.result:
            output = utils.truncate_trailing_prompt(
                con.state_machine.get_state(con.state_machine.current_state),
                self.result.match_output, self.connection.hostname)
            output = re.sub(re.escape(ping_str), "", output, 1)
            self.result = output.strip()

        # Error checking is not part of the linux base infra, adding it here for now
        # TODO: update linux infra
        self.match_flag = False
        self.match_list = []
        for pat in self.error_pattern:
            m = re.search(pat, self.result)
            if m:
                self.match_list.append(m.group())
                self.match_flag = True

        if self.match_flag:
            raise SubCommandFailure(self.result, self.match_list)
예제 #21
0
    def execute(self,
                cmd,
                timeout=None,
                exception_on_bad_command=False,
                prompt=None):
        """Stay in current mode, run the command and return the output.

        :param cmd: a string, such as "show nameif"
        :param timeout: in seconds
        :param exception_on_bad_command: True/False - whether to raise an exception
            on a bad command
        :param prompt: a string representing a pattern to match against the content of the buffer
                      if not given, the pattern of the current state will be used
        :return: output as string

        """

        if not timeout:
            timeout = self.default_timeout

        if not prompt:
            prompt = self.sm.get_state(self.sm.current_state).pattern
        initial_state = self.sm.current_state
        try_reconnect = False
        try:
            # clear buffer before running a command
            if self.spawn_id.read_update_buffer():
                if all(i in self.spawn_id.buffer
                       for i in ['Connection', 'closed']):
                    try_reconnect = True
                else:
                    self.spawn_id.buffer = ''
        except OSError as e:
            if self.type in ['ssh', 'ssh_vty']:
                try_reconnect = True
            else:
                logger.error('Error while executing command: ', e)
                raise e
        if try_reconnect:
            # closing initial spawn
            self.spawn_id.close()
            logger.info('Line was disconnected, trying to reconnect')
            new_spawn_id = NewSpawn(self.spawn_command)

            ctx = AttributeDict({'password': self.sm.patterns.login_password})
            d = Dialog([
                [
                    'continue connecting (yes/no)?', 'sendline(yes)', None,
                    True, False
                ],
                ['(p|P)assword:', 'sendline_ctx(password)', None, True, False],
                ['Password OK', 'sendline()', None, False, False],
                ['[.*>#$] ', 'sendline()', None, False, False],
            ])
            try:
                d.process(new_spawn_id, context=ctx, timeout=timeout)
                self.spawn_id = new_spawn_id
                self.go_to('any')
                # at reconnection, reconfigure the terminal if needed
                self.__reconfigure_terminal(timeout)
                self.go_to(initial_state)
            except:
                logger.error('Connection could not be reestablished')
                raise RuntimeError('Connection could not be reestablished')

        self.spawn_id.sendline(cmd)

        # fmc/ftd inserts ' \r' for every 80 chars. sometimes for unknown
        # reason it gives prompt first, then output, then prompt again.
        # the typical pattern matching easily breaks here. we rely on the
        # fact of '\r\n' is always flanking the output.
        output = self.spawn_id.expect(prompt,
                                      timeout=timeout).last_match.string
        logger.debug("before trimming in execute(): {}".format(output))

        index = output.find('\r\n')
        output = output[index:]

        # handle bad command
        errors = [
            "% Invalid Command", "% Incomplete Command", "Error: ", "ERROR: ",
            "Error ", "ERROR "
        ]
        if any([error in output for error in errors]):
            if exception_on_bad_command:
                raise RuntimeError("bad command: {}".format(cmd))
            else:
                logger.debug("bad command: {}".format(cmd))

        return self.remove_prompt_from_output(prompt, output)