diff --git a/src/context/service/database/ConfigRule.py b/src/context/service/database/ConfigRule.py index af1dd1ec5689f53bd9180e504f3c3acb57f49532..05dda20aa1cb20439e3cbdcbd123c56e8529d4c8 100644 --- a/src/context/service/database/ConfigRule.py +++ b/src/context/service/database/ConfigRule.py @@ -52,7 +52,8 @@ def upsert_config_rules( if service_uuid is not None: stmt = stmt.where(ConfigRuleModel.service_uuid == service_uuid) if slice_uuid is not None: stmt = stmt.where(ConfigRuleModel.slice_uuid == slice_uuid ) session.execute(stmt) - session.execute(insert(ConfigRuleModel).values(config_rules)) + if len(config_rules) > 0: + session.execute(insert(ConfigRuleModel).values(config_rules)) #Union_SpecificConfigRule = Union[ diff --git a/src/context/service/database/Constraint.py b/src/context/service/database/Constraint.py index 5c94d13c07d247f53d59f6a6da73bef1370754e3..f79159a35a5ab3450f92c2539ca5fa65ebc70f98 100644 --- a/src/context/service/database/Constraint.py +++ b/src/context/service/database/Constraint.py @@ -47,7 +47,8 @@ def upsert_constraints( if service_uuid is not None: stmt = stmt.where(ConstraintModel.service_uuid == service_uuid) if slice_uuid is not None: stmt = stmt.where(ConstraintModel.slice_uuid == slice_uuid ) session.execute(stmt) - session.execute(insert(ConstraintModel).values(constraints)) + if len(constraints) > 0: + session.execute(insert(ConstraintModel).values(constraints)) # def set_constraint(self, db_constraints: ConstraintsModel, grpc_constraint: Constraint, position: int # ) -> Tuple[Union_ConstraintModel, bool]: diff --git a/src/context/service/database/Device.py b/src/context/service/database/Device.py index 8899b5a12dbd9e9656d0454e92b17befb87c3453..acb1603c6a3fcbe4296f2ae18cea1b421f3acad8 100644 --- a/src/context/service/database/Device.py +++ b/src/context/service/database/Device.py @@ -23,7 +23,7 @@ from common.tools.object_factory.Device import json_device_id from context.service.database.ConfigRule import compose_config_rules_data, upsert_config_rules from .models.DeviceModel import DeviceModel from .models.EndPointModel import EndPointModel -from .models.RelationModels import TopologyDeviceModel +from .models.TopologyModel import TopologyDeviceModel from .models.enums.DeviceDriver import grpc_to_enum__device_driver from .models.enums.DeviceOperationalStatus import grpc_to_enum__device_operational_status from .models.enums.KpiSampleType import grpc_to_enum__kpi_sample_type diff --git a/src/context/service/database/Link.py b/src/context/service/database/Link.py index 7032a213888e6754ebf07dab0cde22ff3fb92a33..a2b4e3035743f29332eebd920068d206ead1daca 100644 --- a/src/context/service/database/Link.py +++ b/src/context/service/database/Link.py @@ -20,8 +20,8 @@ from typing import Dict, List, Optional, Set, Tuple from common.proto.context_pb2 import Link, LinkId, LinkIdList, LinkList from common.rpc_method_wrapper.ServiceExceptions import NotFoundException from common.tools.object_factory.Link import json_link_id -from .models.LinkModel import LinkModel -from .models.RelationModels import LinkEndPointModel, TopologyLinkModel +from .models.LinkModel import LinkModel, LinkEndPointModel +from .models.TopologyModel import TopologyLinkModel from .uuids.EndPoint import endpoint_get_uuid from .uuids.Link import link_get_uuid diff --git a/src/context/service/database/Service.py b/src/context/service/database/Service.py index 0230bc4d5f6f731fed114716eec4a751cae3fc95..c926c25409fd6fea789228046c7cda40d4cd019d 100644 --- a/src/context/service/database/Service.py +++ b/src/context/service/database/Service.py @@ -25,8 +25,7 @@ from context.service.database.ConfigRule import compose_config_rules_data, upser from context.service.database.Constraint import compose_constraints_data, upsert_constraints from .models.enums.ServiceStatus import grpc_to_enum__service_status from .models.enums.ServiceType import grpc_to_enum__service_type -from .models.RelationModels import ServiceEndPointModel -from .models.ServiceModel import ServiceModel +from .models.ServiceModel import ServiceModel, ServiceEndPointModel from .uuids.Context import context_get_uuid from .uuids.EndPoint import endpoint_get_uuid from .uuids.Service import service_get_uuid diff --git a/src/context/service/database/Slice.py b/src/context/service/database/Slice.py index 318923555e71307aa91258da774ca2a4255d85ff..00b2fd24bd5388aa00ac93e45df01b95c2326a73 100644 --- a/src/context/service/database/Slice.py +++ b/src/context/service/database/Slice.py @@ -25,8 +25,7 @@ from common.tools.object_factory.Slice import json_slice_id from context.service.database.ConfigRule import compose_config_rules_data, upsert_config_rules from context.service.database.Constraint import compose_constraints_data, upsert_constraints from .models.enums.SliceStatus import grpc_to_enum__slice_status -from .models.RelationModels import SliceEndPointModel, SliceServiceModel #, SliceSubSliceModel -from .models.SliceModel import SliceModel +from .models.SliceModel import SliceModel, SliceEndPointModel, SliceServiceModel, SliceSubSliceModel from .uuids.Context import context_get_uuid from .uuids.EndPoint import endpoint_get_uuid from .uuids.Service import service_get_uuid @@ -96,13 +95,13 @@ def slice_set(db_engine : Engine, request : Slice) -> Tuple[SliceId, bool]: 'service_uuid': service_uuid, }) - #slice_subslices_data : List[Dict] = list() - #for i,subslice_id in enumerate(request.slice_subslice_ids): - # _, subslice_uuid = slice_get_uuid(subslice_id, allow_random=False) - # slice_subslices_data.append({ - # 'slice_uuid' : slice_uuid, - # 'subslice_uuid': subslice_uuid, - # }) + slice_subslices_data : List[Dict] = list() + for i,subslice_id in enumerate(request.slice_subslice_ids): + _, subslice_uuid = slice_get_uuid(subslice_id, allow_random=False) + slice_subslices_data.append({ + 'slice_uuid' : slice_uuid, + 'subslice_uuid': subslice_uuid, + }) constraints = compose_constraints_data(request.slice_constraints, slice_uuid=slice_uuid) config_rules = compose_config_rules_data(request.slice_config.config_rules, slice_uuid=slice_uuid) @@ -129,23 +128,26 @@ def slice_set(db_engine : Engine, request : Slice) -> Tuple[SliceId, bool]: ) session.execute(stmt) - stmt = insert(SliceEndPointModel).values(slice_endpoints_data) - stmt = stmt.on_conflict_do_nothing( - index_elements=[SliceEndPointModel.slice_uuid, SliceEndPointModel.endpoint_uuid] - ) - session.execute(stmt) + if len(slice_endpoints_data) > 0: + stmt = insert(SliceEndPointModel).values(slice_endpoints_data) + stmt = stmt.on_conflict_do_nothing( + index_elements=[SliceEndPointModel.slice_uuid, SliceEndPointModel.endpoint_uuid] + ) + session.execute(stmt) - stmt = insert(SliceServiceModel).values(slice_services_data) - stmt = stmt.on_conflict_do_nothing( - index_elements=[SliceServiceModel.slice_uuid, SliceServiceModel.service_uuid] - ) - session.execute(stmt) + if len(slice_services_data) > 0: + stmt = insert(SliceServiceModel).values(slice_services_data) + stmt = stmt.on_conflict_do_nothing( + index_elements=[SliceServiceModel.slice_uuid, SliceServiceModel.service_uuid] + ) + session.execute(stmt) - #stmt = insert(SliceSubSliceModel).values(slice_subslices_data) - #stmt = stmt.on_conflict_do_nothing( - # index_elements=[SliceSubSliceModel.slice_uuid, SliceSubSliceModel.subslice_uuid] - #) - #session.execute(stmt) + if len(slice_subslices_data) > 0: + stmt = insert(SliceSubSliceModel).values(slice_subslices_data) + stmt = stmt.on_conflict_do_nothing( + index_elements=[SliceSubSliceModel.slice_uuid, SliceSubSliceModel.subslice_uuid] + ) + session.execute(stmt) upsert_constraints(session, constraints, slice_uuid=slice_uuid) upsert_config_rules(session, config_rules, slice_uuid=slice_uuid) @@ -193,11 +195,11 @@ def slice_unset(db_engine : Engine, request : Slice) -> Tuple[SliceId, bool]: SliceServiceModel.slice_uuid == slice_uuid, SliceServiceModel.service_uuid.in_(slice_service_uuids) )).delete() - #num_deletes += session.query(SliceSubSliceModel)\ - # .filter_by(and_( - # SliceSubSliceModel.slice_uuid == slice_uuid, - # SliceSubSliceModel.subslice_uuid.in_(slice_subslice_uuids) - # )).delete() + num_deletes += session.query(SliceSubSliceModel)\ + .filter_by(and_( + SliceSubSliceModel.slice_uuid == slice_uuid, + SliceSubSliceModel.subslice_uuid.in_(slice_subslice_uuids) + )).delete() num_deletes += session.query(SliceEndPointModel)\ .filter_by(and_( SliceEndPointModel.slice_uuid == slice_uuid, diff --git a/src/context/service/database/models/ConnectionModel.py b/src/context/service/database/models/ConnectionModel.py index 546fb7a80ee42a524e8950c8d5d3363a09ee6710..19cafc59b4033329b16487a99affddd8555ea529 100644 --- a/src/context/service/database/models/ConnectionModel.py +++ b/src/context/service/database/models/ConnectionModel.py @@ -25,6 +25,11 @@ from common.proto.context_pb2 import EndPointId from .EndPointModel import EndPointModel from .ServiceModel import ServiceModel +from sqlalchemy import Column, ForeignKey #, ForeignKeyConstraint +#from sqlalchemy.dialects.postgresql import UUID +from sqlalchemy.orm import relationship +from ._Base import _Base + def remove_dict_key(dictionary : Dict, key : str): dictionary.pop(key, None) return dictionary @@ -111,6 +116,17 @@ class ConnectionModel(Model): if include_sub_service_ids: result['sub_service_ids'] = self.dump_sub_service_ids() return result + + + +# class ConnectionSubServiceModel(Model): +# pk = PrimaryKeyField() +# connection_fk = ForeignKeyField(ConnectionModel) +# sub_service_fk = ForeignKeyField(ServiceModel) + + + + def set_path_hop( database : Database, db_path : PathModel, position : int, db_endpoint : EndPointModel ) -> Tuple[PathHopModel, bool]: diff --git a/src/context/service/database/models/LinkModel.py b/src/context/service/database/models/LinkModel.py index fd4f80c166998e726d16ef0f7075a0f186a372c1..950f48763ddf57be482dd06e7492afffe0804503 100644 --- a/src/context/service/database/models/LinkModel.py +++ b/src/context/service/database/models/LinkModel.py @@ -13,7 +13,7 @@ # limitations under the License. from typing import Dict -from sqlalchemy import Column, String +from sqlalchemy import Column, ForeignKey, String from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import relationship from ._Base import _Base @@ -39,3 +39,12 @@ class LinkModel(_Base): for link_endpoint in self.link_endpoints ], } + +class LinkEndPointModel(_Base): + __tablename__ = 'link_endpoint' + + link_uuid = Column(ForeignKey('link.link_uuid', ondelete='CASCADE' ), primary_key=True) + endpoint_uuid = Column(ForeignKey('endpoint.endpoint_uuid', ondelete='RESTRICT'), primary_key=True) + + link = relationship('LinkModel', back_populates='link_endpoints', lazy='joined') + endpoint = relationship('EndPointModel', lazy='joined') # back_populates='link_endpoints' diff --git a/src/context/service/database/models/RelationModels.py b/src/context/service/database/models/RelationModels.py deleted file mode 100644 index 468b14519d75d6ca990b0adf09f89da2fd7266d1..0000000000000000000000000000000000000000 --- a/src/context/service/database/models/RelationModels.py +++ /dev/null @@ -1,86 +0,0 @@ -# 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 sqlalchemy import Column, ForeignKey #, ForeignKeyConstraint -#from sqlalchemy.dialects.postgresql import UUID -from sqlalchemy.orm import relationship -from ._Base import _Base - -# class ConnectionSubServiceModel(Model): -# pk = PrimaryKeyField() -# connection_fk = ForeignKeyField(ConnectionModel) -# sub_service_fk = ForeignKeyField(ServiceModel) - -class LinkEndPointModel(_Base): - __tablename__ = 'link_endpoint' - - link_uuid = Column(ForeignKey('link.link_uuid', ondelete='CASCADE' ), primary_key=True) - endpoint_uuid = Column(ForeignKey('endpoint.endpoint_uuid', ondelete='RESTRICT'), primary_key=True) - - link = relationship('LinkModel', back_populates='link_endpoints', lazy='joined') - endpoint = relationship('EndPointModel', lazy='joined') # back_populates='link_endpoints' - -class ServiceEndPointModel(_Base): - __tablename__ = 'service_endpoint' - - service_uuid = Column(ForeignKey('service.service_uuid', ondelete='CASCADE' ), primary_key=True) - endpoint_uuid = Column(ForeignKey('endpoint.endpoint_uuid', ondelete='RESTRICT'), primary_key=True) - - service = relationship('ServiceModel', back_populates='service_endpoints', lazy='joined') - endpoint = relationship('EndPointModel', lazy='joined') # back_populates='service_endpoints' - -class SliceEndPointModel(_Base): - __tablename__ = 'slice_endpoint' - - slice_uuid = Column(ForeignKey('slice.slice_uuid', ondelete='CASCADE' ), primary_key=True) - endpoint_uuid = Column(ForeignKey('endpoint.endpoint_uuid', ondelete='RESTRICT'), primary_key=True) - - slice = relationship('SliceModel', back_populates='slice_endpoints', lazy='joined') - endpoint = relationship('EndPointModel', lazy='joined') # back_populates='slice_endpoints' - -class SliceServiceModel(_Base): - __tablename__ = 'slice_service' - - slice_uuid = Column(ForeignKey('slice.slice_uuid', ondelete='CASCADE' ), primary_key=True) - service_uuid = Column(ForeignKey('service.service_uuid', ondelete='RESTRICT'), primary_key=True) - - slice = relationship('SliceModel', back_populates='slice_services', lazy='joined') - service = relationship('ServiceModel', lazy='joined') # back_populates='slice_services' - -#class SliceSubSliceModel(_Base): -# __tablename__ = 'slice_subslice' -# -# slice_uuid = Column(ForeignKey('slice.slice_uuid', ondelete='CASCADE' ), primary_key=True) -# subslice_uuid = Column(ForeignKey('slice.slice_uuid', ondelete='RESTRICT'), primary_key=True) -# -# slice = relationship('SliceModel', foreign_keys=[slice_uuid], lazy='joined') #back_populates='slice_subslices' -# subslice = relationship('SliceModel', foreign_keys=[subslice_uuid], lazy='joined') #back_populates='slice_subslices' - -class TopologyDeviceModel(_Base): - __tablename__ = 'topology_device' - - topology_uuid = Column(ForeignKey('topology.topology_uuid', ondelete='RESTRICT'), primary_key=True) - device_uuid = Column(ForeignKey('device.device_uuid', ondelete='CASCADE' ), primary_key=True) - - #topology = relationship('TopologyModel', lazy='joined') # back_populates='topology_devices' - device = relationship('DeviceModel', lazy='joined') # back_populates='topology_devices' - -class TopologyLinkModel(_Base): - __tablename__ = 'topology_link' - - topology_uuid = Column(ForeignKey('topology.topology_uuid', ondelete='RESTRICT'), primary_key=True) - link_uuid = Column(ForeignKey('link.link_uuid', ondelete='CASCADE' ), primary_key=True) - - #topology = relationship('TopologyModel', lazy='joined') # back_populates='topology_links' - link = relationship('LinkModel', lazy='joined') # back_populates='topology_links' diff --git a/src/context/service/database/models/ServiceModel.py b/src/context/service/database/models/ServiceModel.py index b080438448a3fd89b359d5b412cdbdcd7aa0e042..e1e57f4c7a12aecd90bf871c88025a1246071b12 100644 --- a/src/context/service/database/models/ServiceModel.py +++ b/src/context/service/database/models/ServiceModel.py @@ -60,3 +60,12 @@ class ServiceModel(_Base): for config_rule in sorted(self.config_rules, key=operator.attrgetter('position')) ]}, } + +class ServiceEndPointModel(_Base): + __tablename__ = 'service_endpoint' + + service_uuid = Column(ForeignKey('service.service_uuid', ondelete='CASCADE' ), primary_key=True) + endpoint_uuid = Column(ForeignKey('endpoint.endpoint_uuid', ondelete='RESTRICT'), primary_key=True) + + service = relationship('ServiceModel', back_populates='service_endpoints', lazy='joined') + endpoint = relationship('EndPointModel', lazy='joined') # back_populates='service_endpoints' diff --git a/src/context/service/database/models/SliceModel.py b/src/context/service/database/models/SliceModel.py index ef2b64962ecd173409b0211e583190f95aeaaa2a..d3dff51e193281a79041c62549931f3595136bfe 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, Enum, ForeignKey, String +from sqlalchemy import Column, Enum, ForeignKey, String, Table from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import relationship from typing import Dict @@ -33,7 +33,8 @@ class SliceModel(_Base): context = relationship('ContextModel', back_populates='slices') slice_endpoints = relationship('SliceEndPointModel') # lazy='joined', back_populates='slice' slice_services = relationship('SliceServiceModel') # lazy='joined', back_populates='slice' - #slice_subslices = relationship('SliceSubSliceModel') # lazy='joined', back_populates='slice' + slice_subslices = relationship( + 'SliceSubSliceModel', primaryjoin='slice.c.slice_uuid == slice_subslice.c.slice_uuid') constraints = relationship('ConstraintModel', passive_deletes=True) # lazy='joined', back_populates='slice' config_rules = relationship('ConfigRuleModel', passive_deletes=True) # lazy='joined', back_populates='slice' @@ -65,11 +66,35 @@ class SliceModel(_Base): for slice_service in self.slice_services ], 'slice_subslice_ids': [ - #slice_subslice.subslice.dump_id() - #for slice_subslice in self.slice_subslices + slice_subslice.subslice.dump_id() + for slice_subslice in self.slice_subslices ], 'slice_owner': { 'owner_uuid': {'uuid': self.slice_owner_uuid}, 'owner_string': self.slice_owner_string } } + +class SliceEndPointModel(_Base): + __tablename__ = 'slice_endpoint' + + slice_uuid = Column(ForeignKey('slice.slice_uuid', ondelete='CASCADE' ), primary_key=True) + endpoint_uuid = Column(ForeignKey('endpoint.endpoint_uuid', ondelete='RESTRICT'), primary_key=True) + + slice = relationship('SliceModel', back_populates='slice_endpoints', lazy='joined') + endpoint = relationship('EndPointModel', lazy='joined') # back_populates='slice_endpoints' + +class SliceServiceModel(_Base): + __tablename__ = 'slice_service' + + slice_uuid = Column(ForeignKey('slice.slice_uuid', ondelete='CASCADE' ), primary_key=True) + service_uuid = Column(ForeignKey('service.service_uuid', ondelete='RESTRICT'), primary_key=True) + + slice = relationship('SliceModel', back_populates='slice_services', lazy='joined') + service = relationship('ServiceModel', lazy='joined') # back_populates='slice_services' + +class SliceSubSliceModel(_Base): + __tablename__ = 'slice_subslice' + + slice_uuid = Column(ForeignKey('slice.slice_uuid', ondelete='CASCADE' ), primary_key=True) + subslice_uuid = Column(ForeignKey('slice.slice_uuid', ondelete='RESTRICT'), primary_key=True) diff --git a/src/context/service/database/models/TopologyModel.py b/src/context/service/database/models/TopologyModel.py index 8c59bf58a01d64306ad0e6138ed7d561a1aae8c5..ef1ae0be8b23692cdefaf4d6a4e4f4627d916f24 100644 --- a/src/context/service/database/models/TopologyModel.py +++ b/src/context/service/database/models/TopologyModel.py @@ -42,3 +42,21 @@ class TopologyModel(_Base): 'device_ids' : [{'device_uuid': {'uuid': td.device_uuid}} for td in self.topology_devices], 'link_ids' : [{'link_uuid' : {'uuid': tl.link_uuid }} for tl in self.topology_links ], } + +class TopologyDeviceModel(_Base): + __tablename__ = 'topology_device' + + topology_uuid = Column(ForeignKey('topology.topology_uuid', ondelete='RESTRICT'), primary_key=True) + device_uuid = Column(ForeignKey('device.device_uuid', ondelete='CASCADE' ), primary_key=True) + + #topology = relationship('TopologyModel', lazy='joined') # back_populates='topology_devices' + device = relationship('DeviceModel', lazy='joined') # back_populates='topology_devices' + +class TopologyLinkModel(_Base): + __tablename__ = 'topology_link' + + topology_uuid = Column(ForeignKey('topology.topology_uuid', ondelete='RESTRICT'), primary_key=True) + link_uuid = Column(ForeignKey('link.link_uuid', ondelete='CASCADE' ), primary_key=True) + + #topology = relationship('TopologyModel', lazy='joined') # back_populates='topology_links' + link = relationship('LinkModel', lazy='joined') # back_populates='topology_links'