Merge "Start building parts of TUI"

This commit is contained in:
Zuul 2024-12-16 17:39:34 +00:00 committed by Gerrit Code Review
commit ca373468f7
21 changed files with 794 additions and 39 deletions

View File

@ -32,6 +32,7 @@ from codegenerator.openapi_spec import OpenApiSchemaGenerator
# from codegenerator.osc import OSCGenerator
from codegenerator.rust_cli import RustCliGenerator
from codegenerator.rust_tui import RustTuiGenerator
from codegenerator.rust_sdk import RustSdkGenerator
from codegenerator.types import Metadata
@ -157,6 +158,7 @@ def main():
"ansible",
"rust-sdk",
"rust-cli",
"rust-tui",
"openapi-spec",
"jsonschema",
"metadata",
@ -196,8 +198,9 @@ def main():
generators = {
# "osc": OSCGenerator(),
# "ansible": AnsibleGenerator(),
"rust-sdk": RustSdkGenerator(),
"rust-cli": RustCliGenerator(),
"rust-tui": RustTuiGenerator(),
"rust-sdk": RustSdkGenerator(),
"openapi-spec": OpenApiSchemaGenerator(),
"jsonschema": JsonSchemaGenerator(),
"metadata": MetadataGenerator(),
@ -269,7 +272,7 @@ def main():
)
)
if args.target == "rust-sdk" and not args.resource:
if args.target in ["rust-sdk", "rust-tui"] and not args.resource:
resource_results: dict[str, dict] = {}
for mod_path, mod_name, path in res_mods:
mn = "/".join(mod_path)
@ -300,7 +303,7 @@ def main():
x["mods"].add(mod_name)
for path, gen_data in resource_results.items():
generators["rust-sdk"].generate_mod(
generators[args.target].generate_mod(
args.work_dir,
path.split("/"),
gen_data["mods"],

View File

@ -13,6 +13,7 @@
import typing as ty
from codegenerator.types import OperationModel
from codegenerator.types import OperationTargetParams
from codegenerator.metadata.base import MetadataBase
@ -132,4 +133,20 @@ class BlockStorageMetadata(MetadataBase):
"rust-cli"
].cli_full_command.replace("delete-all", "purge")
if resource_name in ["backup", "snapshot", "volume"]:
if operation_name in ["list", "delete"]:
operation.targets.setdefault(
"rust-tui",
OperationTargetParams(
module_name=operation.targets["rust-sdk"].module_name
),
)
if resource_name == "quota_set" and operation_name == "details":
operation.targets.setdefault(
"rust-tui",
OperationTargetParams(
module_name=operation.targets["rust-sdk"].module_name
),
)
return operation

View File

@ -14,6 +14,7 @@
import typing as ty
from codegenerator.types import OperationModel
from codegenerator.types import OperationTargetParams
from codegenerator.metadata.base import MetadataBase
@ -192,4 +193,27 @@ class ComputeMetadata(MetadataBase):
"rust-cli"
].cli_full_command.replace("delete-all", "purge")
if resource_name in [
"aggregate",
"flavor",
"hypervisor",
"server",
"server/instance_action",
]:
if operation_name in ["list", "delete", "show"]:
operation.targets.setdefault(
"rust-tui",
OperationTargetParams(
module_name=operation.targets["rust-sdk"].module_name
),
)
if resource_name == "quota_set" and operation_name == "details":
operation.targets.setdefault(
"rust-tui",
OperationTargetParams(
module_name=operation.targets["rust-sdk"].module_name
),
)
return operation

View File

@ -14,6 +14,7 @@
import typing as ty
from codegenerator.types import OperationModel
from codegenerator.types import OperationTargetParams
from codegenerator.metadata.base import MetadataBase
@ -45,4 +46,12 @@ class DnsMetadata(MetadataBase):
def post_process_operation(
resource_name: str, operation_name: str, operation
):
if resource_name in ["zone", "recordset", "zone/recordset"]:
if operation_name in ["list", "delete"]:
operation.targets.setdefault(
"rust-tui",
OperationTargetParams(
module_name=operation.targets["rust-sdk"].module_name
),
)
return operation

View File

@ -14,6 +14,7 @@
import typing as ty
from codegenerator.types import OperationModel
from codegenerator.types import OperationTargetParams
from codegenerator.metadata.base import MetadataBase
@ -140,4 +141,19 @@ class IdentityMetadata(MetadataBase):
"rust-cli"
].cli_full_command.replace("delete-all", "purge")
if resource_name in [
"auth/project",
"group",
"group/user",
"project",
"user",
"user/application_credential",
]:
if operation_name in ["list", "delete"]:
operation.targets.setdefault(
"rust-tui",
OperationTargetParams(
module_name=operation.targets["rust-sdk"].module_name
),
)
return operation

View File

@ -14,6 +14,7 @@
import typing as ty
from codegenerator.types import OperationModel
from codegenerator.types import OperationTargetParams
from codegenerator.metadata.base import MetadataBase
@ -103,4 +104,12 @@ class ImageMetadata(MetadataBase):
"rust-cli"
].cli_full_command.replace("delete-all", "purge")
if resource_name in ["image"]:
if operation_name in ["list", "delete"]:
operation.targets.setdefault(
"rust-tui",
OperationTargetParams(
module_name=operation.targets["rust-sdk"].module_name
),
)
return operation

View File

@ -14,6 +14,7 @@
import typing as ty
from codegenerator.types import OperationModel
from codegenerator.types import OperationTargetParams
from codegenerator.metadata.base import MetadataBase
@ -40,4 +41,19 @@ class LoadBalancerMetadata(MetadataBase):
def post_process_operation(
resource_name: str, operation_name: str, operation
):
if resource_name in [
"healthmonitor",
"loadbalancer",
"listener",
"quota",
"pool",
"pool/member",
]:
if operation_name in ["list", "delete", "show"]:
operation.targets.setdefault(
"rust-tui",
OperationTargetParams(
module_name=operation.targets["rust-sdk"].module_name
),
)
return operation

View File

@ -14,6 +14,7 @@
import typing as ty
from codegenerator.types import OperationModel
from codegenerator.types import OperationTargetParams
from codegenerator.metadata.base import MetadataBase
@ -86,4 +87,25 @@ class NetworkMetadata(MetadataBase):
"rust-cli"
].cli_full_command.replace("delete-all", "purge")
if resource_name in [
"network",
"router",
"security_group",
"security_group_rule",
"subnet",
]:
if operation_name in ["list", "delete"]:
operation.targets.setdefault(
"rust-tui",
OperationTargetParams(
module_name=operation.targets["rust-sdk"].module_name
),
)
if resource_name == "quota" and operation_name == "details":
operation.targets.setdefault(
"rust-tui",
OperationTargetParams(
module_name=operation.targets["rust-sdk"].module_name
),
)
return operation

343
codegenerator/rust_tui.py Normal file
View File

@ -0,0 +1,343 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
import logging
from pathlib import Path
import re
import subprocess
from typing import Type, Any
from codegenerator.base import BaseGenerator
from codegenerator import common
from codegenerator import model
from codegenerator.common import BaseCompoundType
from codegenerator.common import rust as common_rust
from codegenerator.rust_sdk import TypeManager as SdkTypeManager
class String(common_rust.String):
type_hint: str = "String"
class TypeManager(common_rust.TypeManager):
"""Rust SDK type manager
The class is responsible for converting ADT models into types suitable
for Rust (SDK).
"""
primitive_type_mapping: dict[Type[model.PrimitiveType], Type[Any]] = {
model.PrimitiveString: String,
model.ConstraintString: String,
}
data_type_mapping = {model.Struct: common_rust.Struct}
request_parameter_class: Type[common_rust.RequestParameter] = (
common_rust.RequestParameter
)
def get_local_attribute_name(self, name: str) -> str:
"""Get localized attribute name"""
name = name.replace(".", "_")
attr_name = "_".join(
x.lower() for x in re.split(common.SPLIT_NAME_RE, name)
)
if attr_name in ["type", "self", "enum", "ref", "default"]:
attr_name = f"_{attr_name}"
return attr_name
def get_remote_attribute_name(self, name: str) -> str:
"""Get the attribute name on the SDK side"""
return self.get_local_attribute_name(name)
class RustTuiGenerator(BaseGenerator):
def __init__(self):
super().__init__()
def _format_code(self, *args):
"""Format code using Rustfmt
:param *args: Path to the code to format
"""
for path in args:
subprocess.run(["rustfmt", "--edition", "2021", path])
def _render_command(
self, context: dict, impl_template: str, impl_dest: Path
):
"""Render command code"""
self._render(impl_template, context, impl_dest.parent, impl_dest.name)
def generate(
self, res, target_dir, openapi_spec=None, operation_id=None, args=None
):
"""Generate code for the Rust openstack_tui"""
logging.debug(
"Generating Rust TUI code for %s in %s [%s]",
operation_id,
target_dir,
args,
)
if not openapi_spec:
openapi_spec = common.get_openapi_spec(args.openapi_yaml_spec)
if not operation_id:
operation_id = args.openapi_operation_id
(path, method, spec) = common.find_openapi_operation(
openapi_spec, operation_id
)
# srv_name, res_name = res.split(".") if res else (None, None)
path_resources = common.get_resource_names_from_url(path)
res_name = path_resources[-1]
mime_type = None
openapi_parser = model.OpenAPISchemaParser()
operation_params: list[model.RequestParameter] = []
type_manager: TypeManager | None = None
sdk_type_manager: SdkTypeManager | None = None
is_json_patch: bool = False
# Collect all operation parameters
for param in openapi_spec["paths"][path].get(
"parameters", []
) + spec.get("parameters", []):
if (
("{" + param["name"] + "}") in path and param["in"] == "path"
) or param["in"] != "path":
# Respect path params that appear in path and not path params
param_ = openapi_parser.parse_parameter(param)
if param_.name in [
f"{res_name}_id",
f"{res_name.replace('_', '')}_id",
]:
path = path.replace(param_.name, "id")
# for i.e. routers/{router_id} we want local_name to be `id` and not `router_id`
param_.name = "id"
operation_params.append(param_)
# Process body information
# List of operation variants (based on the body)
operation_variants = common.get_operation_variants(
spec, args.operation_name
)
api_ver_matches: re.Match | None = None
path_elements = path.lstrip("/").split("/")
api_ver: dict[str, int] = {}
ver_prefix: str | None = None
is_list_paginated = False
if path_elements:
api_ver_matches = re.match(common.VERSION_RE, path_elements[0])
if api_ver_matches and api_ver_matches.groups():
# Remember the version prefix to discard it in the template
ver_prefix = path_elements[0]
for operation_variant in operation_variants:
logging.debug(f"Processing variant {operation_variant}")
# TODO(gtema): if we are in MV variants filter out unsupported query
# parameters
# TODO(gtema): previously we were ensuring `router_id` path param
# is renamed to `id`
if api_ver_matches:
api_ver = {
"major": api_ver_matches.group(1),
"minor": api_ver_matches.group(3) or 0,
}
else:
api_ver = {}
service_name = common.get_rust_service_type_from_str(
args.service_type
)
class_name = f"{service_name}{res_name.title()}{args.operation_type.title()}".replace(
"_", ""
)
operation_body = operation_variant.get("body")
type_manager = TypeManager()
sdk_type_manager = SdkTypeManager()
type_manager.set_parameters(operation_params)
sdk_type_manager.set_parameters(operation_params)
mod_name = "_".join(
x.lower()
for x in re.split(
common.SPLIT_NAME_RE,
(
args.module_name
or args.operation_name
or args.operation_type.value
or method
),
)
)
if operation_body:
min_ver = operation_body.get("x-openstack", {}).get("min-ver")
if min_ver:
mod_name += "_" + min_ver.replace(".", "")
v = min_ver.split(".")
if not len(v) == 2:
raise RuntimeError(
"Version information is not in format MAJOR.MINOR"
)
api_ver = {"major": v[0], "minor": v[1]}
# There is request body. Get the ADT from jsonschema
# if args.operation_type != "action":
(_, all_types) = openapi_parser.parse(
operation_body, ignore_read_only=True
)
# and feed them into the TypeManager
type_manager.set_models(all_types)
sdk_type_manager.set_models(all_types)
# else:
# logging.warn("Ignoring response type of action")
if method == "patch":
# There might be multiple supported mime types. We only select ones we are aware of
mime_type = operation_variant.get("mime_type")
if not mime_type:
raise RuntimeError(
"No supported mime types for patch operation found"
)
if mime_type != "application/json":
is_json_patch = True
mod_path = common.get_rust_sdk_mod_path(
args.service_type,
args.api_version,
args.alternative_module_path or path,
)
response_key: str | None = None
if args.response_key:
response_key = (
args.response_key if args.response_key != "null" else None
)
else:
# Get basic information about response
if method.upper() != "HEAD":
for code, rspec in spec["responses"].items():
if not code.startswith("2"):
continue
content = rspec.get("content", {})
if "application/json" in content:
response_spec = content["application/json"]
try:
(_, response_key) = (
common.find_resource_schema(
response_spec["schema"],
None,
res_name.lower(),
)
)
except Exception:
# Most likely we have response which is oneOf.
# For the SDK it does not really harm to ignore
# this.
pass
# response_def = (None,)
response_key = None
sdk_mod_path_base = common.get_rust_sdk_mod_path(
args.service_type, args.api_version, args.module_path or path
)
sdk_mod_path: list[str] = sdk_mod_path_base.copy()
mod_suffix: str = ""
sdk_mod_path.append((args.sdk_mod_name or mod_name) + mod_suffix)
additional_imports = set()
additional_imports.add(
"openstack_sdk::api::"
+ "::".join(sdk_mod_path)
+ "::RequestBuilder"
)
additional_imports.add(
"openstack_sdk::{AsyncOpenStack, api::QueryAsync}"
)
if args.operation_type == "list":
if "limit" in [
k for (k, _) in type_manager.get_parameters("query")
]:
is_list_paginated = True
additional_imports.add(
"openstack_sdk::api::{paged, Pagination}"
)
elif args.operation_type == "delete":
additional_imports.add("openstack_sdk::api::ignore")
additional_imports.add(
"crate::cloud_worker::ConfirmableRequest"
)
context = {
"additional_imports": additional_imports,
"operation_id": operation_id,
"operation_type": spec.get(
"x-openstack-operation-type", args.operation_type
),
"command_description": common_rust.sanitize_rust_docstrings(
common.make_ascii_string(spec.get("description"))
),
"class_name": class_name,
"sdk_service_name": service_name,
"resource_name": res_name,
"url": path.lstrip("/").lstrip(ver_prefix).lstrip("/"),
"method": method,
"type_manager": type_manager,
"sdk_type_manager": sdk_type_manager,
"sdk_mod_path": sdk_mod_path,
"response_key": response_key,
"response_list_item_key": args.response_list_item_key,
"mime_type": mime_type,
"is_json_patch": is_json_patch,
"api_ver": api_ver,
"is_list_paginated": is_list_paginated,
}
work_dir = Path(target_dir, "rust", "openstack_tui", "src")
impl_path = Path(
work_dir, "cloud_worker", "/".join(mod_path), f"{mod_name}.rs"
)
# Generate methods for the GET resource command
self._render_command(context, "rust_tui/impl.rs.j2", impl_path)
self._format_code(impl_path)
yield (mod_path, mod_name, path)
def generate_mod(
self, target_dir, mod_path, mod_list, url, resource_name, service_name
):
"""Generate collection module (include individual modules)"""
work_dir = Path(target_dir, "rust", "openstack_tui", "src")
impl_path = Path(
work_dir,
"cloud_worker",
"/".join(mod_path[0:-1]),
f"{mod_path[-1]}.rs",
)
context = {
"mod_list": mod_list,
"mod_path": mod_path,
"url": url,
"resource_name": resource_name,
"service_name": service_name,
}
# Generate methods for the GET resource command
self._render_command(context, "rust_sdk/mod.rs.j2", impl_path)
self._format_code(impl_path)

View File

@ -154,18 +154,18 @@ Some({{ val }})
{%- endmacro %}
{#- Macros to render setting Request data from CLI input #}
{%- macro set_request_data_from_input(manager, dst_var, param, val_var) %}
{%- macro set_request_data_from_input(manager, dst_var, param, val_var, by_ref=False) %}
{%- set is_nullable = param.is_nullable if param.is_nullable is defined else False %}
{%- if param.type_hint in ["Option<Option<bool>>", "Option<Option<i32>>", "Option<Option<i64>>"] %}
{{ dst_var }}.{{ param.remote_name }}({{ "*" + val_var }});
{{ dst_var }}.{{ param.remote_name }}({{ ("*" + val_var) if not by_ref else (val + ".clone()") }});
{%- elif param.type_hint in ["Option<i32>", "Option<i64>", "Option<f32>", "Option<f64>", "Option<bool>"] %}
{%- if param.is_optional is defined and not param.is_optional %}
if let Some(val) = {{ val_var }} {
{{ dst_var }}.{{ param.remote_name }}(*val);
{{ dst_var }}.{{ param.remote_name }}({{ "*val" if not by_ref else "val.clone()" }});
}
{%- else %}
{{ dst_var }}.{{ param.remote_name }}({{ "*" + val_var }});
{{ dst_var }}.{{ param.remote_name }}({{ ("*" + val_var) if not by_ref else (val_var + ".clone()") }});
{%- endif %}
{%- elif param.type_hint in ["i32", "i64", "f32", "f64", "bool"] %}
@ -247,7 +247,7 @@ Some({{ val }})
{%- elif is_nullable and param.is_optional %}
{{ dst_var }}.{{ param.remote_name }}(Some({{ val_var }}.into()));
{%- elif (param.is_optional is defined and param.is_optional) or (param.is_required is defined and not param.is_required) %}
{{ dst_var }}.{{ param.remote_name }}({{ val_var }});
{{ dst_var }}.{{ param.remote_name }}({{ val_var if not by_ref else (val_var + ".clone()")}});
{%- else %}
{{ dst_var }}.{{ param.remote_name }}(&{{ val_var | replace("&", "") }});
{%- endif %}

View File

@ -0,0 +1,162 @@
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0
//
// WARNING: This file is automatically generated from OpenAPI schema using
// `openstack-codegenerator`.
{% import 'rust_macros.j2' as macros with context -%}
use eyre::{Result, WrapErr};
use serde::{Deserialize, Serialize};
use std::fmt;
use tokio::sync::mpsc::UnboundedSender;
use crate::action::Action;
use crate::cloud_worker::common::CloudWorkerError;
use crate::cloud_worker::types::{ApiRequest, ExecuteApiRequest};
{% for mod in additional_imports | sort -%}
use {{ mod }};
{% endfor %}
{%- with data_type = type_manager.get_root_data_type() %}
{%- set sdk_data_type = sdk_type_manager.get_root_data_type() %}
{%- if data_type.__class__.__name__ == "Struct" %}
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct {{ class_name }}{
{%- for name, param in type_manager.parameters | dictsort %}
{%- if param.location != "header" %}
{{ param.local_name }}: {{ param.type_hint }},
{%- if param.local_name.endswith("id") %}
{%- set param_type = False %}
{{ param.local_name[:-2] }}name:
{%- if param.type_hint.startswith("Option") %}
{{ param.type_hint }},
{%- else %}
Option<{{ param.type_hint }}>,
{%- endif %}
{%- endif %}
{%- endif %}
{%- endfor %}
}
impl fmt::Display for {{ class_name }} {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut parts: Vec<String> = Vec::new();
{%- for name, param in type_manager.parameters | dictsort %}
{%- if param.location != "header" %}
{%- if param.local_name.endswith("_id") %}
{%- set alt_name = param.local_name.replace("_id", "_name") %}
{%- if param.type_hint.startswith("Option") %}
if self.{{ param.local_name }}.is_some() || self.{{ alt_name }}.is_some() {
parts.push(format!(
"{{ param.local_name[:-3] }}: {}",
self.{{ alt_name }}
.as_ref()
.or(self.{{ param.local_name }}.as_ref())
.unwrap_or(&String::new())
));
}
{% else %}
parts.push(format!(
"{{ param.local_name[:-3] }}: {}",
self.{{ alt_name }}
.clone()
.unwrap_or(self.{{ param.local_name }}.clone())
));
{%- endif %}
{%- endif %}
{%- endif %}
{%- endfor %}
write!(f, "{}", parts.join(","))
}
}
impl From<&{{ class_name }}> for RequestBuilder{{ "<'_>" if sdk_type_manager.get_request_static_lifetimes(data_type) else "" }} {
fn from(value: &{{ class_name }}) -> Self {
let mut ep_builder = Self::default();
{%- for (k, v) in type_manager.get_parameters("path") %}
{%- if not v.is_required %}
{%- if k != "project_id" %}
if let Some(val) = &value.{{ v.local_name }} {
ep_builder.{{ v.local_name }}(val.clone());
}
{%- else %}
if let Some(val) = &value.{{ v.local_name }} {
ep_builder.{{ v.local_name }}(val.clone());
} else {
ep_builder.{{ v.local_name }}(client.get_current_project().expect("Project ID must be known").id);
}
{%- endif %}
{%- else %}
ep_builder.{{ v.local_name }}(value.{{ v.local_name }}.clone());
{%- endif %}
{%- endfor %}
{%- for (k, v) in type_manager.get_parameters("query") %}
{%- if not v.is_required %}
if let Some(val) = &value.{{ v.local_name }} {
{{ macros.set_request_data_from_input(type_manager, "ep_builder", v, "val", by_ref=True)}}
}
{%- else %}
{{ macros.set_request_data_from_input(type_manager, "ep_builder", v, "value" + v.local_name, by_ref=True )}}
{%- endif %}
{%- endfor %}
ep_builder
}
}
impl ExecuteApiRequest for {{ class_name }} {
async fn execute_request(
&self,
session: &mut AsyncOpenStack,
request: &ApiRequest,
app_tx: &UnboundedSender<Action>,
) -> Result<(), CloudWorkerError> {
let ep = Into::<RequestBuilder>::into(self)
.build()
.wrap_err("Cannot prepare request")?;
{%- if operation_type == "list" %}
app_tx.send(Action::ApiResponsesData {
request: request.clone(),
{%- if operation_type == "list" and is_list_paginated %}
data: paged(ep, Pagination::All).query_async(session).await?,
{%- else %}
data: ep.query_async(session).await?,
{%- endif %}
})?;
{%- elif operation_type == "show" %}
app_tx.send(Action::ApiResponseData {
request: request.clone(),
data: ep.query_async(session).await?,
})?;
{%- elif operation_type == "delete" %}
ignore(ep).query_async(session).await?;
{%- endif %}
Ok(())
}
}
{%- if operation_type == "delete" %}
impl ConfirmableRequest for {{ class_name }} {
fn get_confirm_message(&self) -> Option<String> {
Some(format!(
"Delete {{ sdk_service_name }} {{ resource_name.title() }} {} ?",
self.name.clone().unwrap_or(self.id.clone())
))
}
}
{%- endif %}
{%- endif %}
{%- endwith %}

View File

@ -31,7 +31,7 @@ OPERATION_TYPE = Literal[
"find",
]
SUPPORTED_TARGETS = Literal["rust-sdk", "rust-cli"]
SUPPORTED_TARGETS = Literal["rust-sdk", "rust-cli", "rust-tui"]
class OperationTargetParams(BaseModel):

View File

@ -34,6 +34,8 @@ resources:
targets:
rust-sdk:
module_name: list
rust-tui:
module_name: list
create:
operation_id: volumes:post
operation_type: create
@ -402,6 +404,8 @@ resources:
sdk_mod_name: delete
find_implemented_by_sdk: true
cli_full_command: volume delete
rust-tui:
module_name: delete
find:
operation_id: volumes/detail:get
operation_type: find
@ -975,6 +979,8 @@ resources:
targets:
rust-sdk:
module_name: list
rust-tui:
module_name: list
create:
operation_id: snapshots:post
operation_type: create
@ -1070,6 +1076,8 @@ resources:
sdk_mod_name: delete
find_implemented_by_sdk: true
cli_full_command: snapshot delete
rust-tui:
module_name: delete
find:
operation_id: snapshots/detail:get
operation_type: find
@ -1374,6 +1382,8 @@ resources:
targets:
rust-sdk:
module_name: list
rust-tui:
module_name: list
create:
operation_id: backups:post
operation_type: create
@ -1417,6 +1427,8 @@ resources:
sdk_mod_name: delete
find_implemented_by_sdk: true
cli_full_command: backup delete
rust-tui:
module_name: delete
os-reset-status:
operation_id: backups/id/action:post
operation_type: action

View File

@ -57,6 +57,8 @@ resources:
targets:
rust-sdk:
module_name: list
rust-tui:
module_name: list
create:
operation_id: flavors:post
operation_type: create
@ -89,6 +91,8 @@ resources:
sdk_mod_name: get
find_implemented_by_sdk: true
cli_full_command: flavor show
rust-tui:
module_name: get
update:
operation_id: flavors/id:put
operation_type: set
@ -111,6 +115,8 @@ resources:
sdk_mod_name: delete
find_implemented_by_sdk: true
cli_full_command: flavor delete
rust-tui:
module_name: delete
add-tenant-access:
operation_id: flavors/id/action:post
operation_type: action
@ -246,6 +252,8 @@ resources:
module_name: list
sdk_mod_name: list
cli_full_command: aggregate list
rust-tui:
module_name: list
create:
operation_id: os-aggregates:post
operation_type: create
@ -266,6 +274,8 @@ resources:
module_name: show
sdk_mod_name: get
cli_full_command: aggregate show
rust-tui:
module_name: get
update:
operation_id: os-aggregates/id:put
operation_type: set
@ -286,6 +296,8 @@ resources:
module_name: delete
sdk_mod_name: delete
cli_full_command: aggregate delete
rust-tui:
module_name: delete
add-host:
operation_id: os-aggregates/id/action:post
operation_type: action
@ -512,6 +524,8 @@ resources:
targets:
rust-sdk:
module_name: list
rust-tui:
module_name: list
list_detailed:
operation_id: os-hypervisors/detail:get
operation_type: list
@ -532,6 +546,8 @@ resources:
module_name: show
sdk_mod_name: get
cli_full_command: hypervisor show
rust-tui:
module_name: get
compute.hypervisor/statistic:
spec_file: wrk/openapi_specs/compute/v2.yaml
api_version: v2
@ -751,6 +767,8 @@ resources:
module_name: details
sdk_mod_name: details
cli_full_command: quota-set details
rust-tui:
module_name: details
defaults:
operation_id: os-quota-sets/id/defaults:get
operation_type: show
@ -899,6 +917,8 @@ resources:
targets:
rust-sdk:
module_name: list
rust-tui:
module_name: list
create:
operation_id: servers:post
operation_type: create
@ -931,6 +951,8 @@ resources:
sdk_mod_name: get
find_implemented_by_sdk: true
cli_full_command: server show
rust-tui:
module_name: get
update:
operation_id: servers/id:put
operation_type: set
@ -953,6 +975,8 @@ resources:
sdk_mod_name: delete
find_implemented_by_sdk: true
cli_full_command: server delete
rust-tui:
module_name: delete
confirm-resize:
operation_id: servers/id/action:post
operation_type: action
@ -1660,6 +1684,8 @@ resources:
sdk_mod_name: list
response_key: instanceActions
cli_full_command: server instance-action list
rust-tui:
module_name: list
show:
operation_id: servers/server_id/os-instance-actions/id:get
operation_type: show
@ -1672,6 +1698,8 @@ resources:
sdk_mod_name: get
response_key: instanceAction
cli_full_command: server instance-action show
rust-tui:
module_name: get
compute.server/interface:
spec_file: wrk/openapi_specs/compute/v2.yaml
api_version: v2

View File

@ -127,6 +127,8 @@ resources:
sdk_mod_name: delete
find_implemented_by_sdk: true
cli_full_command: zone delete
rust-tui:
module_name: delete
update:
operation_id: zones/zone_id:patch
operation_type: set
@ -148,6 +150,8 @@ resources:
module_name: list
sdk_mod_name: list
cli_full_command: zone list
rust-tui:
module_name: list
create:
operation_id: zones:post
operation_type: create
@ -205,6 +209,8 @@ resources:
sdk_mod_name: delete
find_implemented_by_sdk: true
cli_full_command: zone recordset delete
rust-tui:
module_name: delete
list:
operation_id: zones/zone_id/recordsets:get
operation_type: list
@ -215,6 +221,8 @@ resources:
module_name: list
sdk_mod_name: list
cli_full_command: zone recordset list
rust-tui:
module_name: list
create:
operation_id: zones/zone_id/recordsets:post
operation_type: create
@ -717,6 +725,8 @@ resources:
module_name: list
sdk_mod_name: list
cli_full_command: recordset list
rust-tui:
module_name: list
show:
operation_id: recordsets/recordset_id:get
operation_type: show

View File

@ -39,6 +39,8 @@ resources:
module_name: list
sdk_mod_name: list
cli_full_command: auth project list
rust-tui:
module_name: list
identity.OS_FEDERATION/project:
spec_file: wrk/openapi_specs/identity/v3.yaml
api_version: v3
@ -384,11 +386,31 @@ resources:
api_version: v3
operations:
check:
operation_id: domains:head
operation_id: domains/domain_id:head
operation_type: get
targets:
rust-sdk:
module_name: head
list:
operation_id: domains:get
operation_type: list
targets:
rust-sdk:
module_name: list
rust-cli:
module_name: list
sdk_mod_name: list
cli_full_command: domain list
create:
operation_id: domains:post
operation_type: create
targets:
rust-sdk:
module_name: create
rust-cli:
module_name: create
sdk_mod_name: create
cli_full_command: domain create
show:
operation_id: domains/domain_id:get
operation_type: show
@ -422,26 +444,6 @@ resources:
sdk_mod_name: set
find_implemented_by_sdk: true
cli_full_command: domain set
list:
operation_id: domains:get
operation_type: list
targets:
rust-sdk:
module_name: list
rust-cli:
module_name: list
sdk_mod_name: list
cli_full_command: domain list
create:
operation_id: domains:post
operation_type: create
targets:
rust-sdk:
module_name: create
rust-cli:
module_name: create
sdk_mod_name: create
cli_full_command: domain create
find:
operation_id: domains:get
operation_type: find
@ -872,6 +874,8 @@ resources:
sdk_mod_name: delete
find_implemented_by_sdk: true
cli_full_command: group delete
rust-tui:
module_name: delete
update:
operation_id: groups/group_id:patch
operation_type: set
@ -893,6 +897,8 @@ resources:
module_name: list
sdk_mod_name: list
cli_full_command: group list
rust-tui:
module_name: list
create:
operation_id: groups:post
operation_type: create
@ -933,6 +939,8 @@ resources:
module_name: list
sdk_mod_name: list
cli_full_command: group user list
rust-tui:
module_name: list
show:
operation_id: groups/group_id/users/user_id:get
operation_type: show
@ -963,6 +971,8 @@ resources:
module_name: delete
sdk_mod_name: delete
cli_full_command: group user delete
rust-tui:
module_name: delete
identity.limit:
spec_file: wrk/openapi_specs/identity/v3.yaml
api_version: v3
@ -2190,6 +2200,8 @@ resources:
module_name: list
sdk_mod_name: list
cli_full_command: project list
rust-tui:
module_name: list
create:
operation_id: projects:post
operation_type: create
@ -2222,6 +2234,8 @@ resources:
sdk_mod_name: delete
find_implemented_by_sdk: true
cli_full_command: project delete
rust-tui:
module_name: delete
update:
operation_id: projects/project_id:patch
operation_type: set
@ -3015,6 +3029,8 @@ resources:
sdk_mod_name: delete
find_implemented_by_sdk: true
cli_full_command: user delete
rust-tui:
module_name: delete
update:
operation_id: users/user_id:patch
operation_type: set
@ -3036,6 +3052,8 @@ resources:
module_name: list
sdk_mod_name: list
cli_full_command: user list
rust-tui:
module_name: list
create:
operation_id: users:post
operation_type: create
@ -3250,6 +3268,8 @@ resources:
module_name: list
sdk_mod_name: list
cli_full_command: application-credential list
rust-tui:
module_name: list
create:
operation_id: users/user_id/application_credentials:post
operation_type: create
@ -3282,6 +3302,8 @@ resources:
sdk_mod_name: delete
find_implemented_by_sdk: true
cli_full_command: application-credential delete
rust-tui:
module_name: delete
find:
operation_id: users/user_id/application_credentials:get
operation_type: find

View File

@ -564,6 +564,8 @@ resources:
module_name: list
sdk_mod_name: list
cli_full_command: image list
rust-tui:
module_name: list
create:
operation_id: images:post
operation_type: create
@ -596,6 +598,8 @@ resources:
sdk_mod_name: delete
find_implemented_by_sdk: true
cli_full_command: image delete
rust-tui:
module_name: delete
patch:
operation_id: images/image_id:patch
operation_type: set

View File

@ -28,6 +28,8 @@ resources:
sdk_mod_name: get
find_implemented_by_sdk: true
cli_full_command: loadbalancer show
rust-tui:
module_name: get
update:
operation_id: lbaas/loadbalancers/loadbalancer_id:put
operation_type: set
@ -50,6 +52,8 @@ resources:
sdk_mod_name: delete
find_implemented_by_sdk: true
cli_full_command: loadbalancer delete
rust-tui:
module_name: delete
list:
operation_id: lbaas/loadbalancers:get
operation_type: list
@ -60,6 +64,8 @@ resources:
module_name: list
sdk_mod_name: list
cli_full_command: loadbalancer list
rust-tui:
module_name: list
create:
operation_id: lbaas/loadbalancers:post
operation_type: create
@ -128,6 +134,8 @@ resources:
sdk_mod_name: get
find_implemented_by_sdk: true
cli_full_command: listener show
rust-tui:
module_name: get
update:
operation_id: lbaas/listeners/listener_id:put
operation_type: set
@ -150,6 +158,8 @@ resources:
sdk_mod_name: delete
find_implemented_by_sdk: true
cli_full_command: listener delete
rust-tui:
module_name: delete
list:
operation_id: lbaas/listeners:get
operation_type: list
@ -160,6 +170,8 @@ resources:
module_name: list
sdk_mod_name: list
cli_full_command: listener list
rust-tui:
module_name: list
create:
operation_id: lbaas/listeners:post
operation_type: create
@ -206,6 +218,8 @@ resources:
sdk_mod_name: get
find_implemented_by_sdk: true
cli_full_command: pool show
rust-tui:
module_name: get
update:
operation_id: lbaas/pools/pool_id:put
operation_type: set
@ -228,6 +242,8 @@ resources:
sdk_mod_name: delete
find_implemented_by_sdk: true
cli_full_command: pool delete
rust-tui:
module_name: delete
list:
operation_id: lbaas/pools:get
operation_type: list
@ -238,6 +254,8 @@ resources:
module_name: list
sdk_mod_name: list
cli_full_command: pool list
rust-tui:
module_name: list
create:
operation_id: lbaas/pools:post
operation_type: create
@ -340,6 +358,8 @@ resources:
sdk_mod_name: get
find_implemented_by_sdk: true
cli_full_command: healthmonitor show
rust-tui:
module_name: get
update:
operation_id: lbaas/healthmonitors/healthmonitor_id:put
operation_type: set
@ -362,6 +382,8 @@ resources:
sdk_mod_name: delete
find_implemented_by_sdk: true
cli_full_command: healthmonitor delete
rust-tui:
module_name: delete
list:
operation_id: lbaas/healthmonitors:get
operation_type: list
@ -372,6 +394,8 @@ resources:
module_name: list
sdk_mod_name: list
cli_full_command: healthmonitor list
rust-tui:
module_name: list
create:
operation_id: lbaas/healthmonitors:post
operation_type: create
@ -406,6 +430,8 @@ resources:
module_name: show
sdk_mod_name: get
cli_full_command: quota show
rust-tui:
module_name: get
update:
operation_id: lbaas/quotas/project_id:put
operation_type: set
@ -426,6 +452,8 @@ resources:
module_name: delete
sdk_mod_name: delete
cli_full_command: quota delete
rust-tui:
module_name: delete
list:
operation_id: lbaas/quotas:get
operation_type: list
@ -436,6 +464,8 @@ resources:
module_name: list
sdk_mod_name: list
cli_full_command: quota list
rust-tui:
module_name: list
load-balancer.provider:
spec_file: wrk/openapi_specs/load-balancer/v2.yaml
api_version: v2
@ -879,6 +909,8 @@ resources:
module_name: list
sdk_mod_name: list
cli_full_command: pool member list
rust-tui:
module_name: list
replace:
operation_id: lbaas/pools/pool_id/members:put
operation_type: set
@ -911,6 +943,8 @@ resources:
sdk_mod_name: get
find_implemented_by_sdk: true
cli_full_command: pool member show
rust-tui:
module_name: get
update:
operation_id: lbaas/pools/pool_id/members/member_id:put
operation_type: set
@ -933,6 +967,8 @@ resources:
sdk_mod_name: delete
find_implemented_by_sdk: true
cli_full_command: pool member delete
rust-tui:
module_name: delete
find:
operation_id: lbaas/pools/pool_id/members:get
operation_type: find

View File

@ -423,6 +423,8 @@ resources:
module_name: list
sdk_mod_name: list
cli_full_command: router list
rust-tui:
module_name: list
create:
operation_id: routers:post
operation_type: create
@ -543,6 +545,8 @@ resources:
sdk_mod_name: delete
find_implemented_by_sdk: true
cli_full_command: router delete
rust-tui:
module_name: delete
find:
operation_id: routers:get
operation_type: find
@ -2392,6 +2396,8 @@ resources:
module_name: details
sdk_mod_name: details
cli_full_command: quota details
rust-tui:
module_name: details
network.rbac_policy:
spec_file: wrk/openapi_specs/network/v2.yaml
api_version: v2
@ -2514,6 +2520,8 @@ resources:
module_name: list
sdk_mod_name: list
cli_full_command: security-group list
rust-tui:
module_name: list
create:
operation_id: security-groups:post
operation_type: create
@ -2557,6 +2565,8 @@ resources:
sdk_mod_name: delete
find_implemented_by_sdk: true
cli_full_command: security-group delete
rust-tui:
module_name: delete
find:
operation_id: security-groups:get
operation_type: find
@ -2581,6 +2591,8 @@ resources:
module_name: list
sdk_mod_name: list
cli_full_command: security-group-rule list
rust-tui:
module_name: list
create:
operation_id: security-group-rules:post
operation_type: create
@ -2621,6 +2633,8 @@ resources:
module_name: delete
sdk_mod_name: delete
cli_full_command: security-group-rule delete
rust-tui:
module_name: delete
network.segment:
spec_file: wrk/openapi_specs/network/v2.yaml
api_version: v2
@ -3499,6 +3513,8 @@ resources:
module_name: list
sdk_mod_name: list
cli_full_command: network list
rust-tui:
module_name: list
create:
operation_id: networks:post
operation_type: create
@ -3542,6 +3558,8 @@ resources:
sdk_mod_name: delete
find_implemented_by_sdk: true
cli_full_command: network delete
rust-tui:
module_name: delete
find:
operation_id: networks:get
operation_type: find
@ -3566,6 +3584,8 @@ resources:
module_name: list
sdk_mod_name: list
cli_full_command: subnet list
rust-tui:
module_name: list
create:
operation_id: subnets:post
operation_type: create
@ -3609,6 +3629,8 @@ resources:
sdk_mod_name: delete
find_implemented_by_sdk: true
cli_full_command: subnet delete
rust-tui:
module_name: delete
find:
operation_id: subnets:get
operation_type: find

View File

@ -21,7 +21,7 @@
- name: "Pre-Compile current code to ensure it builds"
ansible.builtin.command:
cmd: "cargo build -p openstack_sdk -p openstack_cli"
cmd: "cargo build -p openstack_sdk -p openstack_cli -p openstack_tui"
chdir: "{{ rust_project_dir }}"
- name: "Overwrite generated files"
@ -37,7 +37,7 @@
- name: "Compile new code (only generated crates)"
ansible.builtin.command:
cmd: "cargo build -p openstack_sdk -p openstack_cli"
cmd: "cargo build -p openstack_sdk -p openstack_cli -p openstack_tui"
chdir: "{{ rust_project_dir }}"
- name: "Checkout new branch"

View File

@ -14,25 +14,25 @@
codegenerator_service_metadata_target_map:
- service: "block-storage"
metadata: "metadata/block-storage_metadata.yaml"
targets: ["rust-sdk", "rust-cli"]
targets: ["rust-sdk", "rust-cli", "rust-tui"]
- service: "compute"
metadata: "metadata/compute_metadata.yaml"
targets: ["rust-sdk", "rust-cli"]
targets: ["rust-sdk", "rust-cli", "rust-tui"]
- service: "dns"
metadata: "metadata/dns_metadata.yaml"
targets: ["rust-sdk", "rust-cli"]
targets: ["rust-sdk", "rust-cli", "rust-tui"]
- service: "identity"
metadata: "metadata/identity_metadata.yaml"
targets: ["rust-sdk", "rust-cli"]
targets: ["rust-sdk", "rust-cli", "rust-tui"]
- service: "image"
metadata: "metadata/image_metadata.yaml"
targets: ["rust-sdk", "rust-cli"]
targets: ["rust-sdk", "rust-cli", "rust-tui"]
- service: "load-balancer"
metadata: "metadata/load-balancer_metadata.yaml"
targets: ["rust-sdk", "rust-cli"]
targets: ["rust-sdk", "rust-cli", "rust-tui"]
- service: "network"
metadata: "metadata/network_metadata.yaml"
targets: ["rust-sdk", "rust-cli"]
targets: ["rust-sdk", "rust-cli", "rust-tui"]
- service: "object-store"
metadata: "metadata/object-store_metadata.yaml"
targets: ["rust-sdk"]