197 lines
7.0 KiB
Python
197 lines
7.0 KiB
Python
from flask import Blueprint, current_app, render_template, request, make_response, jsonify, redirect
|
|
|
|
from api.http_client import HttpClient, detect_endpoint, create_client, stand_name
|
|
from operations.get_instances import get_organization, get_instances
|
|
from operations.get_services import get_services, get_service_detail
|
|
from operations.tracker import list_all as tracker_list
|
|
from runner import load_config
|
|
|
|
bp = Blueprint("main", __name__)
|
|
AUTOTEST_PREFIX = "autotest-"
|
|
|
|
|
|
def _resolve_instance_status(instance, tracked=None):
|
|
"""Вернуть канонический статус инстанса для API и UI."""
|
|
tracked = tracked or {}
|
|
cloud_status = str(instance.get("explainedStatus") or "").strip()
|
|
display_name = str(instance.get("displayName") or "")
|
|
|
|
if cloud_status:
|
|
return cloud_status
|
|
|
|
if tracked and display_name.startswith(AUTOTEST_PREFIX):
|
|
return "creating"
|
|
|
|
return "unknown"
|
|
|
|
|
|
def _mask(s):
|
|
if not s or len(s) < 8:
|
|
return ""
|
|
return s[:4] + "*" * (len(s) - 8) + s[-4:]
|
|
|
|
|
|
def _client_id(token):
|
|
import base64, json
|
|
try:
|
|
parts = token.split(".")
|
|
if len(parts) >= 2:
|
|
payload = base64.urlsafe_b64decode(parts[1] + "==")
|
|
return json.loads(payload).get("ClientID", "")
|
|
except Exception:
|
|
pass
|
|
return ""
|
|
|
|
|
|
def _token_info(token):
|
|
import base64, json
|
|
try:
|
|
parts = token.split(".")
|
|
if len(parts) >= 2:
|
|
payload = base64.urlsafe_b64decode(parts[1] + "==")
|
|
d = json.loads(payload)
|
|
return {
|
|
"email": d.get("email", ""),
|
|
"company": d.get("company_name", ""),
|
|
"client_id": d.get("ClientID", ""),
|
|
}
|
|
except Exception:
|
|
pass
|
|
return {}
|
|
|
|
|
|
@bp.route("/", methods=["GET", "POST"])
|
|
def index():
|
|
env_token = current_app.config["NUBES_API_TOKEN"]
|
|
user_token = request.cookies.get("token") or request.form.get("token") or ""
|
|
active_token = user_token or env_token
|
|
|
|
org = None
|
|
error = None
|
|
services = []
|
|
instances = []
|
|
instance_groups = {}
|
|
config = {}
|
|
action = request.form.get("action", "")
|
|
|
|
def _tmpl(**overrides):
|
|
"""Собрать контекст шаблона со всеми обязательными переменными."""
|
|
ctx = {
|
|
"organization": org,
|
|
"error": error,
|
|
"env_token_masked": _mask(env_token),
|
|
"has_user_token": bool(user_token),
|
|
"client_id": _client_id(active_token),
|
|
"token_info": _token_info(active_token),
|
|
"config": config,
|
|
"stand": stand,
|
|
"services": services,
|
|
"instances": instances,
|
|
"instance_groups": instance_groups,
|
|
}
|
|
ctx.update(overrides)
|
|
return render_template("index.html", **ctx)
|
|
|
|
if action == "clear":
|
|
resp = make_response(redirect("/"))
|
|
resp.delete_cookie("token")
|
|
return resp
|
|
|
|
if action == "save":
|
|
user_token = request.form.get("token", "")
|
|
active_token = user_token or env_token
|
|
resp = make_response()
|
|
resp.set_cookie("token", user_token, max_age=60*60*24*365)
|
|
# redirect to GET
|
|
resp.headers["Location"] = "/"
|
|
resp.status_code = 302
|
|
return resp
|
|
|
|
services = []
|
|
instances = []
|
|
instance_groups = {}
|
|
config = {}
|
|
stand = "?"
|
|
if active_token:
|
|
result = create_client(active_token, current_app.config["NUBES_API_ENDPOINT"])
|
|
if result:
|
|
client, endpoint = result
|
|
stand = stand_name(endpoint)
|
|
try:
|
|
org = get_organization(client)
|
|
raw_svc = get_services(client)
|
|
services = sorted(raw_svc, key=lambda s: (s.get("svcId", 0), s.get("svc", "")))
|
|
# инфраструктурные сервисы (платформа/среда)
|
|
infra_ids = {2, 12, 21, 22, 25, 26, 29, 110, 150}
|
|
raw_inst = get_instances(client)
|
|
instances = [i for i in raw_inst
|
|
if i.get("explainedStatus") not in ("deleted", "not created")
|
|
and i.get("serviceId") in infra_ids]
|
|
instances.sort(key=lambda i: (0 if i.get("serviceId") == 19 else 1, i.get("displayName", "")))
|
|
|
|
# group by service type
|
|
instance_groups = {}
|
|
for i in instances:
|
|
svc_name = i.get("svc", "Прочее")
|
|
instance_groups.setdefault(svc_name, []).append(i)
|
|
config = dict(load_config() or {})
|
|
config["VERSION"] = current_app.config["VERSION"]
|
|
except Exception as e:
|
|
error = str(e)
|
|
else:
|
|
error = "Токен невалиден или просрочен"
|
|
|
|
if request.method == "POST":
|
|
return redirect("/")
|
|
return _tmpl()
|
|
|
|
|
|
@bp.route("/api/operations/<int:svc_id>")
|
|
def api_operations(svc_id):
|
|
env_token = current_app.config["NUBES_API_TOKEN"]
|
|
user_token = request.cookies.get("token") or ""
|
|
active_token = user_token or env_token
|
|
try:
|
|
result = create_client(active_token, current_app.config["NUBES_API_ENDPOINT"])
|
|
if not result:
|
|
return jsonify({"error": "Не удалось определить стенд"}), 500
|
|
client, _ = result
|
|
detail = get_service_detail(client, svc_id)
|
|
ops = detail.get("operations", [])
|
|
tracked = tracker_list()
|
|
tracked_by_uid = {t["instanceUid"]: t for t in tracked if t["svcId"] == svc_id}
|
|
instances = get_instances(client)
|
|
nubes_uids = {i["instanceUid"] for i in instances}
|
|
|
|
svc_instances = []
|
|
cloud_names = set()
|
|
|
|
for i in instances:
|
|
display_name = str(i.get("displayName", "") or "")
|
|
if not display_name.startswith(AUTOTEST_PREFIX):
|
|
continue
|
|
if i.get("explainedStatus") in ("deleted",):
|
|
continue
|
|
item = dict(i)
|
|
item["status"] = _resolve_instance_status(item, tracked_by_uid.get(i.get("instanceUid")))
|
|
svc_instances.append(item)
|
|
cloud_names.add(display_name)
|
|
|
|
# tracker — только временный fallback, если cloud ещё не отдал конкретный autotest-инстанс
|
|
for uid, t in tracked_by_uid.items():
|
|
if uid not in nubes_uids:
|
|
display_name = str(t.get("displayName", "") or "")
|
|
if display_name in cloud_names:
|
|
continue
|
|
svc_instances.append({
|
|
"instanceUid": uid,
|
|
"displayName": display_name,
|
|
"serviceId": svc_id,
|
|
"svc": detail.get("svc", ""),
|
|
"explainedStatus": "",
|
|
"status": "creating",
|
|
})
|
|
return jsonify({"svc": detail.get("svc", ""), "operations": ops, "instances": svc_instances})
|
|
except Exception as e:
|
|
return jsonify({"error": str(e)}), 500
|