From c926393733b058a345b1a288ebca9f2852281129 Mon Sep 17 00:00:00 2001
From: Lluis Gifre <lluis.gifre@cttc.es>
Date: Tue, 2 Aug 2022 14:47:24 +0000
Subject: [PATCH] Slice component:

- refined create/update of slices
- implemented delete of slices
---
 src/slice/requirements.in                     |   1 +
 src/slice/service/SliceServiceServicerImpl.py | 134 ++++++++++++------
 2 files changed, 89 insertions(+), 46 deletions(-)

diff --git a/src/slice/requirements.in b/src/slice/requirements.in
index e69de29bb..cbf07ecb7 100644
--- a/src/slice/requirements.in
+++ b/src/slice/requirements.in
@@ -0,0 +1 @@
+deepdiff==5.8.*
diff --git a/src/slice/service/SliceServiceServicerImpl.py b/src/slice/service/SliceServiceServicerImpl.py
index 275a20114..8c70b5e5a 100644
--- a/src/slice/service/SliceServiceServicerImpl.py
+++ b/src/slice/service/SliceServiceServicerImpl.py
@@ -12,11 +12,16 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import grpc, json, logging
+import grpc, logging, deepdiff
 from common.proto.context_pb2 import (
-    ConfigActionEnum, Empty, Service, ServiceStatusEnum, ServiceTypeEnum, Slice, SliceId, SliceStatusEnum)
+    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.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
 from context.client.ContextClient import ContextClient
 from interdomain.client.InterdomainClient import InterdomainClient
 from service.client.ServiceClient import ServiceClient
@@ -34,66 +39,69 @@ class SliceServiceServicerImpl(SliceServiceServicer):
 
     def create_update(self, request : Slice) -> SliceId:
         context_client = ContextClient()
-
-        slice_id = context_client.SetSlice(request)
-        if len(request.slice_endpoint_ids) != 2: return slice_id
+        try:
+            _slice = context_client.GetSlice(request.slice_id)
+            json_current_slice = grpc_message_to_json(_slice)
+        except:
+            json_current_slice = {}
+            slice_request = Slice()
+            slice_request.slice_id.CopyFrom(request.slice_id)
+            slice_request.slice_status.slice_status = SliceStatusEnum.SLICESTATUS_PLANNED
+            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)))
 
         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])
+            device_parts = device_uuid.split('@')
+            domain_uuid = '' if len(device_parts) == 1 else device_parts[1]
+            domains.add(domain_uuid)
+        LOGGER.info('domains = {:s}'.format(str(domains)))
+        is_multi_domain = len(domains) > 1
+        LOGGER.info('is_multi_domain = {:s}'.format(str(is_multi_domain)))
 
-        is_multi_domain = len(domains) == 2
         if is_multi_domain:
             interdomain_client = InterdomainClient()
             slice_id = 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_id = ServiceId()
+            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
 
             service_client = ServiceClient()
-            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')
-
-            config_rule = service_request.service_config.config_rules.add()
-            config_rule.action = ConfigActionEnum.CONFIGACTION_SET
-            config_rule.custom.resource_key = '/settings'
-            config_rule.custom.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.custom.resource_key = '/device[{:s}]/endpoint[{:s}]/settings'.format(
-                    device_uuid, endpoint_uuid)
-                config_rule.custom.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)
+            try:
+                _service = context_client.GetService(service_id)
+            except:
+                service_request = Service()
+                service_request.service_id.CopyFrom(service_id)
+                service_request.service_type = ServiceTypeEnum.SERVICETYPE_L2NM
+                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)
 
             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')
 
-            reply = Slice()
-            reply.CopyFrom(request)
-            slice_service_id = reply.slice_service_ids.add()
-            slice_service_id.CopyFrom(service_reply)
-            context_client.SetSlice(reply)
-            slice_id = reply.slice_id
+            update_service_ids(slice_request.slice_service_ids, context_uuid, service_uuid)
+            context_client.SetSlice(slice_request)
+            slice_id = slice_request.slice_id
 
         slice_ = context_client.GetSlice(slice_id)
         slice_active = Slice()
@@ -132,4 +140,38 @@ class SliceServiceServicerImpl(SliceServiceServicer):
 
     @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.slice_id)
+        except:
+            return Empty()
+
+        domains = set()
+        for slice_endpoint_id in _slice.slice_endpoint_ids:
+            device_uuid = slice_endpoint_id.device_id.device_uuid.uuid
+            device_parts = device_uuid.split('@')
+            domain_uuid = '' if len(device_parts) == 1 else device_parts[1]
+            domains.add(domain_uuid)
+        LOGGER.info('domains = {:s}'.format(str(domains)))
+        is_multi_domain = len(domains) > 1
+        LOGGER.info('is_multi_domain = {:s}'.format(str(is_multi_domain)))
+
+        if is_multi_domain:
+            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:
+                try:
+                    service_client.DeleteService(service_id)
+                except:
+                    pass
+
+        context_client.RemoveSlice(request.slice_id)
         return Empty()
-- 
GitLab