... | ... |
@@ -23,6 +23,7 @@ import functools as ft |
23 | 23 |
import asyncio |
24 | 24 |
from asyncio.subprocess import PIPE, DEVNULL |
25 | 25 |
from asyncio import create_subprocess_exec as subprocess |
26 |
+from subprocess import SubprocessError |
|
26 | 27 |
from collections import OrderedDict |
27 | 28 |
from pathlib import Path |
28 | 29 |
|
... | ... |
@@ -304,3 +305,37 @@ async def lock_subprocess(*args, lockfile, **kwargs): |
304 | 305 |
when_dead.add_done_callback(unlock) |
305 | 306 |
|
306 | 307 |
return proc |
308 |
+ |
|
309 |
+ |
|
310 |
+async def ping(host, timeout): |
|
311 |
+ """Return the round-trip time to a host using ICMP ECHO. |
|
312 |
+ |
|
313 |
+ Parameters |
|
314 |
+ ---------- |
|
315 |
+ host : str |
|
316 |
+ The host to ping. May be a hostname, ip address, or anything else |
|
317 |
+ recognized by 'ping'. |
|
318 |
+ timeout : int |
|
319 |
+ Time in seconds after which to stop waiting for a response. |
|
320 |
+ |
|
321 |
+ Returns |
|
322 |
+ ------- |
|
323 |
+ rtt : float |
|
324 |
+ The average round trip time in milliseconds. |
|
325 |
+ |
|
326 |
+ Raises |
|
327 |
+ ------ |
|
328 |
+ SubprocessError if 'ping' returns a non-zero exit code. |
|
329 |
+ """ |
|
330 |
+ cmd = f"/bin/ping -w{int(timeout)} {host}" |
|
331 |
+ proc = await asyncio.create_subprocess_exec(*cmd.split(), |
|
332 |
+ stdout=PIPE, stderr=DEVNULL) |
|
333 |
+ stdout, _ = await proc.communicate() |
|
334 |
+ if proc.returncode != 0: |
|
335 |
+ raise SubprocessError(proc.returncode) |
|
336 |
+ |
|
337 |
+ *_, rtt_line, _ = stdout.decode().split('\n') |
|
338 |
+ assert _ == '' # sanity check |
|
339 |
+ *_, data, _ = rtt_line.split() |
|
340 |
+ _, avg, *_ = data.split('/') |
|
341 |
+ return float(avg) |