diff --git a/broker/commands.py b/broker/commands.py index 15330b7..a28bfed 100644 --- a/broker/commands.py +++ b/broker/commands.py @@ -1,10 +1,13 @@ """Defines the CLI commands for Broker.""" + from functools import wraps import signal import sys import click from logzero import logger +from rich.console import Console +from rich.table import Table from broker import exceptions, helpers, settings from broker.broker import Broker @@ -267,13 +270,14 @@ def checkin(vm, background, all_, sequential, filter): @loggedcli() @click.option("--details", is_flag=True, help="Display all host details") +@click.option("--curated", is_flag=True, help="Display curated host details") @click.option( "--sync", type=str, help="Class-style name of a supported broker provider. (AnsibleTower)", ) @click.option("--filter", type=str, help="Display only what matches the specified filter") -def inventory(details, sync, filter): +def inventory(details, curated, sync, filter): """Get a list of all VMs you've checked out showing hostname and local id. hostname pulled from list of dictionaries. @@ -282,9 +286,25 @@ def inventory(details, sync, filter): Broker.sync_inventory(provider=sync) logger.info("Pulling local inventory") inventory = helpers.load_inventory(filter=filter) - emit_data = [] + helpers.emit({"inventory": inventory}) + if curated: + console = Console() + table = Table(title="Host Inventory") + + table.add_column("Id", justify="left", style="cyan", no_wrap=True) + table.add_column("Host", justify="left", style="magenta") + table.add_column("Provider", justify="left", style="green") + table.add_column("Action", justify="left", style="yellow") + table.add_column("OS", justify="left", style="blue") + + for host in helpers.get_host_inventory_fields(inventory, PROVIDERS): + table.add_row( + str(host["id"]), host["host"], host["provider"], host["action"], host["os"] + ) + + console.print(table) + return for num, host in enumerate(inventory): - emit_data.append(host) if (display_name := host.get("hostname")) is None: display_name = host.get("name") # if we're filtering, then don't show an index. @@ -294,7 +314,6 @@ def inventory(details, sync, filter): logger.info(f"{index}{display_name}:\n{helpers.yaml_format(host)}") else: logger.info(f"{index}{display_name}") - helpers.emit({"inventory": emit_data}) @loggedcli() diff --git a/broker/helpers.py b/broker/helpers.py index 44a30b4..b655660 100644 --- a/broker/helpers.py +++ b/broker/helpers.py @@ -268,6 +268,48 @@ def yaml_format(in_struct): return yaml.dump(in_struct, default_flow_style=False, sort_keys=False) +def get_checkout_options(provider_cls): + """Return the checkout options for a provider.""" + options = [] + # iterate through the _checkout_options list + for option in provider_cls._checkout_options: + # now we need to dig into the baked-in attributes of the click decorator + for param in option.__closure__: + if isinstance(param.cell_contents, tuple): + for opt in param.cell_contents: + if opt.startswith("--"): + options.append(opt[2:].replace("-", "_")) # noqa: PERF401 + return options + + +def get_host_inventory_fields(inv_dict, providers): + """Get a more focused set of fields from the host inventory.""" + curated_hosts = [] + for num, host in enumerate(inv_dict): + match host: + case { + "name": name, + "hostname": hostname, + "_broker_provider": provider, + }: + os_name = host.get("os_distribution", "Unknown") + os_version = host.get("os_distribution_version", "") + checkout_opts = get_checkout_options(providers[provider]) + for opt in checkout_opts: + if action := host["_broker_args"].get(opt): + curated_hosts.append( + { + "id": num, + "host": hostname or name, + "provider": provider, + "os": f"{os_name} {os_version}", + "action": action, + } + ) + break + return curated_hosts + + def kwargs_from_click_ctx(ctx): """Convert a Click context object to a dictionary of keyword arguments.""" # if users use `=` to note arg=value assignment, then we need to split it diff --git a/pyproject.toml b/pyproject.toml index 420dff0..cfc0fec 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,6 +28,7 @@ dependencies = [ "logzero", "packaging", "pyyaml", + "rich", "setuptools", "ssh2-python312", ]