Add octavia query parameters

Sadly there is no reasonable way how to extract information about
supported query parameters ouf ot Octavia code. Moreover there is even
no documentation about that except of basic statement "The Octavia API
v2 supports filtering based on all top level attributes of a resource"
which is only partially true. So for now hardcode those parameter
schemas as known by OpenStackSDK (with exception of definitely wrong
ones).

Change-Id: I3684a6e7d31c8ac8842049373291b234574590aa
This commit is contained in:
Artem Goncharov
2024-11-26 16:54:54 +01:00
parent 3887d49135
commit cadf4f8652
3 changed files with 631 additions and 2 deletions

View File

@@ -641,6 +641,7 @@ class OpenStackServerSourceBase:
start_version,
end_version,
action_name,
operation_name,
)
if hasattr(func, "_wsme_definition"):
@@ -1178,7 +1179,8 @@ class OpenStackServerSourceBase:
mode: str,
start_version,
end_version,
action_name: str | None,
action_name: str | None = None,
operation_name: str | None = None,
):
"""Extract schemas from the decorated method."""
# Unwrap operation decorators to access all properties

View File

@@ -395,6 +395,7 @@ class KeystoneGenerator(OpenStackServerSourceBase):
start_version,
end_version,
None,
None,
)
)

View File

@@ -13,17 +13,574 @@
import inspect
from multiprocessing import Process
from pathlib import Path
from typing import Any
from unittest import mock
import fixtures
from codegenerator.common.schema import SpecSchema
from codegenerator.openapi.base import OpenStackServerSourceBase
from codegenerator.openapi.base import (
OpenStackServerSourceBase,
_convert_wsme_to_jsonschema,
)
from codegenerator.openapi.utils import merge_api_ref_doc
from ruamel.yaml.scalarstring import LiteralScalarString
TAGS_PARAMETERS: dict[str, Any] = {
"tags": {
"type": "array",
"items": {"type": "string"},
"explode": False,
"style": "form",
"description": "Return the list of entities that have this tag or tags.",
},
"tags-any": {
"type": "array",
"items": {"type": "string"},
"explode": False,
"style": "form",
"description": "Return the list of entities that have one or more of the given tags.",
},
"not-tags": {
"type": "array",
"items": {"type": "string"},
"explode": False,
"style": "form",
"description": "Return the list of entities that do not have one or more of the given tags.",
},
"not-tags-any": {
"type": "array",
"items": {"type": "string"},
"explode": False,
"style": "form",
"description": "Return the list of entities that do not have at least one of the given tags.",
},
}
STATUSES: dict[str, Any] = {
"provisioning_status": {
"type": "string",
"description": "The provisioning status of the resource.",
"enum": [
"ACTIVE",
"DELETED",
"ERROR",
"PENDING_CREATE",
"PENDING_UPDATE",
"PENDING_DELETE",
],
},
"operating_status": {
"type": "string",
"description": "The operating status of the resource.",
"enum": [
"ONLINE",
"DRAINING",
"OFFLINE",
"DEGRADED",
"ERROR",
"NO_MONITOR",
],
},
}
LOADBALANCER_QUERY_PARAMETERS: dict[str, Any] = {
"type": "object",
"properties": {
"description": {
"type": "string",
"description": "A human-readable description for the resource.",
},
"name": {
"type": "string",
"description": "Human-readable name of the resource.",
},
"id": {
"type": "string",
"format": "uuid",
"description": "The ID of the resource",
},
"project_id": {
"type": "string",
"format": "uuid",
"description": "The ID of the project owning this resource.",
},
"flavor_id": {
"type": "string",
"format": "uuid",
"description": "The ID of the flavor.",
},
"provider": {
"type": "string",
"description": "Provider name for the load balancer.",
},
"vip_address": {
"type": "string",
"description": "The IP address of the Virtual IP (VIP).",
},
"vip_network_id": {
"type": "string",
"format": "uuid",
"description": "The ID of the network for the Virtual IP (VIP).",
},
"vip_port_id": {
"type": "string",
"format": "uuid",
"description": "The ID of the Virtual IP (VIP) port.",
},
"vip_subnet_id": {
"type": "string",
"format": "uuid",
"description": "The ID of the subnet for the Virtual IP (VIP).",
},
"vip_qos_policy_id": {
"type": "string",
"format": "uuid",
"description": "The ID of the QoS Policy which will apply to the Virtual IP (VIP).",
},
"availability_zone": {
"type": "string",
"description": "An availability zone name.",
},
**STATUSES,
**TAGS_PARAMETERS,
},
}
LISTENER_QUERY_PARAMETERS: dict[str, Any] = {
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"description": "The ID of the resource",
},
"description": {
"type": "string",
"description": "A human-readable description for the resource.",
},
"name": {
"type": "string",
"description": "Human-readable name of the resource.",
},
"project_id": {
"type": "string",
"description": "The ID of the project owning this resource.",
},
"connection_limit": {
"type": "string",
"description": "The maximum number of connections permitted for this listener. Default value is -1 which represents infinite connections or a default value defined by the provider driver.",
},
"default_pool_id": {
"type": "string",
"description": "The ID of the pool used by the listener if no L7 policies match.",
},
"protocol": {
"type": "string",
"description": "The protocol for the resource.",
"enum": [
"HTTP",
"HTTPS",
"SCTP",
"PROMETHEUS",
"TCP",
"TERMINATED_HTTPS",
"UDP",
],
},
"protocol_port": {
"type": "integer",
"description": "The protocol port number for the resource.",
},
"created_at": {
"type": "string",
"format": "date-time",
"description": "The UTC date and timestamp when the resource was created.",
},
"updated_at": {
"type": "string",
"format": "date-time",
"description": "The UTC date and timestamp when the resource was last updated.",
},
"load_balancer_id": {
"type": "string",
"description": "Load balancer ID",
},
"timeout_client_data": {
"type": "integer",
"description": "Frontend client inactivity timeout in milliseconds.",
},
"timeout_member_connect": {
"type": "integer",
"description": "Backend member connection timeout in milliseconds.",
},
"timeout_member_data": {
"type": "integer",
"description": "Backend member inactivity timeout in milliseconds.",
},
"timeout_tcp_inspect": {
"type": "integer",
"description": "Time, in milliseconds, to wait for additional TCP packets for content inspection.",
},
"tls_ciphers": {
"type": "string",
"description": "List of ciphers in OpenSSL format ",
},
"tls_versions": {
"type": "string",
"description": "A list of TLS protocol versions.",
},
"alpn_protocols": {
"type": "string",
"description": "A list of ALPN protocols. Available protocols: http/1.0, http/1.1, h2",
},
"hsts_max_age": {
"type": "integer",
"description": "The value of the max_age directive for the Strict-Transport-Security HTTP response header.",
},
"admin_state_up": {
"type": "boolean",
"description": "The administrative state of the resource",
},
"hsts_include_subdomains": {
"type": "boolean",
"description": "Defines whether the includeSubDomains directive should be added to the Strict-Transport-Security HTTP response header.",
},
"hsts_preload": {
"type": "boolean",
"description": "Defines whether the preload directive should be added to the Strict-Transport-Security HTTP response header.",
},
**STATUSES,
**TAGS_PARAMETERS,
},
}
POOL_QUERY_PARAMETERS: dict[str, Any] = {
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"description": "The ID of the resource",
},
"description": {
"type": "string",
"description": "A human-readable description for the resource.",
},
"name": {
"type": "string",
"description": "Human-readable name of the resource.",
},
"project_id": {
"type": "string",
"description": "The ID of the project owning this resource.",
},
"admin_state_up": {
"type": "boolean",
"description": "The administrative state of the resource",
},
"created_at": {
"type": "string",
"format": "date-time",
"description": "The UTC date and timestamp when the resource was created.",
},
"updated_at": {
"type": "string",
"format": "date-time",
"description": "The UTC date and timestamp when the resource was last updated.",
},
"tls_enabled": {"type": "boolean"},
"tls_ciphers": {
"type": "string",
"description": "List of ciphers in OpenSSL format ",
},
"tls_versions": {
"type": "string",
"description": "A list of TLS protocol versions.",
},
"alpn_protocols": {
"type": "string",
"description": "A list of ALPN protocols. Available protocols: http/1.0, http/1.1, h2",
},
**STATUSES,
**TAGS_PARAMETERS,
},
}
POOL_MEMBER_QUERY_PARAMETERS: dict[str, Any] = {
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"description": "The ID of the resource",
},
"description": {
"type": "string",
"description": "A human-readable description for the resource.",
},
"name": {
"type": "string",
"description": "Human-readable name of the resource.",
},
"project_id": {
"type": "string",
"description": "The ID of the project owning this resource.",
},
"admin_state_up": {
"type": "boolean",
"description": "The administrative state of the resource",
},
"created_at": {
"type": "string",
"format": "date-time",
"description": "The UTC date and timestamp when the resource was created.",
},
"updated_at": {
"type": "string",
"format": "date-time",
"description": "The UTC date and timestamp when the resource was last updated.",
},
"address": {
"type": "string",
"description": "The IP address of the backend member server.",
},
"protocol_port": {
"type": "integer",
"description": "The protocol port number the backend member server is listening on.",
},
"subnet_id": {
"type": "string",
"format": "uuid",
"description": "The subnet ID the member service is accessible from.",
},
"weight": {
"type": "integer",
"description": "The weight of a member determines the portion of requests or connections it services compared to the other members of the pool.",
},
"monitor_address": {
"type": "string",
"description": "An alternate IP address used for health monitoring a backend member.",
},
"monitor_port": {
"type": "string",
"description": "An alternate protocol port used for health monitoring a backend member.",
},
"backup": {
"type": "boolean",
"description": "Is the member a backup?",
},
**STATUSES,
**TAGS_PARAMETERS,
},
}
HEALTHMONITOR_QUERY_PARAMETERS: dict[str, Any] = {
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"description": "The ID of the resource",
},
"description": {
"type": "string",
"description": "A human-readable description for the resource.",
},
"name": {
"type": "string",
"description": "Human-readable name of the resource.",
},
"project_id": {
"type": "string",
"description": "The ID of the project owning this resource.",
},
"admin_state_up": {
"type": "boolean",
"description": "The administrative state of the resource",
},
"created_at": {
"type": "string",
"format": "date-time",
"description": "The UTC date and timestamp when the resource was created.",
},
"updated_at": {
"type": "string",
"format": "date-time",
"description": "The UTC date and timestamp when the resource was last updated.",
},
"delay": {
"type": "integer",
"description": "The time, in seconds, between sending probes to members.",
},
"expected_codes": {
"type": "string",
"description": "The list of HTTP status codes expected in response from the member to declare it healthy.",
},
"http_method": {
"type": "string",
"description": "The HTTP method that the health monitor uses for requests.",
"enum": [
"CONNECT",
"DELETE",
"GET",
"HEAD",
"OPTIONS",
"PATCH",
"POST",
"PUT",
"TRACE",
],
},
"max_retries": {
"type": "integer",
"description": "The number of successful checks before changing the operating status of the member to ONLINE. A valid value is from 1 to 10.",
},
"max_retries_down": {
"type": "integer",
"description": "The number of allowed check failures before changing the operating status of the member to ERROR. A valid value is from 1 to 10.",
},
"pool_id": {"type": "string", "description": "The ID of the pool."},
"timeout": {
"type": "integer",
"description": "The maximum time, in seconds, that a monitor waits to connect before it times out.",
},
"type": {
"type": "string",
"description": "The type of health monitor.",
"enum": [
"HTTP",
"HTTPS",
"PING",
"SCTP",
"TCP",
"TLS-HELLO",
"UDP-CONNECT",
],
},
"url_path": {
"type": "string",
"description": "The HTTP URL path of the request sent by the monitor to test the health of a backend member. Must be a string that begins with a forward slash (/).",
},
**STATUSES,
**TAGS_PARAMETERS,
},
}
AMPHORAE_QUERY_PARAMETERS: dict[str, Any] = {
"type": "object",
"properties": {
"id": {"type": "string", "description": ""},
"loadbalancer_id": {"type": "string", "description": ""},
"compute_id": {"type": "string", "description": ""},
"lb_network_ip": {"type": "string", "description": ""},
"vrrp_ip": {"type": "string", "description": ""},
"ha_ip": {"type": "string", "description": ""},
"vrrp_port_id": {"type": "string", "description": ""},
"ha_port_id": {"type": "string", "description": ""},
"cert_expiration": {"type": "string", "description": ""},
"cert_busy": {"type": "string", "description": ""},
"role": {"type": "string", "description": ""},
"status": {"type": "string", "description": ""},
"vrrp_interface": {"type": "string", "description": ""},
"vrrp_id": {"type": "string", "description": ""},
"vrrp_priority": {"type": "string", "description": ""},
"cached_zone": {"type": "string", "description": ""},
"created_at": {"type": "string", "description": ""},
"updated_at": {"type": "string", "description": ""},
"image_id": {"type": "string", "description": ""},
"compute_flavor": {"type": "string", "description": ""},
},
}
AVAILABILITY_ZONE_PROFILE_QUERY_PARAMETERS: dict[str, Any] = {
"type": "object",
"properties": {
"id": {"type": "string", "description": ""},
"name": {"type": "string", "description": ""},
"provider_name": {"type": "string", "description": ""},
"availability_zone_data": {"type": "string"},
},
}
AVAILABILITY_ZONE_QUERY_PARAMETERS: dict[str, Any] = {
"type": "object",
"properties": {
"name": {"type": "string", "description": ""},
"description": {"type": "string", "description": ""},
"availability_zone_profile_id": {"type": "string", "description": ""},
"status": {"type": "string"},
},
}
FLAVOR_PROFILE_QUERY_PARAMETERS: dict[str, Any] = {
"type": "object",
"properties": {
"id": {"type": "string", "description": ""},
"name": {"type": "string", "description": ""},
"provider_name": {"type": "string", "description": ""},
"flavor_data": {"type": "string", "description": ""},
},
}
FLAVOR_QUERY_PARAMETERS: dict[str, Any] = {
"type": "object",
"properties": {
"id": {"type": "string", "description": ""},
"name": {"type": "string", "description": ""},
"description": {"type": "string", "description": ""},
"flavor_profile_id": {"type": "string"},
"enabled": {"type": "boolean", "description": ""},
},
}
L7POLICY_QUERY_PARAMETERS: dict[str, Any] = {
"type": "object",
"properties": {
"action": {"type": "string", "description": ""},
"description": {"type": "string", "description": ""},
"listener_id": {"type": "string", "description": ""},
"name": {"type": "string", "description": ""},
"position": {"type": "string", "description": ""},
"redirect_pool_id": {"type": "string", "description": ""},
"redirect_url": {"type": "string", "description": ""},
"provisioning_status": {"type": "string", "description": ""},
"operating_status": {"type": "string", "description": ""},
"redirect_prefix": {"type": "string", "description": ""},
"project_id": {"type": "string", "description": ""},
"admin_state_up": {"type": "boolean", "description": ""},
},
}
L7RULE_QUERY_PARAMETERS: dict[str, Any] = {
"type": "object",
"properties": {
"compare_type": {"type": "string", "description": ""},
"created_at": {"type": "string", "description": ""},
"invert": {"type": "string", "description": ""},
"key": {"type": "string", "description": ""},
"project_id": {"type": "string", "description": ""},
"provisioning_status": {"type": "string", "description": ""},
"type": {"type": "string", "description": ""},
"updated_at": {"type": "string", "description": ""},
"rule_value": {"type": "string", "description": ""},
"operating_status": {"type": "string", "description": ""},
"admin_state_up": {"type": "boolean", "description": ""},
},
}
PROVIDER_QUERY_PARAMETERS: dict[str, Any] = {
"type": "object",
"properties": {
"description": {"type": "string", "description": ""},
"name": {"type": "string", "description": ""},
},
}
class OctaviaGenerator(OpenStackServerSourceBase):
URL_TAG_MAP = {
"/lbaas/listeners": "listeners",
@@ -396,3 +953,72 @@ class OctaviaGenerator(OpenStackServerSourceBase):
lnk.symlink_to(impl_path.name)
return impl_path
def _process_decorators(
self,
func,
path_resource_names: list[str],
openapi_spec,
mode: str,
start_version,
end_version,
action_name: str | None = None,
operation_name: str | None = None,
):
(
query_params_versions,
body_schemas,
response_body_schema,
expected_errors,
) = super()._process_decorators(
func,
path_resource_names,
openapi_spec,
mode,
start_version,
end_version,
action_name,
operation_name,
)
if operation_name in ["list", "index"]:
# NOTE(gtema) sadly there is no reasonable way how to extract
# supported query parameters out of octavia so we need to hardcode
# them for now
qp: dict[str, Any] | None = None
if path_resource_names == ["lbaas", "loadbalancers"]:
qp = LOADBALANCER_QUERY_PARAMETERS
elif path_resource_names == ["lbaas", "listeners"]:
qp = LISTENER_QUERY_PARAMETERS
elif path_resource_names == ["lbaas", "pools"]:
qp = POOL_QUERY_PARAMETERS
elif path_resource_names == ["lbaas", "pools", "members"]:
qp = POOL_MEMBER_QUERY_PARAMETERS
elif path_resource_names == ["lbaas", "healthmonitors"]:
qp = HEALTHMONITOR_QUERY_PARAMETERS
elif path_resource_names == ["lbaas", "l7policies"]:
qp = L7POLICY_QUERY_PARAMETERS
elif path_resource_names == ["lbaas", "l7policies", "rules"]:
qp = L7RULE_QUERY_PARAMETERS
elif path_resource_names == ["octavia", "amphorae"]:
qp = AMPHORAE_QUERY_PARAMETERS
elif path_resource_names == ["lbaas", "availabilityzoneprofiles"]:
qp = AVAILABILITY_ZONE_PROFILE_QUERY_PARAMETERS
elif path_resource_names == ["lbaas", "availabilityzones"]:
qp = AVAILABILITY_ZONE_QUERY_PARAMETERS
elif path_resource_names == ["lbaas", "flavorprofiles"]:
qp = FLAVOR_PROFILE_QUERY_PARAMETERS
elif path_resource_names == ["lbaas", "flavors"]:
qp = FLAVOR_QUERY_PARAMETERS
elif path_resource_names == ["lbaas", "providers"]:
qp = PROVIDER_QUERY_PARAMETERS
if qp:
query_params_versions.append((qp, None, None))
return (
query_params_versions,
body_schemas,
response_body_schema,
expected_errors,
)