From 27d1cd460bded289be1b5e064e1c2ad57ef3994d Mon Sep 17 00:00:00 2001 From: Marek Wolan Date: Mon, 29 Apr 2024 11:13:32 +0100 Subject: [PATCH] #2514 Provide more friendly messages on validation failure --- src/primaite/simulator/core.py | 19 ++++++++++++++++++- src/primaite/simulator/domain/controller.py | 5 +++++ .../simulator/network/hardware/base.py | 5 +++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/primaite/simulator/core.py b/src/primaite/simulator/core.py index 8e954229..835f24fe 100644 --- a/src/primaite/simulator/core.py +++ b/src/primaite/simulator/core.py @@ -1,5 +1,6 @@ # flake8: noqa """Core of the PrimAITE Simulator.""" +import warnings from abc import abstractmethod from typing import Callable, Dict, List, Literal, Optional, Union from uuid import uuid4 @@ -26,6 +27,12 @@ class RequestPermissionValidator(BaseModel): """Use the request and context parameters to decide whether the request should be permitted.""" pass + @property + @abstractmethod + def fail_message(self) -> str: + """Message that is reported when a request is rejected by this validator.""" + return "request rejected" + class AllowAllValidator(RequestPermissionValidator): """Always allows the request.""" @@ -34,6 +41,16 @@ class AllowAllValidator(RequestPermissionValidator): """Always allow the request.""" return True + @property + def fail_message(self) -> str: + """ + Message that is reported when a request is rejected by this validator. + + This method should really never be called because this validator never rejects requests. + """ + warnings.warn("Something went wrong - AllowAllValidator rejected a request.") + return super().fail_message + class RequestType(BaseModel): """ @@ -99,7 +116,7 @@ class RequestManager(BaseModel): if not request_type.validator(request_options, context): _LOGGER.debug(f"Request {request} was denied due to insufficient permissions") - return RequestResponse(status="failure", data={"reason": "request validation failed"}) + return RequestResponse(status="failure", data={"reason": request_type.validator.fail_message}) return request_type.func(request_options, context) diff --git a/src/primaite/simulator/domain/controller.py b/src/primaite/simulator/domain/controller.py index 432a1d9a..82312dd3 100644 --- a/src/primaite/simulator/domain/controller.py +++ b/src/primaite/simulator/domain/controller.py @@ -57,6 +57,11 @@ class GroupMembershipValidator(RequestPermissionValidator): return True return False + @property + def fail_message(self) -> str: + """Message that is reported when a request is rejected by this validator.""" + return "User does not belong to group" + class DomainController(SimComponent): """Main object for controlling the domain.""" diff --git a/src/primaite/simulator/network/hardware/base.py b/src/primaite/simulator/network/hardware/base.py index 9083c644..78a0bf2d 100644 --- a/src/primaite/simulator/network/hardware/base.py +++ b/src/primaite/simulator/network/hardware/base.py @@ -798,6 +798,11 @@ class Node(SimComponent): """Return whether the node is on or off.""" return self.node.operating_state == NodeOperatingState.ON + @property + def fail_message(self) -> str: + """Message that is reported when a request is rejected by this validator.""" + return f"Cannot perform request on node '{self.node.hostname}' because it is not turned on." + def _init_request_manager(self) -> RequestManager: """ Initialise the request manager.