diff --git a/aionet/connections/base.py b/aionet/connections/base.py index 25b4162..98f4723 100644 --- a/aionet/connections/base.py +++ b/aionet/connections/base.py @@ -53,7 +53,7 @@ async def read(self): """ read from buffer """ raise NotImplementedError("Connection must implement read method ") - async def read_until_pattern(self, pattern, re_flags=0): + async def read_until_pattern(self, pattern, re_flags=0, read_for=0): """Read channel until pattern detected. Return ALL data available""" if pattern is None: @@ -69,8 +69,10 @@ async def read_until_pattern(self, pattern, re_flags=0): fut = self.read() try: - output += await asyncio.wait_for(fut, self._timeout) + output += await asyncio.wait_for(fut, read_for or self._timeout) except asyncio.TimeoutError: + if read_for: + return output raise TimeoutError(self._host) for exp in pattern: @@ -82,11 +84,11 @@ async def read_until_pattern(self, pattern, re_flags=0): ) return output - async def read_until_prompt(self): + async def read_until_prompt(self, read_for=0): """ read util prompt """ - return await self.read_until_pattern(self._base_pattern) + return await self.read_until_pattern(self._base_pattern, read_for=read_for) - async def read_until_prompt_or_pattern(self, pattern, re_flags=0): + async def read_until_prompt_or_pattern(self, pattern, re_flags=0, read_for=0): """ read util prompt or pattern """ logger.info("Host {}: Reading until prompt or pattern".format(self._host)) @@ -97,4 +99,4 @@ async def read_until_prompt_or_pattern(self, pattern, re_flags=0): pattern = [self._base_prompt] + pattern else: raise ValueError("pattern must be string or list of strings") - return await self.read_until_pattern(pattern=pattern, re_flags=re_flags) + return await self.read_until_pattern(pattern=pattern, re_flags=re_flags, read_for=read_for) diff --git a/aionet/connections/ssh.py b/aionet/connections/ssh.py index 2ac0e11..a9a7115 100644 --- a/aionet/connections/ssh.py +++ b/aionet/connections/ssh.py @@ -4,7 +4,7 @@ import asyncio import asyncssh from aionet.constants import TERM_LEN, TERM_WID, TERM_TYPE -from aionet.exceptions import AionetAuthenticationError +from aionet.exceptions import AionetAuthenticationError, AionetTimeoutError from aionet.connections.base import BaseConnection @@ -14,7 +14,7 @@ def __init__(self, username=u"", password=u"", port=22, - timeout=15, + timeout=30, loop=None, known_hosts=None, local_addr=None, @@ -81,7 +81,7 @@ async def connect(self): except asyncssh.DisconnectError as e: raise AionetAuthenticationError(self._host, e.code, e.reason) except asyncio.TimeoutError: - raise TimeoutError(self._host) + raise AionetTimeoutError('timeout while connecting to %r' % self._host) await self._start_session() diff --git a/aionet/vendors/devices/base.py b/aionet/vendors/devices/base.py index 7a70734..5991090 100644 --- a/aionet/vendors/devices/base.py +++ b/aionet/vendors/devices/base.py @@ -16,7 +16,7 @@ class BaseDevice(object): def __init__( self, - host=u"", + ip=u"", username=u"", password=u"", port=None, @@ -43,7 +43,7 @@ def __init__( """ Initialize base class for asynchronous working with network devices - :param host: device hostname or ip address for connection + :param ip: ip address for connection :param username: username for logging to device :param password: user password for logging to device :param port: port number. Default is 22 for ssh and 23 for telnet @@ -121,8 +121,8 @@ def __init__( :type compression_algs: list[str] :type signature_algs: list[str] """ - if host: - self.host = host + if ip: + self.host = ip else: raise ValueError("Host must be set") @@ -246,7 +246,7 @@ async def _disable_paging(self): """ disable terminal pagination """ self._logger.info( "Disabling Pagination, command = %r" % type(self)._disable_paging_command) - await self._send_command_expect(type(self)._disable_paging_command) + await self.send_command_expect(type(self)._disable_paging_command) async def _set_base_prompt(self): """ @@ -294,6 +294,21 @@ async def _find_prompt(self): self._logger.debug("Found Prompt: %s" % repr(prompt)) return prompt + async def send_command_timing(self, + command_string, + read_for_seconds=2): + """ + send command and keep reading for the specified time in wait or until_prompt + :param command_string: command + :type command_string: str + :param read_for_seconds: seconds of reading + :type read_for_seconds: int + :return: command output + """ + + output = await self.send_command_expect(command_string, read_for=read_for_seconds) + return output + async def send_command( self, command_string, @@ -323,7 +338,7 @@ async def send_command( "Send command: %s" % repr(command_string) ) - output = await self._send_command_expect(command_string, pattern, re_flags) + output = await self.send_command_expect(command_string, pattern, re_flags) # Some platforms have ansi_escape codes if self._ansi_escape_codes: @@ -393,18 +408,18 @@ def _normalize_cmd(command): async def send_new_line(self, pattern='', dont_read=False): """ Sending new line """ - return await self._send_command_expect('\n', pattern=pattern, dont_read=dont_read) + return await self.send_command_expect('\n', pattern=pattern, dont_read=dont_read) - async def _send_command_expect(self, command, pattern='', re_flags=0, dont_read=False): + async def send_command_expect(self, command, pattern='', re_flags=0, dont_read=False, read_for=0): """ Send a single line of command and readuntil prompte""" self._conn.send(self._normalize_cmd(command)) if dont_read: return '' if pattern: - output = await self._conn.read_until_prompt_or_pattern(pattern, re_flags) + output = await self._conn.read_until_prompt_or_pattern(pattern, re_flags, read_for=read_for) else: - output = await self._conn.read_until_prompt() + output = await self._conn.read_until_prompt(read_for=read_for) return output @@ -426,7 +441,7 @@ async def send_config_set(self, config_commands=None): self._logger.debug("Config commands: %s" % config_commands) output = "" for cmd in config_commands: - output += await self._send_command_expect(cmd) + output += await self.send_command_expect(cmd) if self._ansi_escape_codes: output = self._strip_ansi_escape_codes(output) diff --git a/aionet/vendors/devices/base_junos.py b/aionet/vendors/devices/base_junos.py index 93c21d4..0e74d6a 100644 --- a/aionet/vendors/devices/base_junos.py +++ b/aionet/vendors/devices/base_junos.py @@ -111,7 +111,7 @@ async def send_config_set( if commit_comment: commit = type(self)._commit_comment_command.format(commit_comment) - output += await self._send_command_expect(commit) + output += await self.send_command_expect(commit) if exit_config_mode: output += await self.config_mode.exit() diff --git a/aionet/vendors/devices/cisco/cisco_asa.py b/aionet/vendors/devices/cisco/cisco_asa.py index 53da181..3d23e38 100644 --- a/aionet/vendors/devices/cisco/cisco_asa.py +++ b/aionet/vendors/devices/cisco/cisco_asa.py @@ -40,7 +40,7 @@ async def _session_preparation(self): async def _check_multiple_mode(self): """Check mode multiple. If mode is multiple we adding info about contexts""" self._logger.info("Checking multiple mode") - out = await self._send_command_expect("show mode") + out = await self.send_command_expect("show mode") if "multiple" in out: self._multiple_mode = True diff --git a/aionet/vendors/devices/cisco/cisco_iosxr.py b/aionet/vendors/devices/cisco/cisco_iosxr.py index 21d8798..a261c05 100644 --- a/aionet/vendors/devices/cisco/cisco_iosxr.py +++ b/aionet/vendors/devices/cisco/cisco_iosxr.py @@ -62,18 +62,18 @@ async def send_config_set( if commit_comment: commit = type(self)._commit_comment_command.format(commit_comment) - output += await self._send_command_expect( + output += await self.send_command_expect( commit, pattern=r"Do you wish to proceed with this commit anyway\?" ) if "Failed to commit" in output: show_config_failed = type(self)._show_config_failed - reason = await self._send_command_expect(show_config_failed) + reason = await self.send_command_expect(show_config_failed) raise AionetCommitError(self.host, reason) if "One or more commits have occurred" in output: show_commit_changes = type(self)._show_commit_changes - await self._send_command_expect('no') - reason = await self._send_command_expect(show_commit_changes) + await self.send_command_expect('no') + reason = await self.send_command_expect(show_commit_changes) raise AionetCommitError(self.host, reason) if exit_config_mode: @@ -86,5 +86,5 @@ async def send_config_set( async def _cleanup(self): """ Any needed cleanup before closing connection """ abort = type(self)._abort_command - await self._send_command_expect(abort) + await self.send_command_expect(abort) self._logger.info("Cleanup session") diff --git a/aionet/vendors/devices/mikrotik/mikrotik_routeros.py b/aionet/vendors/devices/mikrotik/mikrotik_routeros.py index 03fd5c2..c4de747 100644 --- a/aionet/vendors/devices/mikrotik/mikrotik_routeros.py +++ b/aionet/vendors/devices/mikrotik/mikrotik_routeros.py @@ -62,7 +62,7 @@ async def _set_base_prompt(self): async def _find_prompt(self): """Finds the current network device prompt, last line only.""" self._logger.info("Finding prompt") - prompt = await self._send_command_expect("\r") + prompt = await self.send_command_expect("\r") prompt = prompt.strip() if self._ansi_escape_codes: prompt = self._strip_ansi_escape_codes(prompt) diff --git a/aionet/version.py b/aionet/version.py index 7e8ca55..cd1d066 100644 --- a/aionet/version.py +++ b/aionet/version.py @@ -2,7 +2,7 @@ aionet Version information """ -__version__ = "0.0.2" +__version__ = "0.0.3" __author__ = "ali aqrabawi" __author_email__ = "aaqrabaw@gmail.com" __url__ = "http://aionet.readthedocs.io/"