diff --git a/src/context/client/ContextClient.py b/src/context/client/ContextClient.py index f91f36cf5bf73669e4010c8c65d9c4cabd9c6e2e..7559dde0f64f3264ee568eecd7842ebc1c76c740 100644 --- a/src/context/client/ContextClient.py +++ b/src/context/client/ContextClient.py @@ -22,11 +22,11 @@ from common.proto.context_pb2 import ( Connection, ConnectionEvent, ConnectionId, ConnectionIdList, ConnectionList, Context, ContextEvent, ContextId, ContextIdList, ContextList, Device, DeviceEvent, DeviceId, DeviceIdList, DeviceList, - Empty, + Empty, EndPointIdList, EndPointNameList, Link, LinkEvent, LinkId, LinkIdList, LinkList, Service, ServiceEvent, ServiceId, ServiceIdList, ServiceList, Slice, SliceEvent, SliceId, SliceIdList, SliceList, - Topology, TopologyEvent, TopologyId, TopologyIdList, TopologyList) + Topology, TopologyDetails, TopologyEvent, TopologyId, TopologyIdList, TopologyList) from common.proto.context_pb2_grpc import ContextServiceStub from common.proto.context_policy_pb2_grpc import ContextPolicyServiceStub from common.proto.policy_pb2 import PolicyRuleIdList, PolicyRuleId, PolicyRuleList, PolicyRule @@ -143,6 +143,13 @@ class ContextClient: LOGGER.debug('GetTopologyEvents result: {:s}'.format(grpc_message_to_json_string(response))) return response + @RETRY_DECORATOR + def GetTopologyDetails(self, request: TopologyId) -> TopologyDetails: + LOGGER.debug('GetTopologyDetails request: {:s}'.format(grpc_message_to_json_string(request))) + response = self.stub.GetTopologyDetails(request) + LOGGER.debug('GetTopologyDetails result: {:s}'.format(grpc_message_to_json_string(response))) + return response + @RETRY_DECORATOR def ListDeviceIds(self, request: Empty) -> DeviceIdList: LOGGER.debug('ListDeviceIds request: {:s}'.format(grpc_message_to_json_string(request))) @@ -185,6 +192,13 @@ class ContextClient: LOGGER.debug('GetDeviceEvents result: {:s}'.format(grpc_message_to_json_string(response))) return response + @RETRY_DECORATOR + def ListEndPointNames(self, request: EndPointIdList) -> EndPointNameList: + LOGGER.debug('ListEndPointNames request: {:s}'.format(grpc_message_to_json_string(request))) + response = self.stub.ListEndPointNames(request) + LOGGER.debug('ListEndPointNames result: {:s}'.format(grpc_message_to_json_string(response))) + return response + @RETRY_DECORATOR def ListLinkIds(self, request: Empty) -> LinkIdList: LOGGER.debug('ListLinkIds request: {:s}'.format(grpc_message_to_json_string(request))) diff --git a/src/context/service/ContextServiceServicerImpl.py b/src/context/service/ContextServiceServicerImpl.py index 82e28a7f13135735909a99b635cf26bb3e02e252..41126b8d41a6df30340ec12b1adeb767fdcc58a3 100644 --- a/src/context/service/ContextServiceServicerImpl.py +++ b/src/context/service/ContextServiceServicerImpl.py @@ -19,11 +19,11 @@ from common.proto.context_pb2 import ( Connection, ConnectionEvent, ConnectionId, ConnectionIdList, ConnectionList, Context, ContextEvent, ContextId, ContextIdList, ContextList, Device, DeviceEvent, DeviceId, DeviceIdList, DeviceList, - Empty, EventTypeEnum, + Empty, EndPointIdList, EndPointNameList, EventTypeEnum, Link, LinkEvent, LinkId, LinkIdList, LinkList, Service, ServiceEvent, ServiceId, ServiceIdList, ServiceList, Slice, SliceEvent, SliceId, SliceIdList, SliceList, - Topology, TopologyEvent, TopologyId, TopologyIdList, TopologyList) + Topology, TopologyDetails, TopologyEvent, TopologyId, TopologyIdList, TopologyList) from common.proto.policy_pb2 import PolicyRuleIdList, PolicyRuleId, PolicyRuleList, PolicyRule from common.proto.context_pb2_grpc import ContextServiceServicer from common.proto.context_policy_pb2_grpc import ContextPolicyServiceServicer @@ -32,12 +32,14 @@ from .database.Connection import ( connection_delete, connection_get, connection_list_ids, connection_list_objs, connection_set) from .database.Context import context_delete, context_get, context_list_ids, context_list_objs, context_set from .database.Device import device_delete, device_get, device_list_ids, device_list_objs, device_set +from .database.EndPoint import endpoint_list_names from .database.Link import link_delete, link_get, link_list_ids, link_list_objs, link_set from .database.PolicyRule import ( policyrule_delete, policyrule_get, policyrule_list_ids, policyrule_list_objs, policyrule_set) from .database.Service import service_delete, service_get, service_list_ids, service_list_objs, service_set from .database.Slice import slice_delete, slice_get, slice_list_ids, slice_list_objs, slice_set, slice_unset -from .database.Topology import topology_delete, topology_get, topology_list_ids, topology_list_objs, topology_set +from .database.Topology import ( + topology_delete, topology_get, topology_get_details, topology_list_ids, topology_list_objs, topology_set) from .Events import ( CONSUME_TIMEOUT, TOPIC_CONNECTION, TOPIC_CONTEXT, TOPIC_DEVICE, TOPIC_LINK, TOPIC_POLICY, TOPIC_SERVICE, TOPIC_SLICE, TOPIC_TOPOLOGY, notify_event) @@ -105,6 +107,10 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer def GetTopology(self, request : TopologyId, context : grpc.ServicerContext) -> Topology: return Topology(**topology_get(self.db_engine, request)) + @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) + def GetTopologyDetails(self, request : TopologyId, context : grpc.ServicerContext) -> TopologyDetails: + return TopologyDetails(**topology_get_details(self.db_engine, request)) + @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) def SetTopology(self, request : Topology, context : grpc.ServicerContext) -> TopologyId: topology_id,updated = topology_set(self.db_engine, request) @@ -160,6 +166,10 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer for message in self.messagebroker.consume({TOPIC_DEVICE}, consume_timeout=CONSUME_TIMEOUT): yield DeviceEvent(**json.loads(message.content)) + @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) + def ListEndPointNames(self, request : EndPointIdList, context : grpc.ServicerContext) -> EndPointNameList: + return EndPointNameList(endpoint_names=endpoint_list_names(self.db_engine, request)) + # ----- Link ------------------------------------------------------------------------------------------------------- diff --git a/src/context/service/database/EndPoint.py b/src/context/service/database/EndPoint.py new file mode 100644 index 0000000000000000000000000000000000000000..a26ed902c5b756dfe6bf24eefaaa55eed923db96 --- /dev/null +++ b/src/context/service/database/EndPoint.py @@ -0,0 +1,35 @@ +# 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. + +import logging +from sqlalchemy.engine import Engine +from sqlalchemy.orm import Session, sessionmaker +from sqlalchemy_cockroachdb import run_transaction +from typing import Dict, List +from common.proto.context_pb2 import EndPointIdList +from .models.EndPointModel import EndPointModel +from .uuids.EndPoint import endpoint_get_uuid + +LOGGER = logging.getLogger(__name__) + +def endpoint_list_names(db_engine : Engine, request : EndPointIdList) -> List[Dict]: + endpoint_uuids = { + endpoint_get_uuid(endpoint_id, allow_random=False)[-1] + for endpoint_id in request.endpoint_ids + } + def callback(session : Session) -> List[Dict]: + obj_list : List[EndPointModel] = \ + session.query(EndPointModel).filter(EndPointModel.endpoint_uuid.in_(endpoint_uuids)).all() + return [obj.dump_name() for obj in obj_list] + return run_transaction(sessionmaker(bind=db_engine), callback) diff --git a/src/context/service/database/Topology.py b/src/context/service/database/Topology.py index fcd93e6bb2500c370b5e0e9a206e7d7117507b88..81170d0a1dfb13185fb1a746be4b3ae8a97ff718 100644 --- a/src/context/service/database/Topology.py +++ b/src/context/service/database/Topology.py @@ -58,6 +58,22 @@ def topology_get(db_engine : Engine, request : TopologyId) -> Dict: ]) return obj +def topology_get_details(db_engine : Engine, request : TopologyId) -> Dict: + _,topology_uuid = topology_get_uuid(request, allow_random=False) + def callback(session : Session) -> Optional[Dict]: + obj : Optional[TopologyModel] = session.query(TopologyModel)\ + .filter_by(topology_uuid=topology_uuid).one_or_none() + return None if obj is None else obj.dump_details() + obj = run_transaction(sessionmaker(bind=db_engine), callback) + 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 obj + def topology_set(db_engine : Engine, request : Topology) -> Tuple[Dict, bool]: topology_name = request.name if len(topology_name) == 0: topology_name = request.topology_id.topology_uuid.uuid diff --git a/src/context/service/database/models/EndPointModel.py b/src/context/service/database/models/EndPointModel.py index 07a5df2bf69e154f8d969d716a2eb914145f9919..65d867f3f7ec80c7ffab7e3e2eadae0ca6849a48 100644 --- a/src/context/service/database/models/EndPointModel.py +++ b/src/context/service/database/models/EndPointModel.py @@ -51,3 +51,11 @@ class EndPointModel(_Base): 'endpoint_type' : self.endpoint_type, 'kpi_sample_types': [kst.value for kst in self.kpi_sample_types], } + + def dump_name(self) -> Dict: + return { + 'endpoint_id' : self.dump_id(), + 'device_name' : self.device.device_name, + 'endpoint_name': self.name, + 'endpoint_type': self.endpoint_type, + } diff --git a/src/context/service/database/models/TopologyModel.py b/src/context/service/database/models/TopologyModel.py index 59659ecd3f8ad9f896bd7d8f07c1f65ba1d6f27d..cf730b168a42b30daff0119595f57ace8e665060 100644 --- a/src/context/service/database/models/TopologyModel.py +++ b/src/context/service/database/models/TopologyModel.py @@ -45,6 +45,14 @@ class TopologyModel(_Base): 'link_ids' : [{'link_uuid' : {'uuid': tl.link_uuid }} for tl in self.topology_links ], } + def dump_details(self) -> Dict: + return { + 'topology_id': self.dump_id(), + 'name' : self.topology_name, + 'devices' : [td.device.dump() for td in self.topology_devices], + 'links' : [tl.link.dump() for tl in self.topology_links ], + } + class TopologyDeviceModel(_Base): __tablename__ = 'topology_device'