[#314] Format all files with black and isort
Signed-off-by: Vladimir Domnich <v.domnich@yadro.com>
This commit is contained in:
parent
26032a67ec
commit
147cac0ebc
46 changed files with 1506 additions and 1100 deletions
|
@ -10,7 +10,7 @@ from time import sleep
|
|||
from typing import ClassVar, Optional
|
||||
|
||||
import allure
|
||||
from paramiko import AutoAddPolicy, SFTPClient, SSHClient, SSHException, ssh_exception, RSAKey
|
||||
from paramiko import AutoAddPolicy, RSAKey, SFTPClient, SSHClient, SSHException, ssh_exception
|
||||
from paramiko.ssh_exception import AuthenticationException
|
||||
|
||||
|
||||
|
@ -20,34 +20,37 @@ class HostIsNotAvailable(Exception):
|
|||
def __init__(self, ip: str = None, exc: Exception = None):
|
||||
msg = f'Host is not available{f" by ip: {ip}" if ip else ""}'
|
||||
if exc:
|
||||
msg = f'{msg}. {exc}'
|
||||
msg = f"{msg}. {exc}"
|
||||
super().__init__(msg)
|
||||
|
||||
|
||||
def log_command(func):
|
||||
@wraps(func)
|
||||
def wrapper(host: 'HostClient', command: str, *args, **kwargs):
|
||||
def wrapper(host: "HostClient", command: str, *args, **kwargs):
|
||||
display_length = 60
|
||||
short = command.removeprefix("$ProgressPreference='SilentlyContinue'\n")
|
||||
short = short[:display_length]
|
||||
short += '...' if short != command else ''
|
||||
with allure.step(f'SSH: {short}'):
|
||||
short += "..." if short != command else ""
|
||||
with allure.step(f"SSH: {short}"):
|
||||
logging.info(f'Execute command "{command}" on "{host.ip}"')
|
||||
|
||||
start_time = datetime.utcnow()
|
||||
cmd_result = func(host, command, *args, **kwargs)
|
||||
end_time = datetime.utcnow()
|
||||
|
||||
log_message = f'HOST: {host.ip}\n' \
|
||||
f'COMMAND:\n{textwrap.indent(command, " ")}\n' \
|
||||
f'RC:\n {cmd_result.rc}\n' \
|
||||
f'STDOUT:\n{textwrap.indent(cmd_result.stdout, " ")}\n' \
|
||||
f'STDERR:\n{textwrap.indent(cmd_result.stderr, " ")}\n' \
|
||||
f'Start / End / Elapsed\t {start_time.time()} / {end_time.time()} / {end_time - start_time}'
|
||||
log_message = (
|
||||
f"HOST: {host.ip}\n"
|
||||
f'COMMAND:\n{textwrap.indent(command, " ")}\n'
|
||||
f"RC:\n {cmd_result.rc}\n"
|
||||
f'STDOUT:\n{textwrap.indent(cmd_result.stdout, " ")}\n'
|
||||
f'STDERR:\n{textwrap.indent(cmd_result.stderr, " ")}\n'
|
||||
f"Start / End / Elapsed\t {start_time.time()} / {end_time.time()} / {end_time - start_time}"
|
||||
)
|
||||
|
||||
logging.info(log_message)
|
||||
allure.attach(log_message, 'SSH command', allure.attachment_type.TEXT)
|
||||
allure.attach(log_message, "SSH command", allure.attachment_type.TEXT)
|
||||
return cmd_result
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
|
@ -65,9 +68,15 @@ class HostClient:
|
|||
|
||||
TIMEOUT_RESTORE_CONNECTION = 10, 24
|
||||
|
||||
def __init__(self, ip: str, login: str, password: Optional[str] = None,
|
||||
private_key_path: Optional[str] = None, private_key_passphrase: Optional[str] = None,
|
||||
init_ssh_client=True) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
ip: str,
|
||||
login: str,
|
||||
password: Optional[str] = None,
|
||||
private_key_path: Optional[str] = None,
|
||||
private_key_passphrase: Optional[str] = None,
|
||||
init_ssh_client=True,
|
||||
) -> None:
|
||||
self.ip = ip
|
||||
self.login = login
|
||||
self.password = password
|
||||
|
@ -83,21 +92,25 @@ class HostClient:
|
|||
return cmd_result
|
||||
|
||||
@log_command
|
||||
def exec_with_confirmation(self, cmd: str, confirmation: list, verify=True, timeout=90) -> SSHCommand:
|
||||
def exec_with_confirmation(
|
||||
self, cmd: str, confirmation: list, verify=True, timeout=90
|
||||
) -> SSHCommand:
|
||||
ssh_stdin, ssh_stdout, ssh_stderr = self.ssh_client.exec_command(cmd, timeout=timeout)
|
||||
for line in confirmation:
|
||||
if not line.endswith('\n'):
|
||||
line = f'{line}\n'
|
||||
if not line.endswith("\n"):
|
||||
line = f"{line}\n"
|
||||
try:
|
||||
ssh_stdin.write(line)
|
||||
except OSError as err:
|
||||
logging.error(f'Got error {err} executing command {cmd}')
|
||||
logging.error(f"Got error {err} executing command {cmd}")
|
||||
ssh_stdin.close()
|
||||
output = SSHCommand(stdout=ssh_stdout.read().decode(errors='ignore'),
|
||||
stderr=ssh_stderr.read().decode(errors='ignore'),
|
||||
rc=ssh_stdout.channel.recv_exit_status())
|
||||
output = SSHCommand(
|
||||
stdout=ssh_stdout.read().decode(errors="ignore"),
|
||||
stderr=ssh_stderr.read().decode(errors="ignore"),
|
||||
rc=ssh_stdout.channel.recv_exit_status(),
|
||||
)
|
||||
if verify:
|
||||
debug_info = f'\nSTDOUT: {output.stdout}\nSTDERR: {output.stderr}\nRC: {output.rc}'
|
||||
debug_info = f"\nSTDOUT: {output.stdout}\nSTDERR: {output.stderr}\nRC: {output.rc}"
|
||||
assert output.rc == 0, f'Non zero rc from command: "{cmd}"{debug_info}'
|
||||
return output
|
||||
|
||||
|
@ -111,7 +124,7 @@ class HostClient:
|
|||
self.create_connection()
|
||||
|
||||
@contextmanager
|
||||
def create_ssh_connection(self) -> 'SSHClient':
|
||||
def create_ssh_connection(self) -> "SSHClient":
|
||||
if not self.ssh_client:
|
||||
self.create_connection()
|
||||
try:
|
||||
|
@ -119,38 +132,40 @@ class HostClient:
|
|||
finally:
|
||||
self.drop()
|
||||
|
||||
@allure.step('Restore connection')
|
||||
@allure.step("Restore connection")
|
||||
def restore_ssh_connection(self):
|
||||
retry_time, retry_count = self.TIMEOUT_RESTORE_CONNECTION
|
||||
for _ in range(retry_count):
|
||||
try:
|
||||
self.create_connection()
|
||||
except AssertionError:
|
||||
logging.warning(f'Host: Cant reach host: {self.ip}.')
|
||||
logging.warning(f"Host: Cant reach host: {self.ip}.")
|
||||
sleep(retry_time)
|
||||
else:
|
||||
logging.info(f'Host: Cant reach host: {self.ip}.')
|
||||
logging.info(f"Host: Cant reach host: {self.ip}.")
|
||||
return
|
||||
raise AssertionError(f'Host: Cant reach host: {self.ip} after 240 seconds..')
|
||||
raise AssertionError(f"Host: Cant reach host: {self.ip} after 240 seconds..")
|
||||
|
||||
@allure.step('Copy file {host_path_to_file} to local file {path_to_file}')
|
||||
@allure.step("Copy file {host_path_to_file} to local file {path_to_file}")
|
||||
def copy_file_from_host(self, host_path_to_file: str, path_to_file: str):
|
||||
with self._sftp_client() as sftp_client:
|
||||
sftp_client.get(host_path_to_file, path_to_file)
|
||||
|
||||
def copy_file_to_host(self, path_to_file: str, host_path_to_file: str):
|
||||
with allure.step(f'Copy local file {path_to_file} to remote file {host_path_to_file} on host {self.ip}'):
|
||||
with allure.step(
|
||||
f"Copy local file {path_to_file} to remote file {host_path_to_file} on host {self.ip}"
|
||||
):
|
||||
with self._sftp_client() as sftp_client:
|
||||
sftp_client.put(path_to_file, host_path_to_file)
|
||||
|
||||
@allure.step('Save string to remote file {host_path_to_file}')
|
||||
@allure.step("Save string to remote file {host_path_to_file}")
|
||||
def copy_str_to_host_file(self, string: str, host_path_to_file: str):
|
||||
with tempfile.NamedTemporaryFile(mode='r+') as temp:
|
||||
with tempfile.NamedTemporaryFile(mode="r+") as temp:
|
||||
temp.writelines(string)
|
||||
temp.flush()
|
||||
with self._sftp_client() as client:
|
||||
client.put(temp.name, host_path_to_file)
|
||||
self.exec(f'cat {host_path_to_file}', verify=False)
|
||||
self.exec(f"cat {host_path_to_file}", verify=False)
|
||||
|
||||
def create_connection(self, attempts=SSH_CONNECTION_ATTEMPTS):
|
||||
exc_err = None
|
||||
|
@ -166,8 +181,10 @@ class HostClient:
|
|||
self.ssh_client.connect(
|
||||
hostname=self.ip,
|
||||
username=self.login,
|
||||
pkey=RSAKey.from_private_key_file(self.private_key_path, self.private_key_passphrase),
|
||||
timeout=self.CONNECTION_TIMEOUT
|
||||
pkey=RSAKey.from_private_key_file(
|
||||
self.private_key_path, self.private_key_passphrase
|
||||
),
|
||||
timeout=self.CONNECTION_TIMEOUT,
|
||||
)
|
||||
else:
|
||||
logging.info(
|
||||
|
@ -178,25 +195,25 @@ class HostClient:
|
|||
hostname=self.ip,
|
||||
username=self.login,
|
||||
password=self.password,
|
||||
timeout=self.CONNECTION_TIMEOUT
|
||||
timeout=self.CONNECTION_TIMEOUT,
|
||||
)
|
||||
return True
|
||||
|
||||
except AuthenticationException as auth_err:
|
||||
logging.error(f'Host: {self.ip}. {auth_err}')
|
||||
logging.error(f"Host: {self.ip}. {auth_err}")
|
||||
self.drop()
|
||||
raise auth_err
|
||||
|
||||
except (
|
||||
SSHException,
|
||||
ssh_exception.NoValidConnectionsError,
|
||||
AttributeError,
|
||||
socket.timeout,
|
||||
OSError
|
||||
SSHException,
|
||||
ssh_exception.NoValidConnectionsError,
|
||||
AttributeError,
|
||||
socket.timeout,
|
||||
OSError,
|
||||
) as ssh_err:
|
||||
exc_err = ssh_err
|
||||
self.drop()
|
||||
logging.error(f'Host: {self.ip}, connection error. {exc_err}')
|
||||
logging.error(f"Host: {self.ip}, connection error. {exc_err}")
|
||||
|
||||
raise HostIsNotAvailable(self.ip, exc_err)
|
||||
|
||||
|
@ -211,21 +228,21 @@ class HostClient:
|
|||
try:
|
||||
_, stdout, stderr = self.ssh_client.exec_command(cmd, timeout=timeout)
|
||||
return SSHCommand(
|
||||
stdout=stdout.read().decode(errors='ignore'),
|
||||
stderr=stderr.read().decode(errors='ignore'),
|
||||
rc=stdout.channel.recv_exit_status()
|
||||
stdout=stdout.read().decode(errors="ignore"),
|
||||
stderr=stderr.read().decode(errors="ignore"),
|
||||
rc=stdout.channel.recv_exit_status(),
|
||||
)
|
||||
except (
|
||||
SSHException,
|
||||
TimeoutError,
|
||||
ssh_exception.NoValidConnectionsError,
|
||||
ConnectionResetError,
|
||||
AttributeError,
|
||||
socket.timeout,
|
||||
SSHException,
|
||||
TimeoutError,
|
||||
ssh_exception.NoValidConnectionsError,
|
||||
ConnectionResetError,
|
||||
AttributeError,
|
||||
socket.timeout,
|
||||
) as ssh_err:
|
||||
logging.error(f'Host: {self.ip}, exec command error {ssh_err}')
|
||||
logging.error(f"Host: {self.ip}, exec command error {ssh_err}")
|
||||
self.create_connection()
|
||||
raise HostIsNotAvailable(f'Host: {self.ip} is not reachable.')
|
||||
raise HostIsNotAvailable(f"Host: {self.ip} is not reachable.")
|
||||
|
||||
@contextmanager
|
||||
def _sftp_client(self) -> SFTPClient:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue