I'm trying to design a simple self-service workflow for creating VMs across several Proxmox clusters and servers. At the moment, I manually start a GitLab pipeline, enter Terraform and Ansible variables, create the VM, and then add its details to NetBox. For IP selection, I choose an address from NetBox and use ping to check whether it appears to be unused.
I'd like several teams, as well as myself, to be able to request a VM without manually updating NetBox and both Active Directory DNS and BIND DNS every time. One idea is to use NetBox as the request interface and trigger Terraform and Ansible pipelines through webhooks.
Ideally, a request would look something like: create VM `web-123` running Ubuntu 24.04 with 4 CPUs, 8 GB RAM, a 100 GB disk, `production` as the environment, and VLAN 40.
I'm also unsure how best to pass values into Ansible. For example, should roles use committed variables, or should values such as the IP address and selected role come from GitLab pipeline variables or a form? I'd prefer not to commit a change every time an IP changes, while still keeping the workflow properly version-controlled.
2 Answers
NetBox can drive this workflow, but it isn’t a turnkey feature and may take substantial effort to build and maintain. A reasonable design is to use NetBox webhooks with a small intermediary service that validates the request and starts the appropriate pipeline. Before committing to that architecture, make sure the time saved justifies the additional moving parts.
Keep the existing GitLab pipeline as the entry point initially. A small request form or versioned VM request file is likely easier to maintain than making every NetBox edit trigger provisioning.
Validate the VM name, size, target cluster, VLAN, and the requester’s permissions before running anything. Keep infrastructure credentials in the runner rather than in request variables. Reserve the IP in authoritative IPAM before creating the VM; a failed ping does not prove an address is available because the address may belong to an offline host or one that blocks ICMP. Allocation also needs to handle concurrent requests safely and avoid DHCP-managed ranges.
Use Terraform to create the VM and Ansible to configure it. Give each request an ID and preserve Terraform state so a retry after a DNS or configuration failure does not create a duplicate VM. Once provisioning succeeds, update the authoritative DNS systems and NetBox, with clear ownership for each field so Terraform, discovery, and manual changes do not overwrite one another unexpectedly.
Test partial failures first, especially the case where the VM exists but DNS registration fails. Keep that request marked incomplete and retry only the failed step. During teardown, verify that the VM is gone before releasing its IP reservation, and delete only DNS records owned by that request. Once this lifecycle works reliably, you can add a NetBox-based request interface if the teams actually need one.
That is close to what I have implemented, although I still need to handle some details and edge cases. For Ansible, I currently choose a configuration role and provide the IP through the same GitLab pipeline. Should those values live in committed variables, or should they be supplied through the GitLab interface so I don’t have to commit every IP change?

I’m supporting three teams, and they sometimes need several temporary VM environments on our Proxmox clusters. I also want to provision machines without having to update NetBox and DNS manually each time. Would you recommend another approach for keeping this simple?