фикс передачи логинов в задачи

This commit is contained in:
dv 2026-04-10 16:19:31 +03:00
parent 2a90c9b8dd
commit be1e98e18a
9 changed files with 24 additions and 18 deletions

View file

@ -7,7 +7,9 @@ and an emit() callback to write progress messages to the SSE stream.
from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from typing import Any, Awaitable, Callable
from typing import Any, Awaitable, Callable, Optional
from sqlalchemy.ext.asyncio import AsyncSession
from app.models.device import Device
from app.models.object import Object
@ -46,6 +48,7 @@ class BaseAction(ABC):
obj: Object,
params: dict,
emit: Emitter,
db: Optional[AsyncSession] = None,
) -> ActionResult: ...
def is_compatible(self, category: str) -> bool:
@ -79,10 +82,11 @@ class CompositeAction(BaseAction):
obj: Object,
params: dict,
emit: Emitter,
db: Optional[AsyncSession] = None,
) -> ActionResult:
action = self._routing.get(device.category)
if action is None:
msg = f"[{device.ip}] Нет обработчика для категории '{device.category}'"
await emit(msg, "error")
return ActionResult(success=False, error=msg)
return await action.execute(device, obj, params, emit)
return await action.execute(device, obj, params, emit, db=db)

View file

@ -19,12 +19,12 @@ class MikrotikGetConfigAction(BaseAction):
params_schema = []
async def execute(
self, device: Device, obj: Object, params: dict, emit: Emitter
self, device: Device, obj: Object, params: dict, emit: Emitter, db=None
) -> ActionResult:
await emit(f"[{device.ip}] Running /export compact", "info")
result = await ssh_service.run_command(
device, obj, "/export compact", timeout=60
device, obj, "/export compact", timeout=60, db=db
)
if not result.success and not result.stdout:

View file

@ -29,12 +29,12 @@ class MikrotikGetNTPAction(BaseAction):
params_schema = []
async def execute(
self, device: Device, obj: Object, params: dict, emit: Emitter
self, device: Device, obj: Object, params: dict, emit: Emitter, db=None
) -> ActionResult:
await emit(f"[{device.ip}] /system ntp client print", "info")
result = await ssh_service.run_command(
device, obj, "/system ntp client print"
device, obj, "/system ntp client print", db=db
)
if result.error:

View file

@ -23,7 +23,7 @@ class MikrotikSetNTPAction(BaseAction):
]
async def execute(
self, device: Device, obj: Object, params: dict, emit: Emitter
self, device: Device, obj: Object, params: dict, emit: Emitter, db=None
) -> ActionResult:
server = params.get("server", "").strip()
if not server:
@ -37,7 +37,7 @@ class MikrotikSetNTPAction(BaseAction):
for cmd in commands:
await emit(f"[{device.ip}] {cmd}", "info")
result = await ssh_service.run_command(device, obj, cmd)
result = await ssh_service.run_command(device, obj, cmd, db=db)
if result.error:
await emit(f"[{device.ip}] Error: {result.error}", "error")
return ActionResult(
@ -49,7 +49,7 @@ class MikrotikSetNTPAction(BaseAction):
)
# Verify
verify = await ssh_service.run_command(device, obj, "/system ntp client print")
verify = await ssh_service.run_command(device, obj, "/system ntp client print", db=db)
await emit(f"[{device.ip}] Verify: {verify.stdout[:200]}", "info")
return ActionResult(

View file

@ -26,10 +26,10 @@ class DebianSystemInfoAction(BaseAction):
compatible_categories = ["server", "raspberry", "embedded", "other"]
params_schema = []
async def execute(self, device: Device, obj: Object, params: dict, emit: Emitter) -> ActionResult:
async def execute(self, device: Device, obj: Object, params: dict, emit: Emitter, db=None) -> ActionResult:
await emit(f"[{device.ip}] Collecting system info...", "info")
result = await ssh_service.run_command(device, obj, _CMD, timeout=30)
result = await ssh_service.run_command(device, obj, _CMD, timeout=30, db=db)
if result.error:
await emit(f"[{device.ip}] Error: {result.error}", "error")

View file

@ -26,14 +26,14 @@ class GetFileAction(BaseAction):
]
async def execute(
self, device: Device, obj: Object, params: dict, emit: Emitter
self, device: Device, obj: Object, params: dict, emit: Emitter, db=None
) -> ActionResult:
path = params.get("path", "").strip()
if not path:
return ActionResult(success=False, error="No file path specified")
await emit(f"[{device.ip}] Reading {path}", "info")
result = await ssh_service.run_command(device, obj, f"cat {path}")
result = await ssh_service.run_command(device, obj, f"cat {path}", db=db)
if not result.success:
msg = result.error or result.stderr or f"exit code {result.exit_code}"

View file

@ -10,9 +10,9 @@ class GetTimedatectlAction(BaseAction):
compatible_categories = ["raspberry", "server"]
params_schema = []
async def execute(self, device: Device, obj: Object, params: dict, emit: Emitter) -> ActionResult:
async def execute(self, device: Device, obj: Object, params: dict, emit: Emitter, db=None) -> ActionResult:
await emit(f"[{device.ip}] Running timedatectl...", "info")
result = await ssh_service.run_command(device, obj, "timedatectl show --no-pager 2>/dev/null || timedatectl")
result = await ssh_service.run_command(device, obj, "timedatectl show --no-pager 2>/dev/null || timedatectl", db=db)
if result.error:
await emit(f"[{device.ip}] Error: {result.error}", "error")

View file

@ -12,13 +12,13 @@ class SSHCommandAction(BaseAction):
{"name": "command", "type": "string", "label": "Command", "required": True},
]
async def execute(self, device: Device, obj: Object, params: dict, emit: Emitter) -> ActionResult:
async def execute(self, device: Device, obj: Object, params: dict, emit: Emitter, db=None) -> ActionResult:
command = params.get("command", "").strip()
if not command:
return ActionResult(success=False, error="No command specified")
await emit(f"[{device.ip}] $ {command}", "info")
result = await ssh_service.run_command(device, obj, command)
result = await ssh_service.run_command(device, obj, command, db=db)
if result.error:
await emit(f"[{device.ip}] Error: {result.error}", "error")

View file

@ -134,7 +134,9 @@ async def _run_on_device(
result_id = tr.id
try:
action_result = await action.execute(device, obj, params, emit)
async with AsyncSessionLocal() as action_db:
async with action_db.begin():
action_result = await action.execute(device, obj, params, emit, db=action_db)
except Exception as exc:
action_result_success = False
action_stdout = ""