def check_next(checkid): """Reschedule a given check""" if request.method == 'GET': check = r.table("checks").get(checkid).run(rdb.conn) if check: check['id'] = str(check['id']) return jsonify({'check': check}) else: abort(404) elif request.method == 'POST': if not request.json: abort(400) try: if not request.json.get('next'): abort(400) if request.json.get('next') == 'now': q = r.table("checks").get(checkid).update({"next": time() - 1}).run(rdb.conn) else: q = r.table("checks").get(checkid).update({"next": int(request.json["next"])}).run(rdb.conn) if q["replaced"] != 0: return jsonify({'success': True}) else: abort(404) except Exception as err: logger.error(err) abort(400)
def check_suspended(checkid): """Suspend a given check""" if request.method == 'GET': check = r.table("checks").get(checkid).run(rdb.conn) if check: check['id'] = str(check['id']) return jsonify({'check': check}) else: abort(404) elif request.method == 'POST': if not request.json: abort(400) try: if not request.json.get('suspended'): abort(400) if request.json.get('suspended') is True: q = r.table("checks").get(checkid).update({"suspended": True}).run(rdb.conn) elif request.json.get('suspended') is False: q = r.table("checks").get(checkid).update({"suspended": False}).run(rdb.conn) else: abort(400) if q['replaced'] != 0: return jsonify({'success': True}) else: abort(404) except Exception as err: logger.error(err) abort(400)
def register(): if request.headers.get('X-REGISTER-KEY') != app.config['REGISTER_KEY']: abort(412) if not request.json: abort(400) if not _valid_registration(request.json): abort(400) hid = request.json['hostname'] checks = request.json['checks'] roles = request.json['roles'] try: # TODO: need a unique constraint on hostname q = mongo.db.hosts.update({'hostname': hid}, {"$set": {'hostname': hid, 'ip': request.remote_addr, 'checks': checks, 'roles': roles}}, upsert=True) # TODO: Since this is just a POC we'll just blow away ALL of the # existing checks for the host and readd them. mongo.db.checks.remove({'hostname': hid}) bulk_load = [] for i in checks: bulk_load.append({'hostname': hid, 'ip': request.remote_addr, 'check': i, 'last': 0, 'next': _rand_start(), 'interval': checks[i]['interval'], 'follow_up': checks[i]['follow_up'], 'pending': False, 'status': None, 'in_maintenance': False, 'suspended': False, 'out': '', 'priority': checks[i].get('priority', 1)}) mongo.db.checks.insert(bulk_load) except pymongo.errors.DuplicateKeyError as err: logger.error(err) return jsonify({'status': 'fail', 'error': err}), 400 return jsonify({'status': 'ok'})
def list_notes(hostname): """Retrieve a list of notes associated with a host. Or given {'user': '******', 'note': 'some message'} post a note.""" if request.method == 'GET': try: #someday i should probably add offset support here and in the statelog limit = request.args.get('limit', 50, type=int) except ValueError: abort(400) notes = list(r.table("notes").filter({"hostname": hostname}).order_by(r.desc("ts")).limit(limit).run(rdb.conn)) if notes: return jsonify({'notes': sorted(notes, key=lambda k: k['ts'])}) else: abort(404) elif request.method == 'POST': if not request.json: abort(400) if not request.json.get("user") or not request.json.get("note"): abort(400) if not r.table("hosts").get_all(hostname, index="hostname").run(rdb.conn): abort(404) alerting = [x["check"] for x in r.table("checks").filter({"h stname": hostname, "status": False}).run(rdb.conn)] q = r.table("notes").insert({'hostname': hostname, 'user': request.json.get("user"), 'note': request.json.get("note"), 'ts': time(), 'alerting': alerting}).run(rdb.conn) if q["inserted"] == 1: return jsonify({'success': True}) else: logger.error(q) abort(500) else: abort(400)
def check_next(checkid): if request.method == 'GET': check = mongo.db.checks.find_one({'_id': ObjectId(checkid)}, {'next': 1}) if check: check['_id'] = str(check['_id']) return jsonify({'check': check}) else: abort(404) elif request.method == 'POST': if not request.json: abort(400) try: if request.json['next'] == 'now': q = mongo.db.checks.update({'_id': ObjectId(checkid)}, {'$set': {'next': time() - 1}}) else: q = mongo.db.checks.update({'_id': ObjectId(checkid)}, {'$set': {'next': int(request.json['next'])}}) if q['n'] != 0: return jsonify({'success': True}) else: abort(404) except (KeyError, ValueError, pymongo.errors.InvalidId) as err: logger.error(err) abort(400)
def check_owner(checkid): """claim or unclaim a given check""" if request.method == 'GET': check = r.table("checks").get(checkid).run(rdb.conn) if check: check['id'] = str(check['id']) return jsonify({'check': check}) else: abort(404) elif request.method == 'POST': if not request.json: abort(400) try: if request.json.get('owner'): q = r.table("checks").get(checkid).update({"owner": str(request.json["owner"])}).run(rdb.conn) else: abort(400) if q["replaced"] != 0: return jsonify({'success': True}) else: abort(404) except Exception as err: logger.error(err) abort(400) elif request.method == 'DELETE': try: q = r.table("checks").get(checkid).update({"owner": ""}).run(rdb.conn) if q["replaced"] != 0: return jsonify({'success': True}) else: abort(404) except Exception as err: logger.error(err) abort(400)
def check_suspended(checkid): if request.method == 'GET': check = mongo.db.checks.find_one({'_id': ObjectId(checkid)}, {'suspended': 1}) if check: check['_id'] = str(check['_id']) return jsonify({'check': check}) else: abort(404) elif request.method == 'POST': if not request.json: abort(400) try: if request.json['suspended'] is True: q = mongo.db.checks.update({'_id': ObjectId(checkid)}, {'$set': {'suspended': True}}) elif request.json['suspended'] is False: q = mongo.db.checks.update({'_id': ObjectId(checkid)}, {'$set': {'suspended': False}}) else: abort(400) if q['n'] != 0: return jsonify({'success': True}) else: abort(404) except (KeyError, ValueError, pymongo.errors.InvalidId): abort(400)
def check_state(state): """List of checks in cluster in a given state [alerting/pending/suspended]""" if state == 'alerting': q = list(r.table("checks").get_all(False, index="status").run(rdb.conn)) if q: return jsonify({'alerting': q}) else: return jsonify({'alerting': []}) elif state == 'pending': q = list(r.table("checks").get_all(True, index="pending").run(rdb.conn)) if q: return jsonify({'pending': q}) else: return jsonify({'pending': []}) elif state == 'in_maintenance': q = list(r.table("checks").get_all(True, index="in_maintenance").run(rdb.conn)) if q: return jsonify({'in_maintenance': q}) else: return jsonify({'in_maintenance': []}) elif state == 'suspended': q = list(r.table("checks").get_all(True, index="suspended").run(rdb.conn)) if q: return jsonify({'suspended': q}) else: return jsonify({'suspended': []}) else: abort(400)
def check_state(state): if state == 'alerting': q = [x for x in mongo.db.checks.find({'status': False})] if q: return jsonify({'alerting': q}) else: return jsonify({'alerting': []}) elif state == 'pending': q = [x for x in mongo.db.checks.find({'pending': True})] if q: return jsonify({'pending': q}) else: return jsonify({'pending': []}) elif state == 'in_maintenance': q = [x for x in mongo.db.checks.find({'in_maintenance': True})] if q: return jsonify({'in_maintenance': q}) else: return jsonify({'in_maintenance': []}) elif state == 'suspended': q = [x for x in mongo.db.checks.find({'suspended': True})] if q: return jsonify({'suspended': q}) else: return jsonify({'suspended': []}) else: abort(400)
def checks_by_id(checkid): """Get info for or delete a given check""" if request.method == 'GET': check = r.table("checks").get(checkid).run(rdb.conn) if check: check['id'] = str(check['id']) return jsonify({'check': check}) else: abort(404) elif request.method == 'DELETE': q = r.table("checks").get(checkid).delete().run(rdb.conn) if q["deleted"] == 1: return jsonify({'success': True}) else: return jsonify({'success': False})
def help(): """Show endpoints""" func_list = {} for rule in app.url_map.iter_rules(): if rule.endpoint != 'static': func_list[rule.rule] = app.view_functions[rule.endpoint].__doc__ return jsonify(func_list)
def global_check_state(clusterid, state): if clusterid not in app.config['GLOBAL_CLUSTERS']: abort(400) if state in VALID_STATES: ckey = '%s:%s' % (clusterid, state) cached = cache.get(ckey) if cached: return jsonify({clusterid: cached}) else: q = _get_remote_checks(clusterid, state) if q: cache.set(ckey, q) return jsonify({clusterid: q}) else: abort(500) else: abort(400)
def hosts(host): """Delete a given host and all its checks""" if not host: q = list(r.table("hosts").without("id").run(rdb.conn)) if q: q = {'hosts': q} else: if request.method == 'DELETE': q = r.table("checks").filter((r.row["hostname"] == host) | (r.row["ip"] == host)).delete().run(rdb.conn) q = r.table("hosts").filter((r.row["hostname"] == host) | (r.row["ip"] == host)).delete().run(rdb.conn) return jsonify({'success': True}) else: q = list(r.table("hosts").filter((r.row["hostname"] == host) | (r.row["ip"] == host)).without("id").run(rdb.conn)) if q: return jsonify(q[0]) else: abort(404)
def checks_by_id(checkid): if request.method == 'GET': check = mongo.db.checks.find_one({'_id': ObjectId(checkid)}) if check: check['_id'] = str(check['_id']) return jsonify({'check': check}) else: abort(404) elif request.method == 'DELETE': try: q = mongo.db.checks.remove({'_id': ObjectId(checkid)}, safe=True) return jsonify({'success': True}) except pymongo.errors.InvalidId: abort(404) except pymongo.errors.OperationFailure: logger.exception('Error removing check') abort(500)
def global_check_state(clusterid, state): """Get a list of all checks in provided state for a given cluster""" if clusterid not in app.config['GLOBAL_CLUSTERS']: abort(400) if state in VALID_STATES: ckey = '%s:%s' % (clusterid, state) cached = cache.get(ckey) if cached: return jsonify({clusterid: cached}) else: q = _get_remote_checks(clusterid, state) if q: cache.set(ckey, q) return jsonify({clusterid: q}) else: abort(500) else: abort(400)
def checks(host): """Get all checks for a given hostname or ip""" if not host: q = list(r.table("checks").run(rdb.conn)) else: q = list(r.table("checks").filter((r.row["hostname"] == host) | (r.row["ip"] == host)).run(rdb.conn)) if q: for check in q: check['id'] = str(check['id']) return jsonify({'checks': q}) else: abort(404)
def checks(host): if not host: q = [x for x in mongo.db.checks.find()] else: q = [x for x in mongo.db.checks.find({'$or': [{'hostname': host}, {'ip': host}]})] if q: for check in q: check['_id'] = str(check['_id']) return jsonify({'checks': q}) else: abort(404)
def register(): if request.headers.get('X-REGISTER-KEY') != app.config['REGISTER_KEY']: abort(412) if not request.json: abort(400) if not _valid_registration(request.json): abort(400) hid = request.json['hostname'] checks = request.json['checks'] roles = request.json['roles'] ip_addr = request.json.get('ip', request.remote_addr) if ip_addr == '': ip_addr = request.remote_addr try: pkey = genPrimaryKey64("%s%s" % (hid, ip_addr)) q = r.table("hosts").insert({ "id": pkey, "hostname": hid, "ip": ip_addr, "checks": checks, "roles": roles },conflict="update").run(rdb.conn) q = r.table("checks").filter({"hostname": hid}).delete().run(rdb.conn) #we're about to reinstart all so just delete all incase checks got removed bulk_load = [] for i in checks: bulk_load.append({'id': genPrimaryKey64("%s%s%s" % (hid, ip_addr, i)), 'hostname': hid, 'ip': ip_addr, 'check': i, 'last': 0, 'next': _rand_start(), 'interval': checks[i]['interval'], 'follow_up': checks[i]['follow_up'], 'pending': False, 'status': None, 'in_maintenance': False, 'suspended': False, 'out': '', 'priority': checks[i].get('priority', 1)}) q = r.table("checks").insert(bulk_load, conflict="update").run(rdb.conn) except Exception as err: logger.error(err) return jsonify({'status': 'fail', 'error': str(err)}), 400 return jsonify({'status': 'ok'})
def state_log_by_check(hostname, checkname): if request.method == 'GET': try: limit = request.args.get('limit', 10, type=int) except ValueError: abort(400) log = [x for x in mongo.db.state_log.find({'hostname': hostname, 'check': checkname}, limit=limit).sort('last', pymongo.DESCENDING)] if checks: return jsonify({'state_log': sorted(log, key=lambda k: k['last'])}) else: abort(404) else: abort(400)
def users(username): if not username: if request.method == 'DELETE': abort(400) # don't allow deletes with out user if session.get('username', False): username = session.get('username') else: abort(400) if request.method == 'GET': q = mongo.db.users.find_one({'username': username}, {'hash': False}) if q: q['_id'] = str(q['_id']) if 'theme' not in q: q['theme'] = 'cerulean' return jsonify(q) else: abort(404) elif request.method == 'DELETE': return jsonify({'success': remove_user(username)}) elif request.method == 'POST': fields = {} if not request.json: abort(400) if 'theme' in request.json: if request.json['theme'] in app.config['THEMES']: fields['theme'] = request.json['theme'] else: abort(400) if 'email' in request.json: fields['email'] = request.json['email'] q = mongo.db.users.update({'username': username}, {"$set": fields}, upsert=False) if q: if session and 'theme' in fields: session['theme'] = fields['theme'] return jsonify({'success': True}) else: return jsonify({'success': False})
def state_log_by_check(hostname, checkname): """Get check history for a given check on a given host""" if request.method == 'GET': try: limit = request.args.get('limit', 10, type=int) except ValueError: abort(400) log = list(r.table("state_log").filter({"hostname": hostname, "check": checkname}).order_by(r.desc("last")).limit(limit).run(rdb.conn)) if log: return jsonify({'state_log': sorted(log, key=lambda k: k['last'])}) else: abort(404) else: abort(400)
def hosts(host): if not host: q = [x for x in mongo.db.hosts.find(fields={'_id': False})] if q: q = {'hosts': q} else: if request.method == 'DELETE': try: q = mongo.db.checks.remove({'$or': [{'hostname': host}, {'ip': host}]}, safe=True) q = mongo.db.hosts.remove({'$or': [{'hostname': host}, {'ip': host}]}, safe=True) return jsonify({'success': True}) except pymongo.errors.InvalidId: abort(404) except pymongo.errors.OperationFailure: logger.exception('Error removing hosts/checks.') abort(500) else: q = mongo.db.hosts.find_one({'$or': [{'hostname': host}, {'ip': host}]}, fields={'_id': False}) if q: return jsonify(q) else: abort(404)
def users(username): if not username: if request.method == 'DELETE': abort(400) # don't allow deletes with out user if session.get('username', False): username = session.get('username') else: abort(400) if request.method == 'GET': q = list(r.table("users").filter({"username": username}).without("hash").run(rdb.conn))[0] if q: if 'theme' not in q: q['theme'] = 'cerulean' return jsonify(q) else: abort(404) elif request.method == 'DELETE': return jsonify({'success': remove_user(username)}) elif request.method == 'POST': fields = {} if not request.json: abort(400) if 'theme' in request.json: if request.json['theme'] in app.config['THEMES']: fields['theme'] = request.json['theme'] else: abort(400) if 'email' in request.json: fields['email'] = request.json['email'] q = r.table("users").filter({"username": username}).update(fields).run(rdb.conn) if q["replaced"] != 0 : if session and 'theme' in fields: session['theme'] = fields['theme'] return jsonify({'success': True}) else: return jsonify({'success': False})
def stalker_stats(clusterid): """Obtain stats for this cluster or one with a given clusterid""" default = {'qsize': None, 'failing': None, 'flapping': None, 'suspended': None, 'checks': None, 'pending': None} if not clusterid: q = _get_local_metrics() if q: return jsonify({app.config['LOCAL_CID']: q}) else: return jsonify({app.config['LOCAL_CID']: default}) else: if clusterid in app.config['GLOBAL_CLUSTERS']: ckey = '%s:%s' % (clusterid, 'stats') cached = cache.get(ckey) if cached: return jsonify({clusterid: cached}) else: q = _get_remote_stats(clusterid) if q: cache.set(ckey, q) return jsonify({clusterid: q}) else: return jsonify({clusterid: default}) elif clusterid == 'all': q = {} q[app.config['LOCAL_CID']] = _get_local_metrics() for cid in app.config['GLOBAL_CLUSTERS'].keys(): ckey = '%s:%s' % (cid, 'stats') cached = cache.get(ckey) if cached: q[cid] = cached else: q[cid] = _get_remote_stats(cid) if not q[cid]: q[cid] = default cache.set(ckey, q[cid]) return jsonify({'all': q}) else: abort(404)
def global_clusters(): """List of known clusters and their id""" return jsonify({'clusters': app.config['GLOBAL_CLUSTERS']})
def global_clusters(): return jsonify({'clusters': app.config['GLOBAL_CLUSTERS']})