Newer
Older
# 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.
from common.proto.context_pb2 import (
Empty, Service, ServiceId, ServiceStatusEnum, ServiceTypeEnum, Slice, SliceId, SliceStatusEnum)
from common.proto.slice_pb2_grpc import SliceServiceServicer
from common.rpc_method_wrapper.Decorator import create_metrics, safe_and_metered_rpc_method
from common.tools.context_queries.InterDomain import is_multi_domain
from common.tools.grpc.ConfigRules import copy_config_rules
from common.tools.grpc.Constraints import copy_constraints
from common.tools.grpc.EndPointIds import copy_endpoint_ids
from common.tools.grpc.ServiceIds import update_service_ids
from common.tools.grpc.Tools import grpc_message_to_json_string
from context.client.ContextClient import ContextClient
from interdomain.client.InterdomainClient import InterdomainClient
from service.client.ServiceClient import ServiceClient
LOGGER = logging.getLogger(__name__)
SERVICE_NAME = 'Slice'
METHOD_NAMES = ['CreateSlice', 'UpdateSlice', 'DeleteSlice']
METRICS = create_metrics(SERVICE_NAME, METHOD_NAMES)
class SliceServiceServicerImpl(SliceServiceServicer):
LOGGER.debug('Creating Servicer...')
LOGGER.debug('Servicer Created')
def create_update(self, request : Slice) -> SliceId:
try:
_slice = context_client.GetSlice(request.slice_id)
#json_current_slice = grpc_message_to_json(_slice)
slice_request.slice_id.CopyFrom(request.slice_id) # pylint: disable=no-member
slice_request.slice_status.slice_status = SliceStatusEnum.SLICESTATUS_PLANNED # pylint: disable=no-member
context_client.SetSlice(slice_request)
_slice = context_client.GetSlice(request.slice_id)
slice_request = Slice()
slice_request.CopyFrom(_slice)
#LOGGER.info('json_current_slice = {:s}'.format(str(json_current_slice)))
#json_updated_slice = grpc_message_to_json(request)
#LOGGER.info('json_updated_slice = {:s}'.format(str(json_updated_slice)))
#changes = deepdiff.DeepDiff(json_current_slice, json_updated_slice)
#LOGGER.info('changes = {:s}'.format(str(changes)))
if is_multi_domain(context_client, request.slice_endpoint_ids):
interdomain_client = InterdomainClient()
slice_id = interdomain_client.RequestSlice(request)
else:
context_uuid = service_id.context_id.context_uuid.uuid = request.slice_id.context_id.context_uuid.uuid
slice_uuid = service_uuid = service_id.service_uuid.uuid = request.slice_id.slice_uuid.uuid
try:
_service = context_client.GetService(service_id)
except: # pylint: disable=bare-except
# pylint: disable=no-member
service_request = Service()
service_request.service_id.CopyFrom(service_id)
service_request.service_type = ServiceTypeEnum.SERVICETYPE_UNKNOWN
service_request.service_status.service_status = ServiceStatusEnum.SERVICESTATUS_PLANNED
service_reply = 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')
_service = context_client.GetService(service_id)
service_request = Service()
service_request.CopyFrom(_service)
copy_endpoint_ids(request.slice_endpoint_ids, service_request.service_endpoint_ids)
copy_constraints(request.slice_constraints, service_request.service_constraints)
copy_config_rules(request.slice_config.config_rules, service_request.service_config.config_rules)
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
service_request.service_type = ServiceTypeEnum.SERVICETYPE_UNKNOWN
for config_rule in request.slice_config.config_rules:
LOGGER.info('config_rule: {:s}'.format(grpc_message_to_json_string(config_rule)))
config_rule_kind = config_rule.WhichOneof('config_rule')
LOGGER.info('config_rule_kind: {:s}'.format(str(config_rule_kind)))
if config_rule_kind != 'custom': continue
custom = config_rule.custom
resource_key = custom.resource_key
LOGGER.info('resource_key: {:s}'.format(str(resource_key)))
# TODO: parse resource key with regular expression, e.g.:
# m = re.match('\/device\[[^\]]\]\/endpoint\[[^\]]\]\/settings', s)
if not resource_key.startswith('/device'): continue
if not resource_key.endswith('/settings'): continue
resource_value = json.loads(custom.resource_value)
LOGGER.info('resource_value: {:s}'.format(str(resource_value)))
if service_request.service_type == ServiceTypeEnum.SERVICETYPE_UNKNOWN:
if (resource_value.get('address_ip') is not None and \
resource_value.get('address_prefix') is not None):
service_request.service_type = ServiceTypeEnum.SERVICETYPE_L3NM
LOGGER.info('is L3')
else:
service_request.service_type = ServiceTypeEnum.SERVICETYPE_L2NM
LOGGER.info('is L2')
break
service_reply = 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')
copy_endpoint_ids(request.slice_endpoint_ids, slice_request.slice_endpoint_ids)
copy_constraints(request.slice_constraints, slice_request.slice_constraints)
copy_config_rules(request.slice_config.config_rules, slice_request.slice_config.config_rules)
update_service_ids(slice_request.slice_service_ids, context_uuid, service_uuid)
context_client.SetSlice(slice_request)
slice_id = slice_request.slice_id
slice_active = Slice()
slice_active.CopyFrom(slice_)
slice_active.slice_status.slice_status = SliceStatusEnum.SLICESTATUS_ACTIVE # pylint: disable=no-member
return slice_id
@safe_and_metered_rpc_method(METRICS, LOGGER)
def CreateSlice(self, request : Slice, context : grpc.ServicerContext) -> SliceId:
#try:
# slice_ = context_client.GetSlice(request.slice_id)
# slice_id = slice_.slice_id
#except grpc.RpcError:
#return slice_id
return self.create_update(request)
@safe_and_metered_rpc_method(METRICS, LOGGER)
def UpdateSlice(self, request : Slice, context : grpc.ServicerContext) -> SliceId:
#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:
# interdomain_client = InterdomainClient()
# return 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:
context_client = ContextClient()
try:
_slice = context_client.GetSlice(request)
if is_multi_domain(context_client, _slice.slice_endpoint_ids):
#interdomain_client = InterdomainClient()
#slice_id = interdomain_client.DeleteSlice(request)
raise NotImplementedError('Delete inter-domain slice')
else:
current_slice = Slice()
current_slice.CopyFrom(_slice)
current_slice.slice_status.slice_status = SliceStatusEnum.SLICESTATUS_DEINIT
context_client.SetSlice(current_slice)
service_client = ServiceClient()
for service_id in _slice.slice_service_ids:
current_slice = Slice()
current_slice.slice_id.CopyFrom(_slice.slice_id)
slice_service_id = current_slice.slice_service_ids.add()
slice_service_id.CopyFrom(service_id)
context_client.UnsetSlice(current_slice)
service_client.DeleteService(service_id)
context_client.RemoveSlice(request)
return Empty()