0773f721ea
- Scale small/large/big seeds (3×50 / 10×1000 / 20×2000) with proportional backups, snapshots, HA, replication, Ceph capacity, and OSD totals (10 / 100 / 500) plus matching node disks and crush/pg metadata - Enrich handler responses for apt, certificates, qemu/lxc status, storage, SDN, metrics export, and related cluster/node dumps - Flatten nested body_example fields into PARAMS and sync the request body via dotted paths (oVirt-style) - Restyle DATA controls as size cards with full-width Reset to minimal / Refresh stats; unload reloads the minimal cluster
1086 lines
47 KiB
Python
1086 lines
47 KiB
Python
"""Cluster and node SDN handlers backed by clusters.metadata.sdn."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import secrets
|
|
from typing import Any
|
|
|
|
from fastapi import Request
|
|
|
|
from app.api.errors import ApiError
|
|
from app.api.registry import HandlerRegistry
|
|
from app.handlers.common import (
|
|
cluster_metadata,
|
|
require_node,
|
|
save_cluster_metadata,
|
|
subdirs,
|
|
values,
|
|
)
|
|
|
|
_SECRET_KEYS = frozenset({"key", "token", "fingerprint"})
|
|
|
|
|
|
def _sdn(metadata: dict[str, Any]) -> dict[str, Any]:
|
|
current = metadata.get("sdn")
|
|
return current if isinstance(current, dict) else {}
|
|
|
|
|
|
_VNET_LIST_KEYS = frozenset(
|
|
{
|
|
"vnet",
|
|
"type",
|
|
"zone",
|
|
"alias",
|
|
"tag",
|
|
"vlanaware",
|
|
"digest",
|
|
"isolate-ports",
|
|
"pending",
|
|
"state",
|
|
}
|
|
)
|
|
|
|
_ZONE_LIST_KEYS = frozenset(
|
|
{
|
|
"zone",
|
|
"type",
|
|
"bridge",
|
|
"mtu",
|
|
"nodes",
|
|
"ipam",
|
|
"dns",
|
|
"reversedns",
|
|
"vlan-protocol",
|
|
"digest",
|
|
"pending",
|
|
"state",
|
|
"comment",
|
|
}
|
|
)
|
|
|
|
|
|
def _public(item: dict[str, Any]) -> dict[str, Any]:
|
|
return {key: value for key, value in item.items() if key not in _SECRET_KEYS}
|
|
|
|
|
|
def _vnet_list_item(name: str, item: dict[str, Any]) -> dict[str, Any]:
|
|
payload = {key: value for key, value in item.items() if key in _VNET_LIST_KEYS}
|
|
payload["vnet"] = str(payload.get("vnet") or name)
|
|
payload.setdefault("type", "vnet")
|
|
return _public(payload)
|
|
|
|
|
|
def _zone_list_item(name: str, item: dict[str, Any]) -> dict[str, Any]:
|
|
payload = {key: value for key, value in item.items() if key in _ZONE_LIST_KEYS}
|
|
payload["zone"] = str(payload.get("zone") or name)
|
|
return _public(payload)
|
|
|
|
|
|
def _store_list(store: dict[str, Any], *, id_key: str) -> list[dict[str, Any]]:
|
|
if id_key == "vnet":
|
|
return [_vnet_list_item(name, item) for name, item in sorted(store.items())]
|
|
if id_key == "zone":
|
|
return [_zone_list_item(name, item) for name, item in sorted(store.items())]
|
|
return [_public({id_key: name, **item}) for name, item in sorted(store.items())]
|
|
|
|
|
|
async def _load(
|
|
request: Request, *, for_write: bool = False
|
|
) -> tuple[dict[str, Any], dict[str, Any]]:
|
|
metadata = await cluster_metadata(request)
|
|
sdn = _sdn(metadata)
|
|
if for_write and metadata.get("sdn") is not sdn:
|
|
metadata["sdn"] = sdn
|
|
return metadata, sdn
|
|
|
|
|
|
def register_sdn_handlers(registry: HandlerRegistry) -> None:
|
|
async def index(_request: Request, _inputs: dict[str, Any]) -> list[dict[str, str]]:
|
|
return subdirs(
|
|
"controllers",
|
|
"dns",
|
|
"dry-run",
|
|
"fabrics",
|
|
"ipams",
|
|
"lock",
|
|
"prefix-lists",
|
|
"rollback",
|
|
"route-maps",
|
|
"vnets",
|
|
"zones",
|
|
)
|
|
|
|
async def apply(request: Request, inputs: dict[str, Any]) -> str:
|
|
from app.handlers.cluster_extra import _cluster_task
|
|
|
|
payload = values(inputs)
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
lock = sdn.get("lock")
|
|
token = payload.get("lock-token")
|
|
if lock and token and lock.get("token") != token:
|
|
raise ApiError(400, "invalid SDN lock token")
|
|
sdn["pending"] = False
|
|
sdn["running_version"] = int(sdn.get("running_version") or 1) + 1
|
|
if payload.get("release-lock"):
|
|
sdn["lock"] = None
|
|
await save_cluster_metadata(request, metadata)
|
|
return await _cluster_task(request, task_type="sdn-apply", worker="sdnapply")
|
|
|
|
async def lock_create(request: Request, inputs: dict[str, Any]) -> str:
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
if sdn.get("lock") and not values(inputs).get("allow-pending"):
|
|
raise ApiError(400, "SDN is already locked")
|
|
token = secrets.token_hex(8)
|
|
sdn["lock"] = {"token": token}
|
|
await save_cluster_metadata(request, metadata)
|
|
return token
|
|
|
|
async def lock_delete(request: Request, inputs: dict[str, Any]) -> None:
|
|
payload = values(inputs)
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
lock = sdn.get("lock")
|
|
if lock is None:
|
|
return None
|
|
if not payload.get("force") and lock.get("token") != payload.get("lock-token"):
|
|
raise ApiError(400, "invalid SDN lock token")
|
|
sdn["lock"] = None
|
|
await save_cluster_metadata(request, metadata)
|
|
|
|
async def rollback(request: Request, inputs: dict[str, Any]) -> None:
|
|
payload = values(inputs)
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
sdn["pending"] = False
|
|
if payload.get("release-lock"):
|
|
sdn["lock"] = None
|
|
await save_cluster_metadata(request, metadata)
|
|
|
|
async def dry_run(request: Request, inputs: dict[str, Any]) -> list[dict[str, Any]]:
|
|
_metadata, sdn = await _load(request, for_write=True)
|
|
return [
|
|
{"type": "zone", "name": name, "action": "noop"}
|
|
for name in sorted(sdn.get("zones") or {})
|
|
]
|
|
|
|
def register_named(
|
|
path: str,
|
|
store_key: str,
|
|
id_param: str,
|
|
*,
|
|
create_required: str | None = None,
|
|
) -> None:
|
|
async def list_items(request: Request, inputs: dict[str, Any]) -> list[dict[str, Any]]:
|
|
_metadata, sdn = await _load(request, for_write=True)
|
|
items = _store_list(sdn.get(store_key) or {}, id_key=id_param)
|
|
type_filter = values(inputs).get("type")
|
|
if type_filter:
|
|
items = [item for item in items if item.get("type") == type_filter]
|
|
return items
|
|
|
|
async def create(request: Request, inputs: dict[str, Any]) -> None:
|
|
payload = values(inputs)
|
|
item_id = str(payload[create_required or id_param])
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
store = sdn.setdefault(store_key, {})
|
|
if item_id in store:
|
|
raise ApiError(400, f"{store_key} '{item_id}' already exists")
|
|
store[item_id] = {
|
|
key: value
|
|
for key, value in payload.items()
|
|
if key not in {"lock-token", "digest", "delete"}
|
|
}
|
|
store[item_id][id_param] = item_id
|
|
sdn["pending"] = True
|
|
await save_cluster_metadata(request, metadata)
|
|
|
|
async def get(request: Request, inputs: dict[str, Any]) -> dict[str, Any]:
|
|
item_id = str(values(inputs)[id_param])
|
|
_metadata, sdn = await _load(request, for_write=True)
|
|
item = (sdn.get(store_key) or {}).get(item_id)
|
|
if not isinstance(item, dict):
|
|
raise ApiError(404, f"{store_key} entry does not exist")
|
|
return _public({id_param: item_id, **item})
|
|
|
|
async def update(request: Request, inputs: dict[str, Any]) -> None:
|
|
payload = values(inputs)
|
|
item_id = str(payload[id_param])
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
store = sdn.setdefault(store_key, {})
|
|
if item_id not in store:
|
|
raise ApiError(404, f"{store_key} entry does not exist")
|
|
current = dict(store[item_id])
|
|
for key in [
|
|
item.strip() for item in str(payload.get("delete") or "").split(",") if item.strip()
|
|
]:
|
|
current.pop(key, None)
|
|
for key, value in payload.items():
|
|
if key in {id_param, "delete", "digest", "lock-token"}:
|
|
continue
|
|
current[key] = value
|
|
current[id_param] = item_id
|
|
store[item_id] = current
|
|
sdn["pending"] = True
|
|
await save_cluster_metadata(request, metadata)
|
|
|
|
async def delete(request: Request, inputs: dict[str, Any]) -> None:
|
|
item_id = str(values(inputs)[id_param])
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
store = sdn.setdefault(store_key, {})
|
|
if item_id not in store:
|
|
raise ApiError(404, f"{store_key} entry does not exist")
|
|
del store[item_id]
|
|
sdn["pending"] = True
|
|
await save_cluster_metadata(request, metadata)
|
|
|
|
registry.register(path, "GET", list_items)
|
|
registry.register(path, "POST", create)
|
|
registry.register(f"{path}/{{{id_param}}}", "GET", get)
|
|
registry.register(f"{path}/{{{id_param}}}", "PUT", update)
|
|
registry.register(f"{path}/{{{id_param}}}", "DELETE", delete)
|
|
|
|
# zones / controllers / dns / ipams
|
|
register_named("/cluster/sdn/zones", "zones", "zone")
|
|
register_named("/cluster/sdn/controllers", "controllers", "controller")
|
|
register_named("/cluster/sdn/dns", "dns", "dns")
|
|
register_named("/cluster/sdn/ipams", "ipams", "ipam")
|
|
|
|
async def ipam_status(request: Request, inputs: dict[str, Any]) -> dict[str, Any]:
|
|
ipam = str(values(inputs)["ipam"])
|
|
_metadata, sdn = await _load(request, for_write=True)
|
|
if ipam not in (sdn.get("ipams") or {}):
|
|
raise ApiError(404, "ipam does not exist")
|
|
return {"status": "ok", "ipam": ipam}
|
|
|
|
# vnets + nested
|
|
async def vnets_list(request: Request, _inputs: dict[str, Any]) -> list[dict[str, Any]]:
|
|
_metadata, sdn = await _load(request, for_write=True)
|
|
return _store_list(sdn.get("vnets") or {}, id_key="vnet")
|
|
|
|
async def vnets_create(request: Request, inputs: dict[str, Any]) -> None:
|
|
payload = values(inputs)
|
|
vnet = str(payload["vnet"])
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
store = sdn.setdefault("vnets", {})
|
|
if vnet in store:
|
|
raise ApiError(400, f"vnet '{vnet}' already exists")
|
|
store[vnet] = {
|
|
**{k: v for k, v in payload.items() if k not in {"lock-token", "digest"}},
|
|
"vnet": vnet,
|
|
"subnets": {},
|
|
"ips": [],
|
|
"firewall": {"options": {"enable": 0}, "rules": []},
|
|
}
|
|
sdn["pending"] = True
|
|
await save_cluster_metadata(request, metadata)
|
|
|
|
async def vnet_get(request: Request, inputs: dict[str, Any]) -> dict[str, Any]:
|
|
vnet = str(values(inputs)["vnet"])
|
|
_metadata, sdn = await _load(request, for_write=True)
|
|
item = (sdn.get("vnets") or {}).get(vnet)
|
|
if not isinstance(item, dict):
|
|
raise ApiError(404, "vnet does not exist")
|
|
return _public({"vnet": vnet, **{k: v for k, v in item.items() if k != "firewall"}})
|
|
|
|
async def vnet_update(request: Request, inputs: dict[str, Any]) -> None:
|
|
payload = values(inputs)
|
|
vnet = str(payload["vnet"])
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
store = sdn.setdefault("vnets", {})
|
|
if vnet not in store:
|
|
raise ApiError(404, "vnet does not exist")
|
|
current = dict(store[vnet])
|
|
for key in [
|
|
item.strip() for item in str(payload.get("delete") or "").split(",") if item.strip()
|
|
]:
|
|
current.pop(key, None)
|
|
for key, value in payload.items():
|
|
if key in {"vnet", "delete", "digest", "lock-token"}:
|
|
continue
|
|
current[key] = value
|
|
current["vnet"] = vnet
|
|
store[vnet] = current
|
|
sdn["pending"] = True
|
|
await save_cluster_metadata(request, metadata)
|
|
|
|
async def vnet_delete(request: Request, inputs: dict[str, Any]) -> None:
|
|
vnet = str(values(inputs)["vnet"])
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
store = sdn.setdefault("vnets", {})
|
|
if vnet not in store:
|
|
raise ApiError(404, "vnet does not exist")
|
|
del store[vnet]
|
|
sdn["pending"] = True
|
|
await save_cluster_metadata(request, metadata)
|
|
|
|
async def _vnet(sdn: dict[str, Any], vnet: str) -> dict[str, Any]:
|
|
item = (sdn.get("vnets") or {}).get(vnet)
|
|
if not isinstance(item, dict):
|
|
raise ApiError(404, "vnet does not exist")
|
|
item.setdefault("subnets", {})
|
|
item.setdefault("ips", [])
|
|
item.setdefault("firewall", {"options": {"enable": 0}, "rules": []})
|
|
return item
|
|
|
|
async def subnets_list(request: Request, inputs: dict[str, Any]) -> list[dict[str, Any]]:
|
|
vnet = str(values(inputs)["vnet"])
|
|
_metadata, sdn = await _load(request, for_write=True)
|
|
item = await _vnet(sdn, vnet)
|
|
return _store_list(item.get("subnets") or {}, id_key="subnet")
|
|
|
|
async def subnets_create(request: Request, inputs: dict[str, Any]) -> None:
|
|
payload = values(inputs)
|
|
vnet = str(payload["vnet"])
|
|
subnet = str(payload["subnet"])
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
item = await _vnet(sdn, vnet)
|
|
subnets = item.setdefault("subnets", {})
|
|
if subnet in subnets:
|
|
raise ApiError(400, f"subnet '{subnet}' already exists")
|
|
subnets[subnet] = {
|
|
**{k: v for k, v in payload.items() if k not in {"lock-token", "digest"}},
|
|
"subnet": subnet,
|
|
}
|
|
sdn["pending"] = True
|
|
await save_cluster_metadata(request, metadata)
|
|
|
|
async def subnet_get(request: Request, inputs: dict[str, Any]) -> dict[str, Any]:
|
|
payload = values(inputs)
|
|
vnet = str(payload["vnet"])
|
|
subnet = str(payload["subnet"])
|
|
_metadata, sdn = await _load(request, for_write=True)
|
|
item = await _vnet(sdn, vnet)
|
|
data = (item.get("subnets") or {}).get(subnet)
|
|
if not isinstance(data, dict):
|
|
raise ApiError(404, "subnet does not exist")
|
|
return _public({"subnet": subnet, **data})
|
|
|
|
async def subnet_update(request: Request, inputs: dict[str, Any]) -> None:
|
|
payload = values(inputs)
|
|
vnet = str(payload["vnet"])
|
|
subnet = str(payload["subnet"])
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
item = await _vnet(sdn, vnet)
|
|
subnets = item.setdefault("subnets", {})
|
|
if subnet not in subnets:
|
|
raise ApiError(404, "subnet does not exist")
|
|
current = dict(subnets[subnet])
|
|
for key in [
|
|
item.strip() for item in str(payload.get("delete") or "").split(",") if item.strip()
|
|
]:
|
|
current.pop(key, None)
|
|
for key, value in payload.items():
|
|
if key in {"vnet", "subnet", "delete", "digest", "lock-token"}:
|
|
continue
|
|
current[key] = value
|
|
current["subnet"] = subnet
|
|
subnets[subnet] = current
|
|
sdn["pending"] = True
|
|
await save_cluster_metadata(request, metadata)
|
|
|
|
async def subnet_delete(request: Request, inputs: dict[str, Any]) -> None:
|
|
payload = values(inputs)
|
|
vnet = str(payload["vnet"])
|
|
subnet = str(payload["subnet"])
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
item = await _vnet(sdn, vnet)
|
|
subnets = item.setdefault("subnets", {})
|
|
if subnet not in subnets:
|
|
raise ApiError(404, "subnet does not exist")
|
|
del subnets[subnet]
|
|
sdn["pending"] = True
|
|
await save_cluster_metadata(request, metadata)
|
|
|
|
async def ips_create(request: Request, inputs: dict[str, Any]) -> None:
|
|
payload = values(inputs)
|
|
vnet = str(payload["vnet"])
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
item = await _vnet(sdn, vnet)
|
|
ips = item.setdefault("ips", [])
|
|
if not isinstance(ips, list):
|
|
ips = item["ips"] = []
|
|
ips.append(
|
|
{
|
|
"ip": payload.get("ip"),
|
|
"mac": payload.get("mac"),
|
|
"zone": payload.get("zone"),
|
|
"vmid": payload.get("vmid"),
|
|
}
|
|
)
|
|
await save_cluster_metadata(request, metadata)
|
|
|
|
async def ips_update(request: Request, inputs: dict[str, Any]) -> None:
|
|
await ips_create(request, inputs)
|
|
|
|
async def ips_delete(request: Request, inputs: dict[str, Any]) -> None:
|
|
payload = values(inputs)
|
|
vnet = str(payload["vnet"])
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
item = await _vnet(sdn, vnet)
|
|
ips = item.setdefault("ips", [])
|
|
if not isinstance(ips, list):
|
|
return None
|
|
item["ips"] = [
|
|
entry
|
|
for entry in ips
|
|
if not (entry.get("ip") == payload.get("ip") and entry.get("mac") == payload.get("mac"))
|
|
]
|
|
await save_cluster_metadata(request, metadata)
|
|
|
|
async def fw_index(request: Request, inputs: dict[str, Any]) -> list[dict[str, str]]:
|
|
await _vnet((await _load(request))[1], str(values(inputs)["vnet"]))
|
|
return subdirs("options", "rules")
|
|
|
|
async def fw_options_get(request: Request, inputs: dict[str, Any]) -> dict[str, Any]:
|
|
vnet = str(values(inputs)["vnet"])
|
|
_metadata, sdn = await _load(request, for_write=True)
|
|
item = await _vnet(sdn, vnet)
|
|
return dict(item.get("firewall", {}).get("options") or {"enable": 0})
|
|
|
|
async def fw_options_put(request: Request, inputs: dict[str, Any]) -> None:
|
|
payload = values(inputs)
|
|
vnet = str(payload["vnet"])
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
item = await _vnet(sdn, vnet)
|
|
options = dict(item.setdefault("firewall", {}).setdefault("options", {"enable": 0}))
|
|
for key, value in payload.items():
|
|
if key in {"vnet", "delete", "digest"}:
|
|
continue
|
|
options[key] = value
|
|
item["firewall"]["options"] = options
|
|
await save_cluster_metadata(request, metadata)
|
|
|
|
async def fw_rules_list(request: Request, inputs: dict[str, Any]) -> list[dict[str, Any]]:
|
|
vnet = str(values(inputs)["vnet"])
|
|
_metadata, sdn = await _load(request, for_write=True)
|
|
item = await _vnet(sdn, vnet)
|
|
rules = item.get("firewall", {}).get("rules") or []
|
|
return list(rules) if isinstance(rules, list) else []
|
|
|
|
async def fw_rules_create(request: Request, inputs: dict[str, Any]) -> None:
|
|
payload = values(inputs)
|
|
vnet = str(payload["vnet"])
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
item = await _vnet(sdn, vnet)
|
|
rules = item.setdefault("firewall", {}).setdefault("rules", [])
|
|
if not isinstance(rules, list):
|
|
rules = item["firewall"]["rules"] = []
|
|
rule = {k: v for k, v in payload.items() if k not in {"vnet", "pos", "digest"}}
|
|
rule["pos"] = len(rules)
|
|
rules.append(rule)
|
|
await save_cluster_metadata(request, metadata)
|
|
|
|
async def fw_rule_get(request: Request, inputs: dict[str, Any]) -> dict[str, Any]:
|
|
rules = await fw_rules_list(request, inputs)
|
|
pos = int(values(inputs)["pos"])
|
|
if pos < 0 or pos >= len(rules):
|
|
raise ApiError(404, "firewall rule does not exist")
|
|
return dict(rules[pos])
|
|
|
|
async def fw_rule_update(request: Request, inputs: dict[str, Any]) -> None:
|
|
payload = values(inputs)
|
|
vnet = str(payload["vnet"])
|
|
pos = int(payload["pos"])
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
item = await _vnet(sdn, vnet)
|
|
rules = item.setdefault("firewall", {}).setdefault("rules", [])
|
|
if not isinstance(rules, list) or pos < 0 or pos >= len(rules):
|
|
raise ApiError(404, "firewall rule does not exist")
|
|
rules[pos] = {
|
|
**rules[pos],
|
|
**{k: v for k, v in payload.items() if k not in {"vnet", "pos"}},
|
|
}
|
|
await save_cluster_metadata(request, metadata)
|
|
|
|
async def fw_rule_delete(request: Request, inputs: dict[str, Any]) -> None:
|
|
payload = values(inputs)
|
|
vnet = str(payload["vnet"])
|
|
pos = int(payload["pos"])
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
item = await _vnet(sdn, vnet)
|
|
rules = item.setdefault("firewall", {}).setdefault("rules", [])
|
|
if not isinstance(rules, list) or pos < 0 or pos >= len(rules):
|
|
raise ApiError(404, "firewall rule does not exist")
|
|
del rules[pos]
|
|
await save_cluster_metadata(request, metadata)
|
|
|
|
# fabrics
|
|
async def fabrics_index(_request: Request, _inputs: dict[str, Any]) -> list[dict[str, str]]:
|
|
return subdirs("all", "fabric", "node")
|
|
|
|
async def fabrics_all(request: Request, _inputs: dict[str, Any]) -> list[dict[str, Any]]:
|
|
_metadata, sdn = await _load(request, for_write=True)
|
|
return _store_list(sdn.get("fabrics") or {}, id_key="id")
|
|
|
|
async def fabric_list(request: Request, inputs: dict[str, Any]) -> list[dict[str, Any]]:
|
|
return await fabrics_all(request, inputs)
|
|
|
|
async def fabric_create(request: Request, inputs: dict[str, Any]) -> None:
|
|
payload = values(inputs)
|
|
fabric_id = str(payload["id"])
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
store = sdn.setdefault("fabrics", {})
|
|
if fabric_id in store:
|
|
raise ApiError(400, f"fabric '{fabric_id}' already exists")
|
|
store[fabric_id] = {
|
|
**{k: v for k, v in payload.items() if k not in {"lock-token", "digest"}},
|
|
"id": fabric_id,
|
|
}
|
|
sdn["pending"] = True
|
|
await save_cluster_metadata(request, metadata)
|
|
|
|
async def fabric_get(request: Request, inputs: dict[str, Any]) -> dict[str, Any]:
|
|
fabric_id = str(values(inputs)["id"])
|
|
_metadata, sdn = await _load(request, for_write=True)
|
|
item = (sdn.get("fabrics") or {}).get(fabric_id)
|
|
if not isinstance(item, dict):
|
|
raise ApiError(404, "fabric does not exist")
|
|
return _public({"id": fabric_id, **item})
|
|
|
|
async def fabric_update(request: Request, inputs: dict[str, Any]) -> None:
|
|
payload = values(inputs)
|
|
fabric_id = str(payload["id"])
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
store = sdn.setdefault("fabrics", {})
|
|
if fabric_id not in store:
|
|
raise ApiError(404, "fabric does not exist")
|
|
current = dict(store[fabric_id])
|
|
for key in [
|
|
item.strip() for item in str(payload.get("delete") or "").split(",") if item.strip()
|
|
]:
|
|
current.pop(key, None)
|
|
for key, value in payload.items():
|
|
if key in {"id", "delete", "digest", "lock-token"}:
|
|
continue
|
|
current[key] = value
|
|
current["id"] = fabric_id
|
|
store[fabric_id] = current
|
|
sdn["pending"] = True
|
|
await save_cluster_metadata(request, metadata)
|
|
|
|
async def fabric_delete(request: Request, inputs: dict[str, Any]) -> None:
|
|
fabric_id = str(values(inputs)["id"])
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
store = sdn.setdefault("fabrics", {})
|
|
if fabric_id not in store:
|
|
raise ApiError(404, "fabric does not exist")
|
|
del store[fabric_id]
|
|
nodes = sdn.setdefault("fabric_nodes", {})
|
|
nodes.pop(fabric_id, None)
|
|
sdn["pending"] = True
|
|
await save_cluster_metadata(request, metadata)
|
|
|
|
async def fabric_nodes_list(request: Request, inputs: dict[str, Any]) -> list[dict[str, Any]]:
|
|
_metadata, sdn = await _load(request, for_write=True)
|
|
fabric_id = values(inputs).get("fabric_id")
|
|
nodes = sdn.get("fabric_nodes") or {}
|
|
result: list[dict[str, Any]] = []
|
|
for fid, store in sorted(nodes.items()):
|
|
if fabric_id and fid != fabric_id:
|
|
continue
|
|
if not isinstance(store, dict):
|
|
continue
|
|
for node_id, item in sorted(store.items()):
|
|
result.append(_public({"fabric_id": fid, "node_id": node_id, **item}))
|
|
return result
|
|
|
|
async def fabric_node_create(request: Request, inputs: dict[str, Any]) -> None:
|
|
payload = values(inputs)
|
|
fabric_id = str(payload["fabric_id"])
|
|
node_id = str(payload["node_id"])
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
if fabric_id not in (sdn.get("fabrics") or {}):
|
|
raise ApiError(404, "fabric does not exist")
|
|
store = sdn.setdefault("fabric_nodes", {}).setdefault(fabric_id, {})
|
|
if node_id in store:
|
|
raise ApiError(400, f"fabric node '{node_id}' already exists")
|
|
store[node_id] = {
|
|
**{k: v for k, v in payload.items() if k not in {"lock-token", "digest"}},
|
|
"node_id": node_id,
|
|
}
|
|
sdn["pending"] = True
|
|
await save_cluster_metadata(request, metadata)
|
|
|
|
async def fabric_node_get(request: Request, inputs: dict[str, Any]) -> dict[str, Any]:
|
|
payload = values(inputs)
|
|
fabric_id = str(payload["fabric_id"])
|
|
node_id = str(payload["node_id"])
|
|
_metadata, sdn = await _load(request, for_write=True)
|
|
item = ((sdn.get("fabric_nodes") or {}).get(fabric_id) or {}).get(node_id)
|
|
if not isinstance(item, dict):
|
|
raise ApiError(404, "fabric node does not exist")
|
|
return _public({"fabric_id": fabric_id, "node_id": node_id, **item})
|
|
|
|
async def fabric_node_update(request: Request, inputs: dict[str, Any]) -> None:
|
|
payload = values(inputs)
|
|
fabric_id = str(payload["fabric_id"])
|
|
node_id = str(payload["node_id"])
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
store = sdn.setdefault("fabric_nodes", {}).setdefault(fabric_id, {})
|
|
if node_id not in store:
|
|
raise ApiError(404, "fabric node does not exist")
|
|
current = dict(store[node_id])
|
|
for key in [
|
|
item.strip() for item in str(payload.get("delete") or "").split(",") if item.strip()
|
|
]:
|
|
current.pop(key, None)
|
|
for key, value in payload.items():
|
|
if key in {"fabric_id", "node_id", "delete", "digest", "lock-token"}:
|
|
continue
|
|
current[key] = value
|
|
current["node_id"] = node_id
|
|
store[node_id] = current
|
|
sdn["pending"] = True
|
|
await save_cluster_metadata(request, metadata)
|
|
|
|
async def fabric_node_delete(request: Request, inputs: dict[str, Any]) -> None:
|
|
payload = values(inputs)
|
|
fabric_id = str(payload["fabric_id"])
|
|
node_id = str(payload["node_id"])
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
store = sdn.setdefault("fabric_nodes", {}).setdefault(fabric_id, {})
|
|
if node_id not in store:
|
|
raise ApiError(404, "fabric node does not exist")
|
|
del store[node_id]
|
|
sdn["pending"] = True
|
|
await save_cluster_metadata(request, metadata)
|
|
|
|
# prefix lists
|
|
async def prefix_list(request: Request, _inputs: dict[str, Any]) -> list[dict[str, Any]]:
|
|
_metadata, sdn = await _load(request, for_write=True)
|
|
return _store_list(sdn.get("prefix_lists") or {}, id_key="id")
|
|
|
|
async def prefix_create(request: Request, inputs: dict[str, Any]) -> None:
|
|
payload = values(inputs)
|
|
list_id = str(payload["id"])
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
store = sdn.setdefault("prefix_lists", {})
|
|
if list_id in store:
|
|
raise ApiError(400, f"prefix-list '{list_id}' already exists")
|
|
store[list_id] = {
|
|
"id": list_id,
|
|
"entries": payload.get("entries") if isinstance(payload.get("entries"), dict) else {},
|
|
"digest": payload.get("digest"),
|
|
}
|
|
if isinstance(payload.get("entries"), list):
|
|
store[list_id]["entries"] = {
|
|
str(index): entry for index, entry in enumerate(payload["entries"])
|
|
}
|
|
sdn["pending"] = True
|
|
await save_cluster_metadata(request, metadata)
|
|
|
|
async def prefix_get(request: Request, inputs: dict[str, Any]) -> dict[str, Any]:
|
|
list_id = str(values(inputs)["id"])
|
|
_metadata, sdn = await _load(request, for_write=True)
|
|
item = (sdn.get("prefix_lists") or {}).get(list_id)
|
|
if not isinstance(item, dict):
|
|
raise ApiError(404, "prefix-list does not exist")
|
|
return {"id": list_id, **item}
|
|
|
|
async def prefix_update(request: Request, inputs: dict[str, Any]) -> None:
|
|
payload = values(inputs)
|
|
list_id = str(payload["id"])
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
store = sdn.setdefault("prefix_lists", {})
|
|
if list_id not in store:
|
|
raise ApiError(404, "prefix-list does not exist")
|
|
current = dict(store[list_id])
|
|
if "entries" in payload:
|
|
current["entries"] = payload["entries"]
|
|
store[list_id] = current
|
|
sdn["pending"] = True
|
|
await save_cluster_metadata(request, metadata)
|
|
|
|
async def prefix_delete(request: Request, inputs: dict[str, Any]) -> None:
|
|
list_id = str(values(inputs)["id"])
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
store = sdn.setdefault("prefix_lists", {})
|
|
if list_id not in store:
|
|
raise ApiError(404, "prefix-list does not exist")
|
|
del store[list_id]
|
|
sdn["pending"] = True
|
|
await save_cluster_metadata(request, metadata)
|
|
|
|
async def prefix_entries(request: Request, inputs: dict[str, Any]) -> list[dict[str, Any]]:
|
|
list_id = str(values(inputs)["id"])
|
|
_metadata, sdn = await _load(request, for_write=True)
|
|
item = (sdn.get("prefix_lists") or {}).get(list_id)
|
|
if not isinstance(item, dict):
|
|
raise ApiError(404, "prefix-list does not exist")
|
|
entries = item.get("entries") or {}
|
|
if isinstance(entries, dict):
|
|
return [{"seq": key, **value} for key, value in sorted(entries.items())]
|
|
return list(entries) if isinstance(entries, list) else []
|
|
|
|
async def prefix_entry_create(request: Request, inputs: dict[str, Any]) -> None:
|
|
payload = values(inputs)
|
|
list_id = str(payload["id"])
|
|
seq = str(payload.get("seq") or secrets.randbelow(10000))
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
item = (sdn.get("prefix_lists") or {}).get(list_id)
|
|
if not isinstance(item, dict):
|
|
raise ApiError(404, "prefix-list does not exist")
|
|
entries = item.setdefault("entries", {})
|
|
if not isinstance(entries, dict):
|
|
entries = item["entries"] = {}
|
|
entries[seq] = {
|
|
"seq": seq,
|
|
"action": payload.get("action"),
|
|
"prefix": payload.get("prefix"),
|
|
"ge": payload.get("ge"),
|
|
"le": payload.get("le"),
|
|
}
|
|
sdn["pending"] = True
|
|
await save_cluster_metadata(request, metadata)
|
|
|
|
async def prefix_entry_get(request: Request, inputs: dict[str, Any]) -> dict[str, Any]:
|
|
payload = values(inputs)
|
|
list_id = str(payload["id"])
|
|
seq = str(payload["url_seq"])
|
|
_metadata, sdn = await _load(request, for_write=True)
|
|
item = (sdn.get("prefix_lists") or {}).get(list_id)
|
|
if not isinstance(item, dict):
|
|
raise ApiError(404, "prefix-list does not exist")
|
|
entry = (item.get("entries") or {}).get(seq)
|
|
if not isinstance(entry, dict):
|
|
raise ApiError(404, "prefix-list entry does not exist")
|
|
return {"seq": seq, **entry}
|
|
|
|
async def prefix_entry_update(request: Request, inputs: dict[str, Any]) -> None:
|
|
payload = values(inputs)
|
|
list_id = str(payload["id"])
|
|
seq = str(payload["url_seq"])
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
item = (sdn.get("prefix_lists") or {}).get(list_id)
|
|
if not isinstance(item, dict):
|
|
raise ApiError(404, "prefix-list does not exist")
|
|
entries = item.setdefault("entries", {})
|
|
if seq not in entries:
|
|
raise ApiError(404, "prefix-list entry does not exist")
|
|
current = dict(entries[seq])
|
|
for key in ("action", "prefix", "ge", "le", "seq"):
|
|
if key in payload:
|
|
current[key] = payload[key]
|
|
entries[seq] = current
|
|
sdn["pending"] = True
|
|
await save_cluster_metadata(request, metadata)
|
|
|
|
async def prefix_entry_delete(request: Request, inputs: dict[str, Any]) -> None:
|
|
payload = values(inputs)
|
|
list_id = str(payload["id"])
|
|
seq = str(payload["url_seq"])
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
item = (sdn.get("prefix_lists") or {}).get(list_id)
|
|
if not isinstance(item, dict):
|
|
raise ApiError(404, "prefix-list does not exist")
|
|
entries = item.setdefault("entries", {})
|
|
if seq not in entries:
|
|
raise ApiError(404, "prefix-list entry does not exist")
|
|
del entries[seq]
|
|
sdn["pending"] = True
|
|
await save_cluster_metadata(request, metadata)
|
|
|
|
# route maps
|
|
async def route_maps_index(_request: Request, _inputs: dict[str, Any]) -> list[dict[str, str]]:
|
|
return subdirs("entries")
|
|
|
|
def _route_map_entries(item: object) -> dict[str, Any]:
|
|
if not isinstance(item, dict):
|
|
return {}
|
|
nested = item.get("entries")
|
|
if isinstance(nested, dict):
|
|
return {
|
|
str(key): value
|
|
for key, value in nested.items()
|
|
if isinstance(value, dict) and str(key).isdigit()
|
|
}
|
|
return {
|
|
str(key): value
|
|
for key, value in item.items()
|
|
if isinstance(value, dict) and str(key).isdigit()
|
|
}
|
|
|
|
def _route_map_entries_mutable(sdn: dict[str, Any], map_id: str) -> dict[str, Any]:
|
|
bucket = sdn.setdefault("route_maps", {}).setdefault(map_id, {})
|
|
if not isinstance(bucket, dict):
|
|
bucket = {}
|
|
sdn["route_maps"][map_id] = bucket
|
|
if "entries" in bucket or "name" in bucket:
|
|
entries = bucket.setdefault("entries", {})
|
|
if not isinstance(entries, dict):
|
|
entries = {}
|
|
bucket["entries"] = entries
|
|
return entries
|
|
return bucket
|
|
|
|
async def route_entries_list(request: Request, inputs: dict[str, Any]) -> list[dict[str, Any]]:
|
|
_metadata, sdn = await _load(request, for_write=True)
|
|
maps = sdn.get("route_maps") or {}
|
|
route_map_id = values(inputs).get("route-map-id")
|
|
result: list[dict[str, Any]] = []
|
|
for map_id, raw_entries in sorted(maps.items()):
|
|
if route_map_id and map_id != route_map_id:
|
|
continue
|
|
entries = _route_map_entries(raw_entries)
|
|
for order, entry in sorted(entries.items(), key=lambda pair: int(pair[0])):
|
|
result.append({"route-map-id": map_id, "order": int(order), **entry})
|
|
return result
|
|
|
|
async def route_entry_create(request: Request, inputs: dict[str, Any]) -> None:
|
|
payload = values(inputs)
|
|
map_id = str(payload["route-map-id"])
|
|
order = str(payload.get("order") or 10)
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
entries = _route_map_entries_mutable(sdn, map_id)
|
|
if order in entries:
|
|
raise ApiError(400, f"route-map entry '{order}' already exists")
|
|
entries[order] = {
|
|
k: v for k, v in payload.items() if k not in {"lock-token", "digest", "route-map-id"}
|
|
}
|
|
entries[order]["order"] = int(order)
|
|
sdn["pending"] = True
|
|
await save_cluster_metadata(request, metadata)
|
|
|
|
async def route_map_entries(request: Request, inputs: dict[str, Any]) -> list[dict[str, Any]]:
|
|
return await route_entries_list(
|
|
request,
|
|
{
|
|
"values": {"route-map-id": values(inputs)["route-map-id"]},
|
|
"provided": frozenset(),
|
|
},
|
|
)
|
|
|
|
async def route_entry_get(request: Request, inputs: dict[str, Any]) -> dict[str, Any]:
|
|
payload = values(inputs)
|
|
map_id = str(payload["route-map-id"])
|
|
order = str(payload["order"])
|
|
_metadata, sdn = await _load(request, for_write=True)
|
|
entry = _route_map_entries((sdn.get("route_maps") or {}).get(map_id)).get(order)
|
|
if not isinstance(entry, dict):
|
|
raise ApiError(404, "route-map entry does not exist")
|
|
return {"route-map-id": map_id, "order": int(order), **entry}
|
|
|
|
async def route_entry_update(request: Request, inputs: dict[str, Any]) -> None:
|
|
payload = values(inputs)
|
|
map_id = str(payload["route-map-id"])
|
|
order = str(payload["order"])
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
entries = _route_map_entries_mutable(sdn, map_id)
|
|
if order not in entries:
|
|
raise ApiError(404, "route-map entry does not exist")
|
|
current = dict(entries[order])
|
|
for key, value in payload.items():
|
|
if key in {"route-map-id", "order", "delete", "digest", "lock-token"}:
|
|
continue
|
|
current[key] = value
|
|
current["order"] = int(order)
|
|
entries[order] = current
|
|
sdn["pending"] = True
|
|
await save_cluster_metadata(request, metadata)
|
|
|
|
async def route_entry_delete(request: Request, inputs: dict[str, Any]) -> None:
|
|
payload = values(inputs)
|
|
map_id = str(payload["route-map-id"])
|
|
order = str(payload["order"])
|
|
metadata, sdn = await _load(request, for_write=True)
|
|
entries = _route_map_entries_mutable(sdn, map_id)
|
|
if order not in entries:
|
|
raise ApiError(404, "route-map entry does not exist")
|
|
del entries[order]
|
|
sdn["pending"] = True
|
|
await save_cluster_metadata(request, metadata)
|
|
|
|
# node sdn surfaces
|
|
async def node_sdn_index(request: Request, inputs: dict[str, Any]) -> list[dict[str, str]]:
|
|
await require_node(request, str(values(inputs)["node"]))
|
|
return subdirs("fabrics", "vnets", "zones")
|
|
|
|
async def node_zones(request: Request, inputs: dict[str, Any]) -> list[dict[str, Any]]:
|
|
await require_node(request, str(values(inputs)["node"]))
|
|
_metadata, sdn = await _load(request, for_write=True)
|
|
return _store_list(sdn.get("zones") or {}, id_key="zone")
|
|
|
|
async def node_zone(request: Request, inputs: dict[str, Any]) -> dict[str, Any]:
|
|
await require_node(request, str(values(inputs)["node"]))
|
|
zone = str(values(inputs)["zone"])
|
|
_metadata, sdn = await _load(request, for_write=True)
|
|
item = (sdn.get("zones") or {}).get(zone)
|
|
if not isinstance(item, dict):
|
|
raise ApiError(404, "zone does not exist")
|
|
return _public({"zone": zone, **item})
|
|
|
|
async def node_zone_bridges(request: Request, inputs: dict[str, Any]) -> list[dict[str, Any]]:
|
|
zone = await node_zone(request, inputs)
|
|
bridges = zone.get("bridges")
|
|
if isinstance(bridges, list):
|
|
return [dict(item) for item in bridges if isinstance(item, dict)]
|
|
bridge = zone.get("bridge")
|
|
return [{"iface": bridge, "active": 1}] if bridge else []
|
|
|
|
async def node_zone_content(request: Request, inputs: dict[str, Any]) -> list[dict[str, Any]]:
|
|
await require_node(request, str(values(inputs)["node"]))
|
|
zone = str(values(inputs)["zone"])
|
|
_metadata, sdn = await _load(request, for_write=True)
|
|
return [
|
|
{"vnet": name, **item}
|
|
for name, item in sorted((sdn.get("vnets") or {}).items())
|
|
if item.get("zone") == zone
|
|
]
|
|
|
|
async def node_zone_ip_vrf(request: Request, inputs: dict[str, Any]) -> dict[str, Any]:
|
|
zone = await node_zone(request, inputs)
|
|
return {
|
|
"zone": zone.get("zone"),
|
|
"vrf": zone.get("vrf") or "",
|
|
"table": zone.get("table") if zone.get("table") is not None else 0,
|
|
}
|
|
|
|
async def node_vnet(request: Request, inputs: dict[str, Any]) -> dict[str, Any]:
|
|
await require_node(request, str(values(inputs)["node"]))
|
|
return await vnet_get(request, inputs)
|
|
|
|
async def node_vnet_mac_vrf(request: Request, inputs: dict[str, Any]) -> dict[str, Any]:
|
|
vnet = await node_vnet(request, inputs)
|
|
return {"vnet": vnet.get("vnet"), "mac-vrf": vnet.get("mac-vrf") or ""}
|
|
|
|
async def node_fabric(request: Request, inputs: dict[str, Any]) -> dict[str, Any]:
|
|
await require_node(request, str(values(inputs)["node"]))
|
|
fabric = str(values(inputs)["fabric"])
|
|
return await fabric_get(request, {"values": {"id": fabric}, "provided": frozenset()})
|
|
|
|
async def node_fabric_interfaces(
|
|
request: Request, inputs: dict[str, Any]
|
|
) -> list[dict[str, Any]]:
|
|
await require_node(request, str(values(inputs)["node"]))
|
|
fabric = str(values(inputs)["fabric"])
|
|
_metadata, sdn = await _load(request, for_write=True)
|
|
nodes = (sdn.get("fabric_nodes") or {}).get(fabric) or {}
|
|
result = []
|
|
for node_id, item in nodes.items():
|
|
ifaces = item.get("interfaces") or []
|
|
if isinstance(ifaces, str):
|
|
ifaces = [part.strip() for part in ifaces.split(",") if part.strip()]
|
|
for iface in ifaces:
|
|
result.append({"node": node_id, "iface": iface})
|
|
return result
|
|
|
|
async def node_fabric_neighbors(
|
|
request: Request, inputs: dict[str, Any]
|
|
) -> list[dict[str, Any]]:
|
|
await require_node(request, str(values(inputs)["node"]))
|
|
fabric = str(values(inputs)["fabric"])
|
|
_metadata, sdn = await _load(request)
|
|
nodes = (sdn.get("fabric_nodes") or {}).get(fabric) or {}
|
|
return [
|
|
{
|
|
"node": node_id,
|
|
"state": item.get("state") if isinstance(item, dict) else "",
|
|
}
|
|
for node_id, item in sorted(nodes.items())
|
|
]
|
|
|
|
async def node_fabric_routes(request: Request, inputs: dict[str, Any]) -> list[dict[str, Any]]:
|
|
await require_node(request, str(values(inputs)["node"]))
|
|
fabric = str(values(inputs)["fabric"])
|
|
_metadata, sdn = await _load(request)
|
|
item = (sdn.get("fabrics") or {}).get(fabric) or {}
|
|
routes = item.get("routes") if isinstance(item, dict) else None
|
|
if isinstance(routes, list):
|
|
return [dict(route) for route in routes if isinstance(route, dict)]
|
|
return []
|
|
|
|
# registrations
|
|
registry.register("/cluster/sdn", "GET", index)
|
|
registry.register("/cluster/sdn", "PUT", apply)
|
|
registry.register("/cluster/sdn/lock", "POST", lock_create)
|
|
registry.register("/cluster/sdn/lock", "DELETE", lock_delete)
|
|
registry.register("/cluster/sdn/rollback", "POST", rollback)
|
|
registry.register("/cluster/sdn/dry-run", "GET", dry_run)
|
|
registry.register("/cluster/sdn/ipams/{ipam}/status", "GET", ipam_status)
|
|
|
|
registry.register("/cluster/sdn/vnets", "GET", vnets_list)
|
|
registry.register("/cluster/sdn/vnets", "POST", vnets_create)
|
|
registry.register("/cluster/sdn/vnets/{vnet}", "GET", vnet_get)
|
|
registry.register("/cluster/sdn/vnets/{vnet}", "PUT", vnet_update)
|
|
registry.register("/cluster/sdn/vnets/{vnet}", "DELETE", vnet_delete)
|
|
registry.register("/cluster/sdn/vnets/{vnet}/subnets", "GET", subnets_list)
|
|
registry.register("/cluster/sdn/vnets/{vnet}/subnets", "POST", subnets_create)
|
|
registry.register("/cluster/sdn/vnets/{vnet}/subnets/{subnet}", "GET", subnet_get)
|
|
registry.register("/cluster/sdn/vnets/{vnet}/subnets/{subnet}", "PUT", subnet_update)
|
|
registry.register("/cluster/sdn/vnets/{vnet}/subnets/{subnet}", "DELETE", subnet_delete)
|
|
registry.register("/cluster/sdn/vnets/{vnet}/ips", "POST", ips_create)
|
|
registry.register("/cluster/sdn/vnets/{vnet}/ips", "PUT", ips_update)
|
|
registry.register("/cluster/sdn/vnets/{vnet}/ips", "DELETE", ips_delete)
|
|
registry.register("/cluster/sdn/vnets/{vnet}/firewall", "GET", fw_index)
|
|
registry.register("/cluster/sdn/vnets/{vnet}/firewall/options", "GET", fw_options_get)
|
|
registry.register("/cluster/sdn/vnets/{vnet}/firewall/options", "PUT", fw_options_put)
|
|
registry.register("/cluster/sdn/vnets/{vnet}/firewall/rules", "GET", fw_rules_list)
|
|
registry.register("/cluster/sdn/vnets/{vnet}/firewall/rules", "POST", fw_rules_create)
|
|
registry.register("/cluster/sdn/vnets/{vnet}/firewall/rules/{pos}", "GET", fw_rule_get)
|
|
registry.register("/cluster/sdn/vnets/{vnet}/firewall/rules/{pos}", "PUT", fw_rule_update)
|
|
registry.register("/cluster/sdn/vnets/{vnet}/firewall/rules/{pos}", "DELETE", fw_rule_delete)
|
|
|
|
registry.register("/cluster/sdn/fabrics", "GET", fabrics_index)
|
|
registry.register("/cluster/sdn/fabrics/all", "GET", fabrics_all)
|
|
registry.register("/cluster/sdn/fabrics/fabric", "GET", fabric_list)
|
|
registry.register("/cluster/sdn/fabrics/fabric", "POST", fabric_create)
|
|
registry.register("/cluster/sdn/fabrics/fabric/{id}", "GET", fabric_get)
|
|
registry.register("/cluster/sdn/fabrics/fabric/{id}", "PUT", fabric_update)
|
|
registry.register("/cluster/sdn/fabrics/fabric/{id}", "DELETE", fabric_delete)
|
|
registry.register("/cluster/sdn/fabrics/node", "GET", fabric_nodes_list)
|
|
registry.register("/cluster/sdn/fabrics/node/{fabric_id}", "GET", fabric_nodes_list)
|
|
registry.register("/cluster/sdn/fabrics/node/{fabric_id}", "POST", fabric_node_create)
|
|
registry.register("/cluster/sdn/fabrics/node/{fabric_id}/{node_id}", "GET", fabric_node_get)
|
|
registry.register("/cluster/sdn/fabrics/node/{fabric_id}/{node_id}", "PUT", fabric_node_update)
|
|
registry.register(
|
|
"/cluster/sdn/fabrics/node/{fabric_id}/{node_id}", "DELETE", fabric_node_delete
|
|
)
|
|
|
|
registry.register("/cluster/sdn/prefix-lists", "GET", prefix_list)
|
|
registry.register("/cluster/sdn/prefix-lists", "POST", prefix_create)
|
|
registry.register("/cluster/sdn/prefix-lists/{id}", "GET", prefix_get)
|
|
registry.register("/cluster/sdn/prefix-lists/{id}", "PUT", prefix_update)
|
|
registry.register("/cluster/sdn/prefix-lists/{id}", "DELETE", prefix_delete)
|
|
registry.register("/cluster/sdn/prefix-lists/{id}/entries", "GET", prefix_entries)
|
|
registry.register("/cluster/sdn/prefix-lists/{id}/entries", "POST", prefix_entry_create)
|
|
registry.register("/cluster/sdn/prefix-lists/{id}/entries/{url_seq}", "GET", prefix_entry_get)
|
|
registry.register(
|
|
"/cluster/sdn/prefix-lists/{id}/entries/{url_seq}", "PUT", prefix_entry_update
|
|
)
|
|
registry.register(
|
|
"/cluster/sdn/prefix-lists/{id}/entries/{url_seq}", "DELETE", prefix_entry_delete
|
|
)
|
|
|
|
registry.register("/cluster/sdn/route-maps", "GET", route_maps_index)
|
|
registry.register("/cluster/sdn/route-maps/entries", "GET", route_entries_list)
|
|
registry.register("/cluster/sdn/route-maps/entries", "POST", route_entry_create)
|
|
registry.register("/cluster/sdn/route-maps/entries/{route-map-id}", "GET", route_map_entries)
|
|
registry.register(
|
|
"/cluster/sdn/route-maps/entries/{route-map-id}/entry/{order}",
|
|
"GET",
|
|
route_entry_get,
|
|
)
|
|
registry.register(
|
|
"/cluster/sdn/route-maps/entries/{route-map-id}/entry/{order}",
|
|
"PUT",
|
|
route_entry_update,
|
|
)
|
|
registry.register(
|
|
"/cluster/sdn/route-maps/entries/{route-map-id}/entry/{order}",
|
|
"DELETE",
|
|
route_entry_delete,
|
|
)
|
|
|
|
registry.register("/nodes/{node}/sdn", "GET", node_sdn_index)
|
|
registry.register("/nodes/{node}/sdn/zones", "GET", node_zones)
|
|
registry.register("/nodes/{node}/sdn/zones/{zone}", "GET", node_zone)
|
|
registry.register("/nodes/{node}/sdn/zones/{zone}/bridges", "GET", node_zone_bridges)
|
|
registry.register("/nodes/{node}/sdn/zones/{zone}/content", "GET", node_zone_content)
|
|
registry.register("/nodes/{node}/sdn/zones/{zone}/ip-vrf", "GET", node_zone_ip_vrf)
|
|
registry.register("/nodes/{node}/sdn/vnets/{vnet}", "GET", node_vnet)
|
|
registry.register("/nodes/{node}/sdn/vnets/{vnet}/mac-vrf", "GET", node_vnet_mac_vrf)
|
|
registry.register("/nodes/{node}/sdn/fabrics/{fabric}", "GET", node_fabric)
|
|
registry.register(
|
|
"/nodes/{node}/sdn/fabrics/{fabric}/interfaces", "GET", node_fabric_interfaces
|
|
)
|
|
registry.register("/nodes/{node}/sdn/fabrics/{fabric}/neighbors", "GET", node_fabric_neighbors)
|
|
registry.register("/nodes/{node}/sdn/fabrics/{fabric}/routes", "GET", node_fabric_routes)
|