def test_create_with_key_via_bastion(self): conn_params = {'hostname': 'dummy.host.org', 'bastion_host': 'bastion.host.org', 'username': '******', 'key_files': 'id_rsa'} mock = ParamikoSSHClient(**conn_params) mock.connect() expected_bastion_conn = {'username': '******', 'allow_agent': False, 'hostname': 'bastion.host.org', 'look_for_keys': False, 'key_filename': 'id_rsa', 'timeout': 60, 'port': 22} mock.bastion_client.connect.assert_called_once_with(**expected_bastion_conn) expected_conn = {'username': '******', 'allow_agent': False, 'hostname': 'dummy.host.org', 'look_for_keys': False, 'key_filename': 'id_rsa', 'timeout': 60, 'port': 22, 'sock': mock.bastion_socket} mock.client.connect.assert_called_once_with(**expected_conn)
def test_create_with_key_via_bastion(self): conn_params = { 'hostname': 'dummy.host.org', 'bastion_host': 'bastion.host.org', 'username': '******', 'key_files': 'id_rsa' } mock = ParamikoSSHClient(**conn_params) mock.connect() expected_bastion_conn = { 'username': '******', 'allow_agent': False, 'hostname': 'bastion.host.org', 'look_for_keys': False, 'key_filename': 'id_rsa', 'timeout': 60, 'port': 22 } mock.bastion_client.connect.assert_called_once_with( **expected_bastion_conn) expected_conn = { 'username': '******', 'allow_agent': False, 'hostname': 'dummy.host.org', 'look_for_keys': False, 'key_filename': 'id_rsa', 'timeout': 60, 'port': 22, 'sock': mock.bastion_socket } mock.client.connect.assert_called_once_with(**expected_conn)
def _connect(self, host, results, raise_on_any_error=False): (hostname, port) = self._get_host_port_info(host) extra = {'host': host, 'port': port, 'user': self._ssh_user} if self._ssh_password: extra['password'] = '******' elif self._ssh_key_file: extra['key_file_path'] = self._ssh_key_file else: extra['private_key'] = '<redacted>' LOG.debug('Connecting to host.', extra=extra) client = ParamikoSSHClient(hostname, username=self._ssh_user, password=self._ssh_password, bastion_host=self._bastion_host, key_files=self._ssh_key_file, key_material=self._ssh_key_material, passphrase=self._passphrase, port=port) try: client.connect() except Exception as ex: error = 'Failed connecting to host %s.' % hostname LOG.exception(error) if raise_on_any_error: raise error_dict = self._generate_error_result(exc=ex, message=error) self._bad_hosts[hostname] = error_dict results[hostname] = error_dict else: self._successful_connects += 1 self._hosts_client[hostname] = client results[hostname] = {'message': 'Connected to host.'}
def run(self, hostname, port, username, password=None, keyfile=None, ssh_timeout=5, sleep_delay=20, retries=10): # Note: If neither password nor key file is provided, we try to use system user # key file if not password and not keyfile: keyfile = cfg.CONF.system_user.ssh_key_file self.logger.info( 'Neither "password" nor "keyfile" parameter provided, ' 'defaulting to using "%s" key file' % (keyfile) ) client = ParamikoSSHClient( hostname=hostname, port=port, username=username, password=password, key_files=keyfile, timeout=ssh_timeout ) for index in range(retries): attempt = index + 1 try: self.logger.debug("SSH connection attempt: %s" % (attempt)) client.connect() return True except Exception as e: self.logger.info("Attempt %s failed (%s), sleeping for %s seconds..." % (attempt, str(e), sleep_delay)) time.sleep(sleep_delay) raise Exception("Exceeded max retries (%s)" % (retries))
def test_key_material_argument(self): path = os.path.join(get_resources_base_path(), 'ssh', 'dummy_rsa') with open(path, 'r') as fp: private_key = fp.read() conn_params = { 'hostname': 'dummy.host.org', 'username': '******', 'key_material': private_key } mock = ParamikoSSHClient(**conn_params) mock.connect() pkey = paramiko.RSAKey.from_private_key(StringIO(private_key)) expected_conn = { 'username': '******', 'allow_agent': False, 'hostname': 'dummy.host.org', 'look_for_keys': False, 'pkey': pkey, 'timeout': 60, 'port': 22 } mock.client.connect.assert_called_once_with(**expected_conn)
def test_key_with_passphrase_success(self): path = os.path.join(get_resources_base_path(), 'ssh', 'dummy_rsa_passphrase') with open(path, 'r') as fp: private_key = fp.read() # Key material provided conn_params = { 'hostname': 'dummy.host.org', 'username': '******', 'key_material': private_key, 'passphrase': 'testphrase' } mock = ParamikoSSHClient(**conn_params) mock.connect() pkey = paramiko.RSAKey.from_private_key(StringIO(private_key), 'testphrase') expected_conn = { 'username': '******', 'allow_agent': False, 'hostname': 'dummy.host.org', 'look_for_keys': False, 'pkey': pkey, 'timeout': 60, 'port': 22 } mock.client.connect.assert_called_once_with(**expected_conn) # Path to private key file provided conn_params = { 'hostname': 'dummy.host.org', 'username': '******', 'key_files': path, 'passphrase': 'testphrase' } mock = ParamikoSSHClient(**conn_params) mock.connect() expected_conn = { 'username': '******', 'allow_agent': False, 'hostname': 'dummy.host.org', 'look_for_keys': False, 'key_filename': path, 'password': '******', 'timeout': 60, 'port': 22 } mock.client.connect.assert_called_once_with(**expected_conn)
def test_deprecated_key_argument(self): conn_params = {'hostname': 'dummy.host.org', 'username': '******', 'key_files': 'id_rsa'} mock = ParamikoSSHClient(**conn_params) mock.connect() expected_conn = {'username': '******', 'allow_agent': False, 'hostname': 'dummy.host.org', 'look_for_keys': False, 'key_filename': 'id_rsa', 'timeout': 60, 'port': 22} mock.client.connect.assert_called_once_with(**expected_conn)
def test_create_with_password(self): conn_params = {'hostname': 'dummy.host.org', 'username': '******', 'password': '******'} mock = ParamikoSSHClient(**conn_params) mock.connect() expected_conn = {'username': '******', 'password': '******', 'allow_agent': False, 'hostname': 'dummy.host.org', 'look_for_keys': False, 'timeout': 60, 'port': 22} mock.client.connect.assert_called_once_with(**expected_conn)
def _connect(self, host, results, raise_on_any_error=False): (hostname, port) = self._get_host_port_info(host) extra = {"host": host, "port": port, "user": self._ssh_user} if self._ssh_password: extra["password"] = "******" elif self._ssh_key_file: extra["key_file_path"] = self._ssh_key_file else: extra["private_key"] = "<redacted>" LOG.debug("Connecting to host.", extra=extra) client = ParamikoSSHClient( hostname=hostname, port=port, username=self._ssh_user, password=self._ssh_password, bastion_host=self._bastion_host, key_files=self._ssh_key_file, key_material=self._ssh_key_material, passphrase=self._passphrase, handle_stdout_line_func=self._handle_stdout_line_func, handle_stderr_line_func=self._handle_stderr_line_func, ) try: client.connect() except SSHException as ex: LOG.exception(ex) if raise_on_any_error: raise error_dict = self._generate_error_result( exc=ex, message="Connection error." ) self._bad_hosts[hostname] = error_dict results[hostname] = error_dict except Exception as ex: error = "Failed connecting to host %s." % hostname LOG.exception(error) if raise_on_any_error: raise error_dict = self._generate_error_result(exc=ex, message=error) self._bad_hosts[hostname] = error_dict results[hostname] = error_dict else: self._successful_connects += 1 self._hosts_client[hostname] = client results[hostname] = {"message": "Connected to host."}
def test_set_proxycommand(self, mock_ProxyCommand): """ Loads proxy commands from ssh config file """ ssh_config_file_path = os.path.join(get_resources_base_path(), 'ssh', 'dummy_ssh_config') cfg.CONF.set_override(name='ssh_config_file_path', override=ssh_config_file_path, group='ssh_runner') cfg.CONF.set_override(name='use_ssh_config', override=True, group='ssh_runner') conn_params = {'hostname': 'dummy.host.org', 'username': '******', 'password': '******'} mock = ParamikoSSHClient(**conn_params) mock.connect() mock_ProxyCommand.assert_called_once_with('ssh -q -W dummy.host.org:22 dummy_bastion')
def test_create_without_credentials_use_default_key(self): # No credentials are provided by default stanley ssh key exists so it should use that cfg.CONF.set_override(name='ssh_key_file', override='stanley_rsa', group='system_user') conn_params = {'hostname': 'dummy.host.org', 'username': '******'} mock = ParamikoSSHClient(**conn_params) mock.connect() expected_conn = {'username': '******', 'hostname': 'dummy.host.org', 'key_filename': 'stanley_rsa', 'allow_agent': False, 'look_for_keys': False, 'timeout': 60, 'port': 22} mock.client.connect.assert_called_once_with(**expected_conn)
def test_create_without_credentials(self): """ Initialize object with no credentials. Just to have better coverage, initialize the object without 'password' neither 'key'. """ conn_params = {'hostname': 'dummy.host.org', 'username': '******'} mock = ParamikoSSHClient(**conn_params) mock.connect() expected_conn = {'username': '******', 'hostname': 'dummy.host.org', 'allow_agent': True, 'look_for_keys': True, 'timeout': 60, 'port': 22} mock.client.connect.assert_called_once_with(**expected_conn)
def test_create_with_password(self): conn_params = { 'hostname': 'dummy.host.org', 'username': '******', 'password': '******' } mock = ParamikoSSHClient(**conn_params) mock.connect() expected_conn = { 'username': '******', 'password': '******', 'allow_agent': False, 'hostname': 'dummy.host.org', 'look_for_keys': False, 'timeout': 60, 'port': 22 } mock.client.connect.assert_called_once_with(**expected_conn)
def test_deprecated_key_argument(self): conn_params = { 'hostname': 'dummy.host.org', 'username': '******', 'key_files': 'id_rsa' } mock = ParamikoSSHClient(**conn_params) mock.connect() expected_conn = { 'username': '******', 'allow_agent': False, 'hostname': 'dummy.host.org', 'look_for_keys': False, 'key_filename': 'id_rsa', 'timeout': 60, 'port': 22 } mock.client.connect.assert_called_once_with(**expected_conn)
def test_key_with_passphrase_success(self): path = os.path.join(get_resources_base_path(), 'ssh', 'dummy_rsa_passphrase') with open(path, 'r') as fp: private_key = fp.read() # Key material provided conn_params = {'hostname': 'dummy.host.org', 'username': '******', 'key_material': private_key, 'passphrase': 'testphrase'} mock = ParamikoSSHClient(**conn_params) mock.connect() pkey = paramiko.RSAKey.from_private_key(StringIO(private_key), 'testphrase') expected_conn = {'username': '******', 'allow_agent': False, 'hostname': 'dummy.host.org', 'look_for_keys': False, 'pkey': pkey, 'timeout': 60, 'port': 22} mock.client.connect.assert_called_once_with(**expected_conn) # Path to private key file provided conn_params = {'hostname': 'dummy.host.org', 'username': '******', 'key_files': path, 'passphrase': 'testphrase'} mock = ParamikoSSHClient(**conn_params) mock.connect() expected_conn = {'username': '******', 'allow_agent': False, 'hostname': 'dummy.host.org', 'look_for_keys': False, 'key_filename': path, 'password': '******', 'timeout': 60, 'port': 22} mock.client.connect.assert_called_once_with(**expected_conn)
def run( self, hostname, port, username, password=None, keyfile=None, ssh_timeout=5, sleep_delay=20, retries=10, ): # Note: If neither password nor key file is provided, we try to use system user # key file if not password and not keyfile: keyfile = cfg.CONF.system_user.ssh_key_file self.logger.info( 'Neither "password" nor "keyfile" parameter provided, ' 'defaulting to using "%s" key file' % (keyfile)) client = ParamikoSSHClient( hostname=hostname, port=port, username=username, password=password, key_files=keyfile, timeout=ssh_timeout, ) for index in range(retries): attempt = index + 1 try: self.logger.debug("SSH connection attempt: %s" % (attempt)) client.connect() return True except Exception as e: self.logger.info( "Attempt %s failed (%s), sleeping for %s seconds..." % (attempt, six.text_type(e), sleep_delay)) time.sleep(sleep_delay) raise Exception("Exceeded max retries (%s)" % (retries))
def test_create_without_credentials_use_default_key(self): # No credentials are provided by default stanley ssh key exists so it should use that cfg.CONF.set_override(name='ssh_key_file', override='stanley_rsa', group='system_user') conn_params = {'hostname': 'dummy.host.org', 'username': '******'} mock = ParamikoSSHClient(**conn_params) mock.connect() expected_conn = { 'username': '******', 'hostname': 'dummy.host.org', 'key_filename': 'stanley_rsa', 'allow_agent': False, 'look_for_keys': False, 'timeout': 60, 'port': 22 } mock.client.connect.assert_called_once_with(**expected_conn)
def test_create_without_credentials(self): """ Initialize object with no credentials. Just to have better coverage, initialize the object without 'password' neither 'key'. """ conn_params = {'hostname': 'dummy.host.org', 'username': '******'} mock = ParamikoSSHClient(**conn_params) mock.connect() expected_conn = { 'username': '******', 'hostname': 'dummy.host.org', 'allow_agent': True, 'look_for_keys': True, 'timeout': 60, 'port': 22 } mock.client.connect.assert_called_once_with(**expected_conn)
def test_set_proxycommand(self, mock_ProxyCommand): """ Loads proxy commands from ssh config file """ ssh_config_file_path = os.path.join(get_resources_base_path(), 'ssh', 'dummy_ssh_config') cfg.CONF.set_override(name='ssh_config_file_path', override=ssh_config_file_path, group='ssh_runner') cfg.CONF.set_override(name='use_ssh_config', override=True, group='ssh_runner') conn_params = { 'hostname': 'dummy.host.org', 'username': '******', 'password': '******' } mock = ParamikoSSHClient(**conn_params) mock.connect() mock_ProxyCommand.assert_called_once_with( 'ssh -q -W dummy.host.org:22 dummy_bastion')
def test_key_material_argument(self): path = os.path.join(get_resources_base_path(), 'ssh', 'dummy_rsa') with open(path, 'r') as fp: private_key = fp.read() conn_params = {'hostname': 'dummy.host.org', 'username': '******', 'key_material': private_key} mock = ParamikoSSHClient(**conn_params) mock.connect() pkey = paramiko.RSAKey.from_private_key(StringIO(private_key)) expected_conn = {'username': '******', 'allow_agent': False, 'hostname': 'dummy.host.org', 'look_for_keys': False, 'pkey': pkey, 'timeout': 60, 'port': 22} mock.client.connect.assert_called_once_with(**expected_conn)
def test_sftp_connection_is_only_established_if_required(self): # Verify that SFTP connection is lazily established only if and when needed. conn_params = {'hostname': 'dummy.host.org', 'username': '******', 'password': '******'} # Verify sftp connection and client hasn't been established yet client = ParamikoSSHClient(**conn_params) client.connect() self.assertTrue(client.sftp_client is None) # run method doesn't require sftp access so it shouldn't establish connection client = ParamikoSSHClient(**conn_params) client.connect() client.run(cmd='whoami') self.assertTrue(client.sftp_client is None) # Methods below require SFTP access so they should cause SFTP connection to be established # put client = ParamikoSSHClient(**conn_params) client.connect() path = '/root/random_script.sh' client.put(path, path, mirror_local_mode=False) self.assertTrue(client.sftp_client is not None) # exists client = ParamikoSSHClient(**conn_params) client.connect() client.exists('/root/somepath.txt') self.assertTrue(client.sftp_client is not None) # mkdir client = ParamikoSSHClient(**conn_params) client.connect() client.mkdir('/root/somedirfoo') self.assertTrue(client.sftp_client is not None) # Verify close doesn't throw if SFTP connection is not established client = ParamikoSSHClient(**conn_params) client.connect() self.assertTrue(client.sftp_client is None) client.close() # Verify SFTP connection is closed if it's opened client = ParamikoSSHClient(**conn_params) client.connect() client.mkdir('/root/somedirfoo') self.assertTrue(client.sftp_client is not None) client.close() self.assertEqual(client.sftp_client.close.call_count, 1)
def test_use_ssh_config_port_value_provided_in_the_config( self, mock_sshclient): cfg.CONF.set_override(name='use_ssh_config', override=True, group='ssh_runner') ssh_config_file_path = os.path.join(get_resources_base_path(), 'ssh', 'empty_config') cfg.CONF.set_override(name='ssh_config_file_path', override=ssh_config_file_path, group='ssh_runner') # 1. Default port is used (not explicitly provided) mock_client = mock.Mock() mock_sshclient.return_value = mock_client conn_params = { 'hostname': 'dummy.host.org', 'username': '******', 'password': '******', 'timeout': '600' } ssh_client = ParamikoSSHClient(**conn_params) ssh_client.connect() call_kwargs = mock_client.connect.call_args[1] self.assertEqual(call_kwargs['port'], 22) mock_client = mock.Mock() mock_sshclient.return_value = mock_client conn_params = { 'hostname': 'dummy.host.org', 'username': '******', 'password': '******', 'port': None, 'timeout': '600' } ssh_client = ParamikoSSHClient(**conn_params) ssh_client.connect() call_kwargs = mock_client.connect.call_args[1] self.assertEqual(call_kwargs['port'], 22) # 2. Default port is used (explicitly provided) mock_client = mock.Mock() mock_sshclient.return_value = mock_client conn_params = { 'hostname': 'dummy.host.org', 'username': '******', 'password': '******', 'port': DEFAULT_SSH_PORT, 'timeout': '600' } ssh_client = ParamikoSSHClient(**conn_params) ssh_client.connect() call_kwargs = mock_client.connect.call_args[1] self.assertEqual(call_kwargs['port'], DEFAULT_SSH_PORT) self.assertEqual(call_kwargs['port'], 22) # 3. Custom port is used (explicitly provided) mock_client = mock.Mock() mock_sshclient.return_value = mock_client conn_params = { 'hostname': 'dummy.host.org', 'username': '******', 'password': '******', 'port': 5555, 'timeout': '600' } ssh_client = ParamikoSSHClient(**conn_params) ssh_client.connect() call_kwargs = mock_client.connect.call_args[1] self.assertEqual(call_kwargs['port'], 5555) # 4. Custom port is specified in the ssh config (it has precedence over default port) ssh_config_file_path = os.path.join(get_resources_base_path(), 'ssh', 'ssh_config_custom_port') cfg.CONF.set_override(name='ssh_config_file_path', override=ssh_config_file_path, group='ssh_runner') mock_client = mock.Mock() mock_sshclient.return_value = mock_client conn_params = { 'hostname': 'dummy.host.org', 'username': '******', 'password': '******' } ssh_client = ParamikoSSHClient(**conn_params) ssh_client.connect() call_kwargs = mock_client.connect.call_args[1] self.assertEqual(call_kwargs['port'], 6677) mock_client = mock.Mock() mock_sshclient.return_value = mock_client conn_params = { 'hostname': 'dummy.host.org', 'username': '******', 'password': '******', 'port': DEFAULT_SSH_PORT } ssh_client = ParamikoSSHClient(**conn_params) ssh_client.connect() call_kwargs = mock_client.connect.call_args[1] self.assertEqual(call_kwargs['port'], 6677) # 5. Custom port is specified in ssh config, but one is also provided via runner parameter # (runner parameter one has precedence) ssh_config_file_path = os.path.join(get_resources_base_path(), 'ssh', 'ssh_config_custom_port') cfg.CONF.set_override(name='ssh_config_file_path', override=ssh_config_file_path, group='ssh_runner') mock_client = mock.Mock() mock_sshclient.return_value = mock_client conn_params = { 'hostname': 'dummy.host.org', 'username': '******', 'password': '******', 'port': 9999 } ssh_client = ParamikoSSHClient(**conn_params) ssh_client.connect() call_kwargs = mock_client.connect.call_args[1] self.assertEqual(call_kwargs['port'], 9999)
def test_use_ssh_config_port_value_provided_in_the_config( self, mock_sshclient): cfg.CONF.set_override(name="use_ssh_config", override=True, group="ssh_runner") ssh_config_file_path = os.path.join(get_resources_base_path(), "ssh", "empty_config") cfg.CONF.set_override( name="ssh_config_file_path", override=ssh_config_file_path, group="ssh_runner", ) # 1. Default port is used (not explicitly provided) mock_client = mock.Mock() mock_sshclient.return_value = mock_client conn_params = { "hostname": "dummy.host.org", "username": "******", "password": "******", "timeout": "600", } ssh_client = ParamikoSSHClient(**conn_params) ssh_client.connect() call_kwargs = mock_client.connect.call_args[1] self.assertEqual(call_kwargs["port"], 22) mock_client = mock.Mock() mock_sshclient.return_value = mock_client conn_params = { "hostname": "dummy.host.org", "username": "******", "password": "******", "port": None, "timeout": "600", } ssh_client = ParamikoSSHClient(**conn_params) ssh_client.connect() call_kwargs = mock_client.connect.call_args[1] self.assertEqual(call_kwargs["port"], 22) # 2. Default port is used (explicitly provided) mock_client = mock.Mock() mock_sshclient.return_value = mock_client conn_params = { "hostname": "dummy.host.org", "username": "******", "password": "******", "port": DEFAULT_SSH_PORT, "timeout": "600", } ssh_client = ParamikoSSHClient(**conn_params) ssh_client.connect() call_kwargs = mock_client.connect.call_args[1] self.assertEqual(call_kwargs["port"], DEFAULT_SSH_PORT) self.assertEqual(call_kwargs["port"], 22) # 3. Custom port is used (explicitly provided) mock_client = mock.Mock() mock_sshclient.return_value = mock_client conn_params = { "hostname": "dummy.host.org", "username": "******", "password": "******", "port": 5555, "timeout": "600", } ssh_client = ParamikoSSHClient(**conn_params) ssh_client.connect() call_kwargs = mock_client.connect.call_args[1] self.assertEqual(call_kwargs["port"], 5555) # 4. Custom port is specified in the ssh config (it has precedence over default port) ssh_config_file_path = os.path.join(get_resources_base_path(), "ssh", "ssh_config_custom_port") cfg.CONF.set_override( name="ssh_config_file_path", override=ssh_config_file_path, group="ssh_runner", ) mock_client = mock.Mock() mock_sshclient.return_value = mock_client conn_params = { "hostname": "dummy.host.org", "username": "******", "password": "******", } ssh_client = ParamikoSSHClient(**conn_params) ssh_client.connect() call_kwargs = mock_client.connect.call_args[1] self.assertEqual(call_kwargs["port"], 6677) mock_client = mock.Mock() mock_sshclient.return_value = mock_client conn_params = { "hostname": "dummy.host.org", "username": "******", "password": "******", "port": DEFAULT_SSH_PORT, } ssh_client = ParamikoSSHClient(**conn_params) ssh_client.connect() call_kwargs = mock_client.connect.call_args[1] self.assertEqual(call_kwargs["port"], 6677) # 5. Custom port is specified in ssh config, but one is also provided via runner parameter # (runner parameter one has precedence) ssh_config_file_path = os.path.join(get_resources_base_path(), "ssh", "ssh_config_custom_port") cfg.CONF.set_override( name="ssh_config_file_path", override=ssh_config_file_path, group="ssh_runner", ) mock_client = mock.Mock() mock_sshclient.return_value = mock_client conn_params = { "hostname": "dummy.host.org", "username": "******", "password": "******", "port": 9999, } ssh_client = ParamikoSSHClient(**conn_params) ssh_client.connect() call_kwargs = mock_client.connect.call_args[1] self.assertEqual(call_kwargs["port"], 9999)
def test_handle_stdout_and_stderr_line_funcs(self): mock_handle_stdout_line_func = mock.Mock() mock_handle_stderr_line_func = mock.Mock() conn_params = { 'hostname': 'dummy.host.org', 'username': '******', 'password': '******', 'handle_stdout_line_func': mock_handle_stdout_line_func, 'handle_stderr_line_func': mock_handle_stderr_line_func } client = ParamikoSSHClient(**conn_params) client.connect() mock_get_transport = mock.Mock() mock_chan = mock.Mock() client.client.get_transport = mock.Mock() client.client.get_transport.return_value = mock_get_transport mock_get_transport.open_session.return_value = mock_chan def mock_recv_ready_factory(chan): chan.recv_counter = 0 def mock_recv_ready(): chan.recv_counter += 1 if chan.recv_counter < 2: return True return False return mock_recv_ready def mock_recv_stderr_ready_factory(chan): chan.recv_stderr_counter = 0 def mock_recv_stderr_ready(): chan.recv_stderr_counter += 1 if chan.recv_stderr_counter < 2: return True return False return mock_recv_stderr_ready mock_chan.recv_ready = mock_recv_ready_factory(mock_chan) mock_chan.recv_stderr_ready = mock_recv_stderr_ready_factory(mock_chan) mock_chan.recv.return_value = 'stdout 1\nstdout 2\nstdout 3' mock_chan.recv_stderr.return_value = 'stderr 1\nstderr 2\nstderr 3' # call_line_handler_func is False so handler functions shouldn't be called client.run(cmd='echo "test"', call_line_handler_func=False) self.assertEqual(mock_handle_stdout_line_func.call_count, 0) self.assertEqual(mock_handle_stderr_line_func.call_count, 0) # Reset counters mock_chan.recv_counter = 0 mock_chan.recv_stderr_counter = 0 # call_line_handler_func is True so handler functions should be called for each line client.run(cmd='echo "test"', call_line_handler_func=True) self.assertEqual(mock_handle_stdout_line_func.call_count, 3) self.assertEqual(mock_handle_stdout_line_func.call_args_list[0][1]['line'], 'stdout 1\n') self.assertEqual(mock_handle_stdout_line_func.call_args_list[1][1]['line'], 'stdout 2\n') self.assertEqual(mock_handle_stdout_line_func.call_args_list[2][1]['line'], 'stdout 3\n') self.assertEqual(mock_handle_stderr_line_func.call_count, 3) self.assertEqual(mock_handle_stdout_line_func.call_args_list[0][1]['line'], 'stdout 1\n') self.assertEqual(mock_handle_stdout_line_func.call_args_list[1][1]['line'], 'stdout 2\n') self.assertEqual(mock_handle_stdout_line_func.call_args_list[2][1]['line'], 'stdout 3\n')
def test_sftp_connection_is_only_established_if_required(self): # Verify that SFTP connection is lazily established only if and when needed. conn_params = {'hostname': 'dummy.host.org', 'username': '******'} # Verify sftp connection and client hasn't been established yet client = ParamikoSSHClient(**conn_params) client.connect() self.assertTrue(client.sftp_client is None) # run method doesn't require sftp access so it shouldn't establish connection client = ParamikoSSHClient(**conn_params) client.connect() client.run(cmd='whoami') self.assertTrue(client.sftp_client is None) # Methods bellow require SFTP access so they should cause SFTP connection to be established # put client = ParamikoSSHClient(**conn_params) client.connect() path = '/root/random_script.sh' client.put(path, path, mirror_local_mode=False) self.assertTrue(client.sftp_client is not None) # exists client = ParamikoSSHClient(**conn_params) client.connect() client.exists('/root/somepath.txt') self.assertTrue(client.sftp_client is not None) # mkdir client = ParamikoSSHClient(**conn_params) client.connect() client.mkdir('/root/somedirfoo') self.assertTrue(client.sftp_client is not None) # Verify close doesn't throw if SFTP connection is not established client = ParamikoSSHClient(**conn_params) client.connect() self.assertTrue(client.sftp_client is None) client.close() # Verify SFTP connection is closed if it's opened client = ParamikoSSHClient(**conn_params) client.connect() client.mkdir('/root/somedirfoo') self.assertTrue(client.sftp_client is not None) client.close() self.assertEqual(client.sftp_client.close.call_count, 1)
def test_use_ssh_config_port_value_provided_in_the_config(self, mock_sshclient): cfg.CONF.set_override(name='use_ssh_config', override=True, group='ssh_runner') ssh_config_file_path = os.path.join(get_resources_base_path(), 'ssh', 'empty_config') cfg.CONF.set_override(name='ssh_config_file_path', override=ssh_config_file_path, group='ssh_runner') # 1. Default port is used (not explicitly provided) mock_client = mock.Mock() mock_sshclient.return_value = mock_client conn_params = {'hostname': 'dummy.host.org', 'username': '******', 'password': '******', 'timeout': '600'} ssh_client = ParamikoSSHClient(**conn_params) ssh_client.connect() call_kwargs = mock_client.connect.call_args[1] self.assertEqual(call_kwargs['port'], 22) mock_client = mock.Mock() mock_sshclient.return_value = mock_client conn_params = {'hostname': 'dummy.host.org', 'username': '******', 'password': '******', 'port': None, 'timeout': '600'} ssh_client = ParamikoSSHClient(**conn_params) ssh_client.connect() call_kwargs = mock_client.connect.call_args[1] self.assertEqual(call_kwargs['port'], 22) # 2. Default port is used (explicitly provided) mock_client = mock.Mock() mock_sshclient.return_value = mock_client conn_params = {'hostname': 'dummy.host.org', 'username': '******', 'password': '******', 'port': DEFAULT_SSH_PORT, 'timeout': '600'} ssh_client = ParamikoSSHClient(**conn_params) ssh_client.connect() call_kwargs = mock_client.connect.call_args[1] self.assertEqual(call_kwargs['port'], DEFAULT_SSH_PORT) self.assertEqual(call_kwargs['port'], 22) # 3. Custom port is used (explicitly provided) mock_client = mock.Mock() mock_sshclient.return_value = mock_client conn_params = {'hostname': 'dummy.host.org', 'username': '******', 'password': '******', 'port': 5555, 'timeout': '600'} ssh_client = ParamikoSSHClient(**conn_params) ssh_client.connect() call_kwargs = mock_client.connect.call_args[1] self.assertEqual(call_kwargs['port'], 5555) # 4. Custom port is specified in the ssh config (it has precedence over default port) ssh_config_file_path = os.path.join(get_resources_base_path(), 'ssh', 'ssh_config_custom_port') cfg.CONF.set_override(name='ssh_config_file_path', override=ssh_config_file_path, group='ssh_runner') mock_client = mock.Mock() mock_sshclient.return_value = mock_client conn_params = {'hostname': 'dummy.host.org', 'username': '******', 'password': '******'} ssh_client = ParamikoSSHClient(**conn_params) ssh_client.connect() call_kwargs = mock_client.connect.call_args[1] self.assertEqual(call_kwargs['port'], 6677) mock_client = mock.Mock() mock_sshclient.return_value = mock_client conn_params = {'hostname': 'dummy.host.org', 'username': '******', 'password': '******', 'port': DEFAULT_SSH_PORT} ssh_client = ParamikoSSHClient(**conn_params) ssh_client.connect() call_kwargs = mock_client.connect.call_args[1] self.assertEqual(call_kwargs['port'], 6677) # 5. Custom port is specified in ssh config, but one is also provided via runner parameter # (runner parameter one has precedence) ssh_config_file_path = os.path.join(get_resources_base_path(), 'ssh', 'ssh_config_custom_port') cfg.CONF.set_override(name='ssh_config_file_path', override=ssh_config_file_path, group='ssh_runner') mock_client = mock.Mock() mock_sshclient.return_value = mock_client conn_params = {'hostname': 'dummy.host.org', 'username': '******', 'password': '******', 'port': 9999} ssh_client = ParamikoSSHClient(**conn_params) ssh_client.connect() call_kwargs = mock_client.connect.call_args[1] self.assertEqual(call_kwargs['port'], 9999)