- DB: add usernames/sudo_usernames columns to vm_requests table - create.php: add form inputs for usernames and sudo_usernames - send.php: capture, validate, and store both fields in DB - netbox_integration/netbox_api.php: pass custom_fields to NetBox VM API - requests.php: show usernames/sudo_usernames in request list
148 lines
4.5 KiB
PHP
Executable File
148 lines
4.5 KiB
PHP
Executable File
<?php
|
|
/**
|
|
* NetBox Virtualization API Client
|
|
* Creates Virtual Machines (not physical devices) in NetBox.
|
|
*/
|
|
|
|
class NetBoxClient {
|
|
private $baseUrl;
|
|
private $token;
|
|
|
|
public function __construct($baseUrl, $token) {
|
|
$this->baseUrl = rtrim($baseUrl, '/');
|
|
$this->token = $token;
|
|
}
|
|
|
|
private function headers() {
|
|
$h = [
|
|
'Content-Type: application/json',
|
|
'Accept: application/json',
|
|
];
|
|
if ($this->token) {
|
|
$h[] = 'Authorization: Token ' . $this->token;
|
|
}
|
|
return $h;
|
|
}
|
|
|
|
private function request($method, $endpoint, $body = null) {
|
|
$url = $this->baseUrl . '/api/' . ltrim($endpoint, '/');
|
|
$ch = curl_init();
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_URL => $url,
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_HTTPHEADER => $this->headers(),
|
|
CURLOPT_FOLLOWLOCATION => true,
|
|
CURLOPT_CUSTOMREQUEST => strtoupper($method),
|
|
]);
|
|
if ($body !== null) {
|
|
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
|
|
}
|
|
$resp = curl_exec($ch);
|
|
$info = curl_getinfo($ch);
|
|
curl_close($ch);
|
|
|
|
if ($info['http_code'] >= 400) {
|
|
throw new Exception("NetBox API {$method} {$endpoint} failed (HTTP {$info['http_code']}): {$resp}");
|
|
}
|
|
|
|
return json_decode($resp, true);
|
|
}
|
|
|
|
/**
|
|
* Get list endpoint (handles pagination for small result sets).
|
|
*/
|
|
public function getList($endpoint) {
|
|
$results = [];
|
|
$url = $endpoint . '?limit=100';
|
|
while ($url) {
|
|
$page = $this->request('get', $url);
|
|
foreach (($page['results'] ?? []) as $item) {
|
|
$results[] = $item;
|
|
}
|
|
$url = $page['next'] ?? null;
|
|
// Normalize next URL — NetBox returns absolute URLs
|
|
if ($url && strpos($url, 'http') === 0) {
|
|
$url = str_replace($this->baseUrl . '/api/', '', $url);
|
|
}
|
|
}
|
|
return $results;
|
|
}
|
|
|
|
public function post($endpoint, $data) {
|
|
return $this->request('post', $endpoint, $data);
|
|
}
|
|
|
|
/**
|
|
* Find a tag by name; returns the tag array or null.
|
|
*/
|
|
public function findTag($name) {
|
|
$tags = $this->getList('/extras/tags/');
|
|
foreach ($tags as $tag) {
|
|
if ($tag['name'] === $name) {
|
|
return $tag;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Find a cluster by name; returns the cluster array or null.
|
|
*/
|
|
public function findCluster($name) {
|
|
$clusters = $this->getList('/virtualization/clusters/');
|
|
foreach ($clusters as $c) {
|
|
if ($c['name'] === $name) {
|
|
return $c;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Create a Virtual Machine in NetBox.
|
|
*
|
|
* NetBox virtualization VM API uses:
|
|
* - vcpus: float (e.g. 2.0)
|
|
* - memory: int in MB (e.g. 4096)
|
|
* - disk: int in MB (e.g. 51200)
|
|
* - cluster: required (int id)
|
|
* - tags: array of tag names to look up
|
|
*/
|
|
public function createVirtualMachine(array $params) {
|
|
$payload = [
|
|
'name' => $params['name'],
|
|
'cluster' => $params['cluster_id'],
|
|
'status' => $params['status'] ?? 'active',
|
|
'vcpus' => (float) $params['vcpus'],
|
|
'memory' => (int) ($params['ram_gb'] * 1024), // GB -> MB
|
|
'disk' => (int) ($params['disk_gb'] * 1024), // GB -> MB
|
|
'description' => $params['description'] ?? '',
|
|
];
|
|
|
|
// Custom fields: usernames and sudo_usernames
|
|
$cf = [];
|
|
if (!empty($params['usernames'])) {
|
|
$cf['usernames'] = $params['usernames'];
|
|
}
|
|
if (!empty($params['sudo_usernames'])) {
|
|
$cf['sudo_usernames'] = $params['sudo_usernames'];
|
|
}
|
|
if (!empty($cf)) {
|
|
$payload['custom_fields'] = $cf;
|
|
}
|
|
|
|
// Tag lookup for domain — tags must be numeric IDs in the NetBox API
|
|
if (!empty($params['domain'])) {
|
|
$tag = $this->findTag($params['domain']);
|
|
if ($tag) {
|
|
$payload['tags'] = [$tag['id']];
|
|
} else {
|
|
error_log("NetBox: tag '{$params['domain']}' not found — creating VM without domain tag.");
|
|
}
|
|
}
|
|
|
|
$result = $this->post('/virtualization/virtual-machines/', $payload);
|
|
return $result;
|
|
}
|
|
}
|