#!/usr/bin/env python # Copyright 2012-2016 Skylable Ltd. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Nagios plugin to check response latency of an SX Cluster node.""" import argparse import logging import time import nagiosplugin import requests import sxclient __version__ = '0.2.0' _log = logging.getLogger('nagiosplugin') class ResponseLatency(nagiosplugin.Resource): def __init__( self, cluster_name, node_address, is_secure=True, verify_ssl=True, port=None ): self.cluster = sxclient.Cluster( cluster_name, node_address, is_secure=is_secure, verify_ssl_cert=verify_ssl, port=port ) self.session = sxclient.ClusterSession(self.cluster) self.node_address = node_address def probe(self): time_start = time.time() _log.info('Time before querying node: %f' % time_start) try: url = self.cluster.get_host_url(self.node_address) resp = self.session.head(url) if 'sx-cluster' not in resp.headers: _log.info("No 'SX-Cluster' header in node's response") node_responded = False else: node_responded = True except (requests.ConnectionError, requests.Timeout) as exc: if 'connection refused' in str(exc).lower(): node_responded = False log_msg = ''.join([ 'Node cannot be reached because of ', exc.__class__.__name__, ': ', str(exc) ]) _log.info(log_msg) else: raise time_end = time.time() _log.info('Time after querying node: %f' % time_end) latency = time_end - time_start yield nagiosplugin.Metric('latency', latency, min=0) yield nagiosplugin.Metric('node responded', node_responded) class BooleanContext(nagiosplugin.Context): def __init__( self, name, fmt_metric="'{name}' is {valueunit}", result_cls=nagiosplugin.Result ): super(BooleanContext, self).__init__(name, fmt_metric, result_cls) def evaluate(self, metric, resource): if metric.value: return self.result_cls(nagiosplugin.state.Ok, metric=metric) else: return self.result_cls(nagiosplugin.state.Critical, metric=metric) @nagiosplugin.guarded def main(): args = parse_arguments() check = nagiosplugin.Check( ResponseLatency( args.hostname, args.node_address, args.is_secure, args.verify, args.port ), nagiosplugin.ScalarContext('latency', args.warning, args.critical), BooleanContext('node responded') ) check.main(verbose=args.verbose, timeout=args.timeout) def parse_arguments(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument( '-V', '--version', action='version', version=' '.join(['%(prog)s', __version__]) ) parser.add_argument( '-H', '--hostname', metavar='NAME', required=True, help='name of the cluster' ) parser.add_argument( '-n', '--node-address', metavar='ADDRESS', dest='node_address', required=True, help='IP address of the node to check' ) parser.add_argument( '-p', '--port', type=int, default=None, help='cluster destination port' ) parser.add_argument( '--no-ssl', dest='is_secure', action='store_false', default=True, help="disable secure communication" ) parser.add_argument( '--no-verify', dest='verify', action='store_false', default=True, help="don't verify the SSL certificate" ) parser.add_argument( '-w', '--warning', metavar='RANGE', default='', help='return warning if response latency is outside RANGE' ) parser.add_argument( '-c', '--critical', metavar='RANGE', default='', help='return critical if response latency is outside RANGE' ) parser.add_argument( '-v', '--verbose', action='count', default=0, help='increase output verbosity (use up to 3 times)' ) parser.add_argument( '-t', '--timeout', type=int, metavar='TIMEOUT', default=10, help='set plugin timeout to %(metavar)s; ' 'it is %(default)s by default; ' 'set to 0 or less for no timeout' ) return parser.parse_args() if __name__ == '__main__': main()