Loading src/service/service/service_handlers/__init__.py +7 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ from .l2nm_openconfig.L2NMOpenConfigServiceHandler import L2NMOpenConfigServiceH from .l3nm_emulated.L3NMEmulatedServiceHandler import L3NMEmulatedServiceHandler from .l3nm_openconfig.L3NMOpenConfigServiceHandler import L3NMOpenConfigServiceHandler from .l3nm_gnmi_openconfig.L3NMGnmiOpenConfigServiceHandler import L3NMGnmiOpenConfigServiceHandler from .l3nm_ietf_actn.L3NMIetfActnServiceHandler import L3NMIetfActnServiceHandler from .microwave.MicrowaveServiceHandler import MicrowaveServiceHandler from .p4.p4_service_handler import P4ServiceHandler from .tapi_tapi.TapiServiceHandler import TapiServiceHandler Loading Loading @@ -57,6 +58,12 @@ SERVICE_HANDLERS = [ FilterFieldEnum.DEVICE_DRIVER : DeviceDriverEnum.DEVICEDRIVER_GNMI_OPENCONFIG, } ]), (L3NMIetfActnServiceHandler, [ { FilterFieldEnum.SERVICE_TYPE : ServiceTypeEnum.SERVICETYPE_L3NM, FilterFieldEnum.DEVICE_DRIVER : DeviceDriverEnum.DEVICEDRIVER_IETF_ACTN, } ]), (TapiServiceHandler, [ { FilterFieldEnum.SERVICE_TYPE : ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE, Loading src/service/service/service_handlers/l3nm_ietf_actn/ConfigRuleComposer.py 0 → 100644 +128 −0 Original line number Diff line number Diff line # Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from typing import Dict, List, Optional, Tuple from common.proto.context_pb2 import Device, EndPoint from common.tools.object_factory.ConfigRule import json_config_rule_delete, json_config_rule_set from service.service.service_handler_api.AnyTreeTools import TreeNode def _interface( if_name : str, ipv4_address : str, ipv4_prefix_length : int, enabled : bool, vlan_id : Optional[int] = None, sif_index : Optional[int] = 1 ) -> Tuple[str, Dict]: str_path = '/interface[{:s}]'.format(if_name) data = { 'name': if_name, 'enabled': enabled, 'sub_if_index': sif_index, 'sub_if_enabled': enabled, 'sub_if_ipv4_enabled': enabled, 'sub_if_ipv4_address': ipv4_address, 'sub_if_ipv4_prefix_length': ipv4_prefix_length } if vlan_id is not None: data['sub_if_vlan'] = vlan_id return str_path, data def _network_instance(ni_name, ni_type) -> Tuple[str, Dict]: str_path = '/network_instance[{:s}]'.format(ni_name) data = {'name': ni_name, 'type': ni_type} return str_path, data def _network_instance_static_route(ni_name, prefix, next_hop, next_hop_index=0) -> Tuple[str, Dict]: str_path = '/network_instance[{:s}]/static_route[{:s}]'.format(ni_name, prefix) data = {'name': ni_name, 'prefix': prefix, 'next_hop': next_hop, 'next_hop_index': next_hop_index} return str_path, data def _network_instance_interface(ni_name, if_name, sif_index) -> Tuple[str, Dict]: str_path = '/network_instance[{:s}]/interface[{:s}.{:d}]'.format(ni_name, if_name, sif_index) data = {'name': ni_name, 'if_name': if_name, 'sif_index': sif_index} return str_path, data class EndpointComposer: def __init__(self, endpoint_uuid : str) -> None: self.uuid = endpoint_uuid self.objekt : Optional[EndPoint] = None self.sub_interface_index = 0 self.ipv4_address = None self.ipv4_prefix_length = None self.sub_interface_vlan_id = 0 def configure(self, endpoint_obj : EndPoint, settings : Optional[TreeNode]) -> None: self.objekt = endpoint_obj if settings is None: return json_settings : Dict = settings.value self.ipv4_address = json_settings['ipv4_address'] self.ipv4_prefix_length = json_settings['ipv4_prefix_length'] self.sub_interface_index = json_settings['sub_interface_index'] self.sub_interface_vlan_id = json_settings['sub_interface_vlan_id'] def get_config_rules(self, network_instance_name : str, delete : bool = False) -> List[Dict]: json_config_rule = json_config_rule_delete if delete else json_config_rule_set return [ json_config_rule(*_interface( self.objekt.name, self.ipv4_address, self.ipv4_prefix_length, True, sif_index=self.sub_interface_index, vlan_id=self.sub_interface_vlan_id, )), json_config_rule(*_network_instance_interface( network_instance_name, self.objekt.name, self.sub_interface_index )), ] class DeviceComposer: def __init__(self, device_uuid : str) -> None: self.uuid = device_uuid self.objekt : Optional[Device] = None self.endpoints : Dict[str, EndpointComposer] = dict() self.static_routes : Dict[str, str] = dict() def get_endpoint(self, endpoint_uuid : str) -> EndpointComposer: if endpoint_uuid not in self.endpoints: self.endpoints[endpoint_uuid] = EndpointComposer(endpoint_uuid) return self.endpoints[endpoint_uuid] def configure(self, device_obj : Device, settings : Optional[TreeNode]) -> None: self.objekt = device_obj if settings is None: return json_settings : Dict = settings.value static_routes = json_settings.get('static_routes', []) for static_route in static_routes: prefix = static_route['prefix'] next_hop = static_route['next_hop'] self.static_routes[prefix] = next_hop def get_config_rules(self, network_instance_name : str, delete : bool = False) -> List[Dict]: json_config_rule = json_config_rule_delete if delete else json_config_rule_set config_rules = [ json_config_rule(*_network_instance(network_instance_name, 'L3VRF')) ] for endpoint in self.endpoints.values(): config_rules.extend(endpoint.get_config_rules(network_instance_name, delete=delete)) for prefix, next_hop in self.static_routes.items(): config_rules.append( json_config_rule(*_network_instance_static_route(network_instance_name, prefix, next_hop)) ) if delete: config_rules = list(reversed(config_rules)) return config_rules class ConfigRuleComposer: def __init__(self) -> None: self.devices : Dict[str, DeviceComposer] = dict() def get_device(self, device_uuid : str) -> DeviceComposer: if device_uuid not in self.devices: self.devices[device_uuid] = DeviceComposer(device_uuid) return self.devices[device_uuid] def get_config_rules(self, network_instance_name : str, delete : bool = False) -> Dict[str, List[Dict]]: return { device_uuid : device.get_config_rules(network_instance_name, delete=delete) for device_uuid, device in self.devices.items() } src/service/service/service_handlers/l3nm_ietf_actn/L3NMIetfActnServiceHandler.py 0 → 100644 +161 −0 Original line number Diff line number Diff line # Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import json, logging from typing import Any, Dict, List, Optional, Tuple, Union from common.method_wrappers.Decorator import MetricsPool, metered_subclass_method from common.proto.context_pb2 import ConfigRule, DeviceId, Service from common.tools.object_factory.Device import json_device_id from common.type_checkers.Checkers import chk_type from service.service.service_handler_api.Tools import get_device_endpoint_uuids, get_endpoint_matching from service.service.service_handler_api._ServiceHandler import _ServiceHandler from service.service.service_handler_api.SettingsHandler import SettingsHandler from service.service.task_scheduler.TaskExecutor import TaskExecutor from .ConfigRuleComposer import ConfigRuleComposer LOGGER = logging.getLogger(__name__) METRICS_POOL = MetricsPool('Service', 'Handler', labels={'handler': 'l3nm_ietf_actn'}) class L3NMIetfActnServiceHandler(_ServiceHandler): def __init__( # pylint: disable=super-init-not-called self, service : Service, task_executor : TaskExecutor, **settings ) -> None: self.__service = service self.__task_executor = task_executor self.__settings_handler = SettingsHandler(service.service_config, **settings) self.__composer = ConfigRuleComposer() self.__endpoint_map : Dict[Tuple[str, str], str] = dict() def _compose_config_rules(self, endpoints : List[Tuple[str, str, Optional[str]]]) -> None: for endpoint in endpoints: device_uuid, endpoint_uuid = get_device_endpoint_uuids(endpoint) device_obj = self.__task_executor.get_device(DeviceId(**json_device_id(device_uuid))) device_settings = self.__settings_handler.get_device_settings(device_obj) _device = self.__composer.get_device(device_obj.name) _device.configure(device_obj, device_settings) endpoint_obj = get_endpoint_matching(device_obj, endpoint_uuid) endpoint_settings = self.__settings_handler.get_endpoint_settings(device_obj, endpoint_obj) _endpoint = _device.get_endpoint(endpoint_obj.name) _endpoint.configure(endpoint_obj, endpoint_settings) self.__endpoint_map[(device_uuid, endpoint_uuid)] = device_obj.name def _do_configurations( self, config_rules_per_device : Dict[str, List[Dict]], endpoints : List[Tuple[str, str, Optional[str]]], delete : bool = False ) -> List[Union[bool, Exception]]: # Configuration is done atomically on each device, all OK / all KO per device results_per_device = dict() for device_name,json_config_rules in config_rules_per_device.items(): try: device_obj = self.__composer.get_device(device_name).objekt if len(json_config_rules) == 0: continue del device_obj.device_config.config_rules[:] for json_config_rule in json_config_rules: device_obj.device_config.config_rules.append(ConfigRule(**json_config_rule)) self.__task_executor.configure_device(device_obj) results_per_device[device_name] = True except Exception as e: # pylint: disable=broad-exception-caught verb = 'deconfigure' if delete else 'configure' MSG = 'Unable to {:s} Device({:s}) : ConfigRules({:s})' LOGGER.exception(MSG.format(verb, str(device_name), str(json_config_rules))) results_per_device[device_name] = e results = [] for endpoint in endpoints: device_uuid, endpoint_uuid = get_device_endpoint_uuids(endpoint) device_name = self.__endpoint_map[(device_uuid, endpoint_uuid)] results.append(results_per_device[device_name]) return results @metered_subclass_method(METRICS_POOL) def SetEndpoint( self, endpoints : List[Tuple[str, str, Optional[str]]], connection_uuid : Optional[str] = None ) -> List[Union[bool, Exception]]: chk_type('endpoints', endpoints, list) if len(endpoints) == 0: return [] service_uuid = self.__service.service_id.service_uuid.uuid #settings = self.__settings_handler.get('/settings') self._compose_config_rules(endpoints) network_instance_name = service_uuid.split('-')[0] config_rules_per_device = self.__composer.get_config_rules(network_instance_name, delete=False) results = self._do_configurations(config_rules_per_device, endpoints) return results @metered_subclass_method(METRICS_POOL) def DeleteEndpoint( self, endpoints : List[Tuple[str, str, Optional[str]]], connection_uuid : Optional[str] = None ) -> List[Union[bool, Exception]]: chk_type('endpoints', endpoints, list) if len(endpoints) == 0: return [] service_uuid = self.__service.service_id.service_uuid.uuid #settings = self.__settings_handler.get('/settings') self._compose_config_rules(endpoints) network_instance_name = service_uuid.split('-')[0] config_rules_per_device = self.__composer.get_config_rules(network_instance_name, delete=True) results = self._do_configurations(config_rules_per_device, endpoints, delete=True) return results @metered_subclass_method(METRICS_POOL) def SetConstraint(self, constraints : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]: chk_type('constraints', constraints, list) if len(constraints) == 0: return [] msg = '[SetConstraint] Method not implemented. Constraints({:s}) are being ignored.' LOGGER.warning(msg.format(str(constraints))) return [True for _ in range(len(constraints))] @metered_subclass_method(METRICS_POOL) def DeleteConstraint(self, constraints : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]: chk_type('constraints', constraints, list) if len(constraints) == 0: return [] msg = '[DeleteConstraint] Method not implemented. Constraints({:s}) are being ignored.' LOGGER.warning(msg.format(str(constraints))) return [True for _ in range(len(constraints))] @metered_subclass_method(METRICS_POOL) def SetConfig(self, resources : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]: chk_type('resources', resources, list) if len(resources) == 0: return [] results = [] for resource in resources: try: resource_value = json.loads(resource[1]) self.__settings_handler.set(resource[0], resource_value) results.append(True) except Exception as e: # pylint: disable=broad-except LOGGER.exception('Unable to SetConfig({:s})'.format(str(resource))) results.append(e) return results @metered_subclass_method(METRICS_POOL) def DeleteConfig(self, resources : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]: chk_type('resources', resources, list) if len(resources) == 0: return [] results = [] for resource in resources: try: self.__settings_handler.delete(resource[0]) except Exception as e: # pylint: disable=broad-except LOGGER.exception('Unable to DeleteConfig({:s})'.format(str(resource))) results.append(e) return results src/service/service/service_handlers/l3nm_ietf_actn/__init__.py 0 → 100644 +14 −0 Original line number Diff line number Diff line # Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. Loading
src/service/service/service_handlers/__init__.py +7 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ from .l2nm_openconfig.L2NMOpenConfigServiceHandler import L2NMOpenConfigServiceH from .l3nm_emulated.L3NMEmulatedServiceHandler import L3NMEmulatedServiceHandler from .l3nm_openconfig.L3NMOpenConfigServiceHandler import L3NMOpenConfigServiceHandler from .l3nm_gnmi_openconfig.L3NMGnmiOpenConfigServiceHandler import L3NMGnmiOpenConfigServiceHandler from .l3nm_ietf_actn.L3NMIetfActnServiceHandler import L3NMIetfActnServiceHandler from .microwave.MicrowaveServiceHandler import MicrowaveServiceHandler from .p4.p4_service_handler import P4ServiceHandler from .tapi_tapi.TapiServiceHandler import TapiServiceHandler Loading Loading @@ -57,6 +58,12 @@ SERVICE_HANDLERS = [ FilterFieldEnum.DEVICE_DRIVER : DeviceDriverEnum.DEVICEDRIVER_GNMI_OPENCONFIG, } ]), (L3NMIetfActnServiceHandler, [ { FilterFieldEnum.SERVICE_TYPE : ServiceTypeEnum.SERVICETYPE_L3NM, FilterFieldEnum.DEVICE_DRIVER : DeviceDriverEnum.DEVICEDRIVER_IETF_ACTN, } ]), (TapiServiceHandler, [ { FilterFieldEnum.SERVICE_TYPE : ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE, Loading
src/service/service/service_handlers/l3nm_ietf_actn/ConfigRuleComposer.py 0 → 100644 +128 −0 Original line number Diff line number Diff line # Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from typing import Dict, List, Optional, Tuple from common.proto.context_pb2 import Device, EndPoint from common.tools.object_factory.ConfigRule import json_config_rule_delete, json_config_rule_set from service.service.service_handler_api.AnyTreeTools import TreeNode def _interface( if_name : str, ipv4_address : str, ipv4_prefix_length : int, enabled : bool, vlan_id : Optional[int] = None, sif_index : Optional[int] = 1 ) -> Tuple[str, Dict]: str_path = '/interface[{:s}]'.format(if_name) data = { 'name': if_name, 'enabled': enabled, 'sub_if_index': sif_index, 'sub_if_enabled': enabled, 'sub_if_ipv4_enabled': enabled, 'sub_if_ipv4_address': ipv4_address, 'sub_if_ipv4_prefix_length': ipv4_prefix_length } if vlan_id is not None: data['sub_if_vlan'] = vlan_id return str_path, data def _network_instance(ni_name, ni_type) -> Tuple[str, Dict]: str_path = '/network_instance[{:s}]'.format(ni_name) data = {'name': ni_name, 'type': ni_type} return str_path, data def _network_instance_static_route(ni_name, prefix, next_hop, next_hop_index=0) -> Tuple[str, Dict]: str_path = '/network_instance[{:s}]/static_route[{:s}]'.format(ni_name, prefix) data = {'name': ni_name, 'prefix': prefix, 'next_hop': next_hop, 'next_hop_index': next_hop_index} return str_path, data def _network_instance_interface(ni_name, if_name, sif_index) -> Tuple[str, Dict]: str_path = '/network_instance[{:s}]/interface[{:s}.{:d}]'.format(ni_name, if_name, sif_index) data = {'name': ni_name, 'if_name': if_name, 'sif_index': sif_index} return str_path, data class EndpointComposer: def __init__(self, endpoint_uuid : str) -> None: self.uuid = endpoint_uuid self.objekt : Optional[EndPoint] = None self.sub_interface_index = 0 self.ipv4_address = None self.ipv4_prefix_length = None self.sub_interface_vlan_id = 0 def configure(self, endpoint_obj : EndPoint, settings : Optional[TreeNode]) -> None: self.objekt = endpoint_obj if settings is None: return json_settings : Dict = settings.value self.ipv4_address = json_settings['ipv4_address'] self.ipv4_prefix_length = json_settings['ipv4_prefix_length'] self.sub_interface_index = json_settings['sub_interface_index'] self.sub_interface_vlan_id = json_settings['sub_interface_vlan_id'] def get_config_rules(self, network_instance_name : str, delete : bool = False) -> List[Dict]: json_config_rule = json_config_rule_delete if delete else json_config_rule_set return [ json_config_rule(*_interface( self.objekt.name, self.ipv4_address, self.ipv4_prefix_length, True, sif_index=self.sub_interface_index, vlan_id=self.sub_interface_vlan_id, )), json_config_rule(*_network_instance_interface( network_instance_name, self.objekt.name, self.sub_interface_index )), ] class DeviceComposer: def __init__(self, device_uuid : str) -> None: self.uuid = device_uuid self.objekt : Optional[Device] = None self.endpoints : Dict[str, EndpointComposer] = dict() self.static_routes : Dict[str, str] = dict() def get_endpoint(self, endpoint_uuid : str) -> EndpointComposer: if endpoint_uuid not in self.endpoints: self.endpoints[endpoint_uuid] = EndpointComposer(endpoint_uuid) return self.endpoints[endpoint_uuid] def configure(self, device_obj : Device, settings : Optional[TreeNode]) -> None: self.objekt = device_obj if settings is None: return json_settings : Dict = settings.value static_routes = json_settings.get('static_routes', []) for static_route in static_routes: prefix = static_route['prefix'] next_hop = static_route['next_hop'] self.static_routes[prefix] = next_hop def get_config_rules(self, network_instance_name : str, delete : bool = False) -> List[Dict]: json_config_rule = json_config_rule_delete if delete else json_config_rule_set config_rules = [ json_config_rule(*_network_instance(network_instance_name, 'L3VRF')) ] for endpoint in self.endpoints.values(): config_rules.extend(endpoint.get_config_rules(network_instance_name, delete=delete)) for prefix, next_hop in self.static_routes.items(): config_rules.append( json_config_rule(*_network_instance_static_route(network_instance_name, prefix, next_hop)) ) if delete: config_rules = list(reversed(config_rules)) return config_rules class ConfigRuleComposer: def __init__(self) -> None: self.devices : Dict[str, DeviceComposer] = dict() def get_device(self, device_uuid : str) -> DeviceComposer: if device_uuid not in self.devices: self.devices[device_uuid] = DeviceComposer(device_uuid) return self.devices[device_uuid] def get_config_rules(self, network_instance_name : str, delete : bool = False) -> Dict[str, List[Dict]]: return { device_uuid : device.get_config_rules(network_instance_name, delete=delete) for device_uuid, device in self.devices.items() }
src/service/service/service_handlers/l3nm_ietf_actn/L3NMIetfActnServiceHandler.py 0 → 100644 +161 −0 Original line number Diff line number Diff line # Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import json, logging from typing import Any, Dict, List, Optional, Tuple, Union from common.method_wrappers.Decorator import MetricsPool, metered_subclass_method from common.proto.context_pb2 import ConfigRule, DeviceId, Service from common.tools.object_factory.Device import json_device_id from common.type_checkers.Checkers import chk_type from service.service.service_handler_api.Tools import get_device_endpoint_uuids, get_endpoint_matching from service.service.service_handler_api._ServiceHandler import _ServiceHandler from service.service.service_handler_api.SettingsHandler import SettingsHandler from service.service.task_scheduler.TaskExecutor import TaskExecutor from .ConfigRuleComposer import ConfigRuleComposer LOGGER = logging.getLogger(__name__) METRICS_POOL = MetricsPool('Service', 'Handler', labels={'handler': 'l3nm_ietf_actn'}) class L3NMIetfActnServiceHandler(_ServiceHandler): def __init__( # pylint: disable=super-init-not-called self, service : Service, task_executor : TaskExecutor, **settings ) -> None: self.__service = service self.__task_executor = task_executor self.__settings_handler = SettingsHandler(service.service_config, **settings) self.__composer = ConfigRuleComposer() self.__endpoint_map : Dict[Tuple[str, str], str] = dict() def _compose_config_rules(self, endpoints : List[Tuple[str, str, Optional[str]]]) -> None: for endpoint in endpoints: device_uuid, endpoint_uuid = get_device_endpoint_uuids(endpoint) device_obj = self.__task_executor.get_device(DeviceId(**json_device_id(device_uuid))) device_settings = self.__settings_handler.get_device_settings(device_obj) _device = self.__composer.get_device(device_obj.name) _device.configure(device_obj, device_settings) endpoint_obj = get_endpoint_matching(device_obj, endpoint_uuid) endpoint_settings = self.__settings_handler.get_endpoint_settings(device_obj, endpoint_obj) _endpoint = _device.get_endpoint(endpoint_obj.name) _endpoint.configure(endpoint_obj, endpoint_settings) self.__endpoint_map[(device_uuid, endpoint_uuid)] = device_obj.name def _do_configurations( self, config_rules_per_device : Dict[str, List[Dict]], endpoints : List[Tuple[str, str, Optional[str]]], delete : bool = False ) -> List[Union[bool, Exception]]: # Configuration is done atomically on each device, all OK / all KO per device results_per_device = dict() for device_name,json_config_rules in config_rules_per_device.items(): try: device_obj = self.__composer.get_device(device_name).objekt if len(json_config_rules) == 0: continue del device_obj.device_config.config_rules[:] for json_config_rule in json_config_rules: device_obj.device_config.config_rules.append(ConfigRule(**json_config_rule)) self.__task_executor.configure_device(device_obj) results_per_device[device_name] = True except Exception as e: # pylint: disable=broad-exception-caught verb = 'deconfigure' if delete else 'configure' MSG = 'Unable to {:s} Device({:s}) : ConfigRules({:s})' LOGGER.exception(MSG.format(verb, str(device_name), str(json_config_rules))) results_per_device[device_name] = e results = [] for endpoint in endpoints: device_uuid, endpoint_uuid = get_device_endpoint_uuids(endpoint) device_name = self.__endpoint_map[(device_uuid, endpoint_uuid)] results.append(results_per_device[device_name]) return results @metered_subclass_method(METRICS_POOL) def SetEndpoint( self, endpoints : List[Tuple[str, str, Optional[str]]], connection_uuid : Optional[str] = None ) -> List[Union[bool, Exception]]: chk_type('endpoints', endpoints, list) if len(endpoints) == 0: return [] service_uuid = self.__service.service_id.service_uuid.uuid #settings = self.__settings_handler.get('/settings') self._compose_config_rules(endpoints) network_instance_name = service_uuid.split('-')[0] config_rules_per_device = self.__composer.get_config_rules(network_instance_name, delete=False) results = self._do_configurations(config_rules_per_device, endpoints) return results @metered_subclass_method(METRICS_POOL) def DeleteEndpoint( self, endpoints : List[Tuple[str, str, Optional[str]]], connection_uuid : Optional[str] = None ) -> List[Union[bool, Exception]]: chk_type('endpoints', endpoints, list) if len(endpoints) == 0: return [] service_uuid = self.__service.service_id.service_uuid.uuid #settings = self.__settings_handler.get('/settings') self._compose_config_rules(endpoints) network_instance_name = service_uuid.split('-')[0] config_rules_per_device = self.__composer.get_config_rules(network_instance_name, delete=True) results = self._do_configurations(config_rules_per_device, endpoints, delete=True) return results @metered_subclass_method(METRICS_POOL) def SetConstraint(self, constraints : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]: chk_type('constraints', constraints, list) if len(constraints) == 0: return [] msg = '[SetConstraint] Method not implemented. Constraints({:s}) are being ignored.' LOGGER.warning(msg.format(str(constraints))) return [True for _ in range(len(constraints))] @metered_subclass_method(METRICS_POOL) def DeleteConstraint(self, constraints : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]: chk_type('constraints', constraints, list) if len(constraints) == 0: return [] msg = '[DeleteConstraint] Method not implemented. Constraints({:s}) are being ignored.' LOGGER.warning(msg.format(str(constraints))) return [True for _ in range(len(constraints))] @metered_subclass_method(METRICS_POOL) def SetConfig(self, resources : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]: chk_type('resources', resources, list) if len(resources) == 0: return [] results = [] for resource in resources: try: resource_value = json.loads(resource[1]) self.__settings_handler.set(resource[0], resource_value) results.append(True) except Exception as e: # pylint: disable=broad-except LOGGER.exception('Unable to SetConfig({:s})'.format(str(resource))) results.append(e) return results @metered_subclass_method(METRICS_POOL) def DeleteConfig(self, resources : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]: chk_type('resources', resources, list) if len(resources) == 0: return [] results = [] for resource in resources: try: self.__settings_handler.delete(resource[0]) except Exception as e: # pylint: disable=broad-except LOGGER.exception('Unable to DeleteConfig({:s})'.format(str(resource))) results.append(e) return results
src/service/service/service_handlers/l3nm_ietf_actn/__init__.py 0 → 100644 +14 −0 Original line number Diff line number Diff line # Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License.