diff --git a/.gitignore b/.gitignore index 12e9577d..bcfbadeb 100644 --- a/.gitignore +++ b/.gitignore @@ -18,8 +18,8 @@ debian stamp-h1 # generated protobuf files -daemon/core/api/grpc/core_pb2.py -daemon/core/api/grpc/core_pb2_grpc.py +*_pb2.py +*_pb2_grpc.py # python build directory dist diff --git a/Pipfile b/Pipfile deleted file mode 100644 index e69de29b..00000000 diff --git a/daemon/core/api/grpc/client.py b/daemon/core/api/grpc/client.py index 07e9d8ef..cedf812a 100644 --- a/daemon/core/api/grpc/client.py +++ b/daemon/core/api/grpc/client.py @@ -12,6 +12,14 @@ import netaddr from core import utils from core.api.grpc import core_pb2, core_pb2_grpc +from core.api.grpc.configservices_pb2 import ( + GetConfigServiceRequest, + GetConfigServiceResponse, + GetConfigServicesRequest, + GetConfigServicesResponse, + SetConfigServiceRequest, + SetConfigServiceResponse, +) class InterfaceHelper: @@ -1078,6 +1086,26 @@ class CoreGrpcClient: request = core_pb2.GetInterfacesRequest() return self.stub.GetInterfaces(request) + def get_config_services(self) -> GetConfigServicesResponse: + request = GetConfigServicesRequest() + return self.stub.GetConfigServices(request) + + def get_config_service( + self, session_id: int, node_id: int, name: str + ) -> GetConfigServiceResponse: + request = GetConfigServiceRequest( + session_id=session_id, node_id=node_id, name=name + ) + return self.stub.GetConfigService(request) + + def set_config_service( + self, session_id: int, node_id: int, name: str, config: Dict[str, str] + ) -> SetConfigServiceResponse: + request = SetConfigServiceRequest( + session_id=session_id, node_id=node_id, name=name, config=config + ) + return self.stub.SetConfigService(request) + def connect(self) -> None: """ Open connection to server, must be closed manually. diff --git a/daemon/core/api/grpc/server.py b/daemon/core/api/grpc/server.py index 3d24b981..61fcbade 100644 --- a/daemon/core/api/grpc/server.py +++ b/daemon/core/api/grpc/server.py @@ -10,6 +10,15 @@ import grpc from grpc import ServicerContext from core.api.grpc import core_pb2, core_pb2_grpc, grpcutils +from core.api.grpc.configservices_pb2 import ( + ConfigService, + GetConfigServiceRequest, + GetConfigServiceResponse, + GetConfigServicesRequest, + GetConfigServicesResponse, + SetConfigServiceRequest, + SetConfigServiceResponse, +) from core.api.grpc.events import EventStreamer from core.api.grpc.grpcutils import ( get_config_options, @@ -101,6 +110,10 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer): except CoreError: context.abort(grpc.StatusCode.NOT_FOUND, f"node {node_id} not found") + def validate_service(self, name: str, context: ServicerContext) -> None: + if name not in self.coreemu.service_manager.services: + context.abort(grpc.StatusCode.NOT_FOUND, f"unknown service {name}") + def StartSession( self, request: core_pb2.StartSessionRequest, context: ServicerContext ) -> core_pb2.StartSessionResponse: @@ -1429,3 +1442,55 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer): return core_pb2.EmaneLinkResponse(result=True) else: return core_pb2.EmaneLinkResponse(result=False) + + def GetConfigServices( + self, request: GetConfigServicesRequest, context: ServicerContext + ) -> GetConfigServicesResponse: + services = [] + for service in self.coreemu.service_manager.services.values(): + service_proto = ConfigService( + name=service.name, + group=service.group, + executables=service.executables, + dependencies=service.dependencies, + directories=service.directories, + startup=service.startup, + validate=service.validate, + shutdown=service.shutdown, + validation_mode=service.validation_mode.value, + validation_timer=service.validation_timer, + validation_period=service.validation_period, + ) + services.append(service_proto) + return GetConfigServicesResponse(services=services) + + def GetConfigService( + self, request: GetConfigServiceRequest, context: ServicerContext + ) -> GetConfigServiceResponse: + session = self.get_session(request.session_id, context) + node = self.get_node(session, request.node_id, context) + self.validate_service(request.name, context) + service = node.config_services.get(request.name) + if service: + config = service.get_config() + + else: + service = self.coreemu.service_manager.get_service(request.name) + config = {x.id: x.default for x in service.default_configs} + return GetConfigServiceResponse(config=config) + + def SetConfigService( + self, request: SetConfigServiceRequest, context: ServicerContext + ) -> SetConfigServiceResponse: + session = self.get_session(request.session_id, context) + node = self.get_node(session, request.node_id, context) + self.validate_service(request.name, context) + service = node.config_services.get(request.name) + if service: + service.set_config(request.config) + return SetConfigServiceResponse(result=True) + else: + context.abort( + grpc.StatusCode.NOT_FOUND, + f"node {node.name} missing service {request.name}", + ) diff --git a/daemon/proto/Makefile.am b/daemon/proto/Makefile.am index 05f2d394..e63179ca 100644 --- a/daemon/proto/Makefile.am +++ b/daemon/proto/Makefile.am @@ -1,5 +1,5 @@ all: - $(PYTHON) -m grpc_tools.protoc -I . --python_out=.. --grpc_python_out=.. core/api/grpc/core.proto + $(PYTHON) -m grpc_tools.protoc -I . --python_out=.. --grpc_python_out=.. core/api/grpc/*.proto clean: - -rm -f ../core/api/grpc/core_pb2* + -rm -f ../core/api/grpc/*_pb2* diff --git a/daemon/proto/core/api/grpc/configservices.proto b/daemon/proto/core/api/grpc/configservices.proto new file mode 100644 index 00000000..926e30f7 --- /dev/null +++ b/daemon/proto/core/api/grpc/configservices.proto @@ -0,0 +1,54 @@ +syntax = "proto3"; + +package configservices; + +message ConfigServiceValidationMode { + enum Enum { + BLOCKING = 0; + NON_BLOCKING = 1; + TIMER = 2; + } +} + +message ConfigService { + string group = 1; + string name = 2; + repeated string executables = 3; + repeated string dependencies = 4; + repeated string directories = 5; + repeated string startup = 6; + repeated string validate = 7; + repeated string shutdown = 8; + ConfigServiceValidationMode.Enum validation_mode = 9; + int32 validation_timer = 10; + float validation_period = 11; +} + +message GetConfigServicesRequest { + int32 session_id = 1; +} + +message GetConfigServicesResponse { + repeated ConfigService services = 1; +} + +message GetConfigServiceRequest { + int32 session_id = 1; + int32 node_id = 2; + string name = 3; +} + +message GetConfigServiceResponse { + map config = 1; +} + +message SetConfigServiceRequest { + int32 session_id = 1; + int32 node_id = 2; + string name = 3; + map config = 4; +} + +message SetConfigServiceResponse { + bool result = 1; +} diff --git a/daemon/proto/core/api/grpc/core.proto b/daemon/proto/core/api/grpc/core.proto index 856ed7aa..5930639e 100644 --- a/daemon/proto/core/api/grpc/core.proto +++ b/daemon/proto/core/api/grpc/core.proto @@ -5,6 +5,8 @@ package core; option java_package = "com.core.client.grpc"; option java_outer_classname = "CoreProto"; +import "core/api/grpc/configservices.proto"; + service CoreApi { // session rpc rpc StartSession (StartSessionRequest) returns (StartSessionResponse) { @@ -102,6 +104,14 @@ service CoreApi { rpc ServiceAction (ServiceActionRequest) returns (ServiceActionResponse) { } + // config services + rpc GetConfigServices (configservices.GetConfigServicesRequest) returns (configservices.GetConfigServicesResponse) { + } + rpc GetConfigService (configservices.GetConfigServiceRequest) returns (configservices.GetConfigServiceResponse) { + } + rpc SetConfigService (configservices.SetConfigServiceRequest) returns (configservices.SetConfigServiceResponse) { + } + // wlan rpc rpc GetWlanConfigs (GetWlanConfigsRequest) returns (GetWlanConfigsResponse) { }