panic icon indicating copy to clipboard operation
panic copied to clipboard

Investigation: The creation of a configuration data model

Open dillu24 opened this issue 3 years ago • 1 comments

Rationale

As a developer it would facilitate my life if there are data models in the code-base which represent a particular configuration. So far in our code-base we have treated a configuration as a dictionary, therefore there was no standard way of interacting with the configuration. Having a data model would provide a standard way of interacting with a particular object, for example for validating the structure of a dictionary, parsing, and representing a configuration as a dictionary.

For example, if a CosmosNodeConfig object existed, the MonitorsManager could validate the Cosmos node configuration received from the ConfigsManager using the CosmosNodeConfig.validate() function, load the configuration inside the model using the CosmosNodeConfig.load_json function and retrieve the json representation of the data model using the CosmosNodeConfig.retrieve_json function. As a result, the developer would have a standard way of interacting with a particular configuration.

In the alerter service we already have something similar inside the src/configs folder. However, the folder structuring is not ideal. We should create a data_models/configs folder containing all the configurations' data model. NOTE: It is suggested that these data models are aligned with the configuration changes conducted in UI iteration 2.

For ticket closure

The aim of this task is to come up with a data model design for each configuration we are dealing with in the alerter. This design should ideally be submitted on confluence.

Having this design, we can then create a number of implementation tickets such as:

  • Tickets which implement the respective models
  • Tickets which enables the components to make use of the models

You could use this minimum working example to try and understand what type of data models we want to have. Note that the code below should be used only for example purposes, hence, the developer should think of the best way to implement this:

class Config(ABC):
    def __init__(self):
        self._parent_id = ''

    @property
    def parent_id(self) -> str:
        return self._parent_id

    @abstractmethod
    def _is_valid(config: Dict) -> bool:
        pass

   def _parse(config: Dict) -> None:
       self._parent_id = config['parent_id']

    def load(config: Dict) -> bool:
        if self._is_valid(config):
            self._parse(config)

    @abstractmethod
    def to_json() -> Dict:
        pass

class NodeConfig(ABC, Config):
    def __init__(self):
        super.__init__()
        self._node_id = node_id

    @property
    def node_id(self) -> str:
        return self._node_id

    @abstractmethod
    def _is_valid(config: Dict) -> bool:
        pass

   def _parse(config: Dict) -> None:
       super()._parse(config)
       self._node_id = config['node_id']

    @abstractmethod
    def to_json() -> Dict:
        pass

class CosmosNodeConfig(NodeConfig):
    def __init__(self):
        super.__init__()
        self._cosmos_rest_url = ''

    @property
    def cosmos_rest_url(self) -> str:
        return self._cosmos_rest_url

    def _is_valid(config: Dict) -> bool:
        return schema.is_valid(config)

   def _parse(config: Dict) -> None:
       super()._parse(config)
       self._cosmos_rest_url = config['cosmos_rest_url']

    def to_json() -> Dict:
        return {
            'parent_id': self.parent_id,
            'cosmos_rest_url': self.cosmos_rest_url,
            'node_id': self.node_id,
        }

Schema library we could use: https://pypi.org/project/schema/

dillu24 avatar May 31 '22 09:05 dillu24

@zimaah Also suggested whether we could use custom made types rather than the generic Dict type. After some investigation I have found this resource which makes use of a TypedDict : https://adamj.eu/tech/2021/05/10/python-type-hints-how-to-use-typeddict/

Therefore, apart from creating the Object Data Models/Interfaces, before-hand we need to also create the types which the Object Data Models interact with. These types can reside in the src/types folder. In the examples above we could have the following:

class ConfigDict(TypedDict):
    parent_id: str

def _parse(config: ConfigDict) -> None:
       super()._parse(config)
       self._node_id = config['node_id']

dillu24 avatar May 31 '22 10:05 dillu24