Loading src/service/service/ServiceServiceServicerImpl.py +19 −2 Original line number Diff line number Diff line Loading @@ -55,6 +55,21 @@ LOGGER = logging.getLogger(__name__) METRICS_POOL = MetricsPool('Service', 'RPC') def _load_opticalcontroller_reply(reply_txt : str) -> Dict: try: reply_json = json.loads(reply_txt) except json.JSONDecodeError as exc: raise OperationFailedException( 'optical-controller-reply', extra_details='reply={:s}'.format(str(reply_txt)) ) from exc if not isinstance(reply_json, dict): raise OperationFailedException( 'optical-controller-reply', extra_details='reply={:s}'.format(str(reply_txt)) ) return reply_json class ServiceServiceServicerImpl(ServiceServiceServicer): def __init__(self, service_handler_factory : ServiceHandlerFactory) -> None: Loading Loading @@ -350,7 +365,9 @@ class ServiceServiceServicerImpl(ServiceServiceServicer): spectrum_reservation=spectrum_reservation ) elif oc_type == 2: reply_txt = add_lightpath(src, dst, bitrate, bidir) reply_txt = add_lightpath( src, dst, bitrate, bidir, spectrum_reservation=spectrum_reservation ) else: reply_txt = add_flex_lightpath( src, dst, bitrate, bidir, preferred, ob_band, dj_optical_band_id, Loading @@ -358,7 +375,7 @@ class ServiceServiceServicerImpl(ServiceServiceServicer): ) if reply_txt is None: return service_with_uuids.service_id reply_json = json.loads(reply_txt) reply_json = _load_opticalcontroller_reply(reply_txt) LOGGER.debug('[optical] reply_json[{:s}]={:s}'.format(str(type(reply_json)), str(reply_json))) optical_band_txt = "" Loading src/service/service/tools/OpticalTools.py +17 −1 Original line number Diff line number Diff line Loading @@ -189,7 +189,7 @@ def add_alien_flex_lightpath(src, s_port, dst, d_port, band, ob_id, bidir=None) reply = r.text return reply def add_lightpath(src, dst, bitrate, bidir) -> str: def add_lightpath(src, dst, bitrate, bidir, spectrum_reservation: Optional[Dict] = None) -> str: if not TESTING: urlx = "" headers = {"Content-Type": "application/json"} Loading @@ -197,6 +197,13 @@ def add_lightpath(src, dst, bitrate, bidir) -> str: if bidir is None: bidir = 1 urlx = "{:s}/AddLightpath/{:s}/{:s}/{:s}/{:s}".format(base_url, src, dst, str(bitrate), str(bidir)) if spectrum_reservation is not None: query = { 'reservation_band': spectrum_reservation['band'], 'reservation_start': str(spectrum_reservation['n_start']), 'reservation_end': str(spectrum_reservation['n_end']), } urlx = '{:s}?{:s}'.format(urlx, urlencode(query)) r = requests.put(urlx, headers=headers) LOGGER.debug(f"addpathlight {r}") reply = r.text Loading Loading @@ -541,6 +548,9 @@ def adapt_reply( op_mode = r["op-mode"] if "op-mode" in r else None frequency = r["freq"] if "freq" in r else None flow_id = r["flow_id"] if "flow_id" in r else None slots = r["slots"] if "slots" in r else None links = r["links"] if "links" in r else None path = r["path"] if "path" in r else None r_type = r["band_type"] if "band_type" in r else None if r_type == "l_slots": band_type = "L_BAND" Loading @@ -553,6 +563,12 @@ def adapt_reply( val = {"target-output-power": "1.0", "frequency": frequency, "operational-mode": op_mode, "band": band, "flow_id": flow_id, "ob_id": ob_id, "band_type": band_type, "bidir": bidir_f} else: val = {"target-output-power": "1.0", "frequency": frequency, "operational-mode": op_mode, "band": band, "flow_id": flow_id, "band_type": band_type, "bidir": bidir_f} if slots is not None: val["slots"] = slots if links is not None: val["links"] = links if path is not None: val["path"] = path custom_rule = ConfigRule_Custom(resource_key="/settings", resource_value=json.dumps(val)) rule = ConfigRule(action=ConfigActionEnum.CONFIGACTION_SET, custom=custom_rule) service.service_config.config_rules.add().CopyFrom(rule) Loading src/service/tests/test_optical_spectrum_reservation.py +29 −0 Original line number Diff line number Diff line Loading @@ -72,3 +72,32 @@ def test_add_flex_lightpath_forwards_reservation_query(monkeypatch): assert "reservation_band=c_slots" in captured["url"] assert "reservation_start=51" in captured["url"] assert "reservation_end=66" in captured["url"] def test_add_lightpath_forwards_reservation_query(monkeypatch): captured = {} class Response: text = "{}" def put(url, headers=None): captured["url"] = url captured["headers"] = headers return Response() monkeypatch.setattr(OpticalTools, "get_optical_controller_base_url", lambda: "http://optical/OpticalTFS") monkeypatch.setattr(OpticalTools.requests, "put", put) monkeypatch.setattr(OpticalTools, "TESTING", False) OpticalTools.add_lightpath( "T1", "T2", 100, 0, spectrum_reservation={"band": "c_slots", "n_start": 51, "n_end": 66}, ) assert captured["url"].startswith("http://optical/OpticalTFS/AddLightpath/T1/T2/100/0?") assert "reservation_band=c_slots" in captured["url"] assert "reservation_start=51" in captured["url"] assert "reservation_end=66" in captured["url"] Loading
src/service/service/ServiceServiceServicerImpl.py +19 −2 Original line number Diff line number Diff line Loading @@ -55,6 +55,21 @@ LOGGER = logging.getLogger(__name__) METRICS_POOL = MetricsPool('Service', 'RPC') def _load_opticalcontroller_reply(reply_txt : str) -> Dict: try: reply_json = json.loads(reply_txt) except json.JSONDecodeError as exc: raise OperationFailedException( 'optical-controller-reply', extra_details='reply={:s}'.format(str(reply_txt)) ) from exc if not isinstance(reply_json, dict): raise OperationFailedException( 'optical-controller-reply', extra_details='reply={:s}'.format(str(reply_txt)) ) return reply_json class ServiceServiceServicerImpl(ServiceServiceServicer): def __init__(self, service_handler_factory : ServiceHandlerFactory) -> None: Loading Loading @@ -350,7 +365,9 @@ class ServiceServiceServicerImpl(ServiceServiceServicer): spectrum_reservation=spectrum_reservation ) elif oc_type == 2: reply_txt = add_lightpath(src, dst, bitrate, bidir) reply_txt = add_lightpath( src, dst, bitrate, bidir, spectrum_reservation=spectrum_reservation ) else: reply_txt = add_flex_lightpath( src, dst, bitrate, bidir, preferred, ob_band, dj_optical_band_id, Loading @@ -358,7 +375,7 @@ class ServiceServiceServicerImpl(ServiceServiceServicer): ) if reply_txt is None: return service_with_uuids.service_id reply_json = json.loads(reply_txt) reply_json = _load_opticalcontroller_reply(reply_txt) LOGGER.debug('[optical] reply_json[{:s}]={:s}'.format(str(type(reply_json)), str(reply_json))) optical_band_txt = "" Loading
src/service/service/tools/OpticalTools.py +17 −1 Original line number Diff line number Diff line Loading @@ -189,7 +189,7 @@ def add_alien_flex_lightpath(src, s_port, dst, d_port, band, ob_id, bidir=None) reply = r.text return reply def add_lightpath(src, dst, bitrate, bidir) -> str: def add_lightpath(src, dst, bitrate, bidir, spectrum_reservation: Optional[Dict] = None) -> str: if not TESTING: urlx = "" headers = {"Content-Type": "application/json"} Loading @@ -197,6 +197,13 @@ def add_lightpath(src, dst, bitrate, bidir) -> str: if bidir is None: bidir = 1 urlx = "{:s}/AddLightpath/{:s}/{:s}/{:s}/{:s}".format(base_url, src, dst, str(bitrate), str(bidir)) if spectrum_reservation is not None: query = { 'reservation_band': spectrum_reservation['band'], 'reservation_start': str(spectrum_reservation['n_start']), 'reservation_end': str(spectrum_reservation['n_end']), } urlx = '{:s}?{:s}'.format(urlx, urlencode(query)) r = requests.put(urlx, headers=headers) LOGGER.debug(f"addpathlight {r}") reply = r.text Loading Loading @@ -541,6 +548,9 @@ def adapt_reply( op_mode = r["op-mode"] if "op-mode" in r else None frequency = r["freq"] if "freq" in r else None flow_id = r["flow_id"] if "flow_id" in r else None slots = r["slots"] if "slots" in r else None links = r["links"] if "links" in r else None path = r["path"] if "path" in r else None r_type = r["band_type"] if "band_type" in r else None if r_type == "l_slots": band_type = "L_BAND" Loading @@ -553,6 +563,12 @@ def adapt_reply( val = {"target-output-power": "1.0", "frequency": frequency, "operational-mode": op_mode, "band": band, "flow_id": flow_id, "ob_id": ob_id, "band_type": band_type, "bidir": bidir_f} else: val = {"target-output-power": "1.0", "frequency": frequency, "operational-mode": op_mode, "band": band, "flow_id": flow_id, "band_type": band_type, "bidir": bidir_f} if slots is not None: val["slots"] = slots if links is not None: val["links"] = links if path is not None: val["path"] = path custom_rule = ConfigRule_Custom(resource_key="/settings", resource_value=json.dumps(val)) rule = ConfigRule(action=ConfigActionEnum.CONFIGACTION_SET, custom=custom_rule) service.service_config.config_rules.add().CopyFrom(rule) Loading
src/service/tests/test_optical_spectrum_reservation.py +29 −0 Original line number Diff line number Diff line Loading @@ -72,3 +72,32 @@ def test_add_flex_lightpath_forwards_reservation_query(monkeypatch): assert "reservation_band=c_slots" in captured["url"] assert "reservation_start=51" in captured["url"] assert "reservation_end=66" in captured["url"] def test_add_lightpath_forwards_reservation_query(monkeypatch): captured = {} class Response: text = "{}" def put(url, headers=None): captured["url"] = url captured["headers"] = headers return Response() monkeypatch.setattr(OpticalTools, "get_optical_controller_base_url", lambda: "http://optical/OpticalTFS") monkeypatch.setattr(OpticalTools.requests, "put", put) monkeypatch.setattr(OpticalTools, "TESTING", False) OpticalTools.add_lightpath( "T1", "T2", 100, 0, spectrum_reservation={"band": "c_slots", "n_start": 51, "n_end": 66}, ) assert captured["url"].startswith("http://optical/OpticalTFS/AddLightpath/T1/T2/100/0?") assert "reservation_band=c_slots" in captured["url"] assert "reservation_start=51" in captured["url"] assert "reservation_end=66" in captured["url"]