Project Overview
This interactive Python script simplifies creating valid Ansible YAML inventories, especially in
airgapped environments. It guides you through defining groups, hosts (supporting formats like
hostname=ip, hostname-only, or IP-only), and optional child groups. The output is clean,
Ansible-compliant YAML ready for immediate use with ansible or
ansible-playbook commands.
Built quickly with GenAI assistance—perfect for labs, automation pipelines, or teaching Ansible basics. It eliminates manual YAML errors and enforces best practices.
- Requirements: Python 3 with PyYAML (install via
pip install pyyamlif needed). - Usage: Run
python3 yml-create.py(or with--output filename.ymlto skip prompt). - Features: Input validation, child group checks, sorted output, and built-in preview.
Full Code
Security Note: Always review code before executing. SHA256 Hash: 51ea38c9041b22416e305b7abeb27ccf8d0ebc13c2d71b424a6cc7dd6c039a30/p>
import argparse
import sys
import yaml
def main():
parser = argparse.ArgumentParser(
description="Interactively build an Ansible YAML inventory (official format)."
)
parser.add_argument(
"--output",
default=None,
help="Output file for the inventory (skips filename prompt)"
)
args = parser.parse_args()
# Internal structure:
# groupname: {
# 'hosts': {hostname: {vars}},
# 'children': set()
# }
groups = {}
print("\nInteractive Ansible YAML Inventory Builder")
print("Rules:")
print("- Top-level keys are group names")
print("- Hosts may be 'hostname=ip', hostname-only, or ip-only")
print("- Child groups are optional\n")
while True:
group_name = input("Enter group name (or 'done' to finish): ").strip()
if group_name.lower() == "done":
break
if not group_name:
print("Group name cannot be empty.\n")
continue
group = groups.setdefault(
group_name,
{"hosts": {}, "children": set()}
)
hosts_input = input(
f"Hosts for '{group_name}' "
"(comma-separated, empty for none): "
).strip()
if hosts_input:
for item in hosts_input.split(","):
item = item.strip()
if not item:
continue
# hostname=ip format
if "=" in item:
hostname, addr = item.split("=", 1)
hostname = hostname.strip()
addr = addr.strip()
if not hostname or not addr:
print(f"Ignoring invalid host entry: {item}")
continue
group["hosts"][hostname] = {
"ansible_host": addr
}
else:
# hostname-only OR ip-only
group["hosts"][item] = {}
children_input = input(
f"Child groups for '{group_name}' "
"(comma-separated, empty for none): "
).strip()
if children_input:
for child in children_input.split(","):
child = child.strip()
if not child:
continue
if child == group_name:
print("A group cannot be its own child — ignored.")
else:
group["children"].add(child)
print()
if not groups:
print("No groups defined. Exiting.")
sys.exit(0)
# Validate referenced children
defined_groups = set(groups.keys())
undefined_children = {
child
for g in groups.values()
for child in g["children"]
if child not in defined_groups
}
if undefined_children:
print("\nWarning: These child groups are referenced but not defined:")
for name in sorted(undefined_children):
print(f" - {name}")
if input("Proceed anyway? (y/n): ").strip().lower() != "y":
print("Aborted.")
sys.exit(1)
# Build final inventory
inventory = {}
for group_name in sorted(groups):
data = groups[group_name]
entry = {}
# Hosts (always emitted)
entry["hosts"] = dict(sorted(data["hosts"].items()))
# Children (only if defined)
if data["children"]:
entry["children"] = {child: {} for child in sorted(data["children"])}
inventory[group_name] = entry
# Output filename
if args.output:
output_file = args.output
else:
while True:
output_file = input("Output filename (inventory.yml): ").strip()
if output_file:
break
# Write YAML
try:
with open(output_file, "w") as f:
yaml.safe_dump(
inventory,
f,
indent=2,
sort_keys=False,
default_flow_style=False
)
except Exception as e:
print(f"Error writing file: {e}")
sys.exit(1)
print(f"\nInventory written to {output_file}\n")
print("Preview:")
print("-" * 40)
with open(output_file) as f:
print(f.read())
if __name__ == "__main__":
main()
Execution Demo
Running the script and generating an inventory:
Verifying the generated inventory with Ansible:
Conclusion
This lightweight tool makes Ansible inventory creation fast, error-free, and repeatable—ideal for
airgapped setups or quick prototyping. Save as yml-create.py, make executable if desired,
and start building inventories effortlessly.