64 lines
2.1 KiB
Python
64 lines
2.1 KiB
Python
|
|
"""Remote shell execution with optional passwordless sudo fallback."""
|
||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import shlex
|
||
|
|
|
||
|
|
from server.domain.models import Server
|
||
|
|
from server.infrastructure.ssh.asyncssh_pool import exec_ssh_command
|
||
|
|
from server.utils.files_elevation import FilesElevation, get_files_elevation
|
||
|
|
|
||
|
|
|
||
|
|
def shell_output(result: dict) -> str:
|
||
|
|
return f"{result.get('stderr') or ''}{result.get('stdout') or ''}"
|
||
|
|
|
||
|
|
|
||
|
|
def is_permission_denied_result(result: dict) -> bool:
|
||
|
|
if result.get("exit_code") == 0:
|
||
|
|
return False
|
||
|
|
text = shell_output(result).lower()
|
||
|
|
return "permission denied" in text or "operation not permitted" in text
|
||
|
|
|
||
|
|
|
||
|
|
async def exec_ssh_command_with_fallback(
|
||
|
|
server: Server,
|
||
|
|
command: str,
|
||
|
|
*,
|
||
|
|
timeout: int = 120,
|
||
|
|
) -> dict:
|
||
|
|
"""Run command; elevation follows server ``extra_attrs.files_elevation``."""
|
||
|
|
elevation = get_files_elevation(server)
|
||
|
|
ssh_user = (server.username or "root").strip() or "root"
|
||
|
|
is_root_ssh = ssh_user == "root"
|
||
|
|
|
||
|
|
if elevation == FilesElevation.ALWAYS and not is_root_ssh:
|
||
|
|
sudo_cmd = f"sudo -n bash -c {shlex.quote(command)}"
|
||
|
|
sudo_result = await exec_ssh_command(server, sudo_cmd, timeout=timeout)
|
||
|
|
sudo_result = dict(sudo_result)
|
||
|
|
sudo_result["elevated"] = True
|
||
|
|
return sudo_result
|
||
|
|
|
||
|
|
result = await exec_ssh_command(server, command, timeout=timeout)
|
||
|
|
result = dict(result)
|
||
|
|
if result.get("exit_code") == 0:
|
||
|
|
result["elevated"] = False
|
||
|
|
return result
|
||
|
|
if elevation == FilesElevation.OFF or is_root_ssh:
|
||
|
|
result["elevated"] = False
|
||
|
|
return result
|
||
|
|
if not is_permission_denied_result(result):
|
||
|
|
result["elevated"] = False
|
||
|
|
return result
|
||
|
|
|
||
|
|
sudo_cmd = f"sudo -n bash -c {shlex.quote(command)}"
|
||
|
|
sudo_result = await exec_ssh_command(server, sudo_cmd, timeout=timeout)
|
||
|
|
sudo_result = dict(sudo_result)
|
||
|
|
if sudo_result.get("exit_code") == 0:
|
||
|
|
sudo_result["elevated"] = True
|
||
|
|
return sudo_result
|
||
|
|
if is_permission_denied_result(sudo_result):
|
||
|
|
sudo_result["elevated"] = True
|
||
|
|
return sudo_result
|
||
|
|
sudo_result["elevated"] = False
|
||
|
|
return sudo_result
|