diff --git a/proto/context.proto b/proto/context.proto index 42bf00dff98598fac10febd1ca80c070cd1a4a13..86b6855bd08dd0de3438c9374d0e84ee5cd8207c 100644 --- a/proto/context.proto +++ b/proto/context.proto @@ -77,17 +77,19 @@ service ContextService { // ------------------------------ Experimental ----------------------------- - rpc GetOpticalConfig (Empty ) returns ( OpticalConfigList ) {} - rpc SetOpticalConfig (OpticalConfig ) returns ( OpticalConfigId ) {} - rpc UpdateOpticalConfig (OpticalConfig ) returns ( OpticalConfigId ) {} - rpc SelectOpticalConfig(OpticalConfigId ) returns ( OpticalConfig ) {} - rpc DeleteOpticalConfig(OpticalConfigId ) returns ( Empty ) {} - rpc DeleteOpticalChannel(OpticalConfig ) returns ( Empty ) {} - - rpc SetOpticalLink (OpticalLink ) returns ( Empty ) {} - rpc GetOpticalLink (LinkId ) returns ( OpticalLink ) {} - rpc DeleteOpticalLink (LinkId ) returns ( Empty ) {} - rpc GetOpticalLinkList (Empty ) returns ( OpticalLinkList ) {} + rpc GetOpticalConfig (Empty ) returns ( OpticalConfigList ) {} + rpc SetOpticalConfig (OpticalConfig ) returns ( OpticalConfigId ) {} + rpc UpdateOpticalConfig (OpticalConfig ) returns ( OpticalConfigId ) {} + rpc SelectOpticalConfig (OpticalConfigId ) returns ( OpticalConfig ) {} + rpc DeleteOpticalConfig (OpticalConfigId ) returns ( Empty ) {} + rpc DeleteOpticalChannel (OpticalConfig ) returns ( Empty ) {} + + rpc SetOpticalLink (OpticalLink ) returns ( Empty ) {} + rpc GetOpticalLink (LinkId ) returns ( OpticalLink ) {} + rpc DeleteOpticalLink (LinkId ) returns ( Empty ) {} + rpc GetOpticalLinkList (Empty ) returns ( OpticalLinkList ) {} + + rpc DeleteServiceConfigRule (ServiceConfigRule ) returns ( Empty ) {} } // ----- Generic ------------------------------------------------------------------------------------------------------- @@ -687,3 +689,12 @@ message OpticalLink { LinkId link_id = 3; repeated EndPointId link_endpoint_ids=4; } + + + +////////////////// Config Rule Delete //////////// + +message ServiceConfigRule { + ServiceId service_id =1; + ConfigRule_Custom configrule_custom =2; +} \ No newline at end of file diff --git a/src/context/Dockerfile b/src/context/Dockerfile index 18a7fbc54788d70724716b3f0b5b532de3e7054b..28bc427c57af41a5a42ddfd9b37bcdd944d8c77d 100644 --- a/src/context/Dockerfile +++ b/src/context/Dockerfile @@ -15,8 +15,12 @@ FROM python:3.9-slim # Install dependencies -RUN apt-get --yes --quiet --quiet update && \ - apt-get --yes --quiet --quiet install wget g++ git && \ +# RUN apt-get --yes --quiet --quiet update && \ +# apt-get --yes --quiet --quiet install wget g++ git && \ +# rm -rf /var/lib/apt/lists/* + +RUN apt-get --yes update && \ + apt-get --yes install wget g++ git && \ rm -rf /var/lib/apt/lists/* # Set Python to show logs as they occur diff --git a/src/context/client/ContextClient.py b/src/context/client/ContextClient.py index e30885529fbf2ea2ca1556500463628e8045b062..41ad49138b63ca5c8e87dc174ab872c833fcb539 100644 --- a/src/context/client/ContextClient.py +++ b/src/context/client/ContextClient.py @@ -27,7 +27,7 @@ from common.proto.context_pb2 import ( Service, ServiceEvent, ServiceFilter, ServiceId, ServiceIdList, ServiceList, Slice, SliceEvent, SliceFilter, SliceId, SliceIdList, SliceList, Topology, TopologyDetails, TopologyEvent, TopologyId, TopologyIdList, TopologyList, - OpticalConfig, OpticalConfigId, OpticalConfigList , OpticalLink ,OpticalLinkList + OpticalConfig, OpticalConfigId, OpticalConfigList , OpticalLink ,OpticalLinkList,ServiceConfigRule ) from common.proto.context_pb2_grpc import ContextServiceStub from common.proto.context_policy_pb2_grpc import ContextPolicyServiceStub @@ -510,4 +510,14 @@ class ContextClient: LOGGER.debug('RemoveOpticalLink request: {:s}'.format(grpc_message_to_json_string(request))) response = self.stub.DeleteOpticalLink(request) LOGGER.debug('RemoveOpticalLink result: {:s}'.format(grpc_message_to_json_string(response))) + return response + + + # --------------------------------- Service ConfigRule Deletion ------------------ + + @RETRY_DECORATOR + def DeleteServiceConfigRule(self, request: ServiceConfigRule) -> Empty: + LOGGER.debug('ServiceConfigRule Delete request: {:s}'.format(grpc_message_to_json_string(request))) + response = self.stub.DeleteServiceConfigRule(request) + LOGGER.debug('ServiceConfigRule Delete result: {:s}'.format(grpc_message_to_json_string(response))) return response \ No newline at end of file diff --git a/src/context/service/ContextServiceServicerImpl.py b/src/context/service/ContextServiceServicerImpl.py index 5ac319c291a331a675a24b7c216caa6c8aa11e8c..6317fcf72c025b5c97c074a6adbcd96fae7cfcd6 100644 --- a/src/context/service/ContextServiceServicerImpl.py +++ b/src/context/service/ContextServiceServicerImpl.py @@ -25,6 +25,7 @@ from common.proto.context_pb2 import ( Slice, SliceEvent, SliceFilter, SliceId, SliceIdList, SliceList, Topology, TopologyDetails, TopologyEvent, TopologyId, TopologyIdList, TopologyList, OpticalConfigList, OpticalConfigId, OpticalConfig ,OpticalLink , OpticalLinkList, + ServiceConfigRule ) from common.proto.policy_pb2 import PolicyRuleIdList, PolicyRuleId, PolicyRuleList, PolicyRule from common.proto.context_pb2_grpc import ContextServiceServicer @@ -49,6 +50,7 @@ from .database.OpticalConfig import (set_opticalconfig, select_opticalconfig, ge ,delete_opticalconfig ,update_opticalconfig ,delete_opticalchannel ) from .database.OpticalLink import optical_link_delete,optical_link_get,optical_link_list_objs,optical_link_set +from .database.ConfigRule import delete_config_rule LOGGER = logging.getLogger(__name__) METRICS_POOL = MetricsPool('Context', 'RPC') @@ -358,3 +360,8 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer def DeleteOpticalLink(self, request : LinkId, context : grpc.ServicerContext) -> Empty: return optical_link_delete(self.db_engine, self.messagebroker, request) + + @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) + def DeleteServiceConfigRule(self, request : ServiceConfigRule, context : grpc.ServicerContext) -> Empty: + + return delete_config_rule(self.db_engine, request) diff --git a/src/context/service/database/ConfigRule.py b/src/context/service/database/ConfigRule.py index c5b259a2dfc2ba684f6881dfb2a9a79b3a36032a..0ae61f84f2ca67b0eddf05010566902177ad7329 100644 --- a/src/context/service/database/ConfigRule.py +++ b/src/context/service/database/ConfigRule.py @@ -17,14 +17,17 @@ from sqlalchemy import delete #from sqlalchemy.dialects import postgresql from sqlalchemy.dialects.postgresql import insert from sqlalchemy.orm import Session +from sqlalchemy.engine import Engine from typing import Dict, List, Optional, Set -from common.proto.context_pb2 import ConfigRule +from common.proto.context_pb2 import ConfigRule ,ServiceId ,ServiceConfigRule ,Empty from common.tools.grpc.Tools import grpc_message_to_json_string from .models.enums.ConfigAction import ORM_ConfigActionEnum, grpc_to_enum__config_action from .models.ConfigRuleModel import ( ConfigRuleKindEnum, DeviceConfigRuleModel, ServiceConfigRuleModel, SliceConfigRuleModel) from .uuids._Builder import get_uuid_from_string from .uuids.EndPoint import endpoint_get_uuid +from sqlalchemy_cockroachdb import run_transaction +from sqlalchemy.orm import Session, selectinload, sessionmaker LOGGER = logging.getLogger(__name__) @@ -33,8 +36,10 @@ def compose_config_rules_data( device_uuid : Optional[str] = None, service_uuid : Optional[str] = None, slice_uuid : Optional[str] = None ) -> List[Dict]: dict_config_rules : List[Dict] = list() + for position,config_rule in enumerate(config_rules): str_kind = config_rule.WhichOneof('config_rule') + kind = ConfigRuleKindEnum._member_map_.get(str_kind.upper()) # pylint: disable=no-member dict_config_rule = { 'position' : position, @@ -63,6 +68,7 @@ def compose_config_rules_data( configrule_name = None if kind == ConfigRuleKindEnum.CUSTOM: + configrule_name = '{:s}:{:s}:{:s}'.format(parent_kind, kind.value, config_rule.custom.resource_key) elif kind == ConfigRuleKindEnum.ACL: _, _, endpoint_uuid = endpoint_get_uuid(config_rule.acl.endpoint_id, allow_random=False) @@ -149,3 +155,25 @@ def upsert_config_rules( upsert_affected = any([(updated_at > created_at) for created_at,updated_at in configrule_updates]) return delete_affected or upsert_affected + + +def delete_config_rule (db_engine : Engine,request:ServiceConfigRule): + + config_rule=request.configrule_custom + service_id= request.service_id + parent_uuid = service_id.service_uuid.uuid + configrule_name = 'service:custom:{:s}'.format( config_rule.resource_key) + configrule_uuid = get_uuid_from_string(configrule_name, prefix_for_name=parent_uuid) + + + def callback(session : Session) -> bool: + + num_deleted = session.query(ServiceConfigRuleModel).filter_by(configrule_uuid=configrule_uuid).delete() + return num_deleted > 0 + + deleted = run_transaction(sessionmaker(bind=db_engine), callback) + + return Empty() + + + \ No newline at end of file diff --git a/src/opticalcontroller/OpticalController.py b/src/opticalcontroller/OpticalController.py index d7b589b4307995e9f93a4ede804567d99501a3c1..fd2e07724d0b5ee10049b1d6b9f83a8d600d55cf 100644 --- a/src/opticalcontroller/OpticalController.py +++ b/src/opticalcontroller/OpticalController.py @@ -91,52 +91,143 @@ class AddFlexLightpath(Resource): return rsa.optical_bands[optical_band_id], 200 else: return "Error", 404 - -@optical.route('/DelFlexLightpath/<int:flow_id>/<string:src>/<string:dst>/<int:bitrate>/<int:o_band_id>') -@optical.route('/DelFlexLightpath/<int:flow_id>/<string:src>/<string:dst>/<int:bitrate>/<int:o_band_id>/<string:delete_band>') +# @optical.route('/DelFlexLightpath/<string:src>/<string:dst>/<int:bitrate>/<int:o_band_id>') +@optical.route('/DelFlexLightpath/<string:src>/<string:dst>/<int:bitrate>/<int:o_band_id>/<int:delete_band>') +@optical.route('/DelFlexLightpath/<string:src>/<string:dst>/<int:bitrate>/<int:o_band_id>/<int:delete_band>/<int:flow_id>') @optical.response(200, 'Success') @optical.response(404, 'Error, not found') class DelFLightpath(Resource): @staticmethod - def delete(flow_id, src, dst, bitrate, o_band_id,delete_band): - if flow_id in rsa.db_flows.keys(): - flow = rsa.db_flows[flow_id] - print(f"delete flexlightpath flow {flow}") - bidir = flow["bidir"] - match1 = flow["src"] == src and flow["dst"] == dst and flow["bitrate"] == bitrate - if bidir: - match2 = flow["src"] == dst and flow["dst"] == src and flow["bitrate"] == bitrate - if match1 or match2: - ob_id = flow["parent_opt_band"] - rsa.del_flow(flow, ob_id) - rsa.db_flows[flow_id]["is_active"] = False - if flow_id in rsa.optical_bands[ob_id]["served_lightpaths"].remove: - rsa.optical_bands[ob_id]["served_lightpaths"].remove(flow_id) - #if rsa.optical_bands[ob_id]["reverse_optical_band_id"] != 0: - # rev_ob_id = rsa.optical_bands[ob_id]["reverse_optical_band_id"] - # rsa.optical_bands[rev_ob_id]["served_lightpaths"].remove(flow_id) - - if debug: - print(rsa.links_dict) - return "flow {} deleted".format(flow_id), 200 + def delete( src, dst, bitrate, o_band_id,delete_band,flow_id=None): + flow = None + match1=False + ob_id=None + print(f"delete_lightpath {delete_band} and ob_id {ob_id} and flow_id {flow_id}") + if flow_id is not None: + + if flow_id in rsa.db_flows.keys(): + flow = rsa.db_flows[flow_id] + match1 = flow["src"] == src and flow["dst"] == dst and flow["bitrate"] == bitrate + ob_id = flow["parent_opt_band"] + else : + if o_band_id in rsa.db_flows.keys(): + flow=rsa.db_flows[o_band_id] + match1 = flow["src"] == src and flow["dst"] == dst and flow["bitrate"] == bitrate + ob_id=o_band_id + print(f"delete_lightpath {delete_band} and ob_id {ob_id}") + print(f"and flow {flow}") + if flow is not None: + + + bidir = flow["bidir"] + + if bidir: + match2 = flow["src"] == dst and flow["dst"] == src and flow["bitrate"] == bitrate + if match1 or match2: + ob_id = flow["parent_opt_band"] + rsa.del_flow(flow, ob_id) + rsa.db_flows[flow_id]["is_active"] = False + if flow_id in rsa.optical_bands[ob_id]["served_lightpaths"].remove: + rsa.optical_bands[ob_id]["served_lightpaths"].remove(flow_id) + #if rsa.optical_bands[ob_id]["reverse_optical_band_id"] != 0: + # rev_ob_id = rsa.optical_bands[ob_id]["reverse_optical_band_id"] + # rsa.optical_bands[rev_ob_id]["served_lightpaths"].remove(flow_id) + + if debug: + print(rsa.links_dict) + return "flow {} deleted".format(flow_id), 200 + else: + return "flow {} not matching".format(flow_id), 404 else: - return "flow {} not matching".format(flow_id), 404 - else: - if match1: - ob_id = flow["parent_opt_band"] - rsa.del_handler(flow,flow_id,ob_id,delete_band) - rsa.db_flows[flow_id]["is_active"] = False + if match1: + + if delete_band !=0 and ob_id is not None: + print(f"delete_lightpath {delete_band} and ob_id {ob_id}") + if len( rsa.optical_bands[ob_id]["served_lightpaths"]) != 0: + return "DELETE_NOT_ALLOWED" ,400 + + + rsa.del_handler(flow,flow_id,ob_id,delete_band) + + - - - if debug: - print(f"vor ob_id {ob_id} rsa.optical_bands {rsa.optical_bands[ob_id]}") - print(f"rsa.links_dict {rsa.links_dict}") - return "flow {} deleted".format(flow_id), 200 + if debug: + print(f"vor ob_id {ob_id} rsa.optical_bands {rsa.optical_bands[ob_id]}") + print(f"rsa.links_dict {rsa.links_dict}") + return "flow {} deleted".format(flow_id), 200 + else: + return "flow {} not matching".format(flow_id), 404 + else: + return "flow id {} does not exist".format(flow_id), 404 + + + + + +@optical.route('/DelOpticalBand/<string:src>/<string:dst>/<int:o_band_id>/<int:delete_band>') +@optical.response(200, 'Success') +@optical.response(404, 'Error, not found') +class DelOpticalBand(Resource): + @staticmethod + def delete( src, dst, bitrate, o_band_id,delete_band,flow_id=None): + flow = None + match1=False + ob_id=None + print(f"delete_lightpath {delete_band} and ob_id {ob_id} and flow_id {flow_id}") + + + if o_band_id in rsa.optical_bands.keys(): + flow=rsa.optical_bands[o_band_id] + match1 = flow["src"] == src and flow["dst"] == dst + ob_id=o_band_id + print(f"delete_lightpath {delete_band} and ob_id {ob_id}") + print(f"and flow {flow}") + if flow is not None: + + + bidir = flow["bidir"] + + if bidir: + match2 = flow["src"] == dst and flow["dst"] == src and flow["bitrate"] == bitrate + if match1 or match2: + ob_id = flow["parent_opt_band"] + rsa.del_flow(flow, ob_id) + rsa.db_flows[flow_id]["is_active"] = False + if flow_id in rsa.optical_bands[ob_id]["served_lightpaths"].remove: + rsa.optical_bands[ob_id]["served_lightpaths"].remove(flow_id) + #if rsa.optical_bands[ob_id]["reverse_optical_band_id"] != 0: + # rev_ob_id = rsa.optical_bands[ob_id]["reverse_optical_band_id"] + # rsa.optical_bands[rev_ob_id]["served_lightpaths"].remove(flow_id) + + if debug: + print(rsa.links_dict) + return "flow {} deleted".format(flow_id), 200 + else: + return "flow {} not matching".format(flow_id), 404 else: - return "flow {} not matching".format(flow_id), 404 - else: - return "flow id {} does not exist".format(flow_id), 404 + if match1: + + if ob_id is not None: + + if len( rsa.optical_bands[ob_id]["served_lightpaths"]) != 0: + return "DELETE_NOT_ALLOWED" ,400 + + rsa.del_band(flow,ob_id,delete_band) + + + + if debug: + print(f"vor ob_id {ob_id} rsa.optical_bands {rsa.optical_bands[ob_id]}") + print(f"rsa.links_dict {rsa.links_dict}") + return "flow {} deleted".format(flow_id), 200 + else: + return "flow {} not matching".format(flow_id), 404 + else: + return "flow id {} does not exist".format(flow_id), 404 + + + + diff --git a/src/opticalcontroller/RSA.py b/src/opticalcontroller/RSA.py index 0401c2535f71c69e4948b981ccc043f1cc51cccd..4730769197ee3a5f0fbb7651f0f7a1eaf0cd5f91 100644 --- a/src/opticalcontroller/RSA.py +++ b/src/opticalcontroller/RSA.py @@ -317,7 +317,7 @@ class RSA(): #update_optical_band(optical_bands=self.optical_bands,optical_band_id=optical_band_id,band=band,link=link) - def del_flow(self, flow, o_b_id = None): + def del_flow(self, flow,flow_id, o_b_id = None): flows = flow["flows"] band = flow["band_type"] slots = flow["slots"] @@ -350,6 +350,9 @@ class RSA(): self.restore_link(fib, slots, band) if debug: print(fib[band]) + + if flow_id in self.optical_bands[o_b_id]["served_lightpaths"]: + self.optical_bands[o_b_id]["served_lightpaths"].remove(flow_id) if o_b_id is not None: @@ -392,12 +395,12 @@ class RSA(): return True - def del_band(self, flow,flow_id, o_b_id = None): + def del_band(self, flow, o_b_id = None): print(f"delete band {flow} ") flows = flow["flows"] band = None - slots = flow["slots"] + #slots = flow["slots"] fiber_f = flow["fiber_forward"] fiber_b = flow["fiber_backward"] op = flow["op-mode"] @@ -425,8 +428,7 @@ class RSA(): print(f"invoking restore_link_2 fib: {fib} , slots {slots} , band {band} ") self.restore_link(fib, slots, band) self.optical_bands[o_b_id]["is_active"]=False - if flow_id in self.optical_bands[o_b_id]["served_lightpaths"]: - self.optical_bands[o_b_id]["served_lightpaths"].remove(flow_id) + if debug: print(fib[band]) @@ -471,13 +473,13 @@ class RSA(): return True - def del_handler(self, flow,flow_id, o_b_id = None,delete_band=False): + def del_handler(self, flow,flow_id, o_b_id = None,delete_band=0): print(f" del_handler flow {flow} flow_id {flow_id} o_b_id {o_b_id} delete_band {delete_band}") - if delete_band != 'False': + if delete_band != 0: print(f"delete band del_band") self.del_band(flow,flow_id,o_b_id=o_b_id) else : - self.del_flow(flow,o_b_id=o_b_id) + self.del_flow(flow,flow_id=flow_id,o_b_id=o_b_id) diff --git a/src/service/service/ServiceServiceServicerImpl.py b/src/service/service/ServiceServiceServicerImpl.py index dbda6ce6d7bd15220c987fa501a70b1148af1efe..ce64be9d3b25dc7bddc015e693d7b1cc9ef67a9e 100644 --- a/src/service/service/ServiceServiceServicerImpl.py +++ b/src/service/service/ServiceServiceServicerImpl.py @@ -343,6 +343,10 @@ class ServiceServiceServicerImpl(ServiceServiceServicer): if service is None: raise Exception('Service({:s}) not found'.format(grpc_message_to_json_string(request))) # pylint: disable=no-member service.service_status.service_status = ServiceStatusEnum.SERVICESTATUS_PENDING_REMOVAL + + if service.service_type == ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY: + service.service_status.service_status = ServiceStatusEnum.SERVICESTATUS_ACTIVE + context_client.SetService(service) if service.service_type == ServiceTypeEnum.SERVICETYPE_TE: @@ -384,6 +388,7 @@ class ServiceServiceServicerImpl(ServiceServiceServicer): c_rules_dict = json.loads( service.service_config.config_rules[0].custom.resource_value) ob_id=None + flow_id=None LOGGER.info(f"DELETE configuration rules {c_rules_dict}") if "ob_id" in c_rules_dict: ob_id=c_rules_dict["ob_id"] diff --git a/src/service/service/service_handlers/oc/OCServiceHandler.py b/src/service/service/service_handlers/oc/OCServiceHandler.py index c43dd8cbbb2a8480ad5d0955673624e0f2c69d01..2584874faeef0240936b7a3ab8686a4a5ef16b76 100644 --- a/src/service/service/service_handlers/oc/OCServiceHandler.py +++ b/src/service/service/service_handlers/oc/OCServiceHandler.py @@ -142,32 +142,18 @@ class OCServiceHandler(_ServiceHandler): elif is_opticalband: if "ob_id" in settings.value: channel_indexes.append(settings.value["ob_id"]) - # if ( not is_opticalband): - # if 'flow_id' in settings.value: - - # channel_indexes.append(settings.value["flow_id"]) - # else : - # if "ob_id" in settings.value: - # channel_indexes.append(settings.value["ob_id"]) - - - # json_config_rules = teardown_config_rules( - # service_uuid, connection_uuid, device_uuid, endpoint_uuid, endpoint_name, - # settings, endpoint_settings) - - # if len(json_config_rules) > 0: - # 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) LOGGER.info(f"from DeleteEndpoint channel_indexes {channel_indexes}") if len(channel_indexes)>0: - self.__task_executor.deconfigure_optical_device(device=device_obj + errors=self.__task_executor.deconfigure_optical_device(device=device_obj ,channel_indexes=channel_indexes ,is_opticalband=is_opticalband ,dev_flow=dev_flows) + # if (len(errors)==0): + # service_id =self.__service.service_id + # if not is_opticalband : + # self.__task_executor.delete_setting(service_id,"/settings","value") results.append(True) except Exception as e: # pylint: disable=broad-except LOGGER.exception('Unable to DeleteEndpoint({:s})'.format(str(endpoint))) @@ -214,11 +200,13 @@ class OCServiceHandler(_ServiceHandler): def DeleteConfig(self, resources : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]: chk_type('resources', resources, list) if len(resources) == 0: return [] - + service_id =self.__service.service_id results = [] for resource in resources: try: self.__settings_handler.delete(resource[0]) + + # self.__task_executor.delete_setting(service_id,"/settings","value") except Exception as e: # pylint: disable=broad-except LOGGER.exception('Unable to DeleteConfig({:s})'.format(str(resource))) results.append(e) @@ -227,10 +215,14 @@ class OCServiceHandler(_ServiceHandler): def check_media_channel(self,connection_uuid): - LOGGER.info(f"check_media_channel connection_uuid {connection_uuid} {self.__settings_handler.get('/settings-ob_{}'.format(connection_uuid))}") + if self.__settings_handler.get('/settings-ob_{}'.format(connection_uuid)): - LOGGER.info(f"check_media_channel ob {self.__settings_handler.get('/settings-ob_{}'.format(connection_uuid))}") + return False else: - LOGGER.info(f"check_media_channel {self.__settings_handler.get('/settings')}") - return True \ No newline at end of file + + return True + + + + \ No newline at end of file diff --git a/src/service/service/task_scheduler/TaskExecutor.py b/src/service/service/task_scheduler/TaskExecutor.py index a5bcbd26153d0c6bf80a3e6bbfc357cd79fcdfbd..834b9a4082ce51b03a886f8477c526661a125672 100644 --- a/src/service/service/task_scheduler/TaskExecutor.py +++ b/src/service/service/task_scheduler/TaskExecutor.py @@ -18,7 +18,7 @@ from typing import TYPE_CHECKING, Any, Dict, Optional, Union from common.method_wrappers.ServiceExceptions import NotFoundException from common.proto.context_pb2 import ( Connection, ConnectionId, Device, DeviceDriverEnum, DeviceId, Service, ServiceId, - OpticalConfig, OpticalConfigId,ConnectionList + OpticalConfig, OpticalConfigId,ConnectionList,ServiceConfigRule ) from common.tools.context_queries.Connection import get_connection_by_id from common.tools.context_queries.Device import get_device @@ -157,7 +157,7 @@ class TaskExecutor: # Deconfiguring Optical Devices ( CNIT ) def deconfigure_optical_device(self, device : Device, channel_indexes :list,is_opticalband:bool,dev_flow:list): - + errors=[] dev_flow=dev_flow flows = [] indexes={} @@ -198,7 +198,25 @@ class TaskExecutor: except Exception as e: + errors.append(e) LOGGER.info("error in deconfigure_optical_device %s",e) + return errors + + + def delete_setting (self,service_id:ServiceId, config_key:str,config_value:str) : + service_configRule = ServiceConfigRule() + service_configRule.service_id.CopyFrom( service_id) + service_configRule.configrule_custom.resource_key=config_key + service_configRule.configrule_custom.resource_value=config_value + try: + ctxt = ContextClient() + ctxt.connect() + ctxt.DeleteServiceConfigRule(service_configRule) + ctxt.close() + except Exception as e : + LOGGER.info("error in delete service config rule %s",e) + + def check_service_for_media_channel (self,connections:ConnectionList,item)->bool: diff --git a/src/service/service/task_scheduler/TaskScheduler.py b/src/service/service/task_scheduler/TaskScheduler.py index dc231778a541315836df5c46353be926371d055d..fda9eb02cbce5739a55032b1a05f730fdf839f77 100644 --- a/src/service/service/task_scheduler/TaskScheduler.py +++ b/src/service/service/task_scheduler/TaskScheduler.py @@ -29,6 +29,7 @@ from .tasks.Task_ConnectionDeconfigure import Task_ConnectionDeconfigure from .tasks.Task_ServiceDelete import Task_ServiceDelete from .tasks.Task_ServiceSetStatus import Task_ServiceSetStatus from .TaskExecutor import CacheableObjectType, TaskExecutor +from .tasks.Task_OpticalServiceConfigDelete import Task_OpticalServiceConfigDelete from service.service.tools.OpticalTools import delete_lightpath if TYPE_CHECKING: @@ -85,12 +86,12 @@ class TasksScheduler: self._dag.add(service_delete_key, service_removing_key) return service_removing_key, service_delete_key - def _optical_service_remove(self, service_id : ServiceId,has_media_channel:bool) -> Tuple[str, str]: + def _optical_service_remove(self, service_id : ServiceId,has_media_channel:bool,has_optical_band=True) -> Tuple[str, str]: LOGGER.info(f"adding service into _dag {service_id}") service_removing_key = self._add_task_if_not_exists(Task_ServiceSetStatus( - self._executor, service_id, ServiceStatusEnum.SERVICESTATUS_PENDING_REMOVAL)) + self._executor, service_id, ServiceStatusEnum.SERVICESTATUS_ACTIVE)) - service_delete_key = self._add_task_if_not_exists(Task_OpticalServiceDelete(self._executor, service_id,has_media_channel)) + service_delete_key = self._add_task_if_not_exists(Task_OpticalServiceDelete(self._executor, service_id,has_media_channel,has_optical_band)) # deleting a service requires the service is in removing state self._dag.add(service_delete_key, service_removing_key) @@ -131,23 +132,38 @@ class TasksScheduler: - def _optical_connection_deconfigure(self, connection_id : ConnectionId, service_id : ServiceId,has_media_channel:bool) -> str: + def _optical_connection_deconfigure(self, connection_id : ConnectionId, service_id : ServiceId,has_media_channel:bool,has_optical_band=True) -> str: LOGGER.info(f"adding connection into _dag {connection_id}") connection_deconfigure_key = self._add_task_if_not_exists(Task_OpticalConnectionDeconfigure( self._executor, connection_id,has_media_channel=has_media_channel)) # the connection deconfiguration depends on its connection's service being in removing state service_pending_removal_key = self._add_task_if_not_exists(Task_ServiceSetStatus( - self._executor, service_id, ServiceStatusEnum.SERVICESTATUS_PENDING_REMOVAL)) + self._executor, service_id, ServiceStatusEnum.SERVICESTATUS_ACTIVE)) self._dag.add(connection_deconfigure_key, service_pending_removal_key) service_delete_key = self._add_task_if_not_exists(Task_OpticalServiceDelete( - self._executor, service_id,has_media_channel)) + self._executor, service_id,has_media_channel,has_optical_band)) self._dag.add(service_delete_key, connection_deconfigure_key) return connection_deconfigure_key + def _optical_service_config_remove(self, connection_id : ConnectionId + , service_id : ServiceId + ) -> str: + LOGGER.info(f"_optical_service_config_remove {connection_id}") + service_config_key = self._add_task_if_not_exists(Task_OpticalServiceConfigDelete( + self._executor,connection_id, service_id + + )) + + service_pending_removal_key = self._add_task_if_not_exists(Task_ServiceSetStatus( + self._executor, service_id, ServiceStatusEnum.SERVICESTATUS_ACTIVE)) + + self._dag.add(service_config_key, service_pending_removal_key) + return service_config_key + def compose_from_pathcompreply(self, pathcomp_reply : PathCompReply, is_delete : bool = False) -> None: t0 = time.time() @@ -171,8 +187,10 @@ class TasksScheduler: LOGGER.debug('[compose_from_pathcompreply] elapsed_time: {:f} sec'.format(t1-t0)) - def check_service_for_media_channel (self,connections:ConnectionList,item)->bool: + def check_service_for_media_channel (self,connections:ConnectionList,item)->Tuple[bool,bool]: service=item + has_media_channel=False + has_optical_band=False if (isinstance(item,ServiceId)): service=self._executor.get_service(item) class_service_handler = None @@ -183,18 +201,26 @@ class TasksScheduler: class_service_handler=self._executor.get_service_handler(connection, service,**service_handler_settings) if class_service_handler.check_media_channel(connection_uuid): - return True - return False + has_media_channel= True + else : + has_optical_band=True + + return (has_media_channel,has_optical_band) def compose_from_optical_service(self, service : Service,params:dict, is_delete : bool = False) -> None: t0 = time.time() include_service = self._optical_service_remove if is_delete else self._service_create include_connection = self._optical_connection_deconfigure if is_delete else self._connection_configure + include_service_config = self._optical_service_config_remove if is_delete else None explored_items = set() pending_items_to_explore = queue.Queue() pending_items_to_explore.put(service) has_media_channel=None + has_optical_band=None + reply=None + code=0 + reply_not_allowed="DELETE_NOT_ALLOWED" while not pending_items_to_explore.empty(): try: item = pending_items_to_explore.get(block=False) @@ -207,67 +233,91 @@ class TasksScheduler: str_item_key = grpc_message_to_json_string(item.service_id) if str_item_key in explored_items: continue connections = self._context_client.ListConnections(item.service_id) - has_media_channel=self.check_service_for_media_channel(connections=connections,item=item.service_id) - LOGGER.info(f"checking if media_channel_existed {has_media_channel}") + has_media_channel,has_optical_band=self.check_service_for_media_channel(connections=connections,item=item.service_id) + if len(service.service_config.config_rules) > 0: - reply = delete_lightpath(params['flow_id'] - , params['src'] + reply,code = delete_lightpath( + params['src'] ,params ['dst'] , params['bitrate'] , params['ob_id'] - ,delete_band=not has_media_channel) + ,delete_band=not has_media_channel + , flow_id= params['flow_id'] + ) + - - include_service(item.service_id,has_media_channel=has_media_channel) + if code == 400 and reply_not_allowed in reply : + MSG = 'Deleteion for the service is not Allowed , Served Lightpaths is not empty' + raise Exception(MSG) + LOGGER.info('entered') + include_service(item.service_id,has_media_channel=has_media_channel,has_optical_band=has_optical_band) self._add_service_to_executor_cache(item) for connection in connections.connections: self._add_connection_to_executor_cache(connection) pending_items_to_explore.put(connection) - - explored_items.add(str_item_key) - LOGGER.info(f"explored_items {explored_items}") + elif isinstance(item, ServiceId): - LOGGER.info(f"item instace is srevice id ") + + if code == 400 and reply_not_allowed in reply:break + str_item_key = grpc_message_to_json_string(item) if str_item_key in explored_items: continue connections = self._context_client.ListConnections(item) - has_media_channel=self.check_service_for_media_channel(connections=connections,item=item) + has_media_channel,has_optical_band=self.check_service_for_media_channel(connections=connections,item=item) - - include_service(item,has_media_channel=has_media_channel) + + include_service(item,has_media_channel=has_media_channel,has_optical_band=has_optical_band) + + self._executor.get_service(item) for connection in connections.connections: self._add_connection_to_executor_cache(connection) pending_items_to_explore.put(connection) + explored_items.add(str_item_key) elif isinstance(item, Connection): - LOGGER.info(f"item instace is connection ") + + + if code == 400 and reply_not_allowed in reply:break + str_item_key = grpc_message_to_json_string(item.connection_id) if str_item_key in explored_items: continue - LOGGER.info(f"checking if media_channel_existed {has_media_channel}") - - - connection_key = include_connection(item.connection_id, item.service_id,has_media_channel=has_media_channel) + + + connection_key = include_connection(item.connection_id, item.service_id,has_media_channel=has_media_channel,has_optical_band=has_optical_band) self._add_connection_to_executor_cache(connection) + + if include_service_config is not None : + connections_list = ConnectionList() + connections_list.connections.append(item) + + is_media_channel,_=self.check_service_for_media_channel(connections=connections_list,item=service) + + if has_optical_band and is_media_channel: + include_service_config(item.connection_id + , item.service_id + + ) + self._executor.get_service(item.service_id) pending_items_to_explore.put(item.service_id) for sub_service_id in item.sub_service_ids: - _,service_key_done = include_service(sub_service_id,has_media_channel=has_media_channel) + _,service_key_done = include_service(sub_service_id,has_media_channel=has_media_channel,has_optical_band=has_optical_band) self._executor.get_service(sub_service_id) self._dag.add(service_key_done, connection_key) pending_items_to_explore.put(sub_service_id) diff --git a/src/service/service/task_scheduler/tasks/Task_OpticalServiceConfigDelete.py b/src/service/service/task_scheduler/tasks/Task_OpticalServiceConfigDelete.py new file mode 100644 index 0000000000000000000000000000000000000000..3b69f7333b63c63d487e03da22f56e376e6d6aa7 --- /dev/null +++ b/src/service/service/task_scheduler/tasks/Task_OpticalServiceConfigDelete.py @@ -0,0 +1,47 @@ +# 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 common.proto.context_pb2 import ServiceId , ConnectionId +from service.service.task_scheduler.TaskExecutor import TaskExecutor +from service.service.tools.ObjectKeys import get_service_key +from ._Task import _Task +import logging + +KEY_TEMPLATE = 'optical_service({service_id:s})_Config:delete' + +class Task_OpticalServiceConfigDelete(_Task): + def __init__(self, task_executor : TaskExecutor + ,connection_id:ConnectionId + , service_id : ServiceId + ) -> None: + super().__init__(task_executor) + self._connection_id=connection_id + self._service_id = service_id + + @property + def service_id(self) -> ServiceId: return self._service_id + + @staticmethod + def build_key(service_id : ServiceId) -> str: # pylint: disable=arguments-differ + str_service_id = get_service_key(service_id) + return KEY_TEMPLATE.format(service_id=str_service_id) + + @property + def key(self) -> str: return self.build_key(self._service_id) + + def execute(self) -> None: + + + + self._task_executor.delete_setting(self._service_id,'/settings','value') diff --git a/src/service/service/task_scheduler/tasks/Task_OpticalServiceDelete.py b/src/service/service/task_scheduler/tasks/Task_OpticalServiceDelete.py index e3701a0ba08d932effeeea0028c390e3d7f7dda1..b45830dc483520d833cae3f1e76d6c127a929036 100644 --- a/src/service/service/task_scheduler/tasks/Task_OpticalServiceDelete.py +++ b/src/service/service/task_scheduler/tasks/Task_OpticalServiceDelete.py @@ -20,10 +20,11 @@ from ._Task import _Task KEY_TEMPLATE = 'optical_service({service_id:s}):delete' class Task_OpticalServiceDelete(_Task): - def __init__(self, task_executor : TaskExecutor, service_id : ServiceId,has_media_channel:bool) -> None: + def __init__(self, task_executor : TaskExecutor, service_id : ServiceId,has_media_channel:bool,has_optical_band:bool) -> None: super().__init__(task_executor) self._service_id = service_id self._has_media_channel=has_media_channel + self._has_optical_band=has_optical_band @property def service_id(self) -> ServiceId: return self._service_id @@ -37,5 +38,5 @@ class Task_OpticalServiceDelete(_Task): def key(self) -> str: return self.build_key(self._service_id) def execute(self) -> None: - if not self._has_media_channel: + if not self._has_media_channel or not self._has_optical_band: self._task_executor.delete_service(self._service_id) diff --git a/src/service/service/tools/ObjectKeys.py b/src/service/service/tools/ObjectKeys.py index 14c4cdf3ad661df0aa8f22599a294fe50db4a1a9..e79f1533a80c4aa908dba9fd43f56c057794c0d5 100644 --- a/src/service/service/tools/ObjectKeys.py +++ b/src/service/service/tools/ObjectKeys.py @@ -13,6 +13,7 @@ # limitations under the License. from common.proto.context_pb2 import ConnectionId, DeviceId, ServiceId +import logging def get_connection_key(connection_id : ConnectionId) -> str: return connection_id.connection_uuid.uuid @@ -21,6 +22,7 @@ def get_device_key(device_id : DeviceId) -> str: return device_id.device_uuid.uuid def get_service_key(service_id : ServiceId) -> str: + context_uuid = service_id.context_id.context_uuid.uuid service_uuid = service_id.service_uuid.uuid return '{:s}/{:s}'.format(context_uuid, service_uuid) diff --git a/src/service/service/tools/OpticalTools.py b/src/service/service/tools/OpticalTools.py index c7c0e76c456deb2371ff984b1dbe629f4532fea2..331b0b8274a800498305c4b7cbace5e434e56193 100644 --- a/src/service/service/tools/OpticalTools.py +++ b/src/service/service/tools/OpticalTools.py @@ -127,15 +127,22 @@ def get_optical_band(idx) -> str: return optical_band_uni_txt -def delete_lightpath(flow_id, src, dst, bitrate, ob_id,delete_band) -> str: +def delete_lightpath( src, dst, bitrate, ob_id,delete_band,flow_id=None) -> str: reply = "200" + delete_band=1 if delete_band else 0 if not testing: - urlx = "http://{}:{}/OpticalTFS/DelFlexLightpath/{}/{}/{}/{}/{}/{}".format(OPTICAL_IP, OPTICAL_PORT, flow_id, src, dst, bitrate, ob_id,delete_band) + urlx=None + if flow_id is not None: + urlx = "http://{}:{}/OpticalTFS/DelFlexLightpath/{}/{}/{}/{}/{}/{}".format(OPTICAL_IP, OPTICAL_PORT, src, dst, bitrate, ob_id,delete_band,flow_id) + else : + urlx = "http://{}:{}/OpticalTFS/DelFlexLightpath/{}/{}/{}/{}/{}".format(OPTICAL_IP, OPTICAL_PORT, src, dst, bitrate, ob_id,delete_band) headers = {"Content-Type": "application/json"} r = requests.delete(urlx, headers=headers) reply = r.text - return reply + code = r.status_code + logging.info(f"delete_lightpath reply {reply}") + return (reply,code) def DelFlexLightpath (flow_id,src,dst,bitrate,o_band_id): reply = "200" diff --git a/src/tests/ofc24/get_all.sh b/src/tests/ofc24/get_all.sh new file mode 100644 index 0000000000000000000000000000000000000000..2f0412d460e07c29e3b4f1feb43528f9925709ca --- /dev/null +++ b/src/tests/ofc24/get_all.sh @@ -0,0 +1,6 @@ +#!/bin/bash + + ~/tfs-ctrl/src/tests/ofc24/get_bands.sh > bands.json + ~/tfs-ctrl/src/tests/ofc24/get_links.sh > links.json + ~/tfs-ctrl/src/tests/ofc24/get_lightpath.sh > lightpath.json +