Refactor privileges for ssh commands

Remove logic that checks for root login and prepends command with sudo, because
we should not use root login at all and all commands (that require higher permissions
should be prefixed with sudo anyways).
Add sudo prefix to privileged commands that require it.

Signed-off-by: Vladimir Domnich <v.domnich@yadro.com>
This commit is contained in:
Vladimir Domnich 2022-08-12 18:44:36 +03:00 committed by Vladimir Domnich
parent f9ba463d2e
commit b6b1644fd6
5 changed files with 22 additions and 18 deletions

View file

@ -6,11 +6,11 @@ class IpTablesHelper:
@staticmethod @staticmethod
def drop_input_traffic_to_port(client: HostClient, ports: list[str]): def drop_input_traffic_to_port(client: HostClient, ports: list[str]):
for port in ports: for port in ports:
cmd_output = client.exec(cmd=f'iptables -A INPUT -p tcp --dport {port} -j DROP') cmd_output = client.exec(cmd=f'sudo iptables -A INPUT -p tcp --dport {port} -j DROP')
assert cmd_output.rc == 0 assert cmd_output.rc == 0
@staticmethod @staticmethod
def restore_input_traffic_to_port(client: HostClient, ports: list[str]): def restore_input_traffic_to_port(client: HostClient, ports: list[str]):
for port in ports: for port in ports:
cmd_output = client.exec(cmd=f'iptables -D INPUT -p tcp --dport {port} -j DROP') cmd_output = client.exec(cmd=f'sudo iptables -D INPUT -p tcp --dport {port} -j DROP')
assert cmd_output.rc == 0 assert cmd_output.rc == 0

View file

@ -38,6 +38,13 @@ class SberCloudConfig:
class SberCloud: class SberCloud:
"""
Manages resources in Sbercloud via API.
API reference:
https://docs.sbercloud.ru/terraform/ug/topics/quickstart.html
https://support.hc.sbercloud.ru/en-us/api/ecs/en-us_topic_0020212668.html
"""
def __init__(self, config: SberCloudConfig) -> None: def __init__(self, config: SberCloudConfig) -> None:
self.config = config self.config = config
self.ecs_url = None self.ecs_url = None

View file

@ -81,13 +81,13 @@ class CloudVmStorageServiceHelper:
def stop_node(self, node_name: str) -> None: def stop_node(self, node_name: str) -> None:
with _create_ssh_client(node_name) as ssh_client: with _create_ssh_client(node_name) as ssh_client:
cmd = f"systemctl stop {self.STORAGE_SERVICE}" cmd = f"sudo systemctl stop {self.STORAGE_SERVICE}"
output = ssh_client.exec_with_confirmation(cmd, [""]) output = ssh_client.exec_with_confirmation(cmd, [""])
logger.info(f"Stop command output: {output.stdout}") logger.info(f"Stop command output: {output.stdout}")
def start_node(self, node_name: str) -> None: def start_node(self, node_name: str) -> None:
with _create_ssh_client(node_name) as ssh_client: with _create_ssh_client(node_name) as ssh_client:
cmd = f"systemctl start {self.STORAGE_SERVICE}" cmd = f"sudo systemctl start {self.STORAGE_SERVICE}"
output = ssh_client.exec_with_confirmation(cmd, [""]) output = ssh_client.exec_with_confirmation(cmd, [""])
logger.info(f"Start command output: {output.stdout}") logger.info(f"Start command output: {output.stdout}")
@ -95,7 +95,7 @@ class CloudVmStorageServiceHelper:
expected_state = 'active (running)' expected_state = 'active (running)'
with _create_ssh_client(node_name) as ssh_client: with _create_ssh_client(node_name) as ssh_client:
for __attempt in range(10): for __attempt in range(10):
output = ssh_client.exec(f'systemctl status {self.STORAGE_SERVICE}') output = ssh_client.exec(f'sudo systemctl status {self.STORAGE_SERVICE}')
if expected_state in output.stdout: if expected_state in output.stdout:
return return
time.sleep(3) time.sleep(3)
@ -113,17 +113,17 @@ class CloudVmStorageServiceHelper:
# Copy wallet content on storage node host # Copy wallet content on storage node host
with open(wallet_path, "r") as file: with open(wallet_path, "r") as file:
wallet = file.read() wallet = file.read()
remote_wallet_path = "/tmp/{node_name}-wallet.json" remote_wallet_path = f"/tmp/{node_name}-wallet.json"
ssh_client.exec_with_confirmation(f"echo '{wallet}' > {remote_wallet_path}", [""]) ssh_client.exec_with_confirmation(f"echo '{wallet}' > {remote_wallet_path}", [""])
# Put config on storage node host # Put config on storage node host
remote_config_path = "/tmp/{node_name}-config.yaml" remote_config_path = f"/tmp/{node_name}-config.yaml"
remote_config = 'password: ""' remote_config = 'password: ""'
ssh_client.exec_with_confirmation(f"echo '{remote_config}' > {remote_config_path}", [""]) ssh_client.exec_with_confirmation(f"echo '{remote_config}' > {remote_config_path}", [""])
# Execute command # Execute command
cmd = ( cmd = (
f'{STORAGE_NODE_BIN_PATH}/neofs-cli {command} --endpoint {control_endpoint} ' f'sudo {STORAGE_NODE_BIN_PATH}/neofs-cli {command} --endpoint {control_endpoint} '
f'--wallet {remote_wallet_path} --config {remote_config_path}' f'--wallet {remote_wallet_path} --config {remote_config_path}'
) )
output = ssh_client.exec_with_confirmation(cmd, [""]) output = ssh_client.exec_with_confirmation(cmd, [""])
@ -131,7 +131,7 @@ class CloudVmStorageServiceHelper:
def delete_node_data(self, node_name: str) -> None: def delete_node_data(self, node_name: str) -> None:
with _create_ssh_client(node_name) as ssh_client: with _create_ssh_client(node_name) as ssh_client:
ssh_client.exec('rm -rf /srv/neofs/*') ssh_client.exec("sudo rm -rf /srv/neofs/*")
def get_binaries_version(self, binaries: list = None) -> dict: def get_binaries_version(self, binaries: list = None) -> dict:
default_binaries = [ default_binaries = [
@ -153,7 +153,7 @@ class CloudVmStorageServiceHelper:
with _create_ssh_client(node_name) as ssh_client: with _create_ssh_client(node_name) as ssh_client:
for binary in binaries: for binary in binaries:
try: try:
out = ssh_client.exec(f'{binary} --version').stdout out = ssh_client.exec(f'sudo {binary} --version').stdout
except AssertionError as err: except AssertionError as err:
logger.error(f'Can not get version for {binary} because of\n{err}') logger.error(f'Can not get version for {binary} because of\n{err}')
version_map[binary] = 'Can not get version' version_map[binary] = 'Can not get version'
@ -192,7 +192,8 @@ class RemoteDevEnvStorageServiceHelper(LocalDevEnvStorageServiceHelper):
# SSH into remote machine and delete files in host directory that is mounted as docker volume # SSH into remote machine and delete files in host directory that is mounted as docker volume
with _create_ssh_client(node_name) as ssh_client: with _create_ssh_client(node_name) as ssh_client:
ssh_client.exec(f'rm -rf {volume_path}/*') # TODO: add sudo prefix after we change a user
ssh_client.exec(f"rm -rf {volume_path}/*")
def get_storage_service_helper(): def get_storage_service_helper():

View file

@ -77,8 +77,6 @@ class HostClient:
self.create_connection(self.SSH_CONNECTION_ATTEMPTS) self.create_connection(self.SSH_CONNECTION_ATTEMPTS)
def exec(self, cmd: str, verify=True, timeout=90) -> SSHCommand: def exec(self, cmd: str, verify=True, timeout=90) -> SSHCommand:
if self.login != 'root':
cmd = f'sudo {cmd}'
cmd_result = self._inner_exec(cmd, timeout) cmd_result = self._inner_exec(cmd, timeout)
if verify: if verify:
assert cmd_result.rc == 0, f'Non zero rc from command: "{cmd}"' assert cmd_result.rc == 0, f'Non zero rc from command: "{cmd}"'
@ -86,8 +84,6 @@ class HostClient:
@log_command @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:
if self.login != "root":
cmd = f"sudo {cmd}"
ssh_stdin, ssh_stdout, ssh_stderr = self.ssh_client.exec_command(cmd, timeout=timeout) ssh_stdin, ssh_stdout, ssh_stderr = self.ssh_client.exec_command(cmd, timeout=timeout)
for line in confirmation: for line in confirmation:
if not line.endswith('\n'): if not line.endswith('\n'):
@ -176,7 +172,7 @@ class HostClient:
else: else:
logging.info( logging.info(
f"Trying to connect to host {self.ip} as {self.login} using password " f"Trying to connect to host {self.ip} as {self.login} using password "
f"{self.password[:2] + '***' if self.password else ''} (attempt {attempt})" f"(attempt {attempt})"
) )
self.ssh_client.connect( self.ssh_client.connect(
hostname=self.ip, hostname=self.ip,

View file

@ -25,8 +25,8 @@ blocked_hosts = []
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
@allure.step('Install iptables if needed') @allure.step('Install iptables if needed')
def install_iptables_if_needed(): def install_iptables_if_needed():
check_command = 'iptables --version' check_command = 'sudo iptables --version'
install_command = 'apt-get --yes install iptables' install_command = 'sudo apt-get --yes install iptables'
for node_config in NEOFS_NETMAP_DICT.values(): for node_config in NEOFS_NETMAP_DICT.values():
host = node_config.get('rpc').split(':')[0] host = node_config.get('rpc').split(':')[0]
client = HostClient(ip=host, login=STORAGE_NODE_SSH_USER, client = HostClient(ip=host, login=STORAGE_NODE_SSH_USER,