Skip to content

Commit

Permalink
Merge 07239ab into 5f107c0
Browse files Browse the repository at this point in the history
  • Loading branch information
penguinolog committed May 2, 2018
2 parents 5f107c0 + 07239ab commit 731e55e
Show file tree
Hide file tree
Showing 12 changed files with 969 additions and 460 deletions.
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ insert_final_newline = true
trim_trailing_whitespace = true

[*.{py,ini}]
max_line_length = 79
max_line_length = 120

[*.{yml,rst}]
indent_size = 2
Expand Down
2 changes: 1 addition & 1 deletion .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ logging-modules=logging
[FORMAT]

# Maximum number of characters on a single line.
max-line-length=80
max-line-length=120

# Regexp for a line that is allowed to be longer than the limit.
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
Expand Down
12 changes: 8 additions & 4 deletions doc/source/SSHClient.rst
Original file line number Diff line number Diff line change
Expand Up @@ -101,24 +101,28 @@ API: SSHClient and SSHAuth.
:param enforce: Enforce sudo enabled or disabled. By default: None
:type enforce: ``typing.Optional[bool]``

.. py:method:: execute_async(command, get_pty=False, open_stdout=True, open_stderr=True, stdin=None, **kwargs)
.. py:method:: execute_async(command, stdin=None, open_stdout=True, open_stderr=True, verbose=False, log_mask_re=None, **kwargs)
Execute command in async mode and return channel with IO objects.

:param command: Command for execution
:type command: ``str``
:param get_pty: open PTY on remote machine
:type get_pty: ``bool``
:param stdin: pass STDIN text to the process
:type stdin: ``typing.Union[six.text_type, six.binary_type, None]``
:type stdin: ``typing.Union[six.text_type, six.binary_type, bytearray, None]``
:param open_stdout: open STDOUT stream for read
:type open_stdout: bool
:param open_stderr: open STDERR stream for read
:type open_stderr: bool
:param verbose: produce verbose log record on command call
:type verbose: bool
:param log_mask_re: regex lookup rule to mask command for logger.
all MATCHED groups will be replaced by '<*masked*>'
:type log_mask_re: typing.Optional[str]
:rtype: ``typing.Tuple[paramiko.Channel, paramiko.ChannelFile, paramiko.ChannelFile, paramiko.ChannelFile]``

.. versionchanged:: 1.2.0 open_stdout and open_stderr flags
.. versionchanged:: 1.2.0 stdin data
.. versionchanged:: 1.2.0 get_pty moved to `**kwargs`

.. py:method:: execute(command, verbose=False, timeout=1*60*60, **kwargs)
Expand Down
21 changes: 21 additions & 0 deletions doc/source/Subprocess.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,27 @@ API: Subprocess

.. versionchanged:: 1.1.0 release lock on exit

.. py:method:: execute_async(command, stdin=None, open_stdout=True, open_stderr=True, verbose=False, log_mask_re=None, **kwargs)
Execute command in async mode and return Popen with IO objects.

:param command: Command for execution
:type command: str
:param stdin: pass STDIN text to the process
:type stdin: typing.Union[six.text_type, six.binary_type, bytearray, None]
:param open_stdout: open STDOUT stream for read
:type open_stdout: bool
:param open_stderr: open STDERR stream for read
:type open_stderr: bool
:param verbose: produce verbose log record on command call
:type verbose: bool
:param log_mask_re: regex lookup rule to mask command for logger.
all MATCHED groups will be replaced by '<*masked*>'
:type log_mask_re: typing.Optional[str]
:rtype: ``typing.Tuple[subprocess.Popen, None, typing.Optional[io.TextIOWrapper], typing.Optional[io.TextIOWrapper], ]``

.. versionadded:: 1.2.0

.. py:method:: execute(command, verbose=False, timeout=1*60*60, **kwargs)
Execute command and wait for return code.
Expand Down
107 changes: 105 additions & 2 deletions exec_helpers/_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,16 @@
from __future__ import division
from __future__ import unicode_literals

import logging
import re
import threading
import typing # noqa # pylint: disable=unused-import

import six # noqa # pylint: disable=unused-import

from exec_helpers import constants
from exec_helpers import exceptions
from exec_helpers import exec_result # noqa # pylint: disable=unused-import
from exec_helpers import proc_enums
from exec_helpers import _log_templates

Expand All @@ -44,7 +49,7 @@ def __init__(
self,
logger, # type: logging.Logger
log_mask_re=None, # type: typing.Optional[str]
):
): # type: (...) -> None
"""ExecHelper global API.
:param log_mask_re: regex lookup rule to mask command for logger.
Expand Down Expand Up @@ -126,6 +131,78 @@ def mask(text, rules): # type: (str, str) -> str

return cmd

def execute_async(
self,
command, # type: str
stdin=None, # type: typing.Union[six.text_type, six.binary_type, bytearray, None]
open_stdout=True, # type: bool
open_stderr=True, # type: bool
verbose=False, # type: bool
log_mask_re=None, # type: typing.Optional[str]
**kwargs
):
"""Execute command in async mode and return remote interface with IO objects.
:param command: Command for execution
:type command: str
:param stdin: pass STDIN text to the process
:type stdin: typing.Union[six.text_type, six.binary_type, bytearray, None]
:param open_stdout: open STDOUT stream for read
:type open_stdout: bool
:param open_stderr: open STDERR stream for read
:type open_stderr: bool
:param verbose: produce verbose log record on command call
:type verbose: bool
:param log_mask_re: regex lookup rule to mask command for logger.
all MATCHED groups will be replaced by '<*masked*>'
:type log_mask_re: typing.Optional[str]
:rtype: typing.Tuple[
typing.Any,
typing.Any,
typing.Any,
typing.Any,
]
.. versionchanged:: 1.2.0 open_stdout and open_stderr flags
.. versionchanged:: 1.2.0 stdin data
"""
raise NotImplementedError # pragma: no cover

def _exec_command(
self,
command, # type: str
interface, # type: typing.Any,
stdout, # type: typing.Any,
stderr, # type: typing.Any,
timeout, # type: int
verbose=False, # type: bool
log_mask_re=None, # type: typing.Optional[str]
**kwargs
): # type: (...) -> exec_result.ExecResult
"""Get exit status from channel with timeout.
:param command: Command for execution
:type command: str
:param interface: Control interface
:type interface: typing.Any
:param stdout: STDOUT pipe or file-like object
:type stdout: typing.Any
:param stderr: STDERR pipe or file-like object
:type stderr: typing.Any
:param timeout: Timeout for command execution
:type timeout: int
:param verbose: produce verbose log record on command call
:type verbose: bool
:param log_mask_re: regex lookup rule to mask command for logger.
all MATCHED groups will be replaced by '<*masked*>'
:type log_mask_re: typing.Optional[str]
:rtype: ExecResult
:raises ExecHelperTimeoutError: Timeout exceeded
.. versionchanged:: 1.2.0 log_mask_re regex rule for masking cmd
"""
raise NotImplementedError # pragma: no cover

def execute(
self,
command, # type: str
Expand All @@ -148,7 +225,33 @@ def execute(
.. versionchanged:: 1.2.0 default timeout 1 hour
"""
raise NotImplementedError() # pragma: no cover
with self.lock:
(
iface, # type: typing.Any
_,
stderr, # type: typing.Any
stdout, # type: typing.Any
) = self.execute_async(
command,
verbose=verbose,
**kwargs
)

result = self._exec_command(
command=command,
interface=iface,
stdout=stdout,
stderr=stderr,
timeout=timeout,
verbose=verbose,
**kwargs
)
message = _log_templates.CMD_RESULT.format(result=result)
self.logger.log(
level=logging.INFO if verbose else logging.DEBUG,
msg=message
)
return result

def check_call(
self,
Expand Down

0 comments on commit 731e55e

Please sign in to comment.