From 6091ecffd4d6c549dc836f29ac702e37b615c07c Mon Sep 17 00:00:00 2001
From: gifrerenom <lluis.gifre@cttc.es>
Date: Sat, 25 Mar 2023 07:51:05 +0000
Subject: [PATCH] Context component:

- Fixed composition of PolicyRule messages
- Added position of endpoints in Link, Service, and Slice.
- Added sort of endpoints according to their position.
---
 src/context/service/database/Link.py                   |  3 ++-
 src/context/service/database/Service.py                |  1 +
 src/context/service/database/Slice.py                  |  1 +
 src/context/service/database/models/LinkModel.py       | 10 ++++++++--
 src/context/service/database/models/PolicyRuleModel.py |  2 +-
 src/context/service/database/models/ServiceModel.py    |  9 +++++++--
 src/context/service/database/models/SliceModel.py      |  9 +++++++--
 7 files changed, 27 insertions(+), 8 deletions(-)

diff --git a/src/context/service/database/Link.py b/src/context/service/database/Link.py
index 8d195cb1d..299827dbd 100644
--- a/src/context/service/database/Link.py
+++ b/src/context/service/database/Link.py
@@ -64,13 +64,14 @@ def link_set(db_engine : Engine, request : Link) -> Tuple[Dict, bool]:
     topology_uuids : Set[str] = set()
     related_topologies : List[Dict] = list()
     link_endpoints_data : List[Dict] = list()
-    for endpoint_id in request.link_endpoint_ids:
+    for i,endpoint_id in enumerate(request.link_endpoint_ids):
         endpoint_topology_uuid, _, endpoint_uuid = endpoint_get_uuid(
             endpoint_id, allow_random=False)
 
         link_endpoints_data.append({
             'link_uuid'    : link_uuid,
             'endpoint_uuid': endpoint_uuid,
+            'position'     : i,
         })
 
         if endpoint_topology_uuid not in topology_uuids:
diff --git a/src/context/service/database/Service.py b/src/context/service/database/Service.py
index a81a80c3c..fe12eaf8a 100644
--- a/src/context/service/database/Service.py
+++ b/src/context/service/database/Service.py
@@ -91,6 +91,7 @@ def service_set(db_engine : Engine, request : Service) -> Tuple[Dict, bool]:
         service_endpoints_data.append({
             'service_uuid' : service_uuid,
             'endpoint_uuid': endpoint_uuid,
+            'position'     : i,
         })
 
     constraints = compose_constraints_data(request.service_constraints, now, service_uuid=service_uuid)
diff --git a/src/context/service/database/Slice.py b/src/context/service/database/Slice.py
index 1d6781d53..724046bfa 100644
--- a/src/context/service/database/Slice.py
+++ b/src/context/service/database/Slice.py
@@ -91,6 +91,7 @@ def slice_set(db_engine : Engine, request : Slice) -> Tuple[Dict, bool]:
         slice_endpoints_data.append({
             'slice_uuid'   : slice_uuid,
             'endpoint_uuid': endpoint_uuid,
+            'position'     : i,
         })
 
     slice_services_data : List[Dict] = list()
diff --git a/src/context/service/database/models/LinkModel.py b/src/context/service/database/models/LinkModel.py
index ee591f5c8..e9fd9bc87 100644
--- a/src/context/service/database/models/LinkModel.py
+++ b/src/context/service/database/models/LinkModel.py
@@ -12,7 +12,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from sqlalchemy import Column, DateTime, ForeignKey, String
+import operator
+from sqlalchemy import CheckConstraint, Column, DateTime, ForeignKey, Integer, String
 from sqlalchemy.dialects.postgresql import UUID
 from sqlalchemy.orm import relationship
 from typing import Dict
@@ -38,7 +39,7 @@ class LinkModel(_Base):
             'name'             : self.link_name,
             'link_endpoint_ids': [
                 link_endpoint.endpoint.dump_id()
-                for link_endpoint in self.link_endpoints
+                for link_endpoint in sorted(self.link_endpoints, key=operator.attrgetter('position'))
             ],
         }
 
@@ -47,6 +48,11 @@ class LinkEndPointModel(_Base):
 
     link_uuid     = Column(ForeignKey('link.link_uuid',         ondelete='CASCADE' ), primary_key=True)
     endpoint_uuid = Column(ForeignKey('endpoint.endpoint_uuid', ondelete='RESTRICT'), primary_key=True, index=True)
+    position      = Column(Integer, nullable=False)
 
     link     = relationship('LinkModel',     back_populates='link_endpoints', lazy='joined')
     endpoint = relationship('EndPointModel', lazy='joined') # back_populates='link_endpoints'
+
+    __table_args__ = (
+        CheckConstraint(position >= 0, name='check_position_value'),
+    )
diff --git a/src/context/service/database/models/PolicyRuleModel.py b/src/context/service/database/models/PolicyRuleModel.py
index 2f0c8a326..663a9a39a 100644
--- a/src/context/service/database/models/PolicyRuleModel.py
+++ b/src/context/service/database/models/PolicyRuleModel.py
@@ -64,7 +64,7 @@ class PolicyRuleModel(_Base):
             'deviceList': [{'device_uuid': {'uuid': pr_d.device_uuid}} for pr_d in self.policyrule_devices],
         }
         if self.policyrule_kind == PolicyRuleKindEnum.SERVICE:
-            result['serviceId'] = self.policyrule_service.dump_id(),
+            result['serviceId'] = self.policyrule_service.dump_id()
         return {self.policyrule_kind.value: result}
 
 class PolicyRuleDeviceModel(_Base):
diff --git a/src/context/service/database/models/ServiceModel.py b/src/context/service/database/models/ServiceModel.py
index 09ff381b5..f1781c4f8 100644
--- a/src/context/service/database/models/ServiceModel.py
+++ b/src/context/service/database/models/ServiceModel.py
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 import operator
-from sqlalchemy import Column, DateTime, Enum, ForeignKey, String
+from sqlalchemy import CheckConstraint, Column, DateTime, Enum, ForeignKey, Integer, String
 from sqlalchemy.dialects.postgresql import UUID
 from sqlalchemy.orm import relationship
 from typing import Dict
@@ -51,7 +51,7 @@ class ServiceModel(_Base):
             'service_status'      : {'service_status': self.service_status.value},
             'service_endpoint_ids': [
                 service_endpoint.endpoint.dump_id()
-                for service_endpoint in self.service_endpoints
+                for service_endpoint in sorted(self.service_endpoints, key=operator.attrgetter('position'))
             ],
             'service_constraints' : [
                 constraint.dump()
@@ -68,6 +68,11 @@ class ServiceEndPointModel(_Base):
 
     service_uuid  = Column(ForeignKey('service.service_uuid',   ondelete='CASCADE' ), primary_key=True)
     endpoint_uuid = Column(ForeignKey('endpoint.endpoint_uuid', ondelete='RESTRICT'), primary_key=True, index=True)
+    position      = Column(Integer, nullable=False)
 
     service  = relationship('ServiceModel',  back_populates='service_endpoints', lazy='joined')
     endpoint = relationship('EndPointModel', lazy='joined') # back_populates='service_endpoints'
+
+    __table_args__ = (
+        CheckConstraint(position >= 0, name='check_position_value'),
+    )
diff --git a/src/context/service/database/models/SliceModel.py b/src/context/service/database/models/SliceModel.py
index 2d6c88416..7f1550eb2 100644
--- a/src/context/service/database/models/SliceModel.py
+++ b/src/context/service/database/models/SliceModel.py
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 import operator
-from sqlalchemy import Column, DateTime, Enum, ForeignKey, String
+from sqlalchemy import CheckConstraint, Column, DateTime, Enum, ForeignKey, Integer, String
 from sqlalchemy.dialects.postgresql import UUID
 from sqlalchemy.orm import relationship
 from typing import Dict
@@ -53,7 +53,7 @@ class SliceModel(_Base):
             'slice_status'      : {'slice_status': self.slice_status.value},
             'slice_endpoint_ids': [
                 slice_endpoint.endpoint.dump_id()
-                for slice_endpoint in self.slice_endpoints
+                for slice_endpoint in sorted(self.slice_endpoints, key=operator.attrgetter('position'))
             ],
             'slice_constraints' : [
                 constraint.dump()
@@ -82,10 +82,15 @@ class SliceEndPointModel(_Base):
 
     slice_uuid    = Column(ForeignKey('slice.slice_uuid',       ondelete='CASCADE' ), primary_key=True)
     endpoint_uuid = Column(ForeignKey('endpoint.endpoint_uuid', ondelete='RESTRICT'), primary_key=True, index=True)
+    position      = Column(Integer, nullable=False)
 
     slice    = relationship('SliceModel', back_populates='slice_endpoints', lazy='joined')
     endpoint = relationship('EndPointModel', lazy='joined') # back_populates='slice_endpoints'
 
+    __table_args__ = (
+        CheckConstraint(position >= 0, name='check_position_value'),
+    )
+
 class SliceServiceModel(_Base):
     __tablename__ = 'slice_service'
 
-- 
GitLab