66 lines
2.1 KiB
Python
66 lines
2.1 KiB
Python
"""
|
|
GetFileAction — reads a remote file via SSH and saves it as a config snapshot.
|
|
|
|
Compatible with Linux-based devices (raspberry, server, embedded, other).
|
|
"""
|
|
|
|
from app.models.device import Device
|
|
from app.models.object import Object
|
|
from app.plugins.base import ActionResult, BaseAction, Emitter
|
|
from app.services import snapshot as snapshot_service
|
|
from app.services import ssh as ssh_service
|
|
|
|
|
|
class GetFileAction(BaseAction):
|
|
name = "get_file"
|
|
display_name = "Get File (Snapshot)"
|
|
compatible_categories = ["raspberry", "server", "embedded", "other"]
|
|
params_schema = [
|
|
{
|
|
"name": "path",
|
|
"type": "string",
|
|
"label": "File path",
|
|
"required": True,
|
|
"placeholder": "/etc/ntp.conf",
|
|
},
|
|
]
|
|
|
|
async def execute(
|
|
self, device: Device, obj: Object, params: dict, emit: Emitter
|
|
) -> 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}")
|
|
|
|
if not result.success:
|
|
msg = result.error or result.stderr or f"exit code {result.exit_code}"
|
|
await emit(f"[{device.ip}] Failed: {msg}", "error")
|
|
return ActionResult(
|
|
success=False,
|
|
stdout=result.stdout,
|
|
stderr=result.stderr,
|
|
exit_code=result.exit_code,
|
|
error=msg,
|
|
)
|
|
|
|
content = result.stdout
|
|
snap_id, sha256, size = await snapshot_service.save_snapshot(
|
|
device_id=device.id,
|
|
content=content,
|
|
label=path,
|
|
)
|
|
|
|
await emit(
|
|
f"[{device.ip}] Snapshot saved: {sha256[:12]}… ({size} bytes, id={snap_id})",
|
|
"info",
|
|
)
|
|
|
|
return ActionResult(
|
|
success=True,
|
|
stdout=content,
|
|
exit_code=0,
|
|
data={"snapshot_id": snap_id, "sha256": sha256, "size": size, "path": path},
|
|
)
|