Files
openstack-api-simulator/app/openstack/seed_discovery.py
T
inecs 147f04c9a2 Fix Nova/Cinder stateful CRUD so the full surface and Pulumi matrix pass clean.
Persist aggregates and server security groups in domain tables, add Cinder quota
show from DB-backed defaults, align unit tests with OpenStack series, auto-pick
Keystone :5000/:15000 for smoke, and document test locations plus 6514/6514 results.
2026-07-18 09:38:45 +03:00

532 lines
15 KiB
Python

"""Seed discovery / catalog / schema documents into ``os_api_objects``."""
from __future__ import annotations
from typing import Any
from asyncpg import Connection
from app.openstack.db_docs import upsert_doc
from app.openstack.surface import SERVICES
def _version_doc(service: str, payload: dict[str, Any]) -> tuple[str, str, str, dict[str, Any]]:
return service, "discovery_version", "default", payload
async def seed_discovery_documents(conn: Connection) -> dict[str, int]:
"""Persist API discovery documents so handlers never hardcode them."""
docs: list[tuple[str, str, str, dict[str, Any]]] = [
_version_doc(
"keystone",
{
"versions": {
"values": [
{
"id": "v3.14",
"status": "stable",
"updated": "2024-07-01T00:00:00Z",
"links": [{"rel": "self", "href": "/v3/"}],
"media-types": [
{
"base": "application/json",
"type": "application/vnd.openstack.identity-v3+json",
}
],
}
]
}
},
),
_version_doc(
"nova",
{
"versions": [
{
"id": "v2.1",
"status": "CURRENT",
"version": "2.96",
"min_version": "2.1",
"links": [{"rel": "self", "href": "/v2.1/"}],
}
]
},
),
_version_doc(
"neutron",
{
"versions": [
{
"id": "v2.0",
"status": "CURRENT",
"links": [{"rel": "self", "href": "/v2.0/"}],
}
]
},
),
_version_doc(
"glance",
{
"versions": [
{"id": "v2.9", "status": "CURRENT", "links": [{"rel": "self", "href": "/v2/"}]}
]
},
),
_version_doc(
"cinder",
{
"versions": [
{
"id": "v3.0",
"status": "CURRENT",
"version": "3.70",
"min_version": "3.0",
"links": [{"rel": "self", "href": "/v3/"}],
}
]
},
),
_version_doc(
"placement",
{
"versions": [
{
"id": "v1.0",
"status": "CURRENT",
"min_version": "1.0",
"max_version": "1.39",
"links": [{"rel": "self", "href": "/"}],
}
]
},
),
_version_doc("swift", {"swift": {"version": "2.30.0"}}),
_version_doc(
"ironic",
{
"id": "v1",
"version": {
"id": "1.90",
"status": "CURRENT",
"min_version": "1.1",
"version": "1.90",
},
},
),
_version_doc(
"octavia",
{
"versions": [
{"id": "v2.0", "status": "CURRENT", "links": [{"href": "/v2/", "rel": "self"}]}
]
},
),
_version_doc(
"heat",
{
"versions": [
{"id": "v1.0", "status": "CURRENT", "links": [{"rel": "self", "href": "/v1/"}]}
]
},
),
(
"swift",
"info",
"default",
{
"swift": {"version": "2.30.0", "max_file_size": 5368709122},
"tempauth": {"user_groups": ["admin"]},
},
),
(
"glance",
"info_stores",
"default",
{
"stores": [
{
"id": "fast",
"type": "file",
"description": "Local file store",
"default": True,
},
{"id": "cheap", "type": "file", "description": "Secondary file store"},
]
},
),
(
"glance",
"info_import",
"default",
{
"import-methods": {
"type": "array",
"description": "Import methods available.",
"items": {"type": "string"},
"value": ["glance-direct", "web-download", "copy-image"],
}
},
),
(
"glance",
"schema",
"image",
{
"name": "image",
"properties": {
"id": {"type": "string"},
"name": {"type": "string"},
"status": {"type": "string"},
"visibility": {"type": "string"},
"disk_format": {"type": "string"},
"container_format": {"type": "string"},
},
"additionalProperties": True,
},
),
(
"glance",
"schema",
"images",
{
"name": "images",
"properties": {
"images": {"type": "array", "items": {"type": "object"}},
"first": {"type": "string"},
"next": {"type": "string"},
"schema": {"type": "string"},
},
},
),
(
"heat",
"resource_type_list",
"default",
{
"resource_types": [
"OS::Nova::Server",
"OS::Neutron::Net",
"OS::Neutron::Subnet",
"OS::Neutron::Port",
"OS::Cinder::Volume",
"OS::Glance::Image",
"OS::Heat::Stack",
]
},
),
(
"zaqar",
"ping",
"default",
{"ping": "pong"},
),
(
"zaqar",
"health",
"default",
{"catalog": True, "storage": True, "operation_status": "UP"},
),
(
"cinder",
"limits",
"default",
{
"limits": {
"rate": [],
"absolute": {
"maxTotalVolumeGigabytes": 100000,
"maxTotalVolumes": 500,
"totalVolumesUsed": 0,
"totalGigabytesUsed": 0,
},
}
},
),
(
"keystone",
"limits",
"default",
{
"limits": [
{
"resource_name": "project",
"resource_limit": 100,
"region_id": None,
}
]
},
),
(
"nova",
"limits",
"default",
{
"limits": {
"rate": [],
"absolute": {
"maxTotalInstances": 100,
"maxTotalCores": 200,
"maxTotalRAMSize": 512000,
"totalInstancesUsed": 0,
"totalCoresUsed": 0,
"totalRAMUsed": 0,
},
}
},
),
(
"nova",
"console_template",
"default",
{
"type": "novnc",
"url": "https://127.0.0.1:6080/vnc_auto.html?token=__SERVER_ID__",
},
),
(
"nova",
"console_output_template",
"default",
{"output": "Booting...\nSimulator console\n"},
),
(
"nova",
"server_metadata_defaults",
"default",
{"metadata": {"env": "lab"}},
),
(
"nova",
"server_topology_template",
"default",
{
"nodes": [
{
"vcpu_set": [0],
"siblings": [[0]],
"host_node": 0,
"memory_mb": 1024,
"cpu_pinning": {},
}
],
"pagesize_kb": 4,
},
),
(
"nova",
"server_password_defaults",
"default",
{"password": ""},
),
(
"nova",
"server_tag_defaults",
"default",
{"tags": ["lab", "env", "demo"]},
),
(
"nova",
"keypair_defaults",
"default",
{
"name": "default",
"public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC lab@simulator",
"type": "ssh",
"fingerprint_prefix": "https://example.invalid/",
},
),
(
"nova",
"server_group_defaults",
"default",
{"name": "group", "policies": ["soft-anti-affinity"]},
),
(
"placement",
"allocation_defaults",
"default",
{
"resources": {"VCPU": 1, "MEMORY_MB": 1024, "DISK_GB": 10},
"consumer_generation": 0,
},
),
(
"placement",
"resource_provider_defaults",
"default",
{"generation": 1},
),
(
"ironic",
"node_defaults",
"default",
{
"driver": "ipmi",
"resource_class": "baremetal",
"properties": {"cpus": 32, "memory_mb": 131072, "local_gb": 1024},
"power_state": "power on",
"provision_state": "active",
},
),
(
"glance",
"image_defaults",
"default",
{
"name": "image",
"visibility": "private",
"disk_format": "qcow2",
"container_format": "bare",
},
),
(
"cinder",
"volume_defaults",
"default",
{"size": 1, "volume_type": "lvmdriver-1", "name": "volume"},
),
(
"heat",
"stack_defaults",
"default",
{
"template": {"heat_template_version": "2015-04-30", "resources": {}},
"parameters": {},
},
),
(
"octavia",
"loadbalancer_defaults",
"default",
{"name": "lb", "vip_address": "10.0.0.50"},
),
(
"neutron",
"network_defaults",
"default",
{"name": "net"},
),
(
"neutron",
"router_defaults",
"default",
{"name": "router"},
),
(
"neutron",
"security_group_defaults",
"default",
{"name": "default"},
),
(
"neutron",
"security_group_rule_defaults",
"default",
{"direction": "ingress", "ethertype": "IPv4"},
),
(
"nova",
"server_defaults",
"default",
{"name": "instance"},
),
(
"nova",
"volume_attachment_defaults",
"default",
{"device": "/dev/vdb"},
),
(
"nova",
"quota_set_defaults",
"default",
{
"quota_set": {
"instances": 100,
"cores": 200,
"ram": 512000,
"floating_ips": 50,
"fixed_ips": -1,
"metadata_items": 128,
"injected_files": 5,
"injected_file_content_bytes": 10240,
"security_groups": 50,
"security_group_rules": 100,
"key_pairs": 100,
"server_groups": 10,
"server_group_members": 10,
}
},
),
(
"cinder",
"quota_set_defaults",
"default",
{
"quota_set": {
"volumes": 100,
"snapshots": 100,
"gigabytes": 1000,
"backups": 10,
"backup_gigabytes": 1000,
"groups": 10,
"per_volume_gigabytes": -1,
}
},
),
(
"nova",
"console_auth_token_defaults",
"default",
{
"console_type": "novnc",
"host": "127.0.0.1",
"port": 6080,
"internal_access_path": None,
},
),
]
from app.openstack.surface import catalog_entries
# Persist catalog with placeholders so Keystone reads catalog only from DB.
catalog_template = {
"catalog": catalog_entries("__HOST__", scheme="__SCHEME__"),
}
docs.append(("keystone", "service_catalog_template", "default", catalog_template))
# Generic version docs for remaining SERVICES not listed above.
seeded_services = {d[0] for d in docs if d[1] == "discovery_version"}
for spec in SERVICES:
if spec.name in seeded_services:
continue
docs.append(
_version_doc(
spec.name,
{
"versions": [
{
"id": spec.version_path.strip("/") or "v1",
"status": "CURRENT",
"links": [{"rel": "self", "href": spec.version_path or "/"}],
"service": spec.name,
"type": spec.typ,
}
]
},
)
)
for service, rtype, name, data in docs:
await upsert_doc(conn, service=service, resource_type=rtype, name=name, data=data)
# Ironic drivers as listable rows (also used by /v1/drivers).
for driver, payload in (
("ipmi", {"name": "ipmi", "hosts": ["simulator"], "type": "classic"}),
("redfish", {"name": "redfish", "hosts": ["simulator"], "type": "classic"}),
):
await upsert_doc(conn, service="ironic", resource_type="driver", name=driver, data=payload)
return {"documents": len(docs) + 2}