From b5814e9e616c91551c11513b9533a288c13d60e9 Mon Sep 17 00:00:00 2001 From: Fredrick Amnehagen Date: Fri, 6 Feb 2026 08:36:38 +0100 Subject: [PATCH] feat: implement automated VMID discovery for LXC creation --- README.md | 2 +- infra_cli/main.py | 16 +++++++++++++--- infra_cli/proxmox.py | 8 ++++++++ tests/unit/test_proxmox_logic.py | 13 +++++++++++++ 4 files changed, 35 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 796bda1..ed7baca 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ export INFRA_CONFIG=$(pwd)/config.yaml ### Official Recommended Flow 1. **Find an IP:** `infra ip next-free` 2. **Create Database:** `infra db provision "my-project"` -3. **Provision LXC:** `infra proxmox create-lxc 12xxx debian-13 "my-host" "10.32.70.x/16" "10.32.0.1" --node la-vmh-12` +3. **Provision LXC:** `infra proxmox create-lxc debian-13 "my-host" "10.32.70.x/16" "10.32.0.1" --node la-vmh-12` 4. **Setup DNS:** `infra dns add-host 10.32.70.x "my-host"` 5. **Update SSL:** `infra cert renew` 6. **Expose Ingress:** `infra ingress add "my-project.loopaware.com" 10.32.70.x 80` diff --git a/infra_cli/main.py b/infra_cli/main.py index a34dc2c..0f6cc93 100644 --- a/infra_cli/main.py +++ b/infra_cli/main.py @@ -156,7 +156,7 @@ def proxmox_list_lxcs(config, node): click.echo(mgr.list_lxcs()) @proxmox.command(name='create-lxc') -@click.argument('vmid') +@click.option('--vmid', help='VMID for the container (auto-discovered if omitted)') @click.argument('template') @click.argument('hostname') @click.argument('ip') @@ -166,8 +166,18 @@ def proxmox_list_lxcs(config, node): @click.pass_obj def proxmox_create_lxc(config, vmid, template, hostname, ip, gateway, node, password): mgr = ProxmoxManager(config, node) - mgr.create_lxc(vmid, template, hostname, ip, gateway, password=password) - click.echo(f"LXC {vmid} ({hostname}) created on {mgr.node_name or 'default node'}") + + target_vmid = vmid + if not target_vmid: + click.echo("Discovering next available VMID...") + target_vmid = mgr.get_next_vmid() + if not target_vmid: + click.echo("Error: Could not automatically discover next VMID. Please provide one with --vmid", err=True) + sys.exit(1) + + click.echo(f"Using VMID: {target_vmid}") + mgr.create_lxc(target_vmid, template, hostname, ip, gateway, password=password) + click.echo(f"LXC {target_vmid} ({hostname}) created on {mgr.node_name or 'default node'}") @cli.group() def samba(): diff --git a/infra_cli/proxmox.py b/infra_cli/proxmox.py index 0f17808..7e91c0c 100644 --- a/infra_cli/proxmox.py +++ b/infra_cli/proxmox.py @@ -22,6 +22,14 @@ class ProxmoxManager: res = self.client.run(f"pct status {vmid}") return res.stdout + def get_next_vmid(self): + """Retrieves the next available cluster-wide VMID from Proxmox""" + res = self.client.run("pvesh get /cluster/nextid") + if res.returncode == 0 and res.stdout.strip(): + return res.stdout.strip() + # Fallback if pvesh fails (highly unlikely on PVE) + return None + def resolve_template(self, alias): """Resolves a template alias (e.g. 'debian-13') to the latest full path on the node""" if alias == "debian-13": diff --git a/tests/unit/test_proxmox_logic.py b/tests/unit/test_proxmox_logic.py index 94ed406..2346f9b 100644 --- a/tests/unit/test_proxmox_logic.py +++ b/tests/unit/test_proxmox_logic.py @@ -31,3 +31,16 @@ def test_storage_discovery(mock_ssh): storage = mgr.discover_storage() assert storage == "local-zfs" + +@patch('infra_cli.proxmox.SSHClient') +def test_vmid_discovery(mock_ssh): + mock_instance = mock_ssh.return_value + mock_instance.run.return_value.returncode = 0 + mock_instance.run.return_value.stdout = "105" + + mgr = ProxmoxManager(MockConfig()) + vmid = mgr.get_next_vmid() + + assert vmid == "105" + mock_instance.run.assert_called_with("pvesh get /cluster/nextid") +