"""API endpoints for network related operations.""" import ipaddress from uuid import UUID from fastapi import APIRouter from orchestrator.domain import SubscriptionModel from orchestrator.schemas.base import OrchestratorBaseModel from orchestrator.services.subscriptions import build_extended_domain_model from starlette import status from gso.products.product_blocks.iptrunk import IptrunkType, PhysicalPortCapacity from gso.products.product_blocks.router import RouterRole from gso.products.product_blocks.site import LatitudeCoordinate, LongitudeCoordinate from gso.services.subscriptions import get_active_iptrunk_subscriptions from gso.utils.shared_enums import Vendor router = APIRouter(prefix="/networks", tags=["Network"]) class SiteBlock(OrchestratorBaseModel): """Site block schema.""" site_name: str site_city: str site_country: str site_latitude: LatitudeCoordinate site_longitude: LongitudeCoordinate site_internal_id: int class RouterBlock(OrchestratorBaseModel): """Router block schema.""" subscription_instance_id: UUID router_fqdn: str router_access_via_ts: bool router_lo_ipv4_address: ipaddress.IPv4Address router_lo_ipv6_address: ipaddress.IPv6Address router_lo_iso_address: str router_role: RouterRole vendor: Vendor router_site: SiteBlock class IptrunkSideBlock(OrchestratorBaseModel): """Iptrunk side block schema.""" subscription_instance_id: UUID iptrunk_side_node: RouterBlock class IptrunkBlock(OrchestratorBaseModel): """Iptrunk block schema.""" subscription_instance_id: UUID iptrunk_speed: PhysicalPortCapacity iptrunk_type: IptrunkType iptrunk_ipv4_network: ipaddress.IPv4Network iptrunk_ipv6_network: ipaddress.IPv6Network iptrunk_capacity: str iptrunk_isis_metric: int iptrunk_sides: list[IptrunkSideBlock] class IptrunkSchema(OrchestratorBaseModel): """Iptrunk schema.""" subscription_id: UUID insync: bool iptrunk: IptrunkBlock class NetworkTopologyDomainModelSchema(OrchestratorBaseModel): """Network topology domain model schema.""" iptrunks: list[IptrunkSchema] def _calculate_iptrunk_capacity(iptrunk_sides: list, iptrunk_speed: PhysicalPortCapacity) -> str: """Calculate the total capacity of an IP trunk.""" int_iptrunk_speed = int(iptrunk_speed.value.replace("G", "")) capacity = int_iptrunk_speed * len(iptrunk_sides[0]["iptrunk_side_ae_members"]) return f"{capacity}G" @router.get("/topology", status_code=status.HTTP_200_OK, response_model=NetworkTopologyDomainModelSchema) def network_topology() -> NetworkTopologyDomainModelSchema: """Retrieve the network topology.""" topology: dict = {"iptrunks": []} active_iptrunks = get_active_iptrunk_subscriptions() for iptrunk in active_iptrunks: subscription = SubscriptionModel.from_subscription(iptrunk["subscription_id"]) extended_model = build_extended_domain_model(subscription) formatted_model = { "subscription_id": extended_model["subscription_id"], "insync": extended_model["insync"], "iptrunk": { "subscription_instance_id": extended_model["iptrunk"]["subscription_instance_id"], "iptrunk_speed": extended_model["iptrunk"]["iptrunk_speed"], "iptrunk_type": extended_model["iptrunk"]["iptrunk_type"], "iptrunk_ipv4_network": extended_model["iptrunk"]["iptrunk_ipv4_network"], "iptrunk_ipv6_network": extended_model["iptrunk"]["iptrunk_ipv6_network"], "iptrunk_isis_metric": extended_model["iptrunk"]["iptrunk_isis_metric"], "iptrunk_capacity": _calculate_iptrunk_capacity( extended_model["iptrunk"]["iptrunk_sides"], extended_model["iptrunk"]["iptrunk_speed"] ), "iptrunk_sides": [ { "subscription_instance_id": side["subscription_instance_id"], "iptrunk_side_node": { "subscription_instance_id": side["iptrunk_side_node"]["subscription_instance_id"], "router_fqdn": side["iptrunk_side_node"]["router_fqdn"], "router_access_via_ts": side["iptrunk_side_node"]["router_access_via_ts"], "router_lo_ipv4_address": side["iptrunk_side_node"]["router_lo_ipv4_address"], "router_lo_ipv6_address": side["iptrunk_side_node"]["router_lo_ipv6_address"], "router_lo_iso_address": side["iptrunk_side_node"]["router_lo_iso_address"], "router_role": side["iptrunk_side_node"]["router_role"], "vendor": side["iptrunk_side_node"]["vendor"], "router_site": side["iptrunk_side_node"]["router_site"], }, } for side in extended_model["iptrunk"]["iptrunk_sides"] ], }, } topology["iptrunks"].append(IptrunkSchema(**formatted_model)) return NetworkTopologyDomainModelSchema(**topology)