refactor: rename package directory fabledscryer → roundtable
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
from __future__ import annotations
|
||||
import asyncio
|
||||
import logging
|
||||
import time
|
||||
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from fabledscryer.core.alerts import record_metric
|
||||
from fabledscryer.models.hosts import Host, ProbeType
|
||||
from fabledscryer.models.monitors import PingResult, PingStatus
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
TCP_TIMEOUT = 5.0
|
||||
DEFAULT_TCP_PORT = 80
|
||||
|
||||
|
||||
async def ping_check(host: Host, session: AsyncSession) -> None:
|
||||
"""Probe a single host and write ping_result + metrics."""
|
||||
if host.probe_type == ProbeType.icmp:
|
||||
result = await _icmp_ping(host.address)
|
||||
else:
|
||||
result = await _tcp_ping(host.address, host.probe_port or DEFAULT_TCP_PORT)
|
||||
|
||||
status = PingStatus.up if result["up"] else PingStatus.down
|
||||
session.add(PingResult(
|
||||
host_id=host.id,
|
||||
status=status,
|
||||
response_time_ms=result.get("response_time_ms"),
|
||||
))
|
||||
await session.flush()
|
||||
|
||||
await record_metric(session, "ping", host.name, "up", 1.0 if result["up"] else 0.0)
|
||||
await record_metric(
|
||||
session, "ping", host.name, "response_time_ms",
|
||||
result.get("response_time_ms") or 0.0,
|
||||
)
|
||||
|
||||
|
||||
async def _tcp_ping(address: str, port: int) -> dict:
|
||||
start = time.monotonic()
|
||||
try:
|
||||
reader, writer = await asyncio.wait_for(
|
||||
asyncio.open_connection(address, port),
|
||||
timeout=TCP_TIMEOUT,
|
||||
)
|
||||
writer.close()
|
||||
await writer.wait_closed()
|
||||
return {"up": True, "response_time_ms": round((time.monotonic() - start) * 1000, 2)}
|
||||
except Exception:
|
||||
return {"up": False, "response_time_ms": None}
|
||||
|
||||
|
||||
async def _icmp_ping(address: str) -> dict:
|
||||
"""Use system ping command (setuid binary; no raw socket privilege needed in Python)."""
|
||||
start = time.monotonic()
|
||||
try:
|
||||
proc = await asyncio.create_subprocess_exec(
|
||||
"ping", "-c", "1", "-W", "2", address,
|
||||
stdout=asyncio.subprocess.DEVNULL,
|
||||
stderr=asyncio.subprocess.DEVNULL,
|
||||
)
|
||||
await asyncio.wait_for(proc.wait(), timeout=5.0)
|
||||
if proc.returncode == 0:
|
||||
return {"up": True, "response_time_ms": round((time.monotonic() - start) * 1000, 2)}
|
||||
return {"up": False, "response_time_ms": None}
|
||||
except Exception as exc:
|
||||
logger.warning(f"ICMP ping failed for {address}: {exc}, falling back to TCP")
|
||||
return await _tcp_ping(address, DEFAULT_TCP_PORT)
|
||||
Reference in New Issue
Block a user