Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor client-side handlers #19

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 56 additions & 71 deletions docs/developer_docs/ADDING_NEW_PRESETS.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
# Adding New Preset To An Existing Preset Group
# Adding A New Preset

## **1. Add the preset name to the corresponding enum class in `openstackquery/enums/query_presets.py`**
## **1. Add the preset name to the QueryPresets enum class in `openstackquery/enums/query_presets.py`**

e.g.
```python
class QueryPresetsGeneric(QueryPresets):
class QueryPresets(EnumWithAliases):
"""
Enum class which holds generic query comparison operators
"""

EQUAL_TO = auto()
...
NEW_PRESET = auto() # <- we add this line to repesent a new preset enum belonging to the 'Generic' group
NEW_PRESET = auto() # <- we add this line to represent a new preset enum belonging to the 'Generic' group
```

(Optional) Add alias mappings for the preset - see [Adding Aliases](ADDING_ALIASES.md)

## **2. Edit the corresponding handler class in `openstackquery/handlers/client_side_handler_<preset-group>.py`.**
## **2. Create a function to act as the client-side filter function for your new query preset

Here you must:
- add a 'client-side' filter function as a method
- add the mapping between the enum and filter function in self._filter_functions.
Client-side filter functions are located in `openstackquery/handlers/client_side_filters.py`

The filter function must:
- **take as input at least one parameter - `prop`**:
Expand All @@ -30,32 +28,41 @@ The filter function must:
- `True` if the prop passes filter
- `False` if not

e.g. editing `client_side_handler_generic.py`
```python
class ClientSideHandlerGeneric(ClientSideHandler):
...
def prop_new_preset_filter_func(self, prop: Any, arg1, arg2):
"""
A new preset filter - takes a property value, performs some logic and returns a boolean if
property passes a filter or not
:param prop: property value to check
:param arg1: some arg the filter uses
:param arg2: some other arg the filter uses
:returns: True or False
"""
# Define your filter logic here
```

def __init__(self, filter_function_mappings: PresetPropMappings):
super().__init__(filter_function_mappings)
## **3. Edit the corresponding handler class in `openstackquery/handlers/client_side_handler.py`.**

self._filter_functions = {
QueryPresetsGeneric.EQUAL_TO: self._prop_equal_to,
...
QueryPresetsGeneric.NEW_PRESET: self._new_preset_filter_func # <- 2) add the enum-to-function mapping
}
Here you must:
- add a 'client-side' filter function as a method
- add the mapping between the enum and filter function in self._filter_functions.

e.g. editing `client_side_handler_generic.py`
```python
from openstackquery.handlers.client_side_filters import (
prop_new_preset_filter_func # newly made filter func
)

class ClientSideHandler(HandlerBase):
...

def _new_preset_filter_func(self, prop: Any, arg1, arg2):
"""
A new preset filter - takes a property value, performs some logic and returns a boolean if
property passes a filter or not
:param prop: property value to check
:param arg1: some arg the filter uses
:param arg2: some other arg the filter uses
:returns: True or False
"""
... # Define your preset logic here
def __init__(self, preset_prop_mappings: ClientSidePresetPropertyMappings):
self._filter_functions = {
QueryPresets.EQUAL_TO: self._prop_equal_to,
...
QueryPresets.NEW_PRESET: prop_new_preset_filter_func # <- 2) add the enum-to-function mapping
}
...
```

## **3. Edit the query class mappings for each Query class you wish to use the preset in**
Expand All @@ -76,24 +83,22 @@ class ServerMapping(MappingInterface):
...

@staticmethod
def get_client_side_handlers() -> ServerSideHandler:
def get_client_side_handler() -> ClientSideHandler:
...
return QueryClientSideHandlers(
# set generic query preset mappings
generic_handler=ClientSideHandlerGeneric(
{
# Line below maps EQUAL_TO preset on all available properties
# ["*"] - represents all props
QueryPresetsGeneric.EQUAL_TO: ["*"],
...
# Line below maps our 'new preset' to two properties which the preset can run on
# Running the preset on any other property leads to an error
QueryPresetsGeneric.NEW_PRESET: [
ServerProperties.SERVER_ID,
ServerProperties.SERVER_NAME
]
}
),
return ClientSideHandler(

{
# Line below maps EQUAL_TO preset on all available properties
# ["*"] - represents all props
QueryPresets.EQUAL_TO: ["*"],
# ...
# Line below maps our 'new preset' to two properties which the preset can run on
# Running the preset on any other property leads to an error
QueryPresets.NEW_PRESET: [
ServerProperties.SERVER_ID,
ServerProperties.SERVER_NAME
]
}
)
...
```
Expand All @@ -110,40 +115,20 @@ e.g. Adding server-side mapping for `QueryPresetsGeneric.NEW_PRESET` to `ServerQ
```python

class ServerMapping(MappingInterface):
...
#...

@staticmethod
def get_server_side_handler() -> ServerSideHandler:
...
#...
return ServerSideHandler(
{
QueryPresetsGeneric.NEW_PRESET: {
#...
QueryPresets.NEW_PRESET: {
# adding a server-side mapping for NEW_PRESET when given SERVER_ID
ServerProperties.SERVER_ID: lambda value, arg1, arg2:
{"server-side-kwarg": value, "server-side-arg1": arg1, "server-side-arg2": arg2}
}
}
...
)
#...
```

# **Adding a new preset group**

As stated above - presets are grouped based on the datatype of the property the act on. If you need another preset
group - you can add one like so:

1. Create a new preset group class in `openstackquery/enums/query_presets.py`
- it inherits from base class QueryPresets


2. Create new client side handler in `openstackquery/handlers/client_side_handler_<preset>.py`
- it inherits from base class `ClientSideHandler` - `openstackquery/handlers/client_side_handler.py`.


3. Add your preset as a attribute in query_client_side_handlers dataclass
- located in `openstackquery/structs/query_client_side_handlers.py`


4. Follow steps mentioned above to add new presets to the new preset group class you've created

5. Edit `QueryPresets` type declaration at the bottom of the file `openstackquery/enums/query_presets.py` and add your new
preset class to it
69 changes: 31 additions & 38 deletions docs/developer_docs/ADDING_NEW_QUERIES.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class ResourceProperties(PropEnum):

# add enums for each property you found here like so
PROP_1 = auto() # replace `PROP_1` with property name
...
# ...

@staticmethod
def get_prop_mapping(prop):
Expand Down Expand Up @@ -62,18 +62,20 @@ class ResourceRunner(RunnerWrapper):

def _parse_meta_params(
self,
conn: OpenstackConnection
conn: OpenstackConnection,

# define meta params that could be passed
# they should all be optional, if no meta-params are passed, the query should still work with default values
meta_param_1 = None,
meta_param_2 = None,
...
# ...
):
pass
# Define logic here that will alter the keyword arguments that will be passed to the openstacksdk command
# based on the meta-parameter values passed in. This method should return a dictionary which will be merged with
# server-side filters and be used when calling the specific openstacksdk query which gets the resources being queried for
...

# ...

def _run_query(
self,
Expand Down Expand Up @@ -153,55 +155,46 @@ we can add mapping like so:
...
return {
# Here we map the prop_1 enum stored in ResourceProperties to the user_id enum stored in UserProperties
# Values must be a list - because a query property may map to multiple other query properties
# These two properties MUST store the same info
ResourceProperties.PROP_1: UserProperties.USER_ID,
ResourceProperties.PROP_1: [UserProperties.USER_ID],
}
...
```

### 3d. Set the client_side_handlers
### 3d. Set the client_side_handler
We must define which preset-property pair can be used together when calling `where()` on this Query class.

The `get_client_side_handlers` class is where we define these mappings.
This class creates a Dataclass called `QueryClientSideHandlers` from the mappings we define.
The `get_client_side_handler` class is where we define these mappings.
This class creates an object of `ClientSideHandler` from which mappings can be stored.

Here you must:
1. Evaluate which presets you want to the query to accept and which properties they should work on
2. You must add the presets like so:
2. Add the presets like so:

```python

def get_client_side_handlers() -> ServerSideHandler:
# This is required - at least one preset mapping must be defined here
def get_client_side_handlers() -> ClientSideHandler:
...
return QueryClientSideHandlers(
# generic_handler = set preset-property mappings that belong to generic presets
# This is required - at least one preset mapping must be defined here
generic_handler=ClientSideHandlerGeneric(
{
# Line below maps EQUAL_TO preset on all available properties
# ["*"] - represents all props
QueryPresetsGeneric.EQUAL_TO: ["*"],
...
}
),
# do the same for each of these (all optional)
string_handler=ClientSideHandlerString(
{
# Line Below maps MATCHES_REGEX preset on PROP_1 only
# All other properties are invalid
QueryPresetsString.MATCHES_REGEX: [ResourceProperties.PROP_1]
}
),
# we don't want any datetime presets to be valid - so set it to None
datetime_handler=None,

# we don't want any integer presets to be valid - so set it to None
integer_handler=None
return ClientSideHandler(
{
# Line below maps EQUAL_TO preset on all available properties
# ["*"] - represents all props
QueryPresets.EQUAL_TO: ["*"],
#...

# Line Below maps MATCHES_REGEX preset on PROP_1 only
# All other properties are invalid
QueryPresets.MATCHES_REGEX: [ResourceProperties.PROP_1]

#...
# keep going until all presets you want to allow are mapped
}
)
...
# ...
```

## 3e (Optional) Map client-side filters
## 3e (Optional) Map server-side filters

To add a server-side filter you must:
1. Read the Openstack API documentation for each Query the preset works on
Expand Down Expand Up @@ -234,7 +227,7 @@ will call `QueryFactory` with the `ResourceMapping` class we just created.

e.g. Add this function to `openstackquery/api/query_objects.py` (as usual, replace `Resource` with the name of the openstack resource your querying)
```python
def ResourceQuery() -> QueryAPI:
def ResourceQuery() -> "QueryAPI":
"""
Simple helper function to setup a query using a factory
"""
Expand Down
Loading