예제 #1
0
    def __init__(
        self,
        transport: Union[AsyncTransport, Transport],
        base_channel_args: BaseChannelArgs,
    ):
        """
        BaseChannel Object -- provides convenience methods to both sync and async Channels

        Args:
            transport: initialized scrapli Transport/AsyncTransport object
            base_channel_args: BaseChannelArgs object

        Returns:
            None

        Raises:
            N/A

        """
        self.transport = transport
        self._base_channel_args = base_channel_args

        self.logger = get_instance_logger(
            instance_name="scrapli.channel",
            host=self.transport._base_transport_args.host,
            port=self.transport._base_transport_args.port,
            uid=self.transport._base_transport_args.logging_uid,
        )

        self.channel_log: Optional[BinaryIO] = None

        self._auth_telnet_login_pattern = r"^(.*username:)|(.*login:)\s?$"
        self._auth_password_pattern = r"(.*@.*)?password:\s?$"
        self._auth_passphrase_pattern = r"enter passphrase for key"
예제 #2
0
    def __init__(self, host: str, port: int, timeout: float):
        """
        Socket object

        Args:
            host: host to connect to
            port: port to connect to
            timeout: timeout in seconds

        Returns:
            None

        Raises:
            N/A

        """
        self.logger = get_instance_logger(instance_name="scrapli.socket",
                                          host=host,
                                          port=port)

        self.host = host
        self.port = port
        self.timeout = timeout

        self.sock: Optional[socket.socket] = None
예제 #3
0
    def __init__(
        self,
        transport: Union[AsyncTransport, Transport],
        base_channel_args: BaseChannelArgs,
    ):
        """
        BaseChannel Object -- provides convenience methods to both sync and async Channels

        Args:
            transport: initialized scrapli Transport/AsyncTransport object
            base_channel_args: BaseChannelArgs object

        Returns:
            None

        Raises:
            N/A

        """
        self.transport = transport
        self._base_channel_args = base_channel_args

        self.logger = get_instance_logger(
            instance_name="scrapli.channel",
            host=self.transport._base_transport_args.host,
            port=self.transport._base_transport_args.port,
            uid=self.transport._base_transport_args.logging_uid,
        )

        self.channel_log: Optional[BinaryIO] = None
예제 #4
0
    def __init__(self,
                 config_sources: List[str],
                 ignore_version: bool = False) -> None:
        """
        Base class for all CFG platforms

        Args:
            config_sources: list of allowed config sources
            ignore_version: ignore platform version check or not

        Returns:
            None

        Raises:
            N/A

        """
        self.logger = get_instance_logger(instance_name="scrapli_cfg.platform",
                                          host=self.conn.host,
                                          port=self.conn.port)

        self.config_sources = config_sources
        self.candidate_config = ""

        self.ignore_version = ignore_version
        self._get_version_command = ""
        self._version_string = ""

        # bool indicated if a `on_prepare` callable has been executed or not
        self._prepared = False
예제 #5
0
    def __init__(self, base_transport_args: BaseTransportArgs) -> None:
        self._base_transport_args = base_transport_args

        self.logger = get_instance_logger(
            instance_name="scrapli.transport",
            host=self._base_transport_args.host,
            port=self._base_transport_args.port,
            uid=self._base_transport_args.logging_uid,
        )
예제 #6
0
    def __init__(
        self,
        transport: Union[AsyncTransport, Transport],
        base_channel_args: BaseChannelArgs,
    ):
        """
        BaseChannel Object -- provides convenience methods to both sync and async Channels

        Args:
            transport: initialized scrapli Transport/AsyncTransport object
            base_channel_args: BaseChannelArgs object

        Returns:
            None

        Raises:
            N/A

        """
        self.transport = transport
        self._base_channel_args = base_channel_args

        self.logger = get_instance_logger(
            instance_name="scrapli.channel",
            host=self.transport._base_transport_args.host,
            port=self.transport._base_transport_args.port,
            uid=self.transport._base_transport_args.logging_uid,
        )

        self.channel_log: Optional[BinaryIO] = None
        if self._base_channel_args.channel_log:
            if isinstance(self._base_channel_args.channel_log, BytesIO):
                self.channel_log = self._base_channel_args.channel_log
            else:
                channel_log_destination = "scrapli_channel.log"
                if isinstance(self._base_channel_args.channel_log, str):
                    channel_log_destination = self._base_channel_args.channel_log
                self.logger.info(
                    f"channel log enabled, logging channel output to '{channel_log_destination}'"
                )
                self.channel_log = open(channel_log_destination, "wb")
예제 #7
0
    def __init__(self, base_transport_args: BaseTransportArgs) -> None:
        """
        Scrapli's transport base class

        Args:
            base_transport_args: base transport args dataclass

        Returns:
            None

        Raises:
            N/A

        """
        self._base_transport_args = base_transport_args

        self.logger = get_instance_logger(
            instance_name="scrapli.transport",
            host=self._base_transport_args.host,
            port=self._base_transport_args.port,
            uid=self._base_transport_args.logging_uid,
        )
예제 #8
0
    def __init__(
        self,
        host: str,
        port: int = 22,
        auth_username: str = "",
        auth_password: str = "",
        auth_private_key: str = "",
        auth_private_key_passphrase: str = "",
        auth_strict_key: bool = True,
        auth_bypass: bool = False,
        timeout_socket: float = 15.0,
        timeout_transport: float = 30.0,
        timeout_ops: float = 30.0,
        comms_prompt_pattern: str = r"^[a-z0-9.\-@()/:]{1,48}[#>$]\s*$",
        comms_return_char: str = "\n",
        comms_ansi: bool = False,
        ssh_config_file: Union[str, bool] = False,
        ssh_known_hosts_file: Union[str, bool] = False,
        on_init: Optional[Callable[..., Any]] = None,
        on_open: Optional[Callable[..., Any]] = None,
        on_close: Optional[Callable[..., Any]] = None,
        transport: str = "system",
        transport_options: Optional[Dict[str, Any]] = None,
        channel_log: Union[str, bool, BytesIO] = False,
        channel_lock: bool = False,
        logging_uid: str = "",
    ) -> None:
        r"""
        BaseDriver Object

        BaseDriver is the root for all Scrapli driver classes. The synchronous and asyncio driver
        base driver classes can be used to provide a semi-pexpect like experience over top of
        whatever transport a user prefers. Generally, however, the base driver classes should not be
        used directly. It is best to use the GenericDriver (or AsyncGenericDriver) or NetworkDriver
        (or AsyncNetworkDriver) sub-classes of the base drivers.

        Args:
            host: host ip/name to connect to
            port: port to connect to
            auth_username: username for authentication
            auth_private_key: path to private key for authentication
            auth_private_key_passphrase: passphrase for decrypting ssh key if necessary
            auth_password: password for authentication
            auth_strict_key: strict host checking or not
            auth_bypass: bypass "in channel" authentication -- only supported with telnet,
                asynctelnet, and system transport plugins
            timeout_socket: timeout for establishing socket/initial connection in seconds
            timeout_transport: timeout for ssh|telnet transport in seconds
            timeout_ops: timeout for ssh channel operations
            comms_prompt_pattern: raw string regex pattern -- preferably use `^` and `$` anchors!
                this is the single most important attribute here! if this does not match a prompt,
                scrapli will not work!
                IMPORTANT: regex search uses multi-line + case insensitive flags. multi-line allows
                for highly reliably matching for prompts however we do NOT strip trailing whitespace
                for each line, so be sure to add '\\s?' or similar if your device needs that. This
                should be mostly sorted for you if using network drivers (i.e. `IOSXEDriver`).
                Lastly, the case insensitive is just a convenience factor so i can be lazy.
            comms_return_char: character to use to send returns to host
            comms_ansi: True/False strip comms_ansi characters from output, generally the default
                value of False should be fine
            ssh_config_file: string to path for ssh config file, True to use default ssh config file
                or False to ignore default ssh config file
            ssh_known_hosts_file: string to path for ssh known hosts file, True to use default known
                file locations. Only applicable/needed if `auth_strict_key` is set to True
            on_init: callable that accepts the class instance as its only argument. this callable,
                if provided, is executed as the last step of object instantiation -- its purpose is
                primarily to provide a mechanism for scrapli community platforms to have an easy way
                to modify initialization arguments/object attributes without needing to create a
                class that extends the driver, instead allowing the community platforms to simply
                build from the GenericDriver or NetworkDriver classes, and pass this callable to do
                things such as appending to a username (looking at you RouterOS!!). Note that this
                is *always* a synchronous function (even for asyncio drivers)!
            on_open: callable that accepts the class instance as its only argument. this callable,
                if provided, is executed immediately after authentication is completed. Common use
                cases for this callable would be to disable paging or accept any kind of banner
                message that prompts a user upon connection
            on_close: callable that accepts the class instance as its only argument. this callable,
                if provided, is executed immediately prior to closing the underlying transport.
                Common use cases for this callable would be to save configurations prior to exiting,
                or to logout properly to free up vtys or similar
            transport: name of the transport plugin to use for the actual telnet/ssh/netconf
                connection. Available "core" transports are:
                    - system
                    - telnet
                    - asynctelnet
                    - ssh2
                    - paramiko
                    - asyncssh
                Please see relevant transport plugin section for details. Additionally third party
                transport plugins may be available.
            transport_options: dictionary of options to pass to selected transport class; see
                docs for given transport class for details of what to pass here
            channel_lock: True/False to lock the channel (threading.Lock/asyncio.Lock) during
                any channel operations, defaults to False
            channel_log: True/False or a string path to a file of where to write out channel logs --
                these are not "logs" in the normal logging module sense, but only the output that is
                read from the channel. In other words, the output of the channel log should look
                similar to what you would see as a human connecting to a device
            logging_uid: unique identifier (string) to associate to log messages; useful if you have
                multiple connections to the same device (i.e. one console, one ssh, or one to each
                supervisor module, etc.)

        Returns:
            None

        Raises:
            N/A

        """
        self.logger = get_instance_logger(
            instance_name="scrapli.driver", host=host, port=port, uid=logging_uid
        )

        self._base_channel_args = BaseChannelArgs(
            comms_prompt_pattern=comms_prompt_pattern,
            comms_return_char=comms_return_char,
            comms_ansi=comms_ansi,
            timeout_ops=timeout_ops,
            channel_log=channel_log,
            channel_lock=channel_lock,
        )

        # transport options is unused in most transport plugins, but when used will be a dict of
        # user provided arguments, defaults to None to not be mutable argument, so if its still
        # None at this point turn it into an empty dict to pass into the transports
        transport_options = transport_options or {}
        self._base_transport_args = BaseTransportArgs(
            transport_options=transport_options,
            host=host,
            port=port,
            timeout_socket=timeout_socket,
            timeout_transport=timeout_transport,
            logging_uid=logging_uid,
        )

        self.host, self.port = self._setup_host(host=host, port=port)

        self.auth_username = auth_username
        self.auth_password = auth_password
        self.auth_private_key_passphrase = auth_private_key_passphrase
        self.auth_private_key, self.auth_strict_key, self.auth_bypass = self._setup_auth(
            auth_private_key=auth_private_key,
            auth_strict_key=auth_strict_key,
            auth_bypass=auth_bypass,
        )

        self.ssh_config_file, self.ssh_known_hosts_file = self._setup_ssh_file_args(
            transport=transport,
            ssh_config_file=ssh_config_file,
            ssh_known_hosts_file=ssh_known_hosts_file,
        )

        self._setup_callables(on_init=on_init, on_open=on_open, on_close=on_close)

        self.transport_name = transport
        if self.transport_name in ("asyncssh", "ssh2", "paramiko"):
            # for mostly(?) historical reasons these transports use the `ssh_config` module to get
            # port/username/key file. asyncssh may not need this at all anymore as asyncssh core
            # has added ssh config file support since scrapli's inception
            self._update_ssh_args_from_ssh_config()

        transport_class, self._plugin_transport_args = self._transport_factory()

        self.transport = transport_class(
            base_transport_args=self._base_transport_args,
            plugin_transport_args=self._plugin_transport_args,
        )

        if self.on_init:
            self.on_init(self)