# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) # # 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 grpc, json, logging from common.rpc_method_wrapper.Decorator import create_metrics, safe_and_metered_rpc_method from context.client.ContextClient import ContextClient from context.proto.context_pb2 import ( ConfigActionEnum, Empty, Service, ServiceStatusEnum, ServiceTypeEnum, Slice, SliceId, SliceStatusEnum) from interdomain.client.InterdomainClient import InterdomainClient from service.client.ServiceClient import ServiceClient from slice.proto.slice_pb2_grpc import SliceServiceServicer LOGGER = logging.getLogger(__name__) SERVICE_NAME = 'Slice' METHOD_NAMES = ['CreateSlice', 'UpdateSlice', 'DeleteSlice'] METRICS = create_metrics(SERVICE_NAME, METHOD_NAMES) class SliceServiceServicerImpl(SliceServiceServicer): def __init__( self, context_client : ContextClient, interdomain_client : InterdomainClient, service_client : ServiceClient ): LOGGER.debug('Creating Servicer...') self.context_client = context_client self.interdomain_client = interdomain_client self.service_client = service_client LOGGER.debug('Servicer Created') def create_update(self, request : Slice) -> SliceId: slice_id = self.context_client.SetSlice(request) if len(request.slice_endpoint_ids) != 2: return slice_id domains = set() for slice_endpoint_id in request.slice_endpoint_ids: device_uuid = slice_endpoint_id.device_id.device_uuid.uuid domains.add(device_uuid.split('@')[1]) is_multi_domain = len(domains) == 2 if is_multi_domain: slice_id = self.interdomain_client.RequestSlice(request) else: # pylint: disable=no-member service_request = Service() service_request.service_id.context_id.context_uuid.uuid = request.slice_id.context_id.context_uuid.uuid service_request.service_id.service_uuid.uuid = request.slice_id.slice_uuid.uuid service_request.service_type = ServiceTypeEnum.SERVICETYPE_L3NM service_request.service_status.service_status = ServiceStatusEnum.SERVICESTATUS_PLANNED service_reply = self.service_client.CreateService(service_request) if service_reply != service_request.service_id: # pylint: disable=no-member raise Exception('Service creation failed. Wrong Service Id was returned') config_rule = service_request.service_config.config_rules.add() config_rule.action = ConfigActionEnum.CONFIGACTION_SET config_rule.resource_key = '/settings' config_rule.resource_value = json.dumps( {'mtu': 1512, 'address_families': ['IPV4'], 'bgp_as': 65000, 'bgp_route_target': '65000:333'}, sort_keys=True) for slice_endpoint_id in request.slice_endpoint_ids: device_uuid = slice_endpoint_id.device_id.device_uuid.uuid endpoint_uuid = slice_endpoint_id.endpoint_uuid.uuid endpoint_id = service_request.service_endpoint_ids.add() endpoint_id.device_id.device_uuid.uuid = device_uuid endpoint_id.endpoint_uuid.uuid = endpoint_uuid config_rule = service_request.service_config.config_rules.add() config_rule.action = ConfigActionEnum.CONFIGACTION_SET config_rule.resource_key = '/device[{:s}]/endpoint[{:s}]/settings'.format(device_uuid, endpoint_uuid) config_rule.resource_value = json.dumps( {'router_id': '0.0.0.0', 'route_distinguisher': '0:0', 'sub_interface_index': 0, 'vlan_id': 0, 'address_ip': '0.0.0.0', 'address_prefix': 0}, sort_keys=True) service_reply = self.service_client.UpdateService(service_request) if service_reply != service_request.service_id: # pylint: disable=no-member raise Exception('Service update failed. Wrong Service Id was returned') reply = Slice() reply.CopyFrom(request) slice_service_id = reply.slice_service_ids.add() slice_service_id.CopyFrom(service_reply) self.context_client.SetSlice(reply) slice_id = reply.slice_id slice_ = self.context_client.GetSlice(slice_id) slice_active = Slice() slice_active.CopyFrom(slice_) slice_active.slice_status.slice_status = SliceStatusEnum.SLICESTATUS_ACTIVE self.context_client.SetSlice(slice_active) return slice_id @safe_and_metered_rpc_method(METRICS, LOGGER) def CreateSlice(self, request : Slice, context : grpc.ServicerContext) -> SliceId: #try: # slice_ = self.context_client.GetSlice(request.slice_id) # slice_id = slice_.slice_id #except grpc.RpcError: # slice_id = self.context_client.SetSlice(request) #return slice_id return self.create_update(request) @safe_and_metered_rpc_method(METRICS, LOGGER) def UpdateSlice(self, request : Slice, context : grpc.ServicerContext) -> SliceId: #slice_id = self.context_client.SetSlice(request) #if len(request.slice_endpoint_ids) != 2: return slice_id # #domains = set() #for slice_endpoint_id in request.slice_endpoint_ids: # device_uuid = slice_endpoint_id.device_id.device_uuid.uuid # domains.add(device_uuid.split('@')[0]) # #is_multi_domain = len(domains) == 2 #if is_multi_domain: # return self.interdomain_client.LookUpSlice(request) #else: # raise NotImplementedError('Slice should create local services for single domain slice') return self.create_update(request) @safe_and_metered_rpc_method(METRICS, LOGGER) def DeleteSlice(self, request : SliceId, context : grpc.ServicerContext) -> Empty: return Empty()