Source code for duct.sources.network
"""
.. module:: network
:platform: Unix
:synopsis: A source module for network checks
.. moduleauthor:: Colin Alston <colin@tamvera.com>
"""
import asyncio
import logging
import time
from zope.interface import implementer
from duct.interfaces import IDuctSource
from duct.objects import Source
from duct.protocol import icmp
from duct.utils import HTTPRequest, Timeout
log = logging.getLogger(__name__)
[docs]
@implementer(IDuctSource)
class HTTP(Source):
"""Performs an HTTP request
:param url: HTTP URL
:type url: str.
:param method: HTTP request method to use (default GET)
:type method: str.
:param match: A text string to match in the document when it is correct
:type match: str.
:param useragent: User-Agent header to use
:type useragent: str.
:param timeout: Timeout for connection (default 60s)
:type timeout: int.
**Metrics:**
:(service name).latency: Time to complete request
"""
[docs]
async def get(self):
method = self.config.get('method', 'GET')
url = self.config.get('url', f'http://{self.hostname}/')
match = self.config.get('match', None)
ua = self.config.get('useragent', 'Duct HTTP checker')
timeout = self.config.get('timeout', 60)
t0 = time.time()
try:
body = await HTTPRequest(timeout).getBody(url, method,
{'User-Agent': ua})
except Timeout:
log.warning('[%s] Request timeout', url)
t_delta = (time.time() - t0) * 1000
return self.createEvent('critical',
f'{url} - timeout', t_delta,
prefix="latency")
except Exception as e:
log.warning('[%s] Request error %s', url, e)
t_delta = (time.time() - t0) * 1000
return self.createEvent('critical',
f'{url} - {e}',
t_delta,
prefix="latency")
t_delta = (time.time() - t0) * 1000
if match:
if match in body:
state = 'ok'
else:
state = 'critical'
else:
state = 'ok'
return self.createEvent(state, f'Latency to {url}',
t_delta, prefix="latency")
[docs]
@implementer(IDuctSource)
class Ping(Source):
"""Performs an Ping checks against a destination
:param destination: Host name or IP address to ping
:type destination: str.
**Metrics:**
:(service name).latency: Ping latency
:(service name).loss: Packet loss
You can also override the `hostname` argument to make it match
metrics from that host.
"""
[docs]
async def get(self):
host = self.config.get('destination', self.hostname)
try:
loop = asyncio.get_event_loop()
infos = await loop.getaddrinfo(host, None)
ip = infos[0][4][0] if infos else None
except Exception:
ip = None
if ip:
try:
loss, latency = await icmp.ping(ip, 5)
except Exception:
loss, latency = 100, None
event = [self.createEvent('ok', f'{loss}% loss to {host}',
loss, prefix="loss")]
if latency:
event.append(self.createEvent('ok', f'Latency to {host}',
latency, prefix="latency"))
else:
event = [self.createEvent('critical', f'Unable to resolve {host}',
100, prefix="loss")]
return event