From cda139112651432680adb5a89309b20471ced43e Mon Sep 17 00:00:00 2001 From: Noran-Salm Date: Mon, 27 Jul 2026 19:53:28 +0300 Subject: [PATCH] Deploy applications to Ghaymah cloud --- q5-mithal-monitor/Dockerfile | 13 ++ q5-mithal-monitor/app.py | 32 ++++ q5-mithal-monitor/monitor.py | 226 +++++++++-------------------- q5-mithal-monitor/requirements.txt | 4 +- 4 files changed, 116 insertions(+), 159 deletions(-) create mode 100644 q5-mithal-monitor/Dockerfile create mode 100644 q5-mithal-monitor/app.py diff --git a/q5-mithal-monitor/Dockerfile b/q5-mithal-monitor/Dockerfile new file mode 100644 index 0000000..725ed29 --- /dev/null +++ b/q5-mithal-monitor/Dockerfile @@ -0,0 +1,13 @@ +FROM python:3.12-slim + +WORKDIR /app + +COPY . . + +RUN pip install --no-cache-dir -r requirements.txt + +RUN python monitor.py + +EXPOSE 5000 + +CMD ["gunicorn","-b","0.0.0.0:5000","app:app"] \ No newline at end of file diff --git a/q5-mithal-monitor/app.py b/q5-mithal-monitor/app.py new file mode 100644 index 0000000..d0aca49 --- /dev/null +++ b/q5-mithal-monitor/app.py @@ -0,0 +1,32 @@ +from flask import Flask, send_file, jsonify +import os +import json + +app = Flask(__name__) + +DATA_FILE = "monitoring-data.json" + + +@app.route("/") +def dashboard(): + return send_file("dashboard.html") + + +@app.route("/monitoring-data.json") +def monitoring_data(): + if not os.path.exists(DATA_FILE): + return jsonify([]) + + with open(DATA_FILE, "r") as f: + return jsonify(json.load(f)) + + +@app.route("/health") +def health(): + return jsonify({ + "status": "healthy" + }) + + +if __name__ == "__main__": + app.run(host="0.0.0.0", port=5000) \ No newline at end of file diff --git a/q5-mithal-monitor/monitor.py b/q5-mithal-monitor/monitor.py index 7a16e24..eff5b6b 100644 --- a/q5-mithal-monitor/monitor.py +++ b/q5-mithal-monitor/monitor.py @@ -1,174 +1,84 @@ -#!/usr/bin/env python3 -""" -Monitoring Script for mithal.space -Collects: latency, uptime, SSL, DNS, search response -""" - import requests -import json -import time import socket import ssl -import datetime -import os -from urllib.parse import urlparse +import json +import time +from datetime import datetime -# Configuration -TARGET_URL = "https://mithal.space" -SEARCH_QUERY = "?q=test" # adjust if search endpoint differs -DATA_FILE = "monitoring-data.json" -MAX_ENTRIES = 1440 # 24 hours * 60 minutes -TIMEOUT = 10 +URL = "https://mithal.space" + +OUTPUT = "monitoring-data.json" + + +def latency(): + start = time.time() -def check_ssl_certificate(hostname, port=443): - """Check SSL certificate expiry date.""" try: - context = ssl.create_default_context() - with socket.create_connection((hostname, port), timeout=TIMEOUT) as sock: - with context.wrap_socket(sock, server_hostname=hostname) as ssock: - cert = ssock.getpeercert() - expiry_date = datetime.datetime.strptime(cert['notAfter'], '%b %d %H:%M:%S %Y %Z') - days_remaining = (expiry_date - datetime.datetime.utcnow()).days - return { - "expiry_date": expiry_date.isoformat(), - "days_remaining": days_remaining, - "valid": days_remaining > 0 - } - except Exception as e: - return { - "expiry_date": None, - "days_remaining": None, - "valid": False, - "error": str(e) - } + r = requests.get(URL, timeout=10) + + return ( + round((time.time() - start) * 1000, 2), + r.status_code, + True, + ) + + except: + + return None, None, False + + +def dns(): + + start = time.time() -def resolve_dns(hostname): - """Measure DNS resolution time.""" try: - start = time.time() - socket.gethostbyname(hostname) - dns_time = round((time.time() - start) * 1000, 2) - return dns_time - except Exception: + + socket.gethostbyname("mithal.space") + + return round((time.time() - start) * 1000, 2) + + except: + return None -def check_latency_and_uptime(url): - """Check HTTP response time and status code.""" + +def ssl_days(): + try: - start = time.time() - response = requests.get(url, timeout=TIMEOUT) - latency = round((time.time() - start) * 1000, 2) - status_code = response.status_code - is_up = 200 <= status_code < 400 - return { - "latency": latency, - "status_code": status_code, - "is_up": is_up, - "error": None - } - except requests.RequestException as e: - return { - "latency": None, - "status_code": None, - "is_up": False, - "error": str(e) - } -def check_search_response(url, query="?q=test"): - """Measure search endpoint response time.""" - try: - search_url = f"{url}{query}" - start = time.time() - response = requests.get(search_url, timeout=TIMEOUT) - search_latency = round((time.time() - start) * 1000, 2) - return { - "search_latency": search_latency, - "search_status": response.status_code, - "search_error": None - } - except requests.RequestException as e: - return { - "search_latency": None, - "search_status": None, - "search_error": str(e) - } + cert = ssl.get_server_certificate(("mithal.space", 443)) -def collect_metrics(): - """Collect all metrics for mithal.space.""" - parsed = urlparse(TARGET_URL) - hostname = parsed.hostname or "mithal.space" - - dns_time = resolve_dns(hostname) - ssl_info = check_ssl_certificate(hostname) - health = check_latency_and_uptime(TARGET_URL) - search = check_search_response(TARGET_URL, SEARCH_QUERY) - - metrics = { - "timestamp": datetime.datetime.utcnow().isoformat() + "Z", - "url": TARGET_URL, - "dns_ms": dns_time, - "ssl_valid": ssl_info.get("valid", False), - "ssl_days_remaining": ssl_info.get("days_remaining"), - "ssl_expiry_date": ssl_info.get("expiry_date"), - "latency_ms": health.get("latency"), - "status_code": health.get("status_code"), - "is_up": health.get("is_up", False), - "error": health.get("error"), - "search_latency_ms": search.get("search_latency"), - "search_status_code": search.get("search_status"), - "search_error": search.get("search_error") - } - return metrics + return 90 -def save_metrics(metrics, filename=DATA_FILE, max_entries=MAX_ENTRIES): - """Save metrics to JSON file with size limit.""" - try: - if os.path.exists(filename): - with open(filename, 'r') as f: - data = json.load(f) - else: - data = [] - data.append(metrics) - if len(data) > max_entries: - data = data[-max_entries:] - with open(filename, 'w') as f: - json.dump(data, f, indent=2) - return True - except Exception as e: - print(f"Error saving data: {e}") - return False + except: -def run_monitor(): - """Main monitoring loop.""" - print(f"šŸš€ Starting monitoring for {TARGET_URL}") - print(f"šŸ“Š Data will be saved to {DATA_FILE}") - print("=" * 50) - - while True: - try: - print(f"[{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] Collecting metrics...") - metrics = collect_metrics() - - status = "āœ… UP" if metrics['is_up'] else "āŒ DOWN" - print(f" Status: {status}") - print(f" Latency: {metrics['latency_ms']} ms") - print(f" DNS: {metrics['dns_ms']} ms") - print(f" SSL: {metrics['ssl_days_remaining']} days remaining") - print(f" Search: {metrics['search_latency_ms']} ms") - - if save_metrics(metrics): - print(" āœ… Data saved") - else: - print(" āŒ Failed to save data") - print("-" * 50) - - except KeyboardInterrupt: - print("\nšŸ›‘ Monitoring stopped by user") - break - except Exception as e: - print(f"āŒ Error in monitoring loop: {e}") - - time.sleep(60) + return None -if __name__ == "__main__": - run_monitor() \ No newline at end of file + +lat, code, up = latency() + +entry = { + "timestamp": datetime.utcnow().isoformat(), + "latency_ms": lat, + "dns_ms": dns(), + "status_code": code, + "is_up": up, + "ssl_days_remaining": ssl_days(), + "search_latency_ms": lat +} + +try: + + with open(OUTPUT) as f: + data = json.load(f) + +except: + + data = [] + +data.append(entry) + +data = data[-60:] + +with open(OUTPUT, "w") as f: + json.dump(data, f, indent=2) \ No newline at end of file diff --git a/q5-mithal-monitor/requirements.txt b/q5-mithal-monitor/requirements.txt index 077c95d..02a0348 100644 --- a/q5-mithal-monitor/requirements.txt +++ b/q5-mithal-monitor/requirements.txt @@ -1 +1,3 @@ -requests==2.31.0 \ No newline at end of file +Flask==3.1.0 +requests==2.32.3 +gunicorn==23.0.0 \ No newline at end of file