Files
wif2ansible/wif2ansible/inventory.py
Kris Forbes fc1c4bfaa8
All checks were successful
Build and Release / Build Windows Exe (push) Successful in 10s
Support multiple IPs per server and robust mapping
2026-02-06 16:19:05 -05:00

95 lines
3.2 KiB
Python

from typing import List, Dict, Any
from .models import Server, Flow
from .network import to_mgt_ip
def generate_inventory(servers: Dict[str, Server], flows: List[Flow]) -> Dict[str, Any]:
"""
Generates the Ansible inventory dictionary.
servers: Dict[Reference, Server]
flows: List[Flow]
"""
# Build Lookup Map: IP -> Server
# Note: A server might have multiple IPs (e.g. Mgt, Public, Private).
# The 'Server' object mainly captures the Management IP or the one listed in the "IP Address" column.
# If the WIF has "Source Public IP" and that differs from "IP Address" in Servers tab,
# we might miss it if we only index the primary IP.
# However, strict filtering means we trust the 'Servers' tab.
ip_to_server = {}
for s in servers.values():
# Index all Management IPs
for ip in s.ip_addresses:
ip_to_server[ip] = s
# Index all Production IPs
for ip in s.production_ips:
ip_to_server[ip] = s
# Also index by reference/hostname for DNS matches
if s.reference:
ip_to_server[s.reference.lower()] = s
if s.hostname:
ip_to_server[s.hostname.lower()] = s
inventory_hosts = {}
# Process flows
match_count = 0
drop_count = 0
for flow in flows:
# Find source server
server = ip_to_server.get(flow.source_ip)
if not server:
# Try DNS resolution (Public IP -> Management FQDN)
mgt_dns = to_mgt_ip(flow.source_ip)
if mgt_dns:
# mgt_dns might be "server.ds.gc.ca".
# Our keys might be "server" or "server.ds.gc.ca" or IPs
# Try exact match
server = ip_to_server.get(mgt_dns.lower())
# If not found, try shortname?
if not server:
short = mgt_dns.split('.')[0]
server = ip_to_server.get(short.lower())
if not server:
drop_count += 1
if drop_count <= 5: # Debug spam limit
print(f"Dropping flow {flow.flow_id}: Source {flow.source_ip} (Mgt: {mgt_dns}) not found in Servers tab.")
continue
match_count += 1
# Prepare host entry if new
# We use the Hostname (from Server Name col) -> Reference (cleaned) -> IP match
host_key = server.hostname or server.reference or server.primary_ip
if host_key not in inventory_hosts:
host_vars = server.get_ansible_vars()
host_vars['flows'] = []
inventory_hosts[host_key] = host_vars
# Add flow
flow_entry = {
'flow_id': flow.flow_id,
'dest': flow.destination_ip,
'ports': flow.ports,
'protocol': flow.protocol
}
# Dedup check?
# Ideally we shouldn't have exact duplicates, but appending is safe.
inventory_hosts[host_key]['flows'].append(flow_entry)
print(f"Inventory Generation Report: Matches={match_count}, Dropped={drop_count}")
return {
'all': {
'hosts': inventory_hosts
}
}