ancalagon / netbox
High Level Netbox API interface to handle objects like virtual machine, ip addresses, ...
Requires
- php: ^8.5
- ext-curl: *
- ext-json: *
Requires (Dev)
- ancalagon/netbox-podman: ^0.0.10
- phpunit/phpunit: ^11.0
- vlucas/phpdotenv: *
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
A PHP library providing high-level object-oriented wrappers around the NetBox REST API.
Each NetBox resource is represented as a PHP class with full CRUD support, fluent setters, and automatic hydration from API responses.
Requirements
- PHP 8.5+
ext-jsonext-curl
Installation
composer require ancalagon/netbox
Configuration
The library requires three environment variables to connect to your NetBox instance:
export NETBOX_URL_PREFIX="https://netbox.example.com/api" export NETBOX_KEY="your-key-prefix" export NETBOX_TOKEN="your-token-value"
The API token is assembled as nbt_{NETBOX_KEY}.{NETBOX_TOKEN}.
Two optional variables tune the cURL timeouts:
export NETBOX_CONNECT_TIMEOUT=5 # connection timeout in seconds (default: 5) export NETBOX_REQUEST_TIMEOUT=30 # total request timeout in seconds (default: 30)
Missing or empty values fall back to the defaults. A present-but-invalid value (non-numeric, zero, negative) throws Ancalagon\Netbox\Exception when the client is constructed.
Usage
Virtual Machines
use Ancalagon\Netbox\VirtualMachine; // Create a VM $vm = new VirtualMachine(); $vm->setName('web-server-01') ->setStatus('active') ->setCluster('1') ->setVcpus(4) ->setMemory(8192) ->setDisk(100); $vm->add(); echo $vm->getId(); // NetBox-assigned ID // Load an existing VM by name $vm = new VirtualMachine(); $vm->setName('web-server-01'); $vm->load(); // Load by ID $vm = new VirtualMachine(); $vm->setId('42'); $vm->load(); // Update (PATCH) $vm->setMemory(16384); $vm->update(); // Replace (PUT) $vm->edit(); // List with filters $vm = new VirtualMachine(); $results = $vm->list(['cluster_id' => '1', 'status' => 'active']); // Delete $vm->delete();
Clusters
use Ancalagon\Netbox\ClusterType; use Ancalagon\Netbox\ClusterGroup; use Ancalagon\Netbox\Cluster; // Create a cluster type and cluster $ct = new ClusterType(); $ct->setName('VMware')->setSlug('vmware'); $ct->add(); $cluster = new Cluster(); $cluster->setName('prod-cluster') ->setType($ct->getId()) ->setStatus('active'); $cluster->add();
Devices
use Ancalagon\Netbox\DeviceType; use Ancalagon\Netbox\DeviceRole; use Ancalagon\Netbox\Device; // Create a device role $role = new DeviceRole(); $role->setName('Server')->setSlug('server'); $role->add(); // Create a device type (requires manufacturer) $dt = new DeviceType(); $dt->setManufacturer($manufacturerId) ->setModel('PowerEdge R640') ->setSlug('poweredge-r640'); $dt->add(); // Create a device $device = new Device(); $device->setName('srv-01') ->setDeviceType($dt->getId()) ->setRole($role->getId()) ->setSite($siteId) ->setStatus('active'); $device->add();
IP Addresses
use Ancalagon\Netbox\IpAddress; // Create an IP address $ip = new IpAddress(); $ip->setAddress('192.168.1.10/24') ->setStatus('active') ->setDnsName('web-server-01.example.com'); $ip->add(); // Assign to a VM interface $ip->assignToVmInterface('15'); // Assign to a physical device interface $ip->assignToInterface('23'); // List IPs on a VM interface $ip = new IpAddress(); $results = $ip->listByVmInterface('15'); // Unassign $ip->unassign();
VLANs
use Ancalagon\Netbox\Vlan; $vlan = new Vlan(); $vlan->setVid(100) ->setName('Management') ->setStatus('active') ->setDescription('Management VLAN'); $vlan->add(); // Load by VID $vlan = new Vlan(); $vlan->setVid(100); $vlan->load();
Prefixes
use Ancalagon\Netbox\Prefix; $prefix = new Prefix(); $prefix->setPrefix('10.0.0.0/24') ->setStatus('active') ->setDescription('Server network'); $prefix->add();
VM Interfaces
use Ancalagon\Netbox\VirtualMachineInterface; // Create an interface on a VM $iface = new VirtualMachineInterface(); $iface->setVirtualMachine('42') ->setName('eth0') ->setEnabled(true) ->setMtu(1500); $iface->add(); // VLAN management $iface->assignUntaggedVlan('100'); $iface->addTaggedVlan('200'); $iface->addTaggedVlan('300'); $iface->removeTaggedVlan('200'); // List all interfaces for a VM $iface = new VirtualMachineInterface(); $results = $iface->listByVm('42');
Physical Network Interfaces
use Ancalagon\Netbox\NetworkInterface; $iface = new NetworkInterface(); $iface->setDevice('5') ->setName('GigabitEthernet0/1') ->setType(['value' => '1000base-t', 'label' => '1000BASE-T']) ->setEnabled(true); $iface->add(); // List all interfaces for a device $results = $iface->listByDevice('5');
MAC Addresses
use Ancalagon\Netbox\MacAddress; $mac = new MacAddress(); $mac->setMacAddress('00:1A:2B:3C:4D:5E') ->setDescription('Primary NIC'); $mac->add(); // Load by MAC $mac = new MacAddress(); $mac->setMacAddress('00:1A:2B:3C:4D:5E'); $mac->load();
Owners and Owner Groups
use Ancalagon\Netbox\OwnerGroup; use Ancalagon\Netbox\Owner; // Create an owner group $group = new OwnerGroup(); $group->setName('Infrastructure Team') ->setDescription('Manages core infrastructure'); $group->add(); // Create an owner in that group $owner = new Owner(); $owner->setName('Network Ops') ->setGroup($group->getId()) ->setDescription('Network operations team') ->setUsers([1, 2, 3]); $owner->add(); // List owners in a group $owner = new Owner(); $results = $owner->listByGroup($group->getId());
Filtering
list() passes its filter array through to the query string. Values may be
strings, ints, floats, bools, or lists:
$devices = (new Device())->list([ 'site' => 'namur', 'status' => ['active', 'planned'], // repeated key: status=active&status=planned 'has_primary_ip' => true, // serialized as true/false, not 1/0 ]);
Both of those forms were broken before 0.0.16 — they serialized to something NetBox does not recognise, and NetBox responds by ignoring the filter and returning the entire collection rather than erroring. If you are upgrading from 0.0.15 or earlier, review any script that filters on a list or a bool: it has been selecting more rows than you think. See the CHANGELOG for measured before/after counts.
Null values are skipped. Associative arrays are rejected with
\InvalidArgumentException, with one exception: the reserved custom_fields
key, which is translated into NetBox's cf_<name>=<value> convention.
$devices = (new Device())->list([ 'custom_fields' => ['is_imap' => true], // -> cf_is_imap=true ]);
Pagination
list() returns NetBox's response envelope verbatim and does not follow
the next link, so how many rows you get depends on the server's
PAGINATE_COUNT. Compare the two counts to turn a silent truncation into a
loud one:
$res = (new Device())->list(['limit' => 0]); if (count($res['results']) !== $res['count']) { throw new RuntimeException("truncated: {$res['count']} matched, " . count($res['results']) . " returned"); }
Error Handling
All API errors are wrapped in Exception:
use Ancalagon\Netbox\Exception; try { $vm = new VirtualMachine(); $vm->setName('test-vm'); $vm->load(); } catch (Exception $e) { echo $e->getMessage(); }
Testing
Integration tests run against a live NetBox instance:
vendor/bin/phpunit
CRUD Method Reference
Every entity class provides the same set of operations:
| Method | HTTP Verb | Description |
|---|---|---|
add() |
POST | Create a new resource |
load() |
GET | Fetch by ID or unique field(s) |
list() |
GET | List resources with optional filters |
edit() |
PUT | Full replacement of a resource |
update() |
PATCH | Partial update of a resource |
delete() |
DELETE | Remove a resource |
License
MIT - see LICENSE.