Merge "Remove some hardcoded nova schemas"
This commit is contained in:
commit
471f414492
codegenerator
@ -296,7 +296,19 @@ class JsonSchemaParser:
|
||||
return PrimitiveAny()
|
||||
if not type_ and "format" in schema:
|
||||
return ConstraintString(**schema)
|
||||
raise RuntimeError("Cannot determine type for %s", schema)
|
||||
const = schema.get("const")
|
||||
if const is not None:
|
||||
if isinstance(const, str):
|
||||
obj = ConstraintString(**schema)
|
||||
return obj
|
||||
if isinstance(const, int):
|
||||
obj = ConstraintInteger(**schema)
|
||||
return obj
|
||||
else:
|
||||
raise RuntimeError(
|
||||
"Unsupported const type", const, type(const)
|
||||
)
|
||||
raise RuntimeError("Cannot determine type", schema)
|
||||
|
||||
def parse_object(
|
||||
self,
|
||||
|
@ -160,67 +160,78 @@ class OpenStackServerSourceBase:
|
||||
openapi_parser = model.OpenAPISchemaParser()
|
||||
for res, res_spec in metadata.resources.items():
|
||||
for operation_name, operation_spec in res_spec.operations.items():
|
||||
operation_id = operation_spec.operation_id
|
||||
try:
|
||||
operation_id = operation_spec.operation_id
|
||||
|
||||
(path, method, spec) = common.find_openapi_operation(
|
||||
openapi_spec, operation_id
|
||||
)
|
||||
resource_name = common.get_resource_names_from_url(path)[-1]
|
||||
(path, method, spec) = common.find_openapi_operation(
|
||||
openapi_spec, operation_id
|
||||
)
|
||||
resource_name = common.get_resource_names_from_url(path)[
|
||||
-1
|
||||
]
|
||||
|
||||
# Parse params
|
||||
for param in openapi_spec["paths"][path].get("parameters", []):
|
||||
openapi_parser.parse_parameter(param)
|
||||
# Parse params
|
||||
for param in openapi_spec["paths"][path].get(
|
||||
"parameters", []
|
||||
):
|
||||
openapi_parser.parse_parameter(param)
|
||||
|
||||
op_name: str | None = None
|
||||
response_key: str | None = None
|
||||
sdk_target = operation_spec.targets.get("rust-sdk")
|
||||
if sdk_target:
|
||||
op_name = sdk_target.operation_name
|
||||
response_key = sdk_target.response_key
|
||||
op_name: str | None = None
|
||||
response_key: str | None = None
|
||||
sdk_target = operation_spec.targets.get("rust-sdk")
|
||||
if sdk_target:
|
||||
op_name = sdk_target.operation_name
|
||||
response_key = sdk_target.response_key
|
||||
|
||||
operation_variants = common.get_operation_variants(
|
||||
spec, op_name or operation_name
|
||||
)
|
||||
|
||||
for operation_variant in operation_variants:
|
||||
operation_body = operation_variant.get("body")
|
||||
if operation_body:
|
||||
openapi_parser.parse(
|
||||
operation_body, ignore_read_only=True
|
||||
)
|
||||
|
||||
if method.upper() != "HEAD":
|
||||
response = common.find_response_schema(
|
||||
spec["responses"],
|
||||
response_key or resource_name,
|
||||
(
|
||||
operation_name
|
||||
if operation_spec.operation_type == "action"
|
||||
else None
|
||||
),
|
||||
operation_variants = common.get_operation_variants(
|
||||
spec, op_name or operation_name
|
||||
)
|
||||
|
||||
if response:
|
||||
if response_key:
|
||||
response_key = (
|
||||
response_key
|
||||
if response_key != "null"
|
||||
else None
|
||||
for operation_variant in operation_variants:
|
||||
operation_body = operation_variant.get("body")
|
||||
if operation_body:
|
||||
openapi_parser.parse(
|
||||
operation_body, ignore_read_only=True
|
||||
)
|
||||
else:
|
||||
response_key = resource_name
|
||||
response_def, _ = common.find_resource_schema(
|
||||
response, None, response_key
|
||||
|
||||
if method.upper() != "HEAD":
|
||||
response = common.find_response_schema(
|
||||
spec["responses"],
|
||||
response_key or resource_name,
|
||||
(
|
||||
operation_name
|
||||
if operation_spec.operation_type == "action"
|
||||
else None
|
||||
),
|
||||
)
|
||||
|
||||
if response_def:
|
||||
if response_def.get(
|
||||
"type", "object"
|
||||
) == "object" or (
|
||||
isinstance(response_def.get("type"), list)
|
||||
and "object" in response_def["type"]
|
||||
):
|
||||
openapi_parser.parse(response_def)
|
||||
if response:
|
||||
if response_key:
|
||||
response_key = (
|
||||
response_key
|
||||
if response_key != "null"
|
||||
else None
|
||||
)
|
||||
else:
|
||||
response_key = resource_name
|
||||
response_def, _ = common.find_resource_schema(
|
||||
response, None, response_key
|
||||
)
|
||||
|
||||
if response_def:
|
||||
if response_def.get(
|
||||
"type", "object"
|
||||
) == "object" or (
|
||||
isinstance(response_def.get("type"), list)
|
||||
and "object" in response_def["type"]
|
||||
):
|
||||
openapi_parser.parse(response_def)
|
||||
|
||||
except Exception as ex:
|
||||
logging.exception(
|
||||
"Error validating %s %s %s", res, operation_name, spec
|
||||
)
|
||||
raise
|
||||
|
||||
def _sanitize_param_ver_info(self, openapi_spec, min_api_version):
|
||||
# Remove min_version of params if it matches to min_api_version
|
||||
@ -1369,6 +1380,7 @@ class OpenStackServerSourceBase:
|
||||
getattr(f, "_response_body_schema", {}),
|
||||
)
|
||||
response_body_schema = obj
|
||||
print(f"the response schema is {response_body_schema}")
|
||||
if "query_params_schema" in closure_locals or hasattr(
|
||||
f, "_request_query_schema"
|
||||
):
|
||||
|
@ -156,8 +156,6 @@ class NovaGenerator(OpenStackServerSourceBase):
|
||||
schema_def=None,
|
||||
action_name=None,
|
||||
):
|
||||
from nova.api.openstack.compute.schemas import flavors
|
||||
|
||||
schema: None = None
|
||||
ref: str | None
|
||||
mime_type: str | None = "application/json"
|
||||
@ -351,94 +349,12 @@ class NovaGenerator(OpenStackServerSourceBase):
|
||||
)
|
||||
ref = f"#/components/schemas/{name}"
|
||||
|
||||
# /flavors/...
|
||||
elif name == "FlavorsListResponse":
|
||||
schema = openapi_spec.components.schemas.setdefault(
|
||||
name, TypeSchema(**nova_schemas.FLAVORS_LIST_SCHEMA)
|
||||
)
|
||||
ref = f"#/components/schemas/{name}"
|
||||
elif name == "FlavorsDetailResponse":
|
||||
schema = openapi_spec.components.schemas.setdefault(
|
||||
name, TypeSchema(**nova_schemas.FLAVORS_LIST_DETAIL_SCHEMA)
|
||||
)
|
||||
ref = f"#/components/schemas/{name}"
|
||||
elif name in [
|
||||
"FlavorsCreateResponse",
|
||||
"FlavorShowResponse",
|
||||
"FlavorUpdateResponse",
|
||||
]:
|
||||
schema = openapi_spec.components.schemas.setdefault(
|
||||
name, TypeSchema(**nova_schemas.FLAVOR_CONTAINER_SCHEMA)
|
||||
)
|
||||
ref = f"#/components/schemas/{name}"
|
||||
elif name == "FlavorUpdateRequest":
|
||||
schema = openapi_spec.components.schemas.setdefault(
|
||||
name, TypeSchema(**flavors.update_v2_55)
|
||||
)
|
||||
ref = f"#/components/schemas/{name}"
|
||||
elif name in [
|
||||
"FlavorsOs_Flavor_AccessListResponse",
|
||||
"FlavorsActionAddtenantaccessResponse",
|
||||
"FlavorsActionRemovetenantaccessResponse",
|
||||
]:
|
||||
schema = openapi_spec.components.schemas.setdefault(
|
||||
name, TypeSchema(**nova_schemas.FLAVOR_ACCESSES_SCHEMA)
|
||||
)
|
||||
ref = f"#/components/schemas/{name}"
|
||||
elif name in [
|
||||
"FlavorsOs_Extra_SpecsListResponse",
|
||||
"FlavorsOs_Extra_SpecsCreateResponse",
|
||||
]:
|
||||
schema = openapi_spec.components.schemas.setdefault(
|
||||
name, TypeSchema(**nova_schemas.FLAVOR_EXTRA_SPECS_LIST_SCHEMA)
|
||||
)
|
||||
ref = f"#/components/schemas/{name}"
|
||||
elif name in [
|
||||
"FlavorsOs_Extra_SpecShowResponse",
|
||||
"FlavorsOs_Extra_SpecUpdateResponse",
|
||||
]:
|
||||
schema = openapi_spec.components.schemas.setdefault(
|
||||
name, TypeSchema(**nova_schemas.FLAVOR_EXTRA_SPEC_SCHEMA)
|
||||
)
|
||||
ref = f"#/components/schemas/{name}"
|
||||
# /limits
|
||||
elif name == "LimitsListResponse":
|
||||
schema = openapi_spec.components.schemas.setdefault(
|
||||
name, TypeSchema(**nova_schemas.LIMITS_SCHEMA)
|
||||
)
|
||||
ref = f"#/components/schemas/{name}"
|
||||
# /os-aggregates
|
||||
elif name == "Os_AggregatesListResponse":
|
||||
schema = openapi_spec.components.schemas.setdefault(
|
||||
name, TypeSchema(**nova_schemas.AGGREGATE_LIST_SCHEMA)
|
||||
)
|
||||
ref = f"#/components/schemas/{name}"
|
||||
elif name in [
|
||||
"Os_AggregatesCreateResponse",
|
||||
"Os_AggregateShowResponse",
|
||||
"Os_AggregateUpdateResponse",
|
||||
"Os_AggregatesActionAdd_HostResponse",
|
||||
"Os_AggregatesActionRemove_HostResponse",
|
||||
"Os_AggregatesActionSet_MetadataResponse",
|
||||
]:
|
||||
schema = openapi_spec.components.schemas.setdefault(
|
||||
name, TypeSchema(**nova_schemas.AGGREGATE_CONTAINER_SCHEMA)
|
||||
)
|
||||
ref = f"#/components/schemas/{name}"
|
||||
elif name == "Os_AggregatesImagesResponse":
|
||||
return (None, None)
|
||||
# /os-assisted-volume-snapshots
|
||||
elif name == "Os_Assisted_Volume_SnapshotsCreateResponse":
|
||||
schema = openapi_spec.components.schemas.setdefault(
|
||||
name, TypeSchema(**nova_schemas.VOLUME_SNAPSHOT_SCHEMA)
|
||||
)
|
||||
ref = f"#/components/schemas/{name}"
|
||||
# /os-assisted-volume-snapshots
|
||||
elif name == "Os_Assisted_Volume_SnapshotsCreateResponse":
|
||||
schema = openapi_spec.components.schemas.setdefault(
|
||||
name, TypeSchema(**nova_schemas.VOLUME_SNAPSHOT_SCHEMA)
|
||||
)
|
||||
ref = f"#/components/schemas/{name}"
|
||||
# /os-availability-zone
|
||||
elif name == "Os_Availability_ZoneListResponse":
|
||||
schema = openapi_spec.components.schemas.setdefault(
|
||||
@ -634,7 +550,11 @@ class NovaGenerator(OpenStackServerSourceBase):
|
||||
return (None, None)
|
||||
else:
|
||||
(ref, mime_type) = super()._get_schema_ref(
|
||||
openapi_spec, name, description, action_name=action_name
|
||||
openapi_spec,
|
||||
name,
|
||||
description,
|
||||
schema_def=schema_def,
|
||||
action_name=action_name,
|
||||
)
|
||||
if action_name and schema:
|
||||
if not schema.openstack:
|
||||
|
@ -13,7 +13,6 @@
|
||||
import copy
|
||||
from typing import Any
|
||||
|
||||
from nova.api.openstack.compute.schemas import flavors_extraspecs
|
||||
from nova.api.openstack.compute.schemas import quota_sets
|
||||
from nova.api.openstack.compute.schemas import remote_consoles
|
||||
from nova.api.validation import parameter_types
|
||||
@ -93,124 +92,6 @@ SERVER_TOPOLOGY_SCHEMA: dict[str, Any] = {
|
||||
},
|
||||
}
|
||||
|
||||
FLAVOR_EXTRA_SPEC_SCHEMA: dict[str, Any] = {
|
||||
"minProperties": 1,
|
||||
"maxProperties": 1,
|
||||
"examples": {"JSON Request": {"hw:numa_nodes": "1"}},
|
||||
**flavors_extraspecs.metadata,
|
||||
}
|
||||
|
||||
FLAVOR_EXTRA_SPECS_SCHEMA: dict[str, Any] = flavors_extraspecs.metadata
|
||||
FLAVOR_EXTRA_SPECS_LIST_SCHEMA: dict[str, Any] = {
|
||||
"type": "object",
|
||||
"description": "A dictionary of the flavor’s extra-specs key-and-value pairs. It appears in the os-extra-specs’ “create” REQUEST body, as well as the os-extra-specs’ “create” and “list” RESPONSE body.",
|
||||
"properties": {"extra_specs": flavors_extraspecs.metadata},
|
||||
}
|
||||
|
||||
FLAVOR_SHORT_SCHEMA: dict[str, Any] = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {"type": "string", "format": "uuid"},
|
||||
"name": {"type": "string"},
|
||||
"description": {"type": "string"},
|
||||
"links": LINKS_SCHEMA,
|
||||
},
|
||||
}
|
||||
FLAVOR_SCHEMA: dict[str, Any] = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "The display name of a flavor.",
|
||||
},
|
||||
"id": {
|
||||
"type": "string",
|
||||
"description": "The ID of the flavor. While people often make this look like an int, this is really a string.",
|
||||
"minLength": 1,
|
||||
"maxLength": 255,
|
||||
"pattern": "^(?! )[a-zA-Z0-9. _-]+(?<! )$",
|
||||
},
|
||||
"ram": {
|
||||
"description": "The amount of RAM a flavor has, in MiB.",
|
||||
**parameter_types.flavor_param_positive,
|
||||
},
|
||||
"vcpus": {
|
||||
"description": "The number of virtual CPUs that will be allocated to the server.",
|
||||
**parameter_types.flavor_param_positive,
|
||||
},
|
||||
"disk": {
|
||||
"description": "The size of the root disk that will be created in GiB. If 0 the root disk will be set to exactly the size of the image used to deploy the instance. However, in this case the scheduler cannot select the compute host based on the virtual image size. Therefore, 0 should only be used for volume booted instances or for testing purposes. Volume-backed instances can be enforced for flavors with zero root disk via the os_compute_api:servers:create:zero_disk_flavor policy rule.",
|
||||
**parameter_types.flavor_param_non_negative,
|
||||
},
|
||||
"OS-FLV-EXT-DATA:ephemeral": {
|
||||
"description": "The size of the ephemeral disk that will be created, in GiB. Ephemeral disks may be written over on server state changes. So should only be used as a scratch space for applications that are aware of its limitations. Defaults to 0.",
|
||||
**parameter_types.flavor_param_non_negative,
|
||||
},
|
||||
"swap": {
|
||||
"description": "The size of a dedicated swap disk that will be allocated, in MiB. If 0 (the default), no dedicated swap disk will be created. Currently, the empty string (‘’) is used to represent 0. As of microversion 2.75 default return value of swap is 0 instead of empty string.",
|
||||
**parameter_types.flavor_param_non_negative,
|
||||
},
|
||||
"rxtx_factor": {
|
||||
"description": "The receive / transmit factor (as a float) that will be set on ports if the network backend supports the QOS extension. Otherwise it will be ignored. It defaults to 1.0.",
|
||||
"type": ["number", "string"],
|
||||
"pattern": r"^[0-9]+(\.[0-9]+)?$",
|
||||
"minimum": 0,
|
||||
"exclusiveMinimum": True,
|
||||
"maximum": 3.40282e38,
|
||||
},
|
||||
"os-flavor-access:is_public": {
|
||||
"description": "Whether the flavor is public (available to all projects) or scoped to a set of projects. Default is True if not specified.",
|
||||
**parameter_types.boolean,
|
||||
},
|
||||
"extra_specs": FLAVOR_EXTRA_SPECS_SCHEMA,
|
||||
"links": LINKS_SCHEMA,
|
||||
},
|
||||
"additionalProperties": False,
|
||||
}
|
||||
|
||||
FLAVOR_CONTAINER_SCHEMA: dict[str, Any] = {
|
||||
"type": "object",
|
||||
"description": "Single flavor details",
|
||||
"properties": {"flavor": copy.deepcopy(FLAVOR_SCHEMA)},
|
||||
}
|
||||
|
||||
FLAVORS_LIST_SCHEMA: dict[str, Any] = {
|
||||
"description": "Flavors list response",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"flavors": {
|
||||
"type": "array",
|
||||
"items": copy.deepcopy(FLAVOR_SHORT_SCHEMA),
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
FLAVORS_LIST_DETAIL_SCHEMA: dict[str, Any] = {
|
||||
"description": "Detailed flavors list response",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"flavors": {"type": "array", "items": copy.deepcopy(FLAVOR_SCHEMA)}
|
||||
},
|
||||
}
|
||||
|
||||
FLAVOR_ACCESS_SCHEMA: dict[str, Any] = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"flavor_id": {"type": "string", "format": "uuid"},
|
||||
"tenant_id": {"type": "string", "format": "uuid"},
|
||||
},
|
||||
}
|
||||
FLAVOR_ACCESSES_SCHEMA: dict[str, Any] = {
|
||||
"description": "A list of objects, each with the keys flavor_id and tenant_id.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"flavor_access": {
|
||||
"type": "array",
|
||||
"items": copy.deepcopy(FLAVOR_ACCESS_SCHEMA),
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
LIMITS_SCHEMA: dict[str, Any] = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@ -274,71 +155,6 @@ LIMITS_SCHEMA: dict[str, Any] = {
|
||||
},
|
||||
}
|
||||
|
||||
AGGREGATE_SCHEMA: dict[str, Any] = {
|
||||
"type": "object",
|
||||
"description": "The host aggregate object",
|
||||
"properties": {
|
||||
"availability_zone": {
|
||||
"type": "string",
|
||||
"description": "The availability zone of the host aggregate.",
|
||||
},
|
||||
"created_at": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "The date and time when the resource was created.",
|
||||
},
|
||||
"deleted": {
|
||||
"type": "boolean",
|
||||
"description": "A boolean indicates whether this aggregate is deleted or not, if it has not been deleted, false will appear.",
|
||||
},
|
||||
"deleted_at": {
|
||||
"type": ["string", "null"],
|
||||
"format": "date-time",
|
||||
"description": "The date and time when the resource was deleted. If the resource has not been deleted yet, this field will be null.",
|
||||
},
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"description": "The ID of the host aggregate.",
|
||||
},
|
||||
"metadata": parameter_types.metadata,
|
||||
"hosts": {
|
||||
"type": "array",
|
||||
"description": "A list of host ids in this aggregate.",
|
||||
"items": {"type": "string"},
|
||||
},
|
||||
"updated_at": {
|
||||
"type": ["string", "null"],
|
||||
"format": "date-time",
|
||||
"description": "The date and time when the resource was updated, if the resource has not been updated, this field will show as null.",
|
||||
},
|
||||
"uuid": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"description": "The UUID of the host aggregate. New in version 2.41",
|
||||
"x-openstack": {"min-ver": "2.41"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
AGGREGATE_CONTAINER_SCHEMA: dict[str, Any] = {
|
||||
"type": "object",
|
||||
"description": "Aggregate object.",
|
||||
"properties": {"aggregate": copy.deepcopy(AGGREGATE_SCHEMA)},
|
||||
}
|
||||
|
||||
|
||||
AGGREGATE_LIST_SCHEMA: dict[str, Any] = {
|
||||
"type": "object",
|
||||
"description": "The list of existing aggregates.",
|
||||
"properties": {
|
||||
"aggregates": {
|
||||
"type": "array",
|
||||
"description": "The list of existing aggregates.",
|
||||
"items": copy.deepcopy(AGGREGATE_SCHEMA),
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
VOLUME_SNAPSHOT_SCHEMA: dict[str, Any] = {
|
||||
"type": "object",
|
||||
"description": "A partial representation of a snapshot that is used to create a snapshot.",
|
||||
|
Loading…
x
Reference in New Issue
Block a user