#!/usr/bin/env python3 """ Get all NPMplus proxy host mappings with VMID, Service, IP, Port, and FQDN """ import os import sys import json import subprocess from pathlib import Path # IP to VMID mapping IP_TO_VMID = { "192.168.11.26": "105", "192.168.11.27": "130", "192.168.11.30": "103", "192.168.11.31": "104", "192.168.11.32": "100", "192.168.11.33": "101", "192.168.11.35": "6200", "192.168.11.36": "7811", "192.168.11.37": "7810", "192.168.11.50": "7800", "192.168.11.51": "7801", "192.168.11.52": "7802", "192.168.11.53": "7803", "192.168.11.57": "6201", "192.168.11.64": "6400", "192.168.11.65": "6000", "192.168.11.100": "1000", "192.168.11.101": "1001", "192.168.11.102": "1002", "192.168.11.103": "1003", "192.168.11.104": "1004", "192.168.11.105": "10100", "192.168.11.106": "10101", "192.168.11.110": "106", "192.168.11.111": "107", "192.168.11.112": "108", "192.168.11.120": "10120", "192.168.11.130": "10130", "192.168.11.140": "5000", "192.168.11.150": "1500", "192.168.11.151": "1501", "192.168.11.152": "1502", "192.168.11.153": "1503", "192.168.11.154": "1504", "192.168.11.155": "10150", "192.168.11.156": "10151", "192.168.11.166": "10233", "192.168.11.167": "10234", "192.168.11.211": "2101", "192.168.11.221": "2201", "192.168.11.232": "2301", "192.168.11.233": "2303", "192.168.11.234": "2304", "192.168.11.235": "2305", "192.168.11.236": "2306", "192.168.11.237": "2307", "192.168.11.238": "2308", "192.168.11.240": "2400", "192.168.11.241": "2401", "192.168.11.242": "2402", "192.168.11.243": "2403", } # IP to hostname mapping (from documentation) IP_TO_HOSTNAME = { "192.168.11.26": "nginxproxymanager", "192.168.11.27": "monitoring-1", "192.168.11.30": "omada", "192.168.11.31": "gitea", "192.168.11.32": "proxmox-mail-gateway", "192.168.11.33": "proxmox-datacenter-manager", "192.168.11.35": "firefly-1", "192.168.11.36": "mim-api-1", "192.168.11.37": "mim-web-1", "192.168.11.50": "sankofa-api-1", "192.168.11.51": "sankofa-portal-1", "192.168.11.52": "sankofa-keycloak-1", "192.168.11.53": "sankofa-postgres-1", "192.168.11.57": "firefly-ali-1", "192.168.11.64": "indy-1", "192.168.11.65": "fabric-1", "192.168.11.100": "besu-validator-1", "192.168.11.101": "besu-validator-2", "192.168.11.102": "besu-validator-3", "192.168.11.103": "besu-validator-4", "192.168.11.104": "besu-validator-5", "192.168.11.105": "dbis-postgres-primary", "192.168.11.106": "dbis-postgres-replica-1", "192.168.11.110": "redis-rpc-translator", "192.168.11.111": "web3signer-rpc-translator", "192.168.11.112": "vault-rpc-translator", "192.168.11.120": "dbis-redis", "192.168.11.130": "dbis-frontend", "192.168.11.140": "blockscout-1", "192.168.11.150": "besu-sentry-1", "192.168.11.151": "besu-sentry-2", "192.168.11.152": "besu-sentry-3", "192.168.11.153": "besu-sentry-4", "192.168.11.154": "besu-sentry-ali", "192.168.11.155": "dbis-api-primary", "192.168.11.156": "dbis-api-secondary", "192.168.11.166": "npmplus", "192.168.11.167": "npmplus-secondary", "192.168.11.211": "besu-rpc-core-1", "192.168.11.221": "besu-rpc-public-1", "192.168.11.232": "besu-rpc-private-1", "192.168.11.233": "besu-rpc-ali-0x8a", "192.168.11.234": "besu-rpc-ali-0x1", "192.168.11.235": "besu-rpc-luis-0x8a", "192.168.11.236": "besu-rpc-luis-0x1", "192.168.11.237": "besu-rpc-putu-0x8a", "192.168.11.238": "besu-rpc-putu-0x1", "192.168.11.240": "thirdweb-rpc-1", "192.168.11.241": "besu-rpc-thirdweb-0x8a-1", "192.168.11.242": "besu-rpc-thirdweb-0x8a-2", "192.168.11.243": "besu-rpc-thirdweb-0x8a-3", } def get_hostname_from_proxmox(ip, vmid): """Try to get hostname from Proxmox""" try: result = subprocess.run( ["ssh", "-o", "StrictHostKeyChecking=no", "-o", "ConnectTimeout=2", "root@192.168.11.11", f"pct config {vmid} 2>/dev/null | grep '^hostname:' | awk '{{print $2}}'"], capture_output=True, text=True, timeout=3 ) if result.returncode == 0 and result.stdout.strip(): return result.stdout.strip() except: pass return IP_TO_HOSTNAME.get(ip, f"VMID-{vmid}") def main(): project_root = Path(__file__).parent.parent # Load .env env_file = project_root / ".env" npm_email = None npm_password = None if env_file.exists(): with open(env_file) as f: for line in f: if line.startswith("NPM_EMAIL="): npm_email = line.split("=", 1)[1].strip().strip('"').strip("'") elif line.startswith("NPM_PASSWORD="): npm_password = line.split("=", 1)[1].strip().strip('"').strip("'") if not npm_email or not npm_password: print("Error: NPM_EMAIL and NPM_PASSWORD must be set in .env", file=sys.stderr) sys.exit(1) npm_url = "https://192.168.11.166:81" # Authenticate import urllib.request import urllib.parse auth_data = json.dumps({ "identity": npm_email, "secret": npm_password }).encode() try: req = urllib.request.Request( f"{npm_url}/api/tokens", data=auth_data, headers={"Content-Type": "application/json"} ) with urllib.request.urlopen(req, context=None) as response: token_response = json.loads(response.read().decode()) token = token_response.get("token") except Exception as e: print(f"Error authenticating: {e}", file=sys.stderr) sys.exit(1) if not token: print("Error: Authentication failed", file=sys.stderr) sys.exit(1) # Get proxy hosts try: req = urllib.request.Request( f"{npm_url}/api/nginx/proxy-hosts", headers={"Authorization": f"Bearer {token}"} ) with urllib.request.urlopen(req, context=None) as response: proxy_hosts = json.loads(response.read().decode()) except Exception as e: print(f"Error fetching proxy hosts: {e}", file=sys.stderr) sys.exit(1) # Format output rows = [] for host in proxy_hosts: host_id = host.get("id") domain_names = host.get("domain_names", []) forward_host = host.get("forward_host", "") forward_port = host.get("forward_port", "") forward_scheme = host.get("forward_scheme", "http") if not domain_names: continue fqdn = domain_names[0] if isinstance(domain_names, list) else str(domain_names) vmid = IP_TO_VMID.get(forward_host, "N/A") if vmid != "N/A": service = get_hostname_from_proxmox(forward_host, vmid) else: service = f"External/{forward_host}" rows.append({ "vmid": vmid, "service": service, "ip": forward_host, "port": forward_port, "fqdn": fqdn, "scheme": forward_scheme }) # Sort by VMID rows.sort(key=lambda x: (int(x["vmid"]) if x["vmid"].isdigit() else 999999, x["fqdn"])) # Print table print(f"{'VMID':<8} {'Service/Hostname':<40} {'IP Address':<18} {'Port':<6} {'FQDN':<60}") print(f"{'-'*8} {'-'*40} {'-'*18} {'-'*6} {'-'*60}") for row in rows: print(f"{row['vmid']:<8} {row['service']:<40} {row['ip']:<18} {row['port']:<6} {row['fqdn']:<60}") if __name__ == "__main__": main()