Loading proto/context.proto +11 −15 Original line number Diff line number Diff line Loading @@ -93,9 +93,13 @@ service ContextService { rpc GetOpticalBand (Empty ) returns (OpticalBandList) {} rpc SelectOpticalBand (OpticalBandId ) returns (OpticalBand) {} rpc ListChildTopology (Empty ) returns (ChildTopologyList) {} rpc ListChildTopologies (ContextId ) returns ( ChildTopologyList ) {} rpc GetChildTopology (TopologyId ) returns ( ChildTopology ) {} rpc GetChildTopologyDetails (TopologyId ) returns ( TopologyDetails ) {} rpc SetChildTopology (ChildTopology ) returns ( TopologyId ) {} rpc RemoveChildTopology (TopologyId ) returns ( Empty ) {} rpc DeleteServiceConfigRule(ServiceConfigRule) returns (Empty ) {} } Loading Loading @@ -765,20 +769,12 @@ message OpticalBandList { } message ChildEndpoint { EndPointId endpoint_id =1 ; DeviceId device_id = 2 ; string endpoint_name = 3; string device_name =4 ; } message ChildTopology { TopologyId topology_id = 2 ; string host = 3; int32 port = 4 ; repeated ChildEndpoint endpoints =5; string host = 1; int32 port = 2; Topology topology = 3 ; } Loading src/context/client/ContextClient.py +40 −2 Original line number Diff line number Diff line Loading @@ -28,7 +28,7 @@ from common.proto.context_pb2 import ( Service, ServiceConfigRule, ServiceEvent, ServiceFilter, ServiceId, ServiceIdList, ServiceList, Slice, SliceEvent, SliceFilter, SliceId, SliceIdList, SliceList, Topology, TopologyDetails, TopologyEvent, TopologyId, TopologyIdList, TopologyList,OpticalBand ,OpticalBandId, OpticalBandList , ChildTopologyList , ChildTopology , ChildEndpoint OpticalBandList , ChildTopologyList , ChildTopology ) from common.proto.context_pb2_grpc import ContextServiceStub from common.proto.context_policy_pb2_grpc import ContextPolicyServiceStub Loading Loading @@ -565,3 +565,41 @@ class ContextClient: LOGGER.debug('ServiceConfigRule Delete result: {:s}'.format(grpc_message_to_json_string(response))) return response # ------------------------------- TAPI Child Toplogy ----------------------- @RETRY_DECORATOR def ListChildTopologies(self, request: ContextId) -> ChildTopologyList: LOGGER.debug('ListChildTopologies request: {:s}'.format(grpc_message_to_json_string(request))) response = self.stub.ListChildTopologies(request) LOGGER.debug('ListChildTopologies result: {:s}'.format(grpc_message_to_json_string(response))) return response @RETRY_DECORATOR def GetChildTopology(self, request: TopologyId) -> ChildTopology: LOGGER.debug('GetChildTopology request: {:s}'.format(grpc_message_to_json_string(request))) response = self.stub.GetChildTopology(request) LOGGER.debug('GetChildTopology result: {:s}'.format(grpc_message_to_json_string(response))) return response @RETRY_DECORATOR def SetChildTopology(self, request: ChildTopology) -> TopologyId: LOGGER.debug('SetChildTopology request: {:s}'.format(grpc_message_to_json_string(request))) response = self.stub.SetChildTopology(request) LOGGER.debug('SetChildTopology result: {:s}'.format(grpc_message_to_json_string(response))) return response @RETRY_DECORATOR def RemoveChildTopology(self, request: TopologyId) -> Empty: LOGGER.debug('RemoveChildTopology request: {:s}'.format(grpc_message_to_json_string(request))) response = self.stub.RemoveChildTopology(request) LOGGER.debug('RemoveChildTopology result: {:s}'.format(grpc_message_to_json_string(response))) return response @RETRY_DECORATOR def GetChildTopologyDetails(self, request: TopologyId) -> TopologyDetails: LOGGER.debug('GetChildTopologyDetails request: {:s}'.format(grpc_message_to_json_string(request))) response = self.stub.GetChildTopologyDetails(request) LOGGER.debug('GetChildTopologyDetails result: {:s}'.format(grpc_message_to_json_string(response))) return response src/context/service/ContextServiceServicerImpl.py +19 −10 Original line number Diff line number Diff line Loading @@ -25,7 +25,7 @@ from common.proto.context_pb2 import ( Slice, SliceEvent, SliceFilter, SliceId, SliceIdList, SliceList, Topology, TopologyDetails, TopologyEvent, TopologyId, TopologyIdList, TopologyList, OpticalConfigList, OpticalConfigId, OpticalConfig, OpticalLink, OpticalLinkList, ServiceConfigRule,OpticalBand,OpticalBandId,OpticalBandList , ChildTopologyList , ChildTopology , ChildEndpoint ServiceConfigRule,OpticalBand,OpticalBandId,OpticalBandList , ChildTopologyList , ChildTopology ) from common.proto.policy_pb2 import PolicyRuleIdList, PolicyRuleId, PolicyRuleList, PolicyRule from common.proto.context_pb2_grpc import ContextServiceServicer Loading Loading @@ -74,7 +74,8 @@ from .database.OpticalBand import ( get_optical_band,set_optical_band , select_optical_band ) from .database.Tapi import ( get_child_topology , get_children_topology , set_child_topology) from .database.Tapi import ( child_topology_get , child_topology_get_details , child_topology_list_objs , child_topology_delete , child_topology_set) LOGGER = logging.getLogger(__name__) Loading Loading @@ -403,16 +404,24 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer def DeleteServiceConfigRule(self, request : ServiceConfigRule, context : grpc.ServicerContext) -> Empty: return delete_config_rule(self.db_engine, request) # ------------------------- TAPI Child Topology ---------------------------- @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) def ListChildTopologies(self, request : ContextId, context : grpc.ServicerContext) -> ChildTopologyList: return child_topology_list_objs(self.db_engine, request) @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) def GetChildTopology(self, request : TopologyId, context : grpc.ServicerContext) -> ChildTopology: return get_child_topology(self.db_engine, request) return child_topology_get(self.db_engine, request) @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) def ListChildTopology(self, request : Empty, context : grpc.ServicerContext) -> ChildTopologyList: return get_children_topology(self.db_engine, request) def GetChildTopologyDetails(self, request : TopologyId, context : grpc.ServicerContext) -> TopologyDetails: return child_topology_get_details(self.db_engine, request) @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) def SetChildTopology(self, request : ChildTopology, context : grpc.ServicerContext) -> TopologyId: topo_id= set_child_topology(self.db_engine, request) return TopologyId(topology_uuid=topo_id) No newline at end of file return child_topology_set(self.db_engine, self.messagebroker, request) @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) def RemoveChildTopology(self, request : TopologyId, context : grpc.ServicerContext) -> Empty: return child_topology_delete(self.db_engine, self.messagebroker, request) src/context/service/database/Tapi.py +140 −82 Original line number Diff line number Diff line Loading @@ -12,103 +12,161 @@ # See the License for the specific language governing permissions and # limitations under the License. import json, logging ,datetime import datetime, logging from sqlalchemy.dialects.postgresql import insert from common.message_broker.MessageBroker import MessageBroker from common.DeviceTypes import DeviceTypeEnum from sqlalchemy import inspect from sqlalchemy.engine import Engine from sqlalchemy.orm import Session, sessionmaker from sqlalchemy.orm import Session, selectinload, sessionmaker from sqlalchemy_cockroachdb import run_transaction from common.proto.context_pb2 import OpticalConfig, OpticalConfigId, Empty, EventTypeEnum ,ChildTopology , ChildEndpoint from .models.TapiModel import ChildTopologyModel ,ChildEndpointsModel from context.service.database.uuids.EndPoint import endpoint_get_uuid from context.service.database.uuids.Device import device_get_uuid from context.service.database.uuids.Topology import topology_get_uuid from typing import Dict, List, Optional, Set from common.proto.context_pb2 import ( ContextId, Empty, EventTypeEnum, ChildTopology, TopologyDetails, TopologyId, ChildTopologyList , Topology) from common.message_broker.MessageBroker import MessageBroker from common.method_wrappers.ServiceExceptions import NotFoundException from common.tools.object_factory.Context import json_context_id from common.tools.object_factory.Topology import json_topology_id from context.Config import ALLOW_EXPLICIT_ADD_DEVICE_TO_TOPOLOGY, ALLOW_EXPLICIT_ADD_LINK_TO_TOPOLOGY from .models.DeviceModel import DeviceModel from .models.OpticalLinkModel import OpticalLinkModel from .models.TapiModel import ChildTopologyDeviceModel, ChildTopologyOpticalLinkModel, ChildTopologyModel from .uuids.Context import context_get_uuid from .uuids.Device import device_get_uuid from .uuids.Link import link_get_uuid from .uuids.Topology import topology_get_uuid from .Events import notify_event_context, notify_event_topology from .Events import notify_event_opticalconfig from .OpticalBand import set_optical_band LOGGER = logging.getLogger(__name__) now = datetime.datetime.utcnow() def get_children_topology(db_engine : Engine): def callback(session:Session): results = session.query(ChildTopologyModel).all() return [r.dump() for r in results] def child_topology_list_objs(db_engine : Engine, request : ContextId) -> ChildTopologyList: context_uuid = context_get_uuid(request, allow_random=False) def callback(session : Session) -> List[Dict]: obj_list : List[ChildTopologyModel] = session.query(ChildTopologyModel)\ .options(selectinload(ChildTopologyModel.child_topology_devices))\ .options(selectinload(ChildTopologyModel.child_topology_optical_links))\ .filter_by(context_uuid=context_uuid).all() return [obj.dump() for obj in obj_list] topologies = run_transaction(sessionmaker(bind=db_engine), callback) return ChildTopologyList(topology_list=topologies) def child_topology_get(db_engine : Engine, request : TopologyId) -> ChildTopology: _,topology_uuid = topology_get_uuid(request, allow_random=False) def callback(session : Session) -> Optional[Dict]: obj : Optional[ChildTopologyModel] = session.query(ChildTopologyModel)\ .options(selectinload(ChildTopologyModel.child_topology_devices))\ .options(selectinload(ChildTopologyModel.child_topology_optical_links))\ .filter_by(child_topology_uuid=topology_uuid).one_or_none() return None if obj is None else obj.dump() obj = run_transaction(sessionmaker(bind=db_engine), callback) return obj def get_child_topology(db_engine : Engine , request:ChildTopology ): _topology_uuid = request.topology_id.topology_uuid.uuid def callback(session:Session): result = session.query(ChildEndpointsModel).filter_by(topology_uuid=_topology_uuid).one_or_none() return result.dump() if result else {} if obj is None: context_uuid = context_get_uuid(request.context_id, allow_random=False) raw_topology_uuid = '{:s}/{:s}'.format(request.context_id.context_uuid.uuid , request.topology_uuid.uuid) raise NotFoundException('Topology', raw_topology_uuid, extra_details=[ 'context_uuid generated was: {:s}'.format(context_uuid), 'topology_uuid generated was: {:s}'.format(topology_uuid), ]) return ChildTopology(**obj) def child_topology_get_details(db_engine : Engine, request : TopologyId) -> TopologyDetails: _,topology_uuid = topology_get_uuid(request, allow_random=False) def callback(session : Session) -> Optional[Dict]: obj : Optional[ChildTopologyModel] = session.query(ChildTopologyModel)\ .options(selectinload(ChildTopologyModel.child_topology_devices, ChildTopologyModel.device, DeviceModel.endpoints))\ .options(selectinload(ChildTopologyModel.child_topology_optical_links , ChildTopologyOpticalLinkModel.optical_link, OpticalLinkModel.opticallink_endpoints))\ .filter_by(child_topology_uuid=topology_uuid).one_or_none() #.options(selectinload(DeviceModel.components))\ return None if obj is None else obj.dump_details() obj = run_transaction(sessionmaker(bind=db_engine), callback) return obj if obj is None: context_uuid = context_get_uuid(request.topology.context_id, allow_random=False) raw_topology_uuid = '{:s}/{:s}'.format(request.context_id.context_uuid.uuid, request.topology_uuid.uuid) raise NotFoundException('Topology', raw_topology_uuid, extra_details=[ 'context_uuid generated was: {:s}'.format(context_uuid), 'topology_uuid generated was: {:s}'.format(topology_uuid), ]) return TopologyDetails(**obj) def child_topology_set(db_engine : Engine, messagebroker : MessageBroker, request : ChildTopology) -> TopologyId: topology_name = request.topology.name if len(topology_name) == 0: topology_name = request.topology.topology_id.topology_uuid.uuid context_uuid,topology_uuid = topology_get_uuid(request.topology.topology_id, topology_name=topology_name, allow_random=True) # By default, ignore request.device_ids and request.link_ids. They are used for retrieving # devices and links added into the topology. Explicit addition into the topology is done # automatically when creating the devices and links, based on the topologies specified in # the endpoints associated with the devices and links. # In some cases, it might be needed to add them explicitly; to allow that, activate flags # ALLOW_EXPLICIT_ADD_DEVICE_TO_TOPOLOGY and/or ALLOW_EXPLICIT_ADD_LINK_TO_TOPOLOGY. related_devices : List[Dict] = list() if ALLOW_EXPLICIT_ADD_DEVICE_TO_TOPOLOGY: device_uuids : Set[str] = set() for device_id in request.toplogy.device_ids: device_uuid = device_get_uuid(device_id) if device_uuid not in device_uuids: continue related_devices.append({'topology_uuid': topology_uuid, 'device_uuid': device_uuid}) device_uuids.add(device_uuid) else: if len(request.topology.device_ids) > 0: # pragma: no cover MSG = 'ALLOW_EXPLICIT_ADD_DEVICE_TO_TOPOLOGY={:s}; '.format(str(ALLOW_EXPLICIT_ADD_DEVICE_TO_TOPOLOGY)) MSG += 'Items in field "device_ids" ignored. This field is used for retrieval purposes only.' LOGGER.warning(MSG) def set_child_topology(db_engine : Engine, request : ChildTopology): topology_uuid = request.topology_id.topology_uuid.uuid endpoints_list = [] topology = {} #is_transpondre = False now = datetime.datetime.now(datetime.timezone.utc) _,topo_uuid= topology_get_uuid(request.topology_id) for endpoint in request.endpoints: endpoints_list.append({ 'endpoint_uuid':endpoint.endpoint_id.endpoint_uuid.uuid, 'device_uuid':endpoint.device_id.device_uuid.uuid, 'endpoint_name':endpoint.endpoint_name, 'device_name':endpoint.device_name, 'updated_at':now , 'created_at':now, 'topology_uuid':topo_uuid }) topology = { 'topology_uuid':topo_uuid, topology_data = [{ 'context_uuid' : context_uuid, 'child_topology_uuid': topology_uuid, 'topology_name': topology_name, 'created_at' : now, 'updated_at' : now, 'host' : request.host, 'port':request.port } def callback(session:Session)->bool: 'port' : request.port, }] stmt = insert(ChildTopologyModel).values(topology) def callback(session : Session) -> bool: stmt = insert(ChildTopologyModel).values(topology_data) stmt = stmt.on_conflict_do_update( index_elements=[ChildTopologyModel.topology_uuid], index_elements=[ChildTopologyModel.child_topology_uuid], set_=dict( host = stmt.excluded.host, port= stmt.excluded.port, topology_name = stmt.excluded.topology_name, updated_at = stmt.excluded.updated_at, ) ) stmt = stmt.returning(ChildTopologyModel.topology_uuid) topology_uuid = session.execute(stmt).fetchone() if topology_uuid and len(endpoints_list) > 0: en_list=[] for en in endpoints_list : stmt = insert(ChildEndpointsModel).values(**en) update_stmt = stmt.on_conflict_do_update( index_elements=[ChildEndpointsModel.endpoint_uuid], set_=dict( endpoint_name = stmt.excluded.endpoint_name, device_name = stmt.excluded.device_name, created_at = stmt.excluded.created_at, updated_at = stmt.excluded.updated_at, stmt = stmt.returning(ChildTopologyModel.created_at, ChildTopologyModel.updated_at) created_at,updated_at = session.execute(stmt).fetchone() updated = updated_at > created_at updated_topology_device = False if len(related_devices) > 0: stmt = insert(ChildTopologyDeviceModel).values(related_devices) stmt = stmt.on_conflict_do_nothing( index_elements=[ChildTopologyDeviceModel.topology_uuid, ChildTopologyDeviceModel.device_uuid] ) ).returning(ChildEndpointsModel.endpoint_uuid) result = session.execute(update_stmt).fetchone() en_list.append(result) topology_device_inserts = session.execute(stmt) updated_topology_device = int(topology_device_inserts.rowcount) > 0 return updated or updated_topology_device updated = run_transaction(sessionmaker(bind=db_engine), callback) context_id = json_context_id(context_uuid) topology_id = json_topology_id(topology_uuid, context_id=context_id) return TopologyId(**topology_id) def child_topology_delete(db_engine : Engine, messagebroker : MessageBroker, request : TopologyId) -> Empty: context_uuid,topology_uuid = topology_get_uuid(request, allow_random=False) def callback(session : Session) -> bool: num_deleted = session.query(ChildTopologyModel).filter_by(child_topology_uuid=topology_uuid).delete() return num_deleted > 0 deleted = run_transaction(sessionmaker(bind=db_engine), callback) context_id = json_context_id(context_uuid) topology_id = json_topology_id(topology_uuid, context_id=context_id) topology_uuid = run_transaction(sessionmaker(bind=db_engine), callback) return {'uuid': topology_uuid} No newline at end of file return Empty() src/context/service/database/models/OpticalLinkModel.py +1 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ class OpticalLinkModel(_Base): s_slots = Column (S_Slot,nullable=True) opticallink_endpoints = relationship('OpticalLinkEndPointModel') topology_optical_links = relationship('TopologyOpticalLinkModel', back_populates='optical_link') child_topology_optical_links = relationship('ChildTopologyOpticalLinkModel', back_populates='optical_link') def dump_id(self) -> Dict: return {'link_uuid': {'uuid': self.opticallink_uuid}} Loading Loading
proto/context.proto +11 −15 Original line number Diff line number Diff line Loading @@ -93,9 +93,13 @@ service ContextService { rpc GetOpticalBand (Empty ) returns (OpticalBandList) {} rpc SelectOpticalBand (OpticalBandId ) returns (OpticalBand) {} rpc ListChildTopology (Empty ) returns (ChildTopologyList) {} rpc ListChildTopologies (ContextId ) returns ( ChildTopologyList ) {} rpc GetChildTopology (TopologyId ) returns ( ChildTopology ) {} rpc GetChildTopologyDetails (TopologyId ) returns ( TopologyDetails ) {} rpc SetChildTopology (ChildTopology ) returns ( TopologyId ) {} rpc RemoveChildTopology (TopologyId ) returns ( Empty ) {} rpc DeleteServiceConfigRule(ServiceConfigRule) returns (Empty ) {} } Loading Loading @@ -765,20 +769,12 @@ message OpticalBandList { } message ChildEndpoint { EndPointId endpoint_id =1 ; DeviceId device_id = 2 ; string endpoint_name = 3; string device_name =4 ; } message ChildTopology { TopologyId topology_id = 2 ; string host = 3; int32 port = 4 ; repeated ChildEndpoint endpoints =5; string host = 1; int32 port = 2; Topology topology = 3 ; } Loading
src/context/client/ContextClient.py +40 −2 Original line number Diff line number Diff line Loading @@ -28,7 +28,7 @@ from common.proto.context_pb2 import ( Service, ServiceConfigRule, ServiceEvent, ServiceFilter, ServiceId, ServiceIdList, ServiceList, Slice, SliceEvent, SliceFilter, SliceId, SliceIdList, SliceList, Topology, TopologyDetails, TopologyEvent, TopologyId, TopologyIdList, TopologyList,OpticalBand ,OpticalBandId, OpticalBandList , ChildTopologyList , ChildTopology , ChildEndpoint OpticalBandList , ChildTopologyList , ChildTopology ) from common.proto.context_pb2_grpc import ContextServiceStub from common.proto.context_policy_pb2_grpc import ContextPolicyServiceStub Loading Loading @@ -565,3 +565,41 @@ class ContextClient: LOGGER.debug('ServiceConfigRule Delete result: {:s}'.format(grpc_message_to_json_string(response))) return response # ------------------------------- TAPI Child Toplogy ----------------------- @RETRY_DECORATOR def ListChildTopologies(self, request: ContextId) -> ChildTopologyList: LOGGER.debug('ListChildTopologies request: {:s}'.format(grpc_message_to_json_string(request))) response = self.stub.ListChildTopologies(request) LOGGER.debug('ListChildTopologies result: {:s}'.format(grpc_message_to_json_string(response))) return response @RETRY_DECORATOR def GetChildTopology(self, request: TopologyId) -> ChildTopology: LOGGER.debug('GetChildTopology request: {:s}'.format(grpc_message_to_json_string(request))) response = self.stub.GetChildTopology(request) LOGGER.debug('GetChildTopology result: {:s}'.format(grpc_message_to_json_string(response))) return response @RETRY_DECORATOR def SetChildTopology(self, request: ChildTopology) -> TopologyId: LOGGER.debug('SetChildTopology request: {:s}'.format(grpc_message_to_json_string(request))) response = self.stub.SetChildTopology(request) LOGGER.debug('SetChildTopology result: {:s}'.format(grpc_message_to_json_string(response))) return response @RETRY_DECORATOR def RemoveChildTopology(self, request: TopologyId) -> Empty: LOGGER.debug('RemoveChildTopology request: {:s}'.format(grpc_message_to_json_string(request))) response = self.stub.RemoveChildTopology(request) LOGGER.debug('RemoveChildTopology result: {:s}'.format(grpc_message_to_json_string(response))) return response @RETRY_DECORATOR def GetChildTopologyDetails(self, request: TopologyId) -> TopologyDetails: LOGGER.debug('GetChildTopologyDetails request: {:s}'.format(grpc_message_to_json_string(request))) response = self.stub.GetChildTopologyDetails(request) LOGGER.debug('GetChildTopologyDetails result: {:s}'.format(grpc_message_to_json_string(response))) return response
src/context/service/ContextServiceServicerImpl.py +19 −10 Original line number Diff line number Diff line Loading @@ -25,7 +25,7 @@ from common.proto.context_pb2 import ( Slice, SliceEvent, SliceFilter, SliceId, SliceIdList, SliceList, Topology, TopologyDetails, TopologyEvent, TopologyId, TopologyIdList, TopologyList, OpticalConfigList, OpticalConfigId, OpticalConfig, OpticalLink, OpticalLinkList, ServiceConfigRule,OpticalBand,OpticalBandId,OpticalBandList , ChildTopologyList , ChildTopology , ChildEndpoint ServiceConfigRule,OpticalBand,OpticalBandId,OpticalBandList , ChildTopologyList , ChildTopology ) from common.proto.policy_pb2 import PolicyRuleIdList, PolicyRuleId, PolicyRuleList, PolicyRule from common.proto.context_pb2_grpc import ContextServiceServicer Loading Loading @@ -74,7 +74,8 @@ from .database.OpticalBand import ( get_optical_band,set_optical_band , select_optical_band ) from .database.Tapi import ( get_child_topology , get_children_topology , set_child_topology) from .database.Tapi import ( child_topology_get , child_topology_get_details , child_topology_list_objs , child_topology_delete , child_topology_set) LOGGER = logging.getLogger(__name__) Loading Loading @@ -403,16 +404,24 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer def DeleteServiceConfigRule(self, request : ServiceConfigRule, context : grpc.ServicerContext) -> Empty: return delete_config_rule(self.db_engine, request) # ------------------------- TAPI Child Topology ---------------------------- @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) def ListChildTopologies(self, request : ContextId, context : grpc.ServicerContext) -> ChildTopologyList: return child_topology_list_objs(self.db_engine, request) @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) def GetChildTopology(self, request : TopologyId, context : grpc.ServicerContext) -> ChildTopology: return get_child_topology(self.db_engine, request) return child_topology_get(self.db_engine, request) @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) def ListChildTopology(self, request : Empty, context : grpc.ServicerContext) -> ChildTopologyList: return get_children_topology(self.db_engine, request) def GetChildTopologyDetails(self, request : TopologyId, context : grpc.ServicerContext) -> TopologyDetails: return child_topology_get_details(self.db_engine, request) @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) def SetChildTopology(self, request : ChildTopology, context : grpc.ServicerContext) -> TopologyId: topo_id= set_child_topology(self.db_engine, request) return TopologyId(topology_uuid=topo_id) No newline at end of file return child_topology_set(self.db_engine, self.messagebroker, request) @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) def RemoveChildTopology(self, request : TopologyId, context : grpc.ServicerContext) -> Empty: return child_topology_delete(self.db_engine, self.messagebroker, request)
src/context/service/database/Tapi.py +140 −82 Original line number Diff line number Diff line Loading @@ -12,103 +12,161 @@ # See the License for the specific language governing permissions and # limitations under the License. import json, logging ,datetime import datetime, logging from sqlalchemy.dialects.postgresql import insert from common.message_broker.MessageBroker import MessageBroker from common.DeviceTypes import DeviceTypeEnum from sqlalchemy import inspect from sqlalchemy.engine import Engine from sqlalchemy.orm import Session, sessionmaker from sqlalchemy.orm import Session, selectinload, sessionmaker from sqlalchemy_cockroachdb import run_transaction from common.proto.context_pb2 import OpticalConfig, OpticalConfigId, Empty, EventTypeEnum ,ChildTopology , ChildEndpoint from .models.TapiModel import ChildTopologyModel ,ChildEndpointsModel from context.service.database.uuids.EndPoint import endpoint_get_uuid from context.service.database.uuids.Device import device_get_uuid from context.service.database.uuids.Topology import topology_get_uuid from typing import Dict, List, Optional, Set from common.proto.context_pb2 import ( ContextId, Empty, EventTypeEnum, ChildTopology, TopologyDetails, TopologyId, ChildTopologyList , Topology) from common.message_broker.MessageBroker import MessageBroker from common.method_wrappers.ServiceExceptions import NotFoundException from common.tools.object_factory.Context import json_context_id from common.tools.object_factory.Topology import json_topology_id from context.Config import ALLOW_EXPLICIT_ADD_DEVICE_TO_TOPOLOGY, ALLOW_EXPLICIT_ADD_LINK_TO_TOPOLOGY from .models.DeviceModel import DeviceModel from .models.OpticalLinkModel import OpticalLinkModel from .models.TapiModel import ChildTopologyDeviceModel, ChildTopologyOpticalLinkModel, ChildTopologyModel from .uuids.Context import context_get_uuid from .uuids.Device import device_get_uuid from .uuids.Link import link_get_uuid from .uuids.Topology import topology_get_uuid from .Events import notify_event_context, notify_event_topology from .Events import notify_event_opticalconfig from .OpticalBand import set_optical_band LOGGER = logging.getLogger(__name__) now = datetime.datetime.utcnow() def get_children_topology(db_engine : Engine): def callback(session:Session): results = session.query(ChildTopologyModel).all() return [r.dump() for r in results] def child_topology_list_objs(db_engine : Engine, request : ContextId) -> ChildTopologyList: context_uuid = context_get_uuid(request, allow_random=False) def callback(session : Session) -> List[Dict]: obj_list : List[ChildTopologyModel] = session.query(ChildTopologyModel)\ .options(selectinload(ChildTopologyModel.child_topology_devices))\ .options(selectinload(ChildTopologyModel.child_topology_optical_links))\ .filter_by(context_uuid=context_uuid).all() return [obj.dump() for obj in obj_list] topologies = run_transaction(sessionmaker(bind=db_engine), callback) return ChildTopologyList(topology_list=topologies) def child_topology_get(db_engine : Engine, request : TopologyId) -> ChildTopology: _,topology_uuid = topology_get_uuid(request, allow_random=False) def callback(session : Session) -> Optional[Dict]: obj : Optional[ChildTopologyModel] = session.query(ChildTopologyModel)\ .options(selectinload(ChildTopologyModel.child_topology_devices))\ .options(selectinload(ChildTopologyModel.child_topology_optical_links))\ .filter_by(child_topology_uuid=topology_uuid).one_or_none() return None if obj is None else obj.dump() obj = run_transaction(sessionmaker(bind=db_engine), callback) return obj def get_child_topology(db_engine : Engine , request:ChildTopology ): _topology_uuid = request.topology_id.topology_uuid.uuid def callback(session:Session): result = session.query(ChildEndpointsModel).filter_by(topology_uuid=_topology_uuid).one_or_none() return result.dump() if result else {} if obj is None: context_uuid = context_get_uuid(request.context_id, allow_random=False) raw_topology_uuid = '{:s}/{:s}'.format(request.context_id.context_uuid.uuid , request.topology_uuid.uuid) raise NotFoundException('Topology', raw_topology_uuid, extra_details=[ 'context_uuid generated was: {:s}'.format(context_uuid), 'topology_uuid generated was: {:s}'.format(topology_uuid), ]) return ChildTopology(**obj) def child_topology_get_details(db_engine : Engine, request : TopologyId) -> TopologyDetails: _,topology_uuid = topology_get_uuid(request, allow_random=False) def callback(session : Session) -> Optional[Dict]: obj : Optional[ChildTopologyModel] = session.query(ChildTopologyModel)\ .options(selectinload(ChildTopologyModel.child_topology_devices, ChildTopologyModel.device, DeviceModel.endpoints))\ .options(selectinload(ChildTopologyModel.child_topology_optical_links , ChildTopologyOpticalLinkModel.optical_link, OpticalLinkModel.opticallink_endpoints))\ .filter_by(child_topology_uuid=topology_uuid).one_or_none() #.options(selectinload(DeviceModel.components))\ return None if obj is None else obj.dump_details() obj = run_transaction(sessionmaker(bind=db_engine), callback) return obj if obj is None: context_uuid = context_get_uuid(request.topology.context_id, allow_random=False) raw_topology_uuid = '{:s}/{:s}'.format(request.context_id.context_uuid.uuid, request.topology_uuid.uuid) raise NotFoundException('Topology', raw_topology_uuid, extra_details=[ 'context_uuid generated was: {:s}'.format(context_uuid), 'topology_uuid generated was: {:s}'.format(topology_uuid), ]) return TopologyDetails(**obj) def child_topology_set(db_engine : Engine, messagebroker : MessageBroker, request : ChildTopology) -> TopologyId: topology_name = request.topology.name if len(topology_name) == 0: topology_name = request.topology.topology_id.topology_uuid.uuid context_uuid,topology_uuid = topology_get_uuid(request.topology.topology_id, topology_name=topology_name, allow_random=True) # By default, ignore request.device_ids and request.link_ids. They are used for retrieving # devices and links added into the topology. Explicit addition into the topology is done # automatically when creating the devices and links, based on the topologies specified in # the endpoints associated with the devices and links. # In some cases, it might be needed to add them explicitly; to allow that, activate flags # ALLOW_EXPLICIT_ADD_DEVICE_TO_TOPOLOGY and/or ALLOW_EXPLICIT_ADD_LINK_TO_TOPOLOGY. related_devices : List[Dict] = list() if ALLOW_EXPLICIT_ADD_DEVICE_TO_TOPOLOGY: device_uuids : Set[str] = set() for device_id in request.toplogy.device_ids: device_uuid = device_get_uuid(device_id) if device_uuid not in device_uuids: continue related_devices.append({'topology_uuid': topology_uuid, 'device_uuid': device_uuid}) device_uuids.add(device_uuid) else: if len(request.topology.device_ids) > 0: # pragma: no cover MSG = 'ALLOW_EXPLICIT_ADD_DEVICE_TO_TOPOLOGY={:s}; '.format(str(ALLOW_EXPLICIT_ADD_DEVICE_TO_TOPOLOGY)) MSG += 'Items in field "device_ids" ignored. This field is used for retrieval purposes only.' LOGGER.warning(MSG) def set_child_topology(db_engine : Engine, request : ChildTopology): topology_uuid = request.topology_id.topology_uuid.uuid endpoints_list = [] topology = {} #is_transpondre = False now = datetime.datetime.now(datetime.timezone.utc) _,topo_uuid= topology_get_uuid(request.topology_id) for endpoint in request.endpoints: endpoints_list.append({ 'endpoint_uuid':endpoint.endpoint_id.endpoint_uuid.uuid, 'device_uuid':endpoint.device_id.device_uuid.uuid, 'endpoint_name':endpoint.endpoint_name, 'device_name':endpoint.device_name, 'updated_at':now , 'created_at':now, 'topology_uuid':topo_uuid }) topology = { 'topology_uuid':topo_uuid, topology_data = [{ 'context_uuid' : context_uuid, 'child_topology_uuid': topology_uuid, 'topology_name': topology_name, 'created_at' : now, 'updated_at' : now, 'host' : request.host, 'port':request.port } def callback(session:Session)->bool: 'port' : request.port, }] stmt = insert(ChildTopologyModel).values(topology) def callback(session : Session) -> bool: stmt = insert(ChildTopologyModel).values(topology_data) stmt = stmt.on_conflict_do_update( index_elements=[ChildTopologyModel.topology_uuid], index_elements=[ChildTopologyModel.child_topology_uuid], set_=dict( host = stmt.excluded.host, port= stmt.excluded.port, topology_name = stmt.excluded.topology_name, updated_at = stmt.excluded.updated_at, ) ) stmt = stmt.returning(ChildTopologyModel.topology_uuid) topology_uuid = session.execute(stmt).fetchone() if topology_uuid and len(endpoints_list) > 0: en_list=[] for en in endpoints_list : stmt = insert(ChildEndpointsModel).values(**en) update_stmt = stmt.on_conflict_do_update( index_elements=[ChildEndpointsModel.endpoint_uuid], set_=dict( endpoint_name = stmt.excluded.endpoint_name, device_name = stmt.excluded.device_name, created_at = stmt.excluded.created_at, updated_at = stmt.excluded.updated_at, stmt = stmt.returning(ChildTopologyModel.created_at, ChildTopologyModel.updated_at) created_at,updated_at = session.execute(stmt).fetchone() updated = updated_at > created_at updated_topology_device = False if len(related_devices) > 0: stmt = insert(ChildTopologyDeviceModel).values(related_devices) stmt = stmt.on_conflict_do_nothing( index_elements=[ChildTopologyDeviceModel.topology_uuid, ChildTopologyDeviceModel.device_uuid] ) ).returning(ChildEndpointsModel.endpoint_uuid) result = session.execute(update_stmt).fetchone() en_list.append(result) topology_device_inserts = session.execute(stmt) updated_topology_device = int(topology_device_inserts.rowcount) > 0 return updated or updated_topology_device updated = run_transaction(sessionmaker(bind=db_engine), callback) context_id = json_context_id(context_uuid) topology_id = json_topology_id(topology_uuid, context_id=context_id) return TopologyId(**topology_id) def child_topology_delete(db_engine : Engine, messagebroker : MessageBroker, request : TopologyId) -> Empty: context_uuid,topology_uuid = topology_get_uuid(request, allow_random=False) def callback(session : Session) -> bool: num_deleted = session.query(ChildTopologyModel).filter_by(child_topology_uuid=topology_uuid).delete() return num_deleted > 0 deleted = run_transaction(sessionmaker(bind=db_engine), callback) context_id = json_context_id(context_uuid) topology_id = json_topology_id(topology_uuid, context_id=context_id) topology_uuid = run_transaction(sessionmaker(bind=db_engine), callback) return {'uuid': topology_uuid} No newline at end of file return Empty()
src/context/service/database/models/OpticalLinkModel.py +1 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ class OpticalLinkModel(_Base): s_slots = Column (S_Slot,nullable=True) opticallink_endpoints = relationship('OpticalLinkEndPointModel') topology_optical_links = relationship('TopologyOpticalLinkModel', back_populates='optical_link') child_topology_optical_links = relationship('ChildTopologyOpticalLinkModel', back_populates='optical_link') def dump_id(self) -> Dict: return {'link_uuid': {'uuid': self.opticallink_uuid}} Loading