commit
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
from flask import Flask, render_template, request, jsonify, Response
|
||||
from flask import Flask, render_template, request, jsonify, Response, stream_with_context
|
||||
import core_functions
|
||||
import auth_utils
|
||||
import logging
|
||||
import os
|
||||
import json
|
||||
import urllib3; urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
import requests
|
||||
from requests.exceptions import HTTPError, RequestException
|
||||
@@ -17,20 +18,60 @@ from services.remote_admin import (
|
||||
)
|
||||
from services.yaml_writer import STAGING, render_to_file
|
||||
from pathlib import Path
|
||||
from services import vpn_runtime
|
||||
from services.log_stream import JournalctlStream, LogTarget
|
||||
|
||||
API_USER = os.getenv("CORE_API_USER", "admin")
|
||||
API_PASS = os.getenv("CORE_API_PASS", "Super4dmin!") # consider moving to env/secret
|
||||
DASHBOARD_URLS = {
|
||||
"Triton": "https://dashboard.arubaedge-triton.athonetusa.com",
|
||||
"Star": "https://dashboard.arubaedge-star.athonetusa.com",
|
||||
"Bluebonnet": "https://dashboard.arubaedge-bluebonnet.athonetusa.com",
|
||||
"Lonestar": "https://dashboard.arubaedge-lonestar.athonetusa.com",
|
||||
"Production": "https://dashboard.us-east-2.p5g.athonet.cloud",
|
||||
"Test (future)": "https://your-test-dashboard-url.com"
|
||||
}
|
||||
|
||||
def _load_dashboard_urls() -> dict:
|
||||
default = {
|
||||
"Production": "https://dashboard.private5g.networking.hpe.com",
|
||||
"Test": "https://your-test-dashboard-url.com",
|
||||
}
|
||||
raw = os.getenv("DASHBOARD_ENVIRONMENTS")
|
||||
if not raw:
|
||||
return default
|
||||
try:
|
||||
parsed = json.loads(raw)
|
||||
cleaned = {str(k): str(v) for k, v in parsed.items() if str(v).strip()}
|
||||
return cleaned or default
|
||||
except json.JSONDecodeError as exc:
|
||||
logging.warning("Failed to parse DASHBOARD_ENVIRONMENTS (%s); falling back to defaults", exc)
|
||||
return default
|
||||
|
||||
DASHBOARD_URLS = _load_dashboard_urls()
|
||||
|
||||
def _resolve_dashboard_url(name: str) -> str:
|
||||
if not name:
|
||||
raise ValueError("Dashboard selection is required")
|
||||
url = DASHBOARD_URLS.get(name)
|
||||
if not url:
|
||||
raise ValueError(f"Unknown dashboard '{name}'")
|
||||
return url
|
||||
|
||||
def _get_available_vpn_configs() -> list:
|
||||
try:
|
||||
available = vpn_runtime.list_available_vpns()
|
||||
except Exception:
|
||||
available = []
|
||||
configured = getattr(core_functions, "VPN_CONFIG_NAMES", [])
|
||||
if not available:
|
||||
return configured
|
||||
ordered = [name for name in configured if name in available]
|
||||
extras = [name for name in available if name not in ordered]
|
||||
return ordered + extras
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
app = Flask(__name__)
|
||||
app.secret_key = os.getenv("FLASK_SECRET_KEY", "dev-secret")
|
||||
|
||||
@app.context_processor
|
||||
def inject_global_options():
|
||||
return {
|
||||
"dashboard_names": list(DASHBOARD_URLS.keys()),
|
||||
"available_vpn_configs": _get_available_vpn_configs(),
|
||||
}
|
||||
|
||||
def _format_ipv6(host: str) -> str:
|
||||
return f"[{host}]" if ":" in host and not host.startswith("[") else host
|
||||
@@ -393,6 +434,23 @@ def hnk_page():
|
||||
def network_clients_page():
|
||||
return render_template("pages/network_clients.html", active_page='network_clients')
|
||||
|
||||
@app.post("/api/supis/list")
|
||||
def api_list_supis():
|
||||
data = request.get_json(silent=True) or {}
|
||||
host = (data.get("host") or "").strip()
|
||||
try:
|
||||
limit = int(data.get("limit", 500))
|
||||
except (TypeError, ValueError):
|
||||
return jsonify({"error": "limit must be an integer"}), 400
|
||||
if not host:
|
||||
return jsonify({"error": "Host IP is missing"}), 400
|
||||
try:
|
||||
supis = core_functions.list_network_clients(host, limit=limit)
|
||||
return jsonify({"count": len(supis), "supis": supis})
|
||||
except Exception as e:
|
||||
app.logger.error(f"Error listing SUPIs for host {host}: {e}", exc_info=True)
|
||||
return jsonify({"error": str(e)}), 502
|
||||
|
||||
@app.route("/system-browser")
|
||||
def system_browser_page():
|
||||
return render_template("pages/system_browser.html", active_page='system_browser')
|
||||
@@ -457,7 +515,10 @@ def gaf_desk_page():
|
||||
def api_list_m2000():
|
||||
data = request.json
|
||||
dashboard_name = data.get('dashboard')
|
||||
base_url = DASHBOARD_URLS.get(dashboard_name)
|
||||
try:
|
||||
base_url = _resolve_dashboard_url(dashboard_name)
|
||||
except ValueError as exc:
|
||||
return jsonify({"error": str(exc)}), 400
|
||||
try:
|
||||
token, session = auth_utils.get_vpn_dashboard_token(base_url)
|
||||
devices = core_functions.list_m2000_vpns(base_url, token, session)
|
||||
@@ -470,7 +531,10 @@ def api_list_m2000():
|
||||
def api_get_network_config():
|
||||
data = request.json
|
||||
dashboard_name = data.get('dashboard')
|
||||
base_url = DASHBOARD_URLS.get(dashboard_name)
|
||||
try:
|
||||
base_url = _resolve_dashboard_url(dashboard_name)
|
||||
except ValueError as exc:
|
||||
return jsonify({"error": str(exc)}), 400
|
||||
try:
|
||||
token, session = auth_utils.get_vpn_dashboard_token(base_url)
|
||||
config_data = core_functions.get_full_network_config(base_url, token, session)
|
||||
@@ -483,7 +547,10 @@ def api_get_network_config():
|
||||
def api_list_tenants():
|
||||
data = request.json
|
||||
dashboard_name = data.get('dashboard')
|
||||
base_url = DASHBOARD_URLS.get(dashboard_name)
|
||||
try:
|
||||
base_url = _resolve_dashboard_url(dashboard_name)
|
||||
except ValueError as exc:
|
||||
return jsonify({"error": str(exc)}), 400
|
||||
try:
|
||||
token, session = auth_utils.get_vpn_dashboard_token(base_url)
|
||||
tenants = core_functions.list_tenants(base_url, token, session)
|
||||
@@ -497,7 +564,10 @@ def api_list_plmns():
|
||||
data = request.json
|
||||
dashboard_name = data.get('dashboard')
|
||||
tenant_id = data.get('tenant_id')
|
||||
base_url = DASHBOARD_URLS.get(dashboard_name)
|
||||
try:
|
||||
base_url = _resolve_dashboard_url(dashboard_name)
|
||||
except ValueError as exc:
|
||||
return jsonify({"error": str(exc)}), 400
|
||||
try:
|
||||
token, session = auth_utils.get_vpn_dashboard_token(base_url)
|
||||
plmns = core_functions.list_plmns(base_url, token, session, tenant_id)
|
||||
@@ -563,7 +633,10 @@ def api_list_plmn_hnks():
|
||||
dashboard_name = data.get('dashboard')
|
||||
tenant_id = data.get('tenant_id')
|
||||
plmn_id = data.get('plmn_id')
|
||||
base_url = DASHBOARD_URLS.get(dashboard_name)
|
||||
try:
|
||||
base_url = _resolve_dashboard_url(dashboard_name)
|
||||
except ValueError as exc:
|
||||
return jsonify({"error": str(exc)}), 400
|
||||
try:
|
||||
token, session = auth_utils.get_vpn_dashboard_token(base_url)
|
||||
hnks = core_functions.list_plmn_hnks(base_url, token, session, tenant_id, plmn_id)
|
||||
@@ -675,7 +748,10 @@ def api_update_radios():
|
||||
network_id = data.get('network_id')
|
||||
new_count = data.get('new_count')
|
||||
operation = data.get('operation')
|
||||
base_url = DASHBOARD_URLS.get(dashboard_name)
|
||||
try:
|
||||
base_url = _resolve_dashboard_url(dashboard_name)
|
||||
except ValueError as exc:
|
||||
return jsonify({"error": str(exc)}), 400
|
||||
try:
|
||||
token, session = auth_utils.get_vpn_dashboard_token(base_url)
|
||||
result = core_functions.update_radio_count(base_url, token, session, network_id, new_count, operation)
|
||||
@@ -693,6 +769,66 @@ def api_get_system_browser_data():
|
||||
app.logger.error(f"Error getting system browser data: {e}", exc_info=True)
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
@app.post("/api/logs/processes")
|
||||
def api_logs_processes():
|
||||
data = request.get_json(force=True) or {}
|
||||
hosts = data.get("hosts") or []
|
||||
if not isinstance(hosts, list) or not hosts:
|
||||
return jsonify({"error": "Provide a list of host IPs"}), 400
|
||||
|
||||
results = []
|
||||
for raw_host in hosts:
|
||||
host = (raw_host or "").strip()
|
||||
if not host:
|
||||
continue
|
||||
try:
|
||||
token = auth_utils.authenticate(host)
|
||||
system_info = core_functions.get_system_info(host, token)
|
||||
frontend = core_functions.get_frontend_config(host, token)
|
||||
services = frontend.get("services", []) if isinstance(frontend, dict) else []
|
||||
running = [svc for svc in services if svc.get("state") == "started"]
|
||||
results.append({
|
||||
"host": host,
|
||||
"hostname": system_info.get("hostname"),
|
||||
"services": running,
|
||||
})
|
||||
except Exception as exc:
|
||||
app.logger.error(f"Failed to fetch services for {host}: {exc}", exc_info=True)
|
||||
results.append({"host": host, "error": str(exc)})
|
||||
|
||||
return jsonify({"hosts": results})
|
||||
|
||||
@app.post("/api/logs/stream")
|
||||
def api_logs_stream():
|
||||
data = request.get_json(force=True) or {}
|
||||
targets_in = data.get("targets") or []
|
||||
if not isinstance(targets_in, list) or not targets_in:
|
||||
return jsonify({"error": "No log targets supplied"}), 400
|
||||
|
||||
targets: list[LogTarget] = []
|
||||
for item in targets_in:
|
||||
host = (item.get("host") or "").strip()
|
||||
processes = [p.strip() for p in item.get("processes", []) if p and p.strip()]
|
||||
if host and processes:
|
||||
targets.append(LogTarget(host=host, processes=processes, hostname=item.get("hostname")))
|
||||
|
||||
if not targets:
|
||||
return jsonify({"error": "No valid hosts/processes to stream"}), 400
|
||||
|
||||
try:
|
||||
streamer = JournalctlStream(targets)
|
||||
except Exception as exc:
|
||||
return jsonify({"error": str(exc)}), 500
|
||||
|
||||
def generate():
|
||||
try:
|
||||
for event in streamer.iter_events():
|
||||
yield json.dumps(event) + "\n"
|
||||
finally:
|
||||
streamer.stop()
|
||||
|
||||
return Response(stream_with_context(generate()), mimetype="text/plain")
|
||||
|
||||
@app.route("/api/backup/create", methods=["POST"])
|
||||
def api_create_backup():
|
||||
data = request.json
|
||||
@@ -741,7 +877,10 @@ def api_get_host_details():
|
||||
def api_list_users():
|
||||
data = request.json
|
||||
dashboard_name = data.get('dashboard')
|
||||
base_url = DASHBOARD_URLS.get(dashboard_name)
|
||||
try:
|
||||
base_url = _resolve_dashboard_url(dashboard_name)
|
||||
except ValueError as exc:
|
||||
return jsonify({"error": str(exc)}), 400
|
||||
try:
|
||||
token, session = auth_utils.get_vpn_dashboard_token(base_url)
|
||||
users = core_functions.list_users(base_url, token, session)
|
||||
@@ -751,4 +890,4 @@ def api_list_users():
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(debug=True)
|
||||
app.run(debug=True)
|
||||
|
||||
Reference in New Issue
Block a user