feat: Linux SSH admin and remote ssh-monitor update (0.11.0)
This commit is contained in:
@@ -10,6 +10,7 @@ from app.models import Event, Host
|
||||
from app.schemas.list_models import HostDetail, HostListResponse, HostSummary
|
||||
from app.services.agent_version import latest_agent_versions_by_product
|
||||
from app.services.host_delete import delete_host_and_related
|
||||
from app.services.linux_admin_settings import get_effective_linux_admin_config
|
||||
from app.services.win_admin_settings import get_effective_win_admin_config
|
||||
from app.services.winrm_connect import (
|
||||
HostNotWindowsError,
|
||||
@@ -19,6 +20,15 @@ from app.services.winrm_connect import (
|
||||
iter_winrm_targets,
|
||||
test_winrm_connection,
|
||||
)
|
||||
from app.services.ssh_connect import (
|
||||
HostNotLinuxError as SshHostNotLinuxError,
|
||||
HostTargetMissingError as SshHostTargetMissingError,
|
||||
LinuxAdminNotConfiguredError,
|
||||
SshCommandResult,
|
||||
iter_ssh_targets,
|
||||
run_ssh_monitor_update,
|
||||
test_ssh_connection,
|
||||
)
|
||||
from app.services.host_health import (
|
||||
HEARTBEAT_TYPE,
|
||||
agent_status as compute_agent_status,
|
||||
@@ -172,6 +182,60 @@ class HostWinRmTestResponse(BaseModel):
|
||||
hostname: str | None = None
|
||||
|
||||
|
||||
class HostSshActionResponse(BaseModel):
|
||||
ok: bool
|
||||
message: str
|
||||
target: str
|
||||
stdout: str | None = None
|
||||
stderr: str | None = None
|
||||
exit_code: int | None = None
|
||||
|
||||
|
||||
def _ssh_action_response(result: SshCommandResult, *, attempts: list[str] | None = None) -> HostSshActionResponse:
|
||||
message = result.message
|
||||
if attempts:
|
||||
message = f"{message} (пробовали: {', '.join(attempts)})"
|
||||
return HostSshActionResponse(
|
||||
ok=result.ok,
|
||||
message=message,
|
||||
target=result.target,
|
||||
stdout=result.stdout or None,
|
||||
stderr=result.stderr or None,
|
||||
exit_code=result.exit_code,
|
||||
)
|
||||
|
||||
|
||||
def _run_ssh_action_on_host(
|
||||
host: Host,
|
||||
cfg,
|
||||
*,
|
||||
action,
|
||||
) -> HostSshActionResponse:
|
||||
try:
|
||||
targets = iter_ssh_targets(host)
|
||||
except SshHostNotLinuxError as exc:
|
||||
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
||||
except SshHostTargetMissingError as exc:
|
||||
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
||||
|
||||
last_result: SshCommandResult | None = None
|
||||
attempts: list[str] = []
|
||||
for target in targets:
|
||||
try:
|
||||
result = action(target=target, user=cfg.user, password=cfg.password)
|
||||
except LinuxAdminNotConfiguredError as exc:
|
||||
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
||||
except RuntimeError as exc:
|
||||
raise HTTPException(status_code=503, detail=str(exc)) from exc
|
||||
last_result = result
|
||||
attempts.append(f"{target}={'OK' if result.ok else 'fail'}")
|
||||
if result.ok:
|
||||
return _ssh_action_response(result, attempts=attempts if len(attempts) > 1 else None)
|
||||
|
||||
assert last_result is not None
|
||||
return _ssh_action_response(last_result, attempts=attempts if len(attempts) > 1 else None)
|
||||
|
||||
|
||||
@router.post("/{host_id}/actions/winrm-test", response_model=HostWinRmTestResponse)
|
||||
def test_host_winrm(
|
||||
host_id: int,
|
||||
@@ -235,6 +299,40 @@ def test_host_winrm(
|
||||
)
|
||||
|
||||
|
||||
@router.post("/{host_id}/actions/ssh-test", response_model=HostSshActionResponse)
|
||||
def test_host_ssh(
|
||||
host_id: int,
|
||||
db: Session = Depends(get_db),
|
||||
_user=Depends(require_admin),
|
||||
) -> HostSshActionResponse:
|
||||
host = db.get(Host, host_id)
|
||||
if host is None:
|
||||
raise HTTPException(status_code=404, detail="Host not found")
|
||||
|
||||
cfg = get_effective_linux_admin_config(db)
|
||||
if not cfg.configured:
|
||||
raise HTTPException(status_code=400, detail="Linux SSH admin is not configured")
|
||||
|
||||
return _run_ssh_action_on_host(host, cfg, action=test_ssh_connection)
|
||||
|
||||
|
||||
@router.post("/{host_id}/actions/agent-update", response_model=HostSshActionResponse)
|
||||
def update_host_agent_via_ssh(
|
||||
host_id: int,
|
||||
db: Session = Depends(get_db),
|
||||
_user=Depends(require_admin),
|
||||
) -> HostSshActionResponse:
|
||||
host = db.get(Host, host_id)
|
||||
if host is None:
|
||||
raise HTTPException(status_code=404, detail="Host not found")
|
||||
|
||||
cfg = get_effective_linux_admin_config(db)
|
||||
if not cfg.configured:
|
||||
raise HTTPException(status_code=400, detail="Linux SSH admin is not configured")
|
||||
|
||||
return _run_ssh_action_on_host(host, cfg, action=run_ssh_monitor_update)
|
||||
|
||||
|
||||
@router.delete("/{host_id}", response_model=HostDeleteResponse)
|
||||
def delete_host(
|
||||
host_id: int,
|
||||
|
||||
Reference in New Issue
Block a user