Пример #1
0
 def _enter_key_value(self,value):
     configuration_dialog = Dialog([
         ['Enter a key', 'sendline({})'.format(value), None, True, True],
         ['Confirm the key:', 'sendline({})'.format(value), None, False, False],
     ])
     target_state = self.handle.sm.current_state
     self.handle.run_cmd_dialog('set key', configuration_dialog, target_state=target_state)
Пример #2
0
def install_remove_inactive(section, steps, device, timeout=180):
    """ This stage removes partially installed packages/images left
    on the device. If a super package is left partially installed,
    we cannot attempt to install another until it is removed.

    Stage Schema
    ------------
    install_image:
        timeout (int, optional): Maximum time to wait for remove process to
            finish. Defaults to 180.

    Example
    -------
    install_remove_inactive:
        timeout: 180

    """

    with steps.start("Removing inactive packages") as step:

        install_remove_inactive_dialog = Dialog([
            Statement(pattern=r".*Do you want to remove the above files\? \[y\/n\]",
                      action='sendline(y)',
                      loop_continue=False,
                      continue_timer=False),
        ])

        try:
            device.execute('install remove inactive',
                           reply=install_remove_inactive_dialog,
                           timeout=timeout)
        except Exception as e:
            step.failed("Remove inactive packages failed. Error: {e}".format(e=str(e)))
Пример #3
0
def clear_cores(device, core_list, crashreport_list, **kwargs):

    # Create dialog for response
    dialog = Dialog([
        Statement(pattern=r'Delete.*',
                  action='sendline()',
                  loop_continue=True,
                  continue_timer=False),
    ])

    # preparing the full list to iterate over
    full_list = core_list + crashreport_list

    # Delete cores from the device
    for item in full_list:
        try:
            # Execute delete command for this core
            cmd = 'delete {location}/{core}'.format(core=item['core'],
                                                    location=item['location'])
            output = device.execute(cmd, timeout=300, reply=dialog)
            # Log to user
            meta_info = 'Successfully deleted {location}/{core}'.format(
                core=item['core'], location=item['location'])
            logger.info(meta_info)
            return OK(meta_info)
        except Exception as e:
            # Handle exception
            logger.warning(e)
            meta_info = 'Unable to delete {location}/{core}'.format(
                core=item['core'], location=item['location'])
            logger.error(meta_info)
            return ERRORED(meta_info)
Пример #4
0
    def rommon_boot(self, timeout=600):
        """Perform TFTP Boot from ROMMON.

        :return: None

        """

        time.sleep(10)
        logger.info('=== Performing TFTP Boot from ROMMON')
        logger.info('=== Wait for installation to complete, timeout = {}'
                    ' seconds ...'.format(str(timeout)))
        self.spawn_id.sendline('tftpdnld')
        d1 = Dialog([
            ['rommon.*> ', 'sendline(tftpdnld)', None, True, False],
            ['Overwrite \(y/n\)', 'sendline(y)', None, True, False],
            ['login:'******'sendline()', None, False, False],
        ])
        try:
            d1.process(self.spawn_id, timeout=timeout)
            self.spawn_id.sendline()
        except:
            logger.info("=== Rommon file download failed, raise runtime error. ")
            raise RuntimeError(
                ">>>>>> Download failed. Please check details - "
                "tftp_server: {}, image file: {}".format(self.rommon_tftp_server,
                                                         self.rommon_image))

        logger.info("=== Rommon file was installed successfully.")
Пример #5
0
def default_interface(device, interfaces):
    """ Reset junos interface configuration 

        Args:
            device (`obj`): Device object
            interfaces (`list`): List of interfaces to be defaulted
        Returns:
            None
    """
    dialog = Dialog(
        [
            Statement(
                pattern=r"Delete everything under this level?.*",
                action="sendline(yes)",
                loop_continue=True,
                continue_timer=False,
            )
        ]
    )

    for intf in interfaces:
        config_cmd = ["edit interfaces {}".format(intf), "delete"]

        try:
            device.configure(config_cmd, reply=dialog)
            log.info("Successfully defaulted {}".format(intf))
        except SubCommandFailure as e:
            raise SubCommandFailure(
                "Couldn't default {interface}. Error:\n{error}".format(
                    interface=intf, error=e
                )
            )
Пример #6
0
    def __init__(self, connection, context, **kwargs):
        self.connection = connection
        self.context = context
        self.timeout_pattern = ['Timeout occurred', ]
        self.error_pattern = []
        self.start_state = 'enable'
        self.end_state = 'enable'
        self.result = None
        self.service_name = 'copy'
        self.dialog = Dialog([
            [pr.are_you_sure,
                lambda spawn: spawn.sendline('y'),
                None, True, False],
            [pc.tftp_starting,
                None, None, True, False],
            [pc.tftp_complete,
                None, None, True, False],
            [pc.restart_system,
                None, None, False, False],
            # Sometime, when AP Images are missing TSIM needs a little prod
            [pc.reboot_to_complete,
                lambda spawn: spawn.sendline('reset system forced'),
                None, True, False]])

        # add the keyword arguments to the object
        self.__dict__.update(kwargs)
Пример #7
0
def unconfigure_pki_trustpoint(device, label_name):
    """ Unconfigures Trustpoint related config on device

        Args:
            device ('obj'): device to use
            label_name ('str'): Label name

        Returns:
            None

        Raises:
            SubCommandFailure
    """
    log.debug("Unconfigure Trustpoint on device")

    dialog = Dialog([
    Statement(pattern=r'.*\% Removing an enrolled trustpoint will destroy all certificates\n'
    'received from the related Certificate Authority\.\n'

    'Are you sure you want to do this\? \[yes\/no\]\:',
                        action='sendline(y)',
                        loop_continue=True,
                        continue_timer=False)
    ])

    try:
       device.configure("no crypto pki trustpoint {label_name}".format(label_name=label_name), reply=dialog)    
    except SubCommandFailure as e:
        raise SubCommandFailure(
            "Could not unconfigure Trustpoint related config from device "
            "Error: {error}".format(error=e)
            )
Пример #8
0
def execute_write_erase(device, timeout=300):
    ''' Execute 'write erase' on the device
        Args:
            device ('obj'): Device object
            timeout ('int'): Max time to for write erase to complete in seconds
    '''

    log.info("Executing 'write erase' on the device")

    # Unicon Statement/Dialog
    write_erase = Statement(
        pattern=r".*remove all configuration files\! Continue\? \[confirm\]",
        action='sendline()',
        loop_continue=True,
        continue_timer=False)

    try:
        output = device.execute("write erase",
                                reply=Dialog([write_erase]),
                                timeout=timeout)
    except Exception as err:
        log.error("Failed to write erase: {err}".format(err=err))
        raise Exception(err)

    if "[OK]" in output:
        log.info("Successfully executed 'write erase'")
    else:
        raise Exception("Failed to execute 'write erase'")
Пример #9
0
def fxos_ftd_transition(statemachine, spawn, context):
    sm = statemachine
    console = context.get('console', False)
    if console:
        spawn.sendline('connect ftd')
    else:
        dialog = Dialog([
            generic_statements.login_stmt, generic_statements.password_stmt,
            Statement(pattern=patterns.you_came_from_fxos,
                      action=update_context,
                      args={'console': True},
                      loop_continue=True)
        ])
        spawn.sendline('exit')
        # Wait a bit using expect, login prompt could appear
        spawn.expect('.+', trim_buffer=False)
        sm.go_to(['ftd', 'disable', 'fxos'],
                 spawn,
                 context=context,
                 timeout=spawn.timeout,
                 dialog=dialog)
        if sm.current_state == 'fxos':
            spawn.sendline('connect ftd')
            context.update({'console': True})
        else:
            spawn.sendline()
Пример #10
0
def configure_replace(device, file_location, timeout=60, file_name=None):
    """Configure replace on device

       Args:
           device (`obj`): Device object
           file_location (`str`): File location
           timeout (`int`): Timeout value in seconds
           file_name (`str`): File name

       Returns:
           None

       Raises:
           pyATS Results
    """
    if file_name:
        file_location = '{}{}'.format(file_location, file_name)
    try:
        # check if file exist
        device.execute.error_pattern.append('.*Path does not exist.*')
        device.execute("dir {}".format(file_location))
    except Exception:
        raise Exception("File {} does not exist".format(file_location))

    dialog = Dialog([
        Statement(pattern=r'\[no\]',
                  action='sendline(y)',
                  loop_continue=True,
                  continue_timer=False)
    ])
    device.configure("load {}\ncommit replace".format(file_location),
                     timeout=timeout,
                     reply=dialog)
Пример #11
0
    def _reload_expect_prompt(self, timeout=300):
        """Wait for ASA to be back online after reload

        :param timeout: timeout for reload
        :return: None

        """

        if 'telnet' in self.type:
            disable_prompt = self.sm.patterns.prompt.disable_prompt

            dialog = Dialog([
                ['Process shutdown finished', None, None, True, False],
                ['The system is restarting', None, None, True, False],
                ['Configuring network interfaces... done', None, None, True, False],
                ['Compiled on', None, None, True, False],
                ['The digital signature of the running image verified successfully', \
                 None, None, True, False],
                ['Compiled on', None, None, True, False],
                ['Cisco Adaptive Security Appliance Software Version', None, None, True, False],
                [disable_prompt, 'sendline()', None, False, False],
            ])
            dialog.process(self.spawn_id, timeout=timeout)

            self.go_to('any')
        elif 'ssh' in self.type:
            pass
Пример #12
0
def save_device_information(device, **kwargs):
    """Save running-configuration to startup-config.
    This is for general IOSXE devices.

    Args:
      Mandatory:
        device (`obj`) : Device object.

    Raises:
        None

    Example:
        >>> save_device_information(device=Device())
    """
    # configure config-register
    device.configure('config-register 0x2102')

    # save all configuration to startup for all slots        
    dialog = Dialog([
        Statement(pattern=r'Destination +filename +\[.*\].*',
                            action='sendline()',
                            loop_continue=True,
                            continue_timer=False)
    ])
    device.execute('copy running-config nvram:startup-config',
                        reply=dialog)
    device.execute('write memory')
Пример #13
0
def enter_shell(device, timeout=60):
    """Enter shell prompt on IOSXE deivces by using command
    "request platform software system shell switch active R0"

    Args:
      Mandatory:
        device (`obj`) : Device object.
      Optional:
        timeout (`int`) : Command execution timeout.

    Returns:
        None

    Raises:
        None

    Example:
        >>> enter_shell(device=Device())
    """

    # Run workon.sh on the RP shell
    dialog = Dialog([
        Statement(pattern=r'continue\? +\[y\/n\]',
                            action='sendline(y)',
                            loop_continue=True,
                            continue_timer=False)
    ])
    # store original pattern
    enable_state = device.state_machine.get_state('enable')
    device.origin_pattern = enable_state._pattern
    # Completely remove the enable state pattern and update it with new pattern.
    enable_state._pattern = [r'(.*)\:\/]\$']
    # enter shell
    device.execute('request platform software system shell switch active R0', reply=dialog)
    def call_service(self, target,
                     timeout=None,
                     *args, **kwargs):

        if not self.connection.connected:
            return

        con = self.connection
        sm = self.get_sm()

        dialog = Dialog([ftd_statements.command_not_completed_stmt])

        timeout = timeout if timeout is not None else self.timeout

        if isinstance(target, str):
            target_list = [target]
        elif isinstance(target, list):
            target_list = target
        else:
            raise Exception('Invalid switchto target type: %s' % repr(target))

        for target_state in target_list:
            m1 = re.match('module\s+(\d+)\s+console', target_state)
            m2 = re.match('cimc\s+(\S+)', target_state)
            m3 = re.match('chassis scope (.*)', target_state)
            if m1:
                mod = m1.group(1)
                self.context._module = mod
                target_state = 'module_console'
            elif m2:
                mod = m2.group(1)
                self.context._cimc_module = mod
                target_state = 'cimc'
                con.state_machine.go_to('chassis', con.spawn,
                                        context=self.context,
                                        hop_wise=True,
                                        timeout=timeout)
            elif m3:
                scope = m3.group(1)
                self.context._scope = scope
                target_state = 'chassis_scope'
                con.state_machine.go_to('chassis', con.spawn,
                                        context=self.context,
                                        hop_wise=True,
                                        timeout=timeout)
            else:
                target_state = target.replace(' ', '_')

            valid_states = [x.name for x in sm.states]
            if target_state not in valid_states:
                con.log.warning('%s is not a valid state, ignoring switchto' % target_state)
                return

            con.state_machine.go_to(target_state, con.spawn,
                                        context=self.context,
                                        hop_wise=True,
                                        timeout=timeout,
                                        dialog=dialog)

        self.end_state = sm.current_state
Пример #15
0
def _cli(device, cmd, timeout, prompt):
    """ Send command to device and get the output

        Args:
            device (`obj`): Device object
            cmd (`str`): Command
            timeout (`int`): Timeout in second
            prompt (`obj`): Unicon statement
        Returns:
            output (`obj`): Output
    """
    # Create a dialog
    state = device.state_machine.current_state
    pattern = device.state_machine.get_state(state).pattern

    device.send(cmd)
    statements = []
    statements.append(prompt)
    statements.append(Statement(pattern=pattern))
    statements.extend(device.state_machine.default_dialog)
    statements.extend(default_statement_list)
    dialog = Dialog(statements)
    output = dialog.process(device.spawn, timeout=timeout)

    return output
Пример #16
0
    def create(self):
        super().create()

        self.remove_path('enable', 'rommon')
        self.remove_path('rommon', 'disable')
        self.remove_state('rommon')

        rommon = State('rommon', patterns.rommon_prompt)
        enable_to_rommon = Path(self.get_state('enable'), rommon, 'reload',
                                Dialog(reload_statement_list))
        rommon_to_disable = Path(rommon, self.get_state('disable'),
                                 boot_from_rommon,
                                 Dialog(connection_statement_list))
        self.add_state(rommon)
        self.add_path(enable_to_rommon)
        self.add_path(rommon_to_disable)
Пример #17
0
def execute_clean_controller_fabric(device, max_time=90):
    """ Cleans the controller part of the ACI fabric

    Args:
        device (obj): Device to execute on

        max_time (int, optional): Max time in seconds allowed for 'acidiag
            touch clean'. Defaults to 90.

    Returns:
        True if successful
        False if failed

    Raises:
        N/A
    """

    clean_dialog = Dialog([
        Statement(
            pattern=r".*This command will wipe out this device\, Proceed\? \[y\/N\].*",
            action='sendline(y)'
        )
    ])

    try:
        device.execute(
            'acidiag touch clean',
            timeout=max_time,
            reply=clean_dialog,
            error_pattern=[r".*Cant find image.*"])
    except Exception as e:
        log.error("Failed to execute the command. Error: {}".format(str(e)))
        return False
    else:
        return True
Пример #18
0
    def ssh_vty(self, ip, port='22'):
        """Setup ssh connection to the server.

        :param ip: ssh host/ip
        :param port: ssh port
        :return: ssh_line

        """

        from .constants import WebserverConstants
        spawn = Spawn(
            'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no '
            '-l {} -p {} {} \n'.format(WebserverConstants.username, port, ip))
        d1 = Dialog([
            [
                'continue connecting (yes/no)?', 'sendline(yes)', None, True,
                False
            ],
            [
                '(p|P)assword:',
                'sendline({})'.format(WebserverConstants.login_password), None,
                False, False
            ],
        ])
        try:
            d1.process(spawn, timeout=60)
            spawn.sendline()
        except TimeoutError:
            pass

        ssh_line = WebserverLine(spawn, self.sm, 'ssh_ftd')
        return ssh_line
Пример #19
0
    def call_service(self,
                     reload_command='reset system forced',
                     dialog=Dialog([]),
                     timeout=None,
                     **kwargs):
        con = self.connection
        timeout = timeout or self.timeout
        con.log.debug('+++ reloading  %s  with reload_command %s and timeout is %s +++'
                      % (self.connection.hostname, reload_command, timeout))

        dialog += self.dialog_reload
        try:
            con.spawn.sendline(reload_command)
            self.result = dialog.process(con.spawn,
                                         timeout=timeout,
                                         prompt_recovery=self.prompt_recovery)
            con.state_machine.go_to('any',
                                    con.spawn,
                                    context=self.context,
                                    prompt_recovery=self.prompt_recovery,
                                    timeout=con.connection_timeout,
                                    dialog=con.connection_provider.get_connection_dialog())
            con.connection_provider.init_handle()
        except Exception as err:
            raise SubCommandFailure('Reload failed %s' % err)
Пример #20
0
def execute_write_erase(device, timeout=300):

    ''' Execute write erase on the device
        Args:
            device ('obj'): Device object
    '''

    log.info("Executing Write Erase")
    write_erase = Statement(
        pattern=r'.*Do you wish to proceed anyway\? \(y\/n\)\s*\[n\]',
        action='sendline(y)',
        loop_continue=True,
        continue_timer=False)

    # Add permisson denied to error pattern
    origin = list(device.execute.error_pattern)
    error_pattern = ['.*[Pp]ermission denied.*']
    error_pattern.extend(origin)

    try:
        device.execute("write erase", reply=Dialog([write_erase]),
                       timeout=timeout, error_pattern=error_pattern)
    except Exception as err:
        log.error("Failed to write erase: {err}".format(err=err))
        raise Exception(err)
    finally:
        # restore original error pattern
        device.execute.error_pattern = origin
Пример #21
0
    def install_activate(self, steps, device, install_timeout=INSTALL_TIMEOUT):
        with steps.start("Activating operation ID {}".format(
                self.operation_id)) as step:

            cmd = 'install activate id {id}'.format(id=self.operation_id)

            install_activate_dialog = Dialog([
                Statement(pattern='.*This install operation will reload the '
                          'system\, continue\?.*\[yes[:\/]no\]\:\[yes\].*',
                          action='sendline(yes)',
                          loop_continue=False,
                          continue_timer=False)
            ])

            try:
                # send the install cmd
                device.sendline(cmd)

                # Process the dialog that appears
                install_activate_dialog.process(device.spawn,
                                                timeout=install_timeout)

                # Wait for successful output
                device.expect([self.successful_operation_string],
                              timeout=install_timeout)
            except Exception as e:
                step.failed("Attempting to activate install id '{id}' "
                            "failed. Error: {e}".format(id=self.operation_id,
                                                        e=str(e)))
    def create(self):
        # Create States
        disable_state = State(AsaSmStates.DISABLE_STATE.value, self.patterns.prompt.disable_prompt)
        enable_state = State(AsaSmStates.ENABLE_STATE.value, self.patterns.prompt.enable_prompt)
        config_state = State(AsaSmStates.CONFIG_STATE.value, self.patterns.prompt.config_prompt)

        # Add states
        self.add_state(disable_state)
        self.add_state(enable_state)
        self.add_state(config_state)

        # Create paths
        enable_dialog = Dialog(
            [self.statements.disable_to_enable_statement,
             self.statements.set_enable_pwd_statement,
             self.statements.repeat_enable_pwd_statement,
            ]
        )
        disable_to_enable_path = Path(disable_state, enable_state, 'enable', enable_dialog)
        enable_to_disable_path = Path(enable_state, disable_state, 'disable', None)
        enable_to_config_path = Path(enable_state, config_state, 'config t', None)
        config_to_enable_path = Path(config_state, enable_state, 'end', None)

        # Add paths
        self.add_path(disable_to_enable_path)
        self.add_path(enable_to_disable_path)
        self.add_path(enable_to_config_path)
        self.add_path(config_to_enable_path)
Пример #23
0
def copy_file_to_running_config(device, path, file, timeout=60):
    """ Restore config from local file using copy function
        Args:
            device (`obj`): Device object
            path (`str`): directory
            file (`str`): file name
            timeout (`str`): timeout
        Returns:
            None
    """
    dialog = Dialog(
        [
            Statement(
                pattern=r".*Destination filename.*",
                action="sendline()",
                loop_continue=True,
                continue_timer=False,
            )
        ]
    )
    try:
        device.execute(
            "copy {path}{file} running-config".format(path=path, file=file),
            reply=dialog, timeout=timeout
        )
    except SubCommandFailure as e:
        raise SubCommandFailure(
            "Could not copy saved configuration on "
            "device {device}.\nError: {e}".format(device=device.name, e=str(e))
        )
Пример #24
0
    def _reloadLc(self, lc):
        """Do the reload LC action for asr1k devices.

        Args:
          Mandatory:
            lc (`str`) : LC slot number need to reload.

        Raises:
            Unicon errors

        Example:
            >>> _reloadLc(lc='27')
        """
        # unicon
        dialog = Dialog([
            Statement(pattern=r'Proceed\[y\/n\]\?.*',
                      action='sendline(y)',
                      loop_continue=True,
                      continue_timer=False),
            Statement(pattern=r'\(y\/n\)\?.*',
                      action='sendline(y)',
                      loop_continue=True,
                      continue_timer=False)
        ])
        # Execute command to reload LC
        self.device.execute('admin reload location {}'.format(lc),
                            reply=dialog)
        time.sleep(5)
Пример #25
0
def restore_running_config(device, path, file, timeout=60):
    """ Restore config from local file

        Args:
            device (`obj`): Device object
            path (`str`): directory
            file (`str`): file name
            timeout (`int`): Timeout for applying config
        Returns:
            None
    """
    dialog = Dialog([
        Statement(
            pattern=r".*Enter Y.*",
            action="sendline(y)",
            loop_continue=True,
            continue_timer=False,
        )
    ])
    try:
        device.execute("configure replace {path}{file}".format(path=path,
                                                               file=file),
                       reply=dialog,
                       timeout=timeout)
    except SubCommandFailure as e:
        raise SubCommandFailure("Could not replace saved configuration on "
                                "device {device}\nError: {e}".format(
                                    device=device.name, e=str(e)))
Пример #26
0
    def create(self):
        cisco_exec = State('cisco_exec', patterns.cisco_prompt)
        cisco_config = State('cisco_config', patterns.cisco_config_prompt)

        self.add_state(cisco_exec)
        self.add_state(cisco_config)

        cisco_exec_to_config = Path(cisco_exec, cisco_config, 'config term',
                                    None)

        # Ignore config changes on state change
        # config commits are done as part of the configure method
        cisco_config_dialog = Dialog([
            # Uncommitted changes found, commit them? [yes/no/CANCEL] no
            [
                patterns.cisco_commit_changes_prompt, 'sendline(no)', None,
                True, False
            ],
        ])

        cisco_config_to_exec = Path(cisco_config, cisco_exec, 'end',
                                    cisco_config_dialog)

        self.add_path(cisco_exec_to_config)
        self.add_path(cisco_config_to_exec)
        self.add_default_statements(default_statement_list)
Пример #27
0
    def rollback_checkpoint(self, device, name):
        '''
            Rollback configuration by checkpoint

            Args:

                device ('obj'): Device Object.
                name ('str'): Checkpoint name.

            Returns:

                None

            Raises:

                SyntaxError

            example:

                >>> rollback_checkpoint(device=device, name='bgp-001')
        '''
        log.info('rollback configuration by checkpoint {n}'.format(n=name))
        # rollback checkpoint
        try:
            dialog = Dialog([
                Statement(pattern=r'you want to proceed.*',
                          action='sendline(y)',
                          loop_continue=True,
                          continue_timer=False)
            ])
            device.execute('configure replace {}'.format(name), reply=dialog)
        except Exception as e:
            raise SyntaxError('Error when running rollback running-config '
                              'checkpoint {}'.format(name)) from e
Пример #28
0
    def create(self):
        """creates the junos state machine"""

        ##########################################################
        # State Definition
        ##########################################################
        shell = State('shell', patterns.shell_prompt)
        enable = State('enable', patterns.enable_prompt)
        config = State('config', patterns.config_prompt)

        ##########################################################
        # Path Definition
        ##########################################################
        config_dialog = Dialog([
           [patterns.commit_changes_prompt, 'sendline(yes)', None, True, False],
        ])
        enable_to_shell = Path(enable, shell, 'exit', None)
        shell_to_enable = Path(shell, enable, 'cli', None)

        enable_to_config = Path(enable, config, 'configure', None)
        config_to_enable = Path(config, enable, 'commit\nexit', config_dialog)

        # Add State and Path to State Machine
        self.add_state(shell)
        self.add_state(enable)
        self.add_state(config)

        self.add_path(enable_to_shell)
        self.add_path(shell_to_enable)

        self.add_path(enable_to_config)
        self.add_path(config_to_enable)
Пример #29
0
 def __init__(self, connection, context, **kwargs):
     super().__init__(connection, context, **kwargs)
     self.start_state = 'enable'
     self.end_state = 'enable'
     self.service_name = 'switchover'
     self.timeout = connection.settings.SWITCHOVER_TIMEOUT
     self.dialog = Dialog(switchover_statement_list)
Пример #30
0
    def scp(self, cmd, pwd, target_state=None, timeout=None):
        """perform the scp action (based on user cmd), and follow up with all
        prompts in scp.

        :param cmd: scp command, such as "scp [email protected]://abc.log ."
        :param pwd: password for scp
        :param target_state: move to this state before issuing the command
        :param timeout: in seconds
        :return: None

        """

        if not target_state:
            target_state = 'sudo_state'

        if not timeout:
            timeout = self.default_timeout

        logger.debug("scp command: {}".format(cmd))

        d = Dialog([[
            'continue connecting (yes/no)?', 'sendline(yes)', None, True, False
        ], ['.*(P|p)assword:', 'sendline({})'.format(pwd), None, True, False],
                    [
                        '100%.*?' +
                        self.sm.get_state('{}'.format(target_state)).pattern,
                        None, None, False, False
                    ]])
        self.run_cmd_dialog(cmd, d, target_state, timeout)