-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapp.py
135 lines (120 loc) · 5.34 KB
/
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import os
import sys
import logging
from clockbridgeconfig import Config
import webhook
from flask import Flask, Response, request
# Kludge libraries
import requests
import urllib3
from datetime import datetime, timezone
import json
file_path = os.environ.get('CLOCKBRIDGE_CONFIG_PATH')
if not file_path:
file_path = os.path.join(os.getcwd(), 'config.yaml')
app = Flask(__name__)
config = Config(file_path)
logging.info("Configuration loaded from %s, logging at %s level", file_path, config.log_level)
logger = logging.getLogger(__name__)
logging.basicConfig(format='%(asctime)s [%(levelname)s] %(message)s',
stream=sys.stderr)
logger.setLevel(config.log_level)
@app.route("/ping", methods = ['GET'])
def ping():
return "Pong\n"
@app.route("/webhook/clockify", methods = ['POST'])
def clockbridge():
try:
logger.info("Incoming payload")
hook = webhook.Webhook(config)
logger.debug("Payload received with headers:\n %s", dict(request.headers))
logger.debug("Payload contents:\n %s", json.dumps(request.json, indent=4))
payload = hook.verify_incoming_webhook(request.headers, request.data)
if not payload:
return Response("Unauthorized", 403)
except ValueError:
return Response("Malformed request body", 400)
try:
# From here on out is just kludge code to make this work because I'm bored of manually entering data
urllib3.disable_warnings(category=urllib3.exceptions.InsecureRequestWarning)
now = datetime.now().astimezone()
dt_end = datetime.strptime(payload['timeInterval']['end'], "%Y-%m-%dT%H:%M:%S%z")
index_name = f"{config.elastic_creds['index_prefix']}-{dt_end.strftime('%Y-%m')}"
payload['@timestamp'] = now.strftime('%Y-%m-%dT%H:%M:%S%z')
pwd = config.elastic_creds['password'].decode().strip()
health = requests.get(
f"{config.elastic_creds['url']}_cluster/health?wait_for_status=yellow&timeout=50s",
auth=(config.elastic_creds['username'], pwd),
verify=not config.elastic_creds['insecure'],
headers={"Content-Type": "application/json"},
timeout=50
)
logger.info("Elasticsearch health check returned %s", health.json()['status'])
if health.ok:
logger.info("Elasticsearch endpoint up, pushing data...")
if hook.action == "TIME_ENTRY_DELETED":
r = delete_doc(url=config.elastic_creds['url'],
index=index_name,
doc_id=payload['id'],
user=config.elastic_creds['username'],
pwd=pwd
)
elif hook.action == "TIME_ENTRY_UPDATED":
r = delete_doc(url=config.elastic_creds['url'],
index=index_name,
doc_id=payload['id'],
user=config.elastic_creds['username'],
pwd=pwd
)
r = create_doc(url=config.elastic_creds['url'],
index=index_name,
doc_id=payload['id'],
user=config.elastic_creds['username'],
pwd=pwd,
data=payload
)
else:
r = create_doc(url=config.elastic_creds['url'],
index=index_name,
doc_id=payload['id'],
user=config.elastic_creds['username'],
pwd=pwd,
data=payload
)
return r
raise requests.exceptions.HTTPError(health.content)
except Exception:
return Response(503)
def delete_doc(url, index, doc_id, user, pwd, verify_ssl=False):
try:
r = requests.delete(f"{url}{index}/_doc/{doc_id}",
auth=(user, pwd),
verify=verify_ssl,
headers={"Content-Type": "application/json"},
timeout=10
)
if r.ok:
logger.info("Deleted existing document from Elasticsearch:\n %s", r.content)
return r.content
else:
raise requests.exceptions.HTTPError(r.content)
except Exception as e:
logger.exception("Unable to delete document from Elasticsearch\n %s", e)
def create_doc(url, index, doc_id, user, pwd, data, verify_ssl=False):
try:
r = requests.post(f"{url}{index}/_create/{doc_id}",
data=json.dumps(data),
auth=(user, pwd),
verify=verify_ssl,
headers={"Content-Type": "application/json"},
timeout=10
)
if r.ok:
logger.info("Created new document in Elasticsearch:\n %s", r.content)
return r.content
else:
raise requests.exceptions.HTTPError(r.content)
except Exception as e:
logger.exception("Unable to create document in Elasticsearch\n %s", e)
if __name__ == "__main__":
app.run(debug=True, port=5000, host='0.0.0.0')