utp_service/backend/app/plugins/builtin/common/ping.py
2026-04-14 10:25:20 +03:00

51 lines
2 KiB
Python

import asyncio
import time
from typing import Optional
from sqlalchemy.ext.asyncio import AsyncSession
from app.models.device import Device
from app.models.object import Object
from app.plugins.base import ActionResult, BaseAction, Emitter
class PingAction(BaseAction):
name = "ping"
display_name = "Ping"
compatible_categories = [] # works for all device types
params_schema = []
async def execute(self, device: Device, obj: Object, params: dict, emit: Emitter, db: Optional[AsyncSession] = None) -> ActionResult:
await emit(f"Pinging {device.ip}...", "info")
start = time.monotonic()
proc = None
try:
proc = await asyncio.create_subprocess_exec(
"ping", "-c", "1", "-W", "2", device.ip,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
)
stdout, stderr = await asyncio.wait_for(proc.communicate(), timeout=10)
duration = int((time.monotonic() - start) * 1000)
success = proc.returncode == 0
msg = f"{device.ip}: {'reachable' if success else 'unreachable'} ({duration}ms)"
await emit(msg, "info" if success else "warn")
return ActionResult(
success=success,
stdout=stdout.decode(errors="replace").strip(),
stderr=stderr.decode(errors="replace").strip(),
exit_code=proc.returncode or 0,
data={"ping_ms": duration if success else None},
)
except asyncio.TimeoutError:
if proc is not None:
try:
proc.kill()
await proc.wait()
except Exception:
pass
await emit(f"{device.ip}: ping timed out", "error")
return ActionResult(success=False, error="Timeout")
except Exception as e:
await emit(f"{device.ip}: error — {e}", "error")
return ActionResult(success=False, error=str(e))