Skip to content

Commit

Permalink
Merge pull request #54 from diggyk/master
Browse files Browse the repository at this point in the history
Add notification system for Hermes
  • Loading branch information
leojli committed Sep 28, 2015
2 parents 0002671 + 32ce166 commit 696ce09
Show file tree
Hide file tree
Showing 6 changed files with 184 additions and 0 deletions.
157 changes: 157 additions & 0 deletions bin/hermes-notify
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
#!/usr/bin/env python

import argparse
import logging
import textwrap

import hermes
from hermes.handlers.util import PluginHelper
from hermes.models import get_db_session, get_db_engine, Session, Quest, Labor
from hermes.settings import settings
from hermes.util import email_message

from sqlalchemy.exc import OperationalError

sa_log = logging.getLogger("sqlalchemy.engine.base.Engine")


def parse_args():
parser = argparse.ArgumentParser(description="Hermes Web Service")
parser.add_argument("-c", "--config", default="/etc/hermes/server.yaml",
help="Path to config file.")
parser.add_argument(
"-v", "--verbose", action="count", default=0,
help="Increase logging verbosity."
)
parser.add_argument(
"-q", "--quiet", action="count", default=0,
help="Decrease logging verbosity."
)
parser.add_argument(
"-V", "--version", action="version",
version="%%(prog)s %s" % hermes.__version__,
help="Display version information."
)
parser.add_argument(
"-p", "--port", type=int, default=None, help="Override port in config."
)
return parser.parse_args()

def find_quest(quests, quest_id):
for quest in quests:
if quest.id == quest_id:
return quest

return None

def main():

args = parse_args()
settings.update_from_config(args.config)

if args.verbose:
logging.basicConfig(level=logging.DEBUG, format=settings.log_format)
elif args.quiet:
logging.basicConfig(level=logging.ERROR, format=settings.log_format)
else:
logging.basicConfig(level=logging.INFO, format=settings.log_format)

logging.info(
"Starting Hermes notification system"
)

# Connect to the database and get the open quests
db_engine = get_db_engine(settings.database)
Session.configure(bind=db_engine)
session = Session()
open_quests = Quest.get_open_quests(session)
open_labors = Labor.get_open_labors(session)

# get the list of all the hostnames that have open labors
hostnames = set()
for labor in open_labors:
hostnames.add(labor.host.hostname)

# get the owner information
try:
results = PluginHelper.request_post(
json_body={
"operation": "owners",
"hostnames": list(hostnames)
}
)
owners = results.json()['results']
except Exception as e:
logging.error("Failed to get host owners: " + e.message)

# get the tags for hosts
try:
results = PluginHelper.request_post(
json_body={
"operation": "tags",
"hostnames": list(hostnames)
}
)
tags = results.json()['results']
except Exception as e:
logging.error("Failed to get host tags: " + e.message)

# map the labors and quests to owners
info = {}
for labor in open_labors:
# FIXME we only map "required" labors -- is that the right approach?
if labor.creation_event.event_type.state != "required":
continue
if owners[labor.host.hostname] not in info:
info[owners[labor.host.hostname]] = {}

owner = info[owners[labor.host.hostname]]

quest_id = labor.quest_id if labor.quest else 0
if quest_id not in owner:
owner[quest_id] = []

owner[quest_id].append(labor.host.hostname)

# generate and send emails
for owner in info:
msg = (
"Hello {}:\n\nYou have open Hermes labors "
"which need to be addressed ASAP.\n\n".format(owner)
)

for quest_id in info[owner]:
quest = find_quest(open_quests, quest_id)
if quest:
msg += " Quest {} created by {}:\n".format(
quest_id, quest.creator
)
msg += " \"{}\"\n".format(textwrap.fill(
quest.description,
width=60, subsequent_indent=" "
))
msg += " href: {}/v1/quests/{}\n\n".format(
settings.frontend, quest_id
)
else:
msg += " Labors not associated with a quest:\n\n"

for hostname in sorted(info[owner][quest_id]):
msg += " {} ({})\n".format(
hostname, (", ".join(tags[hostname]))
)

msg += "\n\n"

msg += (
"\nTo see more information or throw event "
"manually, please visit {}.".format(settings.frontend)
)

email_message(
"{}@{}".format(owner, settings.domain),
"Open Hermes labors need your attention", msg
)

if __name__ == "__main__":
main()
1 change: 1 addition & 0 deletions hermes/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ def __getattr__(self, name):
"num_processes": 1,
"database": None,
"query_server": "http://localhost:5353/api/query",
"frontend": "https://hermes.company.net",
"slack_webhook": None,
"slack_proxyhost": None,
"debug": False,
Expand Down
Binary file added hermes/webapp/src/img/remove_15.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions hermes/webapp/src/js/controllers/laborStatusCtrl.js
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,11 @@
for (var idx = parseInt(vm.offset);
idx < (parseInt(vm.offset) + parseInt(vm.limit));
idx++) {

if (idx >= vm.laborData.length) {
break;
}

if (vm.selected.indexOf(vm.laborData[idx].id) == -1) {
vm.selected.push(vm.laborData[idx].id);
}
Expand All @@ -260,6 +265,11 @@
function deselectAll() {
for (var idx = parseInt(vm.offset);
idx < (parseInt(vm.offset) + parseInt(vm.limit)); idx++) {

if (idx >= vm.laborData.length) {
break;
}

var idy = vm.selected.indexOf(vm.laborData[idx].id);
if (idy != -1) {
vm.selected.splice(idy, 1);
Expand Down
6 changes: 6 additions & 0 deletions hermes/webapp/src/templates/laborList.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
<input id="ownerFilter" type="text" ng-model="lsc.hostOwnerInput" />
</form>
</div>
<div class="col-md-2">
<img src="/img/remove_15.png" alt="Clear owner filter field" class="remove-img-button" ng-click="lsc.hostOwnerInput = ''" />
</div>
</div>
<div style="margin-top: 5px">
<label for="queryFilter">Filter by query:</label>
Expand All @@ -21,6 +24,9 @@
<input id="queryFilter" type="text" ng-model="lsc.queryInput" />
</form>
</div>
<div class="col-md-2">
<img src="/img/remove_15.png" alt="Clear query filter field" class="remove-img-button" ng-click="lsc.queryInput = ''" />
</div>
</div>
<div style="margin-top: 5px">
<label for="event-type-selection">Filter by labor's event type:</label>
Expand Down
10 changes: 10 additions & 0 deletions hermes/webapp/src/templates/questStatus.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
<input id="creatorFilter" type="text" ng-model="qc.filterByCreator" />
</form>
</div>
<div class="col-md-2">
<img src="/img/remove_15.png" alt="Clear owner filter field" class="remove-img-button" ng-click="qc.filterByCreator = ''" />
</div>
</div>
<div style="margin-top: 5px">
<label for="queryFilter">Filter by query:</label>
Expand All @@ -24,6 +27,13 @@
<input id="queryFilter" type="text" ng-model="qc.queryInput" />
</form>
</div>
<div class="col-md-2">
<img src="/img/remove_15.png" alt="Clear query filter field" class="remove-img-button" ng-click="qc.queryInput = ''" />
</div>
</div>
<div class="row" style="margin-top: 10px">
<div class="col-md-10">
</div>
<div class="col-md-2">
<button ng-click="qc.runNewFilter()">GO</button>
</div>
Expand Down

0 comments on commit 696ce09

Please sign in to comment.