Loading src/opticalcontroller/OpticalController.py +61 −18 Changes for src/opticalcontroller/OpticalController.py: 61 added lines, 18 removed lines. Original line number Diff line number Diff line Loading @@ -50,7 +50,8 @@ from opticalcontroller.RSA_P2MP import RSA_P2MP from common.tools.object_factory.Context import json_context_id from common.tools.object_factory.Topology import json_topology_id from common.Constants import OpticalServiceType, DEFAULT_CONTEXT_NAME, DEFAULT_TOPOLOGY_NAME from common.Constants import OpticalServiceType, DEFAULT_CONTEXT_NAME, DEFAULT_TOPOLOGY_NAME, ServiceNameEnum from common.Settings import get_service_host, get_service_port_http from context.client.ContextClient import ContextClient Loading Loading @@ -1732,31 +1733,43 @@ class TapiClient: topology source inside ComputeP2MP._create_tapi_connectivity_response, see the `topology_raw` fallback there). NOTE: topology_extract()/read_DSC_only() below talk to a HARDCODED external HTTP address (http://10.30.7.65/tfs-api/... and http://deviceservice:10065/...) via plain `requests` calls, instead of going through ContextClient/DeviceClient like the rest of this file. That IP is specific to whichever deployment this was last pointed at -- if TAPI topology retrieval breaks after moving to a different cluster/ demo rig, this hardcoded address is almost certainly why.""" topology_extract()/read_DSC_only() below talk to the NBI service's plain REST API (the same '/tfs-api/...' surface used by nbi/service/tfs_api) and to DeviceService's subcarrier-groups endpoint via plain `requests` calls, instead of going through ContextClient/DeviceClient like the rest of this file. Both addresses are resolved automatically at construction time (see __init__ below) via the exact same env-var/service-discovery convention every gRPC client in this file already relies on (ContextClient, KpiManagerClient, ...) -- get_service_host()/get_service_port_http() read the NBISERVICE_SERVICE_HOST / NBISERVICE_SERVICE_PORT_HTTP variables Kubernetes injects into every pod for the "nbiservice" Service, falling back to the in-cluster DNS name "nbiservice" and its default port 8080 if those aren't set for some reason. This used to be a hardcoded LAN IP (10.30.7.65) specific to one physical machine -- moving this demo to a different host/cluster silently broke TAPI topology retrieval until someone edited this file by hand to point it at the new machine's IP. Resolving it this way instead means the exact same image/code runs unmodified on any TFS deployment, on any host.""" def __init__(self): self.headers = { 'Content-Type': 'application/json', 'Accept': 'application/json' } nbi_host = get_service_host(ServiceNameEnum.NBI) nbi_port = get_service_port_http(ServiceNameEnum.NBI) self.nbi_base_url = f"http://{nbi_host}:{nbi_port}/tfs-api" def topology_extract(self): try: # Get topology data topo_resp = requests.get('http://10.30.7.65/tfs-api/context/admin/topologies') topo_resp = requests.get(f'{self.nbi_base_url}/context/admin/topologies') topo_data = topo_resp.json() topology = topo_data['topologies'][0] # Get device UUIDs devices_uuid_data = requests.get('http://10.30.7.65/tfs-api/device_ids') devices_uuid_data = requests.get(f'{self.nbi_base_url}/device_ids') device_uuids = devices_uuid_data.json().get('device_ids', []) # Build nodes for all devices Loading @@ -1767,7 +1780,7 @@ class TapiClient: device_uuid = device_uuid_data['device_uuid']['uuid'] # Get device details for each UUID device_resp = requests.get(f'http://10.30.7.65/tfs-api/device/{device_uuid}') device_resp = requests.get(f'{self.nbi_base_url}/device/{device_uuid}') device_info = device_resp.json() device_name = device_info.get('name', '') Loading Loading @@ -1862,16 +1875,46 @@ class TapiClient: def read_DSC_only(self) -> dict: base_url = "http://deviceservice:10065" # "deviceservice" is already the in-cluster DNS name (not a raw IP), # so this already runs unmodified on any host -- resolved via # get_service_host() anyway for consistency with nbi_base_url above. # Port 10065 is this demo's own custom subcarrier_groups HTTP port # (not part of TFS's generic per-service port registry in # common.Constants, so there's no get_service_port_http() default # for it to fall back on); override via DEVICESERVICE_SUBCARRIER_PORT # if a deployment ever needs a different one. device_host = get_service_host(ServiceNameEnum.DEVICE) device_port = os.environ.get('DEVICESERVICE_SUBCARRIER_PORT', '10065') base_url = f"http://{device_host}:{device_port}" urlx = f"{base_url}/OpticalTFS/subcarrier_groups" #print(f"DSC URL: {urlx}") # This endpoint (device/service/drivers/oc_driver/readSupport.py) is # NOT started at deviceservice's own startup -- its Flask server is # only spun up lazily, on a background thread, the first time # send_subcarrier_groups() (Tools.py) actually has real subcarrier # data to publish, i.e. only after at least one device's OC driver # has polled it at least once. Before that ever happens (freshly # deployed cluster, or simply no devices added/connected yet), this # port is legitimately not listening at all -- that's the normal, # expected state, not a fault. Treat it as the optional, # best-effort enrichment source it actually is (topology_extract # only ever does a plain dict .get()/`in` lookup against the # result) rather than letting a connection failure here take down # the entire /tapi-topology:get-topology response: return {} (no # DSC enrichment available yet) instead of raising. headers = {"Content-Type": "application/json"} r = requests.get(urlx, headers=headers, timeout=500) try: r = requests.get(urlx, headers=headers, timeout=10) r.raise_for_status() response_data = r.json() except requests.exceptions.RequestException as e: LOGGER.warning( "read_DSC_only: subcarrier_groups API at %s is not reachable yet " "(%s) -- likely no device has been polled for subcarrier data " "since deviceservice last started. Returning no DSC data instead " "of failing the whole topology request.", urlx, e, ) return {} # Group by device and channel grouped_response = {} Loading src/webui/service/templates/main/home.html +1 −1 Changes for src/webui/service/templates/main/home.html: 1 added line, 1 removed line. Original line number Diff line number Diff line Loading @@ -17,7 +17,7 @@ {% extends 'base.html' %} {% block content %} <h2>ETSI TeraFlowSDN Controller</h2> <h2>ETSI TeraFlowSDN Controller (Optical SDN Controller)</h2> <style> #topology { border: 1px solid #b5b5b5; Loading Loading
src/opticalcontroller/OpticalController.py +61 −18 Changes for src/opticalcontroller/OpticalController.py: 61 added lines, 18 removed lines. Original line number Diff line number Diff line Loading @@ -50,7 +50,8 @@ from opticalcontroller.RSA_P2MP import RSA_P2MP from common.tools.object_factory.Context import json_context_id from common.tools.object_factory.Topology import json_topology_id from common.Constants import OpticalServiceType, DEFAULT_CONTEXT_NAME, DEFAULT_TOPOLOGY_NAME from common.Constants import OpticalServiceType, DEFAULT_CONTEXT_NAME, DEFAULT_TOPOLOGY_NAME, ServiceNameEnum from common.Settings import get_service_host, get_service_port_http from context.client.ContextClient import ContextClient Loading Loading @@ -1732,31 +1733,43 @@ class TapiClient: topology source inside ComputeP2MP._create_tapi_connectivity_response, see the `topology_raw` fallback there). NOTE: topology_extract()/read_DSC_only() below talk to a HARDCODED external HTTP address (http://10.30.7.65/tfs-api/... and http://deviceservice:10065/...) via plain `requests` calls, instead of going through ContextClient/DeviceClient like the rest of this file. That IP is specific to whichever deployment this was last pointed at -- if TAPI topology retrieval breaks after moving to a different cluster/ demo rig, this hardcoded address is almost certainly why.""" topology_extract()/read_DSC_only() below talk to the NBI service's plain REST API (the same '/tfs-api/...' surface used by nbi/service/tfs_api) and to DeviceService's subcarrier-groups endpoint via plain `requests` calls, instead of going through ContextClient/DeviceClient like the rest of this file. Both addresses are resolved automatically at construction time (see __init__ below) via the exact same env-var/service-discovery convention every gRPC client in this file already relies on (ContextClient, KpiManagerClient, ...) -- get_service_host()/get_service_port_http() read the NBISERVICE_SERVICE_HOST / NBISERVICE_SERVICE_PORT_HTTP variables Kubernetes injects into every pod for the "nbiservice" Service, falling back to the in-cluster DNS name "nbiservice" and its default port 8080 if those aren't set for some reason. This used to be a hardcoded LAN IP (10.30.7.65) specific to one physical machine -- moving this demo to a different host/cluster silently broke TAPI topology retrieval until someone edited this file by hand to point it at the new machine's IP. Resolving it this way instead means the exact same image/code runs unmodified on any TFS deployment, on any host.""" def __init__(self): self.headers = { 'Content-Type': 'application/json', 'Accept': 'application/json' } nbi_host = get_service_host(ServiceNameEnum.NBI) nbi_port = get_service_port_http(ServiceNameEnum.NBI) self.nbi_base_url = f"http://{nbi_host}:{nbi_port}/tfs-api" def topology_extract(self): try: # Get topology data topo_resp = requests.get('http://10.30.7.65/tfs-api/context/admin/topologies') topo_resp = requests.get(f'{self.nbi_base_url}/context/admin/topologies') topo_data = topo_resp.json() topology = topo_data['topologies'][0] # Get device UUIDs devices_uuid_data = requests.get('http://10.30.7.65/tfs-api/device_ids') devices_uuid_data = requests.get(f'{self.nbi_base_url}/device_ids') device_uuids = devices_uuid_data.json().get('device_ids', []) # Build nodes for all devices Loading @@ -1767,7 +1780,7 @@ class TapiClient: device_uuid = device_uuid_data['device_uuid']['uuid'] # Get device details for each UUID device_resp = requests.get(f'http://10.30.7.65/tfs-api/device/{device_uuid}') device_resp = requests.get(f'{self.nbi_base_url}/device/{device_uuid}') device_info = device_resp.json() device_name = device_info.get('name', '') Loading Loading @@ -1862,16 +1875,46 @@ class TapiClient: def read_DSC_only(self) -> dict: base_url = "http://deviceservice:10065" # "deviceservice" is already the in-cluster DNS name (not a raw IP), # so this already runs unmodified on any host -- resolved via # get_service_host() anyway for consistency with nbi_base_url above. # Port 10065 is this demo's own custom subcarrier_groups HTTP port # (not part of TFS's generic per-service port registry in # common.Constants, so there's no get_service_port_http() default # for it to fall back on); override via DEVICESERVICE_SUBCARRIER_PORT # if a deployment ever needs a different one. device_host = get_service_host(ServiceNameEnum.DEVICE) device_port = os.environ.get('DEVICESERVICE_SUBCARRIER_PORT', '10065') base_url = f"http://{device_host}:{device_port}" urlx = f"{base_url}/OpticalTFS/subcarrier_groups" #print(f"DSC URL: {urlx}") # This endpoint (device/service/drivers/oc_driver/readSupport.py) is # NOT started at deviceservice's own startup -- its Flask server is # only spun up lazily, on a background thread, the first time # send_subcarrier_groups() (Tools.py) actually has real subcarrier # data to publish, i.e. only after at least one device's OC driver # has polled it at least once. Before that ever happens (freshly # deployed cluster, or simply no devices added/connected yet), this # port is legitimately not listening at all -- that's the normal, # expected state, not a fault. Treat it as the optional, # best-effort enrichment source it actually is (topology_extract # only ever does a plain dict .get()/`in` lookup against the # result) rather than letting a connection failure here take down # the entire /tapi-topology:get-topology response: return {} (no # DSC enrichment available yet) instead of raising. headers = {"Content-Type": "application/json"} r = requests.get(urlx, headers=headers, timeout=500) try: r = requests.get(urlx, headers=headers, timeout=10) r.raise_for_status() response_data = r.json() except requests.exceptions.RequestException as e: LOGGER.warning( "read_DSC_only: subcarrier_groups API at %s is not reachable yet " "(%s) -- likely no device has been polled for subcarrier data " "since deviceservice last started. Returning no DSC data instead " "of failing the whole topology request.", urlx, e, ) return {} # Group by device and channel grouped_response = {} Loading
src/webui/service/templates/main/home.html +1 −1 Changes for src/webui/service/templates/main/home.html: 1 added line, 1 removed line. Original line number Diff line number Diff line Loading @@ -17,7 +17,7 @@ {% extends 'base.html' %} {% block content %} <h2>ETSI TeraFlowSDN Controller</h2> <h2>ETSI TeraFlowSDN Controller (Optical SDN Controller)</h2> <style> #topology { border: 1px solid #b5b5b5; Loading