From 8f89488fd52752de0414d1e8098bd249dfc5778a Mon Sep 17 00:00:00 2001 From: Blake Harnden <32446120+bharnden@users.noreply.github.com> Date: Tue, 11 Jan 2022 16:29:55 -0800 Subject: [PATCH] grpc: added config service actions and update the gui to leverage them as the default for node context menus of running nodes --- daemon/core/api/grpc/client.py | 24 +++++++++++++++ daemon/core/api/grpc/server.py | 43 +++++++++++++++++++++++++++ daemon/core/gui/graph/node.py | 7 ++--- daemon/proto/core/api/grpc/core.proto | 2 ++ daemon/tests/test_grpc.py | 16 ++++++++++ 5 files changed, 88 insertions(+), 4 deletions(-) diff --git a/daemon/core/api/grpc/client.py b/daemon/core/api/grpc/client.py index 783e80c0..e2e1e729 100644 --- a/daemon/core/api/grpc/client.py +++ b/daemon/core/api/grpc/client.py @@ -810,6 +810,30 @@ class CoreGrpcClient: response = self.stub.ServiceAction(request) return response.result + def config_service_action( + self, + session_id: int, + node_id: int, + service: str, + action: wrappers.ServiceAction, + ) -> bool: + """ + Send an action to a config service for a node. + + :param session_id: session id + :param node_id: node id + :param service: config service name + :param action: action for service (start, stop, restart, + validate) + :return: True for success, False otherwise + :raises grpc.RpcError: when session or node doesn't exist + """ + request = ServiceActionRequest( + session_id=session_id, node_id=node_id, service=service, action=action.value + ) + response = self.stub.ConfigServiceAction(request) + return response.result + def get_wlan_config( self, session_id: int, node_id: int ) -> Dict[str, wrappers.ConfigOption]: diff --git a/daemon/core/api/grpc/server.py b/daemon/core/api/grpc/server.py index a792c6ea..ba20d4ed 100644 --- a/daemon/core/api/grpc/server.py +++ b/daemon/core/api/grpc/server.py @@ -72,6 +72,7 @@ from core.api.grpc.wlan_pb2 import ( WlanLinkRequest, WlanLinkResponse, ) +from core.configservice.base import ConfigServiceBootError from core.emane.modelmanager import EmaneModelManager from core.emulator.coreemu import CoreEmu from core.emulator.data import InterfaceData, LinkData, LinkOptions @@ -986,6 +987,48 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer): return ServiceActionResponse(result=result) + def ConfigServiceAction( + self, request: ServiceActionRequest, context: ServicerContext + ) -> ServiceActionResponse: + """ + Take action whether to start, stop, restart, validate the config service or + none of the above. + + :param request: service action request + :param context: context object + :return: service action response about status of action + """ + logger.debug("service action: %s", request) + session = self.get_session(request.session_id, context) + node = self.get_node(session, request.node_id, context, CoreNode) + service = node.config_services.get(request.service) + if not service: + context.abort(grpc.StatusCode.NOT_FOUND, "config service not found") + result = False + if request.action == ServiceAction.START: + try: + service.start() + result = True + except ConfigServiceBootError: + pass + elif request.action == ServiceAction.STOP: + service.stop() + result = True + elif request.action == ServiceAction.RESTART: + service.stop() + try: + service.start() + result = True + except ConfigServiceBootError: + pass + elif request.action == ServiceAction.VALIDATE: + try: + service.run_validation() + result = True + except ConfigServiceBootError: + pass + return ServiceActionResponse(result=result) + def GetWlanConfig( self, request: GetWlanConfigRequest, context: ServicerContext ) -> GetWlanConfigResponse: diff --git a/daemon/core/gui/graph/node.py b/daemon/core/gui/graph/node.py index b0a78268..1de7319f 100644 --- a/daemon/core/gui/graph/node.py +++ b/daemon/core/gui/graph/node.py @@ -7,8 +7,7 @@ from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple import grpc from PIL.ImageTk import PhotoImage -from core.api.grpc.services_pb2 import ServiceAction -from core.api.grpc.wrappers import Interface, Node, NodeType +from core.api.grpc.wrappers import Interface, Node, NodeType, ServiceAction from core.gui import images from core.gui import nodeutils as nutils from core.gui import themes @@ -238,7 +237,7 @@ class CanvasNode: ) if nutils.is_container(self.core_node): services_menu = tk.Menu(self.context) - for service in sorted(self.core_node.services): + for service in sorted(self.core_node.config_services): service_menu = tk.Menu(services_menu) themes.style_menu(service_menu) start_func = functools.partial(self.start_service, service) @@ -463,7 +462,7 @@ class CanvasNode: def _service_action(self, service: str, action: ServiceAction) -> None: session_id = self.app.core.session.id try: - result = self.app.core.client.service_action( + result = self.app.core.client.config_service_action( session_id, self.core_node.id, service, action ) if not result: diff --git a/daemon/proto/core/api/grpc/core.proto b/daemon/proto/core/api/grpc/core.proto index 1986dcef..f0cb242d 100644 --- a/daemon/proto/core/api/grpc/core.proto +++ b/daemon/proto/core/api/grpc/core.proto @@ -87,6 +87,8 @@ service CoreApi { } rpc GetNodeConfigService (configservices.GetNodeConfigServiceRequest) returns (configservices.GetNodeConfigServiceResponse) { } + rpc ConfigServiceAction (services.ServiceActionRequest) returns (services.ServiceActionResponse) { + } // wlan rpc rpc GetWlanConfig (wlan.GetWlanConfigRequest) returns (wlan.GetWlanConfigResponse) { diff --git a/daemon/tests/test_grpc.py b/daemon/tests/test_grpc.py index 575a502d..e56322ad 100644 --- a/daemon/tests/test_grpc.py +++ b/daemon/tests/test_grpc.py @@ -707,6 +707,22 @@ class TestGrpc: # then assert result is True + def test_config_service_action(self, grpc_server: CoreGrpcServer): + # given + client = CoreGrpcClient() + session = grpc_server.coreemu.create_session() + node = session.add_node(CoreNode) + service_name = "DefaultRoute" + + # then + with client.context_connect(): + result = client.config_service_action( + session.id, node.id, service_name, ServiceAction.STOP + ) + + # then + assert result is True + def test_node_events(self, grpc_server: CoreGrpcServer): # given client = CoreGrpcClient()