diff --git a/WIS2-AlertBridge/README.md b/WIS2-AlertBridge/README.md new file mode 100644 index 0000000..9c19aec --- /dev/null +++ b/WIS2-AlertBridge/README.md @@ -0,0 +1,27 @@ +# 🚨 WIS2 Alert → Jira Bridge + +A **Flask-based service** that receives alerts (via Prometheus/Alertmanager webhook) and automatically creates **Jira tickets**, with assignment, watchers, and rotation logic. + +## ✨ Features + +- 📡 **Webhook endpoint** (`/webhook`) to receive Prometheus alerts. +- 📝 Automatic creation of **Jira incidents** (`issuetype: Incident`). +- 👥 Dynamic ticket assignment through: + - **CSV mapping ISO2 → accountId** (`config/assignees.csv`) + - **Bi-weekly rotation** of watchers (15-day cycle). +- 💾 **Redis persistence** to prevent duplicate ticket creation. +- ✅ Checks ticket status (open/closed) before creating new ones. + +## 📊 Workflow + +Prometheus/Alertmanager sends an alert to /webhook. + +The service checks Redis for an existing ticket. + +If none → creates a new Jira ticket with assignee & watcher. + +If exists but ticket is closed → creates a new one. + +Redis is updated with the new ticket reference. + + diff --git a/WIS2-AlertBridge/app.py b/WIS2-AlertBridge/app.py new file mode 100644 index 0000000..bf65dd9 --- /dev/null +++ b/WIS2-AlertBridge/app.py @@ -0,0 +1,75 @@ +from flask import Flask, request, jsonify +import configparser +import logging + +from utils.logger import setup_logger +from services.redis_service import get_redis_client +from services.assignee_service import load_assignees_from_csv, get_current_assignee, get_assignee_from_centre +from services.jira_service import create_jira_ticket, ticket_is_closed +from services.mqtt_service import publish_mqtt_notification + +# Flask app +app = Flask(__name__) +logger = setup_logger() + +# Config +config = configparser.ConfigParser() +config.read('config/access.ini') + +JIRA_API_URL = config['JIRA']['url'].rstrip('/') +JIRA_AUTH_TOKEN = config['JIRA']['token'] + +MQTT_BROKER = config['MQTT']['broker'] +MQTT_PORT = int(config['MQTT']['port']) +MQTT_USERNAME = config['MQTT']['username'] +MQTT_PASSWORD = config['MQTT']['password'] + +# Redis +redis_client = get_redis_client() + +# Load CSV +load_assignees_from_csv() + +@app.route('/webhook', methods=['POST']) +def webhook(): + data = request.json + try: + for alert in data.get('alerts', []): + labels = alert.get('labels', {}) + alertname = labels.get('alertname') + severity = labels.get('severity') + status = alert.get('status') + starts_at = alert.get('startsAt') + centre_id = labels.get('centre_id') or labels.get('report_by') or "unknown" + summary = f"{centre_id} : {alert.get('annotations', {}).get('summary', '')}" + alert_key = f"{alertname}:{centre_id}" + + if not all([alertname, severity, starts_at, status]): + logger.error(f"Champs manquants : {alert}") + continue + + if severity == "critical": + description = f"{summary}\n\nAlert triggered at: {starts_at}\n\nReported By: ma-marocmeteo-global-monitor" + ticket_id = redis_client.get(alert_key) + if ticket_id: + ticket_id = ticket_id.decode() + if ticket_is_closed(ticket_id, JIRA_API_URL, JIRA_AUTH_TOKEN): + new_ticket = create_jira_ticket(summary, description, centre_id, JIRA_API_URL, JIRA_AUTH_TOKEN, get_assignee_from_centre(centre_id), get_current_assignee()) + if new_ticket: + redis_client.set(alert_key, new_ticket) + else: + logger.info(f"Ticket already opened : {ticket_id}") + else: + new_ticket = create_jira_ticket(summary, description, centre_id, JIRA_API_URL, JIRA_AUTH_TOKEN, get_assignee_from_centre(centre_id), get_current_assignee()) + if new_ticket: + redis_client.set(alert_key, new_ticket) + # else: + # publish_mqtt_notification(alertname, severity, summary, starts_at, MQTT_BROKER, MQTT_PORT, MQTT_USERNAME, MQTT_PASSWORD) + + return jsonify({"status": "success"}) + except Exception as e: + logger.error(f"Erreur webhook: {e}") + return jsonify({'status': 'error', 'message': str(e)}), 500 + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=5002) diff --git a/WIS2-AlertBridge/config/assignees.csv b/WIS2-AlertBridge/config/assignees.csv new file mode 100644 index 0000000..1507ff3 --- /dev/null +++ b/WIS2-AlertBridge/config/assignees.csv @@ -0,0 +1,333 @@ +accountId;gisc;iso2 +bd0458b6-8093-47a2-b9a5-e9a155cd3967;Tehran;af +5ba3e055-e2c8-4d74-8b59-99cfae6f2107;Toulouse;dz +2eae5820-2244-473b-a51b-61234b2dd433;Pretoria;ao +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;ag +8a76f9e8-59b6-4a48-9a94-83db603d20ab;Brasilia;ar +e93af777-469f-4e88-8716-32135b00db68;Moscow;am +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;aw +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;au +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;au +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;au +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;at +e93af777-469f-4e88-8716-32135b00db68;Moscow;az +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;bs +0d8650c1-b4ff-46cc-b691-6521fb17b3f1;Jeddah;bh +712bbfbb-d8b7-4e3a-b36d-17e077f92783;New Delhi;bd +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;bb +e93af777-469f-4e88-8716-32135b00db68;Moscow;by +5ba3e055-e2c8-4d74-8b59-99cfae6f2107;Toulouse;be +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;bz +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;bj +712bbfbb-d8b7-4e3a-b36d-17e077f92783;New Delhi;bt +8a76f9e8-59b6-4a48-9a94-83db603d20ab;Brasilia;bo +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;ba +2eae5820-2244-473b-a51b-61234b2dd433;Pretoria;bw +8a76f9e8-59b6-4a48-9a94-83db603d20ab;Brasilia;br +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;ai +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;vg +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;ky +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;ms +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;tc +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;bn +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;bg +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;bf +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;bi +6bcd27b6-6403-462f-87a0-4fa64cbcad63;Tokyo;kh +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;cm +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;ca +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;cv +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;cf +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;td +8a76f9e8-59b6-4a48-9a94-83db603d20ab;Brasilia;cl +3a567fa5-5df1-4264-a1d8-dca516c577f5;Beijing;cn +8a76f9e8-59b6-4a48-9a94-83db603d20ab;Brasilia;co +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;km +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;cg +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;ck +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;cr +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;ci +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;hr +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;cu +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;cw +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;sx +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;cy +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;cz +3a567fa5-5df1-4264-a1d8-dca516c577f5;Beijing;kp +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;cd +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;dk +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;dj +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;dm +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;do +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;do +8a76f9e8-59b6-4a48-9a94-83db603d20ab;Brasilia;ec +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;eg +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;sv +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;gq +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;er +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;ee +2eae5820-2244-473b-a51b-61234b2dd433;Pretoria;sz +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;et +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;fj +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;fi +5ba3e055-e2c8-4d74-8b59-99cfae6f2107;Toulouse;fr +5ba3e055-e2c8-4d74-8b59-99cfae6f2107;Toulouse;gf +5ba3e055-e2c8-4d74-8b59-99cfae6f2107;Toulouse;gp +5ba3e055-e2c8-4d74-8b59-99cfae6f2107;Toulouse;mf +5ba3e055-e2c8-4d74-8b59-99cfae6f2107;Toulouse;bl +5ba3e055-e2c8-4d74-8b59-99cfae6f2107;Toulouse;tf +5ba3e055-e2c8-4d74-8b59-99cfae6f2107;Toulouse;re +5ba3e055-e2c8-4d74-8b59-99cfae6f2107;Toulouse;mq +5ba3e055-e2c8-4d74-8b59-99cfae6f2107;Toulouse;pm +5ba3e055-e2c8-4d74-8b59-99cfae6f2107;Toulouse;fr +5ba3e055-e2c8-4d74-8b59-99cfae6f2107;Toulouse;wf +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;pf +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;ga +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;gm +e93af777-469f-4e88-8716-32135b00db68;Moscow;ge +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;de +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;gh +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;gr +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;gt +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;gn +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;gw +8a76f9e8-59b6-4a48-9a94-83db603d20ab;Brasilia;gy +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;ht +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;hn +3a567fa5-5df1-4264-a1d8-dca516c577f5;Beijing;hk +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;hu +40d4f6ba-9751-4bc6-82f6-5dc79673de77;Exeter;is +712bbfbb-d8b7-4e3a-b36d-17e077f92783;New Delhi;in +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;id +bd0458b6-8093-47a2-b9a5-e9a155cd3967;Tehran;ir +bd0458b6-8093-47a2-b9a5-e9a155cd3967;Tehran;iq +40d4f6ba-9751-4bc6-82f6-5dc79673de77;Exeter;ie +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;il +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;it +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;jm +6bcd27b6-6403-462f-87a0-4fa64cbcad63;Tokyo;jp +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;jo +e93af777-469f-4e88-8716-32135b00db68;Moscow;kz +e93af777-469f-4e88-8716-32135b00db68;Moscow;kz +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;ke +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;ki +0d8650c1-b4ff-46cc-b691-6521fb17b3f1;Jeddah;kw +e93af777-469f-4e88-8716-32135b00db68;Moscow;kg +6bcd27b6-6403-462f-87a0-4fa64cbcad63;Tokyo;la +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;lv +2eae5820-2244-473b-a51b-61234b2dd433;Pretoria;ls +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;lr +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;ly +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;lt +5ba3e055-e2c8-4d74-8b59-99cfae6f2107;Toulouse;lu +3a567fa5-5df1-4264-a1d8-dca516c577f5;Beijing;mo +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;mg +2eae5820-2244-473b-a51b-61234b2dd433;Pretoria;mw +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;my +712bbfbb-d8b7-4e3a-b36d-17e077f92783;New Delhi;mv +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;ml +40d4f6ba-9751-4bc6-82f6-5dc79673de77;Exeter;mt +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;mr +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;mu +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;mx +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;fm +5ba3e055-e2c8-4d74-8b59-99cfae6f2107;Toulouse;mc +3a567fa5-5df1-4264-a1d8-dca516c577f5;Beijing;mn +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;me +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;ma +2eae5820-2244-473b-a51b-61234b2dd433;Pretoria;mz +6bcd27b6-6403-462f-87a0-4fa64cbcad63;Tokyo;mm +2eae5820-2244-473b-a51b-61234b2dd433;Pretoria;na +3a567fa5-5df1-4264-a1d8-dca516c577f5;Beijing;np +40d4f6ba-9751-4bc6-82f6-5dc79673de77;Exeter;nl +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;nc +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;nz +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;nz +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;ni +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;ne +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;ng +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;nu +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;mk +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;no +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;no +0d8650c1-b4ff-46cc-b691-6521fb17b3f1;Jeddah;om +3a567fa5-5df1-4264-a1d8-dca516c577f5;Beijing;pk +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;pa +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;pg +8a76f9e8-59b6-4a48-9a94-83db603d20ab;Brasilia;py +8a76f9e8-59b6-4a48-9a94-83db603d20ab;Brasilia;pe +6bcd27b6-6403-462f-87a0-4fa64cbcad63;Tokyo;ph +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;pl +5ba3e055-e2c8-4d74-8b59-99cfae6f2107;Toulouse;pt +5ba3e055-e2c8-4d74-8b59-99cfae6f2107;Toulouse;pt +0d8650c1-b4ff-46cc-b691-6521fb17b3f1;Jeddah;qa +0d8650c1-b4ff-46cc-b691-6521fb17b3f1;Jeddah;qa +3bd19e33-804e-4acc-bcf0-966d4cad68f6;Seoul;kr +e93af777-469f-4e88-8716-32135b00db68;Moscow;md +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;ro +e93af777-469f-4e88-8716-32135b00db68;Moscow;ru +e93af777-469f-4e88-8716-32135b00db68;Moscow;ru +e93af777-469f-4e88-8716-32135b00db68;Moscow;ru +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;rw +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;kn +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;lc +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;ws +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;st +0d8650c1-b4ff-46cc-b691-6521fb17b3f1;Jeddah;sa +0d8650c1-b4ff-46cc-b691-6521fb17b3f1;Jeddah;sa +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;sn +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;rs +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;sc +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;sl +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;sg +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;sk +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;si +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;sb +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;so +2eae5820-2244-473b-a51b-61234b2dd433;Pretoria;za +5ba3e055-e2c8-4d74-8b59-99cfae6f2107;Toulouse;es +5ba3e055-e2c8-4d74-8b59-99cfae6f2107;Toulouse;es +712bbfbb-d8b7-4e3a-b36d-17e077f92783;New Delhi;lk +2eae5820-2244-473b-a51b-61234b2dd433;Pretoria;sd +8a76f9e8-59b6-4a48-9a94-83db603d20ab;Brasilia;sr +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;se +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;ch +bd0458b6-8093-47a2-b9a5-e9a155cd3967;Tehran;sy +e93af777-469f-4e88-8716-32135b00db68;Moscow;tj +6bcd27b6-6403-462f-87a0-4fa64cbcad63;Tokyo;th +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;tl +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;tg +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;to +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;tt +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;tn +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;tr +e93af777-469f-4e88-8716-32135b00db68;Moscow;tm +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;tv +6ee7e53f-4811-4ea0-830a-4ec2847a1017;Casablanca;ug +e93af777-469f-4e88-8716-32135b00db68;Moscow;ua +0d8650c1-b4ff-46cc-b691-6521fb17b3f1;Jeddah;ae +40d4f6ba-9751-4bc6-82f6-5dc79673de77;Exeter;uk +40d4f6ba-9751-4bc6-82f6-5dc79673de77;Exeter;bm +40d4f6ba-9751-4bc6-82f6-5dc79673de77;Exeter;uk +40d4f6ba-9751-4bc6-82f6-5dc79673de77;Exeter;gi +40d4f6ba-9751-4bc6-82f6-5dc79673de77;Exeter;pn +40d4f6ba-9751-4bc6-82f6-5dc79673de77;Exeter;sh +2eae5820-2244-473b-a51b-61234b2dd433;Pretoria;tz +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;us +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;ki +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;gu +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;us +8a76f9e8-59b6-4a48-9a94-83db603d20ab;Brasilia;pr +e93af777-469f-4e88-8716-32135b00db68;Moscow;uz +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;vu +8a76f9e8-59b6-4a48-9a94-83db603d20ab;Brasilia;ve +6bcd27b6-6403-462f-87a0-4fa64cbcad63;Tokyo;vn +0d8650c1-b4ff-46cc-b691-6521fb17b3f1;Jeddah;ye +2eae5820-2244-473b-a51b-61234b2dd433;Pretoria;zm +2eae5820-2244-473b-a51b-61234b2dd433;Pretoria;zw +8a76f9e8-59b6-4a48-9a94-83db603d20ab;Brasilia;ar +8a76f9e8-59b6-4a48-9a94-83db603d20ab;Brasilia;ar +8a76f9e8-59b6-4a48-9a94-83db603d20ab;Brasilia;ar +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;au +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;au +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;au +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;au +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;au +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;at +8a76f9e8-59b6-4a48-9a94-83db603d20ab;Brasilia;br +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;bg +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;ca +3a567fa5-5df1-4264-a1d8-dca516c577f5;Beijing;cn +3a567fa5-5df1-4264-a1d8-dca516c577f5;Beijing;cn +3a567fa5-5df1-4264-a1d8-dca516c577f5;Beijing;cn +3a567fa5-5df1-4264-a1d8-dca516c577f5;Beijing;cn +3a567fa5-5df1-4264-a1d8-dca516c577f5;Beijing;cn +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;hr +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;cz +40d4f6ba-9751-4bc6-82f6-5dc79673de77;Exeter;int +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;int +5ba3e055-e2c8-4d74-8b59-99cfae6f2107;Toulouse;fr +5ba3e055-e2c8-4d74-8b59-99cfae6f2107;Toulouse;fr +5ba3e055-e2c8-4d74-8b59-99cfae6f2107;Toulouse;fr +5ba3e055-e2c8-4d74-8b59-99cfae6f2107;Toulouse;fr +5ba3e055-e2c8-4d74-8b59-99cfae6f2107;Toulouse;fr +5ba3e055-e2c8-4d74-8b59-99cfae6f2107;Toulouse;fr +5ba3e055-e2c8-4d74-8b59-99cfae6f2107;Toulouse;fr +5ba3e055-e2c8-4d74-8b59-99cfae6f2107;Toulouse;fr +5ba3e055-e2c8-4d74-8b59-99cfae6f2107;Toulouse;fr +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;de +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;de +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;de +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;de +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;de +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;de +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;de +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;de +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;de +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;de +3a567fa5-5df1-4264-a1d8-dca516c577f5;Beijing;hk +712bbfbb-d8b7-4e3a-b36d-17e077f92783;New Delhi;in +712bbfbb-d8b7-4e3a-b36d-17e077f92783;New Delhi;in +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;id +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;id +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;id +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;id +bd0458b6-8093-47a2-b9a5-e9a155cd3967;Tehran;ir +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;it +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;it +6bcd27b6-6403-462f-87a0-4fa64cbcad63;Tokyo;jp +6bcd27b6-6403-462f-87a0-4fa64cbcad63;Tokyo;jp +6bcd27b6-6403-462f-87a0-4fa64cbcad63;Tokyo;jp +6bcd27b6-6403-462f-87a0-4fa64cbcad63;Tokyo;jp +6bcd27b6-6403-462f-87a0-4fa64cbcad63;Tokyo;jp +6bcd27b6-6403-462f-87a0-4fa64cbcad63;Tokyo;jp +6bcd27b6-6403-462f-87a0-4fa64cbcad63;Tokyo;jp +6bcd27b6-6403-462f-87a0-4fa64cbcad63;Tokyo;jp +6bcd27b6-6403-462f-87a0-4fa64cbcad63;Tokyo;jp +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;ke +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;ke +40d4f6ba-9751-4bc6-82f6-5dc79673de77;Exeter;nl +40d4f6ba-9751-4bc6-82f6-5dc79673de77;Exeter;nl +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;nl +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;nl +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;nl +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;no +0d8650c1-b4ff-46cc-b691-6521fb17b3f1;Jeddah;qa +3bd19e33-804e-4acc-bcf0-966d4cad68f6;Seoul;kr +3bd19e33-804e-4acc-bcf0-966d4cad68f6;Seoul;kr +3bd19e33-804e-4acc-bcf0-966d4cad68f6;Seoul;kr +e93af777-469f-4e88-8716-32135b00db68;Moscow;ru +e93af777-469f-4e88-8716-32135b00db68;Moscow;ru +e93af777-469f-4e88-8716-32135b00db68;Moscow;ru +e93af777-469f-4e88-8716-32135b00db68;Moscow;ru +e93af777-469f-4e88-8716-32135b00db68;Moscow;ru +e93af777-469f-4e88-8716-32135b00db68;Moscow;ru +e93af777-469f-4e88-8716-32135b00db68;Moscow;ru +0d8650c1-b4ff-46cc-b691-6521fb17b3f1;Jeddah;sa +0d8650c1-b4ff-46cc-b691-6521fb17b3f1;Jeddah;sa +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;rs +36d3f1db-5b27-40ab-a94b-867fd63035c0;Melbourne;sg +2eae5820-2244-473b-a51b-61234b2dd433;Pretoria;za +5ba3e055-e2c8-4d74-8b59-99cfae6f2107;Toulouse;es +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;se +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;se +6bcd27b6-6403-462f-87a0-4fa64cbcad63;Tokyo;th +af21d0dc-b0a6-4f85-866e-b9a561003903;Offenbach;tr +40d4f6ba-9751-4bc6-82f6-5dc79673de77;Exeter;uk +40d4f6ba-9751-4bc6-82f6-5dc79673de77;Exeter;uk +40d4f6ba-9751-4bc6-82f6-5dc79673de77;Exeter;uk +40d4f6ba-9751-4bc6-82f6-5dc79673de77;Exeter;uk +40d4f6ba-9751-4bc6-82f6-5dc79673de77;Exeter;uk +40d4f6ba-9751-4bc6-82f6-5dc79673de77;Exeter;uk +40d4f6ba-9751-4bc6-82f6-5dc79673de77;Exeter;uk +40d4f6ba-9751-4bc6-82f6-5dc79673de77;Exeter;uk +40d4f6ba-9751-4bc6-82f6-5dc79673de77;Exeter;uk +40d4f6ba-9751-4bc6-82f6-5dc79673de77;Exeter;uk +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;us +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;us +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;us +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;us +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;us +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;us +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;us +3edcada0-7ebc-4476-bbfa-d5aedad2996d;Washington;us \ No newline at end of file diff --git a/WIS2-AlertBridge/requirements.txt b/WIS2-AlertBridge/requirements.txt new file mode 100644 index 0000000..501d693 --- /dev/null +++ b/WIS2-AlertBridge/requirements.txt @@ -0,0 +1,4 @@ +Flask==2.3.4 +requests==2.31.0 +redis==5.3.7 +paho-mqtt==1.6.1 diff --git a/WIS2-AlertBridge/services/assignee_service.py b/WIS2-AlertBridge/services/assignee_service.py new file mode 100644 index 0000000..3b3d910 --- /dev/null +++ b/WIS2-AlertBridge/services/assignee_service.py @@ -0,0 +1,51 @@ +import csv +import datetime +import logging + +ASSIGNEES_BY_ISO2 = {} +ASSIGNEES_ROTATION = [ + {"accountId": "5ba3e055-e2c8-4d74-8b59-99cfae6f2107", "email": "transmet@meteo.fr"}, # Toulouse + {"accountId": "3a567fa5-5df1-4264-a1d8-dca516c577f5", "email": "gisc-beijing-ims@cma.gov.cn"}, # Beijing + {"accountId": "6ee7e53f-4811-4ea0-830a-4ec2847a1017", "email": "gisc-casablanca@marocmeteo.ma"}, # Casablanca + {"accountId": "2eae5820-2244-473b-a51b-61234b2dd433", "email": "gisc-support@weathersa.co.za"}, # Pretoria + {"accountId": "6bcd27b6-6403-462f-87a0-4fa64cbcad63", "email": "wis-jma@met.kishou.go.jp"}, # Tokyo + {"accountId": "40d4f6ba-9751-4bc6-82f6-5dc79673de77", "email": "nim@metoffice.gov.uk"}, # Exeter + {"accountId": "3bd19e33-804e-4acc-bcf0-966d4cad68f6", "email": "gisc_op@korea.kr"}, # Seoul + {"accountId": "36d3f1db-5b27-40ab-a94b-867fd63035c0", "email": "srcs_all@bom.gov.au"}, # Melbourne + {"accountId": "af21d0dc-b0a6-4f85-866e-b9a561003903", "email": "met.servicedesk@dwd.de"}, # Offenbach + {"accountId": "8a76f9e8-59b6-4a48-9a94-83db603d20ab", "email": "wis2.oper@inmet.gov.br"}, # Brasilia + {"accountId": "712bbfbb-d8b7-4e3a-b36d-17e077f92783", "email": "gisc.delhi@imd.gov.in"}, # New Delhi + {"accountId": "3edcada0-7ebc-4476-bbfa-d5aedad2996d", "email": "nws.gisc.washington.support@noaa.gov"}, # Washington + {"accountId": "0d8650c1-b4ff-46cc-b691-6521fb17b3f1", "email": "wisop@ncm.gov.sa"}, # Jeddah + {"accountId": "e93af777-469f-4e88-8716-32135b00db68", "email": "wisop@avia.mecom.ru"}, # Moscow + {"accountId": "bd0458b6-8093-47a2-b9a5-e9a155cd3967", "email": "wis2operat@irimo.ir"}, # Tehran +] + +def load_assignees_from_csv(csv_path="config/assignees.csv"): + global ASSIGNEES_BY_ISO2 + try: + with open(csv_path, newline='', encoding='utf-8') as csvfile: + reader = csv.DictReader(csvfile, delimiter=';') + for row in reader: + iso2 = row['iso2'].strip().lower() + ASSIGNEES_BY_ISO2[iso2] = row['accountId'].strip() + except Exception as e: + logging.error(f"Erreur chargement CSV : {e}") + +def get_current_assignee(): + base_date = datetime.date(2025, 4, 1) + today = datetime.date.today() + days_diff = (today - base_date).days + if days_diff < 0: + logging.warning("Date before rotation start") + return None + index = (days_diff // 15) % len(ASSIGNEES_ROTATION) + return ASSIGNEES_ROTATION[index] + +def get_assignee_from_centre(centre_id): + if not centre_id or len(centre_id) < 2: + return None + if centre_id.lower() == "ca-eccc-msc-global-discovery-catalogue": + return "ba802b36-b516-46f1-8277-30fa3a5eb8b3" + iso2 = centre_id[:2].lower() + return ASSIGNEES_BY_ISO2.get(iso2) diff --git a/WIS2-AlertBridge/services/jira_service.py b/WIS2-AlertBridge/services/jira_service.py new file mode 100644 index 0000000..e0f791c --- /dev/null +++ b/WIS2-AlertBridge/services/jira_service.py @@ -0,0 +1,58 @@ +import requests +import logging + +def ticket_is_closed(issue_key, jira_url, jira_token): + try: + url = f"{jira_url}/{issue_key}" + headers = {"Authorization": f"Bearer {jira_token}", "Content-Type": "application/json"} + response = requests.get(url, headers=headers, verify=False) + if response.status_code != 200: + logging.warning(f"Ticket verification {issue_key} failed (HTTP {response.status_code})") + return False + statut = response.json()['fields']['status']['name'].lower() + return statut in ['done', 'closed', 'resolved'] + except Exception as e: + logging.error(f"Error: ticket_is_closed({issue_key}): {e}") + return False + +def add_watcher_to_ticket(issue_key, watcher_id, jira_url, jira_token): + url = f"{jira_url}/{issue_key}/watchers" + headers = {"Authorization": f"Bearer {jira_token}", "Content-Type": "application/json"} + try: + response = requests.post(url, headers=headers, json=watcher_id, verify=False) + if response.status_code == 204: + logging.info(f"Watcher {watcher_id} added to ticket {issue_key}") + return True + else: + logging.warning(f"Failed to add watcher: {response.status_code} {response.text}") + return False + except Exception as e: + logging.error(f"Error add_watcher_to_ticket: {e}") + return False + +def create_jira_ticket(summary, description, centre_id, jira_url, jira_token, assignee, watcher): + payload = { + "fields": { + "project": {"key": "TESTWIS"}, + "summary": summary, + "description": description, + "issuetype": {"name": "Incident"} + } + } + if assignee: + payload["fields"]["assignee"] = {"name": assignee} + headers = {"Authorization": f"Bearer {jira_token}", "Content-Type": "application/json"} + + try: + response = requests.post(jira_url, headers=headers, json=payload, verify=False) + if response.status_code == 201: + ticket_key = response.json()['key'] + logging.info(f"Jira ticket created: {ticket_key} (Assigned to {assignee})") + add_watcher_to_ticket(ticket_key, watcher["accountId"], jira_url, jira_token) + return ticket_key + else: + logging.error(f"Failed to create Jira ticket: {response.status_code} {response.text}") + return None + except Exception as e: + logging.error(f"Error create_jira_ticket: {e}") + return None diff --git a/WIS2-AlertBridge/services/mqtt_service.py b/WIS2-AlertBridge/services/mqtt_service.py new file mode 100644 index 0000000..37a3f5f --- /dev/null +++ b/WIS2-AlertBridge/services/mqtt_service.py @@ -0,0 +1,31 @@ +import json +import uuid +import logging +import paho.mqtt.publish as publish + +def publish_mqtt_notification(alertname, severity, summary, starts_at, broker, port, username, password): + try: + topic = "monitor/a/wis2/ma-marocmeteo-global-monitor" + payload = { + "specversion": "1.0", + "type": "int.wmo.codes.performance", + "source": "ma-marocmeteo-global-monitor", + "subject": alertname, + "id": str(uuid.uuid4()), + "time": starts_at, + "datacontenttype": "application/json", + "dataschema": "int.wmo.codes.event.data.v1", + "data": {"level": severity, "text": summary} + } + publish.single( + topic, + payload=json.dumps(payload), + hostname=broker, + port=port, + auth={"username": username, "password": password} + ) + logging.info(f"MQTT notification published") + return True + except Exception as e: + logging.error(f"MQTT send error: {e}") + return False diff --git a/WIS2-AlertBridge/services/redis_service.py b/WIS2-AlertBridge/services/redis_service.py new file mode 100644 index 0000000..8f3a54a --- /dev/null +++ b/WIS2-AlertBridge/services/redis_service.py @@ -0,0 +1,4 @@ +import redis + +def get_redis_client(): + return redis.Redis(host='localhost', port=6379, db=0) \ No newline at end of file diff --git a/WIS2-AlertBridge/utils/logger.py b/WIS2-AlertBridge/utils/logger.py new file mode 100644 index 0000000..13d1f04 --- /dev/null +++ b/WIS2-AlertBridge/utils/logger.py @@ -0,0 +1,8 @@ +import logging + +def setup_logger(): + logging.basicConfig( + level=logging.INFO, + format='[%(asctime)s] %(levelname)s: %(message)s' + ) + return logging.getLogger(__name__) \ No newline at end of file