{"action":"created","comment":{"url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/pulls/comments/38663609","id":38663609,"diff_hunk":"@@ -0,0 +1,1449 @@\n+#!/usr/bin/env python\n+\n+#\n+# A MongoDB Nagios check script\n+#\n+\n+# Script idea taken from a Tag1 script I found and I modified it a lot\n+#\n+# Main Author\n+#   - Mike Zupan <mike@zcentric.com>\n+# Contributers\n+#   - Frank Brandewiede <brande@travel-iq.com> <brande@bfiw.de> <brande@novolab.de>\n+#   - Sam Perman <sam@brightcove.com>\n+#   - Shlomo Priymak <shlomoid@gmail.com>\n+#   - @jhoff909 on github\n+#   - @jbraeuer on github\n+#   - Dag Stockstad <dag.stockstad@gmail.com>\n+#   - @Andor on github\n+#   - Steven Richards - Captainkrtek on Github <sbrichards@mit.edu>\n+#\n+\n+# License: BSD\n+# Copyright (c) 2012, Mike Zupan <mike@zcentric.com>\n+# All rights reserved.\n+# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n+#\n+# Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n+# Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the\n+# documentation and/or other materials provided with the distribution.\n+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS\n+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n+# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+#\n+# README: https://github.com/mzupan/nagios-plugin-mongodb/blob/master/LICENSE\n+\n+# #RED\n+import sys\n+import time\n+import optparse\n+import textwrap\n+import re\n+import os\n+\n+try:\n+    import pymongo\n+except ImportError, e:\n+    print e\n+    sys.exit(2)\n+\n+# As of pymongo v 1.9 the SON API is part of the BSON package, therefore attempt\n+# to import from there and fall back to pymongo in cases of older pymongo\n+if pymongo.version >= \"1.9\":\n+    import bson.son as son\n+else:\n+    import pymongo.son as son\n+\n+\n+#\n+# thanks to http://stackoverflow.com/a/1229667/72987\n+#\n+def optional_arg(arg_default):\n+    def func(option, opt_str, value, parser):\n+        if parser.rargs and not parser.rargs[0].startswith('-'):\n+            val = parser.rargs[0]\n+            parser.rargs.pop(0)\n+        else:\n+            val = arg_default\n+        setattr(parser.values, option.dest, val)\n+    return func\n+\n+\n+def performance_data(perf_data, params):\n+    data = ''\n+    if perf_data:\n+        data = \" |\"\n+        for p in params:\n+            p += (None, None, None, None)\n+            param, param_name, warning, critical = p[0:4]\n+            data += \"%s=%s\" % (param_name, str(param))\n+            if warning or critical:\n+                warning = warning or 0\n+                critical = critical or 0\n+                data += \";%s;%s\" % (warning, critical)\n+\n+            data += \" \"\n+\n+    return data\n+\n+\n+def numeric_type(param):\n+    if ((type(param) == float or type(param) == int or param == None)):\n+        return True\n+    return False\n+\n+\n+def check_levels(param, warning, critical, message, ok=[]):\n+    if (numeric_type(critical) and numeric_type(warning)):\n+        if param >= critical:\n+            print \"CRITICAL - \" + message\n+            sys.exit(2)\n+        elif param >= warning:\n+            print \"WARNING - \" + message\n+            sys.exit(1)\n+        else:\n+            print \"OK - \" + message\n+            sys.exit(0)\n+    else:\n+        if param in critical:\n+            print \"CRITICAL - \" + message\n+            sys.exit(2)\n+\n+        if param in warning:\n+            print \"WARNING - \" + message\n+            sys.exit(1)\n+\n+        if param in ok:\n+            print \"OK - \" + message\n+            sys.exit(0)\n+\n+        # unexpected param value\n+        print \"CRITICAL - Unexpected value : %d\" % param + \"; \" + message\n+        return 2\n+\n+\n+def get_server_status(con):\n+    try:\n+        set_read_preference(con.admin)\n+        data = con.admin.command(pymongo.son_manipulator.SON([('serverStatus', 1)]))\n+    except:\n+        data = con.admin.command(son.SON([('serverStatus', 1)]))\n+    return data\n+\n+\n+def main(argv):\n+    p = optparse.OptionParser(conflict_handler=\"resolve\", description=\"This Nagios plugin checks the health of mongodb.\")\n+\n+    p.add_option('-H', '--host', action='store', type='string', dest='host', default='127.0.0.1', help='The hostname you want to connect to')\n+    p.add_option('-P', '--port', action='store', type='int', dest='port', default=27017, help='The port mongodb is runnung on')\n+    p.add_option('-u', '--user', action='store', type='string', dest='user', default=None, help='The username you want to login as')\n+    p.add_option('-p', '--pass', action='store', type='string', dest='passwd', default=None, help='The password you want to use for that user')\n+    p.add_option('-W', '--warning', action='store', dest='warning', default=None, help='The warning threshold we want to set')\n+    p.add_option('-C', '--critical', action='store', dest='critical', default=None, help='The critical threshold we want to set')\n+    p.add_option('-A', '--action', action='store', type='choice', dest='action', default='connect', help='The action you want to take',\n+                 choices=['connect', 'connections', 'replication_lag', 'replication_lag_percent', 'replset_state', 'memory', 'memory_mapped', 'lock',\n+                          'flushing', 'last_flush_time', 'index_miss_ratio', 'databases', 'collections', 'database_size', 'database_indexes', 'collection_indexes', 'collection_size',\n+                          'queues', 'oplog', 'journal_commits_in_wl', 'write_data_files', 'journaled', 'opcounters', 'current_lock', 'replica_primary', 'page_faults',\n+                          'asserts', 'queries_per_second', 'page_faults', 'chunks_balance', 'connect_primary', 'collection_state', 'row_count', 'replset_quorum'])\n+    p.add_option('--max-lag', action='store_true', dest='max_lag', default=False, help='Get max replication lag (for replication_lag action only)')\n+    p.add_option('--mapped-memory', action='store_true', dest='mapped_memory', default=False, help='Get mapped memory instead of resident (if resident memory can not be read)')\n+    p.add_option('-D', '--perf-data', action='store_true', dest='perf_data', default=False, help='Enable output of Nagios performance data')\n+    p.add_option('-d', '--database', action='store', dest='database', default='admin', help='Specify the database to check')\n+    p.add_option('--all-databases', action='store_true', dest='all_databases', default=False, help='Check all databases (action database_size)')\n+    p.add_option('-s', '--ssl', dest='ssl', default=False, action='callback', callback=optional_arg(True), help='Connect using SSL')\n+    p.add_option('-r', '--replicaset', dest='replicaset', default=None, action='callback', callback=optional_arg(True), help='Connect to replicaset')\n+    p.add_option('-q', '--querytype', action='store', dest='query_type', default='query', help='The query type to check [query|insert|update|delete|getmore|command] from queries_per_second')\n+    p.add_option('-c', '--collection', action='store', dest='collection', default='admin', help='Specify the collection to check')\n+    p.add_option('-T', '--time', action='store', type='int', dest='sample_time', default=1, help='Time used to sample number of pages faults')\n+\n+    options, arguments = p.parse_args()\n+    host = options.host\n+    port = options.port\n+    user = options.user\n+    passwd = options.passwd\n+    query_type = options.query_type\n+    collection = options.collection\n+    sample_time = options.sample_time\n+    if (options.action == 'replset_state'):\n+        warning = str(options.warning or \"\")\n+        critical = str(options.critical or \"\")\n+    else:\n+        warning = float(options.warning or 0)\n+        critical = float(options.critical or 0)\n+\n+    action = options.action\n+    perf_data = options.perf_data\n+    max_lag = options.max_lag\n+    database = options.database\n+    ssl = options.ssl\n+    replicaset = options.replicaset\n+\n+    if action == 'replica_primary' and replicaset is None:\n+        return \"replicaset must be passed in when using replica_primary check\"\n+    elif not action == 'replica_primary' and replicaset:\n+        return \"passing a replicaset while not checking replica_primary does not work\"\n+\n+    #\n+    # moving the login up here and passing in the connection\n+    #\n+    start = time.time()\n+    err, con = mongo_connect(host, port, ssl, user, passwd, replicaset)\n+    if err != 0:\n+        return err\n+\n+    conn_time = time.time() - start\n+    conn_time = round(conn_time, 0)\n+\n+    if action == \"connections\":\n+        return check_connections(con, warning, critical, perf_data)\n+    elif action == \"replication_lag\":\n+        return check_rep_lag(con, host, port, warning, critical, False, perf_data, max_lag, user, passwd)\n+    elif action == \"replication_lag_percent\":\n+        return check_rep_lag(con, host, port, warning, critical, True, perf_data, max_lag, user, passwd)\n+    elif action == \"replset_state\":\n+        return check_replset_state(con, perf_data, warning, critical)\n+    elif action == \"memory\":\n+        return check_memory(con, warning, critical, perf_data, options.mapped_memory)\n+    elif action == \"memory_mapped\":\n+        return check_memory_mapped(con, warning, critical, perf_data)\n+    elif action == \"queues\":\n+        return check_queues(con, warning, critical, perf_data)\n+    elif action == \"lock\":\n+        return check_lock(con, warning, critical, perf_data)\n+    elif action == \"current_lock\":\n+        return check_current_lock(con, host, warning, critical, perf_data)\n+    elif action == \"flushing\":\n+        return check_flushing(con, warning, critical, True, perf_data)\n+    elif action == \"last_flush_time\":\n+        return check_flushing(con, warning, critical, False, perf_data)\n+    elif action == \"index_miss_ratio\":\n+        index_miss_ratio(con, warning, critical, perf_data)\n+    elif action == \"databases\":\n+        return check_databases(con, warning, critical, perf_data)\n+    elif action == \"collections\":\n+        return check_collections(con, warning, critical, perf_data)\n+    elif action == \"oplog\":\n+        return check_oplog(con, warning, critical, perf_data)\n+    elif action == \"journal_commits_in_wl\":\n+        return check_journal_commits_in_wl(con, warning, critical, perf_data)\n+    elif action == \"database_size\":\n+        if options.all_databases:\n+            return check_all_databases_size(con, warning, critical, perf_data)\n+        else:\n+            return check_database_size(con, database, warning, critical, perf_data)\n+    elif action == \"database_indexes\":\n+        return check_database_indexes(con, database, warning, critical, perf_data)\n+    elif action == \"collection_indexes\":\n+        return check_collection_indexes(con, database, collection, warning, critical, perf_data)\n+    elif action == \"collection_size\":\n+        return check_collection_size(con, database, collection, warning, critical, perf_data)\n+    elif action == \"journaled\":\n+        return check_journaled(con, warning, critical, perf_data)\n+    elif action == \"write_data_files\":\n+        return check_write_to_datafiles(con, warning, critical, perf_data)\n+    elif action == \"opcounters\":\n+        return check_opcounters(con, host, warning, critical, perf_data)\n+    elif action == \"asserts\":\n+        return check_asserts(con, host, warning, critical, perf_data)\n+    elif action == \"replica_primary\":\n+        return check_replica_primary(con, host, warning, critical, perf_data, replicaset)\n+    elif action == \"queries_per_second\":\n+        return check_queries_per_second(con, query_type, warning, critical, perf_data)\n+    elif action == \"page_faults\":\n+        check_page_faults(con, sample_time, warning, critical, perf_data)\n+    elif action == \"chunks_balance\":\n+        chunks_balance(con, database, collection, warning, critical)\n+    elif action == \"connect_primary\":\n+        return check_connect_primary(con, warning, critical, perf_data)\n+    elif action == \"collection_state\":\n+        return check_collection_state(con, database, collection)\n+    elif action == \"row_count\":\n+        return check_row_count(con, database, collection, warning, critical, perf_data)\n+    elif action == \"replset_quorum\":\n+        return check_replset_quorum(con, perf_data)\n+    else:\n+        return check_connect(host, port, warning, critical, perf_data, user, passwd, conn_time)\n+\n+\n+def mongo_connect(host=None, port=None, ssl=False, user=None, passwd=None, replica=None):\n+    try:\n+        # ssl connection for pymongo > 2.3\n+        if pymongo.version >= \"2.3\":\n+            if replica is None:\n+                con = pymongo.MongoClient(host, port, ssl=ssl)\n+            else:\n+                con = pymongo.Connection(host, port, read_preference=pymongo.ReadPreference.SECONDARY, ssl=ssl, replicaSet=replica, network_timeout=10)\n+        else:\n+            if replica is None:\n+                con = pymongo.Connection(host, port, slave_okay=True, network_timeout=10)\n+            else:\n+                con = pymongo.Connection(host, port, slave_okay=True, network_timeout=10)\n+                #con = pymongo.Connection(host, port, slave_okay=True, replicaSet=replica, network_timeout=10)\n+\n+        if user and passwd:\n+            db = con[\"admin\"]\n+            if not db.authenticate(user, passwd):\n+                sys.exit(\"Username/Password incorrect\")\n+    except Exception, e:\n+        if isinstance(e, pymongo.errors.AutoReconnect) and str(e).find(\" is an arbiter\") != -1:\n+            # We got a pymongo AutoReconnect exception that tells us we connected to an Arbiter Server\n+            # This means: Arbiter is reachable and can answer requests/votes - this is all we need to know from an arbiter\n+            print \"OK - State: 7 (Arbiter)\"\n+            sys.exit(0)\n+        return exit_with_general_critical(e), None\n+    return 0, con\n+\n+\n+def exit_with_general_warning(e):\n+    if isinstance(e, SystemExit):\n+        return e\n+    else:\n+        print \"WARNING - General MongoDB warning:\", e\n+    return 1\n+\n+\n+def exit_with_general_critical(e):\n+    if isinstance(e, SystemExit):\n+        return e\n+    else:\n+        print \"CRITICAL - General MongoDB Error:\", e\n+    return 2\n+\n+\n+def set_read_preference(db):\n+    if pymongo.version >= \"2.1\":\n+        db.read_preference = pymongo.ReadPreference.SECONDARY\n+\n+\n+def check_connect(host, port, warning, critical, perf_data, user, passwd, conn_time):\n+    warning = warning or 3\n+    critical = critical or 6\n+    message = \"Connection took %i seconds\" % conn_time\n+    message += performance_data(perf_data, [(conn_time, \"connection_time\", warning, critical)])\n+\n+    return check_levels(conn_time, warning, critical, message)\n+\n+\n+def check_connections(con, warning, critical, perf_data):\n+    warning = warning or 80\n+    critical = critical or 95\n+    try:\n+        data = get_server_status(con)\n+\n+        current = float(data['connections']['current'])\n+        available = float(data['connections']['available'])\n+\n+        used_percent = int(float(current / (available + current)) * 100)\n+        message = \"%i percent (%i of %i connections) used\" % (used_percent, current, current + available)\n+        message += performance_data(perf_data, [(used_percent, \"used_percent\", warning, critical),\n+                (current, \"current_connections\"),\n+                (available, \"available_connections\")])\n+        return check_levels(used_percent, warning, critical, message)\n+\n+    except Exception, e:\n+        return exit_with_general_critical(e)\n+\n+\n+def check_rep_lag(con, host, port, warning, critical, percent, perf_data, max_lag, user, passwd):\n+    # Get mongo to tell us replica set member name when connecting locally\n+    if \"127.0.0.1\" == host:\n+        host = con.admin.command(\"ismaster\",\"1\")[\"me\"].split(':')[0]\n+\n+    if percent:\n+        warning = warning or 50\n+        critical = critical or 75\n+    else:\n+        warning = warning or 600\n+        critical = critical or 3600\n+    rs_status = {}\n+    slaveDelays = {}\n+    try:\n+        set_read_preference(con.admin)\n+\n+        # Get replica set status\n+        try:\n+            rs_status = con.admin.command(\"replSetGetStatus\")\n+        except pymongo.errors.OperationFailure, e:\n+            if e.code == None and str(e).find('failed: not running with --replSet\"'):\n+                print \"OK - Not running with replSet\"\n+                return 0\n+\n+        serverVersion = tuple(con.server_info()['version'].split('.'))\n+        if serverVersion >= tuple(\"2.0.0\".split(\".\")):\n+            #\n+            # check for version greater then 2.0\n+            #\n+            rs_conf = con.local.system.replset.find_one()\n+            for member in rs_conf['members']:\n+                if member.get('slaveDelay') is not None:\n+                    slaveDelays[member['host']] = member.get('slaveDelay')\n+                else:\n+                    slaveDelays[member['host']] = 0\n+\n+            # Find the primary and/or the current node\n+            primary_node = None\n+            host_node = None\n+\n+            for member in rs_status[\"members\"]:\n+                if member[\"stateStr\"] == \"PRIMARY\":\n+                    primary_node = member\n+                if member[\"name\"].split(':')[0] == host and int(member[\"name\"].split(':')[1]) == port:\n+                    host_node = member\n+\n+            # Check if we're in the middle of an election and don't have a primary\n+            if primary_node is None:\n+                print \"WARNING - No primary defined. In an election?\"\n+                return 1\n+\n+            # Check if we failed to find the current host\n+            # below should never happen\n+            if host_node is None:\n+                print \"CRITICAL - Unable to find host '\" + host + \"' in replica set.\"\n+                return 2\n+\n+            # Is the specified host the primary?\n+            if host_node[\"stateStr\"] == \"PRIMARY\":\n+                if max_lag == False:\n+                    print \"OK - This is the primary.\"\n+                    return 0\n+                else:\n+                    #get the maximal replication lag\n+                    data = \"\"\n+                    maximal_lag = 0\n+                    for member in rs_status['members']:\n+                        if not member['stateStr'] == \"ARBITER\":\n+                            lastSlaveOpTime = member['optimeDate']\n+                            replicationLag = abs(primary_node[\"optimeDate\"] - lastSlaveOpTime).seconds - slaveDelays[member['name']]\n+                            data = data + member['name'] + \" lag=%d;\" % replicationLag\n+                            maximal_lag = max(maximal_lag, replicationLag)\n+                    if percent:\n+                        err, con = mongo_connect(primary_node['name'].split(':')[0], int(primary_node['name'].split(':')[1]), False, user, passwd)\n+                        if err != 0:\n+                            return err\n+                        primary_timediff = replication_get_time_diff(con)\n+                        maximal_lag = int(float(maximal_lag) / float(primary_timediff) * 100)\n+                        message = \"Maximal lag is \" + str(maximal_lag) + \" percents\"\n+                        message += performance_data(perf_data, [(maximal_lag, \"replication_lag_percent\", warning, critical)])\n+                    else:\n+                        message = \"Maximal lag is \" + str(maximal_lag) + \" seconds\"\n+                        message += performance_data(perf_data, [(maximal_lag, \"replication_lag\", warning, critical)])\n+                    return check_levels(maximal_lag, warning, critical, message)\n+            elif host_node[\"stateStr\"] == \"ARBITER\":\n+                print \"OK - This is an arbiter\"\n+                return 0\n+\n+            # Find the difference in optime between current node and PRIMARY\n+\n+            optime_lag = abs(primary_node[\"optimeDate\"] - host_node[\"optimeDate\"])\n+\n+            if host_node['name'] in slaveDelays:\n+                slave_delay = slaveDelays[host_node['name']]\n+            elif host_node['name'].endswith(':27017') and host_node['name'][:-len(\":27017\")] in slaveDelays:\n+                slave_delay = slaveDelays[host_node['name'][:-len(\":27017\")]]\n+            else:\n+                raise Exception(\"Unable to determine slave delay for {0}\".format(host_node['name']))\n+\n+            try:  # work starting from python2.7\n+                lag = optime_lag.total_seconds()\n+            except:\n+                lag = float(optime_lag.seconds + optime_lag.days * 24 * 3600)\n+\n+            if percent:\n+                err, con = mongo_connect(primary_node['name'].split(':')[0], int(primary_node['name'].split(':')[1]), False, user, passwd)\n+                if err != 0:\n+                    return err\n+                primary_timediff = replication_get_time_diff(con)\n+                if primary_timediff != 0:\n+                    lag = int(float(lag) / float(primary_timediff) * 100)\n+                else:\n+                    lag = 0\n+                message = \"Lag is \" + str(lag) + \" percents\"\n+                message += performance_data(perf_data, [(lag, \"replication_lag_percent\", warning, critical)])\n+            else:\n+                message = \"Lag is \" + str(lag) + \" seconds\"\n+                message += performance_data(perf_data, [(lag, \"replication_lag\", warning, critical)])\n+            return check_levels(lag, warning + slaveDelays[host_node['name']], critical + slaveDelays[host_node['name']], message)\n+        else:\n+            #\n+            # less than 2.0 check\n+            #\n+            # Get replica set status\n+            rs_status = con.admin.command(\"replSetGetStatus\")\n+\n+            # Find the primary and/or the current node\n+            primary_node = None\n+            host_node = None\n+            for member in rs_status[\"members\"]:\n+                if member[\"stateStr\"] == \"PRIMARY\":\n+                    primary_node = (member[\"name\"], member[\"optimeDate\"])\n+                if member[\"name\"].split(\":\")[0].startswith(host):\n+                    host_node = member\n+\n+            # Check if we're in the middle of an election and don't have a primary\n+            if primary_node is None:\n+                print \"WARNING - No primary defined. In an election?\"\n+                sys.exit(1)\n+\n+            # Is the specified host the primary?\n+            if host_node[\"stateStr\"] == \"PRIMARY\":\n+                print \"OK - This is the primary.\"\n+                sys.exit(0)\n+\n+            # Find the difference in optime between current node and PRIMARY\n+            optime_lag = abs(primary_node[1] - host_node[\"optimeDate\"])\n+            lag = optime_lag.seconds\n+            if percent:\n+                err, con = mongo_connect(primary_node['name'].split(':')[0], int(primary_node['name'].split(':')[1]))\n+                if err != 0:\n+                    return err\n+                primary_timediff = replication_get_time_diff(con)\n+                lag = int(float(lag) / float(primary_timediff) * 100)\n+                message = \"Lag is \" + str(lag) + \" percents\"\n+                message += performance_data(perf_data, [(lag, \"replication_lag_percent\", warning, critical)])\n+            else:\n+                message = \"Lag is \" + str(lag) + \" seconds\"\n+                message += performance_data(perf_data, [(lag, \"replication_lag\", warning, critical)])\n+            return check_levels(lag, warning, critical, message)\n+\n+    except Exception, e:\n+        return exit_with_general_critical(e)\n+\n+\n+def check_memory(con, warning, critical, perf_data, mapped_memory):\n+    #\n+    # These thresholds are basically meaningless, and must be customized to your system's ram\n+    #\n+    warning = warning or 8\n+    critical = critical or 16\n+    try:\n+        data = get_server_status(con)\n+        if not data['mem']['supported'] and not mapped_memory:\n+            print \"OK - Platform not supported for memory info\"\n+            return 0\n+        #\n+        # convert to gigs\n+        #\n+        message = \"Memory Usage:\"\n+        try:\n+            mem_resident = float(data['mem']['resident']) / 1024.0\n+            message += \" %.2fGB resident,\" % (mem_resident)\n+        except:\n+            mem_resident = 0\n+            message += \" resident unsupported,\"\n+        try:\n+            mem_virtual = float(data['mem']['virtual']) / 1024.0\n+            message += \" %.2fGB virtual,\" % mem_virtual\n+        except:\n+            mem_virtual = 0\n+            message += \" virtual unsupported,\"\n+        try:\n+            mem_mapped = float(data['mem']['mapped']) / 1024.0\n+            message += \" %.2fGB mapped,\" % mem_mapped\n+        except:\n+            mem_mapped = 0\n+            message += \" mapped unsupported,\"\n+        try:\n+            mem_mapped_journal = float(data['mem']['mappedWithJournal']) / 1024.0\n+            message += \" %.2fGB mappedWithJournal\" % mem_mapped_journal\n+        except:\n+            mem_mapped_journal = 0\n+        message += performance_data(perf_data, [(\"%.2f\" % mem_resident, \"memory_usage\", warning, critical),\n+                    (\"%.2f\" % mem_mapped, \"memory_mapped\"), (\"%.2f\" % mem_virtual, \"memory_virtual\"), (\"%.2f\" % mem_mapped_journal, \"mappedWithJournal\")])\n+        #added for unsupported systems like Solaris\n+        if mapped_memory and mem_resident == 0:\n+            return check_levels(mem_mapped, warning, critical, message)\n+        else:\n+            return check_levels(mem_resident, warning, critical, message)\n+\n+    except Exception, e:\n+        return exit_with_general_critical(e)\n+\n+\n+def check_memory_mapped(con, warning, critical, perf_data):\n+    #\n+    # These thresholds are basically meaningless, and must be customized to your application\n+    #\n+    warning = warning or 8\n+    critical = critical or 16\n+    try:\n+        data = get_server_status(con)\n+        if not data['mem']['supported']:\n+            print \"OK - Platform not supported for memory info\"\n+            return 0\n+        #\n+        # convert to gigs\n+        #\n+        message = \"Memory Usage:\"\n+        try:\n+            mem_mapped = float(data['mem']['mapped']) / 1024.0\n+            message += \" %.2fGB mapped,\" % mem_mapped\n+        except:\n+            mem_mapped = -1\n+            message += \" mapped unsupported,\"\n+        try:\n+            mem_mapped_journal = float(data['mem']['mappedWithJournal']) / 1024.0\n+            message += \" %.2fGB mappedWithJournal\" % mem_mapped_journal\n+        except:\n+            mem_mapped_journal = 0\n+        message += performance_data(perf_data, [(\"%.2f\" % mem_mapped, \"memory_mapped\"), (\"%.2f\" % mem_mapped_journal, \"mappedWithJournal\")])\n+\n+        if not mem_mapped == -1:\n+            return check_levels(mem_mapped, warning, critical, message)\n+        else:\n+            print \"OK - Server does not provide mem.mapped info\"\n+            return 0\n+\n+    except Exception, e:\n+        return exit_with_general_critical(e)\n+\n+\n+def check_lock(con, warning, critical, perf_data):\n+    warning = warning or 10\n+    critical = critical or 30\n+    try:\n+        data = get_server_status(con)\n+        #\n+        # calculate percentage\n+        #\n+        lock_percentage = float(data['globalLock']['lockTime']) / float(data['globalLock']['totalTime']) * 100\n+        message = \"Lock Percentage: %.2f%%\" % lock_percentage\n+        message += performance_data(perf_data, [(\"%.2f\" % lock_percentage, \"lock_percentage\", warning, critical)])\n+        return check_levels(lock_percentage, warning, critical, message)\n+\n+    except Exception, e:\n+        return exit_with_general_critical(e)\n+\n+\n+def check_flushing(con, warning, critical, avg, perf_data):\n+    #\n+    # These thresholds mean it's taking 5 seconds to perform a background flush to issue a warning\n+    # and 10 seconds to issue a critical.\n+    #\n+    warning = warning or 5000\n+    critical = critical or 15000\n+    try:\n+        data = get_server_status(con)\n+        if avg:\n+            flush_time = float(data['backgroundFlushing']['average_ms'])\n+            stat_type = \"Average\"\n+        else:\n+            flush_time = float(data['backgroundFlushing']['last_ms'])\n+            stat_type = \"Last\"\n+\n+        message = \"%s Flush Time: %.2fms\" % (stat_type, flush_time)\n+        message += performance_data(perf_data, [(\"%.2fms\" % flush_time, \"%s_flush_time\" % stat_type.lower(), warning, critical)])\n+\n+        return check_levels(flush_time, warning, critical, message)\n+\n+    except Exception, e:\n+        return exit_with_general_critical(e)\n+\n+\n+def index_miss_ratio(con, warning, critical, perf_data):\n+    warning = warning or 10\n+    critical = critical or 30\n+    try:\n+        data = get_server_status(con)\n+\n+        try:\n+            serverVersion = tuple(con.server_info()['version'].split('.'))\n+            if serverVersion >= tuple(\"2.4.0\".split(\".\")):\n+                miss_ratio = float(data['indexCounters']['missRatio'])\n+            else:\n+                miss_ratio = float(data['indexCounters']['btree']['missRatio'])\n+        except KeyError:\n+            not_supported_msg = \"not supported on this platform\"\n+            if data['indexCounters'].has_key('note'):\n+                print \"OK - MongoDB says: \" + not_supported_msg\n+                return 0\n+            else:\n+                print \"WARNING - Can't get counter from MongoDB\"\n+                return 1\n+\n+        message = \"Miss Ratio: %.2f\" % miss_ratio\n+        message += performance_data(perf_data, [(\"%.2f\" % miss_ratio, \"index_miss_ratio\", warning, critical)])\n+\n+        return check_levels(miss_ratio, warning, critical, message)\n+\n+    except Exception, e:\n+        return exit_with_general_critical(e)\n+\n+def check_replset_quorum(con, perf_data):\n+    db = con['admin']\n+    warning = 1\n+    critical = 2\n+    primary = 0\n+\n+    try:\n+        rs_members = db.command(\"replSetGetStatus\")['members']\n+\n+        for member in rs_members:\n+            if member['state'] == 1:\n+                primary += 1\n+\n+        if primary == 1:\n+            state = 0\n+            message = \"Cluster is quorate\"\n+        else:\n+            state = 2\n+            message = \"Cluster is not quorate and cannot operate\"\n+\n+        return check_levels(state, warning, critical, message)\n+    except Exception, e:\n+        return exit_with_general_critical(e)\n+\n+\n+\n+def check_replset_state(con, perf_data, warning=\"\", critical=\"\"):\n+    try:\n+        warning = [int(x) for x in warning.split(\",\")]\n+    except:\n+        warning = [0, 3, 5]\n+    try:\n+        critical = [int(x) for x in critical.split(\",\")]\n+    except:\n+        critical = [8, 4, -1]\n+\n+    ok = range(-1, 8)  # should include the range of all posiible values\n+    try:\n+        try:\n+            try:\n+                set_read_preference(con.admin)\n+                data = con.admin.command(pymongo.son_manipulator.SON([('replSetGetStatus', 1)]))\n+            except:\n+                data = con.admin.command(son.SON([('replSetGetStatus', 1)]))\n+            state = int(data['myState'])\n+        except pymongo.errors.OperationFailure, e:\n+            if e.code == None and str(e).find('failed: not running with --replSet\"'):\n+                state = -1\n+\n+        if state == 8:\n+            message = \"State: %i (Down)\" % state\n+        elif state == 4:\n+            message = \"State: %i (Fatal error)\" % state\n+        elif state == 0:\n+            message = \"State: %i (Starting up, phase1)\" % state\n+        elif state == 3:\n+            message = \"State: %i (Recovering)\" % state\n+        elif state == 5:\n+            message = \"State: %i (Starting up, phase2)\" % state\n+        elif state == 1:\n+            message = \"State: %i (Primary)\" % state\n+        elif state == 2:\n+            message = \"State: %i (Secondary)\" % state\n+        elif state == 7:\n+            message = \"State: %i (Arbiter)\" % state\n+        elif state == -1:\n+            message = \"Not running with replSet\"\n+        else:\n+            message = \"State: %i (Unknown state)\" % state\n+        message += performance_data(perf_data, [(state, \"state\")])\n+        return check_levels(state, warning, critical, message, ok)\n+    except Exception, e:\n+        return exit_with_general_critical(e)\n+\n+\n+def check_databases(con, warning, critical, perf_data=None):\n+    try:\n+        try:\n+            set_read_preference(con.admin)\n+            data = con.admin.command(pymongo.son_manipulator.SON([('listDatabases', 1)]))\n+        except:\n+            data = con.admin.command(son.SON([('listDatabases', 1)]))\n+\n+        count = len(data['databases'])\n+        message = \"Number of DBs: %.0f\" % count\n+        message += performance_data(perf_data, [(count, \"databases\", warning, critical, message)])\n+        return check_levels(count, warning, critical, message)\n+    except Exception, e:\n+        return exit_with_general_critical(e)\n+\n+\n+def check_collections(con, warning, critical, perf_data=None):\n+    try:\n+        try:\n+            set_read_preference(con.admin)\n+            data = con.admin.command(pymongo.son_manipulator.SON([('listDatabases', 1)]))\n+        except:\n+            data = con.admin.command(son.SON([('listDatabases', 1)]))\n+\n+        count = 0\n+        for db in data['databases']:\n+            dbase = con[db['name']]\n+            set_read_preference(dbase)\n+            count += len(dbase.collection_names())\n+\n+        message = \"Number of collections: %.0f\" % count\n+        message += performance_data(perf_data, [(count, \"collections\", warning, critical, message)])\n+        return check_levels(count, warning, critical, message)\n+\n+    except Exception, e:\n+        return exit_with_general_critical(e)\n+\n+\n+def check_all_databases_size(con, warning, critical, perf_data):\n+    warning = warning or 100\n+    critical = critical or 1000\n+    try:\n+        set_read_preference(con.admin)\n+        all_dbs_data = con.admin.command(pymongo.son_manipulator.SON([('listDatabases', 1)]))\n+    except:\n+        all_dbs_data = con.admin.command(son.SON([('listDatabases', 1)]))\n+\n+    total_storage_size = 0\n+    message = \"\"\n+    perf_data_param = [()]\n+    for db in all_dbs_data['databases']:\n+        database = db['name']\n+        data = con[database].command('dbstats')\n+        storage_size = round(data['storageSize'] / 1024 / 1024, 1)\n+        message += \"; Database %s size: %.0f MB\" % (database, storage_size)\n+        perf_data_param.append((storage_size, database + \"_database_size\"))\n+        total_storage_size += storage_size\n+\n+    perf_data_param[0] = (total_storage_size, \"total_size\", warning, critical)\n+    message += performance_data(perf_data, perf_data_param)\n+    message = \"Total size: %.0f MB\" % total_storage_size + message\n+    return check_levels(total_storage_size, warning, critical, message)\n+\n+\n+def check_database_size(con, database, warning, critical, perf_data):\n+    warning = warning or 100\n+    critical = critical or 1000\n+    perfdata = \"\"\n+    try:\n+        set_read_preference(con.admin)\n+        data = con[database].command('dbstats')\n+        storage_size = data['storageSize'] / 1024 / 1024\n+        if perf_data:\n+            perfdata += \" | database_size=%i;%i;%i\" % (storage_size, warning, critical)\n+            #perfdata += \" database=%s\" %(database)\n+\n+        if storage_size >= critical:\n+            print \"CRITICAL - Database size: %.0f MB, Database: %s%s\" % (storage_size, database, perfdata)\n+            return 2\n+        elif storage_size >= warning:\n+            print \"WARNING - Database size: %.0f MB, Database: %s%s\" % (storage_size, database, perfdata)\n+            return 1\n+        else:\n+            print \"OK - Database size: %.0f MB, Database: %s%s\" % (storage_size, database, perfdata)\n+            return 0\n+    except Exception, e:\n+        return exit_with_general_critical(e)\n+\n+\n+def check_database_indexes(con, database, warning, critical, perf_data):\n+    #\n+    # These thresholds are basically meaningless, and must be customized to your application\n+    #\n+    warning = warning or 100\n+    critical = critical or 1000\n+    perfdata = \"\"\n+    try:\n+        set_read_preference(con.admin)\n+        data = con[database].command('dbstats')\n+        index_size = data['indexSize'] / 1024 / 1024\n+        if perf_data:\n+            perfdata += \" | database_indexes=%i;%i;%i\" % (index_size, warning, critical)\n+\n+        if index_size >= critical:\n+            print \"CRITICAL - %s indexSize: %.0f MB %s\" % (database, index_size, perfdata)\n+            return 2\n+        elif index_size >= warning:\n+            print \"WARNING - %s indexSize: %.0f MB %s\" % (database, index_size, perfdata)\n+            return 1\n+        else:\n+            print \"OK - %s indexSize: %.0f MB %s\" % (database, index_size, perfdata)\n+            return 0\n+    except Exception, e:\n+        return exit_with_general_critical(e)\n+\n+\n+def check_collection_indexes(con, database, collection, warning, critical, perf_data):\n+    #\n+    # These thresholds are basically meaningless, and must be customized to your application\n+    #\n+    warning = warning or 100\n+    critical = critical or 1000\n+    perfdata = \"\"\n+    try:\n+        set_read_preference(con.admin)\n+        data = con[database].command('collstats', collection)\n+        total_index_size = data['totalIndexSize'] / 1024 / 1024\n+        if perf_data:\n+            perfdata += \" | collection_indexes=%i;%i;%i\" % (total_index_size, warning, critical)\n+\n+        if total_index_size >= critical:\n+            print \"CRITICAL - %s.%s totalIndexSize: %.0f MB %s\" % (database, collection, total_index_size, perfdata)\n+            return 2\n+        elif total_index_size >= warning:\n+            print \"WARNING - %s.%s totalIndexSize: %.0f MB %s\" % (database, collection, total_index_size, perfdata)\n+            return 1\n+        else:\n+            print \"OK - %s.%s totalIndexSize: %.0f MB %s\" % (database, collection, total_index_size, perfdata)\n+            return 0\n+    except Exception, e:\n+        return exit_with_general_critical(e)\n+\n+\n+def check_queues(con, warning, critical, perf_data):\n+    warning = warning or 10\n+    critical = critical or 30\n+    try:\n+        data = get_server_status(con)\n+\n+        total_queues = float(data['globalLock']['currentQueue']['total'])\n+        readers_queues = float(data['globalLock']['currentQueue']['readers'])\n+        writers_queues = float(data['globalLock']['currentQueue']['writers'])\n+        message = \"Current queue is : total = %d, readers = %d, writers = %d\" % (total_queues, readers_queues, writers_queues)\n+        message += performance_data(perf_data, [(total_queues, \"total_queues\", warning, critical), (readers_queues, \"readers_queues\"), (writers_queues, \"writers_queues\")])\n+        return check_levels(total_queues, warning, critical, message)\n+\n+    except Exception, e:\n+        return exit_with_general_critical(e)\n+\n+def check_collection_size(con, database, collection, warning, critical, perf_data):\n+    warning = warning or 100\n+    critical = critical or 1000\n+    perfdata = \"\"\n+    try:\n+        set_read_preference(con.admin)\n+        data = con[database].command('collstats', collection)\n+        size = data['size'] / 1024 / 1024\n+        if perf_data:\n+            perfdata += \" | collection_size=%i;%i;%i\" % (size, warning, critical)\n+\n+        if size >= critical:\n+            print \"CRITICAL - %s.%s size: %.0f MB %s\" % (database, collection, size, perfdata)\n+            return 2\n+        elif size >= warning:\n+            print \"WARNING - %s.%s size: %.0f MB %s\" % (database, collection, size, perfdata)\n+            return 1\n+        else:\n+            print \"OK - %s.%s size: %.0f MB %s\" % (database, collection, size, perfdata)\n+            return 0\n+    except Exception, e:\n+        return exit_with_general_critical(e)\n+\n+def check_queries_per_second(con, query_type, warning, critical, perf_data):\n+    warning = warning or 250\n+    critical = critical or 500\n+\n+    if query_type not in ['insert', 'query', 'update', 'delete', 'getmore', 'command']:\n+        return exit_with_general_critical(\"The query type of '%s' is not valid\" % query_type)\n+\n+    try:\n+        db = con.local\n+        data = get_server_status(con)\n+\n+        # grab the count\n+        num = int(data['opcounters'][query_type])\n+\n+        # do the math\n+        last_count = db.nagios_check.find_one({'check': 'query_counts'})\n+        try:\n+            ts = int(time.time())\n+            diff_query = num - last_count['data'][query_type]['count']\n+            diff_ts = ts - last_count['data'][query_type]['ts']\n+\n+            query_per_sec = float(diff_query) / float(diff_ts)\n+\n+            # update the count now\n+            db.nagios_check.update({u'_id': last_count['_id']}, {'$set': {\"data.%s\" % query_type: {'count': num, 'ts': int(time.time())}}})\n+\n+            message = \"Queries / Sec: %f\" % query_per_sec\n+            message += performance_data(perf_data, [(query_per_sec, \"%s_per_sec\" % query_type, warning, critical, message)])\n+        except KeyError:\n+            #\n+            # since it is the first run insert it\n+            query_per_sec = 0\n+            message = \"First run of check.. no data\"\n+            db.nagios_check.update({u'_id': last_count['_id']}, {'$set': {\"data.%s\" % query_type: {'count': num, 'ts': int(time.time())}}})\n+        except TypeError:\n+            #\n+            # since it is the first run insert it\n+            query_per_sec = 0\n+            message = \"First run of check.. no data\"\n+            db.nagios_check.insert({'check': 'query_counts', 'data': {query_type: {'count': num, 'ts': int(time.time())}}})\n+\n+        return check_levels(query_per_sec, warning, critical, message)\n+\n+    except Exception, e:\n+        return exit_with_general_critical(e)\n+\n+\n+def check_oplog(con, warning, critical, perf_data):\n+    \"\"\" Checking the oplog time - the time of the log currntly saved in the oplog collection\n+    defaults:\n+        critical 4 hours\n+        warning 24 hours\n+    those can be changed as usual with -C and -W parameters\"\"\"\n+    warning = warning or 24\n+    critical = critical or 4\n+    try:\n+        db = con.local\n+        ol = db.system.namespaces.find_one({\"name\": \"local.oplog.rs\"})\n+        if (db.system.namespaces.find_one({\"name\": \"local.oplog.rs\"}) != None):\n+            oplog = \"oplog.rs\"\n+        else:\n+            ol = db.system.namespaces.find_one({\"name\": \"local.oplog.$main\"})\n+            if (db.system.namespaces.find_one({\"name\": \"local.oplog.$main\"}) != None):\n+                oplog = \"oplog.$main\"\n+            else:\n+                message = \"neither master/slave nor replica set replication detected\"\n+                return check_levels(None, warning, critical, message)\n+\n+        try:\n+                set_read_preference(con.admin)\n+                data = con.local.command(pymongo.son_manipulator.SON([('collstats', oplog)]))\n+        except:\n+                data = con.admin.command(son.SON([('collstats', oplog)]))\n+\n+        ol_size = data['size']\n+        ol_storage_size = data['storageSize']\n+        ol_used_storage = int(float(ol_size) / ol_storage_size * 100 + 1)\n+        ol = con.local[oplog]\n+        firstc = ol.find().sort(\"$natural\", pymongo.ASCENDING).limit(1)[0]['ts']\n+        lastc = ol.find().sort(\"$natural\", pymongo.DESCENDING).limit(1)[0]['ts']\n+        time_in_oplog = (lastc.as_datetime() - firstc.as_datetime())\n+        message = \"Oplog saves \" + str(time_in_oplog) + \" %d%% used\" % ol_used_storage\n+        try:  # work starting from python2.7\n+            hours_in_oplog = time_in_oplog.total_seconds() / 60 / 60\n+        except:\n+            hours_in_oplog = float(time_in_oplog.seconds + time_in_oplog.days * 24 * 3600) / 60 / 60\n+        approx_level = hours_in_oplog * 100 / ol_used_storage\n+        message += performance_data(perf_data, [(\"%.2f\" % hours_in_oplog, 'oplog_time', warning, critical), (\"%.2f \" % approx_level, 'oplog_time_100_percent_used')])\n+        return check_levels(-approx_level, -warning, -critical, message)\n+\n+    except Exception, e:\n+        return exit_with_general_critical(e)\n+\n+\n+def check_journal_commits_in_wl(con, warning, critical, perf_data):\n+    \"\"\"  Checking the number of commits which occurred in the db's write lock.\n+Most commits are performed outside of this lock; committed while in the write lock is undesirable.\n+Under very high write situations it is normal for this value to be nonzero.  \"\"\"\n+\n+    warning = warning or 10\n+    critical = critical or 40\n+    try:\n+        data = get_server_status(con)\n+        j_commits_in_wl = data['dur']['commitsInWriteLock']\n+        message = \"Journal commits in DB write lock : %d\" % j_commits_in_wl\n+        message += performance_data(perf_data, [(j_commits_in_wl, \"j_commits_in_wl\", warning, critical)])\n+        return check_levels(j_commits_in_wl, warning, critical, message)\n+\n+    except Exception, e:\n+        return exit_with_general_critical(e)\n+\n+\n+def check_journaled(con, warning, critical, perf_data):\n+    \"\"\" Checking the average amount of data in megabytes written to the recovery log in the last four seconds\"\"\"\n+\n+    warning = warning or 20\n+    critical = critical or 40\n+    try:\n+        data = get_server_status(con)\n+        journaled = data['dur']['journaledMB']\n+        message = \"Journaled : %.2f MB\" % journaled\n+        message += performance_data(perf_data, [(\"%.2f\" % journaled, \"journaled\", warning, critical)])\n+        return check_levels(journaled, warning, critical, message)\n+\n+    except Exception, e:\n+        return exit_with_general_critical(e)\n+\n+\n+def check_write_to_datafiles(con, warning, critical, perf_data):\n+    \"\"\"    Checking the average amount of data in megabytes written to the databases datafiles in the last four seconds.\n+As these writes are already journaled, they can occur lazily, and thus the number indicated here may be lower\n+than the amount physically written to disk.\"\"\"\n+    warning = warning or 20\n+    critical = critical or 40\n+    try:\n+        data = get_server_status(con)\n+        writes = data['dur']['writeToDataFilesMB']\n+        message = \"Write to data files : %.2f MB\" % writes\n+        message += performance_data(perf_data, [(\"%.2f\" % writes, \"write_to_data_files\", warning, critical)])\n+        return check_levels(writes, warning, critical, message)\n+\n+    except Exception, e:\n+        return exit_with_general_critical(e)\n+\n+\n+def get_opcounters(data, opcounters_name, host):\n+    try:\n+        insert = data[opcounters_name]['insert']\n+        query = data[opcounters_name]['query']\n+        update = data[opcounters_name]['update']\n+        delete = data[opcounters_name]['delete']\n+        getmore = data[opcounters_name]['getmore']\n+        command = data[opcounters_name]['command']\n+    except KeyError, e:\n+        return 0, [0] * 100\n+    total_commands = insert + query + update + delete + getmore + command\n+    new_vals = [total_commands, insert, query, update, delete, getmore, command]\n+    return  maintain_delta(new_vals, host, opcounters_name)\n+\n+\n+def check_opcounters(con, host, warning, critical, perf_data):\n+    \"\"\" A function to get all opcounters delta per minute. In case of a replication - gets the opcounters+opcountersRepl\"\"\"\n+    warning = warning or 10000\n+    critical = critical or 15000\n+\n+    data = get_server_status(con)\n+    err1, delta_opcounters = get_opcounters(data, 'opcounters', host)\n+    err2, delta_opcounters_repl = get_opcounters(data, 'opcountersRepl', host)\n+    if err1 == 0 and err2 == 0:\n+        delta = [(x + y) for x, y in zip(delta_opcounters, delta_opcounters_repl)]\n+        delta[0] = delta_opcounters[0]  # only the time delta shouldn't be summarized\n+        per_minute_delta = [int(x / delta[0] * 60) for x in delta[1:]]\n+        message = \"Test succeeded , old values missing\"\n+        message = \"Opcounters: total=%d,insert=%d,query=%d,update=%d,delete=%d,getmore=%d,command=%d\" % tuple(per_minute_delta)\n+        message += performance_data(perf_data, ([(per_minute_delta[0], \"total\", warning, critical), (per_minute_delta[1], \"insert\"),\n+                    (per_minute_delta[2], \"query\"), (per_minute_delta[3], \"update\"), (per_minute_delta[5], \"delete\"),\n+                    (per_minute_delta[5], \"getmore\"), (per_minute_delta[6], \"command\")]))\n+        return check_levels(per_minute_delta[0], warning, critical, message)\n+    else:\n+        return exit_with_general_critical(\"problem reading data from temp file\")\n+\n+\n+def check_current_lock(con, host, warning, critical, perf_data):\n+    \"\"\" A function to get current lock percentage and not a global one, as check_lock function does\"\"\"\n+    warning = warning or 10\n+    critical = critical or 30\n+    data = get_server_status(con)\n+\n+    lockTime = float(data['globalLock']['lockTime'])\n+    totalTime = float(data['globalLock']['totalTime'])\n+\n+    err, delta = maintain_delta([totalTime, lockTime], host, \"locktime\")\n+    if err == 0:\n+        lock_percentage = delta[2] / delta[1] * 100     # lockTime/totalTime*100\n+        message = \"Current Lock Percentage: %.2f%%\" % lock_percentage\n+        message += performance_data(perf_data, [(\"%.2f\" % lock_percentage, \"current_lock_percentage\", warning, critical)])\n+        return check_levels(lock_percentage, warning, critical, message)\n+    else:\n+        return exit_with_general_warning(\"problem reading data from temp file\")\n+\n+\n+def check_page_faults(con, host, warning, critical, perf_data):\n+    \"\"\" A function to get page_faults per second from the system\"\"\"\n+    warning = warning or 10\n+    critical = critical or 30\n+    data = get_server_status(con)\n+\n+    try:\n+        page_faults = float(data['extra_info']['page_faults'])\n+    except:\n+        # page_faults unsupported on the underlaying system\n+        return exit_with_general_critical(\"page_faults unsupported on the underlaying system\")\n+\n+    err, delta = maintain_delta([page_faults], host, \"page_faults\")\n+    if err == 0:\n+        page_faults_ps = delta[1] / delta[0]\n+        message = \"Page faults : %.2f ps\" % page_faults_ps\n+        message += performance_data(perf_data, [(\"%.2f\" % page_faults_ps, \"page_faults_ps\", warning, critical)])\n+        return check_levels(page_faults_ps, warning, critical, message)\n+    else:\n+        return exit_with_general_warning(\"problem reading data from temp file\")\n+\n+\n+def check_asserts(con, host, warning, critical, perf_data):\n+    \"\"\" A function to get asserts from the system\"\"\"\n+    warning = warning or 1\n+    critical = critical or 10\n+    data = get_server_status(con)\n+\n+    asserts = data['asserts']\n+\n+    #{ \"regular\" : 0, \"warning\" : 6, \"msg\" : 0, \"user\" : 12, \"rollovers\" : 0 }\n+    regular = asserts['regular']\n+    warning_asserts = asserts['warning']\n+    msg = asserts['msg']\n+    user = asserts['user']\n+    rollovers = asserts['rollovers']\n+\n+    err, delta = maintain_delta([regular, warning_asserts, msg, user, rollovers], host, \"asserts\")\n+\n+    if err == 0:\n+        if delta[5] != 0:\n+            #the number of rollovers were increased\n+            warning = -1  # no matter the metrics this situation should raise a warning\n+            # if this is normal rollover - the warning will not appear again, but if there will be a lot of asserts\n+            # the warning will stay for a long period of time\n+            # although this is not a usual situation\n+\n+        regular_ps = delta[1] / delta[0]\n+        warning_ps = delta[2] / delta[0]\n+        msg_ps = delta[3] / delta[0]\n+        user_ps = delta[4] / delta[0]\n+        rollovers_ps = delta[5] / delta[0]\n+        total_ps = regular_ps + warning_ps + msg_ps + user_ps\n+        message = \"Total asserts : %.2f ps\" % total_ps\n+        message += performance_data(perf_data, [(total_ps, \"asserts_ps\", warning, critical), (regular_ps, \"regular\"),\n+                    (warning_ps, \"warning\"), (msg_ps, \"msg\"), (user_ps, \"user\")])\n+        return check_levels(total_ps, warning, critical, message)\n+    else:\n+        return exit_with_general_warning(\"problem reading data from temp file\")\n+\n+\n+def get_stored_primary_server_name(db):\n+    \"\"\" get the stored primary server name from db. \"\"\"\n+    if \"last_primary_server\" in db.collection_names():\n+        stored_primary_server = db.last_primary_server.find_one()[\"server\"]\n+    else:\n+        stored_primary_server = None\n+\n+    return stored_primary_server\n+\n+\n+def check_replica_primary(con, host, warning, critical, perf_data, replicaset):\n+    \"\"\" A function to check if the primary server of a replica set has changed \"\"\"\n+    if warning is None and critical is None:\n+        warning = 1\n+    warning = warning or 2\n+    critical = critical or 2\n+\n+    primary_status = 0\n+    message = \"Primary server has not changed\"\n+    db = con[\"nagios\"]\n+    data = get_server_status(con)\n+    if replicaset != data['repl'].get('setName'):\n+        message = \"Replica set requested: %s differs from the one found: %s\" % (replicaset, data['repl'].get('setName'))\n+        primary_status = 2\n+        return check_levels(primary_status, warning, critical, message)\n+    current_primary = data['repl'].get('primary')\n+    saved_primary = get_stored_primary_server_name(db)\n+    if current_primary is None:\n+        current_primary = \"None\"\n+    if saved_primary is None:\n+        saved_primary = \"None\"\n+    if current_primary != saved_primary:\n+        last_primary_server_record = {\"server\": current_primary}\n+        db.last_primary_server.update({\"_id\": \"last_primary\"}, {\"$set\": last_primary_server_record}, upsert=True, safe=True)\n+        message = \"Primary server has changed from %s to %s\" % (saved_primary, current_primary)\n+        primary_status = 1\n+    return check_levels(primary_status, warning, critical, message)\n+\n+\n+def check_page_faults(con, sample_time, warning, critical, perf_data):\n+    warning = warning or 10\n+    critical = critical or 20\n+    try:\n+        try:\n+            set_read_preference(con.admin)\n+            data1 = con.admin.command(pymongo.son_manipulator.SON([('serverStatus', 1)]))\n+            time.sleep(sample_time)\n+            data2 = con.admin.command(pymongo.son_manipulator.SON([('serverStatus', 1)]))\n+        except:\n+            data1 = con.admin.command(son.SON([('serverStatus', 1)]))\n+            time.sleep(sample_time)\n+            data2 = con.admin.command(son.SON([('serverStatus', 1)]))\n+\n+        try:\n+            #on linux servers only\n+            page_faults = (int(data2['extra_info']['page_faults']) - int(data1['extra_info']['page_faults'])) / sample_time\n+        except KeyError:\n+            print \"WARNING - Can't get extra_info.page_faults counter from MongoDB\"\n+            sys.exit(1)\n+\n+        message = \"Page Faults: %i\" % (page_faults)\n+\n+        message += performance_data(perf_data, [(page_faults, \"page_faults\", warning, critical)])\n+        check_levels(page_faults, warning, critical, message)\n+\n+    except Exception, e:\n+        exit_with_general_critical(e)\n+\n+\n+def chunks_balance(con, database, collection, warning, critical):\n+    warning = warning or 10\n+    critical = critical or 20\n+    nsfilter = database + \".\" + collection\n+    try:\n+        try:\n+            set_read_preference(con.admin)\n+            col = con.config.chunks\n+            nscount = col.find({\"ns\": nsfilter}).count()\n+            shards = col.distinct(\"shard\")\n+\n+        except:\n+            print \"WARNING - Can't get chunks infos from MongoDB\"\n+            sys.exit(1)\n+\n+        if nscount == 0:\n+            print \"WARNING - Namespace %s is not sharded\" % (nsfilter)\n+            sys.exit(1)\n+\n+        avgchunksnb = nscount / len(shards)\n+        warningnb = avgchunksnb * warning / 100\n+        criticalnb = avgchunksnb * critical / 100\n+\n+        for shard in shards:\n+            delta = abs(avgchunksnb - col.find({\"ns\": nsfilter, \"shard\": shard}).count())\n+            message = \"Namespace: %s, Shard name: %s, Chunk delta: %i\" % (nsfilter, shard, delta)\n+\n+            if delta >= criticalnb and delta > 0:\n+                print \"CRITICAL - Chunks not well balanced \" + message\n+                sys.exit(2)\n+            elif delta >= warningnb  and delta > 0:\n+                print \"WARNING - Chunks not well balanced  \" + message\n+                sys.exit(1)\n+\n+        print \"OK - Chunks well balanced across shards\"\n+        sys.exit(0)\n+\n+    except Exception, e:\n+        exit_with_general_critical(e)\n+\n+    print \"OK - Chunks well balanced across shards\"\n+    sys.exit(0)\n+\n+\n+def check_connect_primary(con, warning, critical, perf_data):\n+    warning = warning or 3\n+    critical = critical or 6\n+\n+    try:\n+        try:\n+            set_read_preference(con.admin)\n+            data = con.admin.command(pymongo.son_manipulator.SON([('isMaster', 1)]))\n+        except:\n+            data = con.admin.command(son.SON([('isMaster', 1)]))\n+\n+        if data['ismaster'] == True:\n+            print \"OK - This server is primary\"","path":"sensu/plugins/check-mongodb.py","position":1317,"original_position":1317,"commit_id":"a3ed8fa36e09f8f95174be37a299e14163ee28eb","original_commit_id":"a3ed8fa36e09f8f95174be37a299e14163ee28eb","user":{"login":"j2sol","id":523287,"avatar_url":"https://avatars.githubusercontent.com/u/523287?v=3","gravatar_id":"","url":"https://api.github.com/users/j2sol","html_url":"https://github.com/j2sol","followers_url":"https://api.github.com/users/j2sol/followers","following_url":"https://api.github.com/users/j2sol/following{/other_user}","gists_url":"https://api.github.com/users/j2sol/gists{/gist_id}","starred_url":"https://api.github.com/users/j2sol/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/j2sol/subscriptions","organizations_url":"https://api.github.com/users/j2sol/orgs","repos_url":"https://api.github.com/users/j2sol/repos","events_url":"https://api.github.com/users/j2sol/events{/privacy}","received_events_url":"https://api.github.com/users/j2sol/received_events","type":"User","site_admin":false},"body":"print()","created_at":"2015-09-03T16:06:40Z","updated_at":"2015-09-03T16:06:40Z","html_url":"https://github.com/blueboxgroup/ursula-monitoring/pull/29#discussion_r38663609","pull_request_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/pulls/29","_links":{"self":{"href":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/pulls/comments/38663609"},"html":{"href":"https://github.com/blueboxgroup/ursula-monitoring/pull/29#discussion_r38663609"},"pull_request":{"href":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/pulls/29"}}},"pull_request":{"url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/pulls/29","id":44120117,"html_url":"https://github.com/blueboxgroup/ursula-monitoring/pull/29","diff_url":"https://github.com/blueboxgroup/ursula-monitoring/pull/29.diff","patch_url":"https://github.com/blueboxgroup/ursula-monitoring/pull/29.patch","issue_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/issues/29","number":29,"state":"open","locked":false,"title":"Mongodb","user":{"login":"jlcoello","id":13853153,"avatar_url":"https://avatars.githubusercontent.com/u/13853153?v=3","gravatar_id":"","url":"https://api.github.com/users/jlcoello","html_url":"https://github.com/jlcoello","followers_url":"https://api.github.com/users/jlcoello/followers","following_url":"https://api.github.com/users/jlcoello/following{/other_user}","gists_url":"https://api.github.com/users/jlcoello/gists{/gist_id}","starred_url":"https://api.github.com/users/jlcoello/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jlcoello/subscriptions","organizations_url":"https://api.github.com/users/jlcoello/orgs","repos_url":"https://api.github.com/users/jlcoello/repos","events_url":"https://api.github.com/users/jlcoello/events{/privacy}","received_events_url":"https://api.github.com/users/jlcoello/received_events","type":"User","site_admin":false},"body":"added community checks for mongodb \r\nsource : https://github.com/sensu-plugins/sensu-plugins-mongodb/blob/master/bin/check-mongodb.py","created_at":"2015-09-03T15:20:32Z","updated_at":"2015-09-03T16:06:40Z","closed_at":null,"merged_at":null,"merge_commit_sha":"79b6a17fb095bee56dcf7eeed6704067c46ac2af","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/pulls/29/commits","review_comments_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/pulls/29/comments","review_comment_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/pulls/comments{/number}","comments_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/issues/29/comments","statuses_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/statuses/a3ed8fa36e09f8f95174be37a299e14163ee28eb","head":{"label":"jlcoello:mongodb","ref":"mongodb","sha":"a3ed8fa36e09f8f95174be37a299e14163ee28eb","user":{"login":"jlcoello","id":13853153,"avatar_url":"https://avatars.githubusercontent.com/u/13853153?v=3","gravatar_id":"","url":"https://api.github.com/users/jlcoello","html_url":"https://github.com/jlcoello","followers_url":"https://api.github.com/users/jlcoello/followers","following_url":"https://api.github.com/users/jlcoello/following{/other_user}","gists_url":"https://api.github.com/users/jlcoello/gists{/gist_id}","starred_url":"https://api.github.com/users/jlcoello/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jlcoello/subscriptions","organizations_url":"https://api.github.com/users/jlcoello/orgs","repos_url":"https://api.github.com/users/jlcoello/repos","events_url":"https://api.github.com/users/jlcoello/events{/privacy}","received_events_url":"https://api.github.com/users/jlcoello/received_events","type":"User","site_admin":false},"repo":{"id":40981293,"name":"ursula-monitoring","full_name":"jlcoello/ursula-monitoring","owner":{"login":"jlcoello","id":13853153,"avatar_url":"https://avatars.githubusercontent.com/u/13853153?v=3","gravatar_id":"","url":"https://api.github.com/users/jlcoello","html_url":"https://github.com/jlcoello","followers_url":"https://api.github.com/users/jlcoello/followers","following_url":"https://api.github.com/users/jlcoello/following{/other_user}","gists_url":"https://api.github.com/users/jlcoello/gists{/gist_id}","starred_url":"https://api.github.com/users/jlcoello/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jlcoello/subscriptions","organizations_url":"https://api.github.com/users/jlcoello/orgs","repos_url":"https://api.github.com/users/jlcoello/repos","events_url":"https://api.github.com/users/jlcoello/events{/privacy}","received_events_url":"https://api.github.com/users/jlcoello/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/jlcoello/ursula-monitoring","description":"Urusla monitoring and logging repo","fork":true,"url":"https://api.github.com/repos/jlcoello/ursula-monitoring","forks_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/forks","keys_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/teams","hooks_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/hooks","issue_events_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/issues/events{/number}","events_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/events","assignees_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/assignees{/user}","branches_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/branches{/branch}","tags_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/tags","blobs_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/git/refs{/sha}","trees_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/statuses/{sha}","languages_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/languages","stargazers_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/stargazers","contributors_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/contributors","subscribers_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/subscribers","subscription_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/subscription","commits_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/commits{/sha}","git_commits_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/git/commits{/sha}","comments_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/comments{/number}","issue_comment_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/issues/comments{/number}","contents_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/contents/{+path}","compare_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/merges","archive_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/downloads","issues_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/issues{/number}","pulls_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/pulls{/number}","milestones_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/milestones{/number}","notifications_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/labels{/name}","releases_url":"https://api.github.com/repos/jlcoello/ursula-monitoring/releases{/id}","created_at":"2015-08-18T15:53:07Z","updated_at":"2015-08-18T15:53:07Z","pushed_at":"2015-09-03T15:17:38Z","git_url":"git://github.com/jlcoello/ursula-monitoring.git","ssh_url":"git@github.com:jlcoello/ursula-monitoring.git","clone_url":"https://github.com/jlcoello/ursula-monitoring.git","svn_url":"https://github.com/jlcoello/ursula-monitoring","homepage":null,"size":254,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"blueboxgroup:master","ref":"master","sha":"16d6a77e36af8508b16b0ec359d32d4d98ba41d0","user":{"login":"blueboxgroup","id":458705,"avatar_url":"https://avatars.githubusercontent.com/u/458705?v=3","gravatar_id":"","url":"https://api.github.com/users/blueboxgroup","html_url":"https://github.com/blueboxgroup","followers_url":"https://api.github.com/users/blueboxgroup/followers","following_url":"https://api.github.com/users/blueboxgroup/following{/other_user}","gists_url":"https://api.github.com/users/blueboxgroup/gists{/gist_id}","starred_url":"https://api.github.com/users/blueboxgroup/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/blueboxgroup/subscriptions","organizations_url":"https://api.github.com/users/blueboxgroup/orgs","repos_url":"https://api.github.com/users/blueboxgroup/repos","events_url":"https://api.github.com/users/blueboxgroup/events{/privacy}","received_events_url":"https://api.github.com/users/blueboxgroup/received_events","type":"Organization","site_admin":false},"repo":{"id":31778305,"name":"ursula-monitoring","full_name":"blueboxgroup/ursula-monitoring","owner":{"login":"blueboxgroup","id":458705,"avatar_url":"https://avatars.githubusercontent.com/u/458705?v=3","gravatar_id":"","url":"https://api.github.com/users/blueboxgroup","html_url":"https://github.com/blueboxgroup","followers_url":"https://api.github.com/users/blueboxgroup/followers","following_url":"https://api.github.com/users/blueboxgroup/following{/other_user}","gists_url":"https://api.github.com/users/blueboxgroup/gists{/gist_id}","starred_url":"https://api.github.com/users/blueboxgroup/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/blueboxgroup/subscriptions","organizations_url":"https://api.github.com/users/blueboxgroup/orgs","repos_url":"https://api.github.com/users/blueboxgroup/repos","events_url":"https://api.github.com/users/blueboxgroup/events{/privacy}","received_events_url":"https://api.github.com/users/blueboxgroup/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/blueboxgroup/ursula-monitoring","description":"Urusla monitoring and logging repo","fork":false,"url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring","forks_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/forks","keys_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/keys{/key_id}","collaborators_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/teams","hooks_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/hooks","issue_events_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/issues/events{/number}","events_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/events","assignees_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/assignees{/user}","branches_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/branches{/branch}","tags_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/tags","blobs_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/git/refs{/sha}","trees_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/git/trees{/sha}","statuses_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/statuses/{sha}","languages_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/languages","stargazers_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/stargazers","contributors_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/contributors","subscribers_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/subscribers","subscription_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/subscription","commits_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/commits{/sha}","git_commits_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/git/commits{/sha}","comments_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/comments{/number}","issue_comment_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/issues/comments{/number}","contents_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/contents/{+path}","compare_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/compare/{base}...{head}","merges_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/merges","archive_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/downloads","issues_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/issues{/number}","pulls_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/pulls{/number}","milestones_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/milestones{/number}","notifications_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/labels{/name}","releases_url":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/releases{/id}","created_at":"2015-03-06T16:32:28Z","updated_at":"2015-05-07T09:28:23Z","pushed_at":"2015-09-03T15:20:33Z","git_url":"git://github.com/blueboxgroup/ursula-monitoring.git","ssh_url":"git@github.com:blueboxgroup/ursula-monitoring.git","clone_url":"https://github.com/blueboxgroup/ursula-monitoring.git","svn_url":"https://github.com/blueboxgroup/ursula-monitoring","homepage":null,"size":636,"stargazers_count":1,"watchers_count":1,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":3,"mirror_url":null,"open_issues_count":7,"forks":3,"open_issues":7,"watchers":1,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/pulls/29"},"html":{"href":"https://github.com/blueboxgroup/ursula-monitoring/pull/29"},"issue":{"href":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/issues/29"},"comments":{"href":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/issues/29/comments"},"review_comments":{"href":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/pulls/29/comments"},"review_comment":{"href":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/pulls/29/commits"},"statuses":{"href":"https://api.github.com/repos/blueboxgroup/ursula-monitoring/statuses/a3ed8fa36e09f8f95174be37a299e14163ee28eb"}}}}