Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ FROM ${img_user}/${img_repo}:${img_tag}
COPY . /usr/local/src_dragonfly

WORKDIR /usr/local/src_dragonfly
RUN pip install docker pymodbus
RUN pip install docker pymodbus Flask
RUN pip install .

WORKDIR /
15 changes: 0 additions & 15 deletions dragonfly/__init__.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,4 @@
import logging
logger = logging.getLogger(__name__)

def __get_version():
import scarab
import dragonfly
import pkg_resources
#TODO: this all needs to be populated from setup.py and gita
version = scarab.VersionSemantic()
logger.info('version should be: {}'.format(pkg_resources.get_distribution('dragonfly').version))
version.parse(pkg_resources.get_distribution('dragonfly').version)
version.package = 'project8/dragonfly'
version.commit = 'na'
dragonfly.core.add_version('dragonfly', version)
return version
version = __get_version()
__version__ = version.version

from .watchdog import *
81 changes: 81 additions & 0 deletions dragonfly/alarm_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
from flask import Flask, redirect, request, render_template, url_for
import os
import yaml

CONFIG_FILE = "/root/AlarmSystem.yaml"

def load_data():
if not os.path.exists(CONFIG_FILE):
return []
with open(CONFIG_FILE, "r") as open_file:
config = yaml.safe_load( open_file )
return config["check_endpoints"]

def save_data(data):
with open(CONFIG_FILE, "r") as open_file:
config = yaml.safe_load( open_file )
config["check_endpoints"] = data
print(config, flush=True)
with open(CONFIG_FILE, "w") as open_file:
yaml.safe_dump(config, open_file)

app = Flask(__name__)

@app.route('/')
def index():
data = load_data()

return render_template("index.html", data=data)

@app.route('/add', methods=["POST"])
def add_row():
data = load_data()


new_row = {
"enable": request.form.get("enable") == "on",
"endpoint": request.form.get("endpoint"),
"method": request.form.get("comparison"),
"reference": request.form.get("reference"),
"message": request.form.get("message"),
}
try:
new_row["reference"] = float(new_row["reference"])
except:
pass

data.append(new_row)

save_data(data)

return redirect(url_for("index"))

@app.route("/delete/<int:index>", methods=["POST"])
def delete_row(index):
data = load_data()

if 0 <= index < len(data):
data.pop(index)

save_data(data)

return redirect(url_for("index"))

@app.route("/update", methods=["POST"])
def update():
data = load_data()

for i, row in enumerate(data):
row["enable"] = request.form.get(f"enable_{i}") == "on"
row["endpoint"] = request.form.get(f"endpoint_{i}")
row["comparison"] = request.form.get(f"comparison_{i}")
row["reference"] = request.form.get(f"reference_{i}")
try:
row["reference"] = float(row["reference"])
except:
pass
row["message"] = request.form.get(f"message_{i}")

save_data(data)

return redirect(url_for("index"))
97 changes: 97 additions & 0 deletions dragonfly/templates/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<!DOCTYPE html>
<html>
<head>
<title>YAML Monitor Table</title>
<style>
table {
border-collapse: collapse;
width: 100%;
}
th, td {
border: 1px solid #ccc;
padding: 8px;
}
th {
background: #eee;
}
</style>
</head>
<body>

<h2>Alarm System Configuration Table</h2>

<form method="POST" action="/update">
<table>
<tr>
<th>Enable</th>
<th>Endpoint</th>
<th>Comparison</th>
<th>Reference</th>
<th>Message</th>
<th>Action</th>
</tr>

{% for row in data %}
<tr>
<td>
<input type="checkbox" name="enable_{{ loop.index0 }}" {% if row['enable'] %}checked{% endif %}>
</td>
<td>
<input name="endpoint_{{ loop.index0 }}" value="{{ row.endpoint }}">
</td>
<td>
<input name="comparison_{{ loop.index0 }}" value="{{ row.method }}">
</td>
<td>
<input name="reference_{{ loop.index0 }}" value="{{ row.reference }}">
</td>
<td>
<input name="message_{{ loop.index0 }}" value="{{ row.message }}">
</td>
<td>
<form method="POST" action="/delete/{{ loop.index0 }}">
<button type="submit">Delete</button>
</form>
</td>
</tr>
{% endfor %}
</table>

<br>
<button type="submit">Save Changes</button>
</form>

<hr>

<h3>Add New Row</h3>

<form method="POST" action="/add">
<table>
<tr>
<th>Enable</th>
<th>Endpoint</th>
<th>Comparison</th>
<th>Reference</th>
<th>Message</th>
<th>Action</th>
</tr>
<tr>
<td><input type="checkbox" name="enable"></td>
<td><input name="endpoint"></td>
<td><input name="comparison"></td>
<td><input name="reference"></td>
<td><input name="message"></td>
<td><button type="submit">Add</button></td>
</tr>
</table>
</form>
<h3>Notes:</h3>
<ul>
<li>Enable: If checkbox is not checked, the check of the endpoint is skipped.</li>
<li>Endpoint: has to be a valid dripline endpoint name.</li>
<li>Comparison: Has to be one of ["equal", "not_equal", "lower", "greater"]</li>
<li>Reference: Will be interpreted as float if possible, otherwise as string. Has to match endpoint type.</li>
<li>Message: The message that is send to slack, it the condition is fullfilled. </li>
</ul>
</body>
</html>
29 changes: 22 additions & 7 deletions dragonfly/watchdog.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class WatchDog(object):
def __init__(self, config_path):
self.config_path = config_path
self.load_configuration()
self.load_slack_hook()
self.setup_docker_client()
self.setup_dripline_connection()
signal.signal(signal.SIGINT, self.exit_gracefully)
Expand All @@ -27,11 +28,21 @@ def load_configuration(self):
with open(Path(args.config), "r") as open_file:
self.config = yaml.safe_load( open_file.read() )

if not "slack_hook" in self.config.keys():
self.config["slack_hook"] = None
if not "slack_hook_file" in self.config.keys():
self.config["slack_hook_file"] = None

print("Configuration is:", flush=True)
print(self.config, flush=True)

def load_slack_hook(self):
if self.config["slack_hook_file"] is not None:
with open(Path(self.config["slack_hook_file"]), "r") as open_file:
self.hook_config = yaml.safe_load( open_file.read() )

if not "slack_hook" in self.hook_config.keys():
self.hook_config["slack_hook"] = None
else:
self.hook_config = {"slack_hook": None}

def setup_docker_client(self):
self.client = docker.from_env()
Expand All @@ -45,11 +56,11 @@ def exit_gracefully(self, signum, frame):
self.send_slack_message("Stopping, received signal: %d"%signum)

def send_slack_message(self, message):
if self.config["slack_hook"] is None:
if self.hook_config["slack_hook"] is None:
print("Slack hook not configured. No message will be send!")
return
post = {"text": "{0}".format(message)}
response = requests.post(self.config["slack_hook"], headers={'Content-Type': 'application/json'}, data=json.dumps(post))
response = requests.post(self.hook_config["slack_hook"], headers={'Content-Type': 'application/json'}, data=json.dumps(post))

if response.status_code != 200:
print(f'Request to slack returned an error {response.status_code}, the response is:\n{response.text}')
Expand All @@ -73,20 +84,24 @@ def compare(self, value, reference, method):
raise ValueError(f"Comparison method {method} is not defined. You can use one of ['not_equal', 'equal', 'lower', 'greater'].")

def run(self):

while not self.kill_now:
self.load_configuration()

if self.config["check_endpoints"] is not None:
for entry in self.config["check_endpoints"]:
if self.kill_now: break
if "enable" in entry.keys() and entry["enable"]==False: continue
try:
value = self.get_endpoint(entry["endpoint"])
if ":value_cal" in entry["endpoint"]:
value = self.get_endpoint(entry["endpoint"].replace(":value_cal", ""), calibrated=True)
else:
value = self.get_endpoint(entry["endpoint"])
print(entry["endpoint"], value, flush=True)
if self.compare(value, entry["reference"], entry["method"]):
self.send_slack_message(entry["message"].format(**locals()))
except Exception as e:
self.send_slack_message("Could not get endpoint %s. Got error %s."%(entry["endpoint"], str(e) ))


for container in self.client.containers.list(all=True):
if self.kill_now: break
if any([container.name.startswith(black) for black in self.config["blacklist_containers"]]):
Expand Down
Loading