16 from __future__
import print_function
20 from .deco
import keyword
22 from robot.api
import logger
26 from .sshconnectioncache
import SSHConnectionCache
27 from .abstractclient
import SSHClientException
28 from .client
import SSHClient
29 from .config
import (Configuration, IntegerEntry, LogLevelEntry, NewlineEntry,
30 StringEntry, TimeEntry)
31 from .utils
import ConnectionCache, is_string, is_truthy, plural_or_not
32 from .version
import VERSION
443 ROBOT_LIBRARY_SCOPE =
'GLOBAL'
444 ROBOT_LIBRARY_VERSION = __version__
446 DEFAULT_TIMEOUT =
'3 seconds'
447 DEFAULT_NEWLINE =
'LF'
448 DEFAULT_PROMPT =
None
449 DEFAULT_LOGLEVEL =
'INFO'
450 DEFAULT_TERM_TYPE =
'vt100'
451 DEFAULT_TERM_WIDTH = 80
452 DEFAULT_TERM_HEIGHT = 24
453 DEFAULT_PATH_SEPARATOR =
'/'
454 DEFAULT_ENCODING =
'UTF-8'
455 DEFAULT_ESCAPE_ANSI =
False
456 DEFAULT_ENCODING_ERRORS =
'strict'
484 timeout=DEFAULT_TIMEOUT,
485 newline=DEFAULT_NEWLINE,
486 prompt=DEFAULT_PROMPT,
487 loglevel=DEFAULT_LOGLEVEL,
488 term_type=DEFAULT_TERM_TYPE,
489 width=DEFAULT_TERM_WIDTH,
490 height=DEFAULT_TERM_HEIGHT,
491 path_separator=DEFAULT_PATH_SEPARATOR,
492 encoding=DEFAULT_ENCODING,
493 escape_ansi=DEFAULT_ESCAPE_ANSI,
494 encoding_errors=DEFAULT_ENCODING_ERRORS):
549 loglevel=None, term_type=None, width=None,
550 height=None, path_separator=None,
551 encoding=None, escape_ansi=None, encoding_errors=None):
552 self.
_config_config.update(timeout=timeout, newline=newline, prompt=prompt,
553 loglevel=loglevel, term_type=term_type, width=width,
554 height=height, path_separator=path_separator,
555 encoding=encoding, escape_ansi=escape_ansi, encoding_errors=encoding_errors)
588 term_type=None, width=None, height=None,
589 path_separator=None, encoding=None, escape_ansi=None, encoding_errors=None):
590 self.
currentcurrentcurrent.config.update(timeout=timeout, newline=newline,
591 prompt=prompt, term_type=term_type,
592 width=width, height=height,
593 path_separator=path_separator,
594 encoding=encoding, escape_ansi=escape_ansi,
595 encoding_errors=encoding_errors)
616 if SSHClient.enable_logging(logfile):
617 self.
_log_log(
'SSH log is written to <a href="%s">file</a>.' % logfile,
684 newline=None, prompt=None, term_type=None, width=None,
685 height=None, path_separator=None, encoding=None, escape_ansi=None, encoding_errors=None):
686 timeout = timeout
or self.
_config_config.timeout
687 newline = newline
or self.
_config_config.newline
688 prompt = prompt
or self.
_config_config.prompt
689 term_type = term_type
or self.
_config_config.term_type
690 width = width
or self.
_config_config.width
691 height = height
or self.
_config_config.height
692 path_separator = path_separator
or self.
_config_config.path_separator
693 encoding = encoding
or self.
_config_config.encoding
694 escape_ansi = escape_ansi
or self.
_config_config.escape_ansi
695 encoding_errors = encoding_errors
or self.
_config_config.encoding_errors
696 client = SSHClient(host, alias, port, timeout, newline, prompt,
697 term_type, width, height, path_separator, encoding, escape_ansi, encoding_errors)
698 connection_index = self.
_connections_connections.register(client, alias)
699 client.config.update(index=connection_index)
700 return connection_index
728 if index_or_alias
is None:
748 connections.close_current()
849 alias=False, port=False, timeout=False, newline=False,
850 prompt=False, term_type=False, width=False, height=False,
851 encoding=False, escape_ansi=False):
852 if not index_or_alias:
853 index_or_alias = self.
_connections_connections.current_index
857 config = SSHClient(
None).config
858 except AttributeError:
859 config = SSHClient(
None).config
860 self.
_log_log(str(config), self.
_config_config.loglevel)
862 alias, port, timeout,
864 term_type, width, height,
865 encoding, escape_ansi))
866 if not return_values:
868 if len(return_values) == 1:
869 return return_values[0]
872 def _log(self, msg, level='INFO'):
879 logger.write(msg, level)
881 print(
'*%s* %s' % (level, msg))
885 return self.
_config_config.loglevel
886 if is_string(level)
and \
887 level.upper()
in [
'TRACE',
'DEBUG',
'INFO',
'WARN',
'HTML',
'NONE']:
889 raise AssertionError(
"Invalid log level '%s'." % level)
892 newline, prompt, term_type, width, height, encoding, escape_ansi):
901 if is_truthy(timeout):
903 if is_truthy(newline):
905 if is_truthy(prompt):
907 if is_truthy(term_type):
908 yield config.term_type
911 if is_truthy(height):
913 if is_truthy(encoding):
914 yield config.encoding
915 if is_truthy(escape_ansi):
916 yield config.escape_ansi
936 configs = [c.config
for c
in self.
_connections_connections._connections
if c]
938 self.
_log_log(str(c), self.
_config_config.loglevel)
1002 def login(self, username=None, password=None, allow_agent=False, look_for_keys=False, delay='0.5 seconds',
1003 proxy_cmd=None, read_config=False, jumphost_index_or_alias=None, keep_alive_interval='0 seconds'):
1004 jumphost_connection_conf = self.
get_connectionget_connection(index_or_alias=jumphost_index_or_alias) \
1005 if jumphost_index_or_alias
else None
1006 jumphost_connection = self.
_connections_connections.connections[jumphost_connection_conf.index-1] \
1007 if jumphost_connection_conf
and jumphost_connection_conf.index
else None
1009 return self.
_login_login(self.
currentcurrentcurrent.login, username, password, is_truthy(allow_agent),
1010 is_truthy(look_for_keys), delay, proxy_cmd, is_truthy(read_config),
1011 jumphost_connection, keep_alive_interval)
1071 allow_agent=False, look_for_keys=False,
1072 delay='0.5 seconds', proxy_cmd=None,
1073 jumphost_index_or_alias=None,
1074 read_config=False, keep_alive_interval='0 seconds'):
1075 if proxy_cmd
and jumphost_index_or_alias:
1076 raise ValueError(
"`proxy_cmd` and `jumphost_connection` are mutually exclusive SSH features.")
1077 jumphost_connection_conf = self.
get_connectionget_connection(index_or_alias=jumphost_index_or_alias)
if jumphost_index_or_alias
else None
1078 jumphost_connection = self.
_connections_connections.connections[jumphost_connection_conf.index-1]
if jumphost_connection_conf
and jumphost_connection_conf.index
else None
1080 keyfile, password, is_truthy(allow_agent),
1081 is_truthy(look_for_keys), delay, proxy_cmd,
1082 jumphost_connection, is_truthy(read_config), keep_alive_interval)
1084 def _login(self, login_method, username, *args):
1085 self.
_log_log(
"Logging into '%s:%s' as '%s'."
1087 username), self.
_config_config.loglevel)
1089 login_output = login_method(username, *args)
1092 self.
_log_log(
'Read output: %s' % login_output, self.
_config_config.loglevel)
1094 except SSHClientException
as e:
1122 banner = SSHClient.get_banner_without_login(host, port)
1126 raise RuntimeError(
"'host' argument is mandatory if there is no open connection.")
1199 return_rc=False, sudo=False, sudo_password=None, timeout=None, output_during_execution=False,
1200 output_if_timeout=False, invoke_subsystem=False, forward_agent=False):
1201 if not is_truthy(sudo):
1202 self.
_log_log(
"Executing command '%s'." % command, self.
_config_config.loglevel)
1204 self.
_log_log(
"Executing command 'sudo %s'." % command, self.
_config_config.loglevel)
1208 timeout, output_during_execution, output_if_timeout,
1209 is_truthy(invoke_subsystem), forward_agent)
1254 def start_command(self, command, sudo=False, sudo_password=None, invoke_subsystem=False, forward_agent=False):
1255 if not is_truthy(sudo):
1256 self.
_log_log(
"Starting command '%s'." % command, self.
_config_config.loglevel)
1258 self.
_log_log(
"Starting command 'sudo %s'." % command, self.
_config_config.loglevel)
1314 return_rc=False, timeout=None):
1320 except SSHClientException
as msg:
1357 if not is_string(stdout):
1358 return stdout, stderr, rc
1359 stdout = stdout.lower()
1360 if stdout ==
'stderr':
1361 return False,
True, rc
1362 if stdout ==
'both':
1363 return True,
True, rc
1364 return stdout, stderr, rc
1367 return_stderr, return_rc):
1368 self.
_log_log(
"Command exited with return code %d." % rc, self.
_config_config.loglevel)
1370 if is_truthy(return_stdout):
1371 ret.append(stdout.rstrip(
'\n'))
1372 if is_truthy(return_stderr):
1373 ret.append(stderr.rstrip(
'\n'))
1374 if is_truthy(return_rc):
1404 self.
_write_write(text, add_newline=
True)
1429 except SSHClientException
as e:
1456 retry_interval, loglevel=None):
1458 expected, timeout, retry_interval)
1486 def read(self, loglevel=None, delay=None):
1585 output = reader(*args)
1586 except SSHClientException
as e:
1593 self.
_log_log(output, loglevel)
1598 ansi_escape = re.compile(
r'(?:\x1B[@-_]|[\x80-\x9F])[0-?]*[ -/]*[@-~]', flags=re.IGNORECASE)
1599 output = ansi_escape.sub(
'', output)
1600 return (
"%r" % output)[1:-1].encode().decode(
'unicode-escape')
1654 def get_file(self, source, destination='.', scp='OFF', scp_preserve_times=False):
1656 destination, scp, scp_preserve_times)
1703 scp='OFF', scp_preserve_times=False):
1705 destination, is_truthy(recursive), scp, scp_preserve_times)
1764 def put_file(self, source, destination='.', mode='0744', newline='',
1765 scp='OFF', scp_preserve_times=False):
1767 destination, mode, newline, scp, scp_preserve_times)
1821 recursive=False, scp='OFF', scp_preserve_times=False):
1823 destination, mode, newline,
1824 is_truthy(recursive), scp, scp_preserve_times)
1828 files = command(*args)
1829 except SSHClientException
as e:
1832 for src, dst
in files:
1833 self.
_log_log(
"'%s' -> '%s'" % (src, dst), self.
_config_config.loglevel)
1848 raise AssertionError(
"File '%s' does not exist." % path)
1863 raise AssertionError(
"File '%s' exists." % path)
1878 raise AssertionError(
"Directory '%s' does not exist." % path)
1893 raise AssertionError(
"Directory '%s' exists." % path)
1925 items = self.
currentcurrentcurrent.list_dir(path, pattern, is_truthy(absolute))
1926 except SSHClientException
as msg:
1928 self.
_log_log(
'%d item%s:\n%s' % (len(items), plural_or_not(items),
1929 '\n'.join(items)), self.
_config_config.loglevel)
1934 absolute = is_truthy(absolute)
1936 files = self.
currentcurrentcurrent.list_files_in_dir(path, pattern, absolute)
1937 except SSHClientException
as msg:
1939 files = self.
currentcurrentcurrent.list_files_in_dir(path, pattern, absolute)
1940 self.
_log_log(
'%d file%s:\n%s' % (len(files), plural_or_not(files),
1941 '\n'.join(files)), self.
_config_config.loglevel)
1947 dirs = self.
currentcurrentcurrent.list_dirs_in_dir(path, pattern, is_truthy(absolute))
1948 except SSHClientException
as msg:
1950 self.
_log_log(
'%d director%s:\n%s' % (len(dirs),
1951 'y' if len(dirs) == 1
else 'ies',
1952 '\n'.join(dirs)), self.
_config_config.loglevel)
1958 def __init__(self, timeout, newline, prompt, loglevel, term_type, width,
1959 height, path_separator, encoding, escape_ansi, encoding_errors):
1960 super(_DefaultConfiguration, self).
__init__(
A simple configuration class.
Integer value to be stored in stored in :py:class:Configuration.
Log level to be stored in :py:class:Configuration.
New line sequence to be stored in :py:class:Configuration.
String value to be stored in :py:class:Configuration.
Time string to be stored in :py:class:Configuration.
SSHLibrary is a Robot Framework test library for SSH and SFTP.
def close_connection(self)
Closes the current connection.
def write(self, text, loglevel=None)
Writes the given text on the remote machine and appends a newline.
def _legacy_output_options(self, stdout, stderr, rc)
def set_default_configuration(self, timeout=None, newline=None, prompt=None, loglevel=None, term_type=None, width=None, height=None, path_separator=None, encoding=None, escape_ansi=None, encoding_errors=None)
Update the default configuration.
def read_until(self, expected, loglevel=None)
Consumes and returns the server output until expected is encountered.
def put_directory(self, source, destination='.', mode='0744', newline='', recursive=False, scp='OFF', scp_preserve_times=False)
Uploads a directory, including its content, from the local machine to the remote machine.
def _escape_ansi_sequences(output)
string DEFAULT_PATH_SEPARATOR
def read(self, loglevel=None, delay=None)
Consumes and returns everything available on the server output.
def _read_and_log(self, loglevel, reader, *args)
def login(self, username=None, password=None, allow_agent=False, look_for_keys=False, delay='0.5 seconds', proxy_cmd=None, read_config=False, jumphost_index_or_alias=None, keep_alive_interval='0 seconds')
Logs into the SSH server with the given username and password.
def get_connections(self)
Returns information about all the open connections.
def _write(self, text, add_newline=False)
def list_directories_in_directory(self, path, pattern=None, absolute=False)
A wrapper for List Directory that returns only directories.
def write_bare(self, text)
Writes the given text on the remote machine without appending a newline.
def _return_command_output(self, stdout, stderr, rc, return_stdout, return_stderr, return_rc)
def put_file(self, source, destination='.', mode='0744', newline='', scp='OFF', scp_preserve_times=False)
Uploads file(s) from the local machine to the remote machine.
string DEFAULT_ENCODING_ERRORS
def read_until_prompt(self, loglevel=None, strip_prompt=False)
Consumes and returns the server output until the prompt is found.
def read_until_regexp(self, regexp, loglevel=None)
Consumes and returns the server output until a match to regexp is found.
def switch_connection(self, index_or_alias)
Switches the active connection by index or alias.
def set_client_configuration(self, timeout=None, newline=None, prompt=None, term_type=None, width=None, height=None, path_separator=None, encoding=None, escape_ansi=None, encoding_errors=None)
Update the configuration of the current connection.
def _get_config_values(self, config, index, host, alias, port, timeout, newline, prompt, term_type, width, height, encoding, escape_ansi)
def directory_should_not_exist(self, path)
Fails if the given path points to an existing directory.
def get_file(self, source, destination='.', scp='OFF', scp_preserve_times=False)
Downloads file(s) from the remote machine to the local machine.
def close_all_connections(self)
Closes all open connections.
def list_files_in_directory(self, path, pattern=None, absolute=False)
A wrapper for List Directory that returns only files.
def enable_ssh_logging(self, logfile)
Enables logging of SSH protocol output to given logfile.
def _log(self, msg, level='INFO')
def file_should_exist(self, path)
Fails if the given path does NOT point to an existing file.
def _active_loglevel(self, level)
def login_with_public_key(self, username=None, keyfile=None, password='', allow_agent=False, look_for_keys=False, delay='0.5 seconds', proxy_cmd=None, jumphost_index_or_alias=None, read_config=False, keep_alive_interval='0 seconds')
Logs into the SSH server using key-based authentication.
def open_connection(self, host, alias=None, port=22, timeout=None, newline=None, prompt=None, term_type=None, width=None, height=None, path_separator=None, encoding=None, escape_ansi=None, encoding_errors=None)
Opens a new SSH connection to the given host and port.
def get_directory(self, source, destination='.', recursive=False, scp='OFF', scp_preserve_times=False)
Downloads a directory, including its content, from the remote machine to the local machine.
def get_connection(self, index_or_alias=None, index=False, host=False, alias=False, port=False, timeout=False, newline=False, prompt=False, term_type=False, width=False, height=False, encoding=False, escape_ansi=False)
Returns information about the connection.
def file_should_not_exist(self, path)
Fails if the given path points to an existing file.
def read_command_output(self, return_stdout=True, return_stderr=False, return_rc=False, timeout=None)
Returns outputs of the most recent started command.
def __init__(self, timeout=DEFAULT_TIMEOUT, newline=DEFAULT_NEWLINE, prompt=DEFAULT_PROMPT, loglevel=DEFAULT_LOGLEVEL, term_type=DEFAULT_TERM_TYPE, width=DEFAULT_TERM_WIDTH, height=DEFAULT_TERM_HEIGHT, path_separator=DEFAULT_PATH_SEPARATOR, encoding=DEFAULT_ENCODING, escape_ansi=DEFAULT_ESCAPE_ANSI, encoding_errors=DEFAULT_ENCODING_ERRORS)
SSHLibrary allows some import time configuration.
def _run_command(self, command, *args)
def list_directory(self, path, pattern=None, absolute=False)
Returns and logs items in the remote path, optionally filtered with pattern.
def directory_should_exist(self, path)
Fails if the given path does not point to an existing directory.
def create_local_ssh_tunnel(self, local_port, remote_host, remote_port=22, bind_address=None)
The keyword uses the existing connection to set up local port forwarding (the openssh -L option) from...
def _login(self, login_method, username, *args)
def execute_command(self, command, return_stdout=True, return_stderr=False, return_rc=False, sudo=False, sudo_password=None, timeout=None, output_during_execution=False, output_if_timeout=False, invoke_subsystem=False, forward_agent=False)
Executes command on the remote machine and returns its outputs.
def start_command(self, command, sudo=False, sudo_password=None, invoke_subsystem=False, forward_agent=False)
Starts execution of the command on the remote machine and returns immediately.
def get_pre_login_banner(self, host=None, port=22)
Returns the banner supplied by the server upon connect.
def write_until_expected_output(self, text, expected, timeout, retry_interval, loglevel=None)
Writes the given text repeatedly until expected appears in the server output.
def __init__(self, timeout, newline, prompt, loglevel, term_type, width, height, path_separator, encoding, escape_ansi, encoding_errors)