Skip to content

Commit

Permalink
add aggregate query functionality
Browse files Browse the repository at this point in the history
allows searching for hypervisor aggregates
  • Loading branch information
anish-mudaraddi committed Jan 23, 2025
1 parent ba9d83e commit b479f46
Show file tree
Hide file tree
Showing 5 changed files with 232 additions and 0 deletions.
1 change: 1 addition & 0 deletions openstackquery/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
ProjectQuery,
ImageQuery,
HypervisorQuery,
AggregateQuery,
)

# Create logger
Expand Down
8 changes: 8 additions & 0 deletions openstackquery/api/query_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from openstackquery.mappings.project_mapping import ProjectMapping
from openstackquery.mappings.server_mapping import ServerMapping
from openstackquery.mappings.user_mapping import UserMapping
from openstackquery.mappings.aggregate_mapping import AggregateMapping

if TYPE_CHECKING:
from openstackquery.api.query_api import QueryAPI
Expand Down Expand Up @@ -70,3 +71,10 @@ def HypervisorQuery() -> "QueryAPI":
Simple helper function to setup a query using a factory
"""
return get_common(HypervisorMapping)


def AggregateQuery() -> QueryAPI:
"""
Simple helper function to setup a query using a factory
"""
return get_common(AggregateMapping)
66 changes: 66 additions & 0 deletions openstackquery/enums/props/aggregate_properties.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
from enum import auto
from typing import Dict, Optional

from openstackquery.enums.props.prop_enum import PropEnum, PropFunc
from exceptions.query_property_mapping_error import QueryPropertyMappingError


class AggregateProperties(PropEnum):
"""
An enum class for Host Aggregate Properties
"""

AGGREGATE_CREATED_AT = auto()
AGGREGATE_DELETED = auto()
AGGREGATE_DELETED_AT = auto()
AGGREGATE_HOST_IPS = auto()
AGGREGATE_HOSTTYPE = auto()
AGGREGATE_UPDATED_AT = auto()
AGGREGATE_ID = auto()

@staticmethod
def _get_aliases() -> Dict:
"""
a method that returns all valid string alias mappings
"""
return {
AggregateProperties.AGGREGATE_CREATED_AT: ["created_at"],
AggregateProperties.AGGREGATE_DELETED: ["deleted"],
AggregateProperties.AGGREGATE_DELETED_AT: ["deleted_at"],
AggregateProperties.AGGREGATE_HOST_IPS: ["hosts"],
AggregateProperties.AGGREGATE_HOSTTYPE: ["metadata_hosttype", "hosttype"],
AggregateProperties.AGGREGATE_UPDATED_AT: ["updated_at"],
AggregateProperties.AGGREGATE_ID: ["id", "uuid"],
}

@staticmethod
def get_prop_mapping(prop) -> Optional[PropFunc]:
"""
Method that returns the property function if function mapping exists for a given AggregateProperty Enum
how to get specified property from an openstacksdk Aggregate object is documented here:
https://docs.openstack.org/openstacksdk/latest/user/resources/compute/v2/aggregate.html
:param prop: A Aggregate Enum for which a function may exist for
"""
mapping = {
AggregateProperties.AGGREGATE_CREATED_AT: lambda a: a["created_at"],
AggregateProperties.AGGREGATE_DELETED: lambda a: a["deleted"],
AggregateProperties.AGGREGATE_DELETED_AT: lambda a: a["deleted_at"],
AggregateProperties.AGGREGATE_HOST_IPS: lambda a: a["hosts"],
AggregateProperties.AGGREGATE_HOSTTYPE: lambda a: a["metadata"].get(
"hosttype", None
),
AggregateProperties.AGGREGATE_ID: lambda a: a["id"],
}
try:
return mapping[prop]
except KeyError as exp:
raise QueryPropertyMappingError(
f"Error: failed to get property mapping, property {prop.name} is not supported in AggregateProperties"
) from exp

@staticmethod
def get_marker_prop_func():
"""
A getter method to return marker property function for pagination
"""
return AggregateProperties.get_prop_mapping(AggregateProperties.AGGREGATE_ID)
106 changes: 106 additions & 0 deletions openstackquery/mappings/aggregate_mapping.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
from typing import Type

from openstackquery.enums.props.aggregate_properties import AggregateProperties
from openstackquery.enums.query_presets import (
QueryPresetsDateTime,
QueryPresetsString,
QueryPresetsGeneric,
)
from openstackquery.handlers.client_side_handler_datetime import (
ClientSideHandlerDateTime,
)
from openstackquery.handlers.client_side_handler_generic import (
ClientSideHandlerGeneric,
)
from openstackquery.handlers.client_side_handler_string import ClientSideHandlerString
from openstackquery.handlers.server_side_handler import ServerSideHandler
from openstackquery.mappings.mapping_interface import MappingInterface
from openstackquery.runners.aggregate_runner import AggregateRunner
from openstackquery.runners.runner_wrapper import RunnerWrapper
from openstackquery.structs.query_client_side_handlers import QueryClientSideHandlers


class AggregateMapping(MappingInterface):
"""
Mapping class for querying Openstack Aggregate objects
Define property mappings, kwarg mappings and filter function mappings, and runner mapping related to hypervisors here
"""

@staticmethod
def get_chain_mappings():
"""
Should return a dictionary containing property pairs mapped to query mappings.
This is used to define how to chain results from this query to other possible queries
"""
# TODO: find a way to map list of hostnames:
# AggregateProperties.HOST_IPS to HypervisorProperties.HYPERVISOR_NAME
return None

@staticmethod
def get_runner_mapping() -> Type[RunnerWrapper]:
"""
Returns a mapping to associated Runner class for the Query (AggregateRunner)
"""
return AggregateRunner

@staticmethod
def get_prop_mapping() -> Type[AggregateProperties]:
"""
Returns a mapping of valid presets for server side attributes (HypervisorProperties)
"""
return AggregateProperties

@staticmethod
def get_server_side_handler() -> ServerSideHandler:
"""
method to configure a server handler which can be used to get 'filter' keyword arguments that
can be passed to openstack function conn.compute.aggregates() to filter results for a valid preset-property
pair
valid filters documented here:
https://docs.openstack.org/openstacksdk/latest/user/proxies/compute.html
https://docs.openstack.org/api-ref/compute/?expanded=list-hypervisors-detail#list-aggregates
"""
# No server-side filters for AggregateQuery
return ServerSideHandler({})

@staticmethod
def get_client_side_handlers() -> QueryClientSideHandlers:
"""
method to configure a set of client-side handlers which can be used to get local filter functions
corresponding to valid preset-property pairs. These filter functions can be used to filter results after
listing all aggregates.
"""
datetime_props = [
AggregateProperties.AGGREGATE_DELETED_AT,
AggregateProperties.AGGREGATE_UPDATED_AT,
AggregateProperties.AGGREGATE_CREATED_AT,
]

return QueryClientSideHandlers(
# set generic query preset mappings
generic_handler=ClientSideHandlerGeneric(
{
QueryPresetsGeneric.EQUAL_TO: ["*"],
QueryPresetsGeneric.NOT_EQUAL_TO: ["*"],
QueryPresetsGeneric.ANY_IN: ["*"],
QueryPresetsGeneric.NOT_ANY_IN: ["*"],
}
),
string_handler=ClientSideHandlerString(
{
QueryPresetsString.MATCHES_REGEX: [
AggregateProperties.AGGREGATE_HOSTTYPE
]
}
),
datetime_handler=ClientSideHandlerDateTime(
{
QueryPresetsDateTime.OLDER_THAN: datetime_props,
QueryPresetsDateTime.YOUNGER_THAN: datetime_props,
QueryPresetsDateTime.OLDER_THAN_OR_EQUAL_TO: datetime_props,
QueryPresetsDateTime.YOUNGER_THAN_OR_EQUAL_TO: datetime_props,
}
),
integer_handler=None,
)
51 changes: 51 additions & 0 deletions openstackquery/runners/aggregate_runner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import logging
from typing import Optional, List

from openstackquery.aliases import ServerSideFilters, OpenstackResourceObj
from openstackquery.openstack_connection import OpenstackConnection
from openstackquery.runners.runner_wrapper import RunnerWrapper
from openstack.compute.v2.aggregate import Aggregate

logger = logging.getLogger(__name__)


class AggregateRunner(RunnerWrapper):
"""
Runner class for openstack Aggregate resource
AggregateRunner encapsulates running any openstacksdk Aggregate commands
"""

RESOURCE_TYPE = Aggregate

def parse_meta_params(self, conn: OpenstackConnection, **kwargs):
"""
This method is a helper function that will parse a set of meta params specific to the resource and
return a set of parsed meta-params to pass to _run_query
"""
logger.debug("AggregateQuery has no meta-params available")
return super().parse_meta_params(conn, **kwargs)

def run_query(
self,
conn: OpenstackConnection,
filter_kwargs: Optional[ServerSideFilters] = None,
**kwargs,
) -> List[OpenstackResourceObj]:
"""
This method runs the query by running openstacksdk commands
For AggregateQuery, this command finds all aggregates that match a given set of filter_kwargs
:param conn: An OpenstackConnection object - used to connect to openstacksdk
:param filter_kwargs: An Optional list of filter kwargs to pass to conn.identity.aggregates()
to limit the hypervisors being returned.
- see https://docs.openstack.org/api-ref/compute/?expanded=list-hypervisors-detail#list-aggregates
"""
if not filter_kwargs:
# return server info
filter_kwargs = {}
logger.debug(
"running openstacksdk command conn.compute.aggregates(%s)",
",".join(f"{key}={value}" for key, value in filter_kwargs.items()),
)

return conn.compute.aggregates(**filter_kwargs)

0 comments on commit b479f46

Please sign in to comment.