diff --git a/codegenerator/model.py b/codegenerator/model.py index d45823a..a1f0a28 100644 --- a/codegenerator/model.py +++ b/codegenerator/model.py @@ -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, diff --git a/codegenerator/openapi/base.py b/codegenerator/openapi/base.py index 7c2e336..6d0c799 100644 --- a/codegenerator/openapi/base.py +++ b/codegenerator/openapi/base.py @@ -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 @@ -1368,6 +1379,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" ): diff --git a/codegenerator/openapi/nova.py b/codegenerator/openapi/nova.py index b0e50d4..85b71c7 100644 --- a/codegenerator/openapi/nova.py +++ b/codegenerator/openapi/nova.py @@ -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: diff --git a/codegenerator/openapi/nova_schemas.py b/codegenerator/openapi/nova_schemas.py index 8dac965..3d252f6 100644 --- a/codegenerator/openapi/nova_schemas.py +++ b/codegenerator/openapi/nova_schemas.py @@ -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. _-]+(?