Search by

ancalagon / netbox

bmairlot

High Level Netbox API interface to handle objects like virtual machine, ip addresses, ...

Package info

github.com/bmairlot/netbox

pkg:composer/ancalagon/netbox

Statistics

Installs: 279

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.0.16 2026-08-27 19:19 UTC

This package is auto-updated.

Last update: 2026-08-27 19:21:52 UTC


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-json
  • ext-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.