async def collect(self, host: str = None, port: int = None) -> Sequence: """Connect directly to a device. Directly connects to the router via Netmiko library, returns the command output. """ driver = _map_driver(self.device.nos) if host is not None: log.debug( "Connecting to {} via proxy {} [{}]", self.device.name, self.device.proxy.name, f"{host}:{port}", ) else: log.debug("Connecting directly to {}", self.device.name) global_args = driver_global_args.get(self.device.nos, {}) driver_kwargs = { "host": host or self.device._target, "port": port or self.device.port, "auth_username": self.device.credential.username, "timeout_transport": math.floor(params.request_timeout * 1.25), "transport": "asyncssh", "auth_strict_key": False, "ssh_known_hosts_file": False, "ssh_config_file": False, **global_args, } if self.device.credential._method == "password": # Use password auth if no key is defined. driver_kwargs[ "auth_password"] = self.device.credential.password.get_secret_value( ) else: # Otherwise, use key auth. driver_kwargs[ "auth_private_key"] = self.device.credential.key.as_posix() if self.device.credential._method == "encrypted_key": # If the key is encrypted, use the password field as the # private key password. driver_kwargs[ "auth_private_key_passphrase"] = self.device.credential.password.get_secret_value( ) driver = driver(**driver_kwargs) driver.logger = log.bind(logger_name=f"scrapli.driver-{driver._host}") try: responses = () async with driver as connection: await connection.get_prompt() for query in self.query: raw = await connection.send_command(query) responses += (raw.result, ) log.debug( f'Raw response for command "{query}":\n{raw.result}') except ScrapliTimeout as err: log.error(err) raise DeviceTimeout( params.messages.connection_error, device_name=self.device.display_name, proxy=None, error=params.messages.request_timeout, ) except (ScrapliAuthenticationFailed, KeyVerificationFailed) as err: log.error( "Error authenticating to device {loc}: {e}", loc=self.device.name, e=str(err), ) raise AuthError( params.messages.connection_error, device_name=self.device.display_name, proxy=None, error=params.messages.authentication_error, ) except ScrapliException as err: log.error(err) raise ScrapeError( params.messages.connection_error, device_name=self.device.display_name, proxy=None, error=params.messages.no_response, ) if not responses: raise ScrapeError( params.messages.connection_error, device_name=self.device.display_name, proxy=None, error=params.messages.no_response, ) return responses
async def collect(self, host: str = None, port: int = None) -> Iterable: """Connect directly to a device. Directly connects to the router via Netmiko library, returns the command output. """ if host is not None: log.debug( "Connecting to {} via proxy {} [{}]", self.device.name, self.device.proxy.name, f"{host}:{port}", ) else: log.debug("Connecting directly to {}", self.device.name) global_args = netmiko_nos_globals.get(self.device.nos, {}) send_args = netmiko_nos_send_args.get(self.device.nos, {}) driver_kwargs = { "host": host or self.device._target, "port": port or self.device.port, "device_type": self.device.nos, "username": self.device.credential.username, "global_delay_factor": params.netmiko_delay_factor, "timeout": math.floor(params.request_timeout * 1.25), "session_timeout": math.ceil(params.request_timeout - 1), **global_args, } if "_telnet" in self.device.nos: # Telnet devices with a low delay factor (default) tend to # throw login errors. driver_kwargs["global_delay_factor"] = 2 if self.device.credential._method == "password": # Use password auth if no key is defined. driver_kwargs[ "password"] = self.device.credential.password.get_secret_value( ) else: # Otherwise, use key auth. driver_kwargs["use_keys"] = True driver_kwargs["key_file"] = self.device.credential.key if self.device.credential._method == "encrypted_key": # If the key is encrypted, use the password field as the # private key password. driver_kwargs[ "passphrase"] = self.device.credential.password.get_secret_value( ) try: nm_connect_direct = ConnectHandler(**driver_kwargs) responses = () for query in self.query: raw = nm_connect_direct.send_command(query, **send_args) responses += (raw, ) log.debug(f'Raw response for command "{query}":\n{raw}') nm_connect_direct.disconnect() except NetMikoTimeoutException as scrape_error: log.error(str(scrape_error)) raise DeviceTimeout( params.messages.connection_error, device_name=self.device.name, proxy=None, error=params.messages.request_timeout, ) except NetMikoAuthenticationException as auth_error: log.error( "Error authenticating to device {loc}: {e}", loc=self.device.name, e=str(auth_error), ) raise AuthError( params.messages.connection_error, device_name=self.device.name, proxy=None, error=params.messages.authentication_error, ) if not responses: raise ScrapeError( params.messages.connection_error, device_name=self.device.name, proxy=None, error=params.messages.no_response, ) return responses
async def scrape_direct(self): """Connect directly to a device. Directly connects to the router via Netmiko library, returns the command output. """ log.debug(f"Connecting directly to {self.device.name}...") scrape_host = { "host": self.device.address, "port": self.device.port, "device_type": self.device.nos, "username": self.device.credential.username, "password": self.device.credential.password.get_secret_value(), **self.netmiko_args, } try: nm_connect_direct = ConnectHandler(**scrape_host) def handle_timeout(*args, **kwargs): nm_connect_direct.disconnect() raise DeviceTimeout( params.messages.connection_error, device_name=self.device.display_name, error=params.messages.request_timeout, ) signal.signal(signal.SIGALRM, handle_timeout) signal.alarm(params.request_timeout - 1) responses = () for query in self.query: raw = nm_connect_direct.send_command(query) responses += (raw, ) log.debug(f'Raw response for command "{query}":\n{raw}') nm_connect_direct.disconnect() except (NetMikoTimeoutException, NetmikoTimeoutError) as scrape_error: log.error(str(scrape_error)) raise DeviceTimeout( params.messages.connection_error, device_name=self.device.display_name, proxy=None, error=params.messages.request_timeout, ) except (NetMikoAuthenticationException, NetmikoAuthError) as auth_error: log.error( "Error authenticating to device {loc}: {e}", loc=self.device.name, e=str(auth_error), ) raise AuthError( params.messages.connection_error, device_name=self.device.display_name, proxy=None, error=params.messages.authentication_error, ) if not responses: raise ScrapeError( params.messages.connection_error, device_name=self.device.display_name, proxy=None, error=params.messages.no_response, ) signal.alarm(0) return await self.parsed_response(responses)
async def collect(self, host: str = None, port: int = None) -> Iterable: """Connect directly to a device. Directly connects to the router via Netmiko library, returns the command output. """ if host is not None: log.debug( "Connecting to {} via proxy {} [{}]", self.device.name, self.device.proxy.name, f"{host}:{port}", ) else: log.debug("Connecting directly to {}", self.device.name) netmiko_args = { "host": host or self.device._target, "port": port or self.device.port, "device_type": self.device.nos, "username": self.device.credential.username, "password": self.device.credential.password.get_secret_value(), "global_delay_factor": params.netmiko_delay_factor, "timeout": math.floor(params.request_timeout * 1.25), "session_timeout": math.ceil(params.request_timeout - 1), } try: nm_connect_direct = ConnectHandler(**netmiko_args) responses = () for query in self.query: raw = nm_connect_direct.send_command(query) responses += (raw,) log.debug(f'Raw response for command "{query}":\n{raw}') nm_connect_direct.disconnect() except (NetMikoTimeoutException, NetmikoTimeoutError) as scrape_error: log.error(str(scrape_error)) raise DeviceTimeout( params.messages.connection_error, device_name=self.device.display_name, proxy=None, error=params.messages.request_timeout, ) except (NetMikoAuthenticationException, NetmikoAuthError) as auth_error: log.error( "Error authenticating to device {loc}: {e}", loc=self.device.name, e=str(auth_error), ) raise AuthError( params.messages.connection_error, device_name=self.device.display_name, proxy=None, error=params.messages.authentication_error, ) if not responses: raise ScrapeError( params.messages.connection_error, device_name=self.device.display_name, proxy=None, error=params.messages.no_response, ) return responses
async def scrape_proxied(self): """Connect to a device via an SSH proxy. Connects to the router via Netmiko library via the sshtunnel library, returns the command output. """ log.debug( f"Connecting to {self.device.proxy} via sshtunnel library...") try: tunnel = sshtunnel.open_tunnel( self.device.proxy.address, self.device.proxy.port, ssh_username=self.device.proxy.credential.username, ssh_password=self.device.proxy.credential.password. get_secret_value(), remote_bind_address=(self.device.address, self.device.port), local_bind_address=("localhost", 0), skip_tunnel_checkup=False, gateway_timeout=params.request_timeout - 2, ) except sshtunnel.BaseSSHTunnelForwarderError as scrape_proxy_error: log.error(f"Error connecting to device {self.device.name} via " f"proxy {self.device.proxy.name}") raise ScrapeError( params.messages.connection_error, device_name=self.device.display_name, proxy=self.device.proxy.name, error=str(scrape_proxy_error), ) def handle_timeout(*args, **kwargs): tunnel.close() raise DeviceTimeout( params.messages.connection_error, device_name=self.device.display_name, proxy=self.device.proxy.name, error=params.messages.request_timeout, ) signal.signal(signal.SIGALRM, handle_timeout) signal.alarm(params.request_timeout - 1) with tunnel: log.debug( "Established tunnel with {d}. Local bind port: {p}", d=self.device.proxy, p=tunnel.local_bind_port, ) scrape_host = { "host": "localhost", "port": tunnel.local_bind_port, "device_type": self.device.nos, "username": self.device.credential.username, "password": self.device.credential.password.get_secret_value(), **self.netmiko_args, } try: log.debug("Connecting to {loc}...", loc=self.device.name) nm_connect_direct = ConnectHandler(**scrape_host) responses = () for query in self.query: raw = nm_connect_direct.send_command(query) responses += (raw, ) log.debug(f'Raw response for command "{query}":\n{raw}') nm_connect_direct.disconnect() except (NetMikoTimeoutException, NetmikoTimeoutError) as scrape_error: log.error( "Timeout connecting to device {loc}: {e}", loc=self.device.name, e=str(scrape_error), ) raise DeviceTimeout( params.messages.connection_error, device_name=self.device.display_name, proxy=self.device.proxy.name, error=params.messages.request_timeout, ) except (NetMikoAuthenticationException, NetmikoAuthError) as auth_error: log.error( "Error authenticating to device {loc}: {e}", loc=self.device.name, e=str(auth_error), ) raise AuthError( params.messages.connection_error, device_name=self.device.display_name, proxy=self.device.proxy.name, error=params.messages.authentication_error, ) from None except sshtunnel.BaseSSHTunnelForwarderError: raise ScrapeError( params.messages.connection_error, device_name=self.device.display_name, proxy=self.device.proxy.name, error=params.messages.general, ) if not responses: raise ScrapeError( params.messages.connection_error, device_name=self.device.display_name, proxy=None, error=params.messages.no_response, ) signal.alarm(0) return await self.parsed_response(responses)