Source code for tensor.sources.network

"""
.. module:: network
   :platform: Unix
   :synopsis: A source module for network checks

.. moduleauthor:: Colin Alston <colin@imcol.in>
"""

import time

from twisted.internet import defer, reactor
from twisted.python import log

from zope.interface import implements

from tensor.interfaces import ITensorSource
from tensor.objects import Source

from tensor.utils import fork, HTTPRequest, Timeout

[docs]class HTTP(Source): """Performs an HTTP request **Configuration arguments:** :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 """ implements(ITensorSource) @defer.inlineCallbacks def get(self): method = self.config.get('method', 'GET') url = self.config.get('url', 'http://%s/' % self.hostname) match = self.config.get('match', None) ua = self.config.get('useragent', 'Tensor HTTP checker') timeout = self.config.get('timeout', 60) t0 = time.time() try: body = yield HTTPRequest(timeout).getBody(url, method, {'User-Agent': [ua]}, ) except Timeout: log.msg('[%s] Request timeout' % url) t_delta = (time.time() - t0) * 1000 defer.returnValue( self.createEvent('critical', '%s - timeout' % url, t_delta, prefix="latency") ) except Exception, e: log.msg('[%s] Request error %s' % (url, e)) t_delta = (time.time() - t0) * 1000 defer.returnValue( self.createEvent('critical', '%s - %s' % (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' defer.returnValue( self.createEvent(state, 'Latency to %s' % url, t_delta, prefix="latency") )
[docs]class Ping(Source): """Performs an Ping checks against a destination This is a horrible implementation which forks to `ping` **Configuration arguments:** :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. """ implements(ITensorSource) @defer.inlineCallbacks def get(self): host = self.config.get('destination', self.hostname) try: out, err, code = yield fork('/bin/ping', args=('-q', '-n', '-c', '5', '-i', '0.2', host), timeout=30.0) except: code = 1 if code == 0: # Successful ping try: out = out.strip('\n').split('\n')[-2:] loss = int(out[0].split()[5].strip('%')) stat = out[1].split()[3].split('/') pmin, avg, pmax, mdev = [float(i) for i in stat] event = [ self.createEvent('ok', 'Latency to %s' % host, avg, prefix="latency"), self.createEvent('ok', '%s%% loss to %s' % (loss,host), loss, prefix="loss"), ] except Exception, e: print("Could not parse response %s" % repr(out)) event = None elif code == 1: # Host unreachable event = self.createEvent('critical', '100%% loss to %s' % host, 100.0, prefix="loss") else: # Some other kind of error like DNS resolution event = self.createEvent('critical', 'Unable to reach %s' % host, 100.0, prefix="loss") defer.returnValue(event)