From 2d565baf829c63feb2c9c1f30802153775587351 Mon Sep 17 00:00:00 2001 From: Christian Berendt Date: Fri, 13 Mar 2026 19:45:33 +0100 Subject: [PATCH] Fix host resolution with minified inventory ansible-inventory --list does not populate _meta.hostvars for hosts without variables. The minified inventory has no host variables, so _meta.hostvars is always empty, breaking --limit and host listing. Extract hosts from group listings as well via a new get_hosts_from_inventory() helper. AI-assisted: Claude Code Signed-off-by: Christian Berendt --- osism/api.py | 7 +++---- osism/commands/get.py | 4 ++-- osism/commands/report.py | 8 ++++---- osism/utils/inventory.py | 15 +++++++++++++++ osism/utils/rabbitmq.py | 9 ++------- 5 files changed, 26 insertions(+), 17 deletions(-) diff --git a/osism/api.py b/osism/api.py index 25404344..c05b7101 100644 --- a/osism/api.py +++ b/osism/api.py @@ -25,7 +25,7 @@ from osism.tasks import reconciler, openstack from osism import utils -from osism.utils.inventory import get_inventory_path +from osism.utils.inventory import get_hosts_from_inventory, get_inventory_path from osism.services.listener import BaremetalEvents from osism.services.websocket_manager import websocket_manager from osism.services.event_bridge import event_bridge @@ -766,9 +766,8 @@ async def get_inventory_hosts(limit: Optional[str] = None) -> HostsResponse: data = json.loads(result.stdout) logger.debug(f"Inventory data keys: {list(data.keys())}") - hosts = list(data.get("_meta", {}).get("hostvars", {}).keys()) + hosts = get_hosts_from_inventory(data) logger.debug(f"Found {len(hosts)} hosts in inventory") - hosts.sort() return HostsResponse(hosts=hosts, count=len(hosts)) except subprocess.TimeoutExpired: @@ -1071,7 +1070,7 @@ async def search_inventory( ) inventory_data = json.loads(result.stdout) - all_hosts = list(inventory_data.get("_meta", {}).get("hostvars", {}).keys()) + all_hosts = get_hosts_from_inventory(inventory_data) # Filter hosts by pattern if host_regex: diff --git a/osism/commands/get.py b/osism/commands/get.py index 1e1ad3ac..d96a256b 100644 --- a/osism/commands/get.py +++ b/osism/commands/get.py @@ -13,7 +13,7 @@ from osism.tasks import Config from osism.utils import redis -from osism.utils.inventory import get_inventory_path +from osism.utils.inventory import get_hosts_from_inventory, get_inventory_path class VersionsManager(Command): @@ -249,7 +249,7 @@ def take_action(self, parsed_args): data = json.loads(result) table = [] - for host in data["_meta"]["hostvars"]: + for host in get_hosts_from_inventory(data): table.append([host]) if table: diff --git a/osism/commands/report.py b/osism/commands/report.py index 03489b8e..bd651a20 100644 --- a/osism/commands/report.py +++ b/osism/commands/report.py @@ -10,7 +10,7 @@ from osism import settings from osism.commands.console import resolve_host_with_fallback -from osism.utils.inventory import get_inventory_path +from osism.utils.inventory import get_hosts_from_inventory, get_inventory_path from osism.utils.ssh import ensure_known_hosts_file, KNOWN_HOSTS_PATH @@ -56,7 +56,7 @@ def take_action(self, parsed_args): return data = json.loads(result.stdout) - hosts = sorted(data.get("_meta", {}).get("hostvars", {}).keys()) + hosts = get_hosts_from_inventory(data) if not hosts: logger.error("No hosts found in inventory.") @@ -194,7 +194,7 @@ def take_action(self, parsed_args): return data = json.loads(result.stdout) - hosts = sorted(data.get("_meta", {}).get("hostvars", {}).keys()) + hosts = get_hosts_from_inventory(data) if not hosts: logger.error("No hosts found in inventory.") @@ -341,7 +341,7 @@ def take_action(self, parsed_args): return data = json.loads(result.stdout) - hosts = sorted(data.get("_meta", {}).get("hostvars", {}).keys()) + hosts = get_hosts_from_inventory(data) if not hosts: logger.error("No hosts found in inventory.") diff --git a/osism/utils/inventory.py b/osism/utils/inventory.py index 6206c4a0..5591f8dd 100644 --- a/osism/utils/inventory.py +++ b/osism/utils/inventory.py @@ -27,3 +27,18 @@ def get_inventory_path(base_path: str, prefer_minified: bool = True) -> str: logger.debug(f"Using minified inventory: {minified_path}") return minified_path return base_path + + +def get_hosts_from_inventory(data: dict) -> list: + """Extract host names from ansible-inventory --list JSON output. + + The minified inventory does not populate _meta.hostvars (since hosts + have no variables), so we also collect hosts from group listings. + """ + hosts = set(data.get("_meta", {}).get("hostvars", {}).keys()) + for key, value in data.items(): + if key == "_meta": + continue + if isinstance(value, dict) and "hosts" in value: + hosts.update(value["hosts"]) + return sorted(hosts) diff --git a/osism/utils/rabbitmq.py b/osism/utils/rabbitmq.py index 7387b944..8990b505 100644 --- a/osism/utils/rabbitmq.py +++ b/osism/utils/rabbitmq.py @@ -10,7 +10,7 @@ from osism.tasks.conductor.utils import get_vault from osism.utils import redis -from osism.utils.inventory import get_inventory_path +from osism.utils.inventory import get_hosts_from_inventory, get_inventory_path def get_rabbitmq_node_addresses(): @@ -30,12 +30,7 @@ def get_rabbitmq_node_addresses(): ) inventory = json.loads(result) - # Get hosts from _meta.hostvars (contains all hosts matching the limit) - if "_meta" not in inventory or "hostvars" not in inventory["_meta"]: - logger.error("Invalid inventory format: _meta.hostvars not found") - return None - - rabbitmq_hosts = list(inventory["_meta"]["hostvars"].keys()) + rabbitmq_hosts = get_hosts_from_inventory(inventory) if not rabbitmq_hosts: logger.error("No hosts found in rabbitmq group") return None