Add placement resource_provider and inventory schemas

Change-Id: Ic4c592b2c3d7ef89b6bdda84d041a17c93e3c5c4
This commit is contained in:
Artem Goncharov
2024-11-05 17:08:33 +01:00
parent 0afb9590ab
commit aa45e193ee
3 changed files with 325 additions and 2 deletions

View File

@@ -26,9 +26,11 @@ from codegenerator.openapi.base import OpenStackServerSourceBase
from codegenerator.openapi.utils import merge_api_ref_doc
from codegenerator.openapi.placement_schemas import allocation
from codegenerator.openapi.placement_schemas import allocation_candidate
from codegenerator.openapi.placement_schemas import resource_class
from codegenerator.openapi.placement_schemas import trait
from codegenerator.openapi.placement_schemas import inventory
from codegenerator.openapi.placement_schemas import reshaper
from codegenerator.openapi.placement_schemas import resource_class
from codegenerator.openapi.placement_schemas import resource_provider
from codegenerator.openapi.placement_schemas import trait
class PlacementGenerator(OpenStackServerSourceBase):
@@ -37,8 +39,10 @@ class PlacementGenerator(OpenStackServerSourceBase):
RESOURCE_MODULES = [
allocation,
allocation_candidate,
inventory,
reshaper,
resource_class,
resource_provider,
trait,
]

View File

@@ -0,0 +1,118 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
import copy
from typing import Any
from codegenerator.common.schema import TypeSchema
from codegenerator.common.schema import ParameterSchema
INVENTORY_PROPERTIES: dict[str, Any] = {
"total": {
"type": "integer",
"minimum": 1,
"description": "The actual amount of the resource that the provider can accommodate.",
},
"reserved": {
"type": "integer",
"minimum": 0,
"description": "The amount of the resource a provider has reserved for its own use.",
},
"min_unit": {
"type": "integer",
"minimum": 1,
"description": "A minimum amount any single allocation against an inventory can have.",
},
"max_unit": {
"type": "integer",
"minimum": 1,
"description": "A maximum amount any single allocation against an inventory can have.",
},
"step_size": {
"type": "integer",
"minimum": 1,
"description": "A representation of the divisible amount of the resource that may be requested. For example, step_size = 5 means that only values divisible by 5 (5, 10, 15, etc.) can be requested.",
},
"allocation_ratio": {
"type": "number",
"description": "It is used in determining whether consumption of the resource of the provider can exceed physical constraints. For example, for a vCPU resource with: ``allocation_ratio = 16.0 total = 8`` Overall capacity is equal to 128 vCPUs.",
},
}
INVENTORIES_SCHEMA: dict[str, Any] = {
"type": "object",
"properties": {
"inventories": {
"type": "object",
"description": "A dictionary of inventories keyed by resource classes.",
"patternProperties": {
"^[A-Z0-9_]+$": {
"type": "object",
"properties": INVENTORY_PROPERTIES,
"required": ["total"],
"additionalProperties": False,
}
},
},
"resource_provider_generation": {
"type": "integer",
"description": "A consistent view marker that assists with the management of concurrent resource provider updates.",
},
},
"required": ["inventories", "resource_provider_generation"],
"additionalProperties": False,
}
INVENTORY_SCHEMA: dict[str, Any] = {
"type": "object",
"properties": {
"resource_provider_generation": {
"type": "integer",
"description": "A consistent view marker that assists with the management of concurrent resource provider updates.",
},
**INVENTORY_PROPERTIES,
},
"required": ["total", "resource_provider_generation"],
"additionalProperties": False,
}
def _get_schema_ref(
openapi_spec, name, description=None, schema_def=None, action_name=None
) -> tuple[str | None, str | None, bool]:
mime_type: str = "application/json"
ref: str
if name in [
"Resource_ProvidersInventoriesGet_InventoriesResponse",
"Resource_ProvidersInventoriesCreate_InventoryRequest",
"Resource_ProvidersInventoriesCreate_InventoryResponse",
"Resource_ProvidersInventoriesSet_InventoriesRequest",
"Resource_ProvidersInventoriesSet_InventoriesResponse",
]:
openapi_spec.components.schemas.setdefault(
name, TypeSchema(**INVENTORIES_SCHEMA)
)
ref = f"#/components/schemas/{name}"
elif name in [
"Resource_ProvidersInventoryGet_InventoryResponse",
"Resource_ProvidersInventoryUpdate_InventoryRequest",
"Resource_ProvidersInventoryUpdate_InventoryResponse",
]:
openapi_spec.components.schemas.setdefault(
name, TypeSchema(**INVENTORY_SCHEMA)
)
ref = f"#/components/schemas/{name}"
else:
return (None, None, False)
return (ref, mime_type, True)

View File

@@ -0,0 +1,201 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
import copy
from typing import Any
from codegenerator.common.schema import TypeSchema
from codegenerator.common.schema import ParameterSchema
from placement.schemas import resource_provider
RESOURCE_PROVIDER_SCHEMA: dict[str, Any] = {
"type": "object",
"properties": {
"generation": {
"type": "integer",
"description": "A consistent view marker that assists with the management of concurrent resource provider updates.",
},
"uuid": {
"type": "string",
"format": "uuid",
"description": "The uuid of a resource provider.",
},
"links": {
"type": "array",
"items": {
"type": "object",
"properties": {
"href": {"type": "string", "format": "uri"},
"rel": {"type": "string"},
},
},
},
"name": {
"type": "string",
"description": "The name of one resource provider.",
},
"parent_provider_uuid": {
"type": "string",
"description": "The UUID of the immediate parent of the resource provider.",
"x-openstack": {"min-ver": "1.14"},
},
"root_provider_uuid": {
"type": "string",
"description": "Read-only UUID of the top-most provider in this provider tree.",
"x-openstack": {"min-ver": "1.14"},
},
},
"required": ["generation", "uuid", "links", "name"],
"additionalProperties": False,
}
RESOURCE_PROVIDER_LIST_SCHEMA: dict[str, Any] = {
"type": "object",
"properties": {
"resource_providers": {
"type": "array",
"items": RESOURCE_PROVIDER_SCHEMA,
}
},
"required": ["resource_providers"],
"additionalProperties": False,
}
RESOURCE_PROVIDER_POST_REQUEST_SCHEMA: dict[str, Any] = {
"oneOf": [
{
**resource_provider.POST_RESOURCE_PROVIDER_SCHEMA,
"x-openstack": {"min-ver": "1.0", "max-ver": "1.13"},
},
{
**resource_provider.POST_RP_SCHEMA_V1_14,
"x-openstack": {"min-ver": "1.14"},
},
],
"x-openstack": {"discriminator": "microversion"},
}
RESOURCE_PROVIDER_PUT_REQUEST_SCHEMA: dict[str, Any] = {
"oneOf": [
{
**resource_provider.PUT_RESOURCE_PROVIDER_SCHEMA,
"x-openstack": {"min-ver": "1.0", "max-ver": "1.13"},
},
{
**resource_provider.PUT_RP_SCHEMA_V1_14,
"x-openstack": {"min-ver": "1.14"},
},
],
"x-openstack": {"discriminator": "microversion"},
}
RESOURCE_PROVIDER_POST_SCHEMA: dict[str, Any] = {"oneOf": {}}
RESOURCE_PROVIDER_LIST_PARAMETERS: dict[str, Any] = {
"name": {
"in": "query",
"name": "name",
"description": "The name of a resource provider to filter the list.",
"schema": {"type": "string"},
},
"uuid": {
"in": "query",
"name": "uuid",
"description": "The uuid of a resource provider.",
"schema": {"type": "string"},
},
"resources": {
"in": "query",
"name": "resources",
"description": "A comma-separated list of strings indicating an amount of resource of a specified class that providers in each allocation request must collectively have the capacity and availability to serve: ``resources=VCPU:4,DISK_GB:64,MEMORY_MB:2048`` These resources may be satisfied by any provider in the same non-sharing tree or associated via aggregate.",
"schema": {"type": "string"},
"x-openstack": {"min-ver": "1.4"},
},
"required": {
"in": "query",
"name": "required",
"description": "A comma-separated list of traits that a provider must have:\n ``required=HW_CPU_X86_AVX,HW_CPU_X86_SSE``\n Allocation requests in the response will be for resource providers that have capacity for all requested resources and the set of those resource providers will collectively contain all of the required traits. These traits may be satisfied by any provider in the same non-sharing tree or associated via aggregate as far as that provider also contributes resource to the request. Starting from microversion 1.22 traits which are forbidden from any resource provider contributing resources to the request may be expressed by prefixing a trait with a `!`.\nStarting from microversion 1.39 the required query parameter can be repeated. The trait lists from the repeated parameters are AND-ed together. So:\n``required=T1,!T2&required=T3`` means T1 and not T2 and T3.\n Also starting from microversion 1.39 the required parameter supports the syntax:\n``required=in:T1,T2,T3`` which means T1 or T2 or T3.\nMixing forbidden traits into an in: prefixed value is not supported and rejected. But mixing a normal trait list and an in: prefixed trait list in two query params within the same request is supported. So: ``required=in:T3,T4&required=T1,!T2`` is supported and it means T1 and not T2 and (T3 or T4).",
"schema": {"type": "array", "items": {"type": "string"}},
"style": "form",
"explode": True,
"x-openstack": {"min-ver": "1.18"},
},
"member_of": {
"in": "query",
"name": "member_of",
"description": "A string representing an aggregate uuid; or the prefix in: followed by a comma-separated list of strings representing aggregate uuids. The resource providers in the allocation request in the response must directly or via the root provider be associated with the aggregate or aggregates identified by uuid:\n``member_of=5e08ea53-c4c6-448e-9334-ac4953de3cfa``, ``member_of=in:42896e0d-205d-4fe3-bd1e-100924931787,5e08ea53-c4c6-448e-9334-ac4953de3cfa``\nStarting from microversion 1.24 specifying multiple member_of query string parameters is possible. Multiple member_of parameters will result in filtering providers that are directly or via root provider associated with aggregates listed in all of the member_of query string values. For example, to get the providers that are associated with aggregate A as well as associated with any of aggregates B or C, the user could issue the following query: ``member_of=AGGA_UUID&member_of=in:AGGB_UUID,AGGC_UUID``\nStarting from microversion 1.32 specifying forbidden aggregates is supported in the member_of query string parameter. Forbidden aggregates are prefixed with a !. This negative expression can also be used in multiple member_of parameters: ``member_of=AGGA_UUID&member_of=!AGGB_UUID`` would translate logically to “Candidate resource providers must be in AGGA and not in AGGB.” We do NOT support ! on the values within in:, but we support !in:. Both of the following two example queries return candidate resource providers that are NOT in AGGA, AGGB, or AGGC: ``member_of=!in:AGGA_UUID,AGGB_UUID,AGGC_UUID``, ``member_of=!AGGA_UUID&member_of=!AGGB_UUID&member_of=!AGGC_UUID``\nWe do not check if the same aggregate uuid is in both positive and negative expression to return 400 BadRequest. We still return 200 for such cases. For example: ``member_of=AGGA_UUID&member_of=!AGGA_UUID`` would return empty allocation_requests and provider_summaries, while: ``member_of=in:AGGA_UUID,AGGB_UUID&member_of=!AGGA_UUID`` would return resource providers that are NOT in AGGA but in AGGB.",
"schema": {"type": "array", "items": {"type": "string"}},
"style": "form",
"explode": True,
"x-openstack": {"min-ver": "1.3"},
},
"in_tree": {
"in": "query",
"name": "in_tree",
"description": "A string representing a resource provider uuid. When supplied, it will filter the returned allocation candidates to only those resource providers that are in the same tree with the given resource provider.",
"schema": {"type": "string"},
"x-openstack": {"min-ver": "1.14"},
},
}
def _post_process_operation_hook(
openapi_spec, operation_spec, path: str | None = None
):
"""Hook to allow service specific generator to modify details"""
operationId = operation_spec.operationId
if operationId == "resource_providers:get":
for key, val in RESOURCE_PROVIDER_LIST_PARAMETERS.items():
openapi_spec.components.parameters.setdefault(
key, ParameterSchema(**val)
)
ref = f"#/components/parameters/{key}"
if ref not in [x.ref for x in operation_spec.parameters]:
operation_spec.parameters.append(ParameterSchema(ref=ref))
def _get_schema_ref(
openapi_spec, name, description=None, schema_def=None, action_name=None
) -> tuple[str | None, str | None, bool]:
mime_type: str = "application/json"
ref: str
if name == "Resource_ProvidersList_Resource_ProvidersResponse":
openapi_spec.components.schemas.setdefault(
name, TypeSchema(**RESOURCE_PROVIDER_LIST_SCHEMA)
)
ref = f"#/components/schemas/{name}"
elif name in [
"Resource_ProviderGet_Resource_ProviderResponse",
"Resource_ProvidersCreate_Resource_ProviderResponse",
"Resource_ProviderUpdate_Resource_ProviderResponse",
]:
openapi_spec.components.schemas.setdefault(
name, TypeSchema(**RESOURCE_PROVIDER_SCHEMA)
)
ref = f"#/components/schemas/{name}"
elif name == "Resource_ProvidersCreate_Resource_ProviderRequest":
openapi_spec.components.schemas.setdefault(
name, TypeSchema(**RESOURCE_PROVIDER_POST_REQUEST_SCHEMA)
)
ref = f"#/components/schemas/{name}"
elif name == "Resource_ProviderUpdate_Resource_ProviderRequest":
openapi_spec.components.schemas.setdefault(
name, TypeSchema(**RESOURCE_PROVIDER_PUT_REQUEST_SCHEMA)
)
ref = f"#/components/schemas/{name}"
else:
return (None, None, False)
return (ref, mime_type, True)