jdeip/app/rotation_service.py

78 lines
2.7 KiB
Python
Raw Normal View History

from typing import Any, Dict, List, Optional, Tuple
from .config import settings
from .eip_client import client_singleton as eip
from .redis_store import store_singleton as kv
def _extract_device_ip_and_id(device: Dict[str, Any]) -> Tuple[Optional[str], Optional[str]]:
# 由于未知后端返回结构,尽可能容错地提取
ip = (
device.get("ip")
or device.get("public_ip")
or device.get("eip")
or device.get("addr")
or device.get("address")
)
edge_id = device.get("id") or device.get("edge") or device.get("mac") or device.get("device_id")
# 若 edge 是数组或对象,尝试取可打印的第一项
if isinstance(edge_id, list) and edge_id:
edge_id = edge_id[0]
if isinstance(edge_id, dict):
edge_id = edge_id.get("id") or edge_id.get("mac") or edge_id.get("edge")
return (str(ip) if ip else None, str(edge_id) if edge_id else None)
def select_unused_ip(devices: List[Dict[str, Any]]) -> Tuple[Optional[str], Optional[str]]:
for d in devices:
ip, edge_id = _extract_device_ip_and_id(d)
if not ip:
# 没有可识别的 IP跳过
continue
if not kv.is_ip_used_today(ip):
return ip, edge_id
return None, None
def apply_gateway_route(edge_id: Optional[str], ip: str) -> Dict[str, Any]:
# 将选中的 edge 配置到网关规则中
rule = {
"table": 1,
"enable": True,
"edge": [edge_id] if edge_id else [],
"network": [],
"cityhash": settings.eip_default_cityhash or "",
}
config = {"id": 1, "rules": [rule]}
return eip.gateway_config_set(settings.eip_gateway_mac, config)
def rotate(cityhash: Optional[str] = None, num: Optional[int] = None) -> Dict[str, Any]:
geo = cityhash or settings.eip_default_cityhash
if not geo:
raise ValueError("cityhash 不能为空,请在请求中或环境变量中提供")
n = int(num or settings.eip_default_num or 10)
devices = eip.list_devices(geo=geo, offset=0, num=n)
ip, edge_id = select_unused_ip(devices)
if not ip:
return {"changed": False, "reason": "没有可用且今天未使用的 IP"}
_ = apply_gateway_route(edge_id=edge_id, ip=ip)
kv.add_used_ip_today(ip)
kv.set_current(ip=ip, edge_id=edge_id)
status = eip.gateway_status(settings.eip_gateway_mac)
return {"changed": True, "ip": ip, "edge": edge_id, "status": status}
def status() -> Dict[str, Any]:
cur = kv.get_current()
used_count = kv.get_used_count_today()
gw = {}
try:
gw = eip.gateway_status(settings.eip_gateway_mac)
except Exception:
pass
return {"current": cur, "used_today": used_count, "gateway": gw}