Fix pyproject.toml file name
- rename properly pyproject.toml file - reformatted files due to rules not being applied before - address now failing unittest Change-Id: I189a0c71253fe87c5fa91f6d7f46fb350fe4d0d9
This commit is contained in:
parent
ca4120cddd
commit
2326ce5e7b
codegenerator
ansible.pybase.pycli.py
common
jsonschema.pymetadata.pymodel.pyopenapi
base.pycinder.py
openapi_spec.pyosc.pyrust_cli.pyrust_sdk.pycinder_schemas
attachment.pybackup.pycluster.pycommon.pyextension.pygroup.pygroup_snapshot.pygroup_type.pyhost.pylimit.pymessage.pyqos.pyresource_filter.pysnapshot.pysnapshot_manage.pyvolume.pyvolume_manage.pyvolume_transfer.pyvolume_type.py
glance.pykeystone.pykeystone_schemas
application_credential.pyauth.pycommon.pydomain.pyendpoint.pyfederation.pygroup.pyproject.pyregion.pyrole.pyservice.pyuser.py
manila.pyneutron.pyneutron_schemas.pynova.pynova_schemas.pyoctavia.pyplacement.pyutils.pytests
doc/source
pyproject.tomlreleasenotes/source
@ -44,21 +44,21 @@ class AnsibleGenerator(BaseGenerator):
|
|||||||
|
|
||||||
def generate(self, res, target_dir, args=None):
|
def generate(self, res, target_dir, args=None):
|
||||||
"""Generate code for the Ansible"""
|
"""Generate code for the Ansible"""
|
||||||
logging.debug("Generating Ansible code in %s" % target_dir)
|
logging.debug(f"Generating Ansible code in {target_dir}")
|
||||||
ansible_path = ["plugins", "modules"]
|
ansible_path = ["plugins", "modules"]
|
||||||
|
|
||||||
context = dict(
|
context = {
|
||||||
res=res.resource_class,
|
"res": res.resource_class,
|
||||||
sdk_mod_name=res.mod_name,
|
"sdk_mod_name": res.mod_name,
|
||||||
class_name=res.class_name,
|
"class_name": res.class_name,
|
||||||
resource_name=res.class_name.lower(),
|
"resource_name": res.class_name.lower(),
|
||||||
sdk_service_name=res.service_name,
|
"sdk_service_name": res.service_name,
|
||||||
proxy=res.proxy_obj,
|
"proxy": res.proxy_obj,
|
||||||
fqcn=res.fqcn,
|
"fqcn": res.fqcn,
|
||||||
registry_name=res.registry_name,
|
"registry_name": res.registry_name,
|
||||||
attrs=res.attrs,
|
"attrs": res.attrs,
|
||||||
target_name=res.class_name.lower(),
|
"target_name": res.class_name.lower(),
|
||||||
)
|
}
|
||||||
if args and args.alternative_target_name:
|
if args and args.alternative_target_name:
|
||||||
context["target_name"] = args.alternative_target_name
|
context["target_name"] = args.alternative_target_name
|
||||||
context["ansible_module_name"] = "".join(
|
context["ansible_module_name"] = "".join(
|
||||||
@ -96,6 +96,4 @@ class AnsibleGenerator(BaseGenerator):
|
|||||||
# Format rendered code to have less flake complains. This will still
|
# Format rendered code to have less flake complains. This will still
|
||||||
# not guarantee code is fitting perfect, since there might be too long
|
# not guarantee code is fitting perfect, since there might be too long
|
||||||
# lines
|
# lines
|
||||||
self._format_code(
|
self._format_code(Path(work_dir, "/".join(ansible_path)))
|
||||||
Path(work_dir, "/".join(ansible_path)),
|
|
||||||
)
|
|
||||||
|
@ -49,7 +49,7 @@ class BaseGenerator:
|
|||||||
content = template.render(**context)
|
content = template.render(**context)
|
||||||
dest.mkdir(parents=True, exist_ok=True)
|
dest.mkdir(parents=True, exist_ok=True)
|
||||||
with open(Path(dest, fname), "w") as fp:
|
with open(Path(dest, fname), "w") as fp:
|
||||||
logging.debug("Writing %s" % (fp.name))
|
logging.debug(f"Writing {fp.name}")
|
||||||
fp.write(content)
|
fp.write(content)
|
||||||
|
|
||||||
def _format_code(self, *args):
|
def _format_code(self, *args):
|
||||||
|
@ -39,14 +39,16 @@ class ResourceProcessor:
|
|||||||
def __init__(self, mod_name, class_name):
|
def __init__(self, mod_name, class_name):
|
||||||
self.mod_name = mod_name
|
self.mod_name = mod_name
|
||||||
self.class_name = class_name
|
self.class_name = class_name
|
||||||
self.class_plural_name = class_name + "s" if class_name[:-1] != "y" else "ies"
|
self.class_plural_name = (
|
||||||
|
class_name + "s" if class_name[:-1] != "y" else "ies"
|
||||||
|
)
|
||||||
|
|
||||||
spec = importlib.util.find_spec(self.mod_name)
|
spec = importlib.util.find_spec(self.mod_name)
|
||||||
if not spec:
|
if not spec:
|
||||||
raise RuntimeError("Module %s not found" % self.mod_name)
|
raise RuntimeError(f"Module {self.mod_name} not found")
|
||||||
self.module = importlib.util.module_from_spec(spec)
|
self.module = importlib.util.module_from_spec(spec)
|
||||||
if not self.module:
|
if not self.module:
|
||||||
raise RuntimeError("Error loading module %s" % self.mod_name)
|
raise RuntimeError(f"Error loading module {self.mod_name}")
|
||||||
sys.modules[self.mod_name] = self.module
|
sys.modules[self.mod_name] = self.module
|
||||||
if not spec.loader:
|
if not spec.loader:
|
||||||
raise RuntimeError("No module loader available")
|
raise RuntimeError("No module loader available")
|
||||||
@ -58,10 +60,10 @@ class ResourceProcessor:
|
|||||||
proxy_mod_name = srv_ver_mod + "._proxy"
|
proxy_mod_name = srv_ver_mod + "._proxy"
|
||||||
proxy_spec = importlib.util.find_spec(proxy_mod_name)
|
proxy_spec = importlib.util.find_spec(proxy_mod_name)
|
||||||
if not proxy_spec:
|
if not proxy_spec:
|
||||||
raise RuntimeError("Module %s not found" % proxy_mod_name)
|
raise RuntimeError(f"Module {proxy_mod_name} not found")
|
||||||
self.proxy_mod = importlib.util.module_from_spec(proxy_spec)
|
self.proxy_mod = importlib.util.module_from_spec(proxy_spec)
|
||||||
if not self.proxy_mod:
|
if not self.proxy_mod:
|
||||||
raise RuntimeError("Error loading module %s" % proxy_mod_name)
|
raise RuntimeError(f"Error loading module {proxy_mod_name}")
|
||||||
sys.modules[proxy_mod_name] = self.proxy_mod
|
sys.modules[proxy_mod_name] = self.proxy_mod
|
||||||
if not proxy_spec.loader:
|
if not proxy_spec.loader:
|
||||||
raise RuntimeError("No module loader available")
|
raise RuntimeError("No module loader available")
|
||||||
@ -81,7 +83,7 @@ class ResourceProcessor:
|
|||||||
):
|
):
|
||||||
self.registry_name = f"{self.service_name}.{k}"
|
self.registry_name = f"{self.service_name}.{k}"
|
||||||
|
|
||||||
self.attrs = dict()
|
self.attrs = {}
|
||||||
self.process()
|
self.process()
|
||||||
|
|
||||||
def process(self):
|
def process(self):
|
||||||
@ -95,7 +97,7 @@ class ResourceProcessor:
|
|||||||
doc = "Name"
|
doc = "Name"
|
||||||
elif not doc and k == "tags":
|
elif not doc and k == "tags":
|
||||||
doc = f"{self.class_name} Tags."
|
doc = f"{self.class_name} Tags."
|
||||||
self.attrs[k] = dict(attr=v, docs=doc)
|
self.attrs[k] = {"attr": v, "docs": doc}
|
||||||
|
|
||||||
def get_attr_docs(self):
|
def get_attr_docs(self):
|
||||||
mod = pycode.ModuleAnalyzer.for_module(self.mod_name)
|
mod = pycode.ModuleAnalyzer.for_module(self.mod_name)
|
||||||
@ -121,11 +123,13 @@ class Generator:
|
|||||||
def get_openapi_spec(self, path: Path):
|
def get_openapi_spec(self, path: Path):
|
||||||
logging.debug("Fetch %s", path)
|
logging.debug("Fetch %s", path)
|
||||||
if path.as_posix() not in self.schemas:
|
if path.as_posix() not in self.schemas:
|
||||||
self.schemas[path.as_posix()] = common.get_openapi_spec(path.as_posix())
|
self.schemas[path.as_posix()] = common.get_openapi_spec(
|
||||||
|
path.as_posix()
|
||||||
|
)
|
||||||
return self.schemas[path.as_posix()]
|
return self.schemas[path.as_posix()]
|
||||||
|
|
||||||
def load_metadata(self, path: Path):
|
def load_metadata(self, path: Path):
|
||||||
with open(path, "r") as fp:
|
with open(path) as fp:
|
||||||
data = yaml.safe_load(fp)
|
data = yaml.safe_load(fp)
|
||||||
self.metadata = Metadata(**data)
|
self.metadata = Metadata(**data)
|
||||||
|
|
||||||
@ -158,45 +162,30 @@ def main():
|
|||||||
],
|
],
|
||||||
help="Target for which to generate code",
|
help="Target for which to generate code",
|
||||||
)
|
)
|
||||||
parser.add_argument("--work-dir", help="Working directory for the generated code")
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--alternative-module-path",
|
"--work-dir", help="Working directory for the generated code"
|
||||||
help=("Optional new module path"),
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--alternative-module-path", help=("Optional new module path")
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--alternative-module-name",
|
"--alternative-module-name",
|
||||||
help=("Optional new module name " "(rename get into list)"),
|
help=("Optional new module name " "(rename get into list)"),
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--openapi-yaml-spec",
|
"--openapi-yaml-spec", help=("Path to the OpenAPI spec file (yaml)")
|
||||||
help=("Path to the OpenAPI spec file (yaml)"),
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--openapi-operation-id",
|
|
||||||
help=("OpenAPI operationID"),
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--service-type",
|
|
||||||
help=("Catalog service type"),
|
|
||||||
)
|
)
|
||||||
|
parser.add_argument("--openapi-operation-id", help=("OpenAPI operationID"))
|
||||||
|
parser.add_argument("--service-type", help=("Catalog service type"))
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--api-version",
|
"--api-version",
|
||||||
help=("Api version (used in path for resulting code, i.e. v1)"),
|
help=("Api version (used in path for resulting code, i.e. v1)"),
|
||||||
)
|
)
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument("--metadata", help=("Metadata file to load"))
|
||||||
"--metadata",
|
parser.add_argument("--service", help=("Metadata service name filter"))
|
||||||
help=("Metadata file to load"),
|
parser.add_argument("--resource", help=("Metadata resource name filter"))
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--service",
|
|
||||||
help=("Metadata service name filter"),
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--resource",
|
|
||||||
help=("Metadata resource name filter"),
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--validate",
|
"--validate",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
@ -246,11 +235,13 @@ def main():
|
|||||||
openapi_spec = generator.get_openapi_spec(
|
openapi_spec = generator.get_openapi_spec(
|
||||||
Path(
|
Path(
|
||||||
# metadata_path.parent,
|
# metadata_path.parent,
|
||||||
op_data.spec_file or res_data.spec_file,
|
op_data.spec_file or res_data.spec_file
|
||||||
).resolve()
|
).resolve()
|
||||||
)
|
)
|
||||||
|
|
||||||
for mod_path, mod_name, path in generators[args.target].generate(
|
for mod_path, mod_name, path in generators[
|
||||||
|
args.target
|
||||||
|
].generate(
|
||||||
res,
|
res,
|
||||||
args.work_dir,
|
args.work_dir,
|
||||||
openapi_spec=openapi_spec,
|
openapi_spec=openapi_spec,
|
||||||
@ -278,16 +269,19 @@ def main():
|
|||||||
)
|
)
|
||||||
|
|
||||||
if args.target == "rust-sdk" and not args.resource:
|
if args.target == "rust-sdk" and not args.resource:
|
||||||
resource_results: dict[str, dict] = dict()
|
resource_results: dict[str, dict] = {}
|
||||||
for mod_path, mod_name, path in res_mods:
|
for mod_path, mod_name, path in res_mods:
|
||||||
mn = "/".join(mod_path)
|
mn = "/".join(mod_path)
|
||||||
x = resource_results.setdefault(mn, {"path": path, "mods": set()})
|
x = resource_results.setdefault(
|
||||||
|
mn, {"path": path, "mods": set()}
|
||||||
|
)
|
||||||
x["mods"].add(mod_name)
|
x["mods"].add(mod_name)
|
||||||
changed = True
|
changed = True
|
||||||
while changed:
|
while changed:
|
||||||
changed = False
|
changed = False
|
||||||
for mod_path in [
|
for mod_path in [
|
||||||
mod_path_str.split("/") for mod_path_str in resource_results.keys()
|
mod_path_str.split("/")
|
||||||
|
for mod_path_str in resource_results.keys()
|
||||||
]:
|
]:
|
||||||
if len(mod_path) < 3:
|
if len(mod_path) < 3:
|
||||||
continue
|
continue
|
||||||
|
@ -35,7 +35,9 @@ FQAN_ALIAS_MAP = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _deep_merge(dict1: dict[Any, Any], dict2: dict[Any, Any]) -> dict[Any, Any]:
|
def _deep_merge(
|
||||||
|
dict1: dict[Any, Any], dict2: dict[Any, Any]
|
||||||
|
) -> dict[Any, Any]:
|
||||||
result = dict1.copy()
|
result = dict1.copy()
|
||||||
for key, value in dict2.items():
|
for key, value in dict2.items():
|
||||||
if key in result:
|
if key in result:
|
||||||
@ -51,7 +53,7 @@ def _deep_merge(dict1: dict[Any, Any], dict2: dict[Any, Any]) -> dict[Any, Any]:
|
|||||||
|
|
||||||
class BasePrimitiveType(BaseModel):
|
class BasePrimitiveType(BaseModel):
|
||||||
lifetimes: set[str] | None = None
|
lifetimes: set[str] | None = None
|
||||||
builder_macros: set[str] = set([])
|
builder_macros: set[str] = set()
|
||||||
|
|
||||||
|
|
||||||
class BaseCombinedType(BaseModel):
|
class BaseCombinedType(BaseModel):
|
||||||
@ -70,7 +72,7 @@ class BaseCompoundType(BaseModel):
|
|||||||
|
|
||||||
def get_openapi_spec(path: str | Path):
|
def get_openapi_spec(path: str | Path):
|
||||||
"""Load OpenAPI spec from a file"""
|
"""Load OpenAPI spec from a file"""
|
||||||
with open(path, "r") as fp:
|
with open(path) as fp:
|
||||||
spec_data = jsonref.replace_refs(yaml.safe_load(fp), proxies=False)
|
spec_data = jsonref.replace_refs(yaml.safe_load(fp), proxies=False)
|
||||||
return Spec.from_dict(spec_data)
|
return Spec.from_dict(spec_data)
|
||||||
|
|
||||||
@ -83,7 +85,7 @@ def find_openapi_operation(spec, operationId: str):
|
|||||||
continue
|
continue
|
||||||
if method_spec.get("operationId") == operationId:
|
if method_spec.get("operationId") == operationId:
|
||||||
return (path, method, method_spec)
|
return (path, method, method_spec)
|
||||||
raise RuntimeError("Cannot find operation %s specification" % operationId)
|
raise RuntimeError(f"Cannot find operation {operationId} specification")
|
||||||
|
|
||||||
|
|
||||||
def get_plural_form(resource: str) -> str:
|
def get_plural_form(resource: str) -> str:
|
||||||
@ -171,10 +173,14 @@ def find_resource_schema(
|
|||||||
elif "properties" in schema:
|
elif "properties" in schema:
|
||||||
schema["type"] = "object"
|
schema["type"] = "object"
|
||||||
else:
|
else:
|
||||||
raise RuntimeError("No type in %s" % schema)
|
raise RuntimeError(f"No type in {schema}")
|
||||||
schema_type = schema["type"]
|
schema_type = schema["type"]
|
||||||
if schema_type == "array":
|
if schema_type == "array":
|
||||||
if parent and resource_name and parent == get_plural_form(resource_name):
|
if (
|
||||||
|
parent
|
||||||
|
and resource_name
|
||||||
|
and parent == get_plural_form(resource_name)
|
||||||
|
):
|
||||||
items = schema["items"]
|
items = schema["items"]
|
||||||
if (
|
if (
|
||||||
items.get("type") == "object"
|
items.get("type") == "object"
|
||||||
@ -185,7 +191,9 @@ def find_resource_schema(
|
|||||||
return (items["properties"][resource_name], parent)
|
return (items["properties"][resource_name], parent)
|
||||||
else:
|
else:
|
||||||
return (items, parent)
|
return (items, parent)
|
||||||
elif not parent and schema.get("items", {}).get("type") == "object":
|
elif (
|
||||||
|
not parent and schema.get("items", {}).get("type") == "object"
|
||||||
|
):
|
||||||
# Array on the top level. Most likely we are searching for items
|
# Array on the top level. Most likely we are searching for items
|
||||||
# directly
|
# directly
|
||||||
return (schema["items"], None)
|
return (schema["items"], None)
|
||||||
@ -228,7 +236,9 @@ def find_resource_schema(
|
|||||||
else:
|
else:
|
||||||
return (schema, None)
|
return (schema, None)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
logging.exception(f"Caught exception {ex} during processing of {schema}")
|
logging.exception(
|
||||||
|
f"Caught exception {ex} during processing of {schema}"
|
||||||
|
)
|
||||||
raise
|
raise
|
||||||
return (None, None)
|
return (None, None)
|
||||||
|
|
||||||
@ -275,7 +285,9 @@ def find_response_schema(
|
|||||||
for candidate in oneof:
|
for candidate in oneof:
|
||||||
if (
|
if (
|
||||||
action_name
|
action_name
|
||||||
and candidate.get("x-openstack", {}).get("action-name")
|
and candidate.get("x-openstack", {}).get(
|
||||||
|
"action-name"
|
||||||
|
)
|
||||||
== action_name
|
== action_name
|
||||||
):
|
):
|
||||||
if response_key in candidate.get("properties", {}):
|
if response_key in candidate.get("properties", {}):
|
||||||
@ -363,17 +375,24 @@ def get_operation_variants(spec: dict, operation_name: str):
|
|||||||
variant_spec = variant.get("x-openstack", {})
|
variant_spec = variant.get("x-openstack", {})
|
||||||
if variant_spec.get("action-name") == operation_name:
|
if variant_spec.get("action-name") == operation_name:
|
||||||
discriminator = variant_spec.get("discriminator")
|
discriminator = variant_spec.get("discriminator")
|
||||||
if "oneOf" in variant and discriminator == "microversion":
|
if (
|
||||||
|
"oneOf" in variant
|
||||||
|
and discriminator == "microversion"
|
||||||
|
):
|
||||||
logging.debug(
|
logging.debug(
|
||||||
"Microversion discriminator for action bodies"
|
"Microversion discriminator for action bodies"
|
||||||
)
|
)
|
||||||
for subvariant in variant["oneOf"]:
|
for subvariant in variant["oneOf"]:
|
||||||
subvariant_spec = subvariant.get("x-openstack", {})
|
subvariant_spec = subvariant.get(
|
||||||
|
"x-openstack", {}
|
||||||
|
)
|
||||||
operation_variants.append(
|
operation_variants.append(
|
||||||
{
|
{
|
||||||
"body": subvariant,
|
"body": subvariant,
|
||||||
"mode": "action",
|
"mode": "action",
|
||||||
"min-ver": subvariant_spec.get("min-ver"),
|
"min-ver": subvariant_spec.get(
|
||||||
|
"min-ver"
|
||||||
|
),
|
||||||
"mime_type": mime_type,
|
"mime_type": mime_type,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -392,8 +411,7 @@ def get_operation_variants(spec: dict, operation_name: str):
|
|||||||
break
|
break
|
||||||
if not operation_variants:
|
if not operation_variants:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"Cannot find body specification for action %s"
|
f"Cannot find body specification for action {operation_name}"
|
||||||
% operation_name
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
operation_variants.append(
|
operation_variants.append(
|
||||||
@ -527,20 +545,14 @@ def get_resource_names_from_url(path: str):
|
|||||||
|
|
||||||
def get_rust_sdk_mod_path(service_type: str, api_version: str, path: str):
|
def get_rust_sdk_mod_path(service_type: str, api_version: str, path: str):
|
||||||
"""Construct mod path for rust sdk"""
|
"""Construct mod path for rust sdk"""
|
||||||
mod_path = [
|
mod_path = [service_type.replace("-", "_"), api_version]
|
||||||
service_type.replace("-", "_"),
|
|
||||||
api_version,
|
|
||||||
]
|
|
||||||
mod_path.extend([x.lower() for x in get_resource_names_from_url(path)])
|
mod_path.extend([x.lower() for x in get_resource_names_from_url(path)])
|
||||||
return mod_path
|
return mod_path
|
||||||
|
|
||||||
|
|
||||||
def get_rust_cli_mod_path(service_type: str, api_version: str, path: str):
|
def get_rust_cli_mod_path(service_type: str, api_version: str, path: str):
|
||||||
"""Construct mod path for rust sdk"""
|
"""Construct mod path for rust sdk"""
|
||||||
mod_path = [
|
mod_path = [service_type.replace("-", "_"), api_version]
|
||||||
service_type.replace("-", "_"),
|
|
||||||
api_version,
|
|
||||||
]
|
|
||||||
mod_path.extend([x.lower() for x in get_resource_names_from_url(path)])
|
mod_path.extend([x.lower() for x in get_resource_names_from_url(path)])
|
||||||
return mod_path
|
return mod_path
|
||||||
|
|
||||||
|
@ -30,8 +30,8 @@ class Boolean(BasePrimitiveType):
|
|||||||
"""Basic Boolean"""
|
"""Basic Boolean"""
|
||||||
|
|
||||||
type_hint: str = "bool"
|
type_hint: str = "bool"
|
||||||
imports: set[str] = set([])
|
imports: set[str] = set()
|
||||||
clap_macros: set[str] = set(["action=clap::ArgAction::Set"])
|
clap_macros: set[str] = {"action=clap::ArgAction::Set"}
|
||||||
original_data_type: BaseCompoundType | BaseCompoundType | None = None
|
original_data_type: BaseCompoundType | BaseCompoundType | None = None
|
||||||
|
|
||||||
def get_sample(self):
|
def get_sample(self):
|
||||||
@ -40,7 +40,7 @@ class Boolean(BasePrimitiveType):
|
|||||||
|
|
||||||
class Number(BasePrimitiveType):
|
class Number(BasePrimitiveType):
|
||||||
format: str | None = None
|
format: str | None = None
|
||||||
imports: set[str] = set([])
|
imports: set[str] = set()
|
||||||
clap_macros: set[str] = set()
|
clap_macros: set[str] = set()
|
||||||
original_data_type: BaseCompoundType | BaseCompoundType | None = None
|
original_data_type: BaseCompoundType | BaseCompoundType | None = None
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ class Number(BasePrimitiveType):
|
|||||||
|
|
||||||
class Integer(BasePrimitiveType):
|
class Integer(BasePrimitiveType):
|
||||||
format: str | None = None
|
format: str | None = None
|
||||||
imports: set[str] = set([])
|
imports: set[str] = set()
|
||||||
clap_macros: set[str] = set()
|
clap_macros: set[str] = set()
|
||||||
original_data_type: BaseCompoundType | BaseCompoundType | None = None
|
original_data_type: BaseCompoundType | BaseCompoundType | None = None
|
||||||
|
|
||||||
@ -77,8 +77,8 @@ class Integer(BasePrimitiveType):
|
|||||||
|
|
||||||
class Null(BasePrimitiveType):
|
class Null(BasePrimitiveType):
|
||||||
type_hint: str = "Value"
|
type_hint: str = "Value"
|
||||||
imports: set[str] = set(["serde_json::Value"])
|
imports: set[str] = {"serde_json::Value"}
|
||||||
builder_macros: set[str] = set([])
|
builder_macros: set[str] = set()
|
||||||
clap_macros: set[str] = set()
|
clap_macros: set[str] = set()
|
||||||
original_data_type: BaseCompoundType | BaseCompoundType | None = None
|
original_data_type: BaseCompoundType | BaseCompoundType | None = None
|
||||||
|
|
||||||
@ -89,13 +89,13 @@ class Null(BasePrimitiveType):
|
|||||||
class String(BasePrimitiveType):
|
class String(BasePrimitiveType):
|
||||||
format: str | None = None
|
format: str | None = None
|
||||||
type_hint: str = "String"
|
type_hint: str = "String"
|
||||||
builder_macros: set[str] = set(["setter(into)"])
|
builder_macros: set[str] = {"setter(into)"}
|
||||||
|
|
||||||
# NOTE(gtema): it is not possible to override field with computed
|
# NOTE(gtema): it is not possible to override field with computed
|
||||||
# property, thus it must be a property here
|
# property, thus it must be a property here
|
||||||
@property
|
@property
|
||||||
def imports(self) -> set[str]:
|
def imports(self) -> set[str]:
|
||||||
return set([])
|
return set()
|
||||||
|
|
||||||
def get_sample(self):
|
def get_sample(self):
|
||||||
return '"foo"'
|
return '"foo"'
|
||||||
@ -103,14 +103,14 @@ class String(BasePrimitiveType):
|
|||||||
|
|
||||||
class JsonValue(BasePrimitiveType):
|
class JsonValue(BasePrimitiveType):
|
||||||
type_hint: str = "Value"
|
type_hint: str = "Value"
|
||||||
builder_macros: set[str] = set(["setter(into)"])
|
builder_macros: set[str] = {"setter(into)"}
|
||||||
|
|
||||||
def get_sample(self):
|
def get_sample(self):
|
||||||
return "json!({})"
|
return "json!({})"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def imports(self):
|
def imports(self):
|
||||||
imports: set[str] = set(["serde_json::Value"])
|
imports: set[str] = {"serde_json::Value"}
|
||||||
return imports
|
return imports
|
||||||
|
|
||||||
|
|
||||||
@ -133,7 +133,7 @@ class Option(BaseCombinedType):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def builder_macros(self):
|
def builder_macros(self):
|
||||||
macros = set(["setter(into)"])
|
macros = {"setter(into)"}
|
||||||
wrapped_macros = self.item_type.builder_macros
|
wrapped_macros = self.item_type.builder_macros
|
||||||
if "private" in wrapped_macros:
|
if "private" in wrapped_macros:
|
||||||
macros = wrapped_macros
|
macros = wrapped_macros
|
||||||
@ -165,7 +165,7 @@ class Array(BaseCombinedType):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def builder_macros(self):
|
def builder_macros(self):
|
||||||
macros = set(["setter(into)"])
|
macros = {"setter(into)"}
|
||||||
return macros
|
return macros
|
||||||
|
|
||||||
def get_sample(self):
|
def get_sample(self):
|
||||||
@ -194,7 +194,7 @@ class CommaSeparatedList(BaseCombinedType):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def imports(self):
|
def imports(self):
|
||||||
imports: set[str] = set([])
|
imports: set[str] = set()
|
||||||
imports.update(self.item_type.imports)
|
imports.update(self.item_type.imports)
|
||||||
return imports
|
return imports
|
||||||
|
|
||||||
@ -205,7 +205,7 @@ class CommaSeparatedList(BaseCombinedType):
|
|||||||
|
|
||||||
class BTreeSet(BaseCombinedType):
|
class BTreeSet(BaseCombinedType):
|
||||||
item_type: BasePrimitiveType | BaseCombinedType | BaseCompoundType
|
item_type: BasePrimitiveType | BaseCombinedType | BaseCompoundType
|
||||||
builder_macros: set[str] = set(["setter(into)"])
|
builder_macros: set[str] = {"setter(into)"}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def type_hint(self):
|
def type_hint(self):
|
||||||
@ -253,11 +253,13 @@ class Struct(BaseCompoundType):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def type_hint(self):
|
def type_hint(self):
|
||||||
return self.name + (f"<{', '.join(self.lifetimes)}>" if self.lifetimes else "")
|
return self.name + (
|
||||||
|
f"<{', '.join(self.lifetimes)}>" if self.lifetimes else ""
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def imports(self):
|
def imports(self):
|
||||||
imports: set[str] = set([])
|
imports: set[str] = set()
|
||||||
field_types = [x.data_type for x in self.fields.values()]
|
field_types = [x.data_type for x in self.fields.values()]
|
||||||
if len(field_types) > 1 or (
|
if len(field_types) > 1 or (
|
||||||
len(field_types) == 1
|
len(field_types) == 1
|
||||||
@ -313,7 +315,9 @@ class Enum(BaseCompoundType):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def type_hint(self):
|
def type_hint(self):
|
||||||
return self.name + (f"<{', '.join(self.lifetimes)}>" if self.lifetimes else "")
|
return self.name + (
|
||||||
|
f"<{', '.join(self.lifetimes)}>" if self.lifetimes else ""
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def imports(self):
|
def imports(self):
|
||||||
@ -340,9 +344,11 @@ class Enum(BaseCompoundType):
|
|||||||
class StringEnum(BaseCompoundType):
|
class StringEnum(BaseCompoundType):
|
||||||
base_type: str = "enum"
|
base_type: str = "enum"
|
||||||
variants: dict[str, set[str]] = {}
|
variants: dict[str, set[str]] = {}
|
||||||
imports: set[str] = set(["serde::Deserialize", "serde::Serialize"])
|
imports: set[str] = {"serde::Deserialize", "serde::Serialize"}
|
||||||
lifetimes: set[str] = set()
|
lifetimes: set[str] = set()
|
||||||
derive_container_macros: str = "#[derive(Debug, Deserialize, Clone, Serialize)]"
|
derive_container_macros: str = (
|
||||||
|
"#[derive(Debug, Deserialize, Clone, Serialize)]"
|
||||||
|
)
|
||||||
builder_container_macros: str | None = None
|
builder_container_macros: str | None = None
|
||||||
serde_container_macros: str | None = None # "#[serde(untagged)]"
|
serde_container_macros: str | None = None # "#[serde(untagged)]"
|
||||||
serde_macros: set[str] | None = None
|
serde_macros: set[str] | None = None
|
||||||
@ -365,12 +371,12 @@ class StringEnum(BaseCompoundType):
|
|||||||
|
|
||||||
def get_sample(self):
|
def get_sample(self):
|
||||||
"""Generate sample data"""
|
"""Generate sample data"""
|
||||||
variant = list(sorted(self.variants.keys()))[0]
|
variant = sorted(self.variants.keys())[0]
|
||||||
return f"{self.name}::{variant}"
|
return f"{self.name}::{variant}"
|
||||||
|
|
||||||
def variant_serde_macros(self, variant: str):
|
def variant_serde_macros(self, variant: str):
|
||||||
"""Return serde macros"""
|
"""Return serde macros"""
|
||||||
macros = set([])
|
macros = set()
|
||||||
vals = self.variants[variant]
|
vals = self.variants[variant]
|
||||||
if len(vals) > 1:
|
if len(vals) > 1:
|
||||||
macros.add(f'rename(serialize = "{sorted(vals)[0]}")')
|
macros.add(f'rename(serialize = "{sorted(vals)[0]}")')
|
||||||
@ -484,7 +490,9 @@ class TypeManager:
|
|||||||
def get_local_attribute_name(self, name: str) -> str:
|
def get_local_attribute_name(self, name: str) -> str:
|
||||||
"""Get localized attribute name"""
|
"""Get localized attribute name"""
|
||||||
name = name.replace(".", "_")
|
name = name.replace(".", "_")
|
||||||
attr_name = "_".join(x.lower() for x in re.split(common.SPLIT_NAME_RE, name))
|
attr_name = "_".join(
|
||||||
|
x.lower() for x in re.split(common.SPLIT_NAME_RE, name)
|
||||||
|
)
|
||||||
if attr_name in ["type", "self", "enum", "ref", "default"]:
|
if attr_name in ["type", "self", "enum", "ref", "default"]:
|
||||||
attr_name = f"_{attr_name}"
|
attr_name = f"_{attr_name}"
|
||||||
return attr_name
|
return attr_name
|
||||||
@ -502,7 +510,8 @@ class TypeManager:
|
|||||||
if not model_ref:
|
if not model_ref:
|
||||||
return "Request"
|
return "Request"
|
||||||
name = "".join(
|
name = "".join(
|
||||||
x.capitalize() for x in re.split(common.SPLIT_NAME_RE, model_ref.name)
|
x.capitalize()
|
||||||
|
for x in re.split(common.SPLIT_NAME_RE, model_ref.name)
|
||||||
)
|
)
|
||||||
return name
|
return name
|
||||||
|
|
||||||
@ -510,15 +519,16 @@ class TypeManager:
|
|||||||
for model_ in self.models:
|
for model_ in self.models:
|
||||||
if model_.reference == model_ref:
|
if model_.reference == model_ref:
|
||||||
return model_
|
return model_
|
||||||
raise RuntimeError("Cannot find reference %s" % model_ref)
|
raise RuntimeError(f"Cannot find reference {model_ref}")
|
||||||
|
|
||||||
def convert_model(
|
def convert_model(
|
||||||
self,
|
self, type_model: model.PrimitiveType | model.ADT | model.Reference
|
||||||
type_model: model.PrimitiveType | model.ADT | model.Reference,
|
|
||||||
) -> BasePrimitiveType | BaseCombinedType | BaseCompoundType:
|
) -> BasePrimitiveType | BaseCombinedType | BaseCompoundType:
|
||||||
"""Get local destination type from the ModelType"""
|
"""Get local destination type from the ModelType"""
|
||||||
# logging.debug("Get RustSDK type for %s", type_model)
|
# logging.debug("Get RustSDK type for %s", type_model)
|
||||||
typ: BasePrimitiveType | BaseCombinedType | BaseCompoundType | None = None
|
typ: BasePrimitiveType | BaseCombinedType | BaseCompoundType | None = (
|
||||||
|
None
|
||||||
|
)
|
||||||
model_ref: model.Reference | None = None
|
model_ref: model.Reference | None = None
|
||||||
if isinstance(type_model, model.Reference):
|
if isinstance(type_model, model.Reference):
|
||||||
model_ref = type_model
|
model_ref = type_model
|
||||||
@ -530,7 +540,7 @@ class TypeManager:
|
|||||||
# Primitive
|
# Primitive
|
||||||
xtyp = self.primitive_type_mapping.get(type_model.__class__)
|
xtyp = self.primitive_type_mapping.get(type_model.__class__)
|
||||||
if not xtyp:
|
if not xtyp:
|
||||||
raise RuntimeError("No mapping for %s" % type_model)
|
raise RuntimeError(f"No mapping for {type_model}")
|
||||||
return xtyp(**type_model.model_dump())
|
return xtyp(**type_model.model_dump())
|
||||||
|
|
||||||
# Composite/Compound type
|
# Composite/Compound type
|
||||||
@ -573,11 +583,13 @@ class TypeManager:
|
|||||||
# TODO(gtema): make parent nullable or add "null"
|
# TODO(gtema): make parent nullable or add "null"
|
||||||
# as enum value
|
# as enum value
|
||||||
type_model.literals.remove(None)
|
type_model.literals.remove(None)
|
||||||
for lit in set(x.lower() for x in type_model.literals):
|
for lit in {x.lower() for x in type_model.literals}:
|
||||||
val = "".join(
|
val = "".join(
|
||||||
[
|
[
|
||||||
x.capitalize()
|
x.capitalize()
|
||||||
for x in re.split(common.SPLIT_NAME_RE, lit)
|
for x in re.split(
|
||||||
|
common.SPLIT_NAME_RE, lit
|
||||||
|
)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
if val and val[0].isdigit():
|
if val and val[0].isdigit():
|
||||||
@ -592,9 +604,13 @@ class TypeManager:
|
|||||||
variants=variants,
|
variants=variants,
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
logging.exception("Error processing enum: %s", type_model)
|
logging.exception(
|
||||||
|
"Error processing enum: %s", type_model
|
||||||
|
)
|
||||||
elif base_type is model.ConstraintInteger:
|
elif base_type is model.ConstraintInteger:
|
||||||
typ = self.primitive_type_mapping[model.ConstraintInteger]()
|
typ = self.primitive_type_mapping[
|
||||||
|
model.ConstraintInteger
|
||||||
|
]()
|
||||||
elif base_type is model.ConstraintNumber:
|
elif base_type is model.ConstraintNumber:
|
||||||
typ = self.primitive_type_mapping[model.ConstraintNumber]()
|
typ = self.primitive_type_mapping[model.ConstraintNumber]()
|
||||||
elif base_type is model.PrimitiveBoolean:
|
elif base_type is model.PrimitiveBoolean:
|
||||||
@ -602,8 +618,7 @@ class TypeManager:
|
|||||||
|
|
||||||
if not typ:
|
if not typ:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"Cannot map model type %s to Rust type [%s]"
|
f"Cannot map model type {type_model.__class__.__name__} to Rust type [{type_model}]"
|
||||||
% (type_model.__class__.__name__, type_model)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if not model_ref:
|
if not model_ref:
|
||||||
@ -673,7 +688,9 @@ class TypeManager:
|
|||||||
if item_type.__class__ == lt.item_type.__class__:
|
if item_type.__class__ == lt.item_type.__class__:
|
||||||
result_data_type = self.data_type_mapping[model.Array](
|
result_data_type = self.data_type_mapping[model.Array](
|
||||||
item_type=item_type,
|
item_type=item_type,
|
||||||
description=sanitize_rust_docstrings(type_model.description),
|
description=sanitize_rust_docstrings(
|
||||||
|
type_model.description
|
||||||
|
),
|
||||||
)
|
)
|
||||||
# logging.debug("Replacing Typ + list[Typ] with list[Typ]")
|
# logging.debug("Replacing Typ + list[Typ] with list[Typ]")
|
||||||
elif len(kinds) == 1:
|
elif len(kinds) == 1:
|
||||||
@ -702,7 +719,9 @@ class TypeManager:
|
|||||||
result_data_type.kinds[enum_kind.name] = enum_kind
|
result_data_type.kinds[enum_kind.name] = enum_kind
|
||||||
|
|
||||||
if is_nullable:
|
if is_nullable:
|
||||||
result_data_type = self.option_type_class(item_type=result_data_type)
|
result_data_type = self.option_type_class(
|
||||||
|
item_type=result_data_type
|
||||||
|
)
|
||||||
|
|
||||||
return result_data_type
|
return result_data_type
|
||||||
|
|
||||||
@ -761,18 +780,26 @@ class TypeManager:
|
|||||||
kinds.remove(typ)
|
kinds.remove(typ)
|
||||||
elif string_klass in kinds_classes and integer_klass in kinds_classes:
|
elif string_klass in kinds_classes and integer_klass in kinds_classes:
|
||||||
int_klass = next(
|
int_klass = next(
|
||||||
(x for x in type_model.kinds if isinstance(x, model.ConstraintInteger))
|
x
|
||||||
|
for x in type_model.kinds
|
||||||
|
if isinstance(x, model.ConstraintInteger)
|
||||||
)
|
)
|
||||||
if (
|
if (
|
||||||
# XX_size or XX_count is clearly an integer
|
# XX_size or XX_count is clearly an integer
|
||||||
(
|
(
|
||||||
enum_name
|
enum_name
|
||||||
and (enum_name.endswith("size") or enum_name.endswith("count"))
|
and (
|
||||||
|
enum_name.endswith("size")
|
||||||
|
or enum_name.endswith("count")
|
||||||
|
)
|
||||||
)
|
)
|
||||||
# There is certain limit (min/max) - it can be only integer
|
# There is certain limit (min/max) - it can be only integer
|
||||||
or (
|
or (
|
||||||
int_klass
|
int_klass
|
||||||
and (int_klass.minimum is not None or int_klass.maximum is not None)
|
and (
|
||||||
|
int_klass.minimum is not None
|
||||||
|
or int_klass.maximum is not None
|
||||||
|
)
|
||||||
)
|
)
|
||||||
):
|
):
|
||||||
for typ in list(kinds):
|
for typ in list(kinds):
|
||||||
@ -832,7 +859,8 @@ class TypeManager:
|
|||||||
# Try adding parent_name as prefix
|
# Try adding parent_name as prefix
|
||||||
new_name = (
|
new_name = (
|
||||||
"".join(
|
"".join(
|
||||||
x.title() for x in model_.reference.parent.name.split("_")
|
x.title()
|
||||||
|
for x in model_.reference.parent.name.split("_")
|
||||||
)
|
)
|
||||||
+ name
|
+ name
|
||||||
)
|
)
|
||||||
@ -851,7 +879,8 @@ class TypeManager:
|
|||||||
# Try adding parent_name as prefix
|
# Try adding parent_name as prefix
|
||||||
new_other_name = (
|
new_other_name = (
|
||||||
"".join(
|
"".join(
|
||||||
x.title() for x in other_model.parent.name.split("_")
|
x.title()
|
||||||
|
for x in other_model.parent.name.split("_")
|
||||||
)
|
)
|
||||||
+ name
|
+ name
|
||||||
)
|
)
|
||||||
@ -862,34 +891,37 @@ class TypeManager:
|
|||||||
# with remote being oneOf with multiple structs)
|
# with remote being oneOf with multiple structs)
|
||||||
# Try to make a name consisting of props
|
# Try to make a name consisting of props
|
||||||
props = model_data_type.fields.keys()
|
props = model_data_type.fields.keys()
|
||||||
new_new_name = name + "".join(x.title() for x in props).replace(
|
new_new_name = name + "".join(
|
||||||
"_", ""
|
x.title() for x in props
|
||||||
)
|
).replace("_", "")
|
||||||
if new_new_name not in unique_models:
|
if new_new_name not in unique_models:
|
||||||
for other_ref, other_model in self.refs.items():
|
for other_ref, other_model in self.refs.items():
|
||||||
other_name = getattr(other_model, "name", None)
|
other_name = getattr(other_model, "name", None)
|
||||||
if not other_name:
|
if not other_name:
|
||||||
continue
|
continue
|
||||||
if other_name in [
|
if other_name in [name, new_name] and isinstance(
|
||||||
name,
|
other_model, Struct
|
||||||
new_name,
|
):
|
||||||
] and isinstance(other_model, Struct):
|
|
||||||
# rename first occurence to the same scheme
|
# rename first occurence to the same scheme
|
||||||
props = other_model.fields.keys()
|
props = other_model.fields.keys()
|
||||||
new_other_name = name + "".join(
|
new_other_name = name + "".join(
|
||||||
x.title() for x in props
|
x.title() for x in props
|
||||||
).replace("_", "")
|
).replace("_", "")
|
||||||
other_model.name = new_other_name
|
other_model.name = new_other_name
|
||||||
unique_models[new_other_name] = model_.reference
|
unique_models[new_other_name] = (
|
||||||
|
model_.reference
|
||||||
|
)
|
||||||
|
|
||||||
model_data_type.name = new_new_name
|
model_data_type.name = new_new_name
|
||||||
unique_models[new_new_name] = model_.reference
|
unique_models[new_new_name] = model_.reference
|
||||||
else:
|
else:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"Model name %s is already present" % new_new_name
|
f"Model name {new_new_name} is already present"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise RuntimeError("Model name %s is already present" % new_name)
|
raise RuntimeError(
|
||||||
|
f"Model name {new_name} is already present"
|
||||||
|
)
|
||||||
elif (
|
elif (
|
||||||
name
|
name
|
||||||
and name in unique_models
|
and name in unique_models
|
||||||
@ -908,9 +940,17 @@ class TypeManager:
|
|||||||
def get_subtypes(self):
|
def get_subtypes(self):
|
||||||
"""Get all subtypes excluding TLA"""
|
"""Get all subtypes excluding TLA"""
|
||||||
for k, v in self.refs.items():
|
for k, v in self.refs.items():
|
||||||
if k and isinstance(v, (Enum, Struct, StringEnum)) and k.name != "Body":
|
if (
|
||||||
|
k
|
||||||
|
and isinstance(v, (Enum, Struct, StringEnum))
|
||||||
|
and k.name != "Body"
|
||||||
|
):
|
||||||
yield v
|
yield v
|
||||||
elif k and k.name != "Body" and isinstance(v, self.option_type_class):
|
elif (
|
||||||
|
k
|
||||||
|
and k.name != "Body"
|
||||||
|
and isinstance(v, self.option_type_class)
|
||||||
|
):
|
||||||
if isinstance(v.item_type, Enum):
|
if isinstance(v.item_type, Enum):
|
||||||
yield v.item_type
|
yield v.item_type
|
||||||
|
|
||||||
@ -922,7 +962,10 @@ class TypeManager:
|
|||||||
# There might be tuple Struct (with
|
# There might be tuple Struct (with
|
||||||
# fields as list)
|
# fields as list)
|
||||||
field_names = list(v.fields.keys())
|
field_names = list(v.fields.keys())
|
||||||
if len(field_names) == 1 and v.fields[field_names[0]].is_optional:
|
if (
|
||||||
|
len(field_names) == 1
|
||||||
|
and v.fields[field_names[0]].is_optional
|
||||||
|
):
|
||||||
# A body with only field can not normally be optional
|
# A body with only field can not normally be optional
|
||||||
logging.warning(
|
logging.warning(
|
||||||
"Request body with single root field cannot be optional"
|
"Request body with single root field cannot be optional"
|
||||||
@ -997,8 +1040,7 @@ class TypeManager:
|
|||||||
yield (k, v)
|
yield (k, v)
|
||||||
|
|
||||||
def discard_model(
|
def discard_model(
|
||||||
self,
|
self, type_model: model.PrimitiveType | model.ADT | model.Reference
|
||||||
type_model: model.PrimitiveType | model.ADT | model.Reference,
|
|
||||||
):
|
):
|
||||||
"""Discard model from the manager"""
|
"""Discard model from the manager"""
|
||||||
logging.debug(f"Request to discard {type_model}")
|
logging.debug(f"Request to discard {type_model}")
|
||||||
@ -1010,7 +1052,9 @@ class TypeManager:
|
|||||||
if ref == type_model.reference:
|
if ref == type_model.reference:
|
||||||
sub_ref: model.Reference | None = None
|
sub_ref: model.Reference | None = None
|
||||||
if ref.type == model.Struct:
|
if ref.type == model.Struct:
|
||||||
logging.debug("Element is a struct. Purging also field types")
|
logging.debug(
|
||||||
|
"Element is a struct. Purging also field types"
|
||||||
|
)
|
||||||
# For struct type we cascadely discard all field types as
|
# For struct type we cascadely discard all field types as
|
||||||
# well
|
# well
|
||||||
for v in type_model.fields.values():
|
for v in type_model.fields.values():
|
||||||
@ -1022,7 +1066,9 @@ class TypeManager:
|
|||||||
logging.debug(f"Need to purge also {sub_ref}")
|
logging.debug(f"Need to purge also {sub_ref}")
|
||||||
self.discard_model(sub_ref)
|
self.discard_model(sub_ref)
|
||||||
elif ref.type == model.OneOfType:
|
elif ref.type == model.OneOfType:
|
||||||
logging.debug("Element is a OneOf. Purging also kinds types")
|
logging.debug(
|
||||||
|
"Element is a OneOf. Purging also kinds types"
|
||||||
|
)
|
||||||
for v in type_model.kinds:
|
for v in type_model.kinds:
|
||||||
if isinstance(v, model.Reference):
|
if isinstance(v, model.Reference):
|
||||||
sub_ref = v
|
sub_ref = v
|
||||||
@ -1038,7 +1084,9 @@ class TypeManager:
|
|||||||
if isinstance(type_model.item_type, model.Reference):
|
if isinstance(type_model.item_type, model.Reference):
|
||||||
sub_ref = type_model.item_type
|
sub_ref = type_model.item_type
|
||||||
else:
|
else:
|
||||||
sub_ref = getattr(type_model.item_type, "reference", None)
|
sub_ref = getattr(
|
||||||
|
type_model.item_type, "reference", None
|
||||||
|
)
|
||||||
if sub_ref:
|
if sub_ref:
|
||||||
logging.debug(f"Need to purge also {sub_ref}")
|
logging.debug(f"Need to purge also {sub_ref}")
|
||||||
self.discard_model(sub_ref)
|
self.discard_model(sub_ref)
|
||||||
|
@ -35,7 +35,9 @@ class TypeSchema(BaseModel):
|
|||||||
ref: Optional[str] = Field(alias="$ref", default=None)
|
ref: Optional[str] = Field(alias="$ref", default=None)
|
||||||
oneOf: Optional[List[Any]] = Field(default=None)
|
oneOf: Optional[List[Any]] = Field(default=None)
|
||||||
anyOf: Optional[List[Any]] = Field(default=None)
|
anyOf: Optional[List[Any]] = Field(default=None)
|
||||||
openstack: Optional[Dict[str, Any]] = Field(alias="x-openstack", default=None)
|
openstack: Optional[Dict[str, Any]] = Field(
|
||||||
|
alias="x-openstack", default=None
|
||||||
|
)
|
||||||
required: Optional[List[str]] = None
|
required: Optional[List[str]] = None
|
||||||
pattern: Optional[str] = None
|
pattern: Optional[str] = None
|
||||||
maxLength: Optional[int] = None
|
maxLength: Optional[int] = None
|
||||||
@ -103,7 +105,7 @@ class OperationSchema(BaseModel):
|
|||||||
operationId: str | None = None
|
operationId: str | None = None
|
||||||
requestBody: dict = {}
|
requestBody: dict = {}
|
||||||
responses: Dict[str, dict] = {}
|
responses: Dict[str, dict] = {}
|
||||||
tags: List[str] = list()
|
tags: List[str] = []
|
||||||
deprecated: bool | None = None
|
deprecated: bool | None = None
|
||||||
openstack: dict = Field(alias="x-openstack", default={})
|
openstack: dict = Field(alias="x-openstack", default={})
|
||||||
security: List | None = None
|
security: List | None = None
|
||||||
@ -113,7 +115,9 @@ class HeaderSchema(BaseModel):
|
|||||||
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
||||||
|
|
||||||
description: Optional[str] = None
|
description: Optional[str] = None
|
||||||
openstack: Optional[Dict[str, Any]] = Field(alias="x-openstack", default=None)
|
openstack: Optional[Dict[str, Any]] = Field(
|
||||||
|
alias="x-openstack", default=None
|
||||||
|
)
|
||||||
schema: Optional[TypeSchema] = Field(default=None)
|
schema: Optional[TypeSchema] = Field(default=None)
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,7 +29,9 @@ class JsonSchemaGenerator(BaseGenerator):
|
|||||||
properties = {}
|
properties = {}
|
||||||
for k, v in res.attrs.items():
|
for k, v in res.attrs.items():
|
||||||
field = v["attr"]
|
field = v["attr"]
|
||||||
properties[field.name] = TypeSchema.from_sdk_field(field).model_dump(
|
properties[field.name] = TypeSchema.from_sdk_field(
|
||||||
|
field
|
||||||
|
).model_dump(
|
||||||
exclude_none=True, exclude_defaults=True, by_alias=True
|
exclude_none=True, exclude_defaults=True, by_alias=True
|
||||||
)
|
)
|
||||||
if "docs" in v:
|
if "docs" in v:
|
||||||
@ -54,7 +56,9 @@ class JsonSchemaGenerator(BaseGenerator):
|
|||||||
"properties": properties,
|
"properties": properties,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
schema = TypeSchema(type="object", properties=properties, description="")
|
schema = TypeSchema(
|
||||||
|
type="object", properties=properties, description=""
|
||||||
|
)
|
||||||
# if res.resource_class._store_unknown_attrs_as_properties:
|
# if res.resource_class._store_unknown_attrs_as_properties:
|
||||||
# schema_attrs["additionalProperties"] = True
|
# schema_attrs["additionalProperties"] = True
|
||||||
# schema_attrs["properties"] = properties
|
# schema_attrs["properties"] = properties
|
||||||
|
@ -25,16 +25,14 @@ from codegenerator.types import OperationModel
|
|||||||
from codegenerator.types import OperationTargetParams
|
from codegenerator.types import OperationTargetParams
|
||||||
from codegenerator.types import ResourceModel
|
from codegenerator.types import ResourceModel
|
||||||
|
|
||||||
OPERATION_ID_BLACKLIST: set[str] = set(
|
OPERATION_ID_BLACKLIST: set[str] = {
|
||||||
[
|
# # BlockStorage
|
||||||
# # BlockStorage
|
# ## Host put has no schema
|
||||||
# ## Host put has no schema
|
"project_id/os-hosts:put",
|
||||||
"project_id/os-hosts:put",
|
"os-hosts:put",
|
||||||
"os-hosts:put",
|
"project_id/os-hosts/id:put",
|
||||||
"project_id/os-hosts/id:put",
|
"os-hosts/id:put",
|
||||||
"os-hosts/id:put",
|
}
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class MetadataGenerator(BaseGenerator):
|
class MetadataGenerator(BaseGenerator):
|
||||||
@ -45,7 +43,7 @@ class MetadataGenerator(BaseGenerator):
|
|||||||
if not path.exists():
|
if not path.exists():
|
||||||
return
|
return
|
||||||
yaml = YAML(typ="safe")
|
yaml = YAML(typ="safe")
|
||||||
with open(path, "r") as fp:
|
with open(path) as fp:
|
||||||
spec = jsonref.replace_refs(yaml.load(fp))
|
spec = jsonref.replace_refs(yaml.load(fp))
|
||||||
|
|
||||||
return SpecSchema(**spec)
|
return SpecSchema(**spec)
|
||||||
@ -63,12 +61,12 @@ class MetadataGenerator(BaseGenerator):
|
|||||||
|
|
||||||
schema = self.load_openapi(spec_path)
|
schema = self.load_openapi(spec_path)
|
||||||
openapi_spec = common.get_openapi_spec(spec_path)
|
openapi_spec = common.get_openapi_spec(spec_path)
|
||||||
metadata = Metadata(resources=dict())
|
metadata = Metadata(resources={})
|
||||||
api_ver = "v" + schema.info["version"].split(".")[0]
|
api_ver = "v" + schema.info["version"].split(".")[0]
|
||||||
for path, spec in schema.paths.items():
|
for path, spec in schema.paths.items():
|
||||||
path_elements: list[str] = path.split("/")
|
path_elements: list[str] = path.split("/")
|
||||||
resource_name = "/".join(
|
resource_name = "/".join(
|
||||||
[x for x in common.get_resource_names_from_url(path)]
|
list(common.get_resource_names_from_url(path))
|
||||||
)
|
)
|
||||||
if args.service_type == "object-store":
|
if args.service_type == "object-store":
|
||||||
if path == "/v1/{account}":
|
if path == "/v1/{account}":
|
||||||
@ -117,7 +115,7 @@ class MetadataGenerator(BaseGenerator):
|
|||||||
ResourceModel(
|
ResourceModel(
|
||||||
api_version=api_ver,
|
api_version=api_ver,
|
||||||
spec_file=spec_path.as_posix(),
|
spec_file=spec_path.as_posix(),
|
||||||
operations=dict(),
|
operations={},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
for method in [
|
for method in [
|
||||||
@ -139,7 +137,7 @@ class MetadataGenerator(BaseGenerator):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
op_model = OperationModel(
|
op_model = OperationModel(
|
||||||
operation_id=operation.operationId, targets=dict()
|
operation_id=operation.operationId, targets={}
|
||||||
)
|
)
|
||||||
operation_key: str | None = None
|
operation_key: str | None = None
|
||||||
|
|
||||||
@ -170,7 +168,10 @@ class MetadataGenerator(BaseGenerator):
|
|||||||
operation_key = "create"
|
operation_key = "create"
|
||||||
elif method == "delete":
|
elif method == "delete":
|
||||||
operation_key = "delete"
|
operation_key = "delete"
|
||||||
elif path.endswith("/detail") and resource_name != "quota_set":
|
elif (
|
||||||
|
path.endswith("/detail")
|
||||||
|
and resource_name != "quota_set"
|
||||||
|
):
|
||||||
if method == "get":
|
if method == "get":
|
||||||
operation_key = "list_detailed"
|
operation_key = "list_detailed"
|
||||||
# elif path.endswith("/default"):
|
# elif path.endswith("/default"):
|
||||||
@ -335,7 +336,9 @@ class MetadataGenerator(BaseGenerator):
|
|||||||
elif method == "delete":
|
elif method == "delete":
|
||||||
operation_key = "delete"
|
operation_key = "delete"
|
||||||
if not operation_key:
|
if not operation_key:
|
||||||
logging.warn(f"Cannot identify op name for {path}:{method}")
|
logging.warn(
|
||||||
|
f"Cannot identify op name for {path}:{method}"
|
||||||
|
)
|
||||||
|
|
||||||
# Next hacks
|
# Next hacks
|
||||||
if args.service_type == "identity" and resource_name in [
|
if args.service_type == "identity" and resource_name in [
|
||||||
@ -415,28 +418,31 @@ class MetadataGenerator(BaseGenerator):
|
|||||||
body_schema = operation.requestBody["content"][
|
body_schema = operation.requestBody["content"][
|
||||||
"application/json"
|
"application/json"
|
||||||
]["schema"]
|
]["schema"]
|
||||||
bodies = body_schema.get("oneOf", [body_schema])
|
bodies = body_schema.get(
|
||||||
|
"oneOf", [body_schema]
|
||||||
|
)
|
||||||
if len(bodies) > 1:
|
if len(bodies) > 1:
|
||||||
discriminator = body_schema.get(
|
discriminator = body_schema.get(
|
||||||
"x-openstack", {}
|
"x-openstack", {}
|
||||||
).get("discriminator")
|
).get("discriminator")
|
||||||
if discriminator != "action":
|
if discriminator != "action":
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"Cannot generate metadata for %s since request body is not having action discriminator"
|
f"Cannot generate metadata for {path} since request body is not having action discriminator"
|
||||||
% path
|
|
||||||
)
|
)
|
||||||
for body in bodies:
|
for body in bodies:
|
||||||
action_name = body.get("x-openstack", {}).get(
|
action_name = body.get(
|
||||||
"action-name"
|
"x-openstack", {}
|
||||||
)
|
).get("action-name")
|
||||||
if not action_name:
|
if not action_name:
|
||||||
action_name = list(body["properties"].keys())[0]
|
action_name = list(
|
||||||
|
body["properties"].keys()
|
||||||
|
)[0]
|
||||||
# Hardcode fixes
|
# Hardcode fixes
|
||||||
if resource_name == "flavor" and action_name in [
|
if (
|
||||||
"update",
|
resource_name == "flavor"
|
||||||
"create",
|
and action_name
|
||||||
"delete",
|
in ["update", "create", "delete"]
|
||||||
]:
|
):
|
||||||
# Flavor update/create/delete
|
# Flavor update/create/delete
|
||||||
# operations are exposed ALSO as wsgi
|
# operations are exposed ALSO as wsgi
|
||||||
# actions. This is wrong and useless.
|
# actions. This is wrong and useless.
|
||||||
@ -453,26 +459,38 @@ class MetadataGenerator(BaseGenerator):
|
|||||||
common.SPLIT_NAME_RE, action_name
|
common.SPLIT_NAME_RE, action_name
|
||||||
)
|
)
|
||||||
).lower()
|
).lower()
|
||||||
rust_sdk_params = get_rust_sdk_operation_args(
|
rust_sdk_params = (
|
||||||
"action",
|
get_rust_sdk_operation_args(
|
||||||
operation_name=action_name,
|
"action",
|
||||||
module_name=get_module_name(action_name),
|
operation_name=action_name,
|
||||||
|
module_name=get_module_name(
|
||||||
|
action_name
|
||||||
|
),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
rust_cli_params = get_rust_cli_operation_args(
|
rust_cli_params = (
|
||||||
"action",
|
get_rust_cli_operation_args(
|
||||||
operation_name=action_name,
|
"action",
|
||||||
module_name=get_module_name(action_name),
|
operation_name=action_name,
|
||||||
resource_name=resource_name,
|
module_name=get_module_name(
|
||||||
|
action_name
|
||||||
|
),
|
||||||
|
resource_name=resource_name,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
op_model = OperationModel(
|
op_model = OperationModel(
|
||||||
operation_id=operation.operationId,
|
operation_id=operation.operationId,
|
||||||
targets=dict(),
|
targets={},
|
||||||
)
|
)
|
||||||
op_model.operation_type = "action"
|
op_model.operation_type = "action"
|
||||||
|
|
||||||
op_model.targets["rust-sdk"] = rust_sdk_params
|
op_model.targets["rust-sdk"] = (
|
||||||
op_model.targets["rust-cli"] = rust_cli_params
|
rust_sdk_params
|
||||||
|
)
|
||||||
|
op_model.targets["rust-cli"] = (
|
||||||
|
rust_cli_params
|
||||||
|
)
|
||||||
|
|
||||||
op_model = post_process_operation(
|
op_model = post_process_operation(
|
||||||
args.service_type,
|
args.service_type,
|
||||||
@ -481,17 +499,25 @@ class MetadataGenerator(BaseGenerator):
|
|||||||
op_model,
|
op_model,
|
||||||
)
|
)
|
||||||
|
|
||||||
resource_model.operations[operation_name] = op_model
|
resource_model.operations[
|
||||||
|
operation_name
|
||||||
|
] = op_model
|
||||||
|
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise RuntimeError("Cannot get bodies for %s" % path)
|
raise RuntimeError(
|
||||||
|
f"Cannot get bodies for {path}"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
if not operation_key:
|
if not operation_key:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
operation_type = get_operation_type_by_key(operation_key)
|
operation_type = get_operation_type_by_key(
|
||||||
|
operation_key
|
||||||
|
)
|
||||||
op_model.operation_type = operation_type
|
op_model.operation_type = operation_type
|
||||||
# NOTE: sdk gets operation_key and not operation_type
|
# NOTE: sdk gets operation_key and not operation_type
|
||||||
rust_sdk_params = get_rust_sdk_operation_args(operation_key)
|
rust_sdk_params = get_rust_sdk_operation_args(
|
||||||
|
operation_key
|
||||||
|
)
|
||||||
rust_cli_params = get_rust_cli_operation_args(
|
rust_cli_params = get_rust_cli_operation_args(
|
||||||
operation_key, resource_name=resource_name
|
operation_key, resource_name=resource_name
|
||||||
)
|
)
|
||||||
@ -523,16 +549,16 @@ class MetadataGenerator(BaseGenerator):
|
|||||||
list_op.targets.pop("rust-cli")
|
list_op.targets.pop("rust-cli")
|
||||||
|
|
||||||
# Prepare `find` operation data
|
# Prepare `find` operation data
|
||||||
if (list_op or list_detailed_op) and res_data.operations.get("show"):
|
if (list_op or list_detailed_op) and res_data.operations.get(
|
||||||
|
"show"
|
||||||
|
):
|
||||||
show_op = res_data.operations["show"]
|
show_op = res_data.operations["show"]
|
||||||
|
|
||||||
(path, _, spec) = common.find_openapi_operation(
|
(path, _, spec) = common.find_openapi_operation(
|
||||||
openapi_spec, show_op.operation_id
|
openapi_spec, show_op.operation_id
|
||||||
)
|
)
|
||||||
mod_path = common.get_rust_sdk_mod_path(
|
mod_path = common.get_rust_sdk_mod_path(
|
||||||
args.service_type,
|
args.service_type, res_data.api_version or "", path
|
||||||
res_data.api_version or "",
|
|
||||||
path,
|
|
||||||
)
|
)
|
||||||
response_schema = None
|
response_schema = None
|
||||||
for code, rspec in spec.get("responses", {}).items():
|
for code, rspec in spec.get("responses", {}).items():
|
||||||
@ -541,10 +567,7 @@ class MetadataGenerator(BaseGenerator):
|
|||||||
content = rspec.get("content", {})
|
content = rspec.get("content", {})
|
||||||
if "application/json" in content:
|
if "application/json" in content:
|
||||||
try:
|
try:
|
||||||
(
|
(response_schema, _) = common.find_resource_schema(
|
||||||
response_schema,
|
|
||||||
_,
|
|
||||||
) = common.find_resource_schema(
|
|
||||||
content["application/json"].get("schema", {}),
|
content["application/json"].get("schema", {}),
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
@ -582,7 +605,8 @@ class MetadataGenerator(BaseGenerator):
|
|||||||
name_field = fqan.split(".")[-1]
|
name_field = fqan.split(".")[-1]
|
||||||
name_filter_supported: bool = False
|
name_filter_supported: bool = False
|
||||||
if name_field in [
|
if name_field in [
|
||||||
x.get("name") for x in list(list_spec.get("parameters", []))
|
x.get("name")
|
||||||
|
for x in list(list_spec.get("parameters", []))
|
||||||
]:
|
]:
|
||||||
name_filter_supported = True
|
name_filter_supported = True
|
||||||
|
|
||||||
@ -766,7 +790,9 @@ def post_process_operation(
|
|||||||
return operation
|
return operation
|
||||||
|
|
||||||
|
|
||||||
def post_process_compute_operation(resource_name: str, operation_name: str, operation):
|
def post_process_compute_operation(
|
||||||
|
resource_name: str, operation_name: str, operation
|
||||||
|
):
|
||||||
if resource_name == "aggregate":
|
if resource_name == "aggregate":
|
||||||
if operation_name in ["set-metadata", "add-host", "remove-host"]:
|
if operation_name in ["set-metadata", "add-host", "remove-host"]:
|
||||||
operation.targets["rust-sdk"].response_key = "aggregate"
|
operation.targets["rust-sdk"].response_key = "aggregate"
|
||||||
@ -782,7 +808,9 @@ def post_process_compute_operation(resource_name: str, operation_name: str, oper
|
|||||||
operation.targets["rust-cli"].sdk_mod_name = "list"
|
operation.targets["rust-cli"].sdk_mod_name = "list"
|
||||||
operation.targets["rust-cli"].operation_name = "list"
|
operation.targets["rust-cli"].operation_name = "list"
|
||||||
operation.targets["rust-sdk"].response_key = "availabilityZoneInfo"
|
operation.targets["rust-sdk"].response_key = "availabilityZoneInfo"
|
||||||
operation.targets["rust-cli"].cli_full_command = "availability-zone list"
|
operation.targets[
|
||||||
|
"rust-cli"
|
||||||
|
].cli_full_command = "availability-zone list"
|
||||||
elif operation_name == "list_detailed":
|
elif operation_name == "list_detailed":
|
||||||
operation.operation_type = "list"
|
operation.operation_type = "list"
|
||||||
operation.targets["rust-sdk"].operation_name = "list_detail"
|
operation.targets["rust-sdk"].operation_name = "list_detail"
|
||||||
@ -877,7 +905,9 @@ def post_process_compute_operation(resource_name: str, operation_name: str, oper
|
|||||||
return operation
|
return operation
|
||||||
|
|
||||||
|
|
||||||
def post_process_identity_operation(resource_name: str, operation_name: str, operation):
|
def post_process_identity_operation(
|
||||||
|
resource_name: str, operation_name: str, operation
|
||||||
|
):
|
||||||
if resource_name == "role/imply":
|
if resource_name == "role/imply":
|
||||||
if operation_name == "list":
|
if operation_name == "list":
|
||||||
operation.targets["rust-cli"].response_key = "role_inference"
|
operation.targets["rust-cli"].response_key = "role_inference"
|
||||||
@ -934,7 +964,9 @@ def post_process_identity_operation(resource_name: str, operation_name: str, ope
|
|||||||
return operation
|
return operation
|
||||||
|
|
||||||
|
|
||||||
def post_process_image_operation(resource_name: str, operation_name: str, operation):
|
def post_process_image_operation(
|
||||||
|
resource_name: str, operation_name: str, operation
|
||||||
|
):
|
||||||
if resource_name.startswith("schema"):
|
if resource_name.startswith("schema"):
|
||||||
# Image schemas are a JSON operation
|
# Image schemas are a JSON operation
|
||||||
operation.targets["rust-cli"].operation_type = "json"
|
operation.targets["rust-cli"].operation_type = "json"
|
||||||
@ -944,16 +976,25 @@ def post_process_image_operation(resource_name: str, operation_name: str, operat
|
|||||||
elif resource_name == "metadef/namespace" and operation_name != "list":
|
elif resource_name == "metadef/namespace" and operation_name != "list":
|
||||||
operation.targets["rust-sdk"].response_key = "null"
|
operation.targets["rust-sdk"].response_key = "null"
|
||||||
operation.targets["rust-cli"].response_key = "null"
|
operation.targets["rust-cli"].response_key = "null"
|
||||||
elif resource_name == "metadef/namespace/property" and operation_name == "list":
|
elif (
|
||||||
|
resource_name == "metadef/namespace/property"
|
||||||
|
and operation_name == "list"
|
||||||
|
):
|
||||||
operation.targets["rust-cli"].operation_type = "list_from_struct"
|
operation.targets["rust-cli"].operation_type = "list_from_struct"
|
||||||
operation.targets["rust-cli"].response_key = "properties"
|
operation.targets["rust-cli"].response_key = "properties"
|
||||||
operation.targets["rust-sdk"].response_key = "properties"
|
operation.targets["rust-sdk"].response_key = "properties"
|
||||||
elif resource_name == "metadef/namespace/resource_type":
|
elif resource_name == "metadef/namespace/resource_type":
|
||||||
operation.targets["rust-cli"].response_key = "resource_type_associations"
|
operation.targets[
|
||||||
operation.targets["rust-sdk"].response_key = "resource_type_associations"
|
"rust-cli"
|
||||||
|
].response_key = "resource_type_associations"
|
||||||
|
operation.targets[
|
||||||
|
"rust-sdk"
|
||||||
|
].response_key = "resource_type_associations"
|
||||||
operation.targets["rust-cli"].cli_full_command = operation.targets[
|
operation.targets["rust-cli"].cli_full_command = operation.targets[
|
||||||
"rust-cli"
|
"rust-cli"
|
||||||
].cli_full_command.replace("resource-type", "resource-type-association")
|
].cli_full_command.replace(
|
||||||
|
"resource-type", "resource-type-association"
|
||||||
|
)
|
||||||
elif resource_name == "image":
|
elif resource_name == "image":
|
||||||
if operation_name == "patch":
|
if operation_name == "patch":
|
||||||
operation.targets["rust-cli"].cli_full_command = operation.targets[
|
operation.targets["rust-cli"].cli_full_command = operation.targets[
|
||||||
@ -1010,7 +1051,9 @@ def post_process_block_storage_operation(
|
|||||||
if "update-snapshot-status" in operation_name:
|
if "update-snapshot-status" in operation_name:
|
||||||
operation.targets["rust-cli"].cli_full_command = operation.targets[
|
operation.targets["rust-cli"].cli_full_command = operation.targets[
|
||||||
"rust-cli"
|
"rust-cli"
|
||||||
].cli_full_command.replace("update-snapshot-status", "update-status")
|
].cli_full_command.replace(
|
||||||
|
"update-snapshot-status", "update-status"
|
||||||
|
)
|
||||||
|
|
||||||
if resource_name in ["os_volume_transfer", "volume_transfer"]:
|
if resource_name in ["os_volume_transfer", "volume_transfer"]:
|
||||||
if operation_name in ["list", "list_detailed"]:
|
if operation_name in ["list", "list_detailed"]:
|
||||||
@ -1030,7 +1073,9 @@ def post_process_block_storage_operation(
|
|||||||
operation.targets["rust-cli"].sdk_mod_name = "list"
|
operation.targets["rust-cli"].sdk_mod_name = "list"
|
||||||
operation.targets["rust-cli"].operation_name = "list"
|
operation.targets["rust-cli"].operation_name = "list"
|
||||||
operation.targets["rust-sdk"].response_key = "availabilityZoneInfo"
|
operation.targets["rust-sdk"].response_key = "availabilityZoneInfo"
|
||||||
operation.targets["rust-cli"].cli_full_command = "availability-zone list"
|
operation.targets[
|
||||||
|
"rust-cli"
|
||||||
|
].cli_full_command = "availability-zone list"
|
||||||
if resource_name == "qos_spec/association":
|
if resource_name == "qos_spec/association":
|
||||||
operation.operation_type = "list"
|
operation.operation_type = "list"
|
||||||
operation.targets["rust-sdk"].operation_name = "list"
|
operation.targets["rust-sdk"].operation_name = "list"
|
||||||
@ -1040,7 +1085,9 @@ def post_process_block_storage_operation(
|
|||||||
operation.targets["rust-cli"].sdk_mod_name = "list"
|
operation.targets["rust-cli"].sdk_mod_name = "list"
|
||||||
operation.targets["rust-sdk"].response_key = "qos_associations"
|
operation.targets["rust-sdk"].response_key = "qos_associations"
|
||||||
operation.targets["rust-cli"].response_key = "qos_associations"
|
operation.targets["rust-cli"].response_key = "qos_associations"
|
||||||
operation.targets["rust-cli"].cli_full_command = "qos-spec association list"
|
operation.targets[
|
||||||
|
"rust-cli"
|
||||||
|
].cli_full_command = "qos-spec association list"
|
||||||
|
|
||||||
if resource_name == "limit" and operation_name == "list":
|
if resource_name == "limit" and operation_name == "list":
|
||||||
# Limits API return object and not a list
|
# Limits API return object and not a list
|
||||||
@ -1054,7 +1101,9 @@ def post_process_block_storage_operation(
|
|||||||
return operation
|
return operation
|
||||||
|
|
||||||
|
|
||||||
def post_process_network_operation(resource_name: str, operation_name: str, operation):
|
def post_process_network_operation(
|
||||||
|
resource_name: str, operation_name: str, operation
|
||||||
|
):
|
||||||
if resource_name.startswith("floatingip"):
|
if resource_name.startswith("floatingip"):
|
||||||
operation.targets["rust-cli"].cli_full_command = operation.targets[
|
operation.targets["rust-cli"].cli_full_command = operation.targets[
|
||||||
"rust-cli"
|
"rust-cli"
|
||||||
|
@ -42,7 +42,7 @@ class Reference(BaseModel):
|
|||||||
|
|
||||||
#: Name of the object that uses the type under reference
|
#: Name of the object that uses the type under reference
|
||||||
name: str
|
name: str
|
||||||
type: Type | None = None
|
type: Any = None
|
||||||
hash_: str | None = None
|
hash_: str | None = None
|
||||||
parent: Reference | None = None
|
parent: Reference | None = None
|
||||||
|
|
||||||
@ -131,7 +131,7 @@ class OneOfType(ADT):
|
|||||||
class Enum(AbstractCollection):
|
class Enum(AbstractCollection):
|
||||||
"""Enum: a unique collection of primitives"""
|
"""Enum: a unique collection of primitives"""
|
||||||
|
|
||||||
base_types: list[Type[PrimitiveType]] = []
|
base_types: list[type[PrimitiveType]] = []
|
||||||
literals: set[Any] = set()
|
literals: set[Any] = set()
|
||||||
|
|
||||||
|
|
||||||
@ -182,10 +182,12 @@ class JsonSchemaParser:
|
|||||||
|
|
||||||
def parse(
|
def parse(
|
||||||
self, schema, ignore_read_only: bool = False
|
self, schema, ignore_read_only: bool = False
|
||||||
) -> ty.Tuple[ADT | None, list[ADT]]:
|
) -> tuple[ADT | None, list[ADT]]:
|
||||||
"""Parse JsonSchema object into internal DataModel"""
|
"""Parse JsonSchema object into internal DataModel"""
|
||||||
results: list[ADT] = []
|
results: list[ADT] = []
|
||||||
res = self.parse_schema(schema, results, ignore_read_only=ignore_read_only)
|
res = self.parse_schema(
|
||||||
|
schema, results, ignore_read_only=ignore_read_only
|
||||||
|
)
|
||||||
return (res, results)
|
return (res, results)
|
||||||
|
|
||||||
def parse_schema(
|
def parse_schema(
|
||||||
@ -353,9 +355,7 @@ class JsonSchemaParser:
|
|||||||
if ref:
|
if ref:
|
||||||
field = StructField(data_type=ref)
|
field = StructField(data_type=ref)
|
||||||
else:
|
else:
|
||||||
field = StructField(
|
field = StructField(data_type=data_type)
|
||||||
data_type=data_type,
|
|
||||||
)
|
|
||||||
|
|
||||||
field.description = v.get("description")
|
field.description = v.get("description")
|
||||||
if k in required:
|
if k in required:
|
||||||
@ -407,7 +407,9 @@ class JsonSchemaParser:
|
|||||||
if pattern_props and not additional_properties_type:
|
if pattern_props and not additional_properties_type:
|
||||||
# `"type": "object", "pattern_properties": ...`
|
# `"type": "object", "pattern_properties": ...`
|
||||||
if len(list(pattern_props.values())) == 1:
|
if len(list(pattern_props.values())) == 1:
|
||||||
obj = Dictionary(value_type=list(pattern_props.values())[0])
|
obj = Dictionary(
|
||||||
|
value_type=list(pattern_props.values())[0]
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
obj = Struct(pattern_properties=pattern_props)
|
obj = Struct(pattern_properties=pattern_props)
|
||||||
elif not pattern_props and additional_properties_type:
|
elif not pattern_props and additional_properties_type:
|
||||||
@ -448,9 +450,15 @@ class JsonSchemaParser:
|
|||||||
|
|
||||||
if obj:
|
if obj:
|
||||||
obj.description = schema.get("description")
|
obj.description = schema.get("description")
|
||||||
if obj.reference and f"{obj.reference.name}{obj.reference.type}" in [
|
if (
|
||||||
f"{x.reference.name}{x.reference.type}" for x in results if x.reference
|
obj.reference
|
||||||
]:
|
and f"{obj.reference.name}{obj.reference.type}"
|
||||||
|
in [
|
||||||
|
f"{x.reference.name}{x.reference.type}"
|
||||||
|
for x in results
|
||||||
|
if x.reference
|
||||||
|
]
|
||||||
|
):
|
||||||
if obj.reference.__hash__() in [
|
if obj.reference.__hash__() in [
|
||||||
x.reference.__hash__() for x in results if x.reference
|
x.reference.__hash__() for x in results if x.reference
|
||||||
]:
|
]:
|
||||||
@ -466,9 +474,9 @@ class JsonSchemaParser:
|
|||||||
if parent and name:
|
if parent and name:
|
||||||
new_name = parent.name + "_" + name
|
new_name = parent.name + "_" + name
|
||||||
|
|
||||||
if Reference(name=new_name, type=obj.reference.type) in [
|
if Reference(
|
||||||
x.reference for x in results
|
name=new_name, type=obj.reference.type
|
||||||
]:
|
) in [x.reference for x in results]:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
else:
|
else:
|
||||||
obj.reference.name = new_name
|
obj.reference.name = new_name
|
||||||
@ -523,10 +531,7 @@ class JsonSchemaParser:
|
|||||||
# Bad schema with type being a list of 1 entry
|
# Bad schema with type being a list of 1 entry
|
||||||
schema["type"] = schema["type"][0]
|
schema["type"] = schema["type"][0]
|
||||||
obj = self.parse_schema(
|
obj = self.parse_schema(
|
||||||
schema,
|
schema, results, name=name, ignore_read_only=ignore_read_only
|
||||||
results,
|
|
||||||
name=name,
|
|
||||||
ignore_read_only=ignore_read_only,
|
|
||||||
)
|
)
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
@ -598,7 +603,7 @@ class JsonSchemaParser:
|
|||||||
# todo: decide whether some constraints can be under items
|
# todo: decide whether some constraints can be under items
|
||||||
literals = schema.get("enum")
|
literals = schema.get("enum")
|
||||||
obj = Enum(literals=literals, base_types=[])
|
obj = Enum(literals=literals, base_types=[])
|
||||||
literal_types = set([type(x) for x in literals])
|
literal_types = {type(x) for x in literals}
|
||||||
for literal_type in literal_types:
|
for literal_type in literal_types:
|
||||||
if literal_type is str:
|
if literal_type is str:
|
||||||
obj.base_types.append(ConstraintString)
|
obj.base_types.append(ConstraintString)
|
||||||
@ -699,24 +704,24 @@ class OpenAPISchemaParser(JsonSchemaParser):
|
|||||||
dt = Set(item_type=ConstraintString())
|
dt = Set(item_type=ConstraintString())
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
"Parameter serialization %s not supported" % schema
|
f"Parameter serialization {schema} not supported"
|
||||||
)
|
)
|
||||||
|
|
||||||
elif isinstance(param_typ, list):
|
elif isinstance(param_typ, list):
|
||||||
# Param type can be anything. Process supported combinations first
|
# Param type can be anything. Process supported combinations first
|
||||||
if param_location == "query" and param_name == "limit":
|
if param_location == "query" and param_name == "limit":
|
||||||
dt = ConstraintInteger(minimum=0)
|
dt = ConstraintInteger(minimum=0)
|
||||||
elif param_location == "query" and sorted(["string", "boolean"]) == sorted(
|
elif param_location == "query" and sorted(
|
||||||
param_typ
|
["string", "boolean"]
|
||||||
):
|
) == sorted(param_typ):
|
||||||
dt = PrimitiveBoolean()
|
dt = PrimitiveBoolean()
|
||||||
elif param_location == "query" and sorted(["string", "integer"]) == sorted(
|
elif param_location == "query" and sorted(
|
||||||
param_typ
|
["string", "integer"]
|
||||||
):
|
) == sorted(param_typ):
|
||||||
dt = ConstraintInteger(**param_schema)
|
dt = ConstraintInteger(**param_schema)
|
||||||
elif param_location == "query" and sorted(["string", "number"]) == sorted(
|
elif param_location == "query" and sorted(
|
||||||
param_typ
|
["string", "number"]
|
||||||
):
|
) == sorted(param_typ):
|
||||||
dt = ConstraintNumber(**param_schema)
|
dt = ConstraintNumber(**param_schema)
|
||||||
|
|
||||||
if isinstance(dt, ADT):
|
if isinstance(dt, ADT):
|
||||||
@ -728,7 +733,9 @@ class OpenAPISchemaParser(JsonSchemaParser):
|
|||||||
is_flag: bool = False
|
is_flag: bool = False
|
||||||
os_ext = schema.get("x-openstack", {})
|
os_ext = schema.get("x-openstack", {})
|
||||||
if not isinstance(os_ext, dict):
|
if not isinstance(os_ext, dict):
|
||||||
raise RuntimeError(f"x-openstack must be a dictionary inside {schema}")
|
raise RuntimeError(
|
||||||
|
f"x-openstack must be a dictionary inside {schema}"
|
||||||
|
)
|
||||||
if "is-flag" in os_ext:
|
if "is-flag" in os_ext:
|
||||||
is_flag = os_ext["is-flag"]
|
is_flag = os_ext["is-flag"]
|
||||||
|
|
||||||
@ -742,6 +749,6 @@ class OpenAPISchemaParser(JsonSchemaParser):
|
|||||||
is_flag=is_flag,
|
is_flag=is_flag,
|
||||||
resource_link=os_ext.get("resource_link", None),
|
resource_link=os_ext.get("resource_link", None),
|
||||||
)
|
)
|
||||||
raise NotImplementedError("Parameter %s is not covered yet" % schema)
|
raise NotImplementedError(f"Parameter {schema} is not covered yet")
|
||||||
|
|
||||||
raise RuntimeError("Parameter %s is not supported yet" % schema)
|
raise RuntimeError(f"Parameter {schema} is not supported yet")
|
||||||
|
@ -111,7 +111,7 @@ class OpenStackServerSourceBase:
|
|||||||
return
|
return
|
||||||
yaml = YAML(typ="safe")
|
yaml = YAML(typ="safe")
|
||||||
yaml.preserve_quotes = True
|
yaml.preserve_quotes = True
|
||||||
with open(path, "r") as fp:
|
with open(path) as fp:
|
||||||
spec = yaml.load(fp)
|
spec = yaml.load(fp)
|
||||||
|
|
||||||
return SpecSchema(**spec)
|
return SpecSchema(**spec)
|
||||||
@ -150,7 +150,9 @@ class OpenStackServerSourceBase:
|
|||||||
if os_ext == {}:
|
if os_ext == {}:
|
||||||
v.openstack = None
|
v.openstack = None
|
||||||
|
|
||||||
def _process_route(self, route, openapi_spec, ver_prefix=None, framework=None):
|
def _process_route(
|
||||||
|
self, route, openapi_spec, ver_prefix=None, framework=None
|
||||||
|
):
|
||||||
# Placement exposes "action" as controller in route defaults, all others - "controller"
|
# Placement exposes "action" as controller in route defaults, all others - "controller"
|
||||||
if not ("controller" in route.defaults or "action" in route.defaults):
|
if not ("controller" in route.defaults or "action" in route.defaults):
|
||||||
return
|
return
|
||||||
@ -174,11 +176,17 @@ class OpenStackServerSourceBase:
|
|||||||
|
|
||||||
# if "method" not in route.conditions:
|
# if "method" not in route.conditions:
|
||||||
# raise RuntimeError("Method not set for %s", route)
|
# raise RuntimeError("Method not set for %s", route)
|
||||||
method = route.conditions.get("method", "GET")[0] if route.conditions else "GET"
|
method = (
|
||||||
|
route.conditions.get("method", "GET")[0]
|
||||||
|
if route.conditions
|
||||||
|
else "GET"
|
||||||
|
)
|
||||||
|
|
||||||
controller = route.defaults.get("controller")
|
controller = route.defaults.get("controller")
|
||||||
action = route.defaults.get("action")
|
action = route.defaults.get("action")
|
||||||
logging.info("Path: %s; method: %s; operation: %s", path, method, action)
|
logging.info(
|
||||||
|
"Path: %s; method: %s; operation: %s", path, method, action
|
||||||
|
)
|
||||||
|
|
||||||
versioned_methods = {}
|
versioned_methods = {}
|
||||||
controller_actions = {}
|
controller_actions = {}
|
||||||
@ -208,7 +216,7 @@ class OpenStackServerSourceBase:
|
|||||||
contr = action
|
contr = action
|
||||||
action = None
|
action = None
|
||||||
else:
|
else:
|
||||||
raise RuntimeError("Unsupported controller %s" % controller)
|
raise RuntimeError(f"Unsupported controller {controller}")
|
||||||
# logging.debug("Actions: %s, Versioned methods: %s", actions, versioned_methods)
|
# logging.debug("Actions: %s, Versioned methods: %s", actions, versioned_methods)
|
||||||
|
|
||||||
# path_spec = openapi_spec.paths.setdefault(path, PathSchema())
|
# path_spec = openapi_spec.paths.setdefault(path, PathSchema())
|
||||||
@ -231,7 +239,9 @@ class OpenStackServerSourceBase:
|
|||||||
for path_element in path_elements:
|
for path_element in path_elements:
|
||||||
if "{" in path_element:
|
if "{" in path_element:
|
||||||
param_name = path_element.strip("{}")
|
param_name = path_element.strip("{}")
|
||||||
global_param_name = "_".join(path_resource_names) + f"_{param_name}"
|
global_param_name = (
|
||||||
|
"_".join(path_resource_names) + f"_{param_name}"
|
||||||
|
)
|
||||||
|
|
||||||
param_ref_name = self._get_param_ref(
|
param_ref_name = self._get_param_ref(
|
||||||
openapi_spec,
|
openapi_spec,
|
||||||
@ -241,7 +251,7 @@ class OpenStackServerSourceBase:
|
|||||||
path=path,
|
path=path,
|
||||||
)
|
)
|
||||||
# Ensure reference to the param is in the path_params
|
# Ensure reference to the param is in the path_params
|
||||||
if param_ref_name not in [k.ref for k in [p for p in path_params]]:
|
if param_ref_name not in [k.ref for k in list(path_params)]:
|
||||||
path_params.append(ParameterSchema(ref=param_ref_name))
|
path_params.append(ParameterSchema(ref=param_ref_name))
|
||||||
# Cleanup path_resource_names
|
# Cleanup path_resource_names
|
||||||
# if len(path_resource_names) > 0 and VERSION_RE.match(path_resource_names[0]):
|
# if len(path_resource_names) > 0 and VERSION_RE.match(path_resource_names[0]):
|
||||||
@ -263,7 +273,8 @@ class OpenStackServerSourceBase:
|
|||||||
operation_id = re.sub(
|
operation_id = re.sub(
|
||||||
r"^(/?v[0-9.]*/)",
|
r"^(/?v[0-9.]*/)",
|
||||||
"",
|
"",
|
||||||
"/".join([x.strip("{}") for x in path_elements]) + f":{method.lower()}", # noqa
|
"/".join([x.strip("{}") for x in path_elements])
|
||||||
|
+ f":{method.lower()}", # noqa
|
||||||
)
|
)
|
||||||
|
|
||||||
if action in versioned_methods:
|
if action in versioned_methods:
|
||||||
@ -363,7 +374,9 @@ class OpenStackServerSourceBase:
|
|||||||
for action, op_name in controller_actions.items():
|
for action, op_name in controller_actions.items():
|
||||||
logging.info("Action %s: %s", action, op_name)
|
logging.info("Action %s: %s", action, op_name)
|
||||||
(start_version, end_version) = (None, None)
|
(start_version, end_version) = (None, None)
|
||||||
action_impls: list[tuple[Callable, str | None, str | None]] = []
|
action_impls: list[
|
||||||
|
tuple[Callable, str | None, str | None]
|
||||||
|
] = []
|
||||||
if isinstance(op_name, str):
|
if isinstance(op_name, str):
|
||||||
# wsgi action value is a string
|
# wsgi action value is a string
|
||||||
if op_name in versioned_methods:
|
if op_name in versioned_methods:
|
||||||
@ -376,7 +389,9 @@ class OpenStackServerSourceBase:
|
|||||||
ver_method.end_version,
|
ver_method.end_version,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
logging.info("Versioned action %s", ver_method.func)
|
logging.info(
|
||||||
|
"Versioned action %s", ver_method.func
|
||||||
|
)
|
||||||
elif hasattr(contr, op_name):
|
elif hasattr(contr, op_name):
|
||||||
# ACTION with no version bounds
|
# ACTION with no version bounds
|
||||||
func = getattr(contr, op_name)
|
func = getattr(contr, op_name)
|
||||||
@ -413,7 +428,9 @@ class OpenStackServerSourceBase:
|
|||||||
ver_method.end_version,
|
ver_method.end_version,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
logging.info("Versioned action %s", ver_method.func)
|
logging.info(
|
||||||
|
"Versioned action %s", ver_method.func
|
||||||
|
)
|
||||||
elif slf and key:
|
elif slf and key:
|
||||||
vm = getattr(slf, "versioned_methods", None)
|
vm = getattr(slf, "versioned_methods", None)
|
||||||
if vm and key in vm:
|
if vm and key in vm:
|
||||||
@ -431,7 +448,9 @@ class OpenStackServerSourceBase:
|
|||||||
ver_method.end_version,
|
ver_method.end_version,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
logging.info("Versioned action %s", ver_method.func)
|
logging.info(
|
||||||
|
"Versioned action %s", ver_method.func
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
action_impls.append((op_name, None, None))
|
action_impls.append((op_name, None, None))
|
||||||
|
|
||||||
@ -534,10 +553,7 @@ class OpenStackServerSourceBase:
|
|||||||
path: str | None = None,
|
path: str | None = None,
|
||||||
):
|
):
|
||||||
logging.info(
|
logging.info(
|
||||||
"%s: %s [%s]",
|
"%s: %s [%s]", (mode or "operation").title(), operation_name, func
|
||||||
(mode or "operation").title(),
|
|
||||||
operation_name,
|
|
||||||
func,
|
|
||||||
)
|
)
|
||||||
# New decorators start having explicit null ApiVersion instead of being null
|
# New decorators start having explicit null ApiVersion instead of being null
|
||||||
if (
|
if (
|
||||||
@ -574,7 +590,9 @@ class OpenStackServerSourceBase:
|
|||||||
if operation_spec.description:
|
if operation_spec.description:
|
||||||
# Reading spec from yaml file it was converted back to regular
|
# Reading spec from yaml file it was converted back to regular
|
||||||
# string. Therefore need to force it back to Literal block.
|
# string. Therefore need to force it back to Literal block.
|
||||||
operation_spec.description = LiteralScalarString(operation_spec.description)
|
operation_spec.description = LiteralScalarString(
|
||||||
|
operation_spec.description
|
||||||
|
)
|
||||||
|
|
||||||
action_name = None
|
action_name = None
|
||||||
query_params_versions = []
|
query_params_versions = []
|
||||||
@ -591,13 +609,22 @@ class OpenStackServerSourceBase:
|
|||||||
if not (
|
if not (
|
||||||
"min-ver" in operation_spec.openstack
|
"min-ver" in operation_spec.openstack
|
||||||
and tuple(
|
and tuple(
|
||||||
[int(x) for x in operation_spec.openstack["min-ver"].split(".")]
|
[
|
||||||
|
int(x)
|
||||||
|
for x in operation_spec.openstack["min-ver"].split(".")
|
||||||
|
]
|
||||||
)
|
)
|
||||||
< (self._api_ver(start_version))
|
< (self._api_ver(start_version))
|
||||||
):
|
):
|
||||||
operation_spec.openstack["min-ver"] = start_version.get_string()
|
operation_spec.openstack["min-ver"] = (
|
||||||
|
start_version.get_string()
|
||||||
|
)
|
||||||
|
|
||||||
if mode != "action" and end_version and self._api_ver_major(end_version):
|
if (
|
||||||
|
mode != "action"
|
||||||
|
and end_version
|
||||||
|
and self._api_ver_major(end_version)
|
||||||
|
):
|
||||||
if self._api_ver_major(end_version) == 0:
|
if self._api_ver_major(end_version) == 0:
|
||||||
operation_spec.openstack.pop("max-ver", None)
|
operation_spec.openstack.pop("max-ver", None)
|
||||||
operation_spec.deprecated = None
|
operation_spec.deprecated = None
|
||||||
@ -609,11 +636,18 @@ class OpenStackServerSourceBase:
|
|||||||
if not (
|
if not (
|
||||||
"max-ver" in operation_spec.openstack
|
"max-ver" in operation_spec.openstack
|
||||||
and tuple(
|
and tuple(
|
||||||
[int(x) for x in operation_spec.openstack["max-ver"].split(".")]
|
[
|
||||||
|
int(x)
|
||||||
|
for x in operation_spec.openstack["max-ver"].split(
|
||||||
|
"."
|
||||||
|
)
|
||||||
|
]
|
||||||
)
|
)
|
||||||
> self._api_ver(end_version)
|
> self._api_ver(end_version)
|
||||||
):
|
):
|
||||||
operation_spec.openstack["max-ver"] = end_version.get_string()
|
operation_spec.openstack["max-ver"] = (
|
||||||
|
end_version.get_string()
|
||||||
|
)
|
||||||
|
|
||||||
action_name = getattr(func, "wsgi_action", None)
|
action_name = getattr(func, "wsgi_action", None)
|
||||||
if action_name:
|
if action_name:
|
||||||
@ -669,7 +703,9 @@ class OpenStackServerSourceBase:
|
|||||||
if query_params_versions:
|
if query_params_versions:
|
||||||
so = sorted(
|
so = sorted(
|
||||||
query_params_versions,
|
query_params_versions,
|
||||||
key=lambda d: (tuple(map(int, d[1].split("."))) if d[1] else (0, 0)),
|
key=lambda d: (
|
||||||
|
tuple(map(int, d[1].split("."))) if d[1] else (0, 0)
|
||||||
|
),
|
||||||
)
|
)
|
||||||
for data, min_ver, max_ver in so:
|
for data, min_ver, max_ver in so:
|
||||||
self.process_query_parameters(
|
self.process_query_parameters(
|
||||||
@ -695,7 +731,7 @@ class OpenStackServerSourceBase:
|
|||||||
response_body_schema = ser_schema
|
response_body_schema = ser_schema
|
||||||
responses_spec = operation_spec.responses
|
responses_spec = operation_spec.responses
|
||||||
for error in expected_errors:
|
for error in expected_errors:
|
||||||
responses_spec.setdefault(str(error), dict(description="Error"))
|
responses_spec.setdefault(str(error), {"description": "Error"})
|
||||||
|
|
||||||
if mode != "action" and str(error) == "410":
|
if mode != "action" and str(error) == "410":
|
||||||
# This looks like a deprecated operation still hanging out there
|
# This looks like a deprecated operation still hanging out there
|
||||||
@ -721,7 +757,7 @@ class OpenStackServerSourceBase:
|
|||||||
if response_codes:
|
if response_codes:
|
||||||
for response_code in response_codes:
|
for response_code in response_codes:
|
||||||
rsp = responses_spec.setdefault(
|
rsp = responses_spec.setdefault(
|
||||||
str(response_code), dict(description="Ok")
|
str(response_code), {"description": "Ok"}
|
||||||
)
|
)
|
||||||
if str(response_code) != "204" and method != "DELETE":
|
if str(response_code) != "204" and method != "DELETE":
|
||||||
# Arrange response placeholder
|
# Arrange response placeholder
|
||||||
@ -729,7 +765,9 @@ class OpenStackServerSourceBase:
|
|||||||
"".join([x.title() for x in path_resource_names])
|
"".join([x.title() for x in path_resource_names])
|
||||||
+ (
|
+ (
|
||||||
operation_name.replace("index", "list").title()
|
operation_name.replace("index", "list").title()
|
||||||
if not path_resource_names[-1].endswith(operation_name)
|
if not path_resource_names[-1].endswith(
|
||||||
|
operation_name
|
||||||
|
)
|
||||||
else ""
|
else ""
|
||||||
)
|
)
|
||||||
+ "Response"
|
+ "Response"
|
||||||
@ -762,20 +800,24 @@ class OpenStackServerSourceBase:
|
|||||||
curr_oneOf = curr_schema.oneOf
|
curr_oneOf = curr_schema.oneOf
|
||||||
curr_ref = curr_schema.ref
|
curr_ref = curr_schema.ref
|
||||||
if curr_oneOf:
|
if curr_oneOf:
|
||||||
if schema_ref not in [x["$ref"] for x in curr_oneOf]:
|
if schema_ref not in [
|
||||||
|
x["$ref"] for x in curr_oneOf
|
||||||
|
]:
|
||||||
curr_oneOf.append({"$ref": schema_ref})
|
curr_oneOf.append({"$ref": schema_ref})
|
||||||
elif curr_ref and curr_ref != schema_ref:
|
elif curr_ref and curr_ref != schema_ref:
|
||||||
rsp["content"]["application/json"]["schema"] = (
|
rsp["content"]["application/json"][
|
||||||
TypeSchema(
|
"schema"
|
||||||
oneOf=[
|
] = TypeSchema(
|
||||||
{"$ref": curr_ref},
|
oneOf=[
|
||||||
{"$ref": schema_ref},
|
{"$ref": curr_ref},
|
||||||
]
|
{"$ref": schema_ref},
|
||||||
)
|
]
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
rsp["content"] = {
|
rsp["content"] = {
|
||||||
"application/json": {"schema": {"$ref": schema_ref}}
|
"application/json": {
|
||||||
|
"schema": {"$ref": schema_ref}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Ensure operation tags are existing
|
# Ensure operation tags are existing
|
||||||
@ -783,7 +825,9 @@ class OpenStackServerSourceBase:
|
|||||||
if tag not in [x["name"] for x in openapi_spec.tags]:
|
if tag not in [x["name"] for x in openapi_spec.tags]:
|
||||||
openapi_spec.tags.append({"name": tag})
|
openapi_spec.tags.append({"name": tag})
|
||||||
|
|
||||||
self._post_process_operation_hook(openapi_spec, operation_spec, path=path)
|
self._post_process_operation_hook(
|
||||||
|
openapi_spec, operation_spec, path=path
|
||||||
|
)
|
||||||
|
|
||||||
def _post_process_operation_hook(
|
def _post_process_operation_hook(
|
||||||
self, openapi_spec, operation_spec, path: str | None = None
|
self, openapi_spec, operation_spec, path: str | None = None
|
||||||
@ -818,7 +862,9 @@ class OpenStackServerSourceBase:
|
|||||||
# Nova added empty params since it was never validating them. Skip
|
# Nova added empty params since it was never validating them. Skip
|
||||||
param_attrs["schema"] = TypeSchema(type="string")
|
param_attrs["schema"] = TypeSchema(type="string")
|
||||||
elif spec["type"] == "array":
|
elif spec["type"] == "array":
|
||||||
param_attrs["schema"] = TypeSchema(**copy.deepcopy(spec["items"]))
|
param_attrs["schema"] = TypeSchema(
|
||||||
|
**copy.deepcopy(spec["items"])
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
param_attrs["schema"] = TypeSchema(**copy.deepcopy(spec))
|
param_attrs["schema"] = TypeSchema(**copy.deepcopy(spec))
|
||||||
param_attrs["description"] = spec.get("description")
|
param_attrs["description"] = spec.get("description")
|
||||||
@ -837,10 +883,14 @@ class OpenStackServerSourceBase:
|
|||||||
**param_attrs,
|
**param_attrs,
|
||||||
)
|
)
|
||||||
if ref_name not in [x.ref for x in operation_spec.parameters]:
|
if ref_name not in [x.ref for x in operation_spec.parameters]:
|
||||||
operation_spec.parameters.append(ParameterSchema(ref=ref_name))
|
operation_spec.parameters.append(
|
||||||
|
ParameterSchema(ref=ref_name)
|
||||||
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise RuntimeError("Query parameters %s is not an object as expected" % obj)
|
raise RuntimeError(
|
||||||
|
f"Query parameters {obj} is not an object as expected"
|
||||||
|
)
|
||||||
|
|
||||||
def process_body_parameters(
|
def process_body_parameters(
|
||||||
self,
|
self,
|
||||||
@ -863,7 +913,9 @@ class OpenStackServerSourceBase:
|
|||||||
if action_name:
|
if action_name:
|
||||||
path_resource_names.append(action_name)
|
path_resource_names.append(action_name)
|
||||||
|
|
||||||
cont_schema_name = "".join([x.title() for x in path_resource_names]) + "Request"
|
cont_schema_name = (
|
||||||
|
"".join([x.title() for x in path_resource_names]) + "Request"
|
||||||
|
)
|
||||||
cont_schema = None
|
cont_schema = None
|
||||||
|
|
||||||
if body_schemas is not UNSET and len(body_schemas) == 1:
|
if body_schemas is not UNSET and len(body_schemas) == 1:
|
||||||
@ -872,7 +924,9 @@ class OpenStackServerSourceBase:
|
|||||||
if True: # body_schemas[0] is not UNSET:
|
if True: # body_schemas[0] is not UNSET:
|
||||||
if cont_schema_name in openapi_spec.components.schemas:
|
if cont_schema_name in openapi_spec.components.schemas:
|
||||||
# if we have already oneOf - add there
|
# if we have already oneOf - add there
|
||||||
cont_schema = openapi_spec.components.schemas[cont_schema_name]
|
cont_schema = openapi_spec.components.schemas[
|
||||||
|
cont_schema_name
|
||||||
|
]
|
||||||
if cont_schema.oneOf and body_schemas[0] not in [
|
if cont_schema.oneOf and body_schemas[0] not in [
|
||||||
x["$ref"] for x in cont_schema.oneOf
|
x["$ref"] for x in cont_schema.oneOf
|
||||||
]:
|
]:
|
||||||
@ -892,7 +946,9 @@ class OpenStackServerSourceBase:
|
|||||||
)
|
)
|
||||||
cont_schema = openapi_spec.components.schemas.setdefault(
|
cont_schema = openapi_spec.components.schemas.setdefault(
|
||||||
cont_schema_name,
|
cont_schema_name,
|
||||||
TypeSchema(oneOf=[], openstack={"discriminator": "microversion"}),
|
TypeSchema(
|
||||||
|
oneOf=[], openstack={"discriminator": "microversion"}
|
||||||
|
),
|
||||||
)
|
)
|
||||||
# Add new refs to the container oneOf if they are not already
|
# Add new refs to the container oneOf if they are not already
|
||||||
# there
|
# there
|
||||||
@ -949,7 +1005,9 @@ class OpenStackServerSourceBase:
|
|||||||
js_content = op_body.setdefault(mime_type, {})
|
js_content = op_body.setdefault(mime_type, {})
|
||||||
body_schema = js_content.setdefault("schema", {})
|
body_schema = js_content.setdefault("schema", {})
|
||||||
one_of = body_schema.setdefault("oneOf", [])
|
one_of = body_schema.setdefault("oneOf", [])
|
||||||
if schema_ref and schema_ref not in [x.get("$ref") for x in one_of]:
|
if schema_ref and schema_ref not in [
|
||||||
|
x.get("$ref") for x in one_of
|
||||||
|
]:
|
||||||
one_of.append({"$ref": schema_ref})
|
one_of.append({"$ref": schema_ref})
|
||||||
os_ext = body_schema.setdefault("x-openstack", {})
|
os_ext = body_schema.setdefault("x-openstack", {})
|
||||||
os_ext["discriminator"] = "action"
|
os_ext["discriminator"] = "action"
|
||||||
@ -959,11 +1017,13 @@ class OpenStackServerSourceBase:
|
|||||||
op_body = operation_spec.requestBody.setdefault("content", {})
|
op_body = operation_spec.requestBody.setdefault("content", {})
|
||||||
js_content = op_body.setdefault(mime_type, {})
|
js_content = op_body.setdefault(mime_type, {})
|
||||||
body_schema = js_content.setdefault("schema", {})
|
body_schema = js_content.setdefault("schema", {})
|
||||||
operation_spec.requestBody["content"][mime_type]["schema"] = TypeSchema(
|
operation_spec.requestBody["content"][mime_type]["schema"] = (
|
||||||
ref=schema_ref
|
TypeSchema(ref=schema_ref)
|
||||||
)
|
)
|
||||||
|
|
||||||
def _sanitize_schema(self, schema, *, start_version=None, end_version=None):
|
def _sanitize_schema(
|
||||||
|
self, schema, *, start_version=None, end_version=None
|
||||||
|
):
|
||||||
"""Various schemas are broken in various ways"""
|
"""Various schemas are broken in various ways"""
|
||||||
|
|
||||||
if isinstance(schema, dict):
|
if isinstance(schema, dict):
|
||||||
@ -987,7 +1047,11 @@ class OpenStackServerSourceBase:
|
|||||||
if typ == "array" and "additionalItems" in v:
|
if typ == "array" and "additionalItems" in v:
|
||||||
# additionalItems have nothing to do under the type array (create servergroup)
|
# additionalItems have nothing to do under the type array (create servergroup)
|
||||||
schema.properties[k].pop("additionalItems")
|
schema.properties[k].pop("additionalItems")
|
||||||
if typ == "array" and "items" in v and isinstance(v["items"], list):
|
if (
|
||||||
|
typ == "array"
|
||||||
|
and "items" in v
|
||||||
|
and isinstance(v["items"], list)
|
||||||
|
):
|
||||||
# server_group create - type array "items" is a dict and not list
|
# server_group create - type array "items" is a dict and not list
|
||||||
# NOTE: server_groups recently changed to "prefixItems",
|
# NOTE: server_groups recently changed to "prefixItems",
|
||||||
# so this may be not necessary anymore
|
# so this may be not necessary anymore
|
||||||
@ -1023,7 +1087,9 @@ class OpenStackServerSourceBase:
|
|||||||
else:
|
else:
|
||||||
os_ext = None
|
os_ext = None
|
||||||
# Ensure global parameter is present
|
# Ensure global parameter is present
|
||||||
param = ParameterSchema(location=param_location, name=param_name, **param_attrs)
|
param = ParameterSchema(
|
||||||
|
location=param_location, name=param_name, **param_attrs
|
||||||
|
)
|
||||||
if param_location == "path":
|
if param_location == "path":
|
||||||
param.required = True
|
param.required = True
|
||||||
if not param.description and path:
|
if not param.description and path:
|
||||||
@ -1041,7 +1107,7 @@ class OpenStackServerSourceBase:
|
|||||||
# Param is already present. Check whether we need to modify min_ver
|
# Param is already present. Check whether we need to modify min_ver
|
||||||
min_ver = os_ext.get("min-ver")
|
min_ver = os_ext.get("min-ver")
|
||||||
max_ver = os_ext.get("max-ver")
|
max_ver = os_ext.get("max-ver")
|
||||||
param.openstack = dict()
|
param.openstack = {}
|
||||||
if not old_param.openstack:
|
if not old_param.openstack:
|
||||||
old_param.openstack = {}
|
old_param.openstack = {}
|
||||||
old_min_ver = old_param.openstack.get("min-ver")
|
old_min_ver = old_param.openstack.get("min-ver")
|
||||||
@ -1054,7 +1120,8 @@ class OpenStackServerSourceBase:
|
|||||||
if (
|
if (
|
||||||
old_max_ver
|
old_max_ver
|
||||||
and max_ver
|
and max_ver
|
||||||
and tuple(old_max_ver.split(".")) > tuple(max_ver.split("."))
|
and tuple(old_max_ver.split("."))
|
||||||
|
> tuple(max_ver.split("."))
|
||||||
):
|
):
|
||||||
# Existing param has max_ver higher then what we have now. Keep old value
|
# Existing param has max_ver higher then what we have now. Keep old value
|
||||||
os_ext["max_ver"] = old_max_ver
|
os_ext["max_ver"] = old_max_ver
|
||||||
@ -1074,7 +1141,9 @@ class OpenStackServerSourceBase:
|
|||||||
action_name=None,
|
action_name=None,
|
||||||
) -> tuple[str | None, str | None]:
|
) -> tuple[str | None, str | None]:
|
||||||
if schema_def is UNSET:
|
if schema_def is UNSET:
|
||||||
logging.warn("No Schema definition for %s[%s] is known", name, action_name)
|
logging.warn(
|
||||||
|
"No Schema definition for %s[%s] is known", name, action_name
|
||||||
|
)
|
||||||
# Create dummy schema since we got no data for it
|
# Create dummy schema since we got no data for it
|
||||||
schema_def = {
|
schema_def = {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@ -1082,10 +1151,7 @@ class OpenStackServerSourceBase:
|
|||||||
}
|
}
|
||||||
if schema_def is not None:
|
if schema_def is not None:
|
||||||
schema = openapi_spec.components.schemas.setdefault(
|
schema = openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**schema_def)
|
||||||
TypeSchema(
|
|
||||||
**schema_def,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if action_name:
|
if action_name:
|
||||||
@ -1156,7 +1222,9 @@ class OpenStackServerSourceBase:
|
|||||||
if isinstance(expected_errors, list):
|
if isinstance(expected_errors, list):
|
||||||
expected_errors = [
|
expected_errors = [
|
||||||
str(x)
|
str(x)
|
||||||
for x in filter(lambda x: isinstance(x, int), expected_errors)
|
for x in filter(
|
||||||
|
lambda x: isinstance(x, int), expected_errors
|
||||||
|
)
|
||||||
]
|
]
|
||||||
elif isinstance(expected_errors, int):
|
elif isinstance(expected_errors, int):
|
||||||
expected_errors = [str(expected_errors)]
|
expected_errors = [str(expected_errors)]
|
||||||
@ -1178,15 +1246,21 @@ class OpenStackServerSourceBase:
|
|||||||
typ_name = (
|
typ_name = (
|
||||||
"".join([x.title() for x in path_resource_names])
|
"".join([x.title() for x in path_resource_names])
|
||||||
+ func.__name__.title()
|
+ func.__name__.title()
|
||||||
+ (f"_{min_ver.replace('.', '')}" if min_ver else "")
|
+ (
|
||||||
|
f"_{min_ver.replace('.', '')}"
|
||||||
|
if min_ver
|
||||||
|
else ""
|
||||||
|
)
|
||||||
)
|
)
|
||||||
comp_schema = openapi_spec.components.schemas.setdefault(
|
comp_schema = (
|
||||||
typ_name,
|
openapi_spec.components.schemas.setdefault(
|
||||||
self._sanitize_schema(
|
typ_name,
|
||||||
copy.deepcopy(obj),
|
self._sanitize_schema(
|
||||||
start_version=start_version,
|
copy.deepcopy(obj),
|
||||||
end_version=end_version,
|
start_version=start_version,
|
||||||
),
|
end_version=end_version,
|
||||||
|
),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
if min_ver:
|
if min_ver:
|
||||||
@ -1290,13 +1364,15 @@ def _convert_wsme_to_jsonschema(body_spec):
|
|||||||
elif basetype is int:
|
elif basetype is int:
|
||||||
res = {"type": "integer"}
|
res = {"type": "integer"}
|
||||||
else:
|
else:
|
||||||
raise RuntimeError("Unsupported basetype %s" % basetype)
|
raise RuntimeError(f"Unsupported basetype {basetype}")
|
||||||
res["enum"] = list(values)
|
res["enum"] = list(values)
|
||||||
# elif hasattr(body_spec, "__name__") and body_spec.__name__ == "bool":
|
# elif hasattr(body_spec, "__name__") and body_spec.__name__ == "bool":
|
||||||
elif wtypes.isdict(body_spec):
|
elif wtypes.isdict(body_spec):
|
||||||
res = {
|
res = {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": _convert_wsme_to_jsonschema(body_spec.value_type),
|
"additionalProperties": _convert_wsme_to_jsonschema(
|
||||||
|
body_spec.value_type
|
||||||
|
),
|
||||||
}
|
}
|
||||||
elif wtypes.isusertype(body_spec):
|
elif wtypes.isusertype(body_spec):
|
||||||
basetype = body_spec.basetype
|
basetype = body_spec.basetype
|
||||||
@ -1304,7 +1380,7 @@ def _convert_wsme_to_jsonschema(body_spec):
|
|||||||
if basetype is str:
|
if basetype is str:
|
||||||
res = {"type": "string", "format": name}
|
res = {"type": "string", "format": name}
|
||||||
else:
|
else:
|
||||||
raise RuntimeError("Unsupported basetype %s" % basetype)
|
raise RuntimeError(f"Unsupported basetype {basetype}")
|
||||||
elif isinstance(body_spec, wtypes.wsproperty):
|
elif isinstance(body_spec, wtypes.wsproperty):
|
||||||
res = _convert_wsme_to_jsonschema(body_spec.datatype)
|
res = _convert_wsme_to_jsonschema(body_spec.datatype)
|
||||||
elif body_spec is bool:
|
elif body_spec is bool:
|
||||||
@ -1312,9 +1388,12 @@ def _convert_wsme_to_jsonschema(body_spec):
|
|||||||
res = {"type": "boolean"}
|
res = {"type": "boolean"}
|
||||||
elif body_spec is float:
|
elif body_spec is float:
|
||||||
res = {"type": "number", "format": "float"}
|
res = {"type": "number", "format": "float"}
|
||||||
elif isinstance(body_spec, wtypes.dt_types) or body_spec is datetime.datetime:
|
elif (
|
||||||
|
isinstance(body_spec, wtypes.dt_types)
|
||||||
|
or body_spec is datetime.datetime
|
||||||
|
):
|
||||||
res = {"type": "string", "format": "date-time"}
|
res = {"type": "string", "format": "date-time"}
|
||||||
else:
|
else:
|
||||||
raise RuntimeError("Unsupported object %s" % body_spec)
|
raise RuntimeError(f"Unsupported object {body_spec}")
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
@ -42,9 +42,7 @@ from codegenerator.openapi.utils import merge_api_ref_doc
|
|||||||
|
|
||||||
|
|
||||||
class CinderV3Generator(OpenStackServerSourceBase):
|
class CinderV3Generator(OpenStackServerSourceBase):
|
||||||
URL_TAG_MAP = {
|
URL_TAG_MAP = {"/versions": "version"}
|
||||||
"/versions": "version",
|
|
||||||
}
|
|
||||||
|
|
||||||
RESOURCE_MODULES = [
|
RESOURCE_MODULES = [
|
||||||
attachment,
|
attachment,
|
||||||
@ -122,24 +120,24 @@ class CinderV3Generator(OpenStackServerSourceBase):
|
|||||||
openapi_spec = self.load_openapi(impl_path)
|
openapi_spec = self.load_openapi(impl_path)
|
||||||
if not openapi_spec:
|
if not openapi_spec:
|
||||||
openapi_spec = SpecSchema(
|
openapi_spec = SpecSchema(
|
||||||
info=dict(
|
info={
|
||||||
title="OpenStack Block Storage API",
|
"title": "OpenStack Block Storage API",
|
||||||
description=LiteralScalarString(
|
"description": LiteralScalarString(
|
||||||
"Volume API provided by Cinder service"
|
"Volume API provided by Cinder service"
|
||||||
),
|
),
|
||||||
version=self.api_version,
|
"version": self.api_version,
|
||||||
),
|
},
|
||||||
openapi="3.1.0",
|
openapi="3.1.0",
|
||||||
security=[{"ApiKeyAuth": []}],
|
security=[{"ApiKeyAuth": []}],
|
||||||
components=dict(
|
components={
|
||||||
securitySchemes={
|
"securitySchemes": {
|
||||||
"ApiKeyAuth": {
|
"ApiKeyAuth": {
|
||||||
"type": "apiKey",
|
"type": "apiKey",
|
||||||
"in": "header",
|
"in": "header",
|
||||||
"name": "X-Auth-Token",
|
"name": "X-Auth-Token",
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
),
|
},
|
||||||
tags=[
|
tags=[
|
||||||
{"name": k, "description": LiteralScalarString(v)}
|
{"name": k, "description": LiteralScalarString(v)}
|
||||||
for (k, v) in common.OPENAPI_TAGS.items()
|
for (k, v) in common.OPENAPI_TAGS.items()
|
||||||
@ -148,7 +146,9 @@ class CinderV3Generator(OpenStackServerSourceBase):
|
|||||||
|
|
||||||
# Set global parameters
|
# Set global parameters
|
||||||
for name, definition in volume.VOLUME_PARAMETERS.items():
|
for name, definition in volume.VOLUME_PARAMETERS.items():
|
||||||
openapi_spec.components.parameters[name] = ParameterSchema(**definition)
|
openapi_spec.components.parameters[name] = ParameterSchema(
|
||||||
|
**definition
|
||||||
|
)
|
||||||
|
|
||||||
for route in self.router.map.matchlist:
|
for route in self.router.map.matchlist:
|
||||||
# if route.routepath.startswith("/{project"):
|
# if route.routepath.startswith("/{project"):
|
||||||
@ -156,7 +156,9 @@ class CinderV3Generator(OpenStackServerSourceBase):
|
|||||||
if route.routepath.endswith(".:(format)"):
|
if route.routepath.endswith(".:(format)"):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if route.routepath.startswith("/extensions") or route.routepath.startswith(
|
if route.routepath.startswith(
|
||||||
|
"/extensions"
|
||||||
|
) or route.routepath.startswith(
|
||||||
"/{project_id:[0-9a-f\-]+}/extensions"
|
"/{project_id:[0-9a-f\-]+}/extensions"
|
||||||
):
|
):
|
||||||
if route.defaults.get("action") != "index":
|
if route.defaults.get("action") != "index":
|
||||||
|
@ -104,7 +104,9 @@ ATTACHMENTS_DETAIL_SCHEMA: dict[str, Any] = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None = None):
|
def _post_process_operation_hook(
|
||||||
|
openapi_spec, operation_spec, path: str | None = None
|
||||||
|
):
|
||||||
"""Hook to allow service specific generator to modify details"""
|
"""Hook to allow service specific generator to modify details"""
|
||||||
operationId = operation_spec.operationId
|
operationId = operation_spec.operationId
|
||||||
if operationId in [
|
if operationId in [
|
||||||
@ -128,11 +130,7 @@ def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None
|
|||||||
|
|
||||||
|
|
||||||
def _get_schema_ref(
|
def _get_schema_ref(
|
||||||
openapi_spec,
|
openapi_spec, name, description=None, schema_def=None, action_name=None
|
||||||
name,
|
|
||||||
description=None,
|
|
||||||
schema_def=None,
|
|
||||||
action_name=None,
|
|
||||||
) -> tuple[str | None, str | None, bool]:
|
) -> tuple[str | None, str | None, bool]:
|
||||||
mime_type: str = "application/json"
|
mime_type: str = "application/json"
|
||||||
ref: str
|
ref: str
|
||||||
|
@ -180,7 +180,7 @@ BACKUPS_SCHEMA: dict[str, Any] = {
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"items": copy.deepcopy(BACKUP_SHORT_SCHEMA),
|
"items": copy.deepcopy(BACKUP_SHORT_SCHEMA),
|
||||||
"description": "A list of backup objects.",
|
"description": "A list of backup objects.",
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,7 +192,7 @@ BACKUPS_DETAIL_SCHEMA: dict[str, Any] = {
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"items": copy.deepcopy(BACKUP_SCHEMA),
|
"items": copy.deepcopy(BACKUP_SCHEMA),
|
||||||
"description": "A list of backup objects.",
|
"description": "A list of backup objects.",
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,7 +253,9 @@ BACKUP_RECORD_SCHEMA: dict[str, Any] = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None = None):
|
def _post_process_operation_hook(
|
||||||
|
openapi_spec, operation_spec, path: str | None = None
|
||||||
|
):
|
||||||
"""Hook to allow service specific generator to modify details"""
|
"""Hook to allow service specific generator to modify details"""
|
||||||
operationId = operation_spec.operationId
|
operationId = operation_spec.operationId
|
||||||
if operationId in [
|
if operationId in [
|
||||||
@ -263,18 +265,16 @@ def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None
|
|||||||
"backups/detail:get",
|
"backups/detail:get",
|
||||||
]:
|
]:
|
||||||
for key, val in BACKUP_LIST_PARAMETERS.items():
|
for key, val in BACKUP_LIST_PARAMETERS.items():
|
||||||
openapi_spec.components.parameters.setdefault(key, ParameterSchema(**val))
|
openapi_spec.components.parameters.setdefault(
|
||||||
|
key, ParameterSchema(**val)
|
||||||
|
)
|
||||||
ref = f"#/components/parameters/{key}"
|
ref = f"#/components/parameters/{key}"
|
||||||
if ref not in [x.ref for x in operation_spec.parameters]:
|
if ref not in [x.ref for x in operation_spec.parameters]:
|
||||||
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
||||||
|
|
||||||
|
|
||||||
def _get_schema_ref(
|
def _get_schema_ref(
|
||||||
openapi_spec,
|
openapi_spec, name, description=None, schema_def=None, action_name=None
|
||||||
name,
|
|
||||||
description=None,
|
|
||||||
schema_def=None,
|
|
||||||
action_name=None,
|
|
||||||
) -> tuple[str | None, str | None, bool]:
|
) -> tuple[str | None, str | None, bool]:
|
||||||
mime_type: str = "application/json"
|
mime_type: str = "application/json"
|
||||||
ref: str
|
ref: str
|
||||||
@ -284,7 +284,9 @@ def _get_schema_ref(
|
|||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name == "BackupsListResponse":
|
elif name == "BackupsListResponse":
|
||||||
openapi_spec.components.schemas.setdefault(name, TypeSchema(**BACKUPS_SCHEMA))
|
openapi_spec.components.schemas.setdefault(
|
||||||
|
name, TypeSchema(**BACKUPS_SCHEMA)
|
||||||
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in [
|
||||||
"BackupsCreateResponse",
|
"BackupsCreateResponse",
|
||||||
@ -297,14 +299,12 @@ def _get_schema_ref(
|
|||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name == "BackupsImport_RecordResponse":
|
elif name == "BackupsImport_RecordResponse":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**BACKUP_SHORT_CONTAINER_SCHEMA)
|
||||||
TypeSchema(**BACKUP_SHORT_CONTAINER_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name == "BackupsRestoreResponse":
|
elif name == "BackupsRestoreResponse":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**BACKUP_RESTORE_RESPONSE_SCHEMA)
|
||||||
TypeSchema(**BACKUP_RESTORE_RESPONSE_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name == "BackupsExport_RecordResponse":
|
elif name == "BackupsExport_RecordResponse":
|
||||||
|
@ -41,10 +41,7 @@ CLUSTER_SCHEMA: dict[str, Any] = {
|
|||||||
"status": {
|
"status": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The status of the cluster.",
|
"description": "The status of the cluster.",
|
||||||
"enum": [
|
"enum": ["enabled", "disabled"],
|
||||||
"enabled",
|
|
||||||
"disabled",
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -101,10 +98,7 @@ CLUSTER_CONTAINER_SCHEMA: dict[str, Any] = {
|
|||||||
CLUSTERS_SCHEMA: dict[str, Any] = {
|
CLUSTERS_SCHEMA: dict[str, Any] = {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"clusters": {
|
"clusters": {"type": "array", "items": copy.deepcopy(CLUSTER_SCHEMA)}
|
||||||
"type": "array",
|
|
||||||
"items": copy.deepcopy(CLUSTER_SCHEMA),
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,15 +209,16 @@ CLUSTERS_LIST_DETAIL_PARAMETERS: dict[str, Any] = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None = None):
|
def _post_process_operation_hook(
|
||||||
|
openapi_spec, operation_spec, path: str | None = None
|
||||||
|
):
|
||||||
"""Hook to allow service specific generator to modify details"""
|
"""Hook to allow service specific generator to modify details"""
|
||||||
operationId = operation_spec.operationId
|
operationId = operation_spec.operationId
|
||||||
if operationId in [
|
if operationId in ["project_id/clusters:get", "clusters:get"]:
|
||||||
"project_id/clusters:get",
|
|
||||||
"clusters:get",
|
|
||||||
]:
|
|
||||||
for key, val in CLUSTERS_LIST_PARAMETERS.items():
|
for key, val in CLUSTERS_LIST_PARAMETERS.items():
|
||||||
openapi_spec.components.parameters.setdefault(key, ParameterSchema(**val))
|
openapi_spec.components.parameters.setdefault(
|
||||||
|
key, ParameterSchema(**val)
|
||||||
|
)
|
||||||
ref = f"#/components/parameters/{key}"
|
ref = f"#/components/parameters/{key}"
|
||||||
if ref not in [x.ref for x in operation_spec.parameters]:
|
if ref not in [x.ref for x in operation_spec.parameters]:
|
||||||
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
||||||
@ -233,18 +228,16 @@ def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None
|
|||||||
"clusters/detail:get",
|
"clusters/detail:get",
|
||||||
]:
|
]:
|
||||||
for key, val in CLUSTERS_LIST_DETAIL_PARAMETERS.items():
|
for key, val in CLUSTERS_LIST_DETAIL_PARAMETERS.items():
|
||||||
openapi_spec.components.parameters.setdefault(key, ParameterSchema(**val))
|
openapi_spec.components.parameters.setdefault(
|
||||||
|
key, ParameterSchema(**val)
|
||||||
|
)
|
||||||
ref = f"#/components/parameters/{key}"
|
ref = f"#/components/parameters/{key}"
|
||||||
if ref not in [x.ref for x in operation_spec.parameters]:
|
if ref not in [x.ref for x in operation_spec.parameters]:
|
||||||
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
||||||
|
|
||||||
|
|
||||||
def _get_schema_ref(
|
def _get_schema_ref(
|
||||||
openapi_spec,
|
openapi_spec, name, description=None, schema_def=None, action_name=None
|
||||||
name,
|
|
||||||
description=None,
|
|
||||||
schema_def=None,
|
|
||||||
action_name=None,
|
|
||||||
) -> tuple[str | None, str | None, bool]:
|
) -> tuple[str | None, str | None, bool]:
|
||||||
mime_type: str = "application/json"
|
mime_type: str = "application/json"
|
||||||
ref: str
|
ref: str
|
||||||
@ -254,17 +247,16 @@ def _get_schema_ref(
|
|||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name == "ClustersListResponse":
|
elif name == "ClustersListResponse":
|
||||||
openapi_spec.components.schemas.setdefault(name, TypeSchema(**CLUSTERS_SCHEMA))
|
openapi_spec.components.schemas.setdefault(
|
||||||
|
name, TypeSchema(**CLUSTERS_SCHEMA)
|
||||||
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name == "ClusterUpdateRequest":
|
elif name == "ClusterUpdateRequest":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name, TypeSchema(**CLUSTER_UPDATE_SCHEMA)
|
name, TypeSchema(**CLUSTER_UPDATE_SCHEMA)
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in ["ClusterShowResponse", "ClusterUpdateResponse"]:
|
||||||
"ClusterShowResponse",
|
|
||||||
"ClusterUpdateResponse",
|
|
||||||
]:
|
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name, TypeSchema(**CLUSTER_CONTAINER_SCHEMA)
|
name, TypeSchema(**CLUSTER_CONTAINER_SCHEMA)
|
||||||
)
|
)
|
||||||
|
@ -156,7 +156,7 @@ LINKS_SCHEMA: dict[str, Any] = {
|
|||||||
METADATA_SCHEMA: dict[str, Any] = {
|
METADATA_SCHEMA: dict[str, Any] = {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"patternProperties": {
|
"patternProperties": {
|
||||||
"^[a-zA-Z0-9-_:. /]{1,255}$": {"type": "string", "maxLength": 255},
|
"^[a-zA-Z0-9-_:. /]{1,255}$": {"type": "string", "maxLength": 255}
|
||||||
},
|
},
|
||||||
"additionalProperties": False,
|
"additionalProperties": False,
|
||||||
"description": "A metadata object. Contains one or more metadata key and value pairs that are associated with the resource.",
|
"description": "A metadata object. Contains one or more metadata key and value pairs that are associated with the resource.",
|
||||||
|
@ -45,12 +45,14 @@ EXTENSIONS_SCHEMA: dict[str, Any] = {
|
|||||||
"extensions": {
|
"extensions": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": copy.deepcopy(EXTENSION_SCHEMA),
|
"items": copy.deepcopy(EXTENSION_SCHEMA),
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None = None):
|
def _post_process_operation_hook(
|
||||||
|
openapi_spec, operation_spec, path: str | None = None
|
||||||
|
):
|
||||||
"""Hook to allow service specific generator to modify details"""
|
"""Hook to allow service specific generator to modify details"""
|
||||||
operationId = operation_spec.operationId
|
operationId = operation_spec.operationId
|
||||||
if operationId in [
|
if operationId in [
|
||||||
@ -65,11 +67,7 @@ def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None
|
|||||||
|
|
||||||
|
|
||||||
def _get_schema_ref(
|
def _get_schema_ref(
|
||||||
openapi_spec,
|
openapi_spec, name, description=None, schema_def=None, action_name=None
|
||||||
name,
|
|
||||||
description=None,
|
|
||||||
schema_def=None,
|
|
||||||
action_name=None,
|
|
||||||
) -> tuple[str | None, str | None, bool]:
|
) -> tuple[str | None, str | None, bool]:
|
||||||
mime_type: str = "application/json"
|
mime_type: str = "application/json"
|
||||||
ref: str
|
ref: str
|
||||||
|
@ -65,10 +65,7 @@ GROUP_SCHEMA: dict[str, Any] = {
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "A volume group object.",
|
"description": "A volume group object.",
|
||||||
"properties": {
|
"properties": {
|
||||||
"name": {
|
"name": {"type": ["string", "null"], "description": "The group name."},
|
||||||
"type": ["string", "null"],
|
|
||||||
"description": "The group name.",
|
|
||||||
},
|
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "uuid",
|
"format": "uuid",
|
||||||
@ -145,10 +142,7 @@ GROUPS_SCHEMA: dict[str, Any] = {
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "A container with list of group objects.",
|
"description": "A container with list of group objects.",
|
||||||
"properties": {
|
"properties": {
|
||||||
"groups": {
|
"groups": {"type": "array", "items": copy.deepcopy(GROUP_SCHEMA)}
|
||||||
"type": "array",
|
|
||||||
"items": copy.deepcopy(GROUP_SCHEMA),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,7 +153,7 @@ GROUPS_DETAIL_SCHEMA: dict[str, Any] = {
|
|||||||
"groups": {
|
"groups": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": copy.deepcopy(GROUP_DETAIL_SCHEMA),
|
"items": copy.deepcopy(GROUP_DETAIL_SCHEMA),
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,7 +201,9 @@ GROUP_REPLICATION_TARGETS_SCHEMA: dict[str, Any] = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None = None):
|
def _post_process_operation_hook(
|
||||||
|
openapi_spec, operation_spec, path: str | None = None
|
||||||
|
):
|
||||||
"""Hook to allow service specific generator to modify details"""
|
"""Hook to allow service specific generator to modify details"""
|
||||||
operationId = operation_spec.operationId
|
operationId = operation_spec.operationId
|
||||||
if operationId in [
|
if operationId in [
|
||||||
@ -217,18 +213,16 @@ def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None
|
|||||||
"groups/detail:get",
|
"groups/detail:get",
|
||||||
]:
|
]:
|
||||||
for key, val in GROUP_LIST_PARAMETERS.items():
|
for key, val in GROUP_LIST_PARAMETERS.items():
|
||||||
openapi_spec.components.parameters.setdefault(key, ParameterSchema(**val))
|
openapi_spec.components.parameters.setdefault(
|
||||||
|
key, ParameterSchema(**val)
|
||||||
|
)
|
||||||
ref = f"#/components/parameters/{key}"
|
ref = f"#/components/parameters/{key}"
|
||||||
if ref not in [x.ref for x in operation_spec.parameters]:
|
if ref not in [x.ref for x in operation_spec.parameters]:
|
||||||
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
||||||
|
|
||||||
|
|
||||||
def _get_schema_ref(
|
def _get_schema_ref(
|
||||||
openapi_spec,
|
openapi_spec, name, description=None, schema_def=None, action_name=None
|
||||||
name,
|
|
||||||
description=None,
|
|
||||||
schema_def=None,
|
|
||||||
action_name=None,
|
|
||||||
) -> tuple[str | None, str | None, bool]:
|
) -> tuple[str | None, str | None, bool]:
|
||||||
mime_type: str = "application/json"
|
mime_type: str = "application/json"
|
||||||
ref: str
|
ref: str
|
||||||
@ -238,12 +232,11 @@ def _get_schema_ref(
|
|||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name == "GroupsListResponse":
|
elif name == "GroupsListResponse":
|
||||||
openapi_spec.components.schemas.setdefault(name, TypeSchema(**GROUPS_SCHEMA))
|
openapi_spec.components.schemas.setdefault(
|
||||||
|
name, TypeSchema(**GROUPS_SCHEMA)
|
||||||
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in ["GroupsCreateResponse", "GroupShowResponse"]:
|
||||||
"GroupsCreateResponse",
|
|
||||||
"GroupShowResponse",
|
|
||||||
]:
|
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name, TypeSchema(**GROUP_CONTAINER_SCHEMA)
|
name, TypeSchema(**GROUP_CONTAINER_SCHEMA)
|
||||||
)
|
)
|
||||||
|
@ -126,7 +126,7 @@ GROUP_SNAPSHOTS_SCHEMA: dict[str, Any] = {
|
|||||||
"group_snapshots": {
|
"group_snapshots": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": copy.deepcopy(GROUP_SNAPSHOT_SCHEMA),
|
"items": copy.deepcopy(GROUP_SNAPSHOT_SCHEMA),
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,7 +137,7 @@ GROUP_SNAPSHOTS_DETAIL_SCHEMA: dict[str, Any] = {
|
|||||||
"group_snapshots": {
|
"group_snapshots": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": copy.deepcopy(GROUP_SNAPSHOT_DETAIL_SCHEMA),
|
"items": copy.deepcopy(GROUP_SNAPSHOT_DETAIL_SCHEMA),
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +147,9 @@ GROUP_SNAPSHOT_CONTAINER_SCHEMA: dict[str, Any] = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None = None):
|
def _post_process_operation_hook(
|
||||||
|
openapi_spec, operation_spec, path: str | None = None
|
||||||
|
):
|
||||||
"""Hook to allow service specific generator to modify details"""
|
"""Hook to allow service specific generator to modify details"""
|
||||||
operationId = operation_spec.operationId
|
operationId = operation_spec.operationId
|
||||||
if operationId in [
|
if operationId in [
|
||||||
@ -157,18 +159,16 @@ def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None
|
|||||||
"group_snapshots/detail:get",
|
"group_snapshots/detail:get",
|
||||||
]:
|
]:
|
||||||
for key, val in GROUP_SNAPSHOT_LIST_PARAMETERS.items():
|
for key, val in GROUP_SNAPSHOT_LIST_PARAMETERS.items():
|
||||||
openapi_spec.components.parameters.setdefault(key, ParameterSchema(**val))
|
openapi_spec.components.parameters.setdefault(
|
||||||
|
key, ParameterSchema(**val)
|
||||||
|
)
|
||||||
ref = f"#/components/parameters/{key}"
|
ref = f"#/components/parameters/{key}"
|
||||||
if ref not in [x.ref for x in operation_spec.parameters]:
|
if ref not in [x.ref for x in operation_spec.parameters]:
|
||||||
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
||||||
|
|
||||||
|
|
||||||
def _get_schema_ref(
|
def _get_schema_ref(
|
||||||
openapi_spec,
|
openapi_spec, name, description=None, schema_def=None, action_name=None
|
||||||
name,
|
|
||||||
description=None,
|
|
||||||
schema_def=None,
|
|
||||||
action_name=None,
|
|
||||||
) -> tuple[str | None, str | None, bool]:
|
) -> tuple[str | None, str | None, bool]:
|
||||||
mime_type: str = "application/json"
|
mime_type: str = "application/json"
|
||||||
ref: str
|
ref: str
|
||||||
|
@ -104,7 +104,7 @@ GROUP_TYPES_SCHEMA: dict[str, Any] = {
|
|||||||
"group_types": {
|
"group_types": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": copy.deepcopy(GROUP_TYPE_SCHEMA),
|
"items": copy.deepcopy(GROUP_TYPE_SCHEMA),
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,7 +114,9 @@ GROUP_TYPE_CONTAINER_SCHEMA: dict[str, Any] = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None = None):
|
def _post_process_operation_hook(
|
||||||
|
openapi_spec, operation_spec, path: str | None = None
|
||||||
|
):
|
||||||
"""Hook to allow service specific generator to modify details"""
|
"""Hook to allow service specific generator to modify details"""
|
||||||
operationId = operation_spec.operationId
|
operationId = operation_spec.operationId
|
||||||
if operationId in [
|
if operationId in [
|
||||||
@ -124,18 +126,16 @@ def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None
|
|||||||
"group_types/detail:get",
|
"group_types/detail:get",
|
||||||
]:
|
]:
|
||||||
for key, val in GROUP_TYPE_LIST_PARAMETERS.items():
|
for key, val in GROUP_TYPE_LIST_PARAMETERS.items():
|
||||||
openapi_spec.components.parameters.setdefault(key, ParameterSchema(**val))
|
openapi_spec.components.parameters.setdefault(
|
||||||
|
key, ParameterSchema(**val)
|
||||||
|
)
|
||||||
ref = f"#/components/parameters/{key}"
|
ref = f"#/components/parameters/{key}"
|
||||||
if ref not in [x.ref for x in operation_spec.parameters]:
|
if ref not in [x.ref for x in operation_spec.parameters]:
|
||||||
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
||||||
|
|
||||||
|
|
||||||
def _get_schema_ref(
|
def _get_schema_ref(
|
||||||
openapi_spec,
|
openapi_spec, name, description=None, schema_def=None, action_name=None
|
||||||
name,
|
|
||||||
description=None,
|
|
||||||
schema_def=None,
|
|
||||||
action_name=None,
|
|
||||||
) -> tuple[str | None, str | None, bool]:
|
) -> tuple[str | None, str | None, bool]:
|
||||||
mime_type: str = "application/json"
|
mime_type: str = "application/json"
|
||||||
ref: str
|
ref: str
|
||||||
|
@ -109,10 +109,7 @@ HOSTS_SCHEMA: dict[str, Any] = {
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "A container with list of host objects.",
|
"description": "A container with list of host objects.",
|
||||||
"properties": {
|
"properties": {
|
||||||
"hosts": {
|
"hosts": {"type": "array", "items": copy.deepcopy(HOST_SCHEMA)}
|
||||||
"type": "array",
|
|
||||||
"items": copy.deepcopy(HOST_SCHEMA),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,27 +117,18 @@ HOSTS_DETAIL_SCHEMA: dict[str, Any] = {
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "A container with list of host objects.",
|
"description": "A container with list of host objects.",
|
||||||
"properties": {
|
"properties": {
|
||||||
"hosts": {
|
"hosts": {"type": "array", "items": copy.deepcopy(HOST_DETAIL_SCHEMA)}
|
||||||
"type": "array",
|
|
||||||
"items": copy.deepcopy(HOST_DETAIL_SCHEMA),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
HOST_CONTAINER_SCHEMA: dict[str, Any] = {
|
HOST_CONTAINER_SCHEMA: dict[str, Any] = {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {"host": {"type": "array", "items": HOST_DETAIL_SCHEMA}},
|
||||||
"host": {"type": "array", "items": HOST_DETAIL_SCHEMA},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _get_schema_ref(
|
def _get_schema_ref(
|
||||||
openapi_spec,
|
openapi_spec, name, description=None, schema_def=None, action_name=None
|
||||||
name,
|
|
||||||
description=None,
|
|
||||||
schema_def=None,
|
|
||||||
action_name=None,
|
|
||||||
) -> tuple[str | None, str | None, bool]:
|
) -> tuple[str | None, str | None, bool]:
|
||||||
mime_type: str = "application/json"
|
mime_type: str = "application/json"
|
||||||
ref: str
|
ref: str
|
||||||
|
@ -93,16 +93,14 @@ LIMITS_SCHEMA: dict[str, Any] = {
|
|||||||
|
|
||||||
|
|
||||||
def _get_schema_ref(
|
def _get_schema_ref(
|
||||||
openapi_spec,
|
openapi_spec, name, description=None, schema_def=None, action_name=None
|
||||||
name,
|
|
||||||
description=None,
|
|
||||||
schema_def=None,
|
|
||||||
action_name=None,
|
|
||||||
) -> tuple[str | None, str | None, bool]:
|
) -> tuple[str | None, str | None, bool]:
|
||||||
mime_type: str = "application/json"
|
mime_type: str = "application/json"
|
||||||
ref: str
|
ref: str
|
||||||
if name == "LimitsListResponse":
|
if name == "LimitsListResponse":
|
||||||
openapi_spec.components.schemas.setdefault(name, TypeSchema(**LIMITS_SCHEMA))
|
openapi_spec.components.schemas.setdefault(
|
||||||
|
name, TypeSchema(**LIMITS_SCHEMA)
|
||||||
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
else:
|
else:
|
||||||
return (None, None, False)
|
return (None, None, False)
|
||||||
|
@ -88,13 +88,12 @@ MESSAGE_CONTAINER_SCHEMA: dict[str, Any] = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None = None):
|
def _post_process_operation_hook(
|
||||||
|
openapi_spec, operation_spec, path: str | None = None
|
||||||
|
):
|
||||||
"""Hook to allow service specific generator to modify details"""
|
"""Hook to allow service specific generator to modify details"""
|
||||||
operationId = operation_spec.operationId
|
operationId = operation_spec.operationId
|
||||||
if operationId in [
|
if operationId in ["project_id/messages:get", "messages:get"]:
|
||||||
"project_id/messages:get",
|
|
||||||
"messages:get",
|
|
||||||
]:
|
|
||||||
for pname in [
|
for pname in [
|
||||||
"sort",
|
"sort",
|
||||||
"sort_key",
|
"sort_key",
|
||||||
@ -109,16 +108,14 @@ def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None
|
|||||||
|
|
||||||
|
|
||||||
def _get_schema_ref(
|
def _get_schema_ref(
|
||||||
openapi_spec,
|
openapi_spec, name, description=None, schema_def=None, action_name=None
|
||||||
name,
|
|
||||||
description=None,
|
|
||||||
schema_def=None,
|
|
||||||
action_name=None,
|
|
||||||
) -> tuple[str | None, str | None, bool]:
|
) -> tuple[str | None, str | None, bool]:
|
||||||
mime_type: str = "application/json"
|
mime_type: str = "application/json"
|
||||||
ref: str
|
ref: str
|
||||||
if name == "MessagesListResponse":
|
if name == "MessagesListResponse":
|
||||||
openapi_spec.components.schemas.setdefault(name, TypeSchema(**MESSAGES_SCHEMA))
|
openapi_spec.components.schemas.setdefault(
|
||||||
|
name, TypeSchema(**MESSAGES_SCHEMA)
|
||||||
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
if name == "MessageShowResponse":
|
if name == "MessageShowResponse":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
|
@ -20,10 +20,7 @@ from codegenerator.common.schema import TypeSchema
|
|||||||
QOS_SPEC_SCHEMA: dict[str, Any] = {
|
QOS_SPEC_SCHEMA: dict[str, Any] = {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"consumer": {
|
"consumer": {"type": "string", "description": "The consumer type."},
|
||||||
"type": "string",
|
|
||||||
"description": "The consumer type.",
|
|
||||||
},
|
|
||||||
"specs": {
|
"specs": {
|
||||||
"type": ["object", "null"],
|
"type": ["object", "null"],
|
||||||
"description": "A specs object.",
|
"description": "A specs object.",
|
||||||
@ -120,16 +117,17 @@ QOS_SPEC_LIST_PARAMETERS: dict[str, Any] = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None = None):
|
def _post_process_operation_hook(
|
||||||
|
openapi_spec, operation_spec, path: str | None = None
|
||||||
|
):
|
||||||
"""Hook to allow service specific generator to modify details"""
|
"""Hook to allow service specific generator to modify details"""
|
||||||
operationId = operation_spec.operationId
|
operationId = operation_spec.operationId
|
||||||
|
|
||||||
if operationId in [
|
if operationId in ["project_id/qos-specs:get", "qos-specs:get"]:
|
||||||
"project_id/qos-specs:get",
|
|
||||||
"qos-specs:get",
|
|
||||||
]:
|
|
||||||
for key, val in QOS_SPEC_LIST_PARAMETERS.items():
|
for key, val in QOS_SPEC_LIST_PARAMETERS.items():
|
||||||
openapi_spec.components.parameters.setdefault(key, ParameterSchema(**val))
|
openapi_spec.components.parameters.setdefault(
|
||||||
|
key, ParameterSchema(**val)
|
||||||
|
)
|
||||||
ref = f"#/components/parameters/{key}"
|
ref = f"#/components/parameters/{key}"
|
||||||
if ref not in [x.ref for x in operation_spec.parameters]:
|
if ref not in [x.ref for x in operation_spec.parameters]:
|
||||||
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
||||||
@ -147,19 +145,14 @@ def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None
|
|||||||
|
|
||||||
|
|
||||||
def _get_schema_ref(
|
def _get_schema_ref(
|
||||||
openapi_spec,
|
openapi_spec, name, description=None, schema_def=None, action_name=None
|
||||||
name,
|
|
||||||
description=None,
|
|
||||||
schema_def=None,
|
|
||||||
action_name=None,
|
|
||||||
) -> tuple[str | None, str | None, bool]:
|
) -> tuple[str | None, str | None, bool]:
|
||||||
mime_type: str = "application/json"
|
mime_type: str = "application/json"
|
||||||
ref: str
|
ref: str
|
||||||
|
|
||||||
if name == "Qos_SpecsListResponse":
|
if name == "Qos_SpecsListResponse":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**QOS_SPECS_SCHEMA)
|
||||||
TypeSchema(**QOS_SPECS_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in [
|
||||||
@ -168,16 +161,12 @@ def _get_schema_ref(
|
|||||||
"Qos_SpecUpdateResponse",
|
"Qos_SpecUpdateResponse",
|
||||||
]:
|
]:
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**QOS_SPEC_CONTAINER_SCHEMA)
|
||||||
TypeSchema(**QOS_SPEC_CONTAINER_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in ["Qos_SpecsAssociationsResponse"]:
|
||||||
"Qos_SpecsAssociationsResponse",
|
|
||||||
]:
|
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**QOS_SPEC_ASSOCIATIONS_SCHEMA)
|
||||||
TypeSchema(**QOS_SPEC_ASSOCIATIONS_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
|
|
||||||
|
@ -26,9 +26,7 @@ RESOURCE_FILTERS_SCHEMA: dict[str, Any] = {
|
|||||||
"filters": {
|
"filters": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"description": "The resource filter array",
|
"description": "The resource filter array",
|
||||||
"items": {
|
"items": {"type": "string"},
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"resource": {
|
"resource": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -42,11 +40,7 @@ RESOURCE_FILTERS_SCHEMA: dict[str, Any] = {
|
|||||||
|
|
||||||
|
|
||||||
def _get_schema_ref(
|
def _get_schema_ref(
|
||||||
openapi_spec,
|
openapi_spec, name, description=None, schema_def=None, action_name=None
|
||||||
name,
|
|
||||||
description=None,
|
|
||||||
schema_def=None,
|
|
||||||
action_name=None,
|
|
||||||
) -> tuple[str | None, str | None, bool]:
|
) -> tuple[str | None, str | None, bool]:
|
||||||
mime_type: str = "application/json"
|
mime_type: str = "application/json"
|
||||||
ref: str
|
ref: str
|
||||||
|
@ -135,7 +135,7 @@ SNAPSHOTS_SCHEMA: dict[str, Any] = {
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"items": copy.deepcopy(SNAPSHOT_SCHEMA),
|
"items": copy.deepcopy(SNAPSHOT_SCHEMA),
|
||||||
"description": "A list of volume objects.",
|
"description": "A list of volume objects.",
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
"required": ["snapshots"],
|
"required": ["snapshots"],
|
||||||
"additionalProperties": False,
|
"additionalProperties": False,
|
||||||
@ -149,14 +149,16 @@ SNAPSHOTS_DETAIL_SCHEMA: dict[str, Any] = {
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"items": copy.deepcopy(SNAPSHOT_DETAIL_SCHEMA),
|
"items": copy.deepcopy(SNAPSHOT_DETAIL_SCHEMA),
|
||||||
"description": "A list of snapshot objects.",
|
"description": "A list of snapshot objects.",
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
"required": ["snapshots"],
|
"required": ["snapshots"],
|
||||||
"additionalProperties": False,
|
"additionalProperties": False,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None = None):
|
def _post_process_operation_hook(
|
||||||
|
openapi_spec, operation_spec, path: str | None = None
|
||||||
|
):
|
||||||
"""Hook to allow service specific generator to modify details"""
|
"""Hook to allow service specific generator to modify details"""
|
||||||
operationId = operation_spec.operationId
|
operationId = operation_spec.operationId
|
||||||
if operationId in [
|
if operationId in [
|
||||||
@ -182,17 +184,15 @@ def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None
|
|||||||
|
|
||||||
|
|
||||||
def _get_schema_ref(
|
def _get_schema_ref(
|
||||||
openapi_spec,
|
openapi_spec, name, description=None, schema_def=None, action_name=None
|
||||||
name,
|
|
||||||
description=None,
|
|
||||||
schema_def=None,
|
|
||||||
action_name=None,
|
|
||||||
) -> tuple[str | None, str | None, bool]:
|
) -> tuple[str | None, str | None, bool]:
|
||||||
mime_type: str = "application/json"
|
mime_type: str = "application/json"
|
||||||
ref: str
|
ref: str
|
||||||
# ### Snapshot
|
# ### Snapshot
|
||||||
if name == "SnapshotsListResponse":
|
if name == "SnapshotsListResponse":
|
||||||
openapi_spec.components.schemas.setdefault(name, TypeSchema(**SNAPSHOTS_SCHEMA))
|
openapi_spec.components.schemas.setdefault(
|
||||||
|
name, TypeSchema(**SNAPSHOTS_SCHEMA)
|
||||||
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
if name == "SnapshotsDetailResponse":
|
if name == "SnapshotsDetailResponse":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
|
@ -29,7 +29,7 @@ MANAGEABLE_SNAPSHOT_SCHEMA: dict[str, Any] = {
|
|||||||
"source-name": {
|
"source-name": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The resource's name.",
|
"description": "The resource's name.",
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"safe_to_manage": {
|
"safe_to_manage": {
|
||||||
@ -53,12 +53,7 @@ MANAGEABLE_SNAPSHOT_SCHEMA: dict[str, Any] = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"additionalProperties": False,
|
"additionalProperties": False,
|
||||||
"required": [
|
"required": ["source_reference", "safe_to_manage", "reference", "size"],
|
||||||
"source_reference",
|
|
||||||
"safe_to_manage",
|
|
||||||
"reference",
|
|
||||||
"size",
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MANAGEABLE_SNAPSHOT_DETAIL_SCHEMA: dict[str, Any] = {
|
MANAGEABLE_SNAPSHOT_DETAIL_SCHEMA: dict[str, Any] = {
|
||||||
@ -108,7 +103,9 @@ MANAGEABLE_SNAPSHOT_CREATE_REQUEST_SCHEMA: dict[str, Any] = copy.deepcopy(
|
|||||||
MANAGEABLE_SNAPSHOT_CREATE_REQUEST_SCHEMA["properties"].pop("type", None)
|
MANAGEABLE_SNAPSHOT_CREATE_REQUEST_SCHEMA["properties"].pop("type", None)
|
||||||
|
|
||||||
|
|
||||||
def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None = None):
|
def _post_process_operation_hook(
|
||||||
|
openapi_spec, operation_spec, path: str | None = None
|
||||||
|
):
|
||||||
"""Hook to allow service specific generator to modify details"""
|
"""Hook to allow service specific generator to modify details"""
|
||||||
operationId = operation_spec.operationId
|
operationId = operation_spec.operationId
|
||||||
if operationId in [
|
if operationId in [
|
||||||
@ -131,11 +128,7 @@ def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None
|
|||||||
|
|
||||||
|
|
||||||
def _get_schema_ref(
|
def _get_schema_ref(
|
||||||
openapi_spec,
|
openapi_spec, name, description=None, schema_def=None, action_name=None
|
||||||
name,
|
|
||||||
description=None,
|
|
||||||
schema_def=None,
|
|
||||||
action_name=None,
|
|
||||||
) -> tuple[str | None, str | None, bool]:
|
) -> tuple[str | None, str | None, bool]:
|
||||||
mime_type: str = "application/json"
|
mime_type: str = "application/json"
|
||||||
ref: str
|
ref: str
|
||||||
|
@ -112,10 +112,7 @@ VOLUME_SCHEMA: dict[str, Any] = {
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "If true, this volume can attach to more than one instance.",
|
"description": "If true, this volume can attach to more than one instance.",
|
||||||
},
|
},
|
||||||
"status": {
|
"status": {"type": "string", "description": "The volume status."},
|
||||||
"type": "string",
|
|
||||||
"description": "The volume status.",
|
|
||||||
},
|
|
||||||
"migration_status": {
|
"migration_status": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The volume migration status. Admin only.",
|
"description": "The volume migration status. Admin only.",
|
||||||
@ -215,7 +212,7 @@ VOLUMES_SCHEMA: dict[str, Any] = {
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"items": copy.deepcopy(VOLUME_SHORT_SCHEMA),
|
"items": copy.deepcopy(VOLUME_SHORT_SCHEMA),
|
||||||
"description": "A list of volume objects.",
|
"description": "A list of volume objects.",
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,7 +224,7 @@ VOLUMES_DETAIL_SCHEMA: dict[str, Any] = {
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"items": copy.deepcopy(VOLUME_SCHEMA),
|
"items": copy.deepcopy(VOLUME_SCHEMA),
|
||||||
"description": "A list of volume objects.",
|
"description": "A list of volume objects.",
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,34 +232,25 @@ VOLUME_PARAMETERS: dict[str, Any] = {
|
|||||||
"all_tenants": {
|
"all_tenants": {
|
||||||
"in": "query",
|
"in": "query",
|
||||||
"name": "all_tenants",
|
"name": "all_tenants",
|
||||||
"schema": {
|
"schema": {"type": "boolean"},
|
||||||
"type": "boolean",
|
|
||||||
},
|
|
||||||
"description": "Shows details for all project. Admin only.",
|
"description": "Shows details for all project. Admin only.",
|
||||||
},
|
},
|
||||||
"sort": {
|
"sort": {
|
||||||
"in": "query",
|
"in": "query",
|
||||||
"name": "sort",
|
"name": "sort",
|
||||||
"schema": {
|
"schema": {"type": "string"},
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"description": "Comma-separated list of sort keys and optional sort directions in the form of < key > [: < direction > ]. A valid direction is asc (ascending) or desc (descending).",
|
"description": "Comma-separated list of sort keys and optional sort directions in the form of < key > [: < direction > ]. A valid direction is asc (ascending) or desc (descending).",
|
||||||
},
|
},
|
||||||
"sort_key": {
|
"sort_key": {
|
||||||
"in": "query",
|
"in": "query",
|
||||||
"name": "sort_key",
|
"name": "sort_key",
|
||||||
"schema": {
|
"schema": {"type": "string"},
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"description": "Sorts by an attribute. A valid value is name, status, container_format, disk_format, size, id, created_at, or updated_at. Default is created_at. The API uses the natural sorting direction of the sort_key attribute value. Deprecated in favour of the combined sort parameter.",
|
"description": "Sorts by an attribute. A valid value is name, status, container_format, disk_format, size, id, created_at, or updated_at. Default is created_at. The API uses the natural sorting direction of the sort_key attribute value. Deprecated in favour of the combined sort parameter.",
|
||||||
},
|
},
|
||||||
"sort_dir": {
|
"sort_dir": {
|
||||||
"in": "query",
|
"in": "query",
|
||||||
"name": "sort_dir",
|
"name": "sort_dir",
|
||||||
"schema": {
|
"schema": {"type": "string", "enum": ["asc", "desc"]},
|
||||||
"type": "string",
|
|
||||||
"enum": ["asc", "desc"],
|
|
||||||
},
|
|
||||||
"description": "Sorts by one or more sets of attribute and sort direction combinations. If you omit the sort direction in a set, default is desc. Deprecated in favour of the combined sort parameter.",
|
"description": "Sorts by one or more sets of attribute and sort direction combinations. If you omit the sort direction in a set, default is desc. Deprecated in favour of the combined sort parameter.",
|
||||||
},
|
},
|
||||||
"limit": {
|
"limit": {
|
||||||
@ -274,55 +262,40 @@ VOLUME_PARAMETERS: dict[str, Any] = {
|
|||||||
"offset": {
|
"offset": {
|
||||||
"in": "query",
|
"in": "query",
|
||||||
"name": "offset",
|
"name": "offset",
|
||||||
"schema": {
|
"schema": {"type": "integer"},
|
||||||
"type": "integer",
|
|
||||||
},
|
|
||||||
"description": "Used in conjunction with limit to return a slice of items. offset is where to start in the list.",
|
"description": "Used in conjunction with limit to return a slice of items. offset is where to start in the list.",
|
||||||
},
|
},
|
||||||
"marker": {
|
"marker": {
|
||||||
"in": "query",
|
"in": "query",
|
||||||
"name": "marker",
|
"name": "marker",
|
||||||
"schema": {
|
"schema": {"type": "string", "format": "uuid"},
|
||||||
"type": "string",
|
|
||||||
"format": "uuid",
|
|
||||||
},
|
|
||||||
"description": "The ID of the last-seen item. Use the limit parameter to make an initial limited request and use the ID of the last-seen item from the response as the marker parameter value in a subsequent limited request.",
|
"description": "The ID of the last-seen item. Use the limit parameter to make an initial limited request and use the ID of the last-seen item from the response as the marker parameter value in a subsequent limited request.",
|
||||||
},
|
},
|
||||||
"with_count": {
|
"with_count": {
|
||||||
"in": "query",
|
"in": "query",
|
||||||
"name": "with_count",
|
"name": "with_count",
|
||||||
"schema": {
|
"schema": {"type": "boolean"},
|
||||||
"type": "boolean",
|
|
||||||
},
|
|
||||||
"description": "Whether to show count in API response or not, default is False.",
|
"description": "Whether to show count in API response or not, default is False.",
|
||||||
"x-openstack": {"min-ver": "3.45"},
|
"x-openstack": {"min-ver": "3.45"},
|
||||||
},
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"in": "query",
|
"in": "query",
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"schema": {
|
"schema": {"type": "string", "format": "date-time"},
|
||||||
"type": "string",
|
|
||||||
"format": "date-time",
|
|
||||||
},
|
|
||||||
"description": "Filters reuslts by a time that resources are created at with time comparison operators: gt/gte/eq/neq/lt/lte.",
|
"description": "Filters reuslts by a time that resources are created at with time comparison operators: gt/gte/eq/neq/lt/lte.",
|
||||||
"x-openstack": {"min-ver": "3.60"},
|
"x-openstack": {"min-ver": "3.60"},
|
||||||
},
|
},
|
||||||
"updated_at": {
|
"updated_at": {
|
||||||
"in": "query",
|
"in": "query",
|
||||||
"name": "updated_at",
|
"name": "updated_at",
|
||||||
"schema": {
|
"schema": {"type": "string", "format": "date-time"},
|
||||||
"type": "string",
|
|
||||||
"format": "date-time",
|
|
||||||
},
|
|
||||||
"description": "Filters reuslts by a time that resources are updated at with time comparison operators: gt/gte/eq/neq/lt/lte.",
|
"description": "Filters reuslts by a time that resources are updated at with time comparison operators: gt/gte/eq/neq/lt/lte.",
|
||||||
"x-openstack": {"min-ver": "3.60"},
|
"x-openstack": {"min-ver": "3.60"},
|
||||||
},
|
},
|
||||||
"consumes_quota": {
|
"consumes_quota": {
|
||||||
"in": "query",
|
"in": "query",
|
||||||
"name": "consumes_quota",
|
"name": "consumes_quota",
|
||||||
"schema": {
|
"schema": {"type": "boolean"},
|
||||||
"type": "boolean",
|
|
||||||
},
|
|
||||||
"description": "Filters results by consumes_quota field. Resources that don’t use quotas are usually temporary internal resources created to perform an operation. Default is to not filter by it. Filtering by this option may not be always possible in a cloud, see List Resource Filters to determine whether this filter is available in your cloud.",
|
"description": "Filters results by consumes_quota field. Resources that don’t use quotas are usually temporary internal resources created to perform an operation. Default is to not filter by it. Filtering by this option may not be always possible in a cloud, see List Resource Filters to determine whether this filter is available in your cloud.",
|
||||||
"x-openstack": {"min-ver": "3.65"},
|
"x-openstack": {"min-ver": "3.65"},
|
||||||
},
|
},
|
||||||
@ -388,7 +361,9 @@ VOLUME_UPLOAD_IMAGE_RESPONSE_SCHEMA: dict[str, Any] = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None = None):
|
def _post_process_operation_hook(
|
||||||
|
openapi_spec, operation_spec, path: str | None = None
|
||||||
|
):
|
||||||
"""Hook to allow service specific generator to modify details"""
|
"""Hook to allow service specific generator to modify details"""
|
||||||
operationId = operation_spec.operationId
|
operationId = operation_spec.operationId
|
||||||
if operationId in [
|
if operationId in [
|
||||||
@ -413,29 +388,23 @@ def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None
|
|||||||
ref = f"#/components/parameters/{pname}"
|
ref = f"#/components/parameters/{pname}"
|
||||||
if ref not in [x.ref for x in operation_spec.parameters]:
|
if ref not in [x.ref for x in operation_spec.parameters]:
|
||||||
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
||||||
elif operationId in [
|
elif operationId in ["project_id/volumes/summary:get"]:
|
||||||
"project_id/volumes/summary:get",
|
for pname in ["all_tenants"]:
|
||||||
]:
|
|
||||||
for pname in [
|
|
||||||
"all_tenants",
|
|
||||||
]:
|
|
||||||
ref = f"#/components/parameters/{pname}"
|
ref = f"#/components/parameters/{pname}"
|
||||||
if ref not in [x.ref for x in operation_spec.parameters]:
|
if ref not in [x.ref for x in operation_spec.parameters]:
|
||||||
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
||||||
|
|
||||||
|
|
||||||
def _get_schema_ref(
|
def _get_schema_ref(
|
||||||
openapi_spec,
|
openapi_spec, name, description=None, schema_def=None, action_name=None
|
||||||
name,
|
|
||||||
description=None,
|
|
||||||
schema_def=None,
|
|
||||||
action_name=None,
|
|
||||||
) -> tuple[str | None, str | None, bool]:
|
) -> tuple[str | None, str | None, bool]:
|
||||||
mime_type: str = "application/json"
|
mime_type: str = "application/json"
|
||||||
ref: str
|
ref: str
|
||||||
# ### Volume
|
# ### Volume
|
||||||
if name == "VolumesListResponse":
|
if name == "VolumesListResponse":
|
||||||
openapi_spec.components.schemas.setdefault(name, TypeSchema(**VOLUMES_SCHEMA))
|
openapi_spec.components.schemas.setdefault(
|
||||||
|
name, TypeSchema(**VOLUMES_SCHEMA)
|
||||||
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
if name == "VolumesDetailResponse":
|
if name == "VolumesDetailResponse":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
@ -506,8 +475,7 @@ def _get_schema_ref(
|
|||||||
return (None, None, True)
|
return (None, None, True)
|
||||||
elif name == "VolumesActionOs-Volume_Upload_ImageResponse":
|
elif name == "VolumesActionOs-Volume_Upload_ImageResponse":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**VOLUME_UPLOAD_IMAGE_RESPONSE_SCHEMA)
|
||||||
TypeSchema(**VOLUME_UPLOAD_IMAGE_RESPONSE_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
else:
|
else:
|
||||||
|
@ -87,7 +87,9 @@ MANAGEABLE_VOLUMES_DETAIL_SCHEMA: dict[str, Any] = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None = None):
|
def _post_process_operation_hook(
|
||||||
|
openapi_spec, operation_spec, path: str | None = None
|
||||||
|
):
|
||||||
"""Hook to allow service specific generator to modify details"""
|
"""Hook to allow service specific generator to modify details"""
|
||||||
operationId = operation_spec.operationId
|
operationId = operation_spec.operationId
|
||||||
if operationId in [
|
if operationId in [
|
||||||
@ -110,11 +112,7 @@ def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None
|
|||||||
|
|
||||||
|
|
||||||
def _get_schema_ref(
|
def _get_schema_ref(
|
||||||
openapi_spec,
|
openapi_spec, name, description=None, schema_def=None, action_name=None
|
||||||
name,
|
|
||||||
description=None,
|
|
||||||
schema_def=None,
|
|
||||||
action_name=None,
|
|
||||||
) -> tuple[str | None, str | None, bool]:
|
) -> tuple[str | None, str | None, bool]:
|
||||||
mime_type: str = "application/json"
|
mime_type: str = "application/json"
|
||||||
ref: str
|
ref: str
|
||||||
|
@ -98,7 +98,9 @@ VOLUME_TRANSFER_CONTAINER_SCHEMA: dict[str, Any] = {
|
|||||||
|
|
||||||
VOLUME_TRANSFERS_SCHEMA: dict[str, Any] = {
|
VOLUME_TRANSFERS_SCHEMA: dict[str, Any] = {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {"transfers": {"type": "array", "items": VOLUME_TRANSFER_SCHEMA}},
|
"properties": {
|
||||||
|
"transfers": {"type": "array", "items": VOLUME_TRANSFER_SCHEMA}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
OS_VOLUME_TRANSFERS_DETAIL_SCHEMA: dict[str, Any] = {
|
OS_VOLUME_TRANSFERS_DETAIL_SCHEMA: dict[str, Any] = {
|
||||||
@ -170,7 +172,9 @@ VOLUME_TRANSFER_LIST_PARAMETERS: dict[str, Any] = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None = None):
|
def _post_process_operation_hook(
|
||||||
|
openapi_spec, operation_spec, path: str | None = None
|
||||||
|
):
|
||||||
"""Hook to allow service specific generator to modify details"""
|
"""Hook to allow service specific generator to modify details"""
|
||||||
operationId = operation_spec.operationId
|
operationId = operation_spec.operationId
|
||||||
|
|
||||||
@ -179,7 +183,9 @@ def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None
|
|||||||
"volume-transfers/detail:get",
|
"volume-transfers/detail:get",
|
||||||
]:
|
]:
|
||||||
for key, val in VOLUME_TRANSFER_LIST_PARAMETERS.items():
|
for key, val in VOLUME_TRANSFER_LIST_PARAMETERS.items():
|
||||||
openapi_spec.components.parameters.setdefault(key, ParameterSchema(**val))
|
openapi_spec.components.parameters.setdefault(
|
||||||
|
key, ParameterSchema(**val)
|
||||||
|
)
|
||||||
ref = f"#/components/parameters/{key}"
|
ref = f"#/components/parameters/{key}"
|
||||||
if ref not in [x.ref for x in operation_spec.parameters]:
|
if ref not in [x.ref for x in operation_spec.parameters]:
|
||||||
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
||||||
@ -191,7 +197,9 @@ def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None
|
|||||||
# structure and just copy single param.
|
# structure and just copy single param.
|
||||||
key = "transfer_all_tenants"
|
key = "transfer_all_tenants"
|
||||||
val = VOLUME_TRANSFER_LIST_PARAMETERS[key]
|
val = VOLUME_TRANSFER_LIST_PARAMETERS[key]
|
||||||
openapi_spec.components.parameters.setdefault(key, ParameterSchema(**val))
|
openapi_spec.components.parameters.setdefault(
|
||||||
|
key, ParameterSchema(**val)
|
||||||
|
)
|
||||||
ref = f"#/components/parameters/{key}"
|
ref = f"#/components/parameters/{key}"
|
||||||
if ref not in [x.ref for x in operation_spec.parameters]:
|
if ref not in [x.ref for x in operation_spec.parameters]:
|
||||||
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
||||||
@ -200,25 +208,19 @@ def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None
|
|||||||
|
|
||||||
|
|
||||||
def _get_schema_ref(
|
def _get_schema_ref(
|
||||||
openapi_spec,
|
openapi_spec, name, description=None, schema_def=None, action_name=None
|
||||||
name,
|
|
||||||
description=None,
|
|
||||||
schema_def=None,
|
|
||||||
action_name=None,
|
|
||||||
) -> tuple[str | None, str | None, bool]:
|
) -> tuple[str | None, str | None, bool]:
|
||||||
mime_type: str = "application/json"
|
mime_type: str = "application/json"
|
||||||
ref: str
|
ref: str
|
||||||
|
|
||||||
if name == "Os_Volume_TransferListResponse":
|
if name == "Os_Volume_TransferListResponse":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**VOLUME_TRANSFERS_SCHEMA)
|
||||||
TypeSchema(**VOLUME_TRANSFERS_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name == "Os_Volume_TransferDetailResponse":
|
elif name == "Os_Volume_TransferDetailResponse":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**OS_VOLUME_TRANSFERS_DETAIL_SCHEMA)
|
||||||
TypeSchema(**OS_VOLUME_TRANSFERS_DETAIL_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in [
|
||||||
@ -227,21 +229,18 @@ def _get_schema_ref(
|
|||||||
"Os_Volume_TransferShowResponse",
|
"Os_Volume_TransferShowResponse",
|
||||||
]:
|
]:
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**OS_VOLUME_TRANSFER_CONTAINER_SCHEMA)
|
||||||
TypeSchema(**OS_VOLUME_TRANSFER_CONTAINER_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
|
|
||||||
elif name == "Volume_TransfersListResponse":
|
elif name == "Volume_TransfersListResponse":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**VOLUME_TRANSFERS_SCHEMA)
|
||||||
TypeSchema(**VOLUME_TRANSFERS_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name == "Volume_TransfersDetailResponse":
|
elif name == "Volume_TransfersDetailResponse":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**VOLUME_TRANSFERS_DETAIL_SCHEMA)
|
||||||
TypeSchema(**VOLUME_TRANSFERS_DETAIL_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in [
|
||||||
@ -250,8 +249,7 @@ def _get_schema_ref(
|
|||||||
"Volume_TransferShowResponse",
|
"Volume_TransferShowResponse",
|
||||||
]:
|
]:
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**VOLUME_TRANSFER_CONTAINER_SCHEMA)
|
||||||
TypeSchema(**VOLUME_TRANSFER_CONTAINER_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
|
|
||||||
|
@ -60,7 +60,9 @@ VOLUME_TYPE_CONTAINER_SCHEMA: dict[str, Any] = {
|
|||||||
|
|
||||||
VOLUME_TYPES_SCHEMA: dict[str, Any] = {
|
VOLUME_TYPES_SCHEMA: dict[str, Any] = {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {"volume_types": {"type": "array", "items": VOLUME_TYPE_SCHEMA}},
|
"properties": {
|
||||||
|
"volume_types": {"type": "array", "items": VOLUME_TYPE_SCHEMA}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
VOLUME_TYPE_LIST_PARAMETERS: dict[str, Any] = {
|
VOLUME_TYPE_LIST_PARAMETERS: dict[str, Any] = {
|
||||||
@ -114,7 +116,7 @@ VOLUME_TYPE_EXTRA_SPECS_SCHEMA: dict[str, Any] = {
|
|||||||
"extra_specs": {
|
"extra_specs": {
|
||||||
"description": "A key and value pair that contains additional specifications that are associated with the volume type. Examples include capabilities, capacity, compression, and so on, depending on the storage driver in use.",
|
"description": "A key and value pair that contains additional specifications that are associated with the volume type. Examples include capabilities, capacity, compression, and so on, depending on the storage driver in use.",
|
||||||
**parameter_types.extra_specs_with_no_spaces_key,
|
**parameter_types.extra_specs_with_no_spaces_key,
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,7 +206,7 @@ VOLUME_TYPE_ENCRYPTION_SHOW_SCHEMA: dict[str, Any] = {
|
|||||||
"cipher": {
|
"cipher": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The encryption algorithm or mode. For example, aes-xts-plain64. The default value is None.",
|
"description": "The encryption algorithm or mode. For example, aes-xts-plain64. The default value is None.",
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,7 +228,9 @@ DEFAULT_TYPE_SCHEMA: dict[str, Any] = {
|
|||||||
|
|
||||||
DEFAULT_TYPES_SCHEMA: dict[str, Any] = {
|
DEFAULT_TYPES_SCHEMA: dict[str, Any] = {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {"default_types": {"type": "array", "items": DEFAULT_TYPE_SCHEMA}},
|
"properties": {
|
||||||
|
"default_types": {"type": "array", "items": DEFAULT_TYPE_SCHEMA}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFAULT_TYPE_CONTAINER_SCHEMA: dict[str, Any] = {
|
DEFAULT_TYPE_CONTAINER_SCHEMA: dict[str, Any] = {
|
||||||
@ -235,26 +239,24 @@ DEFAULT_TYPE_CONTAINER_SCHEMA: dict[str, Any] = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None = None):
|
def _post_process_operation_hook(
|
||||||
|
openapi_spec, operation_spec, path: str | None = None
|
||||||
|
):
|
||||||
"""Hook to allow service specific generator to modify details"""
|
"""Hook to allow service specific generator to modify details"""
|
||||||
operationId = operation_spec.operationId
|
operationId = operation_spec.operationId
|
||||||
|
|
||||||
if operationId in [
|
if operationId in ["project_id/types:get"]:
|
||||||
"project_id/types:get",
|
|
||||||
]:
|
|
||||||
for key, val in VOLUME_TYPE_LIST_PARAMETERS.items():
|
for key, val in VOLUME_TYPE_LIST_PARAMETERS.items():
|
||||||
openapi_spec.components.parameters.setdefault(key, ParameterSchema(**val))
|
openapi_spec.components.parameters.setdefault(
|
||||||
|
key, ParameterSchema(**val)
|
||||||
|
)
|
||||||
ref = f"#/components/parameters/{key}"
|
ref = f"#/components/parameters/{key}"
|
||||||
if ref not in [x.ref for x in operation_spec.parameters]:
|
if ref not in [x.ref for x in operation_spec.parameters]:
|
||||||
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
||||||
|
|
||||||
|
|
||||||
def _get_schema_ref(
|
def _get_schema_ref(
|
||||||
openapi_spec,
|
openapi_spec, name, description=None, schema_def=None, action_name=None
|
||||||
name,
|
|
||||||
description=None,
|
|
||||||
schema_def=None,
|
|
||||||
action_name=None,
|
|
||||||
) -> tuple[str | None, str | None, bool]:
|
) -> tuple[str | None, str | None, bool]:
|
||||||
mime_type: str = "application/json"
|
mime_type: str = "application/json"
|
||||||
ref: str
|
ref: str
|
||||||
@ -262,8 +264,7 @@ def _get_schema_ref(
|
|||||||
# ### Volume Type
|
# ### Volume Type
|
||||||
if name == "TypesListResponse":
|
if name == "TypesListResponse":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**VOLUME_TYPES_SCHEMA)
|
||||||
TypeSchema(**VOLUME_TYPES_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in [
|
||||||
@ -272,8 +273,7 @@ def _get_schema_ref(
|
|||||||
"TypeUpdateResponse",
|
"TypeUpdateResponse",
|
||||||
]:
|
]:
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**VOLUME_TYPE_CONTAINER_SCHEMA)
|
||||||
TypeSchema(**VOLUME_TYPE_CONTAINER_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in [
|
||||||
@ -281,8 +281,7 @@ def _get_schema_ref(
|
|||||||
"TypesExtra_SpecsCreateResponse",
|
"TypesExtra_SpecsCreateResponse",
|
||||||
]:
|
]:
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**VOLUME_TYPE_EXTRA_SPECS_SCHEMA)
|
||||||
TypeSchema(**VOLUME_TYPE_EXTRA_SPECS_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
|
|
||||||
@ -291,15 +290,13 @@ def _get_schema_ref(
|
|||||||
"TypesExtra_SpecUpdateResponse",
|
"TypesExtra_SpecUpdateResponse",
|
||||||
]:
|
]:
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**VOLUME_TYPE_EXTRA_SPEC_SCHEMA)
|
||||||
TypeSchema(**VOLUME_TYPE_EXTRA_SPEC_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
|
|
||||||
elif name == "TypesOs_Volume_Type_AccessListResponse":
|
elif name == "TypesOs_Volume_Type_AccessListResponse":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**VOLUME_TYPE_ACCESS_SCHEMA)
|
||||||
TypeSchema(**VOLUME_TYPE_ACCESS_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in [
|
||||||
@ -312,14 +309,12 @@ def _get_schema_ref(
|
|||||||
# this is not really a list operation, but who cares
|
# this is not really a list operation, but who cares
|
||||||
elif name == "TypesEncryptionListResponse":
|
elif name == "TypesEncryptionListResponse":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**VOLUME_TYPE_ENCRYPTION_SCHEMA)
|
||||||
TypeSchema(**VOLUME_TYPE_ENCRYPTION_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name == "TypesEncryptionShowResponse":
|
elif name == "TypesEncryptionShowResponse":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**VOLUME_TYPE_ENCRYPTION_SHOW_SCHEMA)
|
||||||
TypeSchema(**VOLUME_TYPE_ENCRYPTION_SHOW_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in [
|
||||||
@ -327,14 +322,12 @@ def _get_schema_ref(
|
|||||||
"TypesEncryptionUpdateResponse",
|
"TypesEncryptionUpdateResponse",
|
||||||
]:
|
]:
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**VOLUME_TYPE_ENCRYPTION_CONTAINER_SCHEMA)
|
||||||
TypeSchema(**VOLUME_TYPE_ENCRYPTION_CONTAINER_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name == "Default_TypesListResponse":
|
elif name == "Default_TypesListResponse":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**DEFAULT_TYPES_SCHEMA)
|
||||||
TypeSchema(**DEFAULT_TYPES_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
|
|
||||||
@ -343,8 +336,7 @@ def _get_schema_ref(
|
|||||||
"Default_TypeDetailResponse",
|
"Default_TypeDetailResponse",
|
||||||
]:
|
]:
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**DEFAULT_TYPE_CONTAINER_SCHEMA)
|
||||||
TypeSchema(**DEFAULT_TYPE_CONTAINER_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
|
|
||||||
|
@ -91,7 +91,9 @@ IMAGE_PARAMETERS = {
|
|||||||
"status": {
|
"status": {
|
||||||
"in": "query",
|
"in": "query",
|
||||||
"name": "status",
|
"name": "status",
|
||||||
"description": LiteralScalarString("Filters the response by an image status."),
|
"description": LiteralScalarString(
|
||||||
|
"Filters the response by an image status."
|
||||||
|
),
|
||||||
"schema": {"type": "string"},
|
"schema": {"type": "string"},
|
||||||
},
|
},
|
||||||
"size_min": {
|
"size_min": {
|
||||||
@ -124,9 +126,7 @@ IMAGE_PARAMETERS = {
|
|||||||
"description": LiteralScalarString(
|
"description": LiteralScalarString(
|
||||||
'When true, filters the response to display only "hidden" images. By default, "hidden" images are not included in the image-list response. (Since Image API v2.7)'
|
'When true, filters the response to display only "hidden" images. By default, "hidden" images are not included in the image-list response. (Since Image API v2.7)'
|
||||||
),
|
),
|
||||||
"schema": {
|
"schema": {"type": "boolean"},
|
||||||
"type": "boolean",
|
|
||||||
},
|
|
||||||
"x-openstack": {"min-ver": "2.7"},
|
"x-openstack": {"min-ver": "2.7"},
|
||||||
},
|
},
|
||||||
"sort_key": {
|
"sort_key": {
|
||||||
@ -287,29 +287,31 @@ class GlanceGenerator(OpenStackServerSourceBase):
|
|||||||
openapi_spec = self.load_openapi(impl_path)
|
openapi_spec = self.load_openapi(impl_path)
|
||||||
if not openapi_spec:
|
if not openapi_spec:
|
||||||
openapi_spec = SpecSchema(
|
openapi_spec = SpecSchema(
|
||||||
info=dict(
|
info={
|
||||||
title="OpenStack Image API",
|
"title": "OpenStack Image API",
|
||||||
description=LiteralScalarString(
|
"description": LiteralScalarString(
|
||||||
"Image API provided by Glance service"
|
"Image API provided by Glance service"
|
||||||
),
|
),
|
||||||
version=self.api_version,
|
"version": self.api_version,
|
||||||
),
|
},
|
||||||
openapi="3.1.0",
|
openapi="3.1.0",
|
||||||
security=[{"ApiKeyAuth": []}],
|
security=[{"ApiKeyAuth": []}],
|
||||||
components=dict(
|
components={
|
||||||
securitySchemes={
|
"securitySchemes": {
|
||||||
"ApiKeyAuth": {
|
"ApiKeyAuth": {
|
||||||
"type": "apiKey",
|
"type": "apiKey",
|
||||||
"in": "header",
|
"in": "header",
|
||||||
"name": "X-Auth-Token",
|
"name": "X-Auth-Token",
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
),
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
# Set global headers and parameters
|
# Set global headers and parameters
|
||||||
for name, definition in IMAGE_PARAMETERS.items():
|
for name, definition in IMAGE_PARAMETERS.items():
|
||||||
openapi_spec.components.parameters[name] = ParameterSchema(**definition)
|
openapi_spec.components.parameters[name] = ParameterSchema(
|
||||||
|
**definition
|
||||||
|
)
|
||||||
for name, definition in IMAGE_HEADERS.items():
|
for name, definition in IMAGE_HEADERS.items():
|
||||||
openapi_spec.components.headers[name] = HeaderSchema(**definition)
|
openapi_spec.components.headers[name] = HeaderSchema(**definition)
|
||||||
|
|
||||||
@ -372,7 +374,9 @@ class GlanceGenerator(OpenStackServerSourceBase):
|
|||||||
key = "OpenStack-image-store-ids"
|
key = "OpenStack-image-store-ids"
|
||||||
ref = f"#/components/headers/{key}"
|
ref = f"#/components/headers/{key}"
|
||||||
operation_spec.responses["201"].setdefault("headers", {})
|
operation_spec.responses["201"].setdefault("headers", {})
|
||||||
operation_spec.responses["201"]["headers"].update({key: {"$ref": ref}})
|
operation_spec.responses["201"]["headers"].update(
|
||||||
|
{key: {"$ref": ref}}
|
||||||
|
)
|
||||||
|
|
||||||
elif operationId == "images/image_id/file:put":
|
elif operationId == "images/image_id/file:put":
|
||||||
for ref in [
|
for ref in [
|
||||||
@ -382,21 +386,17 @@ class GlanceGenerator(OpenStackServerSourceBase):
|
|||||||
if ref not in [x.ref for x in operation_spec.parameters]:
|
if ref not in [x.ref for x in operation_spec.parameters]:
|
||||||
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
||||||
elif operationId == "images/image_id/file:get":
|
elif operationId == "images/image_id/file:get":
|
||||||
for ref in [
|
for ref in ["#/components/parameters/range"]:
|
||||||
"#/components/parameters/range",
|
|
||||||
]:
|
|
||||||
if ref not in [x.ref for x in operation_spec.parameters]:
|
if ref not in [x.ref for x in operation_spec.parameters]:
|
||||||
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
||||||
for code in ["200", "206"]:
|
for code in ["200", "206"]:
|
||||||
operation_spec.responses[code].setdefault("headers", {})
|
operation_spec.responses[code].setdefault("headers", {})
|
||||||
for hdr in ["Content-Type", "Content-Md5", "Content-Length"]:
|
for hdr in ["Content-Type", "Content-Md5", "Content-Length"]:
|
||||||
operation_spec.responses[code]["headers"].setdefault(
|
operation_spec.responses[code]["headers"].setdefault(
|
||||||
hdr,
|
hdr, {"$ref": f"#/components/headers/{hdr}"}
|
||||||
{"$ref": f"#/components/headers/{hdr}"},
|
|
||||||
)
|
)
|
||||||
operation_spec.responses["206"]["headers"].setdefault(
|
operation_spec.responses["206"]["headers"].setdefault(
|
||||||
"Content-Range",
|
"Content-Range", {"$ref": "#/components/headers/Content-Range"}
|
||||||
{"$ref": "#/components/headers/Content-Range"},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def _get_schema_ref(
|
def _get_schema_ref(
|
||||||
@ -433,7 +433,9 @@ class GlanceGenerator(OpenStackServerSourceBase):
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": copy.deepcopy(schema_def.properties),
|
"properties": copy.deepcopy(
|
||||||
|
schema_def.properties
|
||||||
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -451,7 +453,9 @@ class GlanceGenerator(OpenStackServerSourceBase):
|
|||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name,
|
||||||
self._get_glance_schema(
|
self._get_glance_schema(
|
||||||
glance_schema.CollectionSchema("tasks", tasks.get_task_schema()),
|
glance_schema.CollectionSchema(
|
||||||
|
"tasks", tasks.get_task_schema()
|
||||||
|
),
|
||||||
name,
|
name,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@ -470,7 +474,9 @@ class GlanceGenerator(OpenStackServerSourceBase):
|
|||||||
"uri": {"type": "string"},
|
"uri": {"type": "string"},
|
||||||
"glance_image_id": {"type": "string"},
|
"glance_image_id": {"type": "string"},
|
||||||
"glance_region": {"type": "string"},
|
"glance_region": {"type": "string"},
|
||||||
"glance_service_interface": {"type": "string"},
|
"glance_service_interface": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"stores": {
|
"stores": {
|
||||||
@ -496,12 +502,12 @@ class GlanceGenerator(OpenStackServerSourceBase):
|
|||||||
elif name == "ImagesMembersListResponse":
|
elif name == "ImagesMembersListResponse":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name,
|
||||||
self._get_glance_schema(image_members.get_collection_schema(), name),
|
self._get_glance_schema(
|
||||||
|
image_members.get_collection_schema(), name
|
||||||
|
),
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in ["InfoImportGet_Image_ImportResponse"]:
|
||||||
"InfoImportGet_Image_ImportResponse",
|
|
||||||
]:
|
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name,
|
||||||
TypeSchema(
|
TypeSchema(
|
||||||
@ -524,9 +530,7 @@ class GlanceGenerator(OpenStackServerSourceBase):
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in ["InfoStoresGet_StoresResponse"]:
|
||||||
"InfoStoresGet_StoresResponse",
|
|
||||||
]:
|
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name,
|
||||||
TypeSchema(
|
TypeSchema(
|
||||||
@ -549,9 +553,7 @@ class GlanceGenerator(OpenStackServerSourceBase):
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in ["InfoStoresDetailGet_Stores_DetailResponse"]:
|
||||||
"InfoStoresDetailGet_Stores_DetailResponse",
|
|
||||||
]:
|
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name,
|
||||||
TypeSchema(
|
TypeSchema(
|
||||||
@ -580,9 +582,7 @@ class GlanceGenerator(OpenStackServerSourceBase):
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in ["MetadefsNamespacesListResponse"]:
|
||||||
"MetadefsNamespacesListResponse",
|
|
||||||
]:
|
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name,
|
||||||
self._get_glance_schema(
|
self._get_glance_schema(
|
||||||
@ -590,17 +590,15 @@ class GlanceGenerator(OpenStackServerSourceBase):
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in ["MetadefsNamespacesObjectsListResponse"]:
|
||||||
"MetadefsNamespacesObjectsListResponse",
|
|
||||||
]:
|
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name,
|
||||||
self._get_glance_schema(metadef_objects.get_collection_schema(), name),
|
self._get_glance_schema(
|
||||||
|
metadef_objects.get_collection_schema(), name
|
||||||
|
),
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in ["MetadefsNamespacesPropertiesListResponse"]:
|
||||||
"MetadefsNamespacesPropertiesListResponse",
|
|
||||||
]:
|
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name,
|
||||||
self._get_glance_schema(
|
self._get_glance_schema(
|
||||||
@ -608,9 +606,7 @@ class GlanceGenerator(OpenStackServerSourceBase):
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in ["MetadefsResource_TypesListResponse"]:
|
||||||
"MetadefsResource_TypesListResponse",
|
|
||||||
]:
|
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name,
|
||||||
TypeSchema(
|
TypeSchema(
|
||||||
@ -648,9 +644,7 @@ class GlanceGenerator(OpenStackServerSourceBase):
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in ["MetadefsNamespacesResource_TypesShowResponse"]:
|
||||||
"MetadefsNamespacesResource_TypesShowResponse",
|
|
||||||
]:
|
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name,
|
||||||
self._get_glance_schema(
|
self._get_glance_schema(
|
||||||
@ -658,12 +652,12 @@ class GlanceGenerator(OpenStackServerSourceBase):
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in ["MetadefsNamespacesTagsListResponse"]:
|
||||||
"MetadefsNamespacesTagsListResponse",
|
|
||||||
]:
|
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name,
|
||||||
self._get_glance_schema(metadef_tags.get_collection_schema(), name),
|
self._get_glance_schema(
|
||||||
|
metadef_tags.get_collection_schema(), name
|
||||||
|
),
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name == "ImageUpdateRequest":
|
elif name == "ImageUpdateRequest":
|
||||||
@ -674,26 +668,19 @@ class GlanceGenerator(OpenStackServerSourceBase):
|
|||||||
# ),
|
# ),
|
||||||
# )
|
# )
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**{"type": "string", "format": "RFC 6902"})
|
||||||
TypeSchema(**{"type": "string", "format": "RFC 6902"}),
|
|
||||||
)
|
)
|
||||||
mime_type = "application/openstack-images-v2.1-json-patch"
|
mime_type = "application/openstack-images-v2.1-json-patch"
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in ["ImagesFileUploadRequest"]:
|
||||||
"ImagesFileUploadRequest",
|
|
||||||
]:
|
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**{"type": "string", "format": "binary"})
|
||||||
TypeSchema(**{"type": "string", "format": "binary"}),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
mime_type = "application/octet-stream"
|
mime_type = "application/octet-stream"
|
||||||
elif name in [
|
elif name in ["ImagesFileDownloadResponse"]:
|
||||||
"ImagesFileDownloadResponse",
|
|
||||||
]:
|
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**{"type": "string", "format": "binary"})
|
||||||
TypeSchema(**{"type": "string", "format": "binary"}),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
mime_type = "application/octet-stream"
|
mime_type = "application/octet-stream"
|
||||||
@ -734,9 +721,9 @@ class GlanceGenerator(OpenStackServerSourceBase):
|
|||||||
for field in i32_fixes:
|
for field in i32_fixes:
|
||||||
res["properties"][field]["format"] = "int64"
|
res["properties"][field]["format"] = "int64"
|
||||||
elif name == "MetadefsNamespacesPropertiesListResponse":
|
elif name == "MetadefsNamespacesPropertiesListResponse":
|
||||||
res["properties"]["properties"]["additionalProperties"]["type"] = (
|
res["properties"]["properties"]["additionalProperties"][
|
||||||
"object"
|
"type"
|
||||||
)
|
] = "object"
|
||||||
return TypeSchema(**res)
|
return TypeSchema(**res)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -100,24 +100,24 @@ class KeystoneGenerator(OpenStackServerSourceBase):
|
|||||||
openapi_spec = self.load_openapi(impl_path)
|
openapi_spec = self.load_openapi(impl_path)
|
||||||
if not openapi_spec:
|
if not openapi_spec:
|
||||||
openapi_spec = SpecSchema(
|
openapi_spec = SpecSchema(
|
||||||
info=dict(
|
info={
|
||||||
title="OpenStack Identity API",
|
"title": "OpenStack Identity API",
|
||||||
description=LiteralScalarString(
|
"description": LiteralScalarString(
|
||||||
"Identity API provided by Keystone service"
|
"Identity API provided by Keystone service"
|
||||||
),
|
),
|
||||||
version=self.api_version,
|
"version": self.api_version,
|
||||||
),
|
},
|
||||||
openapi="3.1.0",
|
openapi="3.1.0",
|
||||||
security=[{"ApiKeyAuth": []}],
|
security=[{"ApiKeyAuth": []}],
|
||||||
components=dict(
|
components={
|
||||||
securitySchemes={
|
"securitySchemes": {
|
||||||
"ApiKeyAuth": {
|
"ApiKeyAuth": {
|
||||||
"type": "apiKey",
|
"type": "apiKey",
|
||||||
"in": "header",
|
"in": "header",
|
||||||
"name": "X-Auth-Token",
|
"name": "X-Auth-Token",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
headers={
|
"headers": {
|
||||||
"X-Auth-Token": {
|
"X-Auth-Token": {
|
||||||
"description": "A valid authentication token",
|
"description": "A valid authentication token",
|
||||||
"schema": {"type": "string", "format": "secret"},
|
"schema": {"type": "string", "format": "secret"},
|
||||||
@ -131,7 +131,7 @@ class KeystoneGenerator(OpenStackServerSourceBase):
|
|||||||
"schema": {"type": "string"},
|
"schema": {"type": "string"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
parameters={
|
"parameters": {
|
||||||
"X-Auth-Token": {
|
"X-Auth-Token": {
|
||||||
"in": "header",
|
"in": "header",
|
||||||
"name": "X-Auth-Token",
|
"name": "X-Auth-Token",
|
||||||
@ -146,7 +146,7 @@ class KeystoneGenerator(OpenStackServerSourceBase):
|
|||||||
"required": True,
|
"required": True,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
),
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
for route in self.router.iter_rules():
|
for route in self.router.iter_rules():
|
||||||
@ -158,7 +158,9 @@ class KeystoneGenerator(OpenStackServerSourceBase):
|
|||||||
self._sanitize_param_ver_info(openapi_spec, self.min_api_version)
|
self._sanitize_param_ver_info(openapi_spec, self.min_api_version)
|
||||||
|
|
||||||
if args.api_ref_src:
|
if args.api_ref_src:
|
||||||
merge_api_ref_doc(openapi_spec, args.api_ref_src, allow_strip_version=False)
|
merge_api_ref_doc(
|
||||||
|
openapi_spec, args.api_ref_src, allow_strip_version=False
|
||||||
|
)
|
||||||
|
|
||||||
self.dump_openapi(openapi_spec, impl_path, args.validate)
|
self.dump_openapi(openapi_spec, impl_path, args.validate)
|
||||||
|
|
||||||
@ -205,10 +207,12 @@ class KeystoneGenerator(OpenStackServerSourceBase):
|
|||||||
for path_element in path_elements:
|
for path_element in path_elements:
|
||||||
if "{" in path_element:
|
if "{" in path_element:
|
||||||
param_name = path_element.strip("{}")
|
param_name = path_element.strip("{}")
|
||||||
global_param_name = "_".join(path_resource_names) + f"_{param_name}"
|
global_param_name = (
|
||||||
|
"_".join(path_resource_names) + f"_{param_name}"
|
||||||
|
)
|
||||||
param_ref_name = f"#/components/parameters/{global_param_name}"
|
param_ref_name = f"#/components/parameters/{global_param_name}"
|
||||||
# Ensure reference to the param is in the path_params
|
# Ensure reference to the param is in the path_params
|
||||||
if param_ref_name not in [k.ref for k in [p for p in path_params]]:
|
if param_ref_name not in [k.ref for k in list(path_params)]:
|
||||||
path_params.append(ParameterSchema(ref=param_ref_name))
|
path_params.append(ParameterSchema(ref=param_ref_name))
|
||||||
# Ensure global parameter is present
|
# Ensure global parameter is present
|
||||||
path_param = ParameterSchema(
|
path_param = ParameterSchema(
|
||||||
@ -222,17 +226,25 @@ class KeystoneGenerator(OpenStackServerSourceBase):
|
|||||||
# We can only assume the param type. For path it is logically a string only
|
# We can only assume the param type. For path it is logically a string only
|
||||||
path_param.type_schema = TypeSchema(type="string")
|
path_param.type_schema = TypeSchema(type="string")
|
||||||
# For non /users/{id} urls link user_id path attribute to the user resource
|
# For non /users/{id} urls link user_id path attribute to the user resource
|
||||||
if path_param.name == "user_id" and path_resource_names != ["users"]:
|
if path_param.name == "user_id" and path_resource_names != [
|
||||||
|
"users"
|
||||||
|
]:
|
||||||
if not path_param.openstack:
|
if not path_param.openstack:
|
||||||
path_param.openstack = {}
|
path_param.openstack = {}
|
||||||
path_param.openstack["resource_link"] = "identity/v3/user.id"
|
path_param.openstack["resource_link"] = (
|
||||||
|
"identity/v3/user.id"
|
||||||
|
)
|
||||||
if path_param.name == "domain_id" and path_resource_names != [
|
if path_param.name == "domain_id" and path_resource_names != [
|
||||||
"domains"
|
"domains"
|
||||||
]:
|
]:
|
||||||
if not path_param.openstack:
|
if not path_param.openstack:
|
||||||
path_param.openstack = {}
|
path_param.openstack = {}
|
||||||
path_param.openstack["resource_link"] = "identity/v3/domain.id"
|
path_param.openstack["resource_link"] = (
|
||||||
openapi_spec.components.parameters[global_param_name] = path_param
|
"identity/v3/domain.id"
|
||||||
|
)
|
||||||
|
openapi_spec.components.parameters[global_param_name] = (
|
||||||
|
path_param
|
||||||
|
)
|
||||||
if len(path_elements) == 0:
|
if len(path_elements) == 0:
|
||||||
path_resource_names.append("root")
|
path_resource_names.append("root")
|
||||||
elif path_elements[-1].startswith("{"):
|
elif path_elements[-1].startswith("{"):
|
||||||
@ -263,13 +275,17 @@ class KeystoneGenerator(OpenStackServerSourceBase):
|
|||||||
elif path == "/v3":
|
elif path == "/v3":
|
||||||
operation_id_prefix = "version"
|
operation_id_prefix = "version"
|
||||||
else:
|
else:
|
||||||
operation_id_prefix = "/".join([x.strip("{}") for x in path_elements])
|
operation_id_prefix = "/".join(
|
||||||
|
[x.strip("{}") for x in path_elements]
|
||||||
|
)
|
||||||
for method in route.methods:
|
for method in route.methods:
|
||||||
if method == "OPTIONS":
|
if method == "OPTIONS":
|
||||||
# Not sure what should be done with it
|
# Not sure what should be done with it
|
||||||
continue
|
continue
|
||||||
if controller:
|
if controller:
|
||||||
func = getattr(controller, method.replace("HEAD", "GET").lower(), None)
|
func = getattr(
|
||||||
|
controller, method.replace("HEAD", "GET").lower(), None
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
func = view
|
func = view
|
||||||
# Set operationId
|
# Set operationId
|
||||||
@ -350,11 +366,7 @@ class KeystoneGenerator(OpenStackServerSourceBase):
|
|||||||
*,
|
*,
|
||||||
method=None,
|
method=None,
|
||||||
):
|
):
|
||||||
logging.info(
|
logging.info("Operation: %s [%s]", path, method)
|
||||||
"Operation: %s [%s]",
|
|
||||||
path,
|
|
||||||
method,
|
|
||||||
)
|
|
||||||
doc = inspect.getdoc(func)
|
doc = inspect.getdoc(func)
|
||||||
if doc and not operation_spec.description:
|
if doc and not operation_spec.description:
|
||||||
doc = rst_to_md(doc)
|
doc = rst_to_md(doc)
|
||||||
@ -368,25 +380,24 @@ class KeystoneGenerator(OpenStackServerSourceBase):
|
|||||||
end_version = None
|
end_version = None
|
||||||
ser_schema: dict | None = {}
|
ser_schema: dict | None = {}
|
||||||
|
|
||||||
(
|
(query_params_versions, body_schemas, ser_schema, expected_errors) = (
|
||||||
query_params_versions,
|
self._process_decorators(
|
||||||
body_schemas,
|
func,
|
||||||
ser_schema,
|
path_resource_names,
|
||||||
expected_errors,
|
openapi_spec,
|
||||||
) = self._process_decorators(
|
method,
|
||||||
func,
|
start_version,
|
||||||
path_resource_names,
|
end_version,
|
||||||
openapi_spec,
|
None,
|
||||||
method,
|
)
|
||||||
start_version,
|
|
||||||
end_version,
|
|
||||||
None,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if query_params_versions:
|
if query_params_versions:
|
||||||
so = sorted(
|
so = sorted(
|
||||||
query_params_versions,
|
query_params_versions,
|
||||||
key=lambda d: (tuple(map(int, d[1].split("."))) if d[1] else (0, 0)),
|
key=lambda d: (
|
||||||
|
tuple(map(int, d[1].split("."))) if d[1] else (0, 0)
|
||||||
|
),
|
||||||
)
|
)
|
||||||
for data, min_ver, max_ver in so:
|
for data, min_ver, max_ver in so:
|
||||||
self.process_query_parameters(
|
self.process_query_parameters(
|
||||||
@ -411,7 +422,7 @@ class KeystoneGenerator(OpenStackServerSourceBase):
|
|||||||
responses_spec = operation_spec.responses
|
responses_spec = operation_spec.responses
|
||||||
# Errors
|
# Errors
|
||||||
for error in ["403", "404"]:
|
for error in ["403", "404"]:
|
||||||
responses_spec.setdefault(str(error), dict(description="Error"))
|
responses_spec.setdefault(str(error), {"description": "Error"})
|
||||||
# Response data
|
# Response data
|
||||||
if method == "POST":
|
if method == "POST":
|
||||||
response_code = "201"
|
response_code = "201"
|
||||||
@ -438,7 +449,7 @@ class KeystoneGenerator(OpenStackServerSourceBase):
|
|||||||
response_code = "204"
|
response_code = "204"
|
||||||
elif path == "/v3/users/{user_id}/password" and method == "POST":
|
elif path == "/v3/users/{user_id}/password" and method == "POST":
|
||||||
response_code = "204"
|
response_code = "204"
|
||||||
rsp = responses_spec.setdefault(response_code, dict(description="Ok"))
|
rsp = responses_spec.setdefault(response_code, {"description": "Ok"})
|
||||||
if response_code != "204" and method not in ["DELETE", "HEAD"]:
|
if response_code != "204" and method not in ["DELETE", "HEAD"]:
|
||||||
# Arrange response placeholder
|
# Arrange response placeholder
|
||||||
schema_name = (
|
schema_name = (
|
||||||
@ -470,7 +481,9 @@ class KeystoneGenerator(OpenStackServerSourceBase):
|
|||||||
operation_spec.security = []
|
operation_spec.security = []
|
||||||
elif method == "GET":
|
elif method == "GET":
|
||||||
operation_spec.parameters.append(
|
operation_spec.parameters.append(
|
||||||
ParameterSchema(ref="#/components/parameters/X-Subject-Token")
|
ParameterSchema(
|
||||||
|
ref="#/components/parameters/X-Subject-Token"
|
||||||
|
)
|
||||||
)
|
)
|
||||||
rsp_headers.setdefault(
|
rsp_headers.setdefault(
|
||||||
"X-Subject-Token",
|
"X-Subject-Token",
|
||||||
@ -482,7 +495,9 @@ class KeystoneGenerator(OpenStackServerSourceBase):
|
|||||||
if tag not in [x["name"] for x in openapi_spec.tags]:
|
if tag not in [x["name"] for x in openapi_spec.tags]:
|
||||||
openapi_spec.tags.append({"name": tag, "description": None})
|
openapi_spec.tags.append({"name": tag, "description": None})
|
||||||
|
|
||||||
self._post_process_operation_hook(openapi_spec, operation_spec, path=path)
|
self._post_process_operation_hook(
|
||||||
|
openapi_spec, operation_spec, path=path
|
||||||
|
)
|
||||||
|
|
||||||
def _post_process_operation_hook(
|
def _post_process_operation_hook(
|
||||||
self, openapi_spec, operation_spec, path: str | None = None
|
self, openapi_spec, operation_spec, path: str | None = None
|
||||||
|
@ -38,7 +38,7 @@ APPLICATION_CREDENTIAL_ACCESS_RULE_SCHEMA: dict[str, Any] = {
|
|||||||
"properties": {
|
"properties": {
|
||||||
"access_rule": copy.deepcopy(
|
"access_rule": copy.deepcopy(
|
||||||
application_credential_schema._access_rules_properties["items"]
|
application_credential_schema._access_rules_properties["items"]
|
||||||
),
|
)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,9 +83,9 @@ APPLICATION_CREDENTIAL_CREATE_RESPONSE_SCHEMA: dict[str, Any] = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
# Update `secret` field
|
# Update `secret` field
|
||||||
APPLICATION_CREDENTIAL_CREATE_RESPONSE_SCHEMA["properties"]["application_credential"][
|
APPLICATION_CREDENTIAL_CREATE_RESPONSE_SCHEMA["properties"][
|
||||||
"properties"
|
"application_credential"
|
||||||
]["secret"] = {
|
]["properties"]["secret"] = {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The secret for the application credential, either generated by the server or provided by the user. This is only ever shown once in the response to a create request. It is not stored nor ever shown again. If the secret is lost, a new application credential must be created.",
|
"description": "The secret for the application credential, either generated by the server or provided by the user. This is only ever shown once in the response to a create request. It is not stored nor ever shown again. If the secret is lost, a new application credential must be created.",
|
||||||
}
|
}
|
||||||
@ -96,7 +96,7 @@ APPLICATION_CREDENTIALS_SCHEMA: dict[str, Any] = {
|
|||||||
"application_credentials": {
|
"application_credentials": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": copy.deepcopy(APPLICATION_CREDENTIAL_SCHEMA),
|
"items": copy.deepcopy(APPLICATION_CREDENTIAL_SCHEMA),
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,70 +106,59 @@ APPLICATION_CREDENTIALS_LIST_PARAMETERS = {
|
|||||||
"name": "name",
|
"name": "name",
|
||||||
"description": "The name of the application credential. Must be unique to a user.",
|
"description": "The name of the application credential. Must be unique to a user.",
|
||||||
"schema": {"type": "string"},
|
"schema": {"type": "string"},
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None = None):
|
def _post_process_operation_hook(
|
||||||
|
openapi_spec, operation_spec, path: str | None = None
|
||||||
|
):
|
||||||
"""Hook to allow service specific generator to modify details"""
|
"""Hook to allow service specific generator to modify details"""
|
||||||
operationId = operation_spec.operationId
|
operationId = operation_spec.operationId
|
||||||
if operationId == "users/user_id/application_credentials:get":
|
if operationId == "users/user_id/application_credentials:get":
|
||||||
for (
|
for key, val in APPLICATION_CREDENTIALS_LIST_PARAMETERS.items():
|
||||||
key,
|
openapi_spec.components.parameters.setdefault(
|
||||||
val,
|
key, ParameterSchema(**val)
|
||||||
) in APPLICATION_CREDENTIALS_LIST_PARAMETERS.items():
|
)
|
||||||
openapi_spec.components.parameters.setdefault(key, ParameterSchema(**val))
|
|
||||||
ref = f"#/components/parameters/{key}"
|
ref = f"#/components/parameters/{key}"
|
||||||
if ref not in [x.ref for x in operation_spec.parameters]:
|
if ref not in [x.ref for x in operation_spec.parameters]:
|
||||||
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
||||||
|
|
||||||
|
|
||||||
def _get_schema_ref(
|
def _get_schema_ref(
|
||||||
openapi_spec,
|
openapi_spec, name, description=None, schema_def=None, action_name=None
|
||||||
name,
|
|
||||||
description=None,
|
|
||||||
schema_def=None,
|
|
||||||
action_name=None,
|
|
||||||
) -> tuple[str | None, str | None, bool]:
|
) -> tuple[str | None, str | None, bool]:
|
||||||
mime_type: str = "application/json"
|
mime_type: str = "application/json"
|
||||||
ref: str
|
ref: str
|
||||||
# ### Application Credentials
|
# ### Application Credentials
|
||||||
if name == "UsersAccess_RuleGetResponse":
|
if name == "UsersAccess_RuleGetResponse":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**APPLICATION_CREDENTIAL_ACCESS_RULE_SCHEMA)
|
||||||
TypeSchema(**APPLICATION_CREDENTIAL_ACCESS_RULE_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name == "UsersAccess_RulesGetResponse":
|
elif name == "UsersAccess_RulesGetResponse":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**APPLICATION_CREDENTIAL_ACCESS_RULES_SCHEMA)
|
||||||
TypeSchema(**APPLICATION_CREDENTIAL_ACCESS_RULES_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name == "UsersApplication_CredentialsGetResponse":
|
elif name == "UsersApplication_CredentialsGetResponse":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**APPLICATION_CREDENTIALS_SCHEMA)
|
||||||
TypeSchema(**APPLICATION_CREDENTIALS_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in ["UsersApplication_CredentialGetResponse"]:
|
||||||
"UsersApplication_CredentialGetResponse",
|
|
||||||
]:
|
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**APPLICATION_CREDENTIAL_CONTAINER_SCHEMA)
|
||||||
TypeSchema(**APPLICATION_CREDENTIAL_CONTAINER_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name == "UsersApplication_CredentialsPostRequest":
|
elif name == "UsersApplication_CredentialsPostRequest":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**APPLICATION_CREDENTIAL_CREATE_SCHEMA)
|
||||||
TypeSchema(**APPLICATION_CREDENTIAL_CREATE_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name == "UsersApplication_CredentialsPostResponse":
|
elif name == "UsersApplication_CredentialsPostResponse":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**APPLICATION_CREDENTIAL_CREATE_RESPONSE_SCHEMA)
|
||||||
TypeSchema(**APPLICATION_CREDENTIAL_CREATE_RESPONSE_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
|
|
||||||
|
@ -27,14 +27,8 @@ SCOPE_SCHEMA: dict[str, Any] = {
|
|||||||
"project": {
|
"project": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"name": {
|
"name": {"type": "string", "description": "Project Name"},
|
||||||
"type": "string",
|
"id": {"type": "string", "description": "Project Id"},
|
||||||
"description": "Project Name",
|
|
||||||
},
|
|
||||||
"id": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Project Id",
|
|
||||||
},
|
|
||||||
"domain": {
|
"domain": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -53,29 +47,17 @@ SCOPE_SCHEMA: dict[str, Any] = {
|
|||||||
"domain": {
|
"domain": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"id": {
|
"id": {"type": "string", "description": "Domain id"},
|
||||||
"type": "string",
|
"name": {"type": "string", "description": "Domain name"},
|
||||||
"description": "Domain id",
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Domain name",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"OS-TRUST:trust": {
|
"OS-TRUST:trust": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {"id": {"type": "string"}},
|
||||||
"id": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"system": {
|
"system": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {"all": {"type": "boolean"}},
|
||||||
"all": {"type": "boolean"},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -131,7 +113,7 @@ AUTH_TOKEN_ISSUE_SCHEMA: dict[str, Any] = replace_refs(
|
|||||||
"$ref": "#/definitions/user_domain"
|
"$ref": "#/definitions/user_domain"
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"token": {
|
"token": {
|
||||||
@ -142,11 +124,9 @@ AUTH_TOKEN_ISSUE_SCHEMA: dict[str, Any] = replace_refs(
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "password",
|
"format": "password",
|
||||||
"description": "Authorization Token value",
|
"description": "Authorization Token value",
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": ["id"],
|
||||||
"id",
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
"totp": {
|
"totp": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@ -173,11 +153,9 @@ AUTH_TOKEN_ISSUE_SCHEMA: dict[str, Any] = replace_refs(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"required": ["passcode"],
|
"required": ["passcode"],
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": ["user"],
|
||||||
"user",
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
"application_credential": {
|
"application_credential": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@ -217,32 +195,25 @@ AUTH_TOKEN_ISSUE_SCHEMA: dict[str, Any] = replace_refs(
|
|||||||
"required": ["secret"],
|
"required": ["secret"],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"required": [
|
"required": ["methods"],
|
||||||
"methods",
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
"scope": SCOPE_SCHEMA,
|
"scope": SCOPE_SCHEMA,
|
||||||
},
|
},
|
||||||
"required": [
|
"required": ["identity"],
|
||||||
"identity",
|
}
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"definitions": {
|
"definitions": {
|
||||||
"user_domain": {
|
"user_domain": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "User Domain object",
|
"description": "User Domain object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"id": {
|
"id": {"type": "string", "description": "User Domain ID"},
|
||||||
"type": "string",
|
|
||||||
"description": "User Domain ID",
|
|
||||||
},
|
|
||||||
"name": {
|
"name": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "User Domain Name",
|
"description": "User Domain Name",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
proxies=False,
|
proxies=False,
|
||||||
@ -454,9 +425,7 @@ AUTH_TOKEN_SCHEMA: dict[str, Any] = {
|
|||||||
AUTH_SCOPED_TOKEN_SCHEMA: dict[str, Any] = copy.deepcopy(AUTH_TOKEN_SCHEMA)
|
AUTH_SCOPED_TOKEN_SCHEMA: dict[str, Any] = copy.deepcopy(AUTH_TOKEN_SCHEMA)
|
||||||
AUTH_SCOPED_TOKEN_SCHEMA["properties"]["token"]["properties"].update(
|
AUTH_SCOPED_TOKEN_SCHEMA["properties"]["token"]["properties"].update(
|
||||||
**{
|
**{
|
||||||
"is_domain": {
|
"is_domain": {"type": "boolean"},
|
||||||
"type": "boolean",
|
|
||||||
},
|
|
||||||
"domain": {
|
"domain": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "A domain object including the id and name representing the domain the token is scoped to. This is only included in tokens that are scoped to a domain.",
|
"description": "A domain object including the id and name representing the domain the token is scoped to. This is only included in tokens that are scoped to a domain.",
|
||||||
@ -466,10 +435,7 @@ AUTH_SCOPED_TOKEN_SCHEMA["properties"]["token"]["properties"].update(
|
|||||||
"format": "uuid",
|
"format": "uuid",
|
||||||
"description": "A domain UUID",
|
"description": "A domain UUID",
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {"type": "string", "description": "A domain name"},
|
||||||
"type": "string",
|
|
||||||
"description": "A domain name",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"project": {
|
"project": {
|
||||||
@ -498,10 +464,7 @@ AUTH_SCOPED_TOKEN_SCHEMA["properties"]["token"]["properties"].update(
|
|||||||
"format": "uuid",
|
"format": "uuid",
|
||||||
"description": "A role UUID",
|
"description": "A role UUID",
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {"type": "string", "description": "A role name"},
|
||||||
"type": "string",
|
|
||||||
"description": "A role name",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -546,7 +509,9 @@ AUTH_RECEIPT_SCHEMA: dict[str, Any] = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None = None):
|
def _post_process_operation_hook(
|
||||||
|
openapi_spec, operation_spec, path: str | None = None
|
||||||
|
):
|
||||||
"""Hook to allow service specific generator to modify details"""
|
"""Hook to allow service specific generator to modify details"""
|
||||||
operationId = operation_spec.operationId
|
operationId = operation_spec.operationId
|
||||||
|
|
||||||
@ -561,16 +526,14 @@ def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None
|
|||||||
"$ref": "#/components/headers/Openstack-Auth-Receipt"
|
"$ref": "#/components/headers/Openstack-Auth-Receipt"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"content": {receipt_mime_type: {"schema": {"$ref": receipt_schema_ref}}},
|
"content": {
|
||||||
|
receipt_mime_type: {"schema": {"$ref": receipt_schema_ref}}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _get_schema_ref(
|
def _get_schema_ref(
|
||||||
openapi_spec,
|
openapi_spec, name, description=None, schema_def=None, action_name=None
|
||||||
name,
|
|
||||||
description=None,
|
|
||||||
schema_def=None,
|
|
||||||
action_name=None,
|
|
||||||
) -> tuple[str | None, str | None, bool]:
|
) -> tuple[str | None, str | None, bool]:
|
||||||
mime_type: str = "application/json"
|
mime_type: str = "application/json"
|
||||||
ref: str
|
ref: str
|
||||||
@ -578,14 +541,12 @@ def _get_schema_ref(
|
|||||||
# Auth
|
# Auth
|
||||||
if name == "AuthTokensPostRequest":
|
if name == "AuthTokensPostRequest":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**AUTH_TOKEN_ISSUE_SCHEMA)
|
||||||
TypeSchema(**AUTH_TOKEN_ISSUE_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in ["AuthTokensGetResponse", "AuthTokensPostResponse"]:
|
elif name in ["AuthTokensGetResponse", "AuthTokensPostResponse"]:
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**AUTH_SCOPED_TOKEN_SCHEMA)
|
||||||
TypeSchema(**AUTH_SCOPED_TOKEN_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name == "AuthReceiptSchema":
|
elif name == "AuthReceiptSchema":
|
||||||
@ -593,16 +554,12 @@ def _get_schema_ref(
|
|||||||
name, TypeSchema(**AUTH_RECEIPT_SCHEMA)
|
name, TypeSchema(**AUTH_RECEIPT_SCHEMA)
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in ["AuthProjectsGetResponse"]:
|
||||||
"AuthProjectsGetResponse",
|
|
||||||
]:
|
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name, TypeSchema(**AUTH_PROJECTS_SCHEMA)
|
name, TypeSchema(**AUTH_PROJECTS_SCHEMA)
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in ["AuthDomainsGetResponse"]:
|
||||||
"AuthDomainsGetResponse",
|
|
||||||
]:
|
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name, TypeSchema(**AUTH_DOMAINS_SCHEMA)
|
name, TypeSchema(**AUTH_DOMAINS_SCHEMA)
|
||||||
)
|
)
|
||||||
|
@ -33,7 +33,9 @@ LINKS_SCHEMA: dict[str, Any] = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TAG_SCHEMA: dict[str, Any] = copy.deepcopy(ks_schema._project_tag_name_properties)
|
TAG_SCHEMA: dict[str, Any] = copy.deepcopy(
|
||||||
|
ks_schema._project_tag_name_properties
|
||||||
|
)
|
||||||
|
|
||||||
TAGS_SCHEMA: dict[str, Any] = {
|
TAGS_SCHEMA: dict[str, Any] = {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
@ -119,27 +119,24 @@ DOMAIN_LIST_PARAMETERS: dict[str, dict] = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None = None):
|
def _post_process_operation_hook(
|
||||||
|
openapi_spec, operation_spec, path: str | None = None
|
||||||
|
):
|
||||||
"""Hook to allow service specific generator to modify details"""
|
"""Hook to allow service specific generator to modify details"""
|
||||||
|
|
||||||
operationId = operation_spec.operationId
|
operationId = operation_spec.operationId
|
||||||
if operationId == "domains:get":
|
if operationId == "domains:get":
|
||||||
for (
|
for key, val in DOMAIN_LIST_PARAMETERS.items():
|
||||||
key,
|
openapi_spec.components.parameters.setdefault(
|
||||||
val,
|
key, ParameterSchema(**val)
|
||||||
) in DOMAIN_LIST_PARAMETERS.items():
|
)
|
||||||
openapi_spec.components.parameters.setdefault(key, ParameterSchema(**val))
|
|
||||||
ref = f"#/components/parameters/{key}"
|
ref = f"#/components/parameters/{key}"
|
||||||
if ref not in [x.ref for x in operation_spec.parameters]:
|
if ref not in [x.ref for x in operation_spec.parameters]:
|
||||||
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
||||||
|
|
||||||
|
|
||||||
def _get_schema_ref(
|
def _get_schema_ref(
|
||||||
openapi_spec,
|
openapi_spec, name, description=None, schema_def=None, action_name=None
|
||||||
name,
|
|
||||||
description=None,
|
|
||||||
schema_def=None,
|
|
||||||
action_name=None,
|
|
||||||
) -> tuple[str | None, str | None, bool]:
|
) -> tuple[str | None, str | None, bool]:
|
||||||
mime_type: str = "application/json"
|
mime_type: str = "application/json"
|
||||||
ref: str
|
ref: str
|
||||||
@ -156,7 +153,9 @@ def _get_schema_ref(
|
|||||||
)
|
)
|
||||||
ref = "#/components/schemas/Domain"
|
ref = "#/components/schemas/Domain"
|
||||||
elif name == "DomainsGetResponse":
|
elif name == "DomainsGetResponse":
|
||||||
openapi_spec.components.schemas.setdefault(name, TypeSchema(**DOMAINS_SCHEMA))
|
openapi_spec.components.schemas.setdefault(
|
||||||
|
name, TypeSchema(**DOMAINS_SCHEMA)
|
||||||
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
|
|
||||||
# Domain Config
|
# Domain Config
|
||||||
@ -171,8 +170,7 @@ def _get_schema_ref(
|
|||||||
"DomainsConfigDefaultGetResponse",
|
"DomainsConfigDefaultGetResponse",
|
||||||
]:
|
]:
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
"DomainConfig",
|
"DomainConfig", TypeSchema(**DOMAIN_CONFIGS_SCHEMA)
|
||||||
TypeSchema(**DOMAIN_CONFIGS_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = "#/components/schemas/DomainConfig"
|
ref = "#/components/schemas/DomainConfig"
|
||||||
elif name in [
|
elif name in [
|
||||||
@ -184,8 +182,7 @@ def _get_schema_ref(
|
|||||||
"DomainsConfigGroupPatchResponse",
|
"DomainsConfigGroupPatchResponse",
|
||||||
]:
|
]:
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
"DomainConfigGroup",
|
"DomainConfigGroup", TypeSchema(**DOMAIN_CONFIG_GROUP_SCHEMA)
|
||||||
TypeSchema(**DOMAIN_CONFIG_GROUP_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = "#/components/schemas/DomainConfigGroup"
|
ref = "#/components/schemas/DomainConfigGroup"
|
||||||
|
|
||||||
|
@ -90,7 +90,9 @@ ENDPOINTS_LIST_PARAMETERS = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
ENDPOINT_CREATE_SCHEMA: dict[str, Any] = copy.deepcopy(ENDPOINT_CONTAINER_SCHEMA)
|
ENDPOINT_CREATE_SCHEMA: dict[str, Any] = copy.deepcopy(
|
||||||
|
ENDPOINT_CONTAINER_SCHEMA
|
||||||
|
)
|
||||||
ENDPOINT_CREATE_SCHEMA["properties"]["endpoint"]["properties"].pop("id")
|
ENDPOINT_CREATE_SCHEMA["properties"]["endpoint"]["properties"].pop("id")
|
||||||
ENDPOINT_CREATE_SCHEMA["properties"]["endpoint"]["required"] = [
|
ENDPOINT_CREATE_SCHEMA["properties"]["endpoint"]["required"] = [
|
||||||
"interface",
|
"interface",
|
||||||
@ -99,34 +101,30 @@ ENDPOINT_CREATE_SCHEMA["properties"]["endpoint"]["required"] = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None = None):
|
def _post_process_operation_hook(
|
||||||
|
openapi_spec, operation_spec, path: str | None = None
|
||||||
|
):
|
||||||
"""Hook to allow service specific generator to modify details"""
|
"""Hook to allow service specific generator to modify details"""
|
||||||
operationId = operation_spec.operationId
|
operationId = operation_spec.operationId
|
||||||
if operationId == "endpoints:get":
|
if operationId == "endpoints:get":
|
||||||
for (
|
for key, val in ENDPOINTS_LIST_PARAMETERS.items():
|
||||||
key,
|
openapi_spec.components.parameters.setdefault(
|
||||||
val,
|
key, ParameterSchema(**val)
|
||||||
) in ENDPOINTS_LIST_PARAMETERS.items():
|
)
|
||||||
openapi_spec.components.parameters.setdefault(key, ParameterSchema(**val))
|
|
||||||
ref = f"#/components/parameters/{key}"
|
ref = f"#/components/parameters/{key}"
|
||||||
if ref not in [x.ref for x in operation_spec.parameters]:
|
if ref not in [x.ref for x in operation_spec.parameters]:
|
||||||
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
||||||
|
|
||||||
|
|
||||||
def _get_schema_ref(
|
def _get_schema_ref(
|
||||||
openapi_spec,
|
openapi_spec, name, description=None, schema_def=None, action_name=None
|
||||||
name,
|
|
||||||
description=None,
|
|
||||||
schema_def=None,
|
|
||||||
action_name=None,
|
|
||||||
) -> tuple[str | None, str | None, bool]:
|
) -> tuple[str | None, str | None, bool]:
|
||||||
mime_type: str = "application/json"
|
mime_type: str = "application/json"
|
||||||
ref: str
|
ref: str
|
||||||
# ### Endpoints
|
# ### Endpoints
|
||||||
if name == "EndpointsGetResponse":
|
if name == "EndpointsGetResponse":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**ENDPOINTS_SCHEMA)
|
||||||
TypeSchema(**ENDPOINTS_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in [
|
||||||
@ -136,14 +134,12 @@ def _get_schema_ref(
|
|||||||
"EndpointPatchResponse",
|
"EndpointPatchResponse",
|
||||||
]:
|
]:
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
"Endpoint",
|
"Endpoint", TypeSchema(**ENDPOINT_CONTAINER_SCHEMA)
|
||||||
TypeSchema(**ENDPOINT_CONTAINER_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = "#/components/schemas/Endpoint"
|
ref = "#/components/schemas/Endpoint"
|
||||||
elif name == "EndpointsPostRequest":
|
elif name == "EndpointsPostRequest":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**ENDPOINT_CREATE_SCHEMA)
|
||||||
TypeSchema(**ENDPOINT_CREATE_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
|
|
||||||
|
@ -61,12 +61,16 @@ IDENTITY_PROVIDER_CONTAINER_SCHEMA: dict[str, Any] = {
|
|||||||
|
|
||||||
IDENTITY_PROVIDER_CREATE_SCHEMA: dict[str, Any] = {
|
IDENTITY_PROVIDER_CREATE_SCHEMA: dict[str, Any] = {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {"identity_provider": federation_schema.identity_provider_create},
|
"properties": {
|
||||||
|
"identity_provider": federation_schema.identity_provider_create
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
IDENTITY_PROVIDER_UPDATE_SCHEMA: dict[str, Any] = {
|
IDENTITY_PROVIDER_UPDATE_SCHEMA: dict[str, Any] = {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {"identity_provider": federation_schema.identity_provider_update},
|
"properties": {
|
||||||
|
"identity_provider": federation_schema.identity_provider_update
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
IDENTITY_PROVIDERS_SCHEMA: dict[str, Any] = {
|
IDENTITY_PROVIDERS_SCHEMA: dict[str, Any] = {
|
||||||
@ -133,8 +137,7 @@ IDENTITY_PROVIDER_PROTOCOL_UPDATE_SCHEMA: dict[str, Any] = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MAPPING_PROPERTIES = replace_refs(
|
MAPPING_PROPERTIES = replace_refs(
|
||||||
federation_mapping_schema.IDP_ATTRIBUTE_MAPPING_SCHEMA_2_0,
|
federation_mapping_schema.IDP_ATTRIBUTE_MAPPING_SCHEMA_2_0, proxies=False
|
||||||
proxies=False,
|
|
||||||
)
|
)
|
||||||
MAPPING_PROPERTIES.pop("definitions", None)
|
MAPPING_PROPERTIES.pop("definitions", None)
|
||||||
MAPPING_PROPERTIES["properties"]["schema_version"] = {
|
MAPPING_PROPERTIES["properties"]["schema_version"] = {
|
||||||
@ -215,24 +218,29 @@ FEDERATION_SERVICE_PROVIDERS_SCHEMA: dict[str, Any] = {
|
|||||||
|
|
||||||
FEDERATION_SERVICE_PROVIDER_CREATE_SCHEMA: dict[str, Any] = {
|
FEDERATION_SERVICE_PROVIDER_CREATE_SCHEMA: dict[str, Any] = {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {"service_provider": federation_schema.service_provider_create},
|
"properties": {
|
||||||
|
"service_provider": federation_schema.service_provider_create
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
FEDERATION_SERVICE_PROVIDER_UPDATE_SCHEMA: dict[str, Any] = {
|
FEDERATION_SERVICE_PROVIDER_UPDATE_SCHEMA: dict[str, Any] = {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {"service_provider": federation_schema.service_provider_update},
|
"properties": {
|
||||||
|
"service_provider": federation_schema.service_provider_update
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None = None):
|
def _post_process_operation_hook(
|
||||||
|
openapi_spec, operation_spec, path: str | None = None
|
||||||
|
):
|
||||||
"""Hook to allow service specific generator to modify details"""
|
"""Hook to allow service specific generator to modify details"""
|
||||||
operationId = operation_spec.operationId
|
operationId = operation_spec.operationId
|
||||||
if operationId == "OS-FEDERATION/identity_providers:get":
|
if operationId == "OS-FEDERATION/identity_providers:get":
|
||||||
for (
|
for key, val in IDENTITY_PROVIDERS_LIST_PARAMETERS.items():
|
||||||
key,
|
openapi_spec.components.parameters.setdefault(
|
||||||
val,
|
key, ParameterSchema(**val)
|
||||||
) in IDENTITY_PROVIDERS_LIST_PARAMETERS.items():
|
)
|
||||||
openapi_spec.components.parameters.setdefault(key, ParameterSchema(**val))
|
|
||||||
ref = f"#/components/parameters/{key}"
|
ref = f"#/components/parameters/{key}"
|
||||||
if ref not in [x.ref for x in operation_spec.parameters]:
|
if ref not in [x.ref for x in operation_spec.parameters]:
|
||||||
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
||||||
@ -247,11 +255,7 @@ def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None
|
|||||||
|
|
||||||
|
|
||||||
def _get_schema_ref(
|
def _get_schema_ref(
|
||||||
openapi_spec,
|
openapi_spec, name, description=None, schema_def=None, action_name=None
|
||||||
name,
|
|
||||||
description=None,
|
|
||||||
schema_def=None,
|
|
||||||
action_name=None,
|
|
||||||
) -> tuple[str | None, str | None, bool]:
|
) -> tuple[str | None, str | None, bool]:
|
||||||
mime_type: str = "application/json"
|
mime_type: str = "application/json"
|
||||||
ref: str | None
|
ref: str | None
|
||||||
@ -260,9 +264,7 @@ def _get_schema_ref(
|
|||||||
name, TypeSchema(**auth.AUTH_PROJECTS_SCHEMA)
|
name, TypeSchema(**auth.AUTH_PROJECTS_SCHEMA)
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in ["Os_FederationDomainsGetResponse"]:
|
||||||
"Os_FederationDomainsGetResponse",
|
|
||||||
]:
|
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name, TypeSchema(**auth.AUTH_DOMAINS_SCHEMA)
|
name, TypeSchema(**auth.AUTH_DOMAINS_SCHEMA)
|
||||||
)
|
)
|
||||||
@ -272,8 +274,7 @@ def _get_schema_ref(
|
|||||||
"AuthOs_FederationSaml2EcpPostRequest",
|
"AuthOs_FederationSaml2EcpPostRequest",
|
||||||
]:
|
]:
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**auth.AUTH_TOKEN_ISSUE_SCHEMA)
|
||||||
TypeSchema(**auth.AUTH_TOKEN_ISSUE_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in [
|
||||||
@ -312,8 +313,7 @@ def _get_schema_ref(
|
|||||||
# ### Identity provider
|
# ### Identity provider
|
||||||
elif name == "Os_FederationIdentity_ProvidersGetResponse":
|
elif name == "Os_FederationIdentity_ProvidersGetResponse":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**IDENTITY_PROVIDERS_SCHEMA)
|
||||||
TypeSchema(**IDENTITY_PROVIDERS_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in [
|
||||||
@ -322,27 +322,23 @@ def _get_schema_ref(
|
|||||||
"Os_FederationIdentity_ProviderPatchResponse",
|
"Os_FederationIdentity_ProviderPatchResponse",
|
||||||
]:
|
]:
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**IDENTITY_PROVIDER_CONTAINER_SCHEMA)
|
||||||
TypeSchema(**IDENTITY_PROVIDER_CONTAINER_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name == "Os_FederationIdentity_ProviderPutRequest":
|
elif name == "Os_FederationIdentity_ProviderPutRequest":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**IDENTITY_PROVIDER_CREATE_SCHEMA)
|
||||||
TypeSchema(**IDENTITY_PROVIDER_CREATE_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name == "Os_FederationIdentity_ProviderPatchRequest":
|
elif name == "Os_FederationIdentity_ProviderPatchRequest":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**IDENTITY_PROVIDER_UPDATE_SCHEMA)
|
||||||
TypeSchema(**IDENTITY_PROVIDER_UPDATE_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
# ### Identity provider protocols
|
# ### Identity provider protocols
|
||||||
elif name == "Os_FederationIdentity_ProvidersProtocolsGetResponse":
|
elif name == "Os_FederationIdentity_ProvidersProtocolsGetResponse":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**IDENTITY_PROVIDER_PROTOCOLS_SCHEMA)
|
||||||
TypeSchema(**IDENTITY_PROVIDER_PROTOCOLS_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in [
|
||||||
@ -351,27 +347,23 @@ def _get_schema_ref(
|
|||||||
"Os_FederationIdentity_ProvidersProtocolPatchResponse",
|
"Os_FederationIdentity_ProvidersProtocolPatchResponse",
|
||||||
]:
|
]:
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**IDENTITY_PROVIDER_PROTOCOL_CONTAINER_SCHEMA)
|
||||||
TypeSchema(**IDENTITY_PROVIDER_PROTOCOL_CONTAINER_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name == "Os_FederationIdentity_ProvidersProtocolPutRequest":
|
elif name == "Os_FederationIdentity_ProvidersProtocolPutRequest":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**IDENTITY_PROVIDER_PROTOCOL_CREATE_SCHEMA)
|
||||||
TypeSchema(**IDENTITY_PROVIDER_PROTOCOL_CREATE_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name == "Os_FederationIdentity_ProvidersProtocolPatchRequest":
|
elif name == "Os_FederationIdentity_ProvidersProtocolPatchRequest":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**IDENTITY_PROVIDER_PROTOCOL_UPDATE_SCHEMA)
|
||||||
TypeSchema(**IDENTITY_PROVIDER_PROTOCOL_UPDATE_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
# ### Identity provider mapping
|
# ### Identity provider mapping
|
||||||
elif name == "Os_FederationMappingsGetResponse":
|
elif name == "Os_FederationMappingsGetResponse":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**MAPPINGS_SCHEMA)
|
||||||
TypeSchema(**MAPPINGS_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in [
|
||||||
@ -380,8 +372,7 @@ def _get_schema_ref(
|
|||||||
"Os_FederationMappingPatchResponse",
|
"Os_FederationMappingPatchResponse",
|
||||||
]:
|
]:
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**MAPPING_CONTAINER_SCHEMA)
|
||||||
TypeSchema(**MAPPING_CONTAINER_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in [
|
||||||
@ -389,15 +380,13 @@ def _get_schema_ref(
|
|||||||
"Os_FederationMappingPatchRequest",
|
"Os_FederationMappingPatchRequest",
|
||||||
]:
|
]:
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**MAPPING_CREATE_SCHEMA)
|
||||||
TypeSchema(**MAPPING_CREATE_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
# ### Identity provider service provider
|
# ### Identity provider service provider
|
||||||
elif name == "Os_FederationService_ProvidersGetResponse":
|
elif name == "Os_FederationService_ProvidersGetResponse":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**FEDERATION_SERVICE_PROVIDERS_SCHEMA)
|
||||||
TypeSchema(**FEDERATION_SERVICE_PROVIDERS_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in [
|
||||||
@ -406,20 +395,17 @@ def _get_schema_ref(
|
|||||||
"Os_FederationService_ProviderPatchResponse",
|
"Os_FederationService_ProviderPatchResponse",
|
||||||
]:
|
]:
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**FEDERATION_SERVICE_PROVIDER_CONTAINER_SCHEMA)
|
||||||
TypeSchema(**FEDERATION_SERVICE_PROVIDER_CONTAINER_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name == "Os_FederationService_ProviderPutRequest":
|
elif name == "Os_FederationService_ProviderPutRequest":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**FEDERATION_SERVICE_PROVIDER_CREATE_SCHEMA)
|
||||||
TypeSchema(**FEDERATION_SERVICE_PROVIDER_CREATE_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name == "Os_FederationService_ProviderPatchRequest":
|
elif name == "Os_FederationService_ProviderPatchRequest":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**FEDERATION_SERVICE_PROVIDER_UPDATE_SCHEMA)
|
||||||
TypeSchema(**FEDERATION_SERVICE_PROVIDER_UPDATE_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
# SAML2 Metadata
|
# SAML2 Metadata
|
||||||
|
@ -43,7 +43,7 @@ GROUPS_LIST_PARAMETERS: dict[str, Any] = {
|
|||||||
"name": "domain_id",
|
"name": "domain_id",
|
||||||
"description": "Filters the response by a domain ID.",
|
"description": "Filters the response by a domain ID.",
|
||||||
"schema": {"type": "string", "format": "uuid"},
|
"schema": {"type": "string", "format": "uuid"},
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GROUP_USERS_LIST_PARAMETERS: dict[str, Any] = {
|
GROUP_USERS_LIST_PARAMETERS: dict[str, Any] = {
|
||||||
@ -52,41 +52,45 @@ GROUP_USERS_LIST_PARAMETERS: dict[str, Any] = {
|
|||||||
"name": "password_expires_at",
|
"name": "password_expires_at",
|
||||||
"description": "Filter results based on which user passwords have expired. The query should include an operator and a timestamp with a colon (:) separating the two, for example: `password_expires_at={operator}:{timestamp}`.\nValid operators are: `lt`, `lte`, `gt`, `gte`, `eq`, and `neq`.\nValid timestamps are of the form: YYYY-MM-DDTHH:mm:ssZ.",
|
"description": "Filter results based on which user passwords have expired. The query should include an operator and a timestamp with a colon (:) separating the two, for example: `password_expires_at={operator}:{timestamp}`.\nValid operators are: `lt`, `lte`, `gt`, `gte`, `eq`, and `neq`.\nValid timestamps are of the form: YYYY-MM-DDTHH:mm:ssZ.",
|
||||||
"schema": {"type": "string", "format": "date-time"},
|
"schema": {"type": "string", "format": "date-time"},
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None = None):
|
def _post_process_operation_hook(
|
||||||
|
openapi_spec, operation_spec, path: str | None = None
|
||||||
|
):
|
||||||
"""Hook to allow service specific generator to modify details"""
|
"""Hook to allow service specific generator to modify details"""
|
||||||
operationId = operation_spec.operationId
|
operationId = operation_spec.operationId
|
||||||
|
|
||||||
if operationId == "groups:get":
|
if operationId == "groups:get":
|
||||||
for key, val in GROUPS_LIST_PARAMETERS.items():
|
for key, val in GROUPS_LIST_PARAMETERS.items():
|
||||||
openapi_spec.components.parameters.setdefault(key, ParameterSchema(**val))
|
openapi_spec.components.parameters.setdefault(
|
||||||
|
key, ParameterSchema(**val)
|
||||||
|
)
|
||||||
ref = f"#/components/parameters/{key}"
|
ref = f"#/components/parameters/{key}"
|
||||||
if ref not in [x.ref for x in operation_spec.parameters]:
|
if ref not in [x.ref for x in operation_spec.parameters]:
|
||||||
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
||||||
|
|
||||||
elif operationId == "groups/group_id/users:get":
|
elif operationId == "groups/group_id/users:get":
|
||||||
for key, val in GROUP_USERS_LIST_PARAMETERS.items():
|
for key, val in GROUP_USERS_LIST_PARAMETERS.items():
|
||||||
openapi_spec.components.parameters.setdefault(key, ParameterSchema(**val))
|
openapi_spec.components.parameters.setdefault(
|
||||||
|
key, ParameterSchema(**val)
|
||||||
|
)
|
||||||
ref = f"#/components/parameters/{key}"
|
ref = f"#/components/parameters/{key}"
|
||||||
if ref not in [x.ref for x in operation_spec.parameters]:
|
if ref not in [x.ref for x in operation_spec.parameters]:
|
||||||
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
||||||
|
|
||||||
|
|
||||||
def _get_schema_ref(
|
def _get_schema_ref(
|
||||||
openapi_spec,
|
openapi_spec, name, description=None, schema_def=None, action_name=None
|
||||||
name,
|
|
||||||
description=None,
|
|
||||||
schema_def=None,
|
|
||||||
action_name=None,
|
|
||||||
) -> tuple[str | None, str | None, bool]:
|
) -> tuple[str | None, str | None, bool]:
|
||||||
mime_type: str = "application/json"
|
mime_type: str = "application/json"
|
||||||
ref: str
|
ref: str
|
||||||
# Groups
|
# Groups
|
||||||
if name == "GroupsGetResponse":
|
if name == "GroupsGetResponse":
|
||||||
openapi_spec.components.schemas.setdefault(name, TypeSchema(**GROUPS_SCHEMA))
|
openapi_spec.components.schemas.setdefault(
|
||||||
|
name, TypeSchema(**GROUPS_SCHEMA)
|
||||||
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in [
|
||||||
"GroupsPostRequest",
|
"GroupsPostRequest",
|
||||||
|
@ -38,7 +38,7 @@ PROJECT_CONTAINER_SCHEMA: dict[str, Any] = {
|
|||||||
**ks_schema._project_properties,
|
**ks_schema._project_properties,
|
||||||
},
|
},
|
||||||
"additionalProperties": True,
|
"additionalProperties": True,
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,26 +83,23 @@ PROJECT_LIST_PARAMETERS = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None = None):
|
def _post_process_operation_hook(
|
||||||
|
openapi_spec, operation_spec, path: str | None = None
|
||||||
|
):
|
||||||
"""Hook to allow service specific generator to modify details"""
|
"""Hook to allow service specific generator to modify details"""
|
||||||
operationId = operation_spec.operationId
|
operationId = operation_spec.operationId
|
||||||
if operationId == "projects:get":
|
if operationId == "projects:get":
|
||||||
for (
|
for key, val in PROJECT_LIST_PARAMETERS.items():
|
||||||
key,
|
openapi_spec.components.parameters.setdefault(
|
||||||
val,
|
key, ParameterSchema(**val)
|
||||||
) in PROJECT_LIST_PARAMETERS.items():
|
)
|
||||||
openapi_spec.components.parameters.setdefault(key, ParameterSchema(**val))
|
|
||||||
ref = f"#/components/parameters/{key}"
|
ref = f"#/components/parameters/{key}"
|
||||||
if ref not in [x.ref for x in operation_spec.parameters]:
|
if ref not in [x.ref for x in operation_spec.parameters]:
|
||||||
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
||||||
|
|
||||||
|
|
||||||
def _get_schema_ref(
|
def _get_schema_ref(
|
||||||
openapi_spec,
|
openapi_spec, name, description=None, schema_def=None, action_name=None
|
||||||
name,
|
|
||||||
description=None,
|
|
||||||
schema_def=None,
|
|
||||||
action_name=None,
|
|
||||||
) -> tuple[str | None, str | None, bool]:
|
) -> tuple[str | None, str | None, bool]:
|
||||||
mime_type: str = "application/json"
|
mime_type: str = "application/json"
|
||||||
ref: str
|
ref: str
|
||||||
@ -115,12 +112,13 @@ def _get_schema_ref(
|
|||||||
"ProjectGetResponse",
|
"ProjectGetResponse",
|
||||||
]:
|
]:
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
"Project",
|
"Project", TypeSchema(**PROJECT_CONTAINER_SCHEMA)
|
||||||
TypeSchema(**PROJECT_CONTAINER_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = "#/components/schemas/Project"
|
ref = "#/components/schemas/Project"
|
||||||
elif name == "ProjectsGetResponse":
|
elif name == "ProjectsGetResponse":
|
||||||
openapi_spec.components.schemas.setdefault(name, TypeSchema(**PROJECTS_SCHEMA))
|
openapi_spec.components.schemas.setdefault(
|
||||||
|
name, TypeSchema(**PROJECTS_SCHEMA)
|
||||||
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
|
|
||||||
# Project Tags
|
# Project Tags
|
||||||
|
@ -52,38 +52,34 @@ REGIONS_LIST_PARAMETERS = {
|
|||||||
"name": "parent_region_id",
|
"name": "parent_region_id",
|
||||||
"description": "Filters the response by a parent region, by ID.",
|
"description": "Filters the response by a parent region, by ID.",
|
||||||
"schema": {"type": "string", "format": "uuid"},
|
"schema": {"type": "string", "format": "uuid"},
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None = None):
|
def _post_process_operation_hook(
|
||||||
|
openapi_spec, operation_spec, path: str | None = None
|
||||||
|
):
|
||||||
"""Hook to allow service specific generator to modify details"""
|
"""Hook to allow service specific generator to modify details"""
|
||||||
operationId = operation_spec.operationId
|
operationId = operation_spec.operationId
|
||||||
if operationId == "regions:get":
|
if operationId == "regions:get":
|
||||||
for (
|
for key, val in REGIONS_LIST_PARAMETERS.items():
|
||||||
key,
|
openapi_spec.components.parameters.setdefault(
|
||||||
val,
|
key, ParameterSchema(**val)
|
||||||
) in REGIONS_LIST_PARAMETERS.items():
|
)
|
||||||
openapi_spec.components.parameters.setdefault(key, ParameterSchema(**val))
|
|
||||||
ref = f"#/components/parameters/{key}"
|
ref = f"#/components/parameters/{key}"
|
||||||
if ref not in [x.ref for x in operation_spec.parameters]:
|
if ref not in [x.ref for x in operation_spec.parameters]:
|
||||||
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
||||||
|
|
||||||
|
|
||||||
def _get_schema_ref(
|
def _get_schema_ref(
|
||||||
openapi_spec,
|
openapi_spec, name, description=None, schema_def=None, action_name=None
|
||||||
name,
|
|
||||||
description=None,
|
|
||||||
schema_def=None,
|
|
||||||
action_name=None,
|
|
||||||
) -> tuple[str | None, str | None, bool]:
|
) -> tuple[str | None, str | None, bool]:
|
||||||
mime_type: str = "application/json"
|
mime_type: str = "application/json"
|
||||||
ref: str
|
ref: str
|
||||||
# ### Regions
|
# ### Regions
|
||||||
if name == "RegionsGetResponse":
|
if name == "RegionsGetResponse":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**REGIONS_SCHEMA)
|
||||||
TypeSchema(**REGIONS_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in [
|
||||||
@ -94,8 +90,7 @@ def _get_schema_ref(
|
|||||||
"RegionPatchResponse",
|
"RegionPatchResponse",
|
||||||
]:
|
]:
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
"Region",
|
"Region", TypeSchema(**REGION_CONTAINER_SCHEMA)
|
||||||
TypeSchema(**REGION_CONTAINER_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = "#/components/schemas/Region"
|
ref = "#/components/schemas/Region"
|
||||||
|
|
||||||
|
@ -48,10 +48,7 @@ ROLE_INFO_SCHEMA: dict[str, Any] = {
|
|||||||
"format": "uuid",
|
"format": "uuid",
|
||||||
"description": "The role ID.",
|
"description": "The role ID.",
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {"type": "string", "description": "The role name."},
|
||||||
"type": "string",
|
|
||||||
"description": "The role name.",
|
|
||||||
},
|
|
||||||
"description": {
|
"description": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The role description.",
|
"description": "The role description.",
|
||||||
@ -111,7 +108,7 @@ ROLE_LIST_PARAMETERS: dict[str, Any] = {
|
|||||||
"name": "domain_id",
|
"name": "domain_id",
|
||||||
"description": "Filters the response by a domain ID.",
|
"description": "Filters the response by a domain ID.",
|
||||||
"schema": {"type": "string", "format": "uuid"},
|
"schema": {"type": "string", "format": "uuid"},
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -135,10 +132,7 @@ ROLES_INFERENCE_SCHEMA: dict[str, Any] = {
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"prior_role": ROLE_INFO_SCHEMA,
|
"prior_role": ROLE_INFO_SCHEMA,
|
||||||
"implies": {
|
"implies": {"type": "array", "items": ROLE_INFO_SCHEMA},
|
||||||
"type": "array",
|
|
||||||
"items": ROLE_INFO_SCHEMA,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -153,10 +147,7 @@ ROLES_INFERENCES_SCHEMA: dict[str, Any] = {
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"prior_role": ROLE_INFO_SCHEMA,
|
"prior_role": ROLE_INFO_SCHEMA,
|
||||||
"implies": {
|
"implies": {"type": "array", "items": ROLE_INFO_SCHEMA},
|
||||||
"type": "array",
|
|
||||||
"items": ROLE_INFO_SCHEMA,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -213,10 +204,7 @@ ROLE_ASSIGNMENT_SCHEMA: dict[str, Any] = {
|
|||||||
"format": "uri",
|
"format": "uri",
|
||||||
"description": "a link to the assignment that gave rise to this entity",
|
"description": "a link to the assignment that gave rise to this entity",
|
||||||
},
|
},
|
||||||
"membership": {
|
"membership": {"type": "string", "format": "uri"},
|
||||||
"type": "string",
|
|
||||||
"format": "uri",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -298,16 +286,17 @@ ROLE_ASSIGNMENT_LIST_PARAMETERS: dict[str, Any] = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None = None):
|
def _post_process_operation_hook(
|
||||||
|
openapi_spec, operation_spec, path: str | None = None
|
||||||
|
):
|
||||||
"""Hook to allow service specific generator to modify details"""
|
"""Hook to allow service specific generator to modify details"""
|
||||||
operationId = operation_spec.operationId
|
operationId = operation_spec.operationId
|
||||||
|
|
||||||
if operationId == "roles:get":
|
if operationId == "roles:get":
|
||||||
for (
|
for key, val in ROLE_LIST_PARAMETERS.items():
|
||||||
key,
|
openapi_spec.components.parameters.setdefault(
|
||||||
val,
|
key, ParameterSchema(**val)
|
||||||
) in ROLE_LIST_PARAMETERS.items():
|
)
|
||||||
openapi_spec.components.parameters.setdefault(key, ParameterSchema(**val))
|
|
||||||
ref = f"#/components/parameters/{key}"
|
ref = f"#/components/parameters/{key}"
|
||||||
|
|
||||||
if ref not in [x.ref for x in operation_spec.parameters]:
|
if ref not in [x.ref for x in operation_spec.parameters]:
|
||||||
@ -317,10 +306,7 @@ def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None
|
|||||||
ROLE_ASSIGNMENTS_QUERY_PARAMETERS,
|
ROLE_ASSIGNMENTS_QUERY_PARAMETERS,
|
||||||
ROLE_ASSIGNMENT_LIST_PARAMETERS,
|
ROLE_ASSIGNMENT_LIST_PARAMETERS,
|
||||||
]:
|
]:
|
||||||
for (
|
for key, val in map.items():
|
||||||
key,
|
|
||||||
val,
|
|
||||||
) in map.items():
|
|
||||||
openapi_spec.components.parameters.setdefault(
|
openapi_spec.components.parameters.setdefault(
|
||||||
key, ParameterSchema(**val)
|
key, ParameterSchema(**val)
|
||||||
)
|
)
|
||||||
@ -329,11 +315,10 @@ def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None
|
|||||||
if ref not in [x.ref for x in operation_spec.parameters]:
|
if ref not in [x.ref for x in operation_spec.parameters]:
|
||||||
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
||||||
elif operationId == "role_assignments:head":
|
elif operationId == "role_assignments:head":
|
||||||
for (
|
for key, val in ROLE_ASSIGNMENTS_QUERY_PARAMETERS.items():
|
||||||
key,
|
openapi_spec.components.parameters.setdefault(
|
||||||
val,
|
key, ParameterSchema(**val)
|
||||||
) in ROLE_ASSIGNMENTS_QUERY_PARAMETERS.items():
|
)
|
||||||
openapi_spec.components.parameters.setdefault(key, ParameterSchema(**val))
|
|
||||||
ref = f"#/components/parameters/{key}"
|
ref = f"#/components/parameters/{key}"
|
||||||
|
|
||||||
if ref not in [x.ref for x in operation_spec.parameters]:
|
if ref not in [x.ref for x in operation_spec.parameters]:
|
||||||
@ -341,17 +326,15 @@ def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None
|
|||||||
|
|
||||||
|
|
||||||
def _get_schema_ref(
|
def _get_schema_ref(
|
||||||
openapi_spec,
|
openapi_spec, name, description=None, schema_def=None, action_name=None
|
||||||
name,
|
|
||||||
description=None,
|
|
||||||
schema_def=None,
|
|
||||||
action_name=None,
|
|
||||||
) -> tuple[str | None, str | None, bool]:
|
) -> tuple[str | None, str | None, bool]:
|
||||||
mime_type: str = "application/json"
|
mime_type: str = "application/json"
|
||||||
ref: str
|
ref: str
|
||||||
# Roles
|
# Roles
|
||||||
if name == "RolesGetResponse":
|
if name == "RolesGetResponse":
|
||||||
openapi_spec.components.schemas.setdefault(name, TypeSchema(**ROLES_SCHEMA))
|
openapi_spec.components.schemas.setdefault(
|
||||||
|
name, TypeSchema(**ROLES_SCHEMA)
|
||||||
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in [
|
||||||
"RolesPostRequest",
|
"RolesPostRequest",
|
||||||
@ -368,8 +351,7 @@ def _get_schema_ref(
|
|||||||
# Role Implies
|
# Role Implies
|
||||||
elif name == "RolesImpliesGetResponse":
|
elif name == "RolesImpliesGetResponse":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**ROLES_INFERENCE_SCHEMA)
|
||||||
TypeSchema(**ROLES_INFERENCE_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name == "RolesImplyGetResponse":
|
elif name == "RolesImplyGetResponse":
|
||||||
|
@ -33,10 +33,7 @@ SERVICE_SCHEMA: dict[str, Any] = {
|
|||||||
"description": "The UUID of the service to which the endpoint belongs.",
|
"description": "The UUID of the service to which the endpoint belongs.",
|
||||||
"readOnly": True,
|
"readOnly": True,
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {"type": "string", "description": "The service name."},
|
||||||
"type": "string",
|
|
||||||
"description": "The service name.",
|
|
||||||
},
|
|
||||||
"type": {
|
"type": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The service type, which describes the API implemented by the ",
|
"description": "The service type, which describes the API implemented by the ",
|
||||||
@ -60,38 +57,34 @@ SERVICES_LIST_PARAMETERS = {
|
|||||||
"name": "service",
|
"name": "service",
|
||||||
"description": "Filters the response by a domain ID.",
|
"description": "Filters the response by a domain ID.",
|
||||||
"schema": {"type": "string"},
|
"schema": {"type": "string"},
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None = None):
|
def _post_process_operation_hook(
|
||||||
|
openapi_spec, operation_spec, path: str | None = None
|
||||||
|
):
|
||||||
"""Hook to allow service specific generator to modify details"""
|
"""Hook to allow service specific generator to modify details"""
|
||||||
operationId = operation_spec.operationId
|
operationId = operation_spec.operationId
|
||||||
if operationId == "services:get":
|
if operationId == "services:get":
|
||||||
for (
|
for key, val in SERVICES_LIST_PARAMETERS.items():
|
||||||
key,
|
openapi_spec.components.parameters.setdefault(
|
||||||
val,
|
key, ParameterSchema(**val)
|
||||||
) in SERVICES_LIST_PARAMETERS.items():
|
)
|
||||||
openapi_spec.components.parameters.setdefault(key, ParameterSchema(**val))
|
|
||||||
ref = f"#/components/parameters/{key}"
|
ref = f"#/components/parameters/{key}"
|
||||||
if ref not in [x.ref for x in operation_spec.parameters]:
|
if ref not in [x.ref for x in operation_spec.parameters]:
|
||||||
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
||||||
|
|
||||||
|
|
||||||
def _get_schema_ref(
|
def _get_schema_ref(
|
||||||
openapi_spec,
|
openapi_spec, name, description=None, schema_def=None, action_name=None
|
||||||
name,
|
|
||||||
description=None,
|
|
||||||
schema_def=None,
|
|
||||||
action_name=None,
|
|
||||||
) -> tuple[str | None, str | None, bool]:
|
) -> tuple[str | None, str | None, bool]:
|
||||||
mime_type: str = "application/json"
|
mime_type: str = "application/json"
|
||||||
ref: str
|
ref: str
|
||||||
# ### Services
|
# ### Services
|
||||||
if name == "ServicesGetResponse":
|
if name == "ServicesGetResponse":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**SERVICES_SCHEMA)
|
||||||
TypeSchema(**SERVICES_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in [
|
||||||
@ -102,8 +95,7 @@ def _get_schema_ref(
|
|||||||
"ServicePatchResponse",
|
"ServicePatchResponse",
|
||||||
]:
|
]:
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
"Service",
|
"Service", TypeSchema(**SERVICE_CONTAINER_SCHEMA)
|
||||||
TypeSchema(**SERVICE_CONTAINER_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = "#/components/schemas/Service"
|
ref = "#/components/schemas/Service"
|
||||||
|
|
||||||
|
@ -99,12 +99,12 @@ USER_PWD_CHANGE_SCHEMA: dict[str, Any] = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Set `password` format for password change operation
|
# Set `password` format for password change operation
|
||||||
USER_PWD_CHANGE_SCHEMA["properties"]["user"]["properties"]["password"]["format"] = (
|
USER_PWD_CHANGE_SCHEMA["properties"]["user"]["properties"]["password"][
|
||||||
"password"
|
|
||||||
)
|
|
||||||
USER_PWD_CHANGE_SCHEMA["properties"]["user"]["properties"]["original_password"][
|
|
||||||
"format"
|
"format"
|
||||||
] = "password"
|
] = "password"
|
||||||
|
USER_PWD_CHANGE_SCHEMA["properties"]["user"]["properties"][
|
||||||
|
"original_password"
|
||||||
|
]["format"] = "password"
|
||||||
|
|
||||||
USER_GROUP_SCHEMA: dict[str, Any] = {
|
USER_GROUP_SCHEMA: dict[str, Any] = {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@ -123,10 +123,7 @@ USER_GROUP_SCHEMA: dict[str, Any] = {
|
|||||||
"format": "uuid",
|
"format": "uuid",
|
||||||
"description": "The ID of the group.",
|
"description": "The ID of the group.",
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {"type": "string", "description": "The name of the group."},
|
||||||
"type": "string",
|
|
||||||
"description": "The name of the group.",
|
|
||||||
},
|
|
||||||
"membership_expires_at": {
|
"membership_expires_at": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "date-time",
|
"format": "date-time",
|
||||||
@ -169,10 +166,7 @@ USER_PROJECT_SCHEMA: dict[str, Any] = {
|
|||||||
"format": "uuid",
|
"format": "uuid",
|
||||||
"description": "The parent id of the project.",
|
"description": "The parent id of the project.",
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {"type": "string", "description": "The name of the project."},
|
||||||
"type": "string",
|
|
||||||
"description": "The name of the project.",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,24 +182,24 @@ USER_PROJECTS_SCHEMA: dict[str, Any] = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _post_process_operation_hook(openapi_spec, operation_spec, path: str | None = None):
|
def _post_process_operation_hook(
|
||||||
|
openapi_spec, operation_spec, path: str | None = None
|
||||||
|
):
|
||||||
"""Hook to allow service specific generator to modify details"""
|
"""Hook to allow service specific generator to modify details"""
|
||||||
operationId = operation_spec.operationId
|
operationId = operation_spec.operationId
|
||||||
|
|
||||||
if operationId == "users:get":
|
if operationId == "users:get":
|
||||||
for key, val in USER_LIST_PARAMETERS.items():
|
for key, val in USER_LIST_PARAMETERS.items():
|
||||||
openapi_spec.components.parameters.setdefault(key, ParameterSchema(**val))
|
openapi_spec.components.parameters.setdefault(
|
||||||
|
key, ParameterSchema(**val)
|
||||||
|
)
|
||||||
ref = f"#/components/parameters/{key}"
|
ref = f"#/components/parameters/{key}"
|
||||||
if ref not in [x.ref for x in operation_spec.parameters]:
|
if ref not in [x.ref for x in operation_spec.parameters]:
|
||||||
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
operation_spec.parameters.append(ParameterSchema(ref=ref))
|
||||||
|
|
||||||
|
|
||||||
def _get_schema_ref(
|
def _get_schema_ref(
|
||||||
openapi_spec,
|
openapi_spec, name, description=None, schema_def=None, action_name=None
|
||||||
name,
|
|
||||||
description=None,
|
|
||||||
schema_def=None,
|
|
||||||
action_name=None,
|
|
||||||
) -> tuple[str | None, str | None, bool]:
|
) -> tuple[str | None, str | None, bool]:
|
||||||
mime_type: str = "application/json"
|
mime_type: str = "application/json"
|
||||||
ref: str
|
ref: str
|
||||||
@ -221,7 +215,9 @@ def _get_schema_ref(
|
|||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name == "UsersGetResponse":
|
elif name == "UsersGetResponse":
|
||||||
openapi_spec.components.schemas.setdefault(name, TypeSchema(**USERS_SCHEMA))
|
openapi_spec.components.schemas.setdefault(
|
||||||
|
name, TypeSchema(**USERS_SCHEMA)
|
||||||
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in ["UserGetResponse", "UserPostResponse", "UserPatchResponse"]:
|
elif name in ["UserGetResponse", "UserPostResponse", "UserPatchResponse"]:
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
@ -230,8 +226,7 @@ def _get_schema_ref(
|
|||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name == "UsersPasswordPostRequest":
|
elif name == "UsersPasswordPostRequest":
|
||||||
openapi_spec.components.schemas.setdefault(
|
openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name, TypeSchema(**USER_PWD_CHANGE_SCHEMA)
|
||||||
TypeSchema(**USER_PWD_CHANGE_SCHEMA),
|
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name == "UsersGroupsGetResponse":
|
elif name == "UsersGroupsGetResponse":
|
||||||
|
@ -15,17 +15,13 @@ from pathlib import Path
|
|||||||
|
|
||||||
from ruamel.yaml.scalarstring import LiteralScalarString
|
from ruamel.yaml.scalarstring import LiteralScalarString
|
||||||
|
|
||||||
from codegenerator.common.schema import (
|
from codegenerator.common.schema import SpecSchema
|
||||||
SpecSchema,
|
|
||||||
)
|
|
||||||
from codegenerator.openapi.base import OpenStackServerSourceBase
|
from codegenerator.openapi.base import OpenStackServerSourceBase
|
||||||
from codegenerator.openapi.utils import merge_api_ref_doc
|
from codegenerator.openapi.utils import merge_api_ref_doc
|
||||||
|
|
||||||
|
|
||||||
class ManilaGenerator(OpenStackServerSourceBase):
|
class ManilaGenerator(OpenStackServerSourceBase):
|
||||||
URL_TAG_MAP = {
|
URL_TAG_MAP = {"/versions": "version"}
|
||||||
"/versions": "version",
|
|
||||||
}
|
|
||||||
|
|
||||||
def _api_ver_major(self, ver):
|
def _api_ver_major(self, ver):
|
||||||
return ver._ver_major
|
return ver._ver_major
|
||||||
@ -57,11 +53,15 @@ class ManilaGenerator(OpenStackServerSourceBase):
|
|||||||
lock_path = self.useFixture(fixtures.TempDir()).path
|
lock_path = self.useFixture(fixtures.TempDir()).path
|
||||||
self.fixture = self.useFixture(config_fixture.Config(lockutils.CONF))
|
self.fixture = self.useFixture(config_fixture.Config(lockutils.CONF))
|
||||||
self.fixture.config(lock_path=lock_path, group="oslo_concurrency")
|
self.fixture.config(lock_path=lock_path, group="oslo_concurrency")
|
||||||
self.fixture.config(disable_process_locking=True, group="oslo_concurrency")
|
self.fixture.config(
|
||||||
|
disable_process_locking=True, group="oslo_concurrency"
|
||||||
|
)
|
||||||
|
|
||||||
rpc.init(CONF)
|
rpc.init(CONF)
|
||||||
|
|
||||||
CONF.set_override("backend_url", "file://" + lock_path, group="coordination")
|
CONF.set_override(
|
||||||
|
"backend_url", "file://" + lock_path, group="coordination"
|
||||||
|
)
|
||||||
coordination.LOCK_COORDINATOR.start()
|
coordination.LOCK_COORDINATOR.start()
|
||||||
|
|
||||||
# config = cfg.ConfigOpts()
|
# config = cfg.ConfigOpts()
|
||||||
@ -85,24 +85,24 @@ class ManilaGenerator(OpenStackServerSourceBase):
|
|||||||
openapi_spec = self.load_openapi(impl_path)
|
openapi_spec = self.load_openapi(impl_path)
|
||||||
if not openapi_spec:
|
if not openapi_spec:
|
||||||
openapi_spec = SpecSchema(
|
openapi_spec = SpecSchema(
|
||||||
info=dict(
|
info={
|
||||||
title="OpenStack Shared-File-System API",
|
"title": "OpenStack Shared-File-System API",
|
||||||
description=LiteralScalarString(
|
"description": LiteralScalarString(
|
||||||
"Shared File System API provided by Manila service"
|
"Shared File System API provided by Manila service"
|
||||||
),
|
),
|
||||||
version=self.api_version,
|
"version": self.api_version,
|
||||||
),
|
},
|
||||||
openapi="3.1.0",
|
openapi="3.1.0",
|
||||||
security=[{"ApiKeyAuth": []}],
|
security=[{"ApiKeyAuth": []}],
|
||||||
components=dict(
|
components={
|
||||||
securitySchemes={
|
"securitySchemes": {
|
||||||
"ApiKeyAuth": {
|
"ApiKeyAuth": {
|
||||||
"type": "apiKey",
|
"type": "apiKey",
|
||||||
"in": "header",
|
"in": "header",
|
||||||
"name": "X-Auth-Token",
|
"name": "X-Auth-Token",
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
),
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
for route in self.router.map.matchlist:
|
for route in self.router.map.matchlist:
|
||||||
@ -119,9 +119,7 @@ class ManilaGenerator(OpenStackServerSourceBase):
|
|||||||
|
|
||||||
if args.api_ref_src:
|
if args.api_ref_src:
|
||||||
merge_api_ref_doc(
|
merge_api_ref_doc(
|
||||||
openapi_spec,
|
openapi_spec, args.api_ref_src, allow_strip_version=False
|
||||||
args.api_ref_src,
|
|
||||||
allow_strip_version=False,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
self.dump_openapi(openapi_spec, impl_path, args.validate)
|
self.dump_openapi(openapi_spec, impl_path, args.validate)
|
||||||
|
@ -210,17 +210,11 @@ class NeutronGenerator(OpenStackServerSourceBase):
|
|||||||
fp.write(PASTE_CONFIG)
|
fp.write(PASTE_CONFIG)
|
||||||
|
|
||||||
neutron_config.init([])
|
neutron_config.init([])
|
||||||
cfg.CONF.set_override(
|
cfg.CONF.set_override("service_plugins", ["router", "vpnaas"])
|
||||||
"service_plugins",
|
|
||||||
[
|
|
||||||
"router",
|
|
||||||
"vpnaas",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
cfg.CONF.set_override(
|
cfg.CONF.set_override(
|
||||||
"service_provider",
|
"service_provider",
|
||||||
[
|
[
|
||||||
"VPN:dummy:neutron_vpnaas.tests.unit.dummy_ipsec.DummyIPsecVPNDriver:default",
|
"VPN:dummy:neutron_vpnaas.tests.unit.dummy_ipsec.DummyIPsecVPNDriver:default"
|
||||||
],
|
],
|
||||||
group="service_providers",
|
group="service_providers",
|
||||||
)
|
)
|
||||||
@ -261,27 +255,27 @@ class NeutronGenerator(OpenStackServerSourceBase):
|
|||||||
openapi_spec = self.load_openapi(Path(impl_path))
|
openapi_spec = self.load_openapi(Path(impl_path))
|
||||||
if not openapi_spec:
|
if not openapi_spec:
|
||||||
openapi_spec = SpecSchema(
|
openapi_spec = SpecSchema(
|
||||||
info=dict(
|
info={
|
||||||
title="OpenStack Network API",
|
"title": "OpenStack Network API",
|
||||||
description=LiteralScalarString(
|
"description": LiteralScalarString(
|
||||||
"Network API provided by Neutron service"
|
"Network API provided by Neutron service"
|
||||||
),
|
),
|
||||||
version=self.api_version,
|
"version": self.api_version,
|
||||||
),
|
},
|
||||||
openapi="3.1.0",
|
openapi="3.1.0",
|
||||||
security=[{"ApiKeyAuth": []}],
|
security=[{"ApiKeyAuth": []}],
|
||||||
tags=[],
|
tags=[],
|
||||||
paths={},
|
paths={},
|
||||||
components=dict(
|
components={
|
||||||
securitySchemes={
|
"securitySchemes": {
|
||||||
"ApiKeyAuth": {
|
"ApiKeyAuth": {
|
||||||
"type": "apiKey",
|
"type": "apiKey",
|
||||||
"in": "header",
|
"in": "header",
|
||||||
"name": "X-Auth-Token",
|
"name": "X-Auth-Token",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
headers={},
|
"headers": {},
|
||||||
parameters={
|
"parameters": {
|
||||||
"limit": ParameterSchema(
|
"limit": ParameterSchema(
|
||||||
name="limit",
|
name="limit",
|
||||||
location="query",
|
location="query",
|
||||||
@ -310,11 +304,13 @@ class NeutronGenerator(OpenStackServerSourceBase):
|
|||||||
name="sort_dir",
|
name="sort_dir",
|
||||||
location="query",
|
location="query",
|
||||||
description="Sort direction. This is an optional feature and may be silently ignored by the server.",
|
description="Sort direction. This is an optional feature and may be silently ignored by the server.",
|
||||||
type_schema=TypeSchema(type="string", enum=["asc", "desc"]),
|
type_schema=TypeSchema(
|
||||||
|
type="string", enum=["asc", "desc"]
|
||||||
|
),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
schemas={},
|
"schemas": {},
|
||||||
),
|
},
|
||||||
)
|
)
|
||||||
lnk = Path(impl_path.parent, "v2.yaml")
|
lnk = Path(impl_path.parent, "v2.yaml")
|
||||||
lnk.unlink(missing_ok=True)
|
lnk.unlink(missing_ok=True)
|
||||||
@ -363,7 +359,9 @@ class NeutronGenerator(OpenStackServerSourceBase):
|
|||||||
|
|
||||||
# merge descriptions from api-ref doc
|
# merge descriptions from api-ref doc
|
||||||
if args.api_ref_src:
|
if args.api_ref_src:
|
||||||
merge_api_ref_doc(openapi_spec, args.api_ref_src, allow_strip_version=False)
|
merge_api_ref_doc(
|
||||||
|
openapi_spec, args.api_ref_src, allow_strip_version=False
|
||||||
|
)
|
||||||
|
|
||||||
self.dump_openapi(openapi_spec, Path(impl_path), args.validate)
|
self.dump_openapi(openapi_spec, Path(impl_path), args.validate)
|
||||||
|
|
||||||
@ -378,39 +376,50 @@ class NeutronGenerator(OpenStackServerSourceBase):
|
|||||||
# continue
|
# continue
|
||||||
# if "networks" not in route.routepath:
|
# if "networks" not in route.routepath:
|
||||||
# continue
|
# continue
|
||||||
if route.routepath.endswith("/edit") or route.routepath.endswith("/new"):
|
if route.routepath.endswith("/edit") or route.routepath.endswith(
|
||||||
|
"/new"
|
||||||
|
):
|
||||||
# NEUTRON folks - please fix
|
# NEUTRON folks - please fix
|
||||||
logging.warning("Skipping processing %s route", route.routepath)
|
logging.warning(
|
||||||
|
"Skipping processing %s route", route.routepath
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
if "/qos/ports" in route.routepath or "/qos/networks" in route.routepath:
|
if (
|
||||||
|
"/qos/ports" in route.routepath
|
||||||
|
or "/qos/networks" in route.routepath
|
||||||
|
):
|
||||||
# NEUTRON folks - please fix
|
# NEUTRON folks - please fix
|
||||||
logging.warning("Skipping processing %s route", route.routepath)
|
logging.warning(
|
||||||
|
"Skipping processing %s route", route.routepath
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
if (
|
if (
|
||||||
route.routepath.endswith("/tags")
|
route.routepath.endswith("/tags")
|
||||||
and route.conditions["method"][0] == "POST"
|
and route.conditions["method"][0] == "POST"
|
||||||
):
|
):
|
||||||
logging.warning("Skipping processing POST %s route", route.routepath)
|
logging.warning(
|
||||||
|
"Skipping processing POST %s route", route.routepath
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
if route.routepath.startswith("/extensions") and route.conditions["method"][
|
if route.routepath.startswith("/extensions") and route.conditions[
|
||||||
0
|
|
||||||
] in ["POST", "DELETE", "PUT"]:
|
|
||||||
continue
|
|
||||||
if route.routepath.startswith("/availability_zones") and route.conditions[
|
|
||||||
"method"
|
"method"
|
||||||
][0] in ["POST", "DELETE", "PUT"]:
|
][0] in ["POST", "DELETE", "PUT"]:
|
||||||
continue
|
continue
|
||||||
if route.routepath.startswith("/availability_zones/") and route.conditions[
|
if route.routepath.startswith(
|
||||||
"method"
|
"/availability_zones"
|
||||||
][0] in ["GET"]:
|
) and route.conditions["method"][0] in ["POST", "DELETE", "PUT"]:
|
||||||
|
continue
|
||||||
|
if route.routepath.startswith(
|
||||||
|
"/availability_zones/"
|
||||||
|
) and route.conditions["method"][0] in ["GET"]:
|
||||||
# There is no "show" for AZ
|
# There is no "show" for AZ
|
||||||
continue
|
continue
|
||||||
if route.routepath in ["/quotas/tenant", "/quotas/project"]:
|
if route.routepath in ["/quotas/tenant", "/quotas/project"]:
|
||||||
# Tenant and Project quota are not a thing
|
# Tenant and Project quota are not a thing
|
||||||
continue
|
continue
|
||||||
if route.routepath == "/quotas" and route.conditions["method"][0] in [
|
if route.routepath == "/quotas" and route.conditions["method"][
|
||||||
"POST"
|
0
|
||||||
]:
|
] in ["POST"]:
|
||||||
# Tenant and Project quota is the same
|
# Tenant and Project quota is the same
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@ -496,8 +505,12 @@ class NeutronGenerator(OpenStackServerSourceBase):
|
|||||||
path += part
|
path += part
|
||||||
|
|
||||||
if "method" not in route.conditions:
|
if "method" not in route.conditions:
|
||||||
raise RuntimeError("Method not set for %s" % route)
|
raise RuntimeError(f"Method not set for {route}")
|
||||||
method = route.conditions.get("method", "GET")[0] if route.conditions else "GET"
|
method = (
|
||||||
|
route.conditions.get("method", "GET")[0]
|
||||||
|
if route.conditions
|
||||||
|
else "GET"
|
||||||
|
)
|
||||||
|
|
||||||
wsgi_controller = controller or route.defaults["controller"]
|
wsgi_controller = controller or route.defaults["controller"]
|
||||||
# collection_name = route.collection_name
|
# collection_name = route.collection_name
|
||||||
@ -523,7 +536,9 @@ class NeutronGenerator(OpenStackServerSourceBase):
|
|||||||
logging.warning("Skipping duplicated route %s", processed_key)
|
logging.warning("Skipping duplicated route %s", processed_key)
|
||||||
return
|
return
|
||||||
|
|
||||||
logging.info("Path: %s; method: %s; operation: %s", path, method, action)
|
logging.info(
|
||||||
|
"Path: %s; method: %s; operation: %s", path, method, action
|
||||||
|
)
|
||||||
|
|
||||||
# Get Path elements
|
# Get Path elements
|
||||||
path_elements: list[str] = list(filter(None, path.split("/")))
|
path_elements: list[str] = list(filter(None, path.split("/")))
|
||||||
@ -554,15 +569,17 @@ class NeutronGenerator(OpenStackServerSourceBase):
|
|||||||
for path_element in path_elements:
|
for path_element in path_elements:
|
||||||
if "{" in path_element:
|
if "{" in path_element:
|
||||||
param_name = path_element.strip("{}")
|
param_name = path_element.strip("{}")
|
||||||
global_param_name = f"{global_param_name_prefix}_{param_name}".replace(
|
global_param_name = (
|
||||||
":", "_"
|
f"{global_param_name_prefix}_{param_name}".replace(
|
||||||
|
":", "_"
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
if global_param_name == "_project_id":
|
if global_param_name == "_project_id":
|
||||||
global_param_name = "project_id"
|
global_param_name = "project_id"
|
||||||
param_ref_name = f"#/components/parameters/{global_param_name}"
|
param_ref_name = f"#/components/parameters/{global_param_name}"
|
||||||
# Ensure reference to the param is in the path_params
|
# Ensure reference to the param is in the path_params
|
||||||
if param_ref_name not in [k.ref for k in [p for p in path_params]]:
|
if param_ref_name not in [k.ref for k in list(path_params)]:
|
||||||
path_params.append(ParameterSchema(ref=param_ref_name))
|
path_params.append(ParameterSchema(ref=param_ref_name))
|
||||||
# Ensure global parameter is present
|
# Ensure global parameter is present
|
||||||
path_param = ParameterSchema(
|
path_param = ParameterSchema(
|
||||||
@ -570,10 +587,14 @@ class NeutronGenerator(OpenStackServerSourceBase):
|
|||||||
)
|
)
|
||||||
# openapi_spec.components["parameters"].setdefault(global_param_name, dict())
|
# openapi_spec.components["parameters"].setdefault(global_param_name, dict())
|
||||||
if not path_param.description:
|
if not path_param.description:
|
||||||
path_param.description = f"{param_name} parameter for {path} API"
|
path_param.description = (
|
||||||
|
f"{param_name} parameter for {path} API"
|
||||||
|
)
|
||||||
# We can only assume the param type. For path it is logically a string only
|
# We can only assume the param type. For path it is logically a string only
|
||||||
path_param.type_schema = TypeSchema(type="string")
|
path_param.type_schema = TypeSchema(type="string")
|
||||||
openapi_spec.components.parameters[global_param_name] = path_param
|
openapi_spec.components.parameters[global_param_name] = (
|
||||||
|
path_param
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
path_resource_names.append(path_element.replace("-", "_"))
|
path_resource_names.append(path_element.replace("-", "_"))
|
||||||
|
|
||||||
@ -591,7 +612,8 @@ class NeutronGenerator(OpenStackServerSourceBase):
|
|||||||
operation_id = re.sub(
|
operation_id = re.sub(
|
||||||
r"^(/?v[0-9.]*/)",
|
r"^(/?v[0-9.]*/)",
|
||||||
"",
|
"",
|
||||||
"/".join([x.strip("{}") for x in path_elements]) + f":{method.lower()}", # noqa
|
"/".join([x.strip("{}") for x in path_elements])
|
||||||
|
+ f":{method.lower()}", # noqa
|
||||||
)
|
)
|
||||||
|
|
||||||
path_spec = openapi_spec.paths.setdefault(
|
path_spec = openapi_spec.paths.setdefault(
|
||||||
@ -629,10 +651,7 @@ class NeutronGenerator(OpenStackServerSourceBase):
|
|||||||
method=None,
|
method=None,
|
||||||
path=None,
|
path=None,
|
||||||
):
|
):
|
||||||
logging.info(
|
logging.info("Operation: %s", operation_name)
|
||||||
"Operation: %s",
|
|
||||||
operation_name,
|
|
||||||
)
|
|
||||||
|
|
||||||
attr_info = getattr(controller, "_attr_info", {})
|
attr_info = getattr(controller, "_attr_info", {})
|
||||||
collection = getattr(controller, "_collection", None)
|
collection = getattr(controller, "_collection", None)
|
||||||
@ -675,16 +694,22 @@ class NeutronGenerator(OpenStackServerSourceBase):
|
|||||||
for field, data in attr_info.items():
|
for field, data in attr_info.items():
|
||||||
# operation_spec.setdefault("parameters", [])
|
# operation_spec.setdefault("parameters", [])
|
||||||
if data.get("is_filter", False):
|
if data.get("is_filter", False):
|
||||||
global_param_name = f"{collection}_{field}".replace(":", "_")
|
global_param_name = f"{collection}_{field}".replace(
|
||||||
param_ref_name = f"#/components/parameters/{global_param_name}"
|
":", "_"
|
||||||
|
)
|
||||||
|
param_ref_name = (
|
||||||
|
f"#/components/parameters/{global_param_name}"
|
||||||
|
)
|
||||||
# Ensure global parameter is present
|
# Ensure global parameter is present
|
||||||
query_param = openapi_spec.components.parameters.setdefault(
|
query_param = (
|
||||||
global_param_name,
|
openapi_spec.components.parameters.setdefault(
|
||||||
ParameterSchema(
|
global_param_name,
|
||||||
location="query",
|
ParameterSchema(
|
||||||
name=field,
|
location="query",
|
||||||
type_schema=get_schema(data),
|
name=field,
|
||||||
),
|
type_schema=get_schema(data),
|
||||||
|
),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
if not query_param.description:
|
if not query_param.description:
|
||||||
query_param.description = (
|
query_param.description = (
|
||||||
@ -715,7 +740,9 @@ class NeutronGenerator(OpenStackServerSourceBase):
|
|||||||
)
|
)
|
||||||
query_param.style = "form"
|
query_param.style = "form"
|
||||||
query_param.explode = False
|
query_param.explode = False
|
||||||
if param_ref_name not in [x.ref for x in operation_spec.parameters]:
|
if param_ref_name not in [
|
||||||
|
x.ref for x in operation_spec.parameters
|
||||||
|
]:
|
||||||
operation_spec.parameters.append(
|
operation_spec.parameters.append(
|
||||||
ParameterSchema(ref=param_ref_name)
|
ParameterSchema(ref=param_ref_name)
|
||||||
)
|
)
|
||||||
@ -755,7 +782,9 @@ class NeutronGenerator(OpenStackServerSourceBase):
|
|||||||
response_code = "204"
|
response_code = "204"
|
||||||
|
|
||||||
if response_code:
|
if response_code:
|
||||||
rsp = responses_spec.setdefault(response_code, dict(description="Ok"))
|
rsp = responses_spec.setdefault(
|
||||||
|
response_code, {"description": "Ok"}
|
||||||
|
)
|
||||||
if response_code != "204" and method != "DELETE":
|
if response_code != "204" and method != "DELETE":
|
||||||
# Arrange response placeholder
|
# Arrange response placeholder
|
||||||
schema_name = (
|
schema_name = (
|
||||||
@ -799,8 +828,7 @@ class NeutronGenerator(OpenStackServerSourceBase):
|
|||||||
schema = openapi_spec.components.schemas.setdefault(
|
schema = openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name,
|
||||||
TypeSchema(
|
TypeSchema(
|
||||||
type="object",
|
type="object", description=LiteralScalarString(description)
|
||||||
description=LiteralScalarString(description),
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
# Here come schemas that are not present in Neutron
|
# Here come schemas that are not present in Neutron
|
||||||
@ -849,8 +877,12 @@ class NeutronGenerator(OpenStackServerSourceBase):
|
|||||||
"QuotasDefaultDefaultResponse",
|
"QuotasDefaultDefaultResponse",
|
||||||
"QuotasProjectProjectResponse",
|
"QuotasProjectProjectResponse",
|
||||||
]:
|
]:
|
||||||
schema.properties = {"quota": copy.deepcopy(neutron_schemas.QUOTA_SCHEMA)}
|
schema.properties = {
|
||||||
elif name.endswith("TagUpdateRequest") or name.endswith("TagUpdateResponse"):
|
"quota": copy.deepcopy(neutron_schemas.QUOTA_SCHEMA)
|
||||||
|
}
|
||||||
|
elif name.endswith("TagUpdateRequest") or name.endswith(
|
||||||
|
"TagUpdateResponse"
|
||||||
|
):
|
||||||
# PUT tag does not have request body
|
# PUT tag does not have request body
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -885,12 +917,16 @@ class NeutronGenerator(OpenStackServerSourceBase):
|
|||||||
send_props = {}
|
send_props = {}
|
||||||
return_props = {}
|
return_props = {}
|
||||||
# Consume request name to required fields mapping
|
# Consume request name to required fields mapping
|
||||||
required_fields = neutron_schemas.REQUIRED_FIELDS_MAPPING.get(name, [])
|
required_fields = neutron_schemas.REQUIRED_FIELDS_MAPPING.get(
|
||||||
|
name, []
|
||||||
|
)
|
||||||
for field, data in schema_def.items():
|
for field, data in schema_def.items():
|
||||||
js_schema = get_schema(data)
|
js_schema = get_schema(data)
|
||||||
# Dirty hacks for corrupted schemas
|
# Dirty hacks for corrupted schemas
|
||||||
if field in ["availability_zones", "tags"]:
|
if field in ["availability_zones", "tags"]:
|
||||||
js_schema.update({"type": "array", "items": {"type": "string"}})
|
js_schema.update(
|
||||||
|
{"type": "array", "items": {"type": "string"}}
|
||||||
|
)
|
||||||
elif field == "revision_number":
|
elif field == "revision_number":
|
||||||
js_schema.update({"type": "integer"})
|
js_schema.update({"type": "integer"})
|
||||||
elif field == "subnets":
|
elif field == "subnets":
|
||||||
@ -917,14 +953,15 @@ class NeutronGenerator(OpenStackServerSourceBase):
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "hostname",
|
"format": "hostname",
|
||||||
},
|
},
|
||||||
"ip_address": {
|
"ip_address": {"type": "string"},
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
elif resource_key == "floatingip" and field == "port_forwardings":
|
elif (
|
||||||
|
resource_key == "floatingip"
|
||||||
|
and field == "port_forwardings"
|
||||||
|
):
|
||||||
js_schema.update(
|
js_schema.update(
|
||||||
{
|
{
|
||||||
"type": "array",
|
"type": "array",
|
||||||
@ -1014,7 +1051,8 @@ class NeutronGenerator(OpenStackServerSourceBase):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
elif (
|
elif (
|
||||||
resource_key == "security_group" and field == "security_group_rules"
|
resource_key == "security_group"
|
||||||
|
and field == "security_group_rules"
|
||||||
):
|
):
|
||||||
js_schema.update(
|
js_schema.update(
|
||||||
{
|
{
|
||||||
@ -1085,7 +1123,9 @@ class NeutronGenerator(OpenStackServerSourceBase):
|
|||||||
"maxLength": 255,
|
"maxLength": 255,
|
||||||
"description": "A human-readable description for the resource.",
|
"description": "A human-readable description for the resource.",
|
||||||
},
|
},
|
||||||
"normalized_cidr": {"type": ["string", "null"]},
|
"normalized_cidr": {
|
||||||
|
"type": ["string", "null"]
|
||||||
|
},
|
||||||
"remote_address_group_id": {
|
"remote_address_group_id": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The remote address group UUID that is associated with this\nsecurity group rule.",
|
"description": "The remote address group UUID that is associated with this\nsecurity group rule.",
|
||||||
@ -1112,7 +1152,9 @@ class NeutronGenerator(OpenStackServerSourceBase):
|
|||||||
"items": {
|
"items": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": (
|
"properties": (
|
||||||
send_props if name.endswith("Request") else return_props
|
send_props
|
||||||
|
if name.endswith("Request")
|
||||||
|
else return_props
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -1123,7 +1165,9 @@ class NeutronGenerator(OpenStackServerSourceBase):
|
|||||||
resource_key: {
|
resource_key: {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": (
|
"properties": (
|
||||||
send_props if name.endswith("Request") else return_props
|
send_props
|
||||||
|
if name.endswith("Request")
|
||||||
|
else return_props
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1132,7 +1176,7 @@ class NeutronGenerator(OpenStackServerSourceBase):
|
|||||||
required_fields
|
required_fields
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
logging.warning("No Schema information for %s" % name)
|
logging.warning(f"No Schema information for {name}")
|
||||||
|
|
||||||
return f"#/components/schemas/{name}"
|
return f"#/components/schemas/{name}"
|
||||||
|
|
||||||
@ -1287,34 +1331,22 @@ def get_schema(param_data):
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
elif "type:list_of_any_key_specs_or_none" in validate:
|
elif "type:list_of_any_key_specs_or_none" in validate:
|
||||||
logging.warning("TODO: Implement type:list_of_any_key_specs_or_none")
|
logging.warning(
|
||||||
|
"TODO: Implement type:list_of_any_key_specs_or_none"
|
||||||
|
)
|
||||||
schema = {
|
schema = {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {"type": "object", "extraProperties": True},
|
||||||
"type": "object",
|
|
||||||
"extraProperties": True,
|
|
||||||
},
|
|
||||||
"x-openstack": {"todo": "implementme"},
|
"x-openstack": {"todo": "implementme"},
|
||||||
}
|
}
|
||||||
elif "type:subnet_list" in validate:
|
elif "type:subnet_list" in validate:
|
||||||
schema = {
|
schema = {"type": "array", "items": {"type": "string"}}
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
elif "type:service_plugin_type" in validate:
|
elif "type:service_plugin_type" in validate:
|
||||||
schema = {
|
schema = {"type": "string"}
|
||||||
"type": "string",
|
|
||||||
}
|
|
||||||
elif "type:ip_address" in validate:
|
elif "type:ip_address" in validate:
|
||||||
schema = {
|
schema = {"type": "string"}
|
||||||
"type": "string",
|
|
||||||
}
|
|
||||||
elif "type:ip_address_or_none" in validate:
|
elif "type:ip_address_or_none" in validate:
|
||||||
schema = {
|
schema = {"type": "string"}
|
||||||
"type": "string",
|
|
||||||
}
|
|
||||||
elif "type:subnet_or_none" in validate:
|
elif "type:subnet_or_none" in validate:
|
||||||
schema = {"type": ["string", "null"]}
|
schema = {"type": ["string", "null"]}
|
||||||
elif "type:fip_dns_host_name" in validate:
|
elif "type:fip_dns_host_name" in validate:
|
||||||
@ -1346,19 +1378,12 @@ def get_schema(param_data):
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
elif "type:nameservers" in validate:
|
elif "type:nameservers" in validate:
|
||||||
schema = {
|
schema = {"type": "array", "items": {"type": "string"}}
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
elif "type:list_of_subnet_service_types" in validate:
|
elif "type:list_of_subnet_service_types" in validate:
|
||||||
schema = {
|
schema = {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"description": "The service types associated with the subnet",
|
"description": "The service types associated with the subnet",
|
||||||
"items": {
|
"items": {"type": "string"},
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
elif "type:dict_or_nodata" in validate:
|
elif "type:dict_or_nodata" in validate:
|
||||||
schema = get_schema(validate["type:dict_or_nodata"])
|
schema = get_schema(validate["type:dict_or_nodata"])
|
||||||
@ -1367,7 +1392,7 @@ def get_schema(param_data):
|
|||||||
elif "type:list_of_subnets_or_none" in validate:
|
elif "type:list_of_subnets_or_none" in validate:
|
||||||
schema = {"type": "array", "items": {"type": "string"}}
|
schema = {"type": "array", "items": {"type": "string"}}
|
||||||
else:
|
else:
|
||||||
raise RuntimeError("Unsupported type %s in %s" % (validate, param_data))
|
raise RuntimeError(f"Unsupported type {validate} in {param_data}")
|
||||||
schema = {"type": "string"}
|
schema = {"type": "string"}
|
||||||
if convert_to:
|
if convert_to:
|
||||||
# Nice way to get type of the field, isn't it?
|
# Nice way to get type of the field, isn't it?
|
||||||
|
@ -167,10 +167,7 @@ ROUTER_UPDATE_INTERFACE_REQUEST_SCHEMA: dict[str, Any] = {
|
|||||||
"description": "The ID of the port. One of subnet_id or port_id must be specified.",
|
"description": "The ID of the port. One of subnet_id or port_id must be specified.",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"oneOf": [
|
"oneOf": [{"required": ["subnet_id"]}, {"required": ["port_id"]}],
|
||||||
{"required": ["subnet_id"]},
|
|
||||||
{"required": ["port_id"]},
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ROUTER_INTERFACE_RESPONSE_SCHEMA: dict[str, Any] = {
|
ROUTER_INTERFACE_RESPONSE_SCHEMA: dict[str, Any] = {
|
||||||
@ -189,10 +186,7 @@ ROUTER_INTERFACE_RESPONSE_SCHEMA: dict[str, Any] = {
|
|||||||
"subnet_ids": {
|
"subnet_ids": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"description": "A list of the ID of the subnet which the router interface belongs to. The list contains only one member.",
|
"description": "A list of the ID of the subnet which the router interface belongs to. The list contains only one member.",
|
||||||
"items": {
|
"items": {"type": "string", "format": "uuid"},
|
||||||
"type": "string",
|
|
||||||
"format": "uuid",
|
|
||||||
},
|
|
||||||
"minItems": 1,
|
"minItems": 1,
|
||||||
"maxItems": 1,
|
"maxItems": 1,
|
||||||
},
|
},
|
||||||
@ -237,23 +231,17 @@ ROUTER_UPDATE_EXTRAROUTES_REQUEST_SCHEMA: dict[str, Any] = {
|
|||||||
"items": {
|
"items": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"destination": {
|
"destination": {"type": "string"},
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"nexthop": {
|
"nexthop": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{
|
{"format": "ipv4"},
|
||||||
"format": "ipv4",
|
{"format": "ipv6"},
|
||||||
},
|
|
||||||
{
|
|
||||||
"format": "ipv6",
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -281,18 +269,12 @@ ROUTER_EXTRAROUTES_RESPONSE_SCHEMA: dict[str, Any] = {
|
|||||||
"items": {
|
"items": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"destination": {
|
"destination": {"type": "string"},
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"nexthop": {
|
"nexthop": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{
|
{"format": "ipv4"},
|
||||||
"format": "ipv4",
|
{"format": "ipv6"},
|
||||||
},
|
|
||||||
{
|
|
||||||
"format": "ipv6",
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -306,9 +288,7 @@ ROUTER_EXTRAROUTES_RESPONSE_SCHEMA: dict[str, Any] = {
|
|||||||
EXTERNAL_GATEWAY_SCHEMA: dict[str, Any] = {
|
EXTERNAL_GATEWAY_SCHEMA: dict[str, Any] = {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"enable_snat": {
|
"enable_snat": {"type": "boolean"},
|
||||||
"type": "boolean",
|
|
||||||
},
|
|
||||||
"external_fixed_ips": {
|
"external_fixed_ips": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
@ -316,15 +296,9 @@ EXTERNAL_GATEWAY_SCHEMA: dict[str, Any] = {
|
|||||||
"properties": {
|
"properties": {
|
||||||
"ip_address": {
|
"ip_address": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"oneOf": [
|
"oneOf": [{"format": "ipv4"}, {"format": "ipv6"}],
|
||||||
{"format": "ipv4"},
|
|
||||||
{"format": "ipv6"},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"subnet_id": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "uuid",
|
|
||||||
},
|
},
|
||||||
|
"subnet_id": {"type": "string", "format": "uuid"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -343,7 +317,7 @@ ROUTER_ADD_EXTERNAL_GATEWAYS_REQUEST_SCHEMA: dict[str, Any] = {
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"description": "The list of external gateways of the router.",
|
"description": "The list of external gateways of the router.",
|
||||||
"items": EXTERNAL_GATEWAY_SCHEMA,
|
"items": EXTERNAL_GATEWAY_SCHEMA,
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -352,15 +326,15 @@ ROUTER_ADD_EXTERNAL_GATEWAYS_REQUEST_SCHEMA: dict[str, Any] = {
|
|||||||
ROUTER_UPDATE_EXTERNAL_GATEWAYS_REQUEST_SCHEMA: dict[str, Any] = copy.deepcopy(
|
ROUTER_UPDATE_EXTERNAL_GATEWAYS_REQUEST_SCHEMA: dict[str, Any] = copy.deepcopy(
|
||||||
ROUTER_ADD_EXTERNAL_GATEWAYS_REQUEST_SCHEMA
|
ROUTER_ADD_EXTERNAL_GATEWAYS_REQUEST_SCHEMA
|
||||||
)
|
)
|
||||||
ROUTER_UPDATE_EXTERNAL_GATEWAYS_REQUEST_SCHEMA["properties"]["router"]["properties"][
|
ROUTER_UPDATE_EXTERNAL_GATEWAYS_REQUEST_SCHEMA["properties"]["router"][
|
||||||
"external_gateways"
|
"properties"
|
||||||
]["items"]["properties"]["network_id"]["readOnly"] = True
|
]["external_gateways"]["items"]["properties"]["network_id"]["readOnly"] = True
|
||||||
ROUTER_REMOVE_EXTERNAL_GATEWAYS_REQUEST_SCHEMA: dict[str, Any] = copy.deepcopy(
|
ROUTER_REMOVE_EXTERNAL_GATEWAYS_REQUEST_SCHEMA: dict[str, Any] = copy.deepcopy(
|
||||||
ROUTER_ADD_EXTERNAL_GATEWAYS_REQUEST_SCHEMA
|
ROUTER_ADD_EXTERNAL_GATEWAYS_REQUEST_SCHEMA
|
||||||
)
|
)
|
||||||
ROUTER_REMOVE_EXTERNAL_GATEWAYS_REQUEST_SCHEMA["properties"]["router"]["properties"][
|
ROUTER_REMOVE_EXTERNAL_GATEWAYS_REQUEST_SCHEMA["properties"]["router"][
|
||||||
"external_gateways"
|
"properties"
|
||||||
]["items"]["properties"].pop("enable_snat")
|
]["external_gateways"]["items"]["properties"].pop("enable_snat")
|
||||||
|
|
||||||
ADDRESS_GROUP_ADDRESS_SCHEMA: dict[str, Any] = {
|
ADDRESS_GROUP_ADDRESS_SCHEMA: dict[str, Any] = {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@ -371,9 +345,7 @@ ADDRESS_GROUP_ADDRESS_SCHEMA: dict[str, Any] = {
|
|||||||
"addresses": {
|
"addresses": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"description": "A list of IP addresses.",
|
"description": "A list of IP addresses.",
|
||||||
"items": {
|
"items": {"type": "string"},
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -474,10 +446,7 @@ L3_ROUTER_AGENTS_SCHEMA: dict[str, Any] = {
|
|||||||
|
|
||||||
|
|
||||||
def _get_schema_ref(
|
def _get_schema_ref(
|
||||||
openapi_spec,
|
openapi_spec, name, description=None, schema_def=None
|
||||||
name,
|
|
||||||
description=None,
|
|
||||||
schema_def=None,
|
|
||||||
) -> tuple[str | None, str | None, bool]:
|
) -> tuple[str | None, str | None, bool]:
|
||||||
mime_type: str = "application/json"
|
mime_type: str = "application/json"
|
||||||
ref: str
|
ref: str
|
||||||
@ -518,12 +487,18 @@ def _get_schema_ref(
|
|||||||
**ROUTER_ADD_EXTERNAL_GATEWAYS_REQUEST_SCHEMA
|
**ROUTER_ADD_EXTERNAL_GATEWAYS_REQUEST_SCHEMA
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name == "RoutersUpdate_External_GatewaysUpdate_External_GatewaysRequest":
|
elif (
|
||||||
|
name
|
||||||
|
== "RoutersUpdate_External_GatewaysUpdate_External_GatewaysRequest"
|
||||||
|
):
|
||||||
openapi_spec.components.schemas[name] = TypeSchema(
|
openapi_spec.components.schemas[name] = TypeSchema(
|
||||||
**ROUTER_UPDATE_EXTERNAL_GATEWAYS_REQUEST_SCHEMA
|
**ROUTER_UPDATE_EXTERNAL_GATEWAYS_REQUEST_SCHEMA
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name == "RoutersRemove_External_GatewaysRemove_External_GatewaysRequest":
|
elif (
|
||||||
|
name
|
||||||
|
== "RoutersRemove_External_GatewaysRemove_External_GatewaysRequest"
|
||||||
|
):
|
||||||
openapi_spec.components.schemas[name] = TypeSchema(
|
openapi_spec.components.schemas[name] = TypeSchema(
|
||||||
**ROUTER_REMOVE_EXTERNAL_GATEWAYS_REQUEST_SCHEMA
|
**ROUTER_REMOVE_EXTERNAL_GATEWAYS_REQUEST_SCHEMA
|
||||||
)
|
)
|
||||||
@ -552,10 +527,14 @@ def _get_schema_ref(
|
|||||||
ref = "#/components/schemas/Address_GroupShowResponse"
|
ref = "#/components/schemas/Address_GroupShowResponse"
|
||||||
|
|
||||||
elif name == "AgentsL3_RoutersIndexResponse":
|
elif name == "AgentsL3_RoutersIndexResponse":
|
||||||
openapi_spec.components.schemas[name] = TypeSchema(**L3_ROUTER_AGENTS_SCHEMA)
|
openapi_spec.components.schemas[name] = TypeSchema(
|
||||||
|
**L3_ROUTER_AGENTS_SCHEMA
|
||||||
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name == "AgentsL3_RoutersIndexResponse":
|
elif name == "AgentsL3_RoutersIndexResponse":
|
||||||
openapi_spec.components.schemas[name] = TypeSchema(**L3_ROUTER_AGENTS_SCHEMA)
|
openapi_spec.components.schemas[name] = TypeSchema(
|
||||||
|
**L3_ROUTER_AGENTS_SCHEMA
|
||||||
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name == "AgentsL3_RoutersCreateRequest":
|
elif name == "AgentsL3_RoutersCreateRequest":
|
||||||
openapi_spec.components.schemas[name] = TypeSchema(
|
openapi_spec.components.schemas[name] = TypeSchema(
|
||||||
|
@ -68,24 +68,24 @@ class NovaGenerator(OpenStackServerSourceBase):
|
|||||||
openapi_spec = self.load_openapi(impl_path)
|
openapi_spec = self.load_openapi(impl_path)
|
||||||
if not openapi_spec:
|
if not openapi_spec:
|
||||||
openapi_spec = SpecSchema(
|
openapi_spec = SpecSchema(
|
||||||
info=dict(
|
info={
|
||||||
title="OpenStack Compute API",
|
"title": "OpenStack Compute API",
|
||||||
description=LiteralScalarString(
|
"description": LiteralScalarString(
|
||||||
"Compute API provided by Nova service"
|
"Compute API provided by Nova service"
|
||||||
),
|
),
|
||||||
version=self.api_version,
|
"version": self.api_version,
|
||||||
),
|
},
|
||||||
openapi="3.1.0",
|
openapi="3.1.0",
|
||||||
security=[{"ApiKeyAuth": []}],
|
security=[{"ApiKeyAuth": []}],
|
||||||
components=dict(
|
components={
|
||||||
securitySchemes={
|
"securitySchemes": {
|
||||||
"ApiKeyAuth": {
|
"ApiKeyAuth": {
|
||||||
"type": "apiKey",
|
"type": "apiKey",
|
||||||
"in": "header",
|
"in": "header",
|
||||||
"name": "X-Auth-Token",
|
"name": "X-Auth-Token",
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
),
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
for route in self.router.map.matchlist:
|
for route in self.router.map.matchlist:
|
||||||
@ -226,7 +226,9 @@ class NovaGenerator(OpenStackServerSourceBase):
|
|||||||
]:
|
]:
|
||||||
schema = openapi_spec.components.schemas.setdefault(
|
schema = openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name,
|
||||||
TypeSchema(**nova_schemas.SERVER_ACTION_CREATE_IMAGE_RESPONSE_SCHEMA),
|
TypeSchema(
|
||||||
|
**nova_schemas.SERVER_ACTION_CREATE_IMAGE_RESPONSE_SCHEMA
|
||||||
|
),
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in [
|
||||||
@ -241,7 +243,9 @@ class NovaGenerator(OpenStackServerSourceBase):
|
|||||||
elif name == "ServersActionOs-GetconsoleoutputResponse":
|
elif name == "ServersActionOs-GetconsoleoutputResponse":
|
||||||
schema = openapi_spec.components.schemas.setdefault(
|
schema = openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name,
|
||||||
TypeSchema(**nova_schemas.SERVER_ACTION_GET_CONSOLE_OUTPUT_SCHEMA),
|
TypeSchema(
|
||||||
|
**nova_schemas.SERVER_ACTION_GET_CONSOLE_OUTPUT_SCHEMA
|
||||||
|
),
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
elif name in [
|
elif name in [
|
||||||
@ -271,7 +275,9 @@ class NovaGenerator(OpenStackServerSourceBase):
|
|||||||
elif name == "ServersIpShowResponse":
|
elif name == "ServersIpShowResponse":
|
||||||
schema = openapi_spec.components.schemas.setdefault(
|
schema = openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name,
|
||||||
TypeSchema(maxProperties=1, **nova_schemas.SERVER_ADDRESSES_SCHEMA),
|
TypeSchema(
|
||||||
|
maxProperties=1, **nova_schemas.SERVER_ADDRESSES_SCHEMA
|
||||||
|
),
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
# /servers/id/metadata
|
# /servers/id/metadata
|
||||||
@ -299,7 +305,9 @@ class NovaGenerator(OpenStackServerSourceBase):
|
|||||||
elif name == "ServersOs_Instance_ActionShowResponse":
|
elif name == "ServersOs_Instance_ActionShowResponse":
|
||||||
schema = openapi_spec.components.schemas.setdefault(
|
schema = openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name,
|
||||||
TypeSchema(**nova_schemas.SERVER_INSTANCE_ACTION_CONTAINER_SCHEMA),
|
TypeSchema(
|
||||||
|
**nova_schemas.SERVER_INSTANCE_ACTION_CONTAINER_SCHEMA
|
||||||
|
),
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
# /server/id/os-interface-attachment
|
# /server/id/os-interface-attachment
|
||||||
@ -315,7 +323,9 @@ class NovaGenerator(OpenStackServerSourceBase):
|
|||||||
]:
|
]:
|
||||||
schema = openapi_spec.components.schemas.setdefault(
|
schema = openapi_spec.components.schemas.setdefault(
|
||||||
name,
|
name,
|
||||||
TypeSchema(**nova_schemas.INTERFACE_ATTACHMENT_CONTAINER_SCHEMA),
|
TypeSchema(
|
||||||
|
**nova_schemas.INTERFACE_ATTACHMENT_CONTAINER_SCHEMA
|
||||||
|
),
|
||||||
)
|
)
|
||||||
ref = f"#/components/schemas/{name}"
|
ref = f"#/components/schemas/{name}"
|
||||||
# /server/id/os-server-password
|
# /server/id/os-server-password
|
||||||
@ -639,8 +649,12 @@ class NovaGenerator(OpenStackServerSourceBase):
|
|||||||
"""Hook to allow service specific generator to modify details"""
|
"""Hook to allow service specific generator to modify details"""
|
||||||
if operation_spec.operationId == "servers/id/action:post":
|
if operation_spec.operationId == "servers/id/action:post":
|
||||||
# Sereral server actions may return Location header
|
# Sereral server actions may return Location header
|
||||||
operation_spec.responses.setdefault("202", {"description": "Accepted"})
|
operation_spec.responses.setdefault(
|
||||||
headers_202 = operation_spec.responses["202"].setdefault("headers", {})
|
"202", {"description": "Accepted"}
|
||||||
|
)
|
||||||
|
headers_202 = operation_spec.responses["202"].setdefault(
|
||||||
|
"headers", {}
|
||||||
|
)
|
||||||
headers_202.setdefault(
|
headers_202.setdefault(
|
||||||
"Location",
|
"Location",
|
||||||
HeaderSchema(
|
HeaderSchema(
|
||||||
|
@ -44,9 +44,7 @@ SERVER_TAGS_SCHEMA: dict[str, Any] = {
|
|||||||
"tags": {
|
"tags": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"description": "A list of tags. The maximum count of tags in this list is 50.",
|
"description": "A list of tags. The maximum count of tags in this list is 50.",
|
||||||
"items": {
|
"items": {"type": "string"},
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -65,9 +63,7 @@ SERVER_TOPOLOGY_SCHEMA: dict[str, Any] = {
|
|||||||
"cpu_pinning": {
|
"cpu_pinning": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "The mapping of server cores to host physical CPU",
|
"description": "The mapping of server cores to host physical CPU",
|
||||||
"additionalProperties": {
|
"additionalProperties": {"type": "integer"},
|
||||||
"type": "integer",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"vcpu_set": {
|
"vcpu_set": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
@ -192,7 +188,9 @@ FLAVORS_LIST_SCHEMA: dict[str, Any] = {
|
|||||||
FLAVORS_LIST_DETAIL_SCHEMA: dict[str, Any] = {
|
FLAVORS_LIST_DETAIL_SCHEMA: dict[str, Any] = {
|
||||||
"description": "Detailed flavors list response",
|
"description": "Detailed flavors list response",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {"flavors": {"type": "array", "items": copy.deepcopy(FLAVOR_SCHEMA)}},
|
"properties": {
|
||||||
|
"flavors": {"type": "array", "items": copy.deepcopy(FLAVOR_SCHEMA)}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
FLAVOR_ACCESS_SCHEMA: dict[str, Any] = {
|
FLAVOR_ACCESS_SCHEMA: dict[str, Any] = {
|
||||||
@ -270,7 +268,7 @@ LIMITS_SCHEMA: dict[str, Any] = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"additionalProperties": {"type": "integer"},
|
"additionalProperties": {"type": "integer"},
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -467,16 +465,16 @@ REMOTE_CONSOLE_SCHEMA: dict[str, Any] = {
|
|||||||
"properties": {
|
"properties": {
|
||||||
"protocol": {
|
"protocol": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": remote_consoles.create_v28["properties"]["remote_console"][
|
"enum": remote_consoles.create_v28["properties"][
|
||||||
"properties"
|
"remote_console"
|
||||||
]["protocol"]["enum"],
|
]["properties"]["protocol"]["enum"],
|
||||||
"description": "The protocol of remote console. The valid values are vnc, spice, rdp, serial and mks. The protocol mks is added since Microversion 2.8.",
|
"description": "The protocol of remote console. The valid values are vnc, spice, rdp, serial and mks. The protocol mks is added since Microversion 2.8.",
|
||||||
},
|
},
|
||||||
"type": {
|
"type": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": remote_consoles.create_v28["properties"]["remote_console"][
|
"enum": remote_consoles.create_v28["properties"][
|
||||||
"properties"
|
"remote_console"
|
||||||
]["type"]["enum"],
|
]["properties"]["type"]["enum"],
|
||||||
"description": "The type of remote console. The valid values are novnc, rdp-html5, spice-html5, serial, and webmks. The type webmks is added since Microversion 2.8.",
|
"description": "The type of remote console. The valid values are novnc, rdp-html5, spice-html5, serial, and webmks. The type webmks is added since Microversion 2.8.",
|
||||||
},
|
},
|
||||||
"url": {
|
"url": {
|
||||||
@ -786,9 +784,7 @@ KEYPAIR_LIST_SCHEMA: dict[str, Any] = {
|
|||||||
"description": "Array of Keypair objects",
|
"description": "Array of Keypair objects",
|
||||||
"items": {
|
"items": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {"keypair": copy.deepcopy(KEYPAIR_SHORT_SCHEMA)},
|
||||||
"keypair": copy.deepcopy(KEYPAIR_SHORT_SCHEMA),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"keypairs_links": copy.deepcopy(LINKS_SCHEMA),
|
"keypairs_links": copy.deepcopy(LINKS_SCHEMA),
|
||||||
@ -833,8 +829,12 @@ KEYPAIR_CONTAINER_SCHEMA: dict[str, Any] = {
|
|||||||
"properties": {"keypair": KEYPAIR_SCHEMA},
|
"properties": {"keypair": KEYPAIR_SCHEMA},
|
||||||
}
|
}
|
||||||
|
|
||||||
KEYPAIR_CREATED_SCHEMA: dict[str, Any] = copy.deepcopy(KEYPAIR_CONTAINER_SCHEMA)
|
KEYPAIR_CREATED_SCHEMA: dict[str, Any] = copy.deepcopy(
|
||||||
KEYPAIR_CREATED_SCHEMA["properties"]["keypair"]["properties"]["private_key"] = {
|
KEYPAIR_CONTAINER_SCHEMA
|
||||||
|
)
|
||||||
|
KEYPAIR_CREATED_SCHEMA["properties"]["keypair"]["properties"][
|
||||||
|
"private_key"
|
||||||
|
] = {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "If you do not provide a public key on create, a new keypair will be built for you, and the private key will be returned during the initial create call. Make sure to save this, as there is no way to get this private key again in the future.",
|
"description": "If you do not provide a public key on create, a new keypair will be built for you, and the private key will be returned during the initial create call. Make sure to save this, as there is no way to get this private key again in the future.",
|
||||||
"x-openstack": {"max-ver": "2.91"},
|
"x-openstack": {"max-ver": "2.91"},
|
||||||
@ -1031,7 +1031,7 @@ SERVER_MIGRATION_LIST_SCHEMA: dict[str, Any] = {
|
|||||||
"migrations": {
|
"migrations": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": copy.deepcopy(SERVER_MIGRATION_SCHEMA),
|
"items": copy.deepcopy(SERVER_MIGRATION_SCHEMA),
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
SERVER_MIGRATION_CONTAINER_SCHEMA: dict[str, Any] = {
|
SERVER_MIGRATION_CONTAINER_SCHEMA: dict[str, Any] = {
|
||||||
@ -1272,7 +1272,7 @@ SERVER_GROUP_SCHEMA: dict[str, Any] = {
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "The rules field, which is a dict, can be applied to the policy. Currently, only the max_server_per_host rule is supported for the anti-affinity policy. The max_server_per_host rule allows specifying how many members of the anti-affinity group can reside on the same compute host. If not specified, only one member from the same anti-affinity group can reside on a given host.",
|
"description": "The rules field, which is a dict, can be applied to the policy. Currently, only the max_server_per_host rule is supported for the anti-affinity policy. The max_server_per_host rule allows specifying how many members of the anti-affinity group can reside on the same compute host. If not specified, only one member from the same anti-affinity group can reside on a given host.",
|
||||||
"properties": {
|
"properties": {
|
||||||
"max_server_per_host": parameter_types.positive_integer,
|
"max_server_per_host": parameter_types.positive_integer
|
||||||
},
|
},
|
||||||
"additionalProperties": False,
|
"additionalProperties": False,
|
||||||
"x-openstack": {"min-ver": "2.64"},
|
"x-openstack": {"min-ver": "2.64"},
|
||||||
@ -2267,7 +2267,7 @@ SERVER_SECURITY_GROUPS_LIST_SCHEMA: dict[str, Any] = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,24 +179,24 @@ class OctaviaGenerator(OpenStackServerSourceBase):
|
|||||||
openapi_spec = self.load_openapi(Path(impl_path))
|
openapi_spec = self.load_openapi(Path(impl_path))
|
||||||
if not openapi_spec:
|
if not openapi_spec:
|
||||||
openapi_spec = SpecSchema(
|
openapi_spec = SpecSchema(
|
||||||
info=dict(
|
info={
|
||||||
title="OpenStack Load Balancing API",
|
"title": "OpenStack Load Balancing API",
|
||||||
description=LiteralScalarString(
|
"description": LiteralScalarString(
|
||||||
"Load Balancing API provided by Octavia service"
|
"Load Balancing API provided by Octavia service"
|
||||||
),
|
),
|
||||||
version=self.api_version,
|
"version": self.api_version,
|
||||||
),
|
},
|
||||||
openapi="3.1.0",
|
openapi="3.1.0",
|
||||||
security=[{"ApiKeyAuth": []}],
|
security=[{"ApiKeyAuth": []}],
|
||||||
components=dict(
|
components={
|
||||||
securitySchemes={
|
"securitySchemes": {
|
||||||
"ApiKeyAuth": {
|
"ApiKeyAuth": {
|
||||||
"type": "apiKey",
|
"type": "apiKey",
|
||||||
"in": "header",
|
"in": "header",
|
||||||
"name": "X-Auth-Token",
|
"name": "X-Auth-Token",
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
),
|
},
|
||||||
)
|
)
|
||||||
config.register_cli_opts()
|
config.register_cli_opts()
|
||||||
|
|
||||||
@ -385,7 +385,9 @@ class OctaviaGenerator(OpenStackServerSourceBase):
|
|||||||
self._process_route(route, openapi_spec, framework="pecan")
|
self._process_route(route, openapi_spec, framework="pecan")
|
||||||
|
|
||||||
if args.api_ref_src:
|
if args.api_ref_src:
|
||||||
merge_api_ref_doc(openapi_spec, args.api_ref_src, allow_strip_version=False)
|
merge_api_ref_doc(
|
||||||
|
openapi_spec, args.api_ref_src, allow_strip_version=False
|
||||||
|
)
|
||||||
|
|
||||||
self.dump_openapi(openapi_spec, Path(impl_path), args.validate)
|
self.dump_openapi(openapi_spec, Path(impl_path), args.validate)
|
||||||
|
|
||||||
|
@ -15,17 +15,13 @@ from pathlib import Path
|
|||||||
|
|
||||||
from ruamel.yaml.scalarstring import LiteralScalarString
|
from ruamel.yaml.scalarstring import LiteralScalarString
|
||||||
|
|
||||||
from codegenerator.common.schema import (
|
from codegenerator.common.schema import SpecSchema
|
||||||
SpecSchema,
|
|
||||||
)
|
|
||||||
from codegenerator.openapi.base import OpenStackServerSourceBase
|
from codegenerator.openapi.base import OpenStackServerSourceBase
|
||||||
from codegenerator.openapi.utils import merge_api_ref_doc
|
from codegenerator.openapi.utils import merge_api_ref_doc
|
||||||
|
|
||||||
|
|
||||||
class PlacementGenerator(OpenStackServerSourceBase):
|
class PlacementGenerator(OpenStackServerSourceBase):
|
||||||
URL_TAG_MAP = {
|
URL_TAG_MAP = {"/versions": "version"}
|
||||||
"/versions": "version",
|
|
||||||
}
|
|
||||||
|
|
||||||
def _api_ver_major(self, ver):
|
def _api_ver_major(self, ver):
|
||||||
return ver.ver_major
|
return ver.ver_major
|
||||||
@ -65,24 +61,24 @@ class PlacementGenerator(OpenStackServerSourceBase):
|
|||||||
openapi_spec = self.load_openapi(impl_path)
|
openapi_spec = self.load_openapi(impl_path)
|
||||||
if not openapi_spec:
|
if not openapi_spec:
|
||||||
openapi_spec = SpecSchema(
|
openapi_spec = SpecSchema(
|
||||||
info=dict(
|
info={
|
||||||
title="OpenStack Placement API",
|
"title": "OpenStack Placement API",
|
||||||
description=LiteralScalarString(
|
"description": LiteralScalarString(
|
||||||
"Placement API provided by Placement service"
|
"Placement API provided by Placement service"
|
||||||
),
|
),
|
||||||
version=self.api_version,
|
"version": self.api_version,
|
||||||
),
|
},
|
||||||
openapi="3.1.0",
|
openapi="3.1.0",
|
||||||
security=[{"ApiKeyAuth": []}],
|
security=[{"ApiKeyAuth": []}],
|
||||||
components=dict(
|
components={
|
||||||
securitySchemes={
|
"securitySchemes": {
|
||||||
"ApiKeyAuth": {
|
"ApiKeyAuth": {
|
||||||
"type": "apiKey",
|
"type": "apiKey",
|
||||||
"in": "header",
|
"in": "header",
|
||||||
"name": "X-Auth-Token",
|
"name": "X-Auth-Token",
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
),
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
for route in self.router.matchlist:
|
for route in self.router.matchlist:
|
||||||
@ -92,9 +88,7 @@ class PlacementGenerator(OpenStackServerSourceBase):
|
|||||||
|
|
||||||
if args.api_ref_src:
|
if args.api_ref_src:
|
||||||
merge_api_ref_doc(
|
merge_api_ref_doc(
|
||||||
openapi_spec,
|
openapi_spec, args.api_ref_src, allow_strip_version=False
|
||||||
args.api_ref_src,
|
|
||||||
allow_strip_version=False,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
self.dump_openapi(openapi_spec, impl_path, args.validate)
|
self.dump_openapi(openapi_spec, impl_path, args.validate)
|
||||||
|
@ -40,7 +40,7 @@ def merge_api_ref_doc(
|
|||||||
processed_operations: set[str] = set()
|
processed_operations: set[str] = set()
|
||||||
# Iterate over api-ref docs
|
# Iterate over api-ref docs
|
||||||
for api_ref_doc in api_ref_src:
|
for api_ref_doc in api_ref_src:
|
||||||
with open(api_ref_doc, "r") as fp:
|
with open(api_ref_doc) as fp:
|
||||||
html_doc = fp.read()
|
html_doc = fp.read()
|
||||||
|
|
||||||
# openapi_spec = jsonref.replace_refs(openapi_spec)
|
# openapi_spec = jsonref.replace_refs(openapi_spec)
|
||||||
@ -71,7 +71,9 @@ def merge_api_ref_doc(
|
|||||||
# TODO(gtema): notes are aside of main "p" and not
|
# TODO(gtema): notes are aside of main "p" and not
|
||||||
# underneath
|
# underneath
|
||||||
# Iterate over URLs
|
# Iterate over URLs
|
||||||
operation_url_containers = section.find_all("div", class_="operation-grp")
|
operation_url_containers = section.find_all(
|
||||||
|
"div", class_="operation-grp"
|
||||||
|
)
|
||||||
for op in operation_url_containers:
|
for op in operation_url_containers:
|
||||||
ep = op.find("div", class_="endpoint-container")
|
ep = op.find("div", class_="endpoint-container")
|
||||||
ep_divs = ep.find_all("div")
|
ep_divs = ep.find_all("div")
|
||||||
@ -108,7 +110,9 @@ def merge_api_ref_doc(
|
|||||||
# Paths have different length. Skip
|
# Paths have different length. Skip
|
||||||
continue
|
continue
|
||||||
is_search_aborted = False
|
is_search_aborted = False
|
||||||
for source, doc in zip(existing_path_parts, doc_url_parts):
|
for source, doc in zip(
|
||||||
|
existing_path_parts, doc_url_parts
|
||||||
|
):
|
||||||
source_ = source.strip("{}")
|
source_ = source.strip("{}")
|
||||||
doc_ = doc.strip("{}")
|
doc_ = doc.strip("{}")
|
||||||
if (
|
if (
|
||||||
@ -147,18 +151,19 @@ def merge_api_ref_doc(
|
|||||||
break
|
break
|
||||||
|
|
||||||
if not path_spec:
|
if not path_spec:
|
||||||
logging.info("Cannot find path %s in the spec" % url)
|
logging.info(f"Cannot find path {url} in the spec")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
op_spec = getattr(path_spec, method.lower(), None)
|
op_spec = getattr(path_spec, method.lower(), None)
|
||||||
if not op_spec:
|
if not op_spec:
|
||||||
logging.warn(
|
logging.warn(
|
||||||
"Cannot find %s operation for %s in the spec" % (method, url)
|
f"Cannot find {method} operation for {url} in the spec"
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if op_spec.operationId in processed_operations and not url.endswith(
|
if (
|
||||||
"/action"
|
op_spec.operationId in processed_operations
|
||||||
|
and not url.endswith("/action")
|
||||||
):
|
):
|
||||||
# Do not update operation we have already processed
|
# Do not update operation we have already processed
|
||||||
continue
|
continue
|
||||||
@ -169,7 +174,9 @@ def merge_api_ref_doc(
|
|||||||
# details section
|
# details section
|
||||||
details_button = op.find("button")
|
details_button = op.find("button")
|
||||||
details_section_id = details_button["data-target"].strip("#")
|
details_section_id = details_button["data-target"].strip("#")
|
||||||
details_section = section.find("section", id=details_section_id)
|
details_section = section.find(
|
||||||
|
"section", id=details_section_id
|
||||||
|
)
|
||||||
description = []
|
description = []
|
||||||
action_name = None
|
action_name = None
|
||||||
# Gather description section paragraphs to construct operation description
|
# Gather description section paragraphs to construct operation description
|
||||||
@ -179,9 +186,11 @@ def merge_api_ref_doc(
|
|||||||
|
|
||||||
elif details_child.name == "section":
|
elif details_child.name == "section":
|
||||||
if (
|
if (
|
||||||
details_child.h3 and "Request" in details_child.h3.strings
|
details_child.h3
|
||||||
|
and "Request" in details_child.h3.strings
|
||||||
) or (
|
) or (
|
||||||
details_child.h4 and "Request" in details_child.h4.strings
|
details_child.h4
|
||||||
|
and "Request" in details_child.h4.strings
|
||||||
):
|
):
|
||||||
# Found request details
|
# Found request details
|
||||||
if not details_child.table:
|
if not details_child.table:
|
||||||
@ -210,13 +219,15 @@ def merge_api_ref_doc(
|
|||||||
method,
|
method,
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
(schema_specs, action_name) = _get_schema_candidates(
|
(schema_specs, action_name) = (
|
||||||
openapi_spec,
|
_get_schema_candidates(
|
||||||
url,
|
openapi_spec,
|
||||||
spec_body,
|
url,
|
||||||
action_name,
|
spec_body,
|
||||||
summary,
|
action_name,
|
||||||
description,
|
summary,
|
||||||
|
description,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
_doc_process_operation_table(
|
_doc_process_operation_table(
|
||||||
@ -235,13 +246,15 @@ def merge_api_ref_doc(
|
|||||||
details_child.h3
|
details_child.h3
|
||||||
and (
|
and (
|
||||||
"Response" in details_child.h3.strings
|
"Response" in details_child.h3.strings
|
||||||
or "Response Parameters" in details_child.h3.strings
|
or "Response Parameters"
|
||||||
|
in details_child.h3.strings
|
||||||
)
|
)
|
||||||
) or (
|
) or (
|
||||||
details_child.h4
|
details_child.h4
|
||||||
and (
|
and (
|
||||||
"Response" in details_child.h4.strings
|
"Response" in details_child.h4.strings
|
||||||
or "Response Parameters" in details_child.h4.strings
|
or "Response Parameters"
|
||||||
|
in details_child.h4.strings
|
||||||
)
|
)
|
||||||
):
|
):
|
||||||
# Found response details
|
# Found response details
|
||||||
@ -275,8 +288,10 @@ def merge_api_ref_doc(
|
|||||||
op_spec.operationId,
|
op_spec.operationId,
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
(schema_specs, action_name) = _get_schema_candidates(
|
(schema_specs, action_name) = (
|
||||||
openapi_spec, url, spec_body, action_name
|
_get_schema_candidates(
|
||||||
|
openapi_spec, url, spec_body, action_name
|
||||||
|
)
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
_doc_process_operation_table(
|
_doc_process_operation_table(
|
||||||
@ -301,11 +316,7 @@ def merge_api_ref_doc(
|
|||||||
|
|
||||||
|
|
||||||
def _doc_process_operation_table(
|
def _doc_process_operation_table(
|
||||||
tbody,
|
tbody, openapi_spec, op_spec, schema_specs, doc_source_param_mapping
|
||||||
openapi_spec,
|
|
||||||
op_spec,
|
|
||||||
schema_specs,
|
|
||||||
doc_source_param_mapping,
|
|
||||||
):
|
):
|
||||||
"""Process DOC table (Request/Reseponse) and try to set description to
|
"""Process DOC table (Request/Reseponse) and try to set description to
|
||||||
the matching schema property"""
|
the matching schema property"""
|
||||||
@ -335,7 +346,9 @@ def _doc_process_operation_table(
|
|||||||
param_def.location == doc_param_location
|
param_def.location == doc_param_location
|
||||||
and param_def.name == doc_param_name
|
and param_def.name == doc_param_name
|
||||||
):
|
):
|
||||||
param_def.description = LiteralScalarString(doc_param_descr)
|
param_def.description = LiteralScalarString(
|
||||||
|
doc_param_descr
|
||||||
|
)
|
||||||
elif doc_param_location == "body":
|
elif doc_param_location == "body":
|
||||||
# Body param. Traverse through body information
|
# Body param. Traverse through body information
|
||||||
for schema in schema_specs:
|
for schema in schema_specs:
|
||||||
@ -362,7 +375,9 @@ def _find_schema_property(schema, target_prop_name):
|
|||||||
return
|
return
|
||||||
for prop_name, prop_def in props.items():
|
for prop_name, prop_def in props.items():
|
||||||
prop_type = (
|
prop_type = (
|
||||||
prop_def.get("type") if isinstance(prop_def, dict) else prop_def.type
|
prop_def.get("type")
|
||||||
|
if isinstance(prop_def, dict)
|
||||||
|
else prop_def.type
|
||||||
)
|
)
|
||||||
if prop_name == target_prop_name:
|
if prop_name == target_prop_name:
|
||||||
return prop_def
|
return prop_def
|
||||||
@ -397,7 +412,9 @@ def _find_schema_property(schema, target_prop_name):
|
|||||||
|
|
||||||
elif xtype == "array":
|
elif xtype == "array":
|
||||||
items_schema = (
|
items_schema = (
|
||||||
schema.items if isinstance(schema, TypeSchema) else schema.get("items")
|
schema.items
|
||||||
|
if isinstance(schema, TypeSchema)
|
||||||
|
else schema.get("items")
|
||||||
)
|
)
|
||||||
candidate = _find_schema_property(items_schema, target_prop_name)
|
candidate = _find_schema_property(items_schema, target_prop_name)
|
||||||
if candidate:
|
if candidate:
|
||||||
@ -434,7 +451,9 @@ def _get_schema_candidates(
|
|||||||
ref = spec_body.get("$ref")
|
ref = spec_body.get("$ref")
|
||||||
oneOf = spec_body.get("oneOf")
|
oneOf = spec_body.get("oneOf")
|
||||||
if spec_body and ref:
|
if spec_body and ref:
|
||||||
candidate_schema = openapi_spec.components.schemas.get(ref.split("/")[-1])
|
candidate_schema = openapi_spec.components.schemas.get(
|
||||||
|
ref.split("/")[-1]
|
||||||
|
)
|
||||||
if candidate_schema.oneOf:
|
if candidate_schema.oneOf:
|
||||||
for x in candidate_schema.oneOf:
|
for x in candidate_schema.oneOf:
|
||||||
ref = x.get("$ref") if isinstance(x, dict) else x.ref
|
ref = x.get("$ref") if isinstance(x, dict) else x.ref
|
||||||
@ -476,7 +495,9 @@ def _get_schema_candidates(
|
|||||||
|
|
||||||
elif not action_name and section_description:
|
elif not action_name and section_description:
|
||||||
if candidate_action_name and (
|
if candidate_action_name and (
|
||||||
re.search(rf"\b{candidate_action_name}\b", section_summary)
|
re.search(
|
||||||
|
rf"\b{candidate_action_name}\b", section_summary
|
||||||
|
)
|
||||||
or (
|
or (
|
||||||
url.endswith("/volumes/{volume_id}/action")
|
url.endswith("/volumes/{volume_id}/action")
|
||||||
# Cinder doc does not contain action name in the
|
# Cinder doc does not contain action name in the
|
||||||
@ -496,7 +517,9 @@ def _get_schema_candidates(
|
|||||||
itms = res.get("oneOf")
|
itms = res.get("oneOf")
|
||||||
if itms:
|
if itms:
|
||||||
for itm in itms:
|
for itm in itms:
|
||||||
schema_specs.append(get_schema(openapi_spec, itm))
|
schema_specs.append(
|
||||||
|
get_schema(openapi_spec, itm)
|
||||||
|
)
|
||||||
schema_specs.append(res)
|
schema_specs.append(res)
|
||||||
# Set the action name. Since
|
# Set the action name. Since
|
||||||
# Request normally comes before
|
# Request normally comes before
|
||||||
|
@ -72,7 +72,7 @@ class OpenApiSchemaGenerator(BaseGenerator):
|
|||||||
self, res, target_dir, openapi_spec=None, operation_id=None, args=None
|
self, res, target_dir, openapi_spec=None, operation_id=None, args=None
|
||||||
):
|
):
|
||||||
"""Generate Schema definition file for Resource"""
|
"""Generate Schema definition file for Resource"""
|
||||||
logging.debug("Generating OpenAPI schema data in %s" % target_dir)
|
logging.debug(f"Generating OpenAPI schema data in {target_dir}")
|
||||||
# We do not import generators since due to the use of Singletons in the
|
# We do not import generators since due to the use of Singletons in the
|
||||||
# code importing glance, nova, cinder at the same time crashes
|
# code importing glance, nova, cinder at the same time crashes
|
||||||
# dramatically
|
# dramatically
|
||||||
@ -93,4 +93,6 @@ class OpenApiSchemaGenerator(BaseGenerator):
|
|||||||
elif args.service_type == "shared-file-system":
|
elif args.service_type == "shared-file-system":
|
||||||
self.generate_manila(target_dir, args)
|
self.generate_manila(target_dir, args)
|
||||||
else:
|
else:
|
||||||
raise RuntimeError("Service type %s is not supported", args.service_type)
|
raise RuntimeError(
|
||||||
|
"Service type %s is not supported", args.service_type
|
||||||
|
)
|
||||||
|
@ -42,21 +42,23 @@ class OSCGenerator(BaseGenerator):
|
|||||||
|
|
||||||
def generate(self, res, target_dir, args=None):
|
def generate(self, res, target_dir, args=None):
|
||||||
"""Generate code for the OpenStackClient"""
|
"""Generate code for the OpenStackClient"""
|
||||||
logging.debug("Generating OpenStackClient code in %s" % target_dir)
|
logging.debug(f"Generating OpenStackClient code in {target_dir}")
|
||||||
osc_path = res.mod_name.split(".")[1:]
|
osc_path = res.mod_name.split(".")[1:]
|
||||||
|
|
||||||
context = dict(
|
context = {
|
||||||
res=res.resource_class,
|
"res": res.resource_class,
|
||||||
sdk_mod_name=res.mod_name,
|
"sdk_mod_name": res.mod_name,
|
||||||
osc_mod_name=res.mod_name.replace("openstack.", "openstackclient."),
|
"osc_mod_name": res.mod_name.replace(
|
||||||
class_name=res.class_name,
|
"openstack.", "openstackclient."
|
||||||
resource_name=res.class_name.lower(),
|
),
|
||||||
sdk_service_name=res.service_name,
|
"class_name": res.class_name,
|
||||||
proxy=res.proxy_obj,
|
"resource_name": res.class_name.lower(),
|
||||||
fqcn=res.fqcn,
|
"sdk_service_name": res.service_name,
|
||||||
registry_name=res.registry_name,
|
"proxy": res.proxy_obj,
|
||||||
attrs=res.attrs,
|
"fqcn": res.fqcn,
|
||||||
)
|
"registry_name": res.registry_name,
|
||||||
|
"attrs": res.attrs,
|
||||||
|
}
|
||||||
|
|
||||||
work_dir = Path(target_dir)
|
work_dir = Path(target_dir)
|
||||||
work_dir.mkdir(parents=True, exist_ok=True)
|
work_dir.mkdir(parents=True, exist_ok=True)
|
||||||
@ -78,7 +80,9 @@ class OSCGenerator(BaseGenerator):
|
|||||||
context,
|
context,
|
||||||
osc_path,
|
osc_path,
|
||||||
"osc/impl_list.py.j2",
|
"osc/impl_list.py.j2",
|
||||||
Path(work_dir, "openstackclient", "/".join(osc_path), "list.py"),
|
Path(
|
||||||
|
work_dir, "openstackclient", "/".join(osc_path), "list.py"
|
||||||
|
),
|
||||||
"osc/test_unit_list.py.j2",
|
"osc/test_unit_list.py.j2",
|
||||||
Path(
|
Path(
|
||||||
work_dir,
|
work_dir,
|
||||||
@ -96,7 +100,9 @@ class OSCGenerator(BaseGenerator):
|
|||||||
context,
|
context,
|
||||||
osc_path,
|
osc_path,
|
||||||
"osc/impl_show.py.j2",
|
"osc/impl_show.py.j2",
|
||||||
Path(work_dir, "openstackclient", "/".join(osc_path), "show.py"),
|
Path(
|
||||||
|
work_dir, "openstackclient", "/".join(osc_path), "show.py"
|
||||||
|
),
|
||||||
"osc/test_unit_show.py.j2",
|
"osc/test_unit_show.py.j2",
|
||||||
Path(
|
Path(
|
||||||
work_dir,
|
work_dir,
|
||||||
@ -161,10 +167,7 @@ class OSCGenerator(BaseGenerator):
|
|||||||
osc_path,
|
osc_path,
|
||||||
"osc/impl_set.py.j2",
|
"osc/impl_set.py.j2",
|
||||||
Path(
|
Path(
|
||||||
work_dir,
|
work_dir, "openstackclient", "/".join(osc_path), "set.py"
|
||||||
"openstackclient",
|
|
||||||
"/".join(osc_path),
|
|
||||||
"set.py",
|
|
||||||
),
|
),
|
||||||
"osc/test_unit_set.py.j2",
|
"osc/test_unit_set.py.j2",
|
||||||
Path(
|
Path(
|
||||||
@ -183,10 +186,7 @@ class OSCGenerator(BaseGenerator):
|
|||||||
osc_path,
|
osc_path,
|
||||||
"osc/impl_unset.py.j2",
|
"osc/impl_unset.py.j2",
|
||||||
Path(
|
Path(
|
||||||
work_dir,
|
work_dir, "openstackclient", "/".join(osc_path), "unset.py"
|
||||||
"openstackclient",
|
|
||||||
"/".join(osc_path),
|
|
||||||
"unset.py",
|
|
||||||
),
|
),
|
||||||
"osc/test_unit_unset.py.j2",
|
"osc/test_unit_unset.py.j2",
|
||||||
Path(
|
Path(
|
||||||
|
@ -41,7 +41,7 @@ class BooleanFlag(common_rust.Boolean):
|
|||||||
"""Boolean parameter that is represented as a CLI flag"""
|
"""Boolean parameter that is represented as a CLI flag"""
|
||||||
|
|
||||||
type_hint: str = "bool"
|
type_hint: str = "bool"
|
||||||
clap_macros: set[str] = set(["action=clap::ArgAction::SetTrue"])
|
clap_macros: set[str] = {"action=clap::ArgAction::SetTrue"}
|
||||||
original_data_type: BaseCompoundType | BasePrimitiveType | None = None
|
original_data_type: BaseCompoundType | BasePrimitiveType | None = None
|
||||||
|
|
||||||
|
|
||||||
@ -58,14 +58,14 @@ class String(common_rust.String):
|
|||||||
@property
|
@property
|
||||||
def imports(self) -> set[str]:
|
def imports(self) -> set[str]:
|
||||||
if self.format and self.format == "password":
|
if self.format and self.format == "password":
|
||||||
return set(["dialoguer::Password"])
|
return {"dialoguer::Password"}
|
||||||
return set([])
|
return set()
|
||||||
|
|
||||||
|
|
||||||
class IntString(common.BasePrimitiveType):
|
class IntString(common.BasePrimitiveType):
|
||||||
"""CLI Integer or String"""
|
"""CLI Integer or String"""
|
||||||
|
|
||||||
imports: set[str] = set(["crate::common::IntString"])
|
imports: set[str] = {"crate::common::IntString"}
|
||||||
type_hint: str = "IntString"
|
type_hint: str = "IntString"
|
||||||
clap_macros: set[str] = set()
|
clap_macros: set[str] = set()
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ class IntString(common.BasePrimitiveType):
|
|||||||
class NumString(common.BasePrimitiveType):
|
class NumString(common.BasePrimitiveType):
|
||||||
"""CLI Number or String"""
|
"""CLI Number or String"""
|
||||||
|
|
||||||
imports: set[str] = set(["crate::common::NumString"])
|
imports: set[str] = {"crate::common::NumString"}
|
||||||
type_hint: str = "NumString"
|
type_hint: str = "NumString"
|
||||||
clap_macros: set[str] = set()
|
clap_macros: set[str] = set()
|
||||||
|
|
||||||
@ -81,7 +81,7 @@ class NumString(common.BasePrimitiveType):
|
|||||||
class BoolString(common.BasePrimitiveType):
|
class BoolString(common.BasePrimitiveType):
|
||||||
"""CLI Boolean or String"""
|
"""CLI Boolean or String"""
|
||||||
|
|
||||||
imports: set[str] = set(["crate::common::BoolString"])
|
imports: set[str] = {"crate::common::BoolString"}
|
||||||
type_hint: str = "BoolString"
|
type_hint: str = "BoolString"
|
||||||
clap_macros: set[str] = set()
|
clap_macros: set[str] = set()
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ class BoolString(common.BasePrimitiveType):
|
|||||||
class VecString(common.BasePrimitiveType):
|
class VecString(common.BasePrimitiveType):
|
||||||
"""CLI Vector of strings"""
|
"""CLI Vector of strings"""
|
||||||
|
|
||||||
imports: set[str] = set(["crate::common::VecString"])
|
imports: set[str] = {"crate::common::VecString"}
|
||||||
type_hint: str = "VecString"
|
type_hint: str = "VecString"
|
||||||
clap_macros: set[str] = set()
|
clap_macros: set[str] = set()
|
||||||
|
|
||||||
@ -97,12 +97,12 @@ class VecString(common.BasePrimitiveType):
|
|||||||
class JsonValue(common_rust.JsonValue):
|
class JsonValue(common_rust.JsonValue):
|
||||||
"""Arbitrary JSON value"""
|
"""Arbitrary JSON value"""
|
||||||
|
|
||||||
clap_macros: set[str] = set(['value_name="JSON"', "value_parser=parse_json"])
|
clap_macros: set[str] = {'value_name="JSON"', "value_parser=parse_json"}
|
||||||
original_data_type: BaseCombinedType | BaseCompoundType | None = None
|
original_data_type: BaseCombinedType | BaseCompoundType | None = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def imports(self):
|
def imports(self):
|
||||||
imports: set[str] = set(["crate::common::parse_json", "serde_json::Value"])
|
imports: set[str] = {"crate::common::parse_json", "serde_json::Value"}
|
||||||
if self.original_data_type and isinstance(
|
if self.original_data_type and isinstance(
|
||||||
self.original_data_type, common_rust.Dictionary
|
self.original_data_type, common_rust.Dictionary
|
||||||
):
|
):
|
||||||
@ -130,7 +130,7 @@ class StructInputField(common_rust.StructField):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def builder_macros(self):
|
def builder_macros(self):
|
||||||
macros: set[str] = set([])
|
macros: set[str] = set()
|
||||||
if not isinstance(self.data_type, BaseCompoundType):
|
if not isinstance(self.data_type, BaseCompoundType):
|
||||||
macros.update(self.data_type.builder_macros)
|
macros.update(self.data_type.builder_macros)
|
||||||
else:
|
else:
|
||||||
@ -141,7 +141,7 @@ class StructInputField(common_rust.StructField):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def serde_macros(self):
|
def serde_macros(self):
|
||||||
macros = set([])
|
macros = set()
|
||||||
if self.local_name != self.remote_name:
|
if self.local_name != self.remote_name:
|
||||||
macros.add(f'rename="{self.remote_name}"')
|
macros.add(f'rename="{self.remote_name}"')
|
||||||
return f"#[serde({', '.join(sorted(macros))})]"
|
return f"#[serde({', '.join(sorted(macros))})]"
|
||||||
@ -156,7 +156,7 @@ class StructInputField(common_rust.StructField):
|
|||||||
self.data_type.item_type, common_rust.Struct
|
self.data_type.item_type, common_rust.Struct
|
||||||
):
|
):
|
||||||
return "#[command(flatten)]"
|
return "#[command(flatten)]"
|
||||||
macros = set(["long"])
|
macros = {"long"}
|
||||||
try:
|
try:
|
||||||
if self.data_type.clap_macros:
|
if self.data_type.clap_macros:
|
||||||
macros.update(self.data_type.clap_macros)
|
macros.update(self.data_type.clap_macros)
|
||||||
@ -173,7 +173,7 @@ class StructInputField(common_rust.StructField):
|
|||||||
# For substrucs (and maybe enums) we tell Clap to flatten subtype
|
# For substrucs (and maybe enums) we tell Clap to flatten subtype
|
||||||
# instead of exposing attr itself
|
# instead of exposing attr itself
|
||||||
return "#[command(flatten)]"
|
return "#[command(flatten)]"
|
||||||
macros = set(["long"])
|
macros = {"long"}
|
||||||
if is_group and not self.is_optional:
|
if is_group and not self.is_optional:
|
||||||
macros.add("required=false")
|
macros.add("required=false")
|
||||||
try:
|
try:
|
||||||
@ -196,7 +196,7 @@ class StructInput(common_rust.Struct):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def imports(self):
|
def imports(self):
|
||||||
imports: set[str] = set(["serde::Deserialize"])
|
imports: set[str] = {"serde::Deserialize"}
|
||||||
for field in self.fields.values():
|
for field in self.fields.values():
|
||||||
imports.update(field.data_type.imports)
|
imports.update(field.data_type.imports)
|
||||||
if self.additional_fields_type:
|
if self.additional_fields_type:
|
||||||
@ -214,7 +214,9 @@ class EnumGroupStructInputField(StructInputField):
|
|||||||
class EnumGroupStruct(common_rust.Struct):
|
class EnumGroupStruct(common_rust.Struct):
|
||||||
"""Container for complex Enum containing Array"""
|
"""Container for complex Enum containing Array"""
|
||||||
|
|
||||||
field_type_class_: Type[common_rust.StructField] = EnumGroupStructInputField
|
field_type_class_: Type[common_rust.StructField] = (
|
||||||
|
EnumGroupStructInputField
|
||||||
|
)
|
||||||
base_type: str = "struct"
|
base_type: str = "struct"
|
||||||
sdk_enum_name: str
|
sdk_enum_name: str
|
||||||
is_group: bool = True
|
is_group: bool = True
|
||||||
@ -234,7 +236,7 @@ class StructFieldResponse(common_rust.StructField):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def serde_macros(self):
|
def serde_macros(self):
|
||||||
macros = set([])
|
macros = set()
|
||||||
if self.local_name != self.remote_name:
|
if self.local_name != self.remote_name:
|
||||||
macros.add(f'rename="{self.remote_name}"')
|
macros.add(f'rename="{self.remote_name}"')
|
||||||
return f"#[serde({', '.join(sorted(macros))})]"
|
return f"#[serde({', '.join(sorted(macros))})]"
|
||||||
@ -246,23 +248,29 @@ class StructFieldResponse(common_rust.StructField):
|
|||||||
resource_name: str,
|
resource_name: str,
|
||||||
operation_type: str,
|
operation_type: str,
|
||||||
):
|
):
|
||||||
macros = set([])
|
macros = set()
|
||||||
if self.is_optional:
|
if self.is_optional:
|
||||||
macros.add("optional")
|
macros.add("optional")
|
||||||
if self.local_name != self.remote_name:
|
if self.local_name != self.remote_name:
|
||||||
macros.add(f'title="{self.remote_name}"')
|
macros.add(f'title="{self.remote_name}"')
|
||||||
# Fully Qualified Attribute Name
|
# Fully Qualified Attribute Name
|
||||||
fqan: str = ".".join([service_name, resource_name, self.remote_name]).lower()
|
fqan: str = ".".join(
|
||||||
|
[service_name, resource_name, self.remote_name]
|
||||||
|
).lower()
|
||||||
# Check the known alias of the field by FQAN
|
# Check the known alias of the field by FQAN
|
||||||
alias = common.FQAN_ALIAS_MAP.get(fqan)
|
alias = common.FQAN_ALIAS_MAP.get(fqan)
|
||||||
if operation_type in ["list", "list_from_struct"]:
|
if operation_type in ["list", "list_from_struct"]:
|
||||||
if (
|
if (
|
||||||
"id" in struct.fields.keys()
|
"id" in struct.fields.keys()
|
||||||
and not (self.local_name in BASIC_FIELDS or alias in BASIC_FIELDS)
|
and not (
|
||||||
|
self.local_name in BASIC_FIELDS or alias in BASIC_FIELDS
|
||||||
|
)
|
||||||
) or (
|
) or (
|
||||||
"id" not in struct.fields.keys()
|
"id" not in struct.fields.keys()
|
||||||
and (self.local_name not in list(struct.fields.keys())[-10:])
|
and (self.local_name not in list(struct.fields.keys())[-10:])
|
||||||
and not (self.local_name in BASIC_FIELDS or alias in BASIC_FIELDS)
|
and not (
|
||||||
|
self.local_name in BASIC_FIELDS or alias in BASIC_FIELDS
|
||||||
|
)
|
||||||
):
|
):
|
||||||
# Only add "wide" flag if field is not in the basic fields AND
|
# Only add "wide" flag if field is not in the basic fields AND
|
||||||
# there is at least "id" field existing in the struct OR the
|
# there is at least "id" field existing in the struct OR the
|
||||||
@ -283,7 +291,7 @@ class StructResponse(common_rust.Struct):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def imports(self):
|
def imports(self):
|
||||||
imports: set[str] = set(["serde::Deserialize"])
|
imports: set[str] = {"serde::Deserialize"}
|
||||||
for field in self.fields.values():
|
for field in self.fields.values():
|
||||||
imports.update(field.data_type.imports)
|
imports.update(field.data_type.imports)
|
||||||
# In difference to the SDK and Input we do not currently handle
|
# In difference to the SDK and Input we do not currently handle
|
||||||
@ -302,7 +310,7 @@ class TupleStruct(common_rust.Struct):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def imports(self):
|
def imports(self):
|
||||||
imports: set[str] = set([])
|
imports: set[str] = set()
|
||||||
for field in self.tuple_fields:
|
for field in self.tuple_fields:
|
||||||
imports.update(field.data_type.imports)
|
imports.update(field.data_type.imports)
|
||||||
return imports
|
return imports
|
||||||
@ -318,7 +326,7 @@ class DictionaryInput(common_rust.Dictionary):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def imports(self):
|
def imports(self):
|
||||||
imports = set([])
|
imports = set()
|
||||||
if not isinstance(self.value_type, common_rust.Option):
|
if not isinstance(self.value_type, common_rust.Option):
|
||||||
imports.add("crate::common::parse_key_val")
|
imports.add("crate::common::parse_key_val")
|
||||||
else:
|
else:
|
||||||
@ -328,26 +336,21 @@ class DictionaryInput(common_rust.Dictionary):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def clap_macros(self):
|
def clap_macros(self):
|
||||||
macros = set(
|
macros = {"long", 'value_name="key=value"'}
|
||||||
[
|
|
||||||
"long",
|
|
||||||
'value_name="key=value"',
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
if not isinstance(self.value_type, common_rust.Option):
|
if not isinstance(self.value_type, common_rust.Option):
|
||||||
macros.add(
|
macros.add(
|
||||||
f"value_parser=parse_key_val::<String, {self.value_type.type_hint}>",
|
f"value_parser=parse_key_val::<String, {self.value_type.type_hint}>"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
macros.add(
|
macros.add(
|
||||||
f"value_parser=parse_key_val_opt::<String, {self.value_type.item_type.type_hint}>",
|
f"value_parser=parse_key_val_opt::<String, {self.value_type.item_type.type_hint}>"
|
||||||
)
|
)
|
||||||
return macros
|
return macros
|
||||||
|
|
||||||
|
|
||||||
class StringEnum(common_rust.StringEnum):
|
class StringEnum(common_rust.StringEnum):
|
||||||
imports: set[str] = set(["clap::ValueEnum"])
|
imports: set[str] = {"clap::ValueEnum"}
|
||||||
|
|
||||||
|
|
||||||
class ArrayInput(common_rust.Array):
|
class ArrayInput(common_rust.Array):
|
||||||
@ -360,7 +363,7 @@ class ArrayInput(common_rust.Array):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def clap_macros(self):
|
def clap_macros(self):
|
||||||
macros: set[str] = set(["long", "action=clap::ArgAction::Append"])
|
macros: set[str] = {"long", "action=clap::ArgAction::Append"}
|
||||||
macros.update(self.item_type.clap_macros)
|
macros.update(self.item_type.clap_macros)
|
||||||
return macros
|
return macros
|
||||||
|
|
||||||
@ -420,7 +423,9 @@ class RequestParameter(common_rust.RequestParameter):
|
|||||||
|
|
||||||
|
|
||||||
class RequestTypeManager(common_rust.TypeManager):
|
class RequestTypeManager(common_rust.TypeManager):
|
||||||
primitive_type_mapping: dict[Type[model.PrimitiveType], Type[BasePrimitiveType]] = {
|
primitive_type_mapping: dict[
|
||||||
|
Type[model.PrimitiveType], Type[BasePrimitiveType]
|
||||||
|
] = {
|
||||||
model.PrimitiveString: String,
|
model.PrimitiveString: String,
|
||||||
model.ConstraintString: String,
|
model.ConstraintString: String,
|
||||||
model.PrimitiveAny: JsonValue,
|
model.PrimitiveAny: JsonValue,
|
||||||
@ -438,13 +443,17 @@ class RequestTypeManager(common_rust.TypeManager):
|
|||||||
model.Set: ArrayInput,
|
model.Set: ArrayInput,
|
||||||
}
|
}
|
||||||
|
|
||||||
request_parameter_class: Type[common_rust.RequestParameter] = RequestParameter
|
request_parameter_class: Type[common_rust.RequestParameter] = (
|
||||||
|
RequestParameter
|
||||||
|
)
|
||||||
string_enum_class = StringEnum
|
string_enum_class = StringEnum
|
||||||
|
|
||||||
def get_local_attribute_name(self, name: str) -> str:
|
def get_local_attribute_name(self, name: str) -> str:
|
||||||
"""Get localized attribute name"""
|
"""Get localized attribute name"""
|
||||||
name = name.replace(".", "_")
|
name = name.replace(".", "_")
|
||||||
attr_name = "_".join(x.lower() for x in re.split(common.SPLIT_NAME_RE, name))
|
attr_name = "_".join(
|
||||||
|
x.lower() for x in re.split(common.SPLIT_NAME_RE, name)
|
||||||
|
)
|
||||||
if attr_name in ["type", "self", "enum", "ref", "default"]:
|
if attr_name in ["type", "self", "enum", "ref", "default"]:
|
||||||
attr_name = f"_{attr_name}"
|
attr_name = f"_{attr_name}"
|
||||||
return attr_name
|
return attr_name
|
||||||
@ -469,7 +478,9 @@ class RequestTypeManager(common_rust.TypeManager):
|
|||||||
|
|
||||||
# Field is of Enum type.
|
# Field is of Enum type.
|
||||||
if isinstance(result, common_rust.Enum):
|
if isinstance(result, common_rust.Enum):
|
||||||
variant_classes = [x.data_type.__class__ for x in result.kinds.values()]
|
variant_classes = [
|
||||||
|
x.data_type.__class__ for x in result.kinds.values()
|
||||||
|
]
|
||||||
|
|
||||||
if (
|
if (
|
||||||
StringEnum in variant_classes
|
StringEnum in variant_classes
|
||||||
@ -522,12 +533,13 @@ class RequestTypeManager(common_rust.TypeManager):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
def convert_model(
|
def convert_model(
|
||||||
self,
|
self, type_model: model.PrimitiveType | model.ADT | model.Reference
|
||||||
type_model: model.PrimitiveType | model.ADT | model.Reference,
|
|
||||||
) -> BasePrimitiveType | BaseCombinedType | BaseCompoundType:
|
) -> BasePrimitiveType | BaseCombinedType | BaseCompoundType:
|
||||||
"""Get local destination type from the ModelType"""
|
"""Get local destination type from the ModelType"""
|
||||||
model_ref: model.Reference | None = None
|
model_ref: model.Reference | None = None
|
||||||
typ: BasePrimitiveType | BaseCombinedType | BaseCompoundType | None = None
|
typ: BasePrimitiveType | BaseCombinedType | BaseCompoundType | None = (
|
||||||
|
None
|
||||||
|
)
|
||||||
|
|
||||||
if isinstance(type_model, model.Reference):
|
if isinstance(type_model, model.Reference):
|
||||||
model_ref = type_model
|
model_ref = type_model
|
||||||
@ -557,7 +569,10 @@ class RequestTypeManager(common_rust.TypeManager):
|
|||||||
else:
|
else:
|
||||||
item_type = type_model.item_type
|
item_type = type_model.item_type
|
||||||
|
|
||||||
if isinstance(item_type, model.Struct) and len(item_type.fields.keys()) > 1:
|
if (
|
||||||
|
isinstance(item_type, model.Struct)
|
||||||
|
and len(item_type.fields.keys()) > 1
|
||||||
|
):
|
||||||
# An array of structs with more then 1 field
|
# An array of structs with more then 1 field
|
||||||
# Array of Structs can not be handled by the CLI (input).
|
# Array of Structs can not be handled by the CLI (input).
|
||||||
# Therefore handle underlaying structure as Json saving
|
# Therefore handle underlaying structure as Json saving
|
||||||
@ -592,7 +607,9 @@ class RequestTypeManager(common_rust.TypeManager):
|
|||||||
):
|
):
|
||||||
original_data_type = self.convert_model(type_model.value_type)
|
original_data_type = self.convert_model(type_model.value_type)
|
||||||
typ = JsonValue(
|
typ = JsonValue(
|
||||||
original_data_type=DictionaryInput(value_type=original_data_type)
|
original_data_type=DictionaryInput(
|
||||||
|
value_type=original_data_type
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
if typ:
|
if typ:
|
||||||
@ -608,7 +625,9 @@ class RequestTypeManager(common_rust.TypeManager):
|
|||||||
struct_class = self.data_type_mapping[model.Struct]
|
struct_class = self.data_type_mapping[model.Struct]
|
||||||
mod = struct_class(
|
mod = struct_class(
|
||||||
name=self.get_model_name(type_model.reference),
|
name=self.get_model_name(type_model.reference),
|
||||||
description=common_rust.sanitize_rust_docstrings(type_model.description),
|
description=common_rust.sanitize_rust_docstrings(
|
||||||
|
type_model.description
|
||||||
|
),
|
||||||
)
|
)
|
||||||
field_class = mod.field_type_class_
|
field_class = mod.field_type_class_
|
||||||
for field_name, field in type_model.fields.items():
|
for field_name, field in type_model.fields.items():
|
||||||
@ -637,7 +656,9 @@ class RequestTypeManager(common_rust.TypeManager):
|
|||||||
)
|
)
|
||||||
and not (
|
and not (
|
||||||
# and not Option<Primitive>
|
# and not Option<Primitive>
|
||||||
isinstance(field_data_type.value_type, self.option_type_class)
|
isinstance(
|
||||||
|
field_data_type.value_type, self.option_type_class
|
||||||
|
)
|
||||||
and isinstance(
|
and isinstance(
|
||||||
field_data_type.value_type.item_type,
|
field_data_type.value_type.item_type,
|
||||||
common_rust.BasePrimitiveType,
|
common_rust.BasePrimitiveType,
|
||||||
@ -646,9 +667,13 @@ class RequestTypeManager(common_rust.TypeManager):
|
|||||||
):
|
):
|
||||||
dict_type_model = self._get_adt_by_reference(field.data_type)
|
dict_type_model = self._get_adt_by_reference(field.data_type)
|
||||||
simplified_data_type = JsonValue()
|
simplified_data_type = JsonValue()
|
||||||
simplified_data_type.original_data_type = field_data_type.value_type
|
simplified_data_type.original_data_type = (
|
||||||
|
field_data_type.value_type
|
||||||
|
)
|
||||||
field_data_type.value_type = simplified_data_type
|
field_data_type.value_type = simplified_data_type
|
||||||
self.ignored_models.append(dict_type_model.value_type.reference)
|
self.ignored_models.append(
|
||||||
|
dict_type_model.value_type.reference
|
||||||
|
)
|
||||||
elif isinstance(field_data_type, StructInput):
|
elif isinstance(field_data_type, StructInput):
|
||||||
# Check if one of the sub fields has same attribute name as in the current struct.
|
# Check if one of the sub fields has same attribute name as in the current struct.
|
||||||
# Ideally this should not ever happen, but i.e. image.namespace.property has the case
|
# Ideally this should not ever happen, but i.e. image.namespace.property has the case
|
||||||
@ -666,12 +691,16 @@ class RequestTypeManager(common_rust.TypeManager):
|
|||||||
f = field_class(
|
f = field_class(
|
||||||
local_name=self.get_local_attribute_name(field_name),
|
local_name=self.get_local_attribute_name(field_name),
|
||||||
remote_name=self.get_remote_attribute_name(field_name),
|
remote_name=self.get_remote_attribute_name(field_name),
|
||||||
description=common_rust.sanitize_rust_docstrings(field.description),
|
description=common_rust.sanitize_rust_docstrings(
|
||||||
|
field.description
|
||||||
|
),
|
||||||
data_type=field_data_type,
|
data_type=field_data_type,
|
||||||
is_optional=not field.is_required,
|
is_optional=not field.is_required,
|
||||||
is_nullable=is_nullable,
|
is_nullable=is_nullable,
|
||||||
)
|
)
|
||||||
if mod.name != "Request" and isinstance(field_data_type, struct_class):
|
if mod.name != "Request" and isinstance(
|
||||||
|
field_data_type, struct_class
|
||||||
|
):
|
||||||
field_data_type.is_group = True
|
field_data_type.is_group = True
|
||||||
field_data_type.is_required = field.is_required
|
field_data_type.is_required = field.is_required
|
||||||
if isinstance(field_data_type, self.option_type_class):
|
if isinstance(field_data_type, self.option_type_class):
|
||||||
@ -743,7 +772,9 @@ class RequestTypeManager(common_rust.TypeManager):
|
|||||||
|
|
||||||
|
|
||||||
class ResponseTypeManager(common_rust.TypeManager):
|
class ResponseTypeManager(common_rust.TypeManager):
|
||||||
primitive_type_mapping: dict[Type[model.PrimitiveType], Type[BasePrimitiveType]] = {
|
primitive_type_mapping: dict[
|
||||||
|
Type[model.PrimitiveType], Type[BasePrimitiveType]
|
||||||
|
] = {
|
||||||
model.PrimitiveString: common_rust.String,
|
model.PrimitiveString: common_rust.String,
|
||||||
model.ConstraintString: common_rust.String,
|
model.ConstraintString: common_rust.String,
|
||||||
}
|
}
|
||||||
@ -764,16 +795,18 @@ class ResponseTypeManager(common_rust.TypeManager):
|
|||||||
if not model_ref:
|
if not model_ref:
|
||||||
return "Response"
|
return "Response"
|
||||||
return "Response" + "".join(
|
return "Response" + "".join(
|
||||||
x.capitalize() for x in re.split(common.SPLIT_NAME_RE, model_ref.name)
|
x.capitalize()
|
||||||
|
for x in re.split(common.SPLIT_NAME_RE, model_ref.name)
|
||||||
)
|
)
|
||||||
|
|
||||||
def convert_model(
|
def convert_model(
|
||||||
self,
|
self, type_model: model.PrimitiveType | model.ADT | model.Reference
|
||||||
type_model: model.PrimitiveType | model.ADT | model.Reference,
|
|
||||||
) -> BasePrimitiveType | BaseCombinedType | BaseCompoundType:
|
) -> BasePrimitiveType | BaseCombinedType | BaseCompoundType:
|
||||||
"""Get local destination type from the ModelType"""
|
"""Get local destination type from the ModelType"""
|
||||||
model_ref: model.Reference | None = None
|
model_ref: model.Reference | None = None
|
||||||
typ: BasePrimitiveType | BaseCombinedType | BaseCompoundType | None = None
|
typ: BasePrimitiveType | BaseCombinedType | BaseCompoundType | None = (
|
||||||
|
None
|
||||||
|
)
|
||||||
if isinstance(type_model, model.Reference):
|
if isinstance(type_model, model.Reference):
|
||||||
model_ref = type_model
|
model_ref = type_model
|
||||||
type_model = self._get_adt_by_reference(model_ref)
|
type_model = self._get_adt_by_reference(model_ref)
|
||||||
@ -814,7 +847,9 @@ class ResponseTypeManager(common_rust.TypeManager):
|
|||||||
# There is no sense of Enum in the output. Convert to the plain
|
# There is no sense of Enum in the output. Convert to the plain
|
||||||
# string
|
# string
|
||||||
typ = String(
|
typ = String(
|
||||||
description=common_rust.sanitize_rust_docstrings(typ.description)
|
description=common_rust.sanitize_rust_docstrings(
|
||||||
|
typ.description
|
||||||
|
)
|
||||||
)
|
)
|
||||||
if (
|
if (
|
||||||
typ
|
typ
|
||||||
@ -829,18 +864,23 @@ class ResponseTypeManager(common_rust.TypeManager):
|
|||||||
def _simplify_oneof_combinations(self, type_model, kinds):
|
def _simplify_oneof_combinations(self, type_model, kinds):
|
||||||
"""Simplify certain known oneOf combinations"""
|
"""Simplify certain known oneOf combinations"""
|
||||||
kinds_classes = [x["class"] for x in kinds]
|
kinds_classes = [x["class"] for x in kinds]
|
||||||
if common_rust.String in kinds_classes and common_rust.Number in kinds_classes:
|
if (
|
||||||
|
common_rust.String in kinds_classes
|
||||||
|
and common_rust.Number in kinds_classes
|
||||||
|
):
|
||||||
# oneOf [string, number] => NumString
|
# oneOf [string, number] => NumString
|
||||||
kinds.clear()
|
kinds.clear()
|
||||||
kinds.append({"local": NumString(), "class": NumString})
|
kinds.append({"local": NumString(), "class": NumString})
|
||||||
elif (
|
elif (
|
||||||
common_rust.String in kinds_classes and common_rust.Integer in kinds_classes
|
common_rust.String in kinds_classes
|
||||||
|
and common_rust.Integer in kinds_classes
|
||||||
):
|
):
|
||||||
# oneOf [string, integer] => NumString
|
# oneOf [string, integer] => NumString
|
||||||
kinds.clear()
|
kinds.clear()
|
||||||
kinds.append({"local": IntString(), "class": IntString})
|
kinds.append({"local": IntString(), "class": IntString})
|
||||||
elif (
|
elif (
|
||||||
common_rust.String in kinds_classes and common_rust.Boolean in kinds_classes
|
common_rust.String in kinds_classes
|
||||||
|
and common_rust.Boolean in kinds_classes
|
||||||
):
|
):
|
||||||
# oneOf [string, boolean] => String
|
# oneOf [string, boolean] => String
|
||||||
kinds.clear()
|
kinds.clear()
|
||||||
@ -852,7 +892,9 @@ class ResponseTypeManager(common_rust.TypeManager):
|
|||||||
struct_class = self.data_type_mapping[model.Struct]
|
struct_class = self.data_type_mapping[model.Struct]
|
||||||
mod = struct_class(
|
mod = struct_class(
|
||||||
name=self.get_model_name(type_model.reference),
|
name=self.get_model_name(type_model.reference),
|
||||||
description=common_rust.sanitize_rust_docstrings(type_model.description),
|
description=common_rust.sanitize_rust_docstrings(
|
||||||
|
type_model.description
|
||||||
|
),
|
||||||
)
|
)
|
||||||
field_class = mod.field_type_class_
|
field_class = mod.field_type_class_
|
||||||
for field_name, field in type_model.fields.items():
|
for field_name, field in type_model.fields.items():
|
||||||
@ -872,7 +914,9 @@ class ResponseTypeManager(common_rust.TypeManager):
|
|||||||
f = field_class(
|
f = field_class(
|
||||||
local_name=self.get_local_attribute_name(field_name),
|
local_name=self.get_local_attribute_name(field_name),
|
||||||
remote_name=self.get_remote_attribute_name(field_name),
|
remote_name=self.get_remote_attribute_name(field_name),
|
||||||
description=common_rust.sanitize_rust_docstrings(field.description),
|
description=common_rust.sanitize_rust_docstrings(
|
||||||
|
field.description
|
||||||
|
),
|
||||||
data_type=field_data_type,
|
data_type=field_data_type,
|
||||||
is_optional=not field.is_required,
|
is_optional=not field.is_required,
|
||||||
is_nullable=is_nullable,
|
is_nullable=is_nullable,
|
||||||
@ -962,18 +1006,13 @@ class RustCliGenerator(BaseGenerator):
|
|||||||
)
|
)
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--tests",
|
"--tests", action="store_true", help="Generate tests"
|
||||||
action="store_true",
|
|
||||||
help="Generate tests",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
def _render_command(
|
def _render_command(
|
||||||
self,
|
self, context: dict, impl_template: str, impl_dest: Path
|
||||||
context: dict,
|
|
||||||
impl_template: str,
|
|
||||||
impl_dest: Path,
|
|
||||||
):
|
):
|
||||||
"""Render command code"""
|
"""Render command code"""
|
||||||
self._render(impl_template, context, impl_dest.parent, impl_dest.name)
|
self._render(impl_template, context, impl_dest.parent, impl_dest.name)
|
||||||
@ -983,7 +1022,7 @@ class RustCliGenerator(BaseGenerator):
|
|||||||
):
|
):
|
||||||
"""Generate code for the Rust openstack_cli"""
|
"""Generate code for the Rust openstack_cli"""
|
||||||
logging.debug(
|
logging.debug(
|
||||||
"Generating Rust CLI code for `%s` in %s" % (operation_id, target_dir)
|
f"Generating Rust CLI code for `{operation_id}` in {target_dir}"
|
||||||
)
|
)
|
||||||
work_dir = Path(target_dir, "rust", "openstack_cli", "src")
|
work_dir = Path(target_dir, "rust", "openstack_cli", "src")
|
||||||
|
|
||||||
@ -992,21 +1031,19 @@ class RustCliGenerator(BaseGenerator):
|
|||||||
if not operation_id:
|
if not operation_id:
|
||||||
operation_id = args.openapi_operation_id
|
operation_id = args.openapi_operation_id
|
||||||
|
|
||||||
(path, method, spec) = common.find_openapi_operation(openapi_spec, operation_id)
|
(path, method, spec) = common.find_openapi_operation(
|
||||||
|
openapi_spec, operation_id
|
||||||
|
)
|
||||||
_, res_name = res.split(".") if res else (None, None)
|
_, res_name = res.split(".") if res else (None, None)
|
||||||
resource_name = common.get_resource_names_from_url(path)[-1]
|
resource_name = common.get_resource_names_from_url(path)[-1]
|
||||||
|
|
||||||
openapi_parser = model.OpenAPISchemaParser()
|
openapi_parser = model.OpenAPISchemaParser()
|
||||||
operation_params: list[model.RequestParameter] = []
|
operation_params: list[model.RequestParameter] = []
|
||||||
sdk_mod_path_base = common.get_rust_sdk_mod_path(
|
sdk_mod_path_base = common.get_rust_sdk_mod_path(
|
||||||
args.service_type,
|
args.service_type, args.api_version, args.module_path or path
|
||||||
args.api_version,
|
|
||||||
args.module_path or path,
|
|
||||||
)
|
)
|
||||||
cli_mod_path = common.get_rust_cli_mod_path(
|
cli_mod_path = common.get_rust_cli_mod_path(
|
||||||
args.service_type,
|
args.service_type, args.api_version, args.module_path or path
|
||||||
args.api_version,
|
|
||||||
args.module_path or path,
|
|
||||||
)
|
)
|
||||||
target_class_name = resource_name
|
target_class_name = resource_name
|
||||||
is_image_download: bool = False
|
is_image_download: bool = False
|
||||||
@ -1014,12 +1051,12 @@ class RustCliGenerator(BaseGenerator):
|
|||||||
global_additional_imports: set[str] = set()
|
global_additional_imports: set[str] = set()
|
||||||
|
|
||||||
# Collect all operation parameters
|
# Collect all operation parameters
|
||||||
for param in openapi_spec["paths"][path].get("parameters", []) + spec.get(
|
for param in openapi_spec["paths"][path].get(
|
||||||
"parameters", []
|
"parameters", []
|
||||||
):
|
) + spec.get("parameters", []):
|
||||||
if (("{" + param["name"] + "}") in path and param["in"] == "path") or param[
|
if (
|
||||||
"in"
|
("{" + param["name"] + "}") in path and param["in"] == "path"
|
||||||
] != "path":
|
) or param["in"] != "path":
|
||||||
# Respect path params that appear in path and not path params
|
# Respect path params that appear in path and not path params
|
||||||
param_ = openapi_parser.parse_parameter(param)
|
param_ = openapi_parser.parse_parameter(param)
|
||||||
if param_.name in [
|
if param_.name in [
|
||||||
@ -1032,19 +1069,28 @@ class RustCliGenerator(BaseGenerator):
|
|||||||
if param_.resource_link:
|
if param_.resource_link:
|
||||||
link_res_name: str = param_.resource_link.split(".")[0]
|
link_res_name: str = param_.resource_link.split(".")[0]
|
||||||
global_additional_imports.add("tracing::warn")
|
global_additional_imports.add("tracing::warn")
|
||||||
global_additional_imports.add("openstack_sdk::api::find_by_name")
|
global_additional_imports.add(
|
||||||
global_additional_imports.add("openstack_sdk::api::QueryAsync")
|
"openstack_sdk::api::find_by_name"
|
||||||
|
)
|
||||||
|
global_additional_imports.add(
|
||||||
|
"openstack_sdk::api::QueryAsync"
|
||||||
|
)
|
||||||
global_additional_imports.add(
|
global_additional_imports.add(
|
||||||
f"openstack_sdk::api::{'::'.join(link_res_name.split('/'))}::find as find_{link_res_name.split('/')[-1]}"
|
f"openstack_sdk::api::{'::'.join(link_res_name.split('/'))}::find as find_{link_res_name.split('/')[-1]}"
|
||||||
)
|
)
|
||||||
global_additional_imports.add("eyre::OptionExt")
|
global_additional_imports.add("eyre::OptionExt")
|
||||||
|
|
||||||
# List of operation variants (based on the body)
|
# List of operation variants (based on the body)
|
||||||
operation_variants = common.get_operation_variants(spec, args.operation_name)
|
operation_variants = common.get_operation_variants(
|
||||||
|
spec, args.operation_name
|
||||||
|
)
|
||||||
|
|
||||||
body_types: list[str] = []
|
body_types: list[str] = []
|
||||||
last_path_parameter: RequestParameter | None = None
|
last_path_parameter: RequestParameter | None = None
|
||||||
if args.operation_type == "download" and path == "/v2/images/{image_id}/file":
|
if (
|
||||||
|
args.operation_type == "download"
|
||||||
|
and path == "/v2/images/{image_id}/file"
|
||||||
|
):
|
||||||
is_image_download = True
|
is_image_download = True
|
||||||
|
|
||||||
if args.operation_type == "upload":
|
if args.operation_type == "upload":
|
||||||
@ -1054,10 +1100,12 @@ class RustCliGenerator(BaseGenerator):
|
|||||||
body_types = list(content.keys())
|
body_types = list(content.keys())
|
||||||
|
|
||||||
for operation_variant in operation_variants:
|
for operation_variant in operation_variants:
|
||||||
logging.debug("Processing variant %s" % operation_variant)
|
logging.debug(f"Processing variant {operation_variant}")
|
||||||
additional_imports = set(global_additional_imports)
|
additional_imports = set(global_additional_imports)
|
||||||
type_manager: common_rust.TypeManager = RequestTypeManager()
|
type_manager: common_rust.TypeManager = RequestTypeManager()
|
||||||
response_type_manager: common_rust.TypeManager = ResponseTypeManager()
|
response_type_manager: common_rust.TypeManager = (
|
||||||
|
ResponseTypeManager()
|
||||||
|
)
|
||||||
result_is_list: bool = False
|
result_is_list: bool = False
|
||||||
is_list_paginated: bool = False
|
is_list_paginated: bool = False
|
||||||
if operation_params:
|
if operation_params:
|
||||||
@ -1127,14 +1175,20 @@ class RustCliGenerator(BaseGenerator):
|
|||||||
response = common.find_response_schema(
|
response = common.find_response_schema(
|
||||||
spec["responses"],
|
spec["responses"],
|
||||||
args.response_key or resource_name,
|
args.response_key or resource_name,
|
||||||
(args.operation_name if args.operation_type == "action" else None),
|
(
|
||||||
|
args.operation_name
|
||||||
|
if args.operation_type == "action"
|
||||||
|
else None
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
if response:
|
if response:
|
||||||
response_key: str
|
response_key: str
|
||||||
if args.response_key:
|
if args.response_key:
|
||||||
response_key = (
|
response_key = (
|
||||||
args.response_key if args.response_key != "null" else None
|
args.response_key
|
||||||
|
if args.response_key != "null"
|
||||||
|
else None
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
response_key = resource_name
|
response_key = resource_name
|
||||||
@ -1149,7 +1203,9 @@ class RustCliGenerator(BaseGenerator):
|
|||||||
isinstance(response_def.get("type"), list)
|
isinstance(response_def.get("type"), list)
|
||||||
and "object" in response_def["type"]
|
and "object" in response_def["type"]
|
||||||
):
|
):
|
||||||
(root, response_types) = openapi_parser.parse(response_def)
|
(root, response_types) = openapi_parser.parse(
|
||||||
|
response_def
|
||||||
|
)
|
||||||
if isinstance(root, model.Dictionary):
|
if isinstance(root, model.Dictionary):
|
||||||
value_type: (
|
value_type: (
|
||||||
common_rust.BasePrimitiveType
|
common_rust.BasePrimitiveType
|
||||||
@ -1158,8 +1214,10 @@ class RustCliGenerator(BaseGenerator):
|
|||||||
| None
|
| None
|
||||||
) = None
|
) = None
|
||||||
try:
|
try:
|
||||||
value_type = response_type_manager.convert_model(
|
value_type = (
|
||||||
root.value_type
|
response_type_manager.convert_model(
|
||||||
|
root.value_type
|
||||||
|
)
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
# In rare cases we can not conter
|
# In rare cases we can not conter
|
||||||
@ -1170,13 +1228,19 @@ class RustCliGenerator(BaseGenerator):
|
|||||||
value_type = JsonValue()
|
value_type = JsonValue()
|
||||||
# if not isinstance(value_type, common_rust.BasePrimitiveType):
|
# if not isinstance(value_type, common_rust.BasePrimitiveType):
|
||||||
# value_type = JsonValue(original_data_type=value_type)
|
# value_type = JsonValue(original_data_type=value_type)
|
||||||
root_dict = HashMapResponse(value_type=value_type)
|
root_dict = HashMapResponse(
|
||||||
|
value_type=value_type
|
||||||
|
)
|
||||||
response_type_manager.refs[
|
response_type_manager.refs[
|
||||||
model.Reference(name="Body", type=HashMapResponse)
|
model.Reference(
|
||||||
|
name="Body", type=HashMapResponse
|
||||||
|
)
|
||||||
] = root_dict
|
] = root_dict
|
||||||
|
|
||||||
else:
|
else:
|
||||||
response_type_manager.set_models(response_types)
|
response_type_manager.set_models(
|
||||||
|
response_types
|
||||||
|
)
|
||||||
|
|
||||||
if method == "patch" and not request_types:
|
if method == "patch" and not request_types:
|
||||||
# image patch is a jsonpatch based operation
|
# image patch is a jsonpatch based operation
|
||||||
@ -1200,11 +1264,15 @@ class RustCliGenerator(BaseGenerator):
|
|||||||
elif response_def["type"] == "string":
|
elif response_def["type"] == "string":
|
||||||
(root_dt, _) = openapi_parser.parse(response_def)
|
(root_dt, _) = openapi_parser.parse(response_def)
|
||||||
if not root_dt:
|
if not root_dt:
|
||||||
raise RuntimeError("Response data can not be processed")
|
raise RuntimeError(
|
||||||
|
"Response data can not be processed"
|
||||||
|
)
|
||||||
field = common_rust.StructField(
|
field = common_rust.StructField(
|
||||||
local_name="dummy",
|
local_name="dummy",
|
||||||
remote_name="dummy",
|
remote_name="dummy",
|
||||||
data_type=response_type_manager.convert_model(root_dt),
|
data_type=response_type_manager.convert_model(
|
||||||
|
root_dt
|
||||||
|
),
|
||||||
is_optional=False,
|
is_optional=False,
|
||||||
)
|
)
|
||||||
tuple_struct = TupleStruct(name="Response")
|
tuple_struct = TupleStruct(name="Response")
|
||||||
@ -1213,7 +1281,8 @@ class RustCliGenerator(BaseGenerator):
|
|||||||
model.Reference(name="Body", type=TupleStruct)
|
model.Reference(name="Body", type=TupleStruct)
|
||||||
] = tuple_struct
|
] = tuple_struct
|
||||||
elif (
|
elif (
|
||||||
response_def["type"] == "array" and "items" in response_def
|
response_def["type"] == "array"
|
||||||
|
and "items" in response_def
|
||||||
):
|
):
|
||||||
(_, response_types) = openapi_parser.parse(
|
(_, response_types) = openapi_parser.parse(
|
||||||
response_def["items"]
|
response_def["items"]
|
||||||
@ -1223,9 +1292,9 @@ class RustCliGenerator(BaseGenerator):
|
|||||||
response_props = response.get("properties", {})
|
response_props = response.get("properties", {})
|
||||||
if (
|
if (
|
||||||
response_props
|
response_props
|
||||||
and response_props[list(response_props.keys())[0]].get(
|
and response_props[
|
||||||
"type"
|
list(response_props.keys())[0]
|
||||||
)
|
].get("type")
|
||||||
== "array"
|
== "array"
|
||||||
):
|
):
|
||||||
result_is_list = True
|
result_is_list = True
|
||||||
@ -1238,11 +1307,7 @@ class RustCliGenerator(BaseGenerator):
|
|||||||
|
|
||||||
if not (
|
if not (
|
||||||
args.find_implemented_by_sdk
|
args.find_implemented_by_sdk
|
||||||
and args.operation_type
|
and args.operation_type in ["show", "download"]
|
||||||
in [
|
|
||||||
"show",
|
|
||||||
"download",
|
|
||||||
]
|
|
||||||
):
|
):
|
||||||
additional_imports.add(mod_import_name)
|
additional_imports.add(mod_import_name)
|
||||||
|
|
||||||
@ -1267,7 +1332,9 @@ class RustCliGenerator(BaseGenerator):
|
|||||||
|
|
||||||
if args.operation_type == "list":
|
if args.operation_type == "list":
|
||||||
# Make plural form for listing
|
# Make plural form for listing
|
||||||
target_class_name = common.get_plural_form(target_class_name)
|
target_class_name = common.get_plural_form(
|
||||||
|
target_class_name
|
||||||
|
)
|
||||||
if "limit" in [
|
if "limit" in [
|
||||||
k for (k, _) in type_manager.get_parameters("query")
|
k for (k, _) in type_manager.get_parameters("query")
|
||||||
]:
|
]:
|
||||||
@ -1279,10 +1346,18 @@ class RustCliGenerator(BaseGenerator):
|
|||||||
additional_imports.add("crate::common::download_file")
|
additional_imports.add("crate::common::download_file")
|
||||||
|
|
||||||
if args.operation_type == "upload":
|
if args.operation_type == "upload":
|
||||||
additional_imports.add("crate::common::build_upload_asyncread")
|
additional_imports.add(
|
||||||
|
"crate::common::build_upload_asyncread"
|
||||||
|
)
|
||||||
if (
|
if (
|
||||||
(isinstance(root_type, StructResponse) and root_type.fields)
|
(
|
||||||
or (isinstance(root_type, TupleStruct) and root_type.tuple_fields)
|
isinstance(root_type, StructResponse)
|
||||||
|
and root_type.fields
|
||||||
|
)
|
||||||
|
or (
|
||||||
|
isinstance(root_type, TupleStruct)
|
||||||
|
and root_type.tuple_fields
|
||||||
|
)
|
||||||
or (isinstance(root_type, common_rust.Dictionary))
|
or (isinstance(root_type, common_rust.Dictionary))
|
||||||
):
|
):
|
||||||
additional_imports.add("openstack_sdk::api::QueryAsync")
|
additional_imports.add("openstack_sdk::api::QueryAsync")
|
||||||
@ -1295,10 +1370,18 @@ class RustCliGenerator(BaseGenerator):
|
|||||||
additional_imports.add("structable_derive::StructTable")
|
additional_imports.add("structable_derive::StructTable")
|
||||||
|
|
||||||
if resource_header_metadata:
|
if resource_header_metadata:
|
||||||
additional_imports.add("crate::common::HashMapStringString")
|
additional_imports.add(
|
||||||
|
"crate::common::HashMapStringString"
|
||||||
|
)
|
||||||
additional_imports.add("std::collections::HashMap")
|
additional_imports.add("std::collections::HashMap")
|
||||||
if (
|
if (
|
||||||
len([x for x in resource_header_metadata.keys() if "*" in x])
|
len(
|
||||||
|
[
|
||||||
|
x
|
||||||
|
for x in resource_header_metadata.keys()
|
||||||
|
if "*" in x
|
||||||
|
]
|
||||||
|
)
|
||||||
> 0
|
> 0
|
||||||
):
|
):
|
||||||
additional_imports.add("regex::Regex")
|
additional_imports.add("regex::Regex")
|
||||||
@ -1338,60 +1421,62 @@ class RustCliGenerator(BaseGenerator):
|
|||||||
command_description = operation_body.get(
|
command_description = operation_body.get(
|
||||||
"description", command_description
|
"description", command_description
|
||||||
)
|
)
|
||||||
command_summary = operation_body.get("summary", command_summary)
|
command_summary = operation_body.get(
|
||||||
|
"summary", command_summary
|
||||||
|
)
|
||||||
|
|
||||||
if command_summary and microversion:
|
if command_summary and microversion:
|
||||||
command_summary += f" (microversion = {microversion})"
|
command_summary += f" (microversion = {microversion})"
|
||||||
if not command_description:
|
if not command_description:
|
||||||
command_description = "Command without description in OpenAPI"
|
command_description = (
|
||||||
context = dict(
|
"Command without description in OpenAPI"
|
||||||
operation_id=operation_id,
|
)
|
||||||
operation_type=args.operation_type,
|
context = {
|
||||||
command_description=common_rust.sanitize_rust_docstrings(
|
"operation_id": operation_id,
|
||||||
|
"operation_type": args.operation_type,
|
||||||
|
"command_description": common_rust.sanitize_rust_docstrings(
|
||||||
command_description
|
command_description
|
||||||
),
|
),
|
||||||
command_summary=common_rust.sanitize_rust_docstrings(
|
"command_summary": common_rust.sanitize_rust_docstrings(
|
||||||
command_summary
|
command_summary
|
||||||
),
|
),
|
||||||
type_manager=type_manager,
|
"type_manager": type_manager,
|
||||||
resource_name=resource_name,
|
"resource_name": resource_name,
|
||||||
response_type_manager=response_type_manager,
|
"response_type_manager": response_type_manager,
|
||||||
target_class_name="".join(
|
"target_class_name": "".join(
|
||||||
x.title() for x in target_class_name.split("_")
|
x.title() for x in target_class_name.split("_")
|
||||||
),
|
),
|
||||||
sdk_struct_name="Request",
|
"sdk_struct_name": "Request",
|
||||||
sdk_service_name=common.get_rust_service_type_from_str(
|
"sdk_service_name": common.get_rust_service_type_from_str(
|
||||||
args.service_type
|
args.service_type
|
||||||
),
|
),
|
||||||
service_type=args.service_type,
|
"service_type": args.service_type,
|
||||||
url=path[1:] if path.startswith("/") else path,
|
"url": path[1:] if path.startswith("/") else path,
|
||||||
method=method,
|
"method": method,
|
||||||
resource_key=None,
|
"resource_key": None,
|
||||||
resource_header_metadata=resource_header_metadata,
|
"resource_header_metadata": resource_header_metadata,
|
||||||
sdk_mod_path=sdk_mod_path,
|
"sdk_mod_path": sdk_mod_path,
|
||||||
cli_mod_path=cli_mod_path,
|
"cli_mod_path": cli_mod_path,
|
||||||
result_def=result_def,
|
"result_def": result_def,
|
||||||
# Last path param is required for the download operation
|
# Last path param is required for the download operation
|
||||||
last_path_parameter=last_path_parameter,
|
"last_path_parameter": last_path_parameter,
|
||||||
body_types=body_types,
|
"body_types": body_types,
|
||||||
additional_imports=additional_imports,
|
"additional_imports": additional_imports,
|
||||||
find_present=args.find_implemented_by_sdk,
|
"find_present": args.find_implemented_by_sdk,
|
||||||
microversion=microversion,
|
"microversion": microversion,
|
||||||
result_is_list=result_is_list,
|
"result_is_list": result_is_list,
|
||||||
is_image_download=is_image_download,
|
"is_image_download": is_image_download,
|
||||||
is_json_patch=is_json_patch,
|
"is_json_patch": is_json_patch,
|
||||||
is_list_paginated=is_list_paginated,
|
"is_list_paginated": is_list_paginated,
|
||||||
)
|
}
|
||||||
|
|
||||||
if not args.cli_mod_path:
|
if not args.cli_mod_path:
|
||||||
# mod_name = args.operation_name or args.operation_type.value
|
# mod_name = args.operation_name or args.operation_type.value
|
||||||
impl_path = Path(work_dir, "/".join(cli_mod_path), f"{mod_name}.rs")
|
impl_path = Path(
|
||||||
|
work_dir, "/".join(cli_mod_path), f"{mod_name}.rs"
|
||||||
|
)
|
||||||
|
|
||||||
self._render_command(
|
self._render_command(context, "rust_cli/impl.rs.j2", impl_path)
|
||||||
context,
|
|
||||||
"rust_cli/impl.rs.j2",
|
|
||||||
impl_path,
|
|
||||||
)
|
|
||||||
self._format_code(impl_path)
|
self._format_code(impl_path)
|
||||||
|
|
||||||
if args.cli_full_command and True: # args.tests:
|
if args.cli_full_command and True: # args.tests:
|
||||||
@ -1403,7 +1488,9 @@ class RustCliGenerator(BaseGenerator):
|
|||||||
)
|
)
|
||||||
cmd = args.cli_full_command
|
cmd = args.cli_full_command
|
||||||
if microversion:
|
if microversion:
|
||||||
cmd = args.cli_full_command + microversion.replace(".", "")
|
cmd = args.cli_full_command + microversion.replace(
|
||||||
|
".", ""
|
||||||
|
)
|
||||||
|
|
||||||
test_context = {
|
test_context = {
|
||||||
"service_type": args.service_type,
|
"service_type": args.service_type,
|
||||||
|
@ -24,18 +24,18 @@ from codegenerator.common import rust as common_rust
|
|||||||
|
|
||||||
|
|
||||||
class String(common_rust.String):
|
class String(common_rust.String):
|
||||||
lifetimes: set[str] = set(["'a"])
|
lifetimes: set[str] = {"'a"}
|
||||||
type_hint: str = "Cow<'a, str>"
|
type_hint: str = "Cow<'a, str>"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def imports(self) -> set[str]:
|
def imports(self) -> set[str]:
|
||||||
return set(["std::borrow::Cow"])
|
return {"std::borrow::Cow"}
|
||||||
|
|
||||||
|
|
||||||
class Enum(common_rust.Enum):
|
class Enum(common_rust.Enum):
|
||||||
@property
|
@property
|
||||||
def builder_macros(self):
|
def builder_macros(self):
|
||||||
macros: set[str] = set(["setter(into)"])
|
macros: set[str] = {"setter(into)"}
|
||||||
return macros
|
return macros
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -51,14 +51,18 @@ class Enum(common_rust.Enum):
|
|||||||
return "#[derive(Debug, Deserialize, Clone, Serialize)]"
|
return "#[derive(Debug, Deserialize, Clone, Serialize)]"
|
||||||
|
|
||||||
def get_sample(self):
|
def get_sample(self):
|
||||||
(first_kind_name, first_kind_val) = list(sorted(self.kinds.items()))[0]
|
(first_kind_name, first_kind_val) = sorted(self.kinds.items())[0]
|
||||||
res = (
|
res = (
|
||||||
self.name
|
self.name
|
||||||
+ "::"
|
+ "::"
|
||||||
+ first_kind_name
|
+ first_kind_name
|
||||||
+ "("
|
+ "("
|
||||||
+ first_kind_val.data_type.get_sample()
|
+ first_kind_val.data_type.get_sample()
|
||||||
+ (".into()" if isinstance(first_kind_val.data_type, String) else "")
|
+ (
|
||||||
|
".into()"
|
||||||
|
if isinstance(first_kind_val.data_type, String)
|
||||||
|
else ""
|
||||||
|
)
|
||||||
+ ")"
|
+ ")"
|
||||||
)
|
)
|
||||||
return res
|
return res
|
||||||
@ -67,7 +71,7 @@ class Enum(common_rust.Enum):
|
|||||||
class StructField(common_rust.StructField):
|
class StructField(common_rust.StructField):
|
||||||
@property
|
@property
|
||||||
def builder_macros(self):
|
def builder_macros(self):
|
||||||
macros: set[str] = set([])
|
macros: set[str] = set()
|
||||||
if not isinstance(self.data_type, BaseCompoundType):
|
if not isinstance(self.data_type, BaseCompoundType):
|
||||||
macros.update(self.data_type.builder_macros)
|
macros.update(self.data_type.builder_macros)
|
||||||
elif not isinstance(self.data_type, common_rust.StringEnum):
|
elif not isinstance(self.data_type, common_rust.StringEnum):
|
||||||
@ -86,7 +90,7 @@ class StructField(common_rust.StructField):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def serde_macros(self):
|
def serde_macros(self):
|
||||||
macros = set([])
|
macros = set()
|
||||||
if self.local_name != self.remote_name:
|
if self.local_name != self.remote_name:
|
||||||
macros.add(f'rename="{self.remote_name}"')
|
macros.add(f'rename="{self.remote_name}"')
|
||||||
if self.is_optional:
|
if self.is_optional:
|
||||||
@ -145,7 +149,7 @@ class Struct(common_rust.Struct):
|
|||||||
|
|
||||||
|
|
||||||
class BTreeMap(common_rust.Dictionary):
|
class BTreeMap(common_rust.Dictionary):
|
||||||
builder_macros: set[str] = set(["private"])
|
builder_macros: set[str] = {"private"}
|
||||||
requires_builder_private_setter: bool = True
|
requires_builder_private_setter: bool = True
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -154,13 +158,13 @@ class BTreeMap(common_rust.Dictionary):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def imports(self):
|
def imports(self):
|
||||||
imports = set(["std::collections::BTreeMap"])
|
imports = {"std::collections::BTreeMap"}
|
||||||
imports.update(self.value_type.imports)
|
imports.update(self.value_type.imports)
|
||||||
return imports
|
return imports
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def lifetimes(self):
|
def lifetimes(self):
|
||||||
lt = set(["'a"])
|
lt = {"'a"}
|
||||||
if self.value_type.lifetimes:
|
if self.value_type.lifetimes:
|
||||||
lt.update(self.value_type.lifetimes)
|
lt.update(self.value_type.lifetimes)
|
||||||
return lt
|
return lt
|
||||||
@ -182,7 +186,9 @@ class BTreeMap(common_rust.Dictionary):
|
|||||||
f".map(|(k, v)| (k, v.into_iter()))"
|
f".map(|(k, v)| (k, v.into_iter()))"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
type_hint = self.value_type.type_hint.replace("Cow<'a, str>", "String")
|
type_hint = self.value_type.type_hint.replace(
|
||||||
|
"Cow<'a, str>", "String"
|
||||||
|
)
|
||||||
return f"BTreeMap::<String, {type_hint}>::new().into_iter()"
|
return f"BTreeMap::<String, {type_hint}>::new().into_iter()"
|
||||||
|
|
||||||
def get_mandatory_init(self):
|
def get_mandatory_init(self):
|
||||||
@ -190,7 +196,7 @@ class BTreeMap(common_rust.Dictionary):
|
|||||||
|
|
||||||
|
|
||||||
class BTreeSet(common_rust.BTreeSet):
|
class BTreeSet(common_rust.BTreeSet):
|
||||||
builder_macros: set[str] = set(["private"])
|
builder_macros: set[str] = {"private"}
|
||||||
requires_builder_private_setter: bool = True
|
requires_builder_private_setter: bool = True
|
||||||
|
|
||||||
|
|
||||||
@ -201,7 +207,7 @@ class CommaSeparatedList(common_rust.CommaSeparatedList):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def imports(self):
|
def imports(self):
|
||||||
imports: set[str] = set([])
|
imports: set[str] = set()
|
||||||
imports.add("crate::api::common::CommaSeparatedList")
|
imports.add("crate::api::common::CommaSeparatedList")
|
||||||
imports.update(self.item_type.imports)
|
imports.update(self.item_type.imports)
|
||||||
return imports
|
return imports
|
||||||
@ -241,7 +247,9 @@ class TypeManager(common_rust.TypeManager):
|
|||||||
model.CommaSeparatedList: CommaSeparatedList,
|
model.CommaSeparatedList: CommaSeparatedList,
|
||||||
}
|
}
|
||||||
|
|
||||||
request_parameter_class: Type[common_rust.RequestParameter] = RequestParameter
|
request_parameter_class: Type[common_rust.RequestParameter] = (
|
||||||
|
RequestParameter
|
||||||
|
)
|
||||||
|
|
||||||
def set_parameters(self, parameters: list[model.RequestParameter]) -> None:
|
def set_parameters(self, parameters: list[model.RequestParameter]) -> None:
|
||||||
"""Set OpenAPI operation parameters into typemanager for conversion"""
|
"""Set OpenAPI operation parameters into typemanager for conversion"""
|
||||||
@ -285,10 +293,7 @@ class RustSdkGenerator(BaseGenerator):
|
|||||||
return parser
|
return parser
|
||||||
|
|
||||||
def _render_command(
|
def _render_command(
|
||||||
self,
|
self, context: dict, impl_template: str, impl_dest: Path
|
||||||
context: dict,
|
|
||||||
impl_template: str,
|
|
||||||
impl_dest: Path,
|
|
||||||
):
|
):
|
||||||
"""Render command code"""
|
"""Render command code"""
|
||||||
self._render(impl_template, context, impl_dest.parent, impl_dest.name)
|
self._render(impl_template, context, impl_dest.parent, impl_dest.name)
|
||||||
@ -308,7 +313,9 @@ class RustSdkGenerator(BaseGenerator):
|
|||||||
openapi_spec = common.get_openapi_spec(args.openapi_yaml_spec)
|
openapi_spec = common.get_openapi_spec(args.openapi_yaml_spec)
|
||||||
if not operation_id:
|
if not operation_id:
|
||||||
operation_id = args.openapi_operation_id
|
operation_id = args.openapi_operation_id
|
||||||
(path, method, spec) = common.find_openapi_operation(openapi_spec, operation_id)
|
(path, method, spec) = common.find_openapi_operation(
|
||||||
|
openapi_spec, operation_id
|
||||||
|
)
|
||||||
if args.operation_type == "find":
|
if args.operation_type == "find":
|
||||||
yield self.generate_find_mod(
|
yield self.generate_find_mod(
|
||||||
target_dir,
|
target_dir,
|
||||||
@ -334,12 +341,12 @@ class RustSdkGenerator(BaseGenerator):
|
|||||||
type_manager: TypeManager | None = None
|
type_manager: TypeManager | None = None
|
||||||
is_json_patch: bool = False
|
is_json_patch: bool = False
|
||||||
# Collect all operation parameters
|
# Collect all operation parameters
|
||||||
for param in openapi_spec["paths"][path].get("parameters", []) + spec.get(
|
for param in openapi_spec["paths"][path].get(
|
||||||
"parameters", []
|
"parameters", []
|
||||||
):
|
) + spec.get("parameters", []):
|
||||||
if (("{" + param["name"] + "}") in path and param["in"] == "path") or param[
|
if (
|
||||||
"in"
|
("{" + param["name"] + "}") in path and param["in"] == "path"
|
||||||
] != "path":
|
) or param["in"] != "path":
|
||||||
# Respect path params that appear in path and not path params
|
# Respect path params that appear in path and not path params
|
||||||
param_ = openapi_parser.parse_parameter(param)
|
param_ = openapi_parser.parse_parameter(param)
|
||||||
if param_.name in [
|
if param_.name in [
|
||||||
@ -353,7 +360,9 @@ class RustSdkGenerator(BaseGenerator):
|
|||||||
|
|
||||||
# Process body information
|
# Process body information
|
||||||
# List of operation variants (based on the body)
|
# List of operation variants (based on the body)
|
||||||
operation_variants = common.get_operation_variants(spec, args.operation_name)
|
operation_variants = common.get_operation_variants(
|
||||||
|
spec, args.operation_name
|
||||||
|
)
|
||||||
|
|
||||||
api_ver_matches: re.Match | None = None
|
api_ver_matches: re.Match | None = None
|
||||||
path_elements = path.lstrip("/").split("/")
|
path_elements = path.lstrip("/").split("/")
|
||||||
@ -366,7 +375,7 @@ class RustSdkGenerator(BaseGenerator):
|
|||||||
ver_prefix = path_elements[0]
|
ver_prefix = path_elements[0]
|
||||||
|
|
||||||
for operation_variant in operation_variants:
|
for operation_variant in operation_variants:
|
||||||
logging.debug("Processing variant %s" % operation_variant)
|
logging.debug(f"Processing variant {operation_variant}")
|
||||||
# TODO(gtema): if we are in MV variants filter out unsupported query
|
# TODO(gtema): if we are in MV variants filter out unsupported query
|
||||||
# parameters
|
# parameters
|
||||||
# TODO(gtema): previously we were ensuring `router_id` path param
|
# TODO(gtema): previously we were ensuring `router_id` path param
|
||||||
@ -449,13 +458,12 @@ class RustSdkGenerator(BaseGenerator):
|
|||||||
if "application/json" in content:
|
if "application/json" in content:
|
||||||
response_spec = content["application/json"]
|
response_spec = content["application/json"]
|
||||||
try:
|
try:
|
||||||
(
|
(_, response_key) = (
|
||||||
_,
|
common.find_resource_schema(
|
||||||
response_key,
|
response_spec["schema"],
|
||||||
) = common.find_resource_schema(
|
None,
|
||||||
response_spec["schema"],
|
res_name.lower(),
|
||||||
None,
|
)
|
||||||
res_name.lower(),
|
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
# Most likely we have response which is oneOf.
|
# Most likely we have response which is oneOf.
|
||||||
@ -465,42 +473,35 @@ class RustSdkGenerator(BaseGenerator):
|
|||||||
# response_def = (None,)
|
# response_def = (None,)
|
||||||
response_key = None
|
response_key = None
|
||||||
|
|
||||||
context = dict(
|
context = {
|
||||||
operation_id=operation_id,
|
"operation_id": operation_id,
|
||||||
operation_type=spec.get(
|
"operation_type": spec.get(
|
||||||
"x-openstack-operation-type", args.operation_type
|
"x-openstack-operation-type", args.operation_type
|
||||||
),
|
),
|
||||||
command_description=common_rust.sanitize_rust_docstrings(
|
"command_description": common_rust.sanitize_rust_docstrings(
|
||||||
common.make_ascii_string(spec.get("description"))
|
common.make_ascii_string(spec.get("description"))
|
||||||
),
|
),
|
||||||
class_name=class_name,
|
"class_name": class_name,
|
||||||
sdk_service_name=common.get_rust_service_type_from_str(
|
"sdk_service_name": common.get_rust_service_type_from_str(
|
||||||
args.service_type
|
args.service_type
|
||||||
),
|
),
|
||||||
url=path.lstrip("/").lstrip(ver_prefix).lstrip("/"),
|
"url": path.lstrip("/").lstrip(ver_prefix).lstrip("/"),
|
||||||
method=method,
|
"method": method,
|
||||||
type_manager=type_manager,
|
"type_manager": type_manager,
|
||||||
response_key=response_key,
|
"response_key": response_key,
|
||||||
response_list_item_key=args.response_list_item_key,
|
"response_list_item_key": args.response_list_item_key,
|
||||||
mime_type=mime_type,
|
"mime_type": mime_type,
|
||||||
is_json_patch=is_json_patch,
|
"is_json_patch": is_json_patch,
|
||||||
api_ver=api_ver,
|
"api_ver": api_ver,
|
||||||
)
|
}
|
||||||
|
|
||||||
work_dir = Path(target_dir, "rust", "openstack_sdk", "src")
|
work_dir = Path(target_dir, "rust", "openstack_sdk", "src")
|
||||||
impl_path = Path(
|
impl_path = Path(
|
||||||
work_dir,
|
work_dir, "api", "/".join(mod_path), f"{mod_name}.rs"
|
||||||
"api",
|
|
||||||
"/".join(mod_path),
|
|
||||||
f"{mod_name}.rs",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Generate methods for the GET resource command
|
# Generate methods for the GET resource command
|
||||||
self._render_command(
|
self._render_command(context, "rust_sdk/impl.rs.j2", impl_path)
|
||||||
context,
|
|
||||||
"rust_sdk/impl.rs.j2",
|
|
||||||
impl_path,
|
|
||||||
)
|
|
||||||
|
|
||||||
self._format_code(impl_path)
|
self._format_code(impl_path)
|
||||||
|
|
||||||
@ -512,26 +513,19 @@ class RustSdkGenerator(BaseGenerator):
|
|||||||
"""Generate collection module (include individual modules)"""
|
"""Generate collection module (include individual modules)"""
|
||||||
work_dir = Path(target_dir, "rust", "openstack_sdk", "src")
|
work_dir = Path(target_dir, "rust", "openstack_sdk", "src")
|
||||||
impl_path = Path(
|
impl_path = Path(
|
||||||
work_dir,
|
work_dir, "api", "/".join(mod_path[0:-1]), f"{mod_path[-1]}.rs"
|
||||||
"api",
|
|
||||||
"/".join(mod_path[0:-1]),
|
|
||||||
f"{mod_path[-1]}.rs",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
context = dict(
|
context = {
|
||||||
mod_list=mod_list,
|
"mod_list": mod_list,
|
||||||
mod_path=mod_path,
|
"mod_path": mod_path,
|
||||||
url=url,
|
"url": url,
|
||||||
resource_name=resource_name,
|
"resource_name": resource_name,
|
||||||
service_name=service_name,
|
"service_name": service_name,
|
||||||
)
|
}
|
||||||
|
|
||||||
# Generate methods for the GET resource command
|
# Generate methods for the GET resource command
|
||||||
self._render_command(
|
self._render_command(context, "rust_sdk/mod.rs.j2", impl_path)
|
||||||
context,
|
|
||||||
"rust_sdk/mod.rs.j2",
|
|
||||||
impl_path,
|
|
||||||
)
|
|
||||||
|
|
||||||
self._format_code(impl_path)
|
self._format_code(impl_path)
|
||||||
|
|
||||||
@ -550,12 +544,7 @@ class RustSdkGenerator(BaseGenerator):
|
|||||||
):
|
):
|
||||||
"""Generate `find` operation module"""
|
"""Generate `find` operation module"""
|
||||||
work_dir = Path(target_dir, "rust", "openstack_sdk", "src")
|
work_dir = Path(target_dir, "rust", "openstack_sdk", "src")
|
||||||
impl_path = Path(
|
impl_path = Path(work_dir, "api", "/".join(mod_path), "find.rs")
|
||||||
work_dir,
|
|
||||||
"api",
|
|
||||||
"/".join(mod_path),
|
|
||||||
"find.rs",
|
|
||||||
)
|
|
||||||
# Collect all operation parameters
|
# Collect all operation parameters
|
||||||
openapi_parser = model.OpenAPISchemaParser()
|
openapi_parser = model.OpenAPISchemaParser()
|
||||||
path_resources = common.get_resource_names_from_url(path)
|
path_resources = common.get_resource_names_from_url(path)
|
||||||
@ -563,9 +552,9 @@ class RustSdkGenerator(BaseGenerator):
|
|||||||
operation_path_params: list[model.RequestParameter] = []
|
operation_path_params: list[model.RequestParameter] = []
|
||||||
operation_query_params: list[model.RequestParameter] = []
|
operation_query_params: list[model.RequestParameter] = []
|
||||||
|
|
||||||
for param in openapi_spec["paths"][path].get("parameters", []) + spec.get(
|
for param in openapi_spec["paths"][path].get(
|
||||||
"parameters", []
|
"parameters", []
|
||||||
):
|
) + spec.get("parameters", []):
|
||||||
if ("{" + param["name"] + "}") in path and param["in"] == "path":
|
if ("{" + param["name"] + "}") in path and param["in"] == "path":
|
||||||
# Respect path params that appear in path and not in path params
|
# Respect path params that appear in path and not in path params
|
||||||
param_ = openapi_parser.parse_parameter(param)
|
param_ = openapi_parser.parse_parameter(param)
|
||||||
@ -583,24 +572,22 @@ class RustSdkGenerator(BaseGenerator):
|
|||||||
type_manager = TypeManager()
|
type_manager = TypeManager()
|
||||||
type_manager.set_parameters(operation_path_params)
|
type_manager.set_parameters(operation_path_params)
|
||||||
|
|
||||||
context = dict(
|
context = {
|
||||||
mod_path=mod_path,
|
"mod_path": mod_path,
|
||||||
resource_name=resource_name,
|
"resource_name": resource_name,
|
||||||
list_mod=list_mod,
|
"list_mod": list_mod,
|
||||||
name_filter_supported=name_filter_supported,
|
"name_filter_supported": name_filter_supported,
|
||||||
name_field=name_field,
|
"name_field": name_field,
|
||||||
type_manager=type_manager,
|
"type_manager": type_manager,
|
||||||
list_lifetime=(
|
"list_lifetime": (
|
||||||
"<'a>" if operation_query_params or operation_path_params else ""
|
"<'a>"
|
||||||
|
if operation_query_params or operation_path_params
|
||||||
|
else ""
|
||||||
),
|
),
|
||||||
)
|
}
|
||||||
|
|
||||||
# Generate methods for the GET resource command
|
# Generate methods for the GET resource command
|
||||||
self._render_command(
|
self._render_command(context, "rust_sdk/find.rs.j2", impl_path)
|
||||||
context,
|
|
||||||
"rust_sdk/find.rs.j2",
|
|
||||||
impl_path,
|
|
||||||
)
|
|
||||||
|
|
||||||
self._format_code(impl_path)
|
self._format_code(impl_path)
|
||||||
|
|
||||||
|
@ -31,5 +31,7 @@ class TestGenerator(TestCase):
|
|||||||
generator.generate(work_dir.name, Args(validate=True))
|
generator.generate(work_dir.name, Args(validate=True))
|
||||||
|
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
Path(work_dir.name, "openapi_specs", "block-storage", "v3.yaml").exists()
|
Path(
|
||||||
|
work_dir.name, "openapi_specs", "block-storage", "v3.yaml"
|
||||||
|
).exists()
|
||||||
)
|
)
|
||||||
|
@ -31,5 +31,7 @@ class TestGenerator(TestCase):
|
|||||||
generator.generate(work_dir.name, Args(validate=True))
|
generator.generate(work_dir.name, Args(validate=True))
|
||||||
|
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
Path(work_dir.name, "openapi_specs", "identity", "v3.yaml").exists()
|
Path(
|
||||||
|
work_dir.name, "openapi_specs", "identity", "v3.yaml"
|
||||||
|
).exists()
|
||||||
)
|
)
|
||||||
|
@ -31,5 +31,7 @@ class TestGenerator(TestCase):
|
|||||||
generator.generate(work_dir.name, Args(validate=True))
|
generator.generate(work_dir.name, Args(validate=True))
|
||||||
|
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
Path(work_dir.name, "openapi_specs", "load-balancing", "v2.yaml").exists()
|
Path(
|
||||||
|
work_dir.name, "openapi_specs", "load-balancing", "v2.yaml"
|
||||||
|
).exists()
|
||||||
)
|
)
|
||||||
|
@ -81,7 +81,9 @@ class TestFindResponseSchema(TestCase):
|
|||||||
},
|
},
|
||||||
"204": {
|
"204": {
|
||||||
"content": {
|
"content": {
|
||||||
"application/json": {"schema": {"oneOf": [foo_action, bar_action]}}
|
"application/json": {
|
||||||
|
"schema": {"oneOf": [foo_action, bar_action]}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -94,7 +96,7 @@ class TestFindResponseSchema(TestCase):
|
|||||||
common.find_response_schema(responses, "foo", "bar-action"),
|
common.find_response_schema(responses, "foo", "bar-action"),
|
||||||
)
|
)
|
||||||
self.assertIsNone(
|
self.assertIsNone(
|
||||||
common.find_response_schema(responses, "foo", "baz-action"),
|
common.find_response_schema(responses, "foo", "baz-action")
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
responses["200"]["content"]["application/json"]["schema"],
|
responses["200"]["content"]["application/json"]["schema"],
|
||||||
@ -104,11 +106,7 @@ class TestFindResponseSchema(TestCase):
|
|||||||
def test_no_candidates_returns_root(self):
|
def test_no_candidates_returns_root(self):
|
||||||
responses = {
|
responses = {
|
||||||
"200": {
|
"200": {
|
||||||
"content": {
|
"content": {"application/json": {"schema": self.FOO["foo"]}}
|
||||||
"application/json": {
|
|
||||||
"schema": self.FOO["foo"],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
|
@ -135,12 +135,7 @@ SAMPLE_SERVER_SCHEMA = {
|
|||||||
},
|
},
|
||||||
"delete_on_termination": {
|
"delete_on_termination": {
|
||||||
"type": ["boolean", "string"],
|
"type": ["boolean", "string"],
|
||||||
"enum": [
|
"enum": [True, "True", False, "False"],
|
||||||
True,
|
|
||||||
"True",
|
|
||||||
False,
|
|
||||||
"False",
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
"no_device": {},
|
"no_device": {},
|
||||||
"connection_info": {
|
"connection_info": {
|
||||||
@ -179,12 +174,7 @@ SAMPLE_SERVER_SCHEMA = {
|
|||||||
},
|
},
|
||||||
"delete_on_termination": {
|
"delete_on_termination": {
|
||||||
"type": ["boolean", "string"],
|
"type": ["boolean", "string"],
|
||||||
"enum": [
|
"enum": [True, "True", False, "False"],
|
||||||
True,
|
|
||||||
"True",
|
|
||||||
False,
|
|
||||||
"False",
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
"no_device": {},
|
"no_device": {},
|
||||||
"connection_info": {
|
"connection_info": {
|
||||||
@ -410,7 +400,9 @@ EXPECTED_TLA_DATA = model.Struct(
|
|||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
"os:scheduler_hints": model.StructField(
|
"os:scheduler_hints": model.StructField(
|
||||||
data_type=model.Reference(name="os:scheduler_hints", type=model.Struct),
|
data_type=model.Reference(
|
||||||
|
name="os:scheduler_hints", type=model.Struct
|
||||||
|
),
|
||||||
description="scheduler hints description",
|
description="scheduler hints description",
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
@ -434,10 +426,7 @@ EXPECTED_DATA_TYPES = [
|
|||||||
),
|
),
|
||||||
model.OneOfType(
|
model.OneOfType(
|
||||||
reference=model.Reference(name="flavorRef", type=model.OneOfType),
|
reference=model.Reference(name="flavorRef", type=model.OneOfType),
|
||||||
kinds=[
|
kinds=[model.ConstraintString(minLength=1), model.ConstraintInteger()],
|
||||||
model.ConstraintString(minLength=1),
|
|
||||||
model.ConstraintInteger(),
|
|
||||||
],
|
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
model.Dictionary(
|
model.Dictionary(
|
||||||
@ -456,28 +445,27 @@ EXPECTED_DATA_TYPES = [
|
|||||||
),
|
),
|
||||||
model.OneOfType(
|
model.OneOfType(
|
||||||
reference=model.Reference(name="port", type=model.OneOfType),
|
reference=model.Reference(name="port", type=model.OneOfType),
|
||||||
kinds=[
|
kinds=[model.ConstraintString(format="uuid"), model.PrimitiveNull()],
|
||||||
model.ConstraintString(format="uuid"),
|
|
||||||
model.PrimitiveNull(),
|
|
||||||
],
|
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
model.Struct(
|
model.Struct(
|
||||||
reference=model.Reference(name="networks", type=model.Struct),
|
reference=model.Reference(name="networks", type=model.Struct),
|
||||||
fields={
|
fields={
|
||||||
"fixed_ip": model.StructField(
|
"fixed_ip": model.StructField(
|
||||||
data_type=model.Reference(name="fixed_ip", type=model.OneOfType),
|
data_type=model.Reference(
|
||||||
|
name="fixed_ip", type=model.OneOfType
|
||||||
|
)
|
||||||
),
|
),
|
||||||
"port": model.StructField(
|
"port": model.StructField(
|
||||||
data_type=model.Reference(name="port", type=model.OneOfType),
|
data_type=model.Reference(name="port", type=model.OneOfType)
|
||||||
),
|
),
|
||||||
"uuid": model.StructField(
|
"uuid": model.StructField(
|
||||||
data_type=model.ConstraintString(format="uuid"),
|
data_type=model.ConstraintString(format="uuid")
|
||||||
),
|
),
|
||||||
"tag": model.StructField(
|
"tag": model.StructField(
|
||||||
data_type=model.ConstraintString(
|
data_type=model.ConstraintString(
|
||||||
minLength=1, maxLength=60, pattern="^[^,/]*$"
|
minLength=1, maxLength=60, pattern="^[^,/]*$"
|
||||||
),
|
)
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
@ -519,43 +507,45 @@ EXPECTED_DATA_TYPES = [
|
|||||||
# ],
|
# ],
|
||||||
# ),
|
# ),
|
||||||
model.Enum(
|
model.Enum(
|
||||||
reference=model.Reference(name="delete_on_termination", type=model.Enum),
|
reference=model.Reference(
|
||||||
|
name="delete_on_termination", type=model.Enum
|
||||||
|
),
|
||||||
literals=[True, "True", False, "False"],
|
literals=[True, "True", False, "False"],
|
||||||
base_types=[model.ConstraintString, model.PrimitiveBoolean],
|
base_types=[model.ConstraintString, model.PrimitiveBoolean],
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
model.Struct(
|
model.Struct(
|
||||||
reference=model.Reference(name="block_device_mapping", type=model.Struct),
|
reference=model.Reference(
|
||||||
|
name="block_device_mapping", type=model.Struct
|
||||||
|
),
|
||||||
fields={
|
fields={
|
||||||
"virtual_name": model.StructField(
|
"virtual_name": model.StructField(
|
||||||
data_type=model.ConstraintString(maxLength=255),
|
data_type=model.ConstraintString(maxLength=255)
|
||||||
),
|
),
|
||||||
"volume_id": model.StructField(
|
"volume_id": model.StructField(
|
||||||
data_type=model.ConstraintString(format="uuid"),
|
data_type=model.ConstraintString(format="uuid")
|
||||||
),
|
),
|
||||||
"snapshot_id": model.StructField(
|
"snapshot_id": model.StructField(
|
||||||
data_type=model.ConstraintString(format="uuid"),
|
data_type=model.ConstraintString(format="uuid")
|
||||||
),
|
),
|
||||||
"volume_size": model.StructField(
|
"volume_size": model.StructField(
|
||||||
data_type=model.Reference(name="volume_size", type=model.OneOfType),
|
data_type=model.Reference(
|
||||||
|
name="volume_size", type=model.OneOfType
|
||||||
|
)
|
||||||
),
|
),
|
||||||
"device_name": model.StructField(
|
"device_name": model.StructField(
|
||||||
data_type=model.ConstraintString(
|
data_type=model.ConstraintString(
|
||||||
minLength=1,
|
minLength=1, maxLength=255, pattern="^[a-zA-Z0-9._-r/]*$"
|
||||||
maxLength=255,
|
)
|
||||||
pattern="^[a-zA-Z0-9._-r/]*$",
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
"delete_on_termination": model.StructField(
|
"delete_on_termination": model.StructField(
|
||||||
data_type=model.Reference(
|
data_type=model.Reference(
|
||||||
name="delete_on_termination", type=model.Enum
|
name="delete_on_termination", type=model.Enum
|
||||||
),
|
)
|
||||||
),
|
|
||||||
"no_device": model.StructField(
|
|
||||||
data_type=model.PrimitiveNull(),
|
|
||||||
),
|
),
|
||||||
|
"no_device": model.StructField(data_type=model.PrimitiveNull()),
|
||||||
"connection_info": model.StructField(
|
"connection_info": model.StructField(
|
||||||
data_type=model.ConstraintString(maxLength=16777215),
|
data_type=model.ConstraintString(maxLength=16777215)
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
@ -586,122 +576,110 @@ EXPECTED_DATA_TYPES = [
|
|||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
model.Struct(
|
model.Struct(
|
||||||
reference=model.Reference(name="block_device_mapping_v2", type=model.Struct),
|
reference=model.Reference(
|
||||||
|
name="block_device_mapping_v2", type=model.Struct
|
||||||
|
),
|
||||||
fields={
|
fields={
|
||||||
"virtual_name": model.StructField(
|
"virtual_name": model.StructField(
|
||||||
data_type=model.ConstraintString(maxLength=255),
|
data_type=model.ConstraintString(maxLength=255)
|
||||||
),
|
),
|
||||||
"volume_id": model.StructField(
|
"volume_id": model.StructField(
|
||||||
data_type=model.ConstraintString(
|
data_type=model.ConstraintString(format="uuid")
|
||||||
format="uuid",
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
"snapshot_id": model.StructField(
|
"snapshot_id": model.StructField(
|
||||||
data_type=model.ConstraintString(
|
data_type=model.ConstraintString(format="uuid")
|
||||||
format="uuid",
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
"volume_size": model.StructField(
|
"volume_size": model.StructField(
|
||||||
data_type=model.Reference(name="volume_size", type=model.OneOfType),
|
data_type=model.Reference(
|
||||||
|
name="volume_size", type=model.OneOfType
|
||||||
|
)
|
||||||
),
|
),
|
||||||
"device_name": model.StructField(
|
"device_name": model.StructField(
|
||||||
data_type=model.ConstraintString(
|
data_type=model.ConstraintString(
|
||||||
minLength=1,
|
minLength=1, maxLength=255, pattern="^[a-zA-Z0-9._-r/]*$"
|
||||||
maxLength=255,
|
)
|
||||||
pattern="^[a-zA-Z0-9._-r/]*$",
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
"delete_on_termination": model.StructField(
|
"delete_on_termination": model.StructField(
|
||||||
data_type=model.Reference(
|
data_type=model.Reference(
|
||||||
name="delete_on_termination", type=model.Enum
|
name="delete_on_termination", type=model.Enum
|
||||||
),
|
)
|
||||||
),
|
|
||||||
"no_device": model.StructField(
|
|
||||||
data_type=model.PrimitiveNull(),
|
|
||||||
),
|
),
|
||||||
|
"no_device": model.StructField(data_type=model.PrimitiveNull()),
|
||||||
"connection_info": model.StructField(
|
"connection_info": model.StructField(
|
||||||
data_type=model.ConstraintString(
|
data_type=model.ConstraintString(maxLength=16777215)
|
||||||
maxLength=16777215,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
"source_type": model.StructField(
|
"source_type": model.StructField(
|
||||||
data_type=model.Reference(name="source_type", type=model.Enum)
|
data_type=model.Reference(name="source_type", type=model.Enum)
|
||||||
),
|
),
|
||||||
"uuid": model.StructField(
|
"uuid": model.StructField(
|
||||||
data_type=model.ConstraintString(
|
data_type=model.ConstraintString(
|
||||||
minLength=1,
|
minLength=1, maxLength=255, pattern="^[a-zA-Z0-9._-]*$"
|
||||||
maxLength=255,
|
)
|
||||||
pattern="^[a-zA-Z0-9._-]*$",
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
"image_id": model.StructField(
|
"image_id": model.StructField(
|
||||||
data_type=model.ConstraintString(
|
data_type=model.ConstraintString(format="uuid")
|
||||||
format="uuid",
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
"destination_type": model.StructField(
|
"destination_type": model.StructField(
|
||||||
data_type=model.Reference(name="destination_type", type=model.Enum)
|
data_type=model.Reference(
|
||||||
|
name="destination_type", type=model.Enum
|
||||||
|
)
|
||||||
),
|
),
|
||||||
"guest_format": model.StructField(
|
"guest_format": model.StructField(
|
||||||
data_type=model.ConstraintString(
|
data_type=model.ConstraintString(maxLength=255)
|
||||||
maxLength=255,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
"device_type": model.StructField(
|
"device_type": model.StructField(
|
||||||
data_type=model.ConstraintString(
|
data_type=model.ConstraintString(maxLength=255)
|
||||||
maxLength=255,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
"disk_bus": model.StructField(
|
"disk_bus": model.StructField(
|
||||||
data_type=model.ConstraintString(
|
data_type=model.ConstraintString(maxLength=255)
|
||||||
maxLength=255,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
"boot_index": model.StructField(
|
"boot_index": model.StructField(
|
||||||
data_type=model.Reference(name="boot_index", type=model.OneOfType),
|
data_type=model.Reference(
|
||||||
|
name="boot_index", type=model.OneOfType
|
||||||
|
)
|
||||||
),
|
),
|
||||||
"tag": model.StructField(
|
"tag": model.StructField(
|
||||||
data_type=model.ConstraintString(
|
data_type=model.ConstraintString(
|
||||||
minLength=1,
|
minLength=1, maxLength=60, pattern="^[^,/]*$"
|
||||||
maxLength=60,
|
)
|
||||||
pattern="^[^,/]*$",
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
"volume_type": model.StructField(
|
"volume_type": model.StructField(
|
||||||
data_type=model.Reference(name="volume_type", type=model.OneOfType),
|
data_type=model.Reference(
|
||||||
|
name="volume_type", type=model.OneOfType
|
||||||
|
)
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
model.Array(
|
model.Array(
|
||||||
reference=model.Reference(name="block_device_mapping", type=model.Array),
|
reference=model.Reference(
|
||||||
item_type=model.Reference(name="block_device_mapping", type=model.Struct),
|
name="block_device_mapping", type=model.Array
|
||||||
|
),
|
||||||
|
item_type=model.Reference(
|
||||||
|
name="block_device_mapping", type=model.Struct
|
||||||
|
),
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
model.Array(
|
model.Array(
|
||||||
reference=model.Reference(name="block_device_mapping_v2", type=model.Array),
|
reference=model.Reference(
|
||||||
item_type=model.Reference(name="block_device_mapping_v2", type=model.Struct),
|
name="block_device_mapping_v2", type=model.Array
|
||||||
|
),
|
||||||
|
item_type=model.Reference(
|
||||||
|
name="block_device_mapping_v2", type=model.Struct
|
||||||
|
),
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
model.Enum(
|
model.Enum(
|
||||||
reference=model.Reference(name="config_drive", type=model.Enum),
|
reference=model.Reference(name="config_drive", type=model.Enum),
|
||||||
base_types=[
|
base_types=[model.PrimitiveBoolean, model.ConstraintString],
|
||||||
model.PrimitiveBoolean,
|
literals={"No", "no", False},
|
||||||
model.ConstraintString,
|
|
||||||
],
|
|
||||||
literals=set(["No", "no", False]),
|
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
model.OneOfType(
|
model.OneOfType(
|
||||||
reference=model.Reference(name="min_count", type=model.OneOfType),
|
reference=model.Reference(name="min_count", type=model.OneOfType),
|
||||||
kinds=[
|
kinds=[
|
||||||
model.ConstraintInteger(
|
model.ConstraintInteger(minimum=1),
|
||||||
minimum=1,
|
model.ConstraintString(minLength=1, pattern="^[0-9]*$"),
|
||||||
),
|
|
||||||
model.ConstraintString(
|
|
||||||
minLength=1,
|
|
||||||
pattern="^[0-9]*$",
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
@ -726,9 +704,7 @@ EXPECTED_DATA_TYPES = [
|
|||||||
reference=model.Reference(name="description", type=model.OneOfType),
|
reference=model.Reference(name="description", type=model.OneOfType),
|
||||||
kinds=[
|
kinds=[
|
||||||
model.ConstraintString(
|
model.ConstraintString(
|
||||||
minLength=0,
|
minLength=0, maxLength=255, pattern="regex_pattern"
|
||||||
maxLength=255,
|
|
||||||
pattern="regex_pattern",
|
|
||||||
),
|
),
|
||||||
model.PrimitiveNull(),
|
model.PrimitiveNull(),
|
||||||
],
|
],
|
||||||
@ -742,7 +718,9 @@ EXPECTED_DATA_TYPES = [
|
|||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
model.Array(
|
model.Array(
|
||||||
reference=model.Reference(name="trusted_image_certificates", type=model.Array),
|
reference=model.Reference(
|
||||||
|
name="trusted_image_certificates", type=model.Array
|
||||||
|
),
|
||||||
item_type=model.ConstraintString(format=None, minLength=1),
|
item_type=model.ConstraintString(format=None, minLength=1),
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
@ -751,7 +729,9 @@ EXPECTED_DATA_TYPES = [
|
|||||||
name="trusted_image_certificates", type=model.OneOfType
|
name="trusted_image_certificates", type=model.OneOfType
|
||||||
),
|
),
|
||||||
kinds=[
|
kinds=[
|
||||||
model.Reference(name="trusted_image_certificates", type=model.Array),
|
model.Reference(
|
||||||
|
name="trusted_image_certificates", type=model.Array
|
||||||
|
),
|
||||||
model.PrimitiveNull(),
|
model.PrimitiveNull(),
|
||||||
],
|
],
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
@ -769,11 +749,15 @@ EXPECTED_DATA_TYPES = [
|
|||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
"imageRef": model.StructField(
|
"imageRef": model.StructField(
|
||||||
data_type=model.Reference(name="imageRef", type=model.OneOfType),
|
data_type=model.Reference(
|
||||||
|
name="imageRef", type=model.OneOfType
|
||||||
|
),
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
"flavorRef": model.StructField(
|
"flavorRef": model.StructField(
|
||||||
data_type=model.Reference(name="flavorRef", type=model.OneOfType),
|
data_type=model.Reference(
|
||||||
|
name="flavorRef", type=model.OneOfType
|
||||||
|
),
|
||||||
is_required=True,
|
is_required=True,
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
@ -781,18 +765,24 @@ EXPECTED_DATA_TYPES = [
|
|||||||
data_type=model.ConstraintString(format=None), min_ver="2.94"
|
data_type=model.ConstraintString(format=None), min_ver="2.94"
|
||||||
),
|
),
|
||||||
"metadata": model.StructField(
|
"metadata": model.StructField(
|
||||||
data_type=model.Reference(name="metadata", type=model.Dictionary),
|
data_type=model.Reference(
|
||||||
|
name="metadata", type=model.Dictionary
|
||||||
|
),
|
||||||
description="metadata description",
|
description="metadata description",
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
"networks": model.StructField(
|
"networks": model.StructField(
|
||||||
data_type=model.Reference(name="networks", type=model.OneOfType),
|
data_type=model.Reference(
|
||||||
|
name="networks", type=model.OneOfType
|
||||||
|
),
|
||||||
description="Networks description",
|
description="Networks description",
|
||||||
is_required=True,
|
is_required=True,
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
"OS-DCF:diskConfig": model.StructField(
|
"OS-DCF:diskConfig": model.StructField(
|
||||||
data_type=model.Reference(name="OS-DCF:diskConfig", type=model.Enum),
|
data_type=model.Reference(
|
||||||
|
name="OS-DCF:diskConfig", type=model.Enum
|
||||||
|
),
|
||||||
description="DiskConfig description",
|
description="DiskConfig description",
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
@ -822,28 +812,35 @@ EXPECTED_DATA_TYPES = [
|
|||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
"config_drive": model.StructField(
|
"config_drive": model.StructField(
|
||||||
data_type=model.Reference(name="config_drive", type=model.Enum),
|
data_type=model.Reference(
|
||||||
|
name="config_drive", type=model.Enum
|
||||||
|
),
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
"min_count": model.StructField(
|
"min_count": model.StructField(
|
||||||
data_type=model.Reference(name="min_count", type=model.OneOfType),
|
data_type=model.Reference(
|
||||||
|
name="min_count", type=model.OneOfType
|
||||||
|
),
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
"security_groups": model.StructField(
|
"security_groups": model.StructField(
|
||||||
data_type=model.Reference(name="security_groups", type=model.Array),
|
data_type=model.Reference(
|
||||||
|
name="security_groups", type=model.Array
|
||||||
|
),
|
||||||
description="SG descr",
|
description="SG descr",
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
"user_data": model.StructField(
|
"user_data": model.StructField(
|
||||||
data_type=model.ConstraintString(
|
data_type=model.ConstraintString(
|
||||||
format="base64",
|
format="base64", maxLength=65535
|
||||||
maxLength=65535,
|
|
||||||
),
|
),
|
||||||
description="user data",
|
description="user data",
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
"description": model.StructField(
|
"description": model.StructField(
|
||||||
data_type=model.Reference(name="description", type=model.OneOfType),
|
data_type=model.Reference(
|
||||||
|
name="description", type=model.OneOfType
|
||||||
|
),
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
"tags": model.StructField(
|
"tags": model.StructField(
|
||||||
@ -858,25 +855,19 @@ EXPECTED_DATA_TYPES = [
|
|||||||
),
|
),
|
||||||
"host": model.StructField(
|
"host": model.StructField(
|
||||||
data_type=model.ConstraintString(
|
data_type=model.ConstraintString(
|
||||||
minLength=1,
|
minLength=1, maxLength=255, pattern="^[a-zA-Z0-9-._]*$"
|
||||||
maxLength=255,
|
|
||||||
pattern="^[a-zA-Z0-9-._]*$",
|
|
||||||
),
|
),
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
"hypervisor_hostname": model.StructField(
|
"hypervisor_hostname": model.StructField(
|
||||||
data_type=model.ConstraintString(
|
data_type=model.ConstraintString(
|
||||||
minLength=1,
|
minLength=1, maxLength=255, pattern="^[a-zA-Z0-9-._]*$"
|
||||||
maxLength=255,
|
|
||||||
pattern="^[a-zA-Z0-9-._]*$",
|
|
||||||
),
|
),
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
"hostname": model.StructField(
|
"hostname": model.StructField(
|
||||||
data_type=model.ConstraintString(
|
data_type=model.ConstraintString(
|
||||||
minLength=1,
|
minLength=1, maxLength=255, pattern="^[a-zA-Z0-9-._]*$"
|
||||||
maxLength=255,
|
|
||||||
pattern="^[a-zA-Z0-9-._]*$",
|
|
||||||
),
|
),
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
@ -936,7 +927,9 @@ EXPECTED_DATA_TYPES = [
|
|||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
model.OneOfType(
|
model.OneOfType(
|
||||||
reference=model.Reference(name="build_near_host_ip", type=model.OneOfType),
|
reference=model.Reference(
|
||||||
|
name="build_near_host_ip", type=model.OneOfType
|
||||||
|
),
|
||||||
kinds=[
|
kinds=[
|
||||||
model.ConstraintString(format="ipv4"),
|
model.ConstraintString(format="ipv4"),
|
||||||
model.ConstraintString(format="ipv6"),
|
model.ConstraintString(format="ipv6"),
|
||||||
@ -944,18 +937,24 @@ EXPECTED_DATA_TYPES = [
|
|||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
model.Struct(
|
model.Struct(
|
||||||
reference=model.Reference(name="os:scheduler_hints", type=model.Struct),
|
reference=model.Reference(
|
||||||
|
name="os:scheduler_hints", type=model.Struct
|
||||||
|
),
|
||||||
description="scheduler hints description",
|
description="scheduler hints description",
|
||||||
fields={
|
fields={
|
||||||
"group": model.StructField(
|
"group": model.StructField(
|
||||||
data_type=model.ConstraintString(format="uuid"), min_ver="2.94"
|
data_type=model.ConstraintString(format="uuid"), min_ver="2.94"
|
||||||
),
|
),
|
||||||
"different_host": model.StructField(
|
"different_host": model.StructField(
|
||||||
data_type=model.Reference(name="different_host", type=model.OneOfType),
|
data_type=model.Reference(
|
||||||
|
name="different_host", type=model.OneOfType
|
||||||
|
),
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
"same_host": model.StructField(
|
"same_host": model.StructField(
|
||||||
data_type=model.Reference(name="same_host", type=model.OneOfType),
|
data_type=model.Reference(
|
||||||
|
name="same_host", type=model.OneOfType
|
||||||
|
),
|
||||||
description="A list of server UUIDs or a server UUID.",
|
description="A list of server UUIDs or a server UUID.",
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
@ -970,7 +969,9 @@ EXPECTED_DATA_TYPES = [
|
|||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
"different_cell": model.StructField(
|
"different_cell": model.StructField(
|
||||||
data_type=model.Reference(name="different_cell", type=model.OneOfType),
|
data_type=model.Reference(
|
||||||
|
name="different_cell", type=model.OneOfType
|
||||||
|
),
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
"build_near_host_ip": model.StructField(
|
"build_near_host_ip": model.StructField(
|
||||||
@ -981,9 +982,7 @@ EXPECTED_DATA_TYPES = [
|
|||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
"cidr": model.StructField(
|
"cidr": model.StructField(
|
||||||
data_type=model.ConstraintString(
|
data_type=model.ConstraintString(pattern="^/[0-9a-f.:]+$"),
|
||||||
pattern="^/[0-9a-f.:]+$",
|
|
||||||
),
|
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -1031,30 +1030,26 @@ EXPECTED_DATA_TYPES = [
|
|||||||
),
|
),
|
||||||
model.Enum(
|
model.Enum(
|
||||||
reference=model.Reference(name="source_type", type=model.Enum),
|
reference=model.Reference(name="source_type", type=model.Enum),
|
||||||
literals=set(["volume", "image", "snapshot", "blank"]),
|
literals={"volume", "image", "snapshot", "blank"},
|
||||||
base_types=[
|
base_types=[model.ConstraintString],
|
||||||
model.ConstraintString,
|
|
||||||
],
|
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
model.Enum(
|
model.Enum(
|
||||||
reference=model.Reference(name="destination_type", type=model.Enum),
|
reference=model.Reference(name="destination_type", type=model.Enum),
|
||||||
literals=set(["volume", "local"]),
|
literals={"volume", "local"},
|
||||||
base_types=[
|
base_types=[model.ConstraintString],
|
||||||
model.ConstraintString,
|
|
||||||
],
|
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
model.Enum(
|
model.Enum(
|
||||||
reference=model.Reference(name="OS-DCF:diskConfig", type=model.Enum),
|
reference=model.Reference(name="OS-DCF:diskConfig", type=model.Enum),
|
||||||
literals=set(["AUTO", "MANUAL"]),
|
literals={"AUTO", "MANUAL"},
|
||||||
base_types=[
|
base_types=[model.ConstraintString],
|
||||||
model.ConstraintString,
|
|
||||||
],
|
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
model.OneOfType(
|
model.OneOfType(
|
||||||
reference=model.Reference(name="build_near_host_ip", type=model.OneOfType),
|
reference=model.Reference(
|
||||||
|
name="build_near_host_ip", type=model.OneOfType
|
||||||
|
),
|
||||||
kinds=[
|
kinds=[
|
||||||
model.ConstraintString(format="ipv4"),
|
model.ConstraintString(format="ipv4"),
|
||||||
model.ConstraintString(format="ipv6"),
|
model.ConstraintString(format="ipv6"),
|
||||||
@ -1062,18 +1057,24 @@ EXPECTED_DATA_TYPES = [
|
|||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
model.Struct(
|
model.Struct(
|
||||||
reference=model.Reference(name="OS-SCH-HNT:scheduler_hints", type=model.Struct),
|
reference=model.Reference(
|
||||||
|
name="OS-SCH-HNT:scheduler_hints", type=model.Struct
|
||||||
|
),
|
||||||
fields={
|
fields={
|
||||||
"group": model.StructField(
|
"group": model.StructField(
|
||||||
data_type=model.ConstraintString(format="uuid"), min_ver="2.94"
|
data_type=model.ConstraintString(format="uuid"), min_ver="2.94"
|
||||||
),
|
),
|
||||||
"different_host": model.StructField(
|
"different_host": model.StructField(
|
||||||
data_type=model.Reference(name="different_host", type=model.OneOfType),
|
data_type=model.Reference(
|
||||||
|
name="different_host", type=model.OneOfType
|
||||||
|
),
|
||||||
description="A list of server UUIDs or a server UUID.\nSchedule the server on a different host from a set of servers.\nIt is available when `DifferentHostFilter` is available on cloud side.",
|
description="A list of server UUIDs or a server UUID.\nSchedule the server on a different host from a set of servers.\nIt is available when `DifferentHostFilter` is available on cloud side.",
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
"same_host": model.StructField(
|
"same_host": model.StructField(
|
||||||
data_type=model.Reference(name="same_host", type=model.OneOfType),
|
data_type=model.Reference(
|
||||||
|
name="same_host", type=model.OneOfType
|
||||||
|
),
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
"query": model.StructField(
|
"query": model.StructField(
|
||||||
@ -1087,7 +1088,9 @@ EXPECTED_DATA_TYPES = [
|
|||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
"different_cell": model.StructField(
|
"different_cell": model.StructField(
|
||||||
data_type=model.Reference(name="different_cell", type=model.OneOfType),
|
data_type=model.Reference(
|
||||||
|
name="different_cell", type=model.OneOfType
|
||||||
|
),
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
"build_near_host_ip": model.StructField(
|
"build_near_host_ip": model.StructField(
|
||||||
@ -1097,9 +1100,7 @@ EXPECTED_DATA_TYPES = [
|
|||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
"cidr": model.StructField(
|
"cidr": model.StructField(
|
||||||
data_type=model.ConstraintString(
|
data_type=model.ConstraintString(pattern="^/[0-9a-f.:]+$"),
|
||||||
pattern="^/[0-9a-f.:]+$",
|
|
||||||
),
|
|
||||||
min_ver="2.94",
|
min_ver="2.94",
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -1136,10 +1137,7 @@ class TestModel(TestCase):
|
|||||||
schema = {
|
schema = {
|
||||||
"in": "query",
|
"in": "query",
|
||||||
"name": "tags",
|
"name": "tags",
|
||||||
"schema": {
|
"schema": {"type": "string", "format": "regex"},
|
||||||
"type": "string",
|
|
||||||
"format": "regex",
|
|
||||||
},
|
|
||||||
"x-openstack": {"min-ver": "2.26"},
|
"x-openstack": {"min-ver": "2.26"},
|
||||||
}
|
}
|
||||||
parser = model.OpenAPISchemaParser()
|
parser = model.OpenAPISchemaParser()
|
||||||
|
@ -27,7 +27,11 @@ class TestParserObject(TestCase):
|
|||||||
(res, all) = self.parser.parse(schema)
|
(res, all) = self.parser.parse(schema)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
model.Struct(
|
model.Struct(
|
||||||
fields={"foo": model.StructField(data_type=model.ConstraintString())}
|
fields={
|
||||||
|
"foo": model.StructField(
|
||||||
|
data_type=model.ConstraintString()
|
||||||
|
)
|
||||||
|
}
|
||||||
),
|
),
|
||||||
res,
|
res,
|
||||||
)
|
)
|
||||||
@ -36,15 +40,17 @@ class TestParserObject(TestCase):
|
|||||||
def test_parse_props_additional_props_forbidden(self):
|
def test_parse_props_additional_props_forbidden(self):
|
||||||
schema = {
|
schema = {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {"foo": {"type": "string"}},
|
||||||
"foo": {"type": "string"},
|
|
||||||
},
|
|
||||||
"additionalProperties": False,
|
"additionalProperties": False,
|
||||||
}
|
}
|
||||||
(res, all) = self.parser.parse(schema)
|
(res, all) = self.parser.parse(schema)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
model.Struct(
|
model.Struct(
|
||||||
fields={"foo": model.StructField(data_type=model.ConstraintString())}
|
fields={
|
||||||
|
"foo": model.StructField(
|
||||||
|
data_type=model.ConstraintString()
|
||||||
|
)
|
||||||
|
}
|
||||||
),
|
),
|
||||||
res,
|
res,
|
||||||
)
|
)
|
||||||
@ -53,15 +59,17 @@ class TestParserObject(TestCase):
|
|||||||
def test_parse_props_additional_props_allowed(self):
|
def test_parse_props_additional_props_allowed(self):
|
||||||
schema = {
|
schema = {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {"foo": {"type": "string"}},
|
||||||
"foo": {"type": "string"},
|
|
||||||
},
|
|
||||||
"additionalProperties": True,
|
"additionalProperties": True,
|
||||||
}
|
}
|
||||||
(res, all) = self.parser.parse(schema)
|
(res, all) = self.parser.parse(schema)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
model.Struct(
|
model.Struct(
|
||||||
fields={"foo": model.StructField(data_type=model.ConstraintString())},
|
fields={
|
||||||
|
"foo": model.StructField(
|
||||||
|
data_type=model.ConstraintString()
|
||||||
|
)
|
||||||
|
},
|
||||||
additional_fields=model.PrimitiveAny(),
|
additional_fields=model.PrimitiveAny(),
|
||||||
),
|
),
|
||||||
res,
|
res,
|
||||||
@ -71,15 +79,17 @@ class TestParserObject(TestCase):
|
|||||||
def test_parse_props_additional_props_type(self):
|
def test_parse_props_additional_props_type(self):
|
||||||
schema = {
|
schema = {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {"foo": {"type": "string"}},
|
||||||
"foo": {"type": "string"},
|
|
||||||
},
|
|
||||||
"additionalProperties": {"type": "string"},
|
"additionalProperties": {"type": "string"},
|
||||||
}
|
}
|
||||||
(res, all) = self.parser.parse(schema)
|
(res, all) = self.parser.parse(schema)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
model.Struct(
|
model.Struct(
|
||||||
fields={"foo": model.StructField(data_type=model.ConstraintString())},
|
fields={
|
||||||
|
"foo": model.StructField(
|
||||||
|
data_type=model.ConstraintString()
|
||||||
|
)
|
||||||
|
},
|
||||||
additional_fields=model.ConstraintString(),
|
additional_fields=model.ConstraintString(),
|
||||||
),
|
),
|
||||||
res,
|
res,
|
||||||
@ -87,14 +97,10 @@ class TestParserObject(TestCase):
|
|||||||
self.assertEqual(1, len(all))
|
self.assertEqual(1, len(all))
|
||||||
|
|
||||||
def test_parse_only_additional_props(self):
|
def test_parse_only_additional_props(self):
|
||||||
schema = {
|
schema = {"type": "object", "additionalProperties": {"type": "string"}}
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {"type": "string"},
|
|
||||||
}
|
|
||||||
(res, all) = self.parser.parse(schema)
|
(res, all) = self.parser.parse(schema)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
model.Dictionary(value_type=model.ConstraintString()),
|
model.Dictionary(value_type=model.ConstraintString()), res
|
||||||
res,
|
|
||||||
)
|
)
|
||||||
self.assertEqual(1, len(all))
|
self.assertEqual(1, len(all))
|
||||||
|
|
||||||
@ -184,18 +190,18 @@ class TestParserObject(TestCase):
|
|||||||
def test_parse_pattern_props(self):
|
def test_parse_pattern_props(self):
|
||||||
schema = {
|
schema = {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {"foo": {"type": "string"}},
|
||||||
"foo": {"type": "string"},
|
|
||||||
},
|
|
||||||
"patternProperties": {"^A": {"type": "string"}},
|
"patternProperties": {"^A": {"type": "string"}},
|
||||||
}
|
}
|
||||||
(res, all) = self.parser.parse(schema)
|
(res, all) = self.parser.parse(schema)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
model.Struct(
|
model.Struct(
|
||||||
fields={"foo": model.StructField(data_type=model.ConstraintString())},
|
fields={
|
||||||
pattern_properties={
|
"foo": model.StructField(
|
||||||
"^A": model.ConstraintString(),
|
data_type=model.ConstraintString()
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|
pattern_properties={"^A": model.ConstraintString()},
|
||||||
),
|
),
|
||||||
res,
|
res,
|
||||||
)
|
)
|
||||||
@ -208,19 +214,15 @@ class TestParserObject(TestCase):
|
|||||||
}
|
}
|
||||||
(res, all) = self.parser.parse(schema)
|
(res, all) = self.parser.parse(schema)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
model.Dictionary(value_type=model.ConstraintString()),
|
model.Dictionary(value_type=model.ConstraintString()), res
|
||||||
res,
|
|
||||||
)
|
)
|
||||||
self.assertEqual(1, len(all))
|
self.assertEqual(1, len(all))
|
||||||
|
|
||||||
def test_parse_empty(self):
|
def test_parse_empty(self):
|
||||||
schema = {
|
schema = {"type": "object"}
|
||||||
"type": "object",
|
|
||||||
}
|
|
||||||
(res, all) = self.parser.parse(schema)
|
(res, all) = self.parser.parse(schema)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
model.Dictionary(value_type=model.PrimitiveAny()),
|
model.Dictionary(value_type=model.PrimitiveAny()), res
|
||||||
res,
|
|
||||||
)
|
)
|
||||||
self.assertEqual(1, len(all))
|
self.assertEqual(1, len(all))
|
||||||
|
|
||||||
@ -228,16 +230,8 @@ class TestParserObject(TestCase):
|
|||||||
schema = {
|
schema = {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{
|
{"properties": {"foo": {"type": "string"}}},
|
||||||
"properties": {
|
{"properties": {"bar": {"type": "string"}}},
|
||||||
"foo": {"type": "string"},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"properties": {
|
|
||||||
"bar": {"type": "string"},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
(res, all) = self.parser.parse(schema)
|
(res, all) = self.parser.parse(schema)
|
||||||
@ -246,13 +240,17 @@ class TestParserObject(TestCase):
|
|||||||
kinds=[
|
kinds=[
|
||||||
model.Struct(
|
model.Struct(
|
||||||
fields={
|
fields={
|
||||||
"foo": model.StructField(data_type=model.ConstraintString())
|
"foo": model.StructField(
|
||||||
},
|
data_type=model.ConstraintString()
|
||||||
|
)
|
||||||
|
}
|
||||||
),
|
),
|
||||||
model.Struct(
|
model.Struct(
|
||||||
fields={
|
fields={
|
||||||
"bar": model.StructField(data_type=model.ConstraintString())
|
"bar": model.StructField(
|
||||||
},
|
data_type=model.ConstraintString()
|
||||||
|
)
|
||||||
|
}
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
@ -265,11 +263,7 @@ class TestParserObject(TestCase):
|
|||||||
schema = {
|
schema = {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"allOf": [
|
"allOf": [
|
||||||
{
|
{"properties": {"foo": {"type": "string"}}},
|
||||||
"properties": {
|
|
||||||
"foo": {"type": "string"},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"properties": {
|
"properties": {
|
||||||
"foo": {"type": "string"},
|
"foo": {"type": "string"},
|
||||||
@ -286,8 +280,10 @@ class TestParserObject(TestCase):
|
|||||||
"foo": model.StructField(
|
"foo": model.StructField(
|
||||||
data_type=model.ConstraintString(), is_required=True
|
data_type=model.ConstraintString(), is_required=True
|
||||||
),
|
),
|
||||||
"bar": model.StructField(data_type=model.ConstraintString()),
|
"bar": model.StructField(
|
||||||
},
|
data_type=model.ConstraintString()
|
||||||
|
),
|
||||||
|
}
|
||||||
),
|
),
|
||||||
res,
|
res,
|
||||||
)
|
)
|
||||||
|
@ -51,7 +51,7 @@ class TestRustSdkModel(TestCase):
|
|||||||
),
|
),
|
||||||
"g": model.StructField(
|
"g": model.StructField(
|
||||||
data_type=model.Dictionary(
|
data_type=model.Dictionary(
|
||||||
value_type=model.PrimitiveString(),
|
value_type=model.PrimitiveString()
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -120,7 +120,7 @@ class TestRustSdkModel(TestCase):
|
|||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
field.type_hint, "Option<BTreeMap<Cow<'a, str>, Cow<'a, str>>>"
|
field.type_hint, "Option<BTreeMap<Cow<'a, str>, Cow<'a, str>>>"
|
||||||
)
|
)
|
||||||
self.assertEqual(set(["'a"]), mod.lifetimes)
|
self.assertEqual({"'a"}, mod.lifetimes)
|
||||||
|
|
||||||
def test_get_submodels(self):
|
def test_get_submodels(self):
|
||||||
logging.basicConfig(level=logging.DEBUG)
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
@ -128,15 +128,13 @@ class TestRustSdkModel(TestCase):
|
|||||||
type_manager.set_models(test_model.EXPECTED_DATA_TYPES)
|
type_manager.set_models(test_model.EXPECTED_DATA_TYPES)
|
||||||
# res = type_manager.get_subtypes()
|
# res = type_manager.get_subtypes()
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
set(
|
{
|
||||||
[
|
"std::collections::BTreeMap",
|
||||||
"std::collections::BTreeMap",
|
"std::borrow::Cow",
|
||||||
"std::borrow::Cow",
|
"serde::Deserialize",
|
||||||
"serde::Deserialize",
|
"serde::Serialize",
|
||||||
"serde::Serialize",
|
"serde_json::Value",
|
||||||
"serde_json::Value",
|
},
|
||||||
]
|
|
||||||
),
|
|
||||||
type_manager.get_imports(),
|
type_manager.get_imports(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -21,10 +21,7 @@ sys.path.insert(0, os.path.abspath("."))
|
|||||||
|
|
||||||
# Add any Sphinx extension module names here, as strings. They can be
|
# Add any Sphinx extension module names here, as strings. They can be
|
||||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||||
extensions = [
|
extensions = ["sphinx.ext.autodoc", "openstackdocstheme"]
|
||||||
"sphinx.ext.autodoc",
|
|
||||||
"openstackdocstheme",
|
|
||||||
]
|
|
||||||
|
|
||||||
# openstackdocstheme options
|
# openstackdocstheme options
|
||||||
openstackdocs_repo_name = "openstack/codegenerator"
|
openstackdocs_repo_name = "openstack/codegenerator"
|
||||||
@ -86,7 +83,7 @@ latex_documents = [
|
|||||||
"OpenStackCodegenerator Documentation",
|
"OpenStackCodegenerator Documentation",
|
||||||
"OpenStack Foundation",
|
"OpenStack Foundation",
|
||||||
"manual",
|
"manual",
|
||||||
),
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
# Allow deeper levels of nesting for \begin...\end stanzas
|
# Allow deeper levels of nesting for \begin...\end stanzas
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
# You may obtain a copy of the License at
|
# You may obtain a copy of the License at
|
||||||
@ -45,11 +44,7 @@ from sphinx.util import logging
|
|||||||
linklogger = logging.getLogger("sphinx.ext.extlinks")
|
linklogger = logging.getLogger("sphinx.ext.extlinks")
|
||||||
linklogger.setLevel(40) # Ignore messages less severe than ERROR
|
linklogger.setLevel(40) # Ignore messages less severe than ERROR
|
||||||
|
|
||||||
extensions = [
|
extensions = ["openstackdocstheme", "reno.sphinxext", "sphinx.ext.extlinks"]
|
||||||
"openstackdocstheme",
|
|
||||||
"reno.sphinxext",
|
|
||||||
"sphinx.ext.extlinks",
|
|
||||||
]
|
|
||||||
|
|
||||||
# openstackdocstheme options
|
# openstackdocstheme options
|
||||||
openstackdocs_repo_name = "openstack/codegenerator"
|
openstackdocs_repo_name = "openstack/codegenerator"
|
||||||
@ -132,9 +127,7 @@ html_theme = "openstackdocs"
|
|||||||
# Theme options are theme-specific and customize the look and feel of a theme
|
# Theme options are theme-specific and customize the look and feel of a theme
|
||||||
# further. For a list of options available for each theme, see the
|
# further. For a list of options available for each theme, see the
|
||||||
# documentation.
|
# documentation.
|
||||||
html_theme_options = {
|
html_theme_options = {"display_toc": False}
|
||||||
"display_toc": False,
|
|
||||||
}
|
|
||||||
|
|
||||||
# Add any paths that contain custom themes here, relative to this directory.
|
# Add any paths that contain custom themes here, relative to this directory.
|
||||||
# html_theme_path = []
|
# html_theme_path = []
|
||||||
|
Loading…
x
Reference in New Issue
Block a user