From f1fc0d452d4c6314c243073c12ba9e942c98db9a Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Sun, 29 Jan 2023 20:43:35 +0000 Subject: [PATCH 1/5] Common - Proto: - Added gRPC method to retrieve names of endpoints and devices - Added gRPC method to retrieve topology details --- proto/context.proto | 125 ++++++++++++++++++++++++++------------------ 1 file changed, 75 insertions(+), 50 deletions(-) diff --git a/proto/context.proto b/proto/context.proto index ce7534c80..3ab3597e4 100644 --- a/proto/context.proto +++ b/proto/context.proto @@ -19,56 +19,59 @@ import "acl.proto"; import "kpi_sample_types.proto"; service ContextService { - rpc ListContextIds (Empty ) returns ( ContextIdList ) {} - rpc ListContexts (Empty ) returns ( ContextList ) {} - rpc GetContext (ContextId ) returns ( Context ) {} - rpc SetContext (Context ) returns ( ContextId ) {} - rpc RemoveContext (ContextId ) returns ( Empty ) {} - rpc GetContextEvents (Empty ) returns (stream ContextEvent ) {} - - rpc ListTopologyIds (ContextId ) returns ( TopologyIdList ) {} - rpc ListTopologies (ContextId ) returns ( TopologyList ) {} - rpc GetTopology (TopologyId ) returns ( Topology ) {} - rpc SetTopology (Topology ) returns ( TopologyId ) {} - rpc RemoveTopology (TopologyId ) returns ( Empty ) {} - rpc GetTopologyEvents (Empty ) returns (stream TopologyEvent ) {} - - rpc ListDeviceIds (Empty ) returns ( DeviceIdList ) {} - rpc ListDevices (Empty ) returns ( DeviceList ) {} - rpc GetDevice (DeviceId ) returns ( Device ) {} - rpc SetDevice (Device ) returns ( DeviceId ) {} - rpc RemoveDevice (DeviceId ) returns ( Empty ) {} - rpc GetDeviceEvents (Empty ) returns (stream DeviceEvent ) {} - - rpc ListLinkIds (Empty ) returns ( LinkIdList ) {} - rpc ListLinks (Empty ) returns ( LinkList ) {} - rpc GetLink (LinkId ) returns ( Link ) {} - rpc SetLink (Link ) returns ( LinkId ) {} - rpc RemoveLink (LinkId ) returns ( Empty ) {} - rpc GetLinkEvents (Empty ) returns (stream LinkEvent ) {} - - rpc ListServiceIds (ContextId ) returns ( ServiceIdList ) {} - rpc ListServices (ContextId ) returns ( ServiceList ) {} - rpc GetService (ServiceId ) returns ( Service ) {} - rpc SetService (Service ) returns ( ServiceId ) {} - rpc UnsetService (Service ) returns ( ServiceId ) {} - rpc RemoveService (ServiceId ) returns ( Empty ) {} - rpc GetServiceEvents (Empty ) returns (stream ServiceEvent ) {} - - rpc ListSliceIds (ContextId ) returns ( SliceIdList ) {} - rpc ListSlices (ContextId ) returns ( SliceList ) {} - rpc GetSlice (SliceId ) returns ( Slice ) {} - rpc SetSlice (Slice ) returns ( SliceId ) {} - rpc UnsetSlice (Slice ) returns ( SliceId ) {} - rpc RemoveSlice (SliceId ) returns ( Empty ) {} - rpc GetSliceEvents (Empty ) returns (stream SliceEvent ) {} - - rpc ListConnectionIds (ServiceId ) returns ( ConnectionIdList) {} - rpc ListConnections (ServiceId ) returns ( ConnectionList ) {} - rpc GetConnection (ConnectionId) returns ( Connection ) {} - rpc SetConnection (Connection ) returns ( ConnectionId ) {} - rpc RemoveConnection (ConnectionId) returns ( Empty ) {} - rpc GetConnectionEvents(Empty ) returns (stream ConnectionEvent ) {} + rpc ListContextIds (Empty ) returns ( ContextIdList ) {} + rpc ListContexts (Empty ) returns ( ContextList ) {} + rpc GetContext (ContextId ) returns ( Context ) {} + rpc SetContext (Context ) returns ( ContextId ) {} + rpc RemoveContext (ContextId ) returns ( Empty ) {} + rpc GetContextEvents (Empty ) returns (stream ContextEvent ) {} + + rpc ListTopologyIds (ContextId ) returns ( TopologyIdList ) {} + rpc ListTopologies (ContextId ) returns ( TopologyList ) {} + rpc GetTopology (TopologyId ) returns ( Topology ) {} + rpc GetTopologyDetails (TopologyId ) returns ( TopologyDetails ) {} + rpc SetTopology (Topology ) returns ( TopologyId ) {} + rpc RemoveTopology (TopologyId ) returns ( Empty ) {} + rpc GetTopologyEvents (Empty ) returns (stream TopologyEvent ) {} + + rpc ListDeviceIds (Empty ) returns ( DeviceIdList ) {} + rpc ListDevices (Empty ) returns ( DeviceList ) {} + rpc GetDevice (DeviceId ) returns ( Device ) {} + rpc SetDevice (Device ) returns ( DeviceId ) {} + rpc RemoveDevice (DeviceId ) returns ( Empty ) {} + rpc GetDeviceEvents (Empty ) returns (stream DeviceEvent ) {} + + rpc ListEndPointNames (EndPointIdList) returns ( EndPointNameList) {} + + rpc ListLinkIds (Empty ) returns ( LinkIdList ) {} + rpc ListLinks (Empty ) returns ( LinkList ) {} + rpc GetLink (LinkId ) returns ( Link ) {} + rpc SetLink (Link ) returns ( LinkId ) {} + rpc RemoveLink (LinkId ) returns ( Empty ) {} + rpc GetLinkEvents (Empty ) returns (stream LinkEvent ) {} + + rpc ListServiceIds (ContextId ) returns ( ServiceIdList ) {} + rpc ListServices (ContextId ) returns ( ServiceList ) {} + rpc GetService (ServiceId ) returns ( Service ) {} + rpc SetService (Service ) returns ( ServiceId ) {} + rpc UnsetService (Service ) returns ( ServiceId ) {} + rpc RemoveService (ServiceId ) returns ( Empty ) {} + rpc GetServiceEvents (Empty ) returns (stream ServiceEvent ) {} + + rpc ListSliceIds (ContextId ) returns ( SliceIdList ) {} + rpc ListSlices (ContextId ) returns ( SliceList ) {} + rpc GetSlice (SliceId ) returns ( Slice ) {} + rpc SetSlice (Slice ) returns ( SliceId ) {} + rpc UnsetSlice (Slice ) returns ( SliceId ) {} + rpc RemoveSlice (SliceId ) returns ( Empty ) {} + rpc GetSliceEvents (Empty ) returns (stream SliceEvent ) {} + + rpc ListConnectionIds (ServiceId ) returns ( ConnectionIdList) {} + rpc ListConnections (ServiceId ) returns ( ConnectionList ) {} + rpc GetConnection (ConnectionId ) returns ( Connection ) {} + rpc SetConnection (Connection ) returns ( ConnectionId ) {} + rpc RemoveConnection (ConnectionId ) returns ( Empty ) {} + rpc GetConnectionEvents(Empty ) returns (stream ConnectionEvent ) {} } // ----- Generic ------------------------------------------------------------------------------------------------------- @@ -135,6 +138,13 @@ message Topology { repeated LinkId link_ids = 4; } +message TopologyDetails { + TopologyId topology_id = 1; + string name = 2; + repeated Device devices = 3; + repeated Link links = 4; +} + message TopologyIdList { repeated TopologyId topology_ids = 1; } @@ -413,6 +423,21 @@ message EndPoint { Location endpoint_location = 5; } +message EndPointName { + EndPointId endpoint_id = 1; + string device_name = 2; + string endpoint_name = 3; + string endpoint_type = 4; +} + +message EndPointIdList { + repeated EndPointId endpoint_ids = 1; +} + +message EndPointNameList { + repeated EndPointName endpoint_names = 1; +} + // ----- Configuration ------------------------------------------------------------------------------------------------- enum ConfigActionEnum { -- GitLab From ac1f6f07be1ea032f90c1531f46f68174a2ab9fc Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Sun, 29 Jan 2023 20:44:28 +0000 Subject: [PATCH 2/5] Common - Tools - Context Query: - Added method to request device/endpoint names from a list of endpoint identifiers --- src/common/tools/context_queries/EndPoint.py | 46 ++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/common/tools/context_queries/EndPoint.py diff --git a/src/common/tools/context_queries/EndPoint.py b/src/common/tools/context_queries/EndPoint.py new file mode 100644 index 000000000..c5114d124 --- /dev/null +++ b/src/common/tools/context_queries/EndPoint.py @@ -0,0 +1,46 @@ +# 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 typing import Dict, List, Set, Tuple +from common.proto.context_pb2 import EndPointId, EndPointIdList +from context.client.ContextClient import ContextClient + +LOGGER = logging.getLogger(__name__) + +TYPE_DEVICE_NAMES = Dict[str, str] # device_uuid => device_name +TYPE_ENDPOINTS_DATA = Dict[str, Tuple[str, str]] # endpoint_uuid => (endpoint_name, endpoint_type) +TYPE_NAME_MAPS = Tuple[TYPE_DEVICE_NAMES, TYPE_ENDPOINTS_DATA] + +def get_endpoint_names(context_client : ContextClient, endpoint_ids : List[EndPointId]) -> TYPE_NAME_MAPS: + endpoint_uuids_to_names : Set[str] = set() + endpoint_id_list = EndPointIdList() + for endpoint_id in endpoint_ids: + endpoint_uuid = endpoint_id.endpoint_uuid.uuid + if endpoint_uuid in endpoint_uuids_to_names: continue + endpoint_id_list.endpoint_ids.add().CopyFrom(endpoint_id) # pylint: disable=no-member + endpoint_uuids_to_names.add(endpoint_uuid) + + endpoint_names = context_client.ListEndPointNames(endpoint_id_list) + + device_names : TYPE_DEVICE_NAMES = dict() + endpoints_data : TYPE_ENDPOINTS_DATA = dict() + for endpoint_name in endpoint_names.endpoint_names: + device_uuid = endpoint_name.endpoint_id.device_id.device_uuid.uuid + device_names[device_uuid] = endpoint_name.device_name + + endpoint_uuid = endpoint_name.endpoint_id.endpoint_uuid.uuid + endpoints_data[endpoint_uuid] = (endpoint_name.endpoint_name, endpoint_name.endpoint_type) + + return device_names, endpoints_data -- GitLab From 820bf254a7cb0d9d628c1891bbad241f2712305c Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Sun, 29 Jan 2023 20:45:32 +0000 Subject: [PATCH 3/5] Context component: - Implemented method to retrieve names of endpoints and devices - Implemented method to retrieve topology details --- src/context/client/ContextClient.py | 18 ++++++++-- .../service/ContextServiceServicerImpl.py | 16 +++++++-- src/context/service/database/EndPoint.py | 35 +++++++++++++++++++ src/context/service/database/Topology.py | 16 +++++++++ .../service/database/models/EndPointModel.py | 8 +++++ .../service/database/models/TopologyModel.py | 8 +++++ 6 files changed, 96 insertions(+), 5 deletions(-) create mode 100644 src/context/service/database/EndPoint.py diff --git a/src/context/client/ContextClient.py b/src/context/client/ContextClient.py index f91f36cf5..7559dde0f 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 82e28a7f1..41126b8d4 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 000000000..a26ed902c --- /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 fcd93e6bb..81170d0a1 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 07a5df2bf..65d867f3f 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 59659ecd3..cf730b168 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' -- GitLab From 045d29b5107992f1310442471413e64c23f384c6 Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Sun, 29 Jan 2023 20:47:13 +0000 Subject: [PATCH 4/5] WebUI component: - Updated link/service/slice list/detail pages to show device/endpoint names instead of UUIDs --- src/webui/service/link/routes.py | 27 +++++---- src/webui/service/service/routes.py | 37 ++++++++---- src/webui/service/slice/routes.py | 60 ++++++++++++------- src/webui/service/templates/link/detail.html | 12 ++-- src/webui/service/templates/link/home.html | 8 +-- .../service/templates/service/detail.html | 53 ++++++++++------ src/webui/service/templates/service/home.html | 12 +++- src/webui/service/templates/slice/detail.html | 37 ++++++++---- src/webui/service/templates/slice/home.html | 14 ++++- 9 files changed, 176 insertions(+), 84 deletions(-) diff --git a/src/webui/service/link/routes.py b/src/webui/service/link/routes.py index 0bfe2b902..0fc598d65 100644 --- a/src/webui/service/link/routes.py +++ b/src/webui/service/link/routes.py @@ -13,8 +13,9 @@ # limitations under the License. -from flask import current_app, render_template, Blueprint, flash, session, redirect, url_for -from common.proto.context_pb2 import Empty, Link, LinkEvent, LinkId, LinkIdList, LinkList, DeviceId, TopologyId +from flask import render_template, Blueprint, flash, session, redirect, url_for +from common.proto.context_pb2 import Empty, LinkId, LinkList, TopologyId +from common.tools.context_queries.EndPoint import get_endpoint_names from common.tools.object_factory.Context import json_context_id from common.tools.object_factory.Topology import json_topology_id from context.client.ContextClient import ContextClient @@ -37,22 +38,26 @@ def home(): grpc_topology = context_client.GetTopology(TopologyId(**json_topo_id)) topo_link_uuids = {link_id.link_uuid.uuid for link_id in grpc_topology.link_ids} grpc_links: LinkList = context_client.ListLinks(Empty()) - context_client.close() - links = [ - link for link in grpc_links.links - if link.link_id.link_uuid.uuid in topo_link_uuids - ] + endpoint_ids = [] + links = [] + for link_ in grpc_links.links: + if link_.link_id.link_uuid.uuid not in topo_link_uuids: continue + links.append(link_) + endpoint_ids.extend(link_.link_endpoint_ids) + + device_names, endpoints_data = get_endpoint_names(context_client, endpoint_ids) + context_client.close() - return render_template( - 'link/home.html', links=links) + return render_template('link/home.html', links=links, device_names=device_names, endpoints_data=endpoints_data) @link.route('detail/', methods=('GET', 'POST')) def detail(link_uuid: str): request = LinkId() - request.link_uuid.uuid = link_uuid + request.link_uuid.uuid = link_uuid # pylint: disable=no-member context_client.connect() response = context_client.GetLink(request) + device_names, endpoints_data = get_endpoint_names(context_client, response.link_endpoint_ids) context_client.close() - return render_template('link/detail.html',link=response) + return render_template('link/detail.html',link=response, device_names=device_names, endpoints_data=endpoints_data) diff --git a/src/webui/service/service/routes.py b/src/webui/service/service/routes.py index bc05daee3..c3b33df1e 100644 --- a/src/webui/service/service/routes.py +++ b/src/webui/service/service/routes.py @@ -14,7 +14,8 @@ import grpc from flask import current_app, redirect, render_template, Blueprint, flash, session, url_for -from common.proto.context_pb2 import ContextId, Service, ServiceId, ServiceList, ServiceTypeEnum, ServiceStatusEnum, Connection +from common.proto.context_pb2 import ContextId, Service, ServiceId, ServiceTypeEnum, ServiceStatusEnum, Connection +from common.tools.context_queries.EndPoint import get_endpoint_names from context.client.ContextClient import ContextClient from service.client.ServiceClient import ServiceClient @@ -39,18 +40,25 @@ def home(): service_list = context_client.ListServices(request) # print(service_list) services = service_list.services - context_not_found = False + context_found = True except grpc.RpcError as e: if e.code() != grpc.StatusCode.NOT_FOUND: raise if e.details() != 'Context({:s}) not found'.format(context_uuid): raise services = [] - context_not_found = True + context_found = False + + if context_found: + endpoint_ids = [] + for service_ in services: + endpoint_ids.extend(service_.service_endpoint_ids) + device_names, endpoints_data = get_endpoint_names(context_client, endpoint_ids) + else: + device_names, endpoints_data = [],[] context_client.close() - return render_template('service/home.html', services=services, - context_not_found=context_not_found, - ste=ServiceTypeEnum, - sse=ServiceStatusEnum) + return render_template( + 'service/home.html', services=services, device_names=device_names, endpoints_data=endpoints_data, + context_not_found=not context_found, ste=ServiceTypeEnum, sse=ServiceStatusEnum) @service.route('add', methods=['GET', 'POST']) @@ -74,13 +82,22 @@ def detail(service_uuid: str): context_client.connect() response: Service = context_client.GetService(request) connections: Connection = context_client.ListConnections(request) + connections = connections.connections + + endpoint_ids = [] + endpoint_ids.extend(response.service_endpoint_ids) + for connection in connections: + endpoint_ids.extend(connection.path_hops_endpoint_ids) + device_names, endpoints_data = get_endpoint_names(context_client, endpoint_ids) + context_client.close() except Exception as e: flash('The system encountered an error and cannot show the details of this service.', 'warning') current_app.logger.exception(e) return redirect(url_for('service.home')) - return render_template('service/detail.html', service=response, connections=connections,ste=ServiceTypeEnum, - sse=ServiceStatusEnum) + return render_template( + 'service/detail.html', service=response, connections=connections, device_names=device_names, + endpoints_data=endpoints_data, ste=ServiceTypeEnum, sse=ServiceStatusEnum) @service.get('/delete') @@ -102,4 +119,4 @@ def delete(service_uuid: str): except Exception as e: flash('Problem deleting service "{:s}": {:s}'.format(service_uuid, str(e.details())), 'danger') current_app.logger.exception(e) - return redirect(url_for('service.home')) \ No newline at end of file + return redirect(url_for('service.home')) diff --git a/src/webui/service/slice/routes.py b/src/webui/service/slice/routes.py index c52875013..a3dfc99ea 100644 --- a/src/webui/service/slice/routes.py +++ b/src/webui/service/slice/routes.py @@ -14,22 +14,18 @@ # import grpc from flask import current_app, redirect, render_template, Blueprint, flash, session, url_for -from common.proto.context_pb2 import ContextId, Slice, SliceId, SliceList, Connection, SliceStatusEnum +from common.proto.context_pb2 import ContextId, Slice, SliceId, SliceStatusEnum +from common.tools.context_queries.EndPoint import get_endpoint_names from context.client.ContextClient import ContextClient -#from slice.client.SliceClient import SliceClient - - +from slice.client.SliceClient import SliceClient slice = Blueprint('slice', __name__, url_prefix='/slice') context_client = ContextClient() -#slice_client = SliceClient() +slice_client = SliceClient() @slice.get('/') def home(): - # flash('This is an info message', 'info') - # flash('This is a danger message', 'danger') - context_uuid = session.get('context_uuid', '-') if context_uuid == "-": flash("Please select a context!", "warning") @@ -39,25 +35,36 @@ def home(): context_client.connect() try: slice_list = context_client.ListSlices(request) - # print(slice_list) slices = slice_list.slices - context_not_found = False + context_found = True except grpc.RpcError as e: if e.code() != grpc.StatusCode.NOT_FOUND: raise if e.details() != 'Context({:s}) not found'.format(context_uuid): raise slices = [] - context_not_found = True + context_found = False + + if context_found: + endpoint_ids = [] + for slice_ in slices: + endpoint_ids.extend(slice_.slice_endpoint_ids) + device_names, endpoints_data = get_endpoint_names(context_client, endpoint_ids) + else: + device_names, endpoints_data = [],[] + context_client.close() - return render_template('slice/home.html',slices=slices, context_not_found=context_not_found, sse=SliceStatusEnum) -# -#@slice.route('add', methods=['GET', 'POST']) -#def add(): -# flash('Add slice route called', 'danger') -# raise NotImplementedError() -# return render_template('slice/home.html') -# -# + return render_template( + 'slice/home.html', slices=slices, device_names=device_names, endpoints_data=endpoints_data, + context_not_found=not context_found, sse=SliceStatusEnum) + + +@slice.route('add', methods=['GET', 'POST']) +def add(): + flash('Add slice route called', 'danger') + raise NotImplementedError() + return render_template('slice/home.html') + + @slice.get('/detail') def detail(slice_uuid: str): context_uuid = session.get('context_uuid', '-') @@ -74,13 +81,20 @@ def detail(slice_uuid: str): context_client.connect() response: Slice = context_client.GetSlice(request) services = context_client.ListServices(req) + + endpoint_ids = [] + endpoint_ids.extend(response.slice_endpoint_ids) + device_names, endpoints_data = get_endpoint_names(context_client, endpoint_ids) + context_client.close() except Exception as e: flash('The system encountered an error and cannot show the details of this slice.', 'warning') current_app.logger.exception(e) return redirect(url_for('slice.home')) - return render_template('slice/detail.html', slice=response, sse=SliceStatusEnum, services=services) -# + return render_template( + 'slice/detail.html', slice=response, device_names=device_names, endpoints_data=endpoints_data, + sse=SliceStatusEnum, services=services) + #@slice.get('/delete') #def delete(slice_uuid: str): # context_uuid = session.get('context_uuid', '-') @@ -100,4 +114,4 @@ def detail(slice_uuid: str): # except Exception as e: # flash('Problem deleting slice "{:s}": {:s}'.format(slice_uuid, str(e.details())), 'danger') # current_app.logger.exception(e) -# return redirect(url_for('slice.home')) \ No newline at end of file +# return redirect(url_for('slice.home')) diff --git a/src/webui/service/templates/link/detail.html b/src/webui/service/templates/link/detail.html index 16ec5470c..d247527de 100644 --- a/src/webui/service/templates/link/detail.html +++ b/src/webui/service/templates/link/detail.html @@ -38,23 +38,27 @@ Endpoint UUID Device + Endpoint Type - {% for end_point in link.link_endpoint_ids %} + {% for endpoint in link.link_endpoint_ids %} - {{ end_point.endpoint_uuid.uuid }} + {{ endpoints_data.get(endpoint.endpoint_uuid.uuid, (endpoint.endpoint_uuid.uuid, ''))[0] }} - - {{ end_point.device_id.device_uuid.uuid }} + + {{ device_names.get(endpoint.device_id.device_uuid.uuid, endpoint.device_id.device_uuid.uuid) }} + + {{ endpoints_data.get(endpoint.endpoint_uuid.uuid, ('', '-'))[1] }} + {% endfor %} diff --git a/src/webui/service/templates/link/home.html b/src/webui/service/templates/link/home.html index 16fe36e1f..6a14e60dd 100644 --- a/src/webui/service/templates/link/home.html +++ b/src/webui/service/templates/link/home.html @@ -61,12 +61,12 @@ - {% for i in range(connection.path_hops_endpoint_ids|length) %} + {% for endpoint_id in connection.path_hops_endpoint_ids %} - {{ connection.path_hops_endpoint_ids[i].device_id.device_uuid.uuid }} / {{ - connection.path_hops_endpoint_ids[i].endpoint_uuid.uuid }} + + {{ device_names.get(endpoint_id.device_id.device_uuid.uuid, endpoint_id.device_id.device_uuid.uuid) }} + + + + + + / {{ endpoints_data.get(endpoint_id.endpoint_uuid.uuid, (endpoint_id.endpoint_uuid.uuid, ''))[0] }} {% endfor %} diff --git a/src/webui/service/templates/service/home.html b/src/webui/service/templates/service/home.html index 280685fc5..785012422 100644 --- a/src/webui/service/templates/service/home.html +++ b/src/webui/service/templates/service/home.html @@ -69,7 +69,17 @@ diff --git a/src/webui/service/templates/slice/detail.html b/src/webui/service/templates/slice/detail.html index 4f26c75a5..733c3d509 100644 --- a/src/webui/service/templates/slice/detail.html +++ b/src/webui/service/templates/slice/detail.html @@ -56,26 +56,27 @@ Endpoint UUID Device + Endpoint Type {% for endpoint in slice.slice_endpoint_ids %} - {{ endpoint.endpoint_uuid.uuid }} + {{ endpoints_data.get(endpoint.endpoint_uuid.uuid, (endpoint.endpoint_uuid.uuid, ''))[0] }} - {{ endpoint.device_id.device_uuid.uuid }} - - - + {{ device_names.get(endpoint.device_id.device_uuid.uuid, endpoint.device_id.device_uuid.uuid) }} + + + + + {{ endpoints_data.get(endpoint.endpoint_uuid.uuid, ('', '-'))[1] }} + {% endfor %} @@ -103,8 +104,14 @@ Endpoint Location - {{ constraint.endpoint_location.endpoint_id.device_id.device_uuid.uuid }} / {{ - constraint.endpoint_location.endpoint_id.endpoint_uuid.uuid }} + + {{ device_names.get(constraint.endpoint_location.endpoint_id.device_id.device_uuid.uuid, constraint.endpoint_location.endpoint_id.device_id.device_uuid.uuid) }} + + + + + + / {{ endpoints_data.get(constraint.endpoint_location.endpoint_id.endpoint_uuid.uuid, (constraint.endpoint_location.endpoint_id.endpoint_uuid.uuid, ''))[0] }} {% if constraint.endpoint_location.location.WhichOneof('location')=='region' %} @@ -120,8 +127,14 @@ Endpoint Priority - {{ constraint.endpoint_priority.endpoint_id.device_id.device_uuid.uuid }} / {{ - constraint.endpoint_priority.endpoint_id.endpoint_uuid.uuid }} + + {{ device_names.get(constraint.endpoint_priority.endpoint_id.device_id.device_uuid.uuid, constraint.endpoint_priority.endpoint_id.device_id.device_uuid.uuid) }} + + + + + + / {{ endpoints_data.get(constraint.endpoint_priority.endpoint_id.endpoint_uuid.uuid, (constraint.endpoint_priority.endpoint_id.endpoint_uuid.uuid, ''))[0] }} {{ constraint.endpoint_priority.priority }} diff --git a/src/webui/service/templates/slice/home.html b/src/webui/service/templates/slice/home.html index 141234aca..59ad1750b 100644 --- a/src/webui/service/templates/slice/home.html +++ b/src/webui/service/templates/slice/home.html @@ -46,8 +46,18 @@ {{ slice.name }} -- GitLab From 372bf3a4d65c5de816ec82eab4d181c0c4aa87ad Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Sun, 29 Jan 2023 20:53:01 +0000 Subject: [PATCH 5/5] WebUI component: - Minor cosmetic changes --- src/webui/service/templates/service/detail.html | 9 +++------ src/webui/service/templates/slice/detail.html | 6 ++---- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/webui/service/templates/service/detail.html b/src/webui/service/templates/service/detail.html index cb13009e7..f453b2f2d 100644 --- a/src/webui/service/templates/service/detail.html +++ b/src/webui/service/templates/service/detail.html @@ -109,8 +109,7 @@ - - / {{ endpoints_data.get(constraint.endpoint_location.endpoint_id.endpoint_uuid.uuid, (constraint.endpoint_location.endpoint_id.endpoint_uuid.uuid, ''))[0] }} + / {{ endpoints_data.get(constraint.endpoint_location.endpoint_id.endpoint_uuid.uuid, (constraint.endpoint_location.endpoint_id.endpoint_uuid.uuid, ''))[0] }} {% if constraint.endpoint_location.location.WhichOneof('location')=='region' %} @@ -132,8 +131,7 @@ - - / {{ endpoints_data.get(constraint.endpoint_priority.endpoint_id.endpoint_uuid.uuid, (constraint.endpoint_priority.endpoint_id.endpoint_uuid.uuid, ''))[0] }} + / {{ endpoints_data.get(constraint.endpoint_priority.endpoint_id.endpoint_uuid.uuid, (constraint.endpoint_priority.endpoint_id.endpoint_uuid.uuid, ''))[0] }} {{ constraint.endpoint_priority.priority }} @@ -252,8 +250,7 @@ - - / {{ endpoints_data.get(endpoint_id.endpoint_uuid.uuid, (endpoint_id.endpoint_uuid.uuid, ''))[0] }} + / {{ endpoints_data.get(endpoint_id.endpoint_uuid.uuid, (endpoint_id.endpoint_uuid.uuid, ''))[0] }} {% endfor %} diff --git a/src/webui/service/templates/slice/detail.html b/src/webui/service/templates/slice/detail.html index 733c3d509..92be94849 100644 --- a/src/webui/service/templates/slice/detail.html +++ b/src/webui/service/templates/slice/detail.html @@ -110,8 +110,7 @@ - - / {{ endpoints_data.get(constraint.endpoint_location.endpoint_id.endpoint_uuid.uuid, (constraint.endpoint_location.endpoint_id.endpoint_uuid.uuid, ''))[0] }} + / {{ endpoints_data.get(constraint.endpoint_location.endpoint_id.endpoint_uuid.uuid, (constraint.endpoint_location.endpoint_id.endpoint_uuid.uuid, ''))[0] }} {% if constraint.endpoint_location.location.WhichOneof('location')=='region' %} @@ -133,8 +132,7 @@ - - / {{ endpoints_data.get(constraint.endpoint_priority.endpoint_id.endpoint_uuid.uuid, (constraint.endpoint_priority.endpoint_id.endpoint_uuid.uuid, ''))[0] }} + / {{ endpoints_data.get(constraint.endpoint_priority.endpoint_id.endpoint_uuid.uuid, (constraint.endpoint_priority.endpoint_id.endpoint_uuid.uuid, ''))[0] }} {{ constraint.endpoint_priority.priority }} -- GitLab