48 lines
1.9 KiB
Python
48 lines
1.9 KiB
Python
import asyncio
|
|
import time
|
|
|
|
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) -> 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))
|