Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 5 additions & 19 deletions exec_helpers/_ssh_client_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,24 +191,11 @@ def clear_cache(mcs): # type: () -> None
mcs.__cache = {}

@classmethod
def close_connections(
mcs,
hostname=None # type: typing.Optional[str]
): # type: (...) -> None
"""Close connections for selected or all cached records.

:type hostname: str
"""
if hostname is None:
keys = [key for key, ssh in mcs.__cache.items() if ssh.is_alive]
else:
keys = [
(host, port)
for (host, port), ssh
in mcs.__cache.items() if host == hostname and ssh.is_alive]
# raise ValueError(keys)
for key in keys:
mcs.__cache[key].close()
def close_connections(mcs): # type: (...) -> None
"""Close connections for selected or all cached records."""
for ssh in mcs.__cache.values():
if ssh.is_alive:
ssh.close()


class SSHClientBase(six.with_metaclass(_MemorizedSSH, _api.ExecHelper)):
Expand Down Expand Up @@ -742,7 +729,6 @@ def poll_pipes(stop, ): # type: (threading.Event) -> None

# Process closed?
if stop_event.is_set():
stop_event.clear()
interface.close()
return result

Expand Down
13 changes: 5 additions & 8 deletions exec_helpers/proc_enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from __future__ import unicode_literals

import enum
import typing
import typing # noqa # pylint: disable=unused-import

import six

Expand Down Expand Up @@ -72,7 +72,7 @@ class SigNum(enum.IntEnum):
SIGPWR = 30 # Power failure restart (System V).
SIGSYS = 31 # Bad system call.

def __str__(self):
def __str__(self): # pragma: no cover
"""Representation for logs."""
return "{name}<{value:d}(0x{value:02X})>".format(
name=self.name,
Expand Down Expand Up @@ -158,19 +158,16 @@ def __str__(self):
)


_type_exit_codes = typing.Union[int, ExitCodes]


def exit_code_to_enum(code): # type: (_type_exit_codes) -> _type_exit_codes
def exit_code_to_enum(code): # type: (typing.Union[int, ExitCodes]) -> typing.Union[int, ExitCodes]
"""Convert exit code to enum if possible."""
if isinstance(code, int) and code in ExitCodes.__members__.values():
return ExitCodes(code)
return code


def exit_codes_to_enums(
codes=None # type: typing.Optional[typing.Iterable[_type_exit_codes]]
): # type: (...) -> typing.List[_type_exit_codes]
codes=None # type: typing.Optional[typing.Iterable[typing.Union[int, ExitCodes]]]
): # type: (...) -> typing.List[typing.Union[int, ExitCodes]]
"""Convert integer exit codes to enums."""
if codes is None:
return [ExitCodes.EX_OK]
Expand Down
1 change: 0 additions & 1 deletion exec_helpers/subprocess_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,6 @@ def poll_pipes(stop, ): # type: (threading.Event) -> None

# Process closed?
if stop_event.is_set():
stop_event.clear()
return result
# Kill not ended process and wait for close
try:
Expand Down
63 changes: 61 additions & 2 deletions test/test_ssh_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -994,7 +994,7 @@ def test_024_execute_timeout(
logger.reset_mock()

# noinspection PyTypeChecker
result = ssh.execute(command=command, verbose=False, timeout=0.1)
result = ssh.execute(command=command, verbose=False, timeout=0.2)

self.assertEqual(
result,
Expand Down Expand Up @@ -1030,7 +1030,7 @@ def test_025_execute_timeout_fail(

with self.assertRaises(exec_helpers.ExecHelperTimeoutError):
# noinspection PyTypeChecker
ssh.execute(command=command, verbose=False, timeout=0.1)
ssh.execute(command=command, verbose=False, timeout=0.2)

execute_async.assert_called_once_with(command, verbose=False)
chan.assert_has_calls((mock.call.status_event.is_set(), ))
Expand Down Expand Up @@ -1468,6 +1468,65 @@ def test_02_execute_through_host_auth(self, transp, client, policy, logger):
mock.call.close()
))

def test_03_execute_through_host_get_pty(
self, transp, client, policy, logger):
target = '127.0.0.2'
exit_code = 0

# noinspection PyTypeChecker
return_value = exec_result.ExecResult(
cmd=command,
stderr=stderr_list,
stdout=stdout_list,
exit_code=exit_code
)

(
open_session,
transport,
channel,
get_transport,
open_channel,
intermediate_channel
) = self.prepare_execute_through_host(
transp=transp,
client=client,
exit_code=exit_code)

# noinspection PyTypeChecker
ssh = exec_helpers.SSHClient(
host=host,
port=port,
auth=exec_helpers.SSHAuth(
username=username,
password=password
))

# noinspection PyTypeChecker
result = ssh.execute_through_host(target, command, get_pty=True)
self.assertEqual(result, return_value)
get_transport.assert_called_once()
open_channel.assert_called_once()
transp.assert_called_once_with(intermediate_channel)
open_session.assert_called_once()
transport.assert_has_calls((
mock.call.connect(
username=username, password=password, pkey=None,
),
mock.call.open_session()
))

channel.assert_has_calls((
mock.call.get_pty(term='vt100', width=80, height=24, width_pixels=0, height_pixels=0),
mock.call.makefile('rb'),
mock.call.makefile_stderr('rb'),
mock.call.exec_command(command),
mock.call.recv_ready(),
mock.call.recv_stderr_ready(),
mock.call.status_event.is_set(),
mock.call.close()
))


@mock.patch('exec_helpers._ssh_client_base.logger', autospec=True)
@mock.patch('paramiko.AutoAddPolicy', autospec=True, return_value='AutoAddPolicy')
Expand Down
11 changes: 4 additions & 7 deletions test/test_ssh_client_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -708,13 +708,10 @@ def test_023_init_memorize(
no_call.assert_not_called()
# Mock returns false-connected state, so we just count close calls

client.assert_has_calls((
mock.call().get_transport(),
mock.call().get_transport(),
mock.call().get_transport(),
mock.call().close(),
mock.call().close(),
mock.call().close(),
client().close.assert_has_calls((
mock.call(),
mock.call(),
mock.call(),
))

# change creds
Expand Down
7 changes: 4 additions & 3 deletions test/test_subprocess_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ def test_003_context_manager(

with mock.patch('threading.RLock', autospec=True):
with exec_helpers.Subprocess() as runner:
runner.lock.acquire.assert_called()
self.assertEqual(
mock.call.acquire(), runner.lock.mock_calls[0]
)
Expand All @@ -215,7 +216,7 @@ def test_003_context_manager(

)

self.assertEqual(mock.call.release(), runner.lock.mock_calls[-1])
runner.lock.release.assert_called()

subprocess_runner.SingletonMeta._instances.clear()

Expand All @@ -235,7 +236,7 @@ def test_004_execute_timeout_fail(

with self.assertRaises(exec_helpers.ExecHelperTimeoutError):
# noinspection PyTypeChecker
runner.execute(command, timeout=1)
runner.execute(command, timeout=0.2)

popen.assert_has_calls((
mock.call(
Expand Down Expand Up @@ -830,7 +831,7 @@ def test_013_execute_timeout_done(

# noinspection PyTypeChecker

res = runner.execute(command, timeout=0.1)
res = runner.execute(command, timeout=0.2)

self.assertEqual(res, exp_result)

Expand Down