-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.php
227 lines (188 loc) · 8.16 KB
/
index.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
<?php
/**
* Copyright (c) 2022 David Ramsden
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
// Send a GET request with cleardebug query set to clear the debug log file.
if (isset($_GET["cleardebug"])) {
echo "Clearing debug log.";
file_put_contents("debug.txt", "");
exit();
}
// Get JSON sent to us from NetBox webhook.
$json = json_decode(file_get_contents('php://input'));
// What model triggered the webhook?
switch ($json->{'model'}) {
case "ipaddress":
// Get the associated device data in JSON format.
$netbox = netbox_api($json->{'data'}->{'assigned_object'}->{'device'}->{'url'});
// Get the primary IPv4 device address.
$primary_ip = $netbox->{'primary_ip4'}->{'address'};
$primary_ip_nomask = preg_replace("/\/\d+$/", "", $primary_ip);
// Get the device's PRTG ID.
$prtg_id = $netbox->{'custom_fields'}->{'prtg_id'};
// Get the device's name.
$device_name = $netbox->{'name'};
debug("Device primary IPv4 address: " . $primary_ip);
debug("Device PRTG ID: " . $prtg_id);
// No PRTG ID but has a primary IPv4 address, so we need to add this device to PRTG.
// Then update the NetBox device with the PRTG device ID.
if (empty($prtg_id) && !empty($primary_ip)) {
debug("No device PRTG ID - Adding device to PRTG!");
// Duplicate device (NetBox PRTG template devce) in PRTG, in to target group.
// This will return the JSON formatted request to send to NetBox to update the NetBox device with it's PRTG device ID.
$payload = prtg_api("/api/duplicateobject.htm?id=" . get_request_header("X-PRTG-Template-Device") . "&name=" . $device_name . "&host=" . $primary_ip_nomask . "&targetid=" . get_request_header("X-PRTG-Target-Group"));
netbox_api($json->{'data'}->{'assigned_object'}->{'device'}->{'url'}, $payload);
$payload = json_decode($payload);
debug("Set NetBox device PRTG ID: " . $payload->{'custom_fields'}->{'prtg_id'});
// Unpause the device in PRTG.
debug("Unpausing new device in PRTG.");
prtg_api("/api/pause.htm?id=" . $payload->{'custom_fields'}->{'prtg_id'} . "&action=1");
} elseif (!empty($prtg_id)) {
// Note that this will update even if the primary IPv4 address has been removed.
debug("Device has a PRTG ID and primary IPv4 address could have changed - Updating PRTG device IP...");
prtg_api("/api/setobjectproperty.htm?id=" . $prtg_id . "&name=host&value=" . $primary_ip_nomask);
}
break;
case "device":
$prtg_id = $json->{'data'}->{'custom_fields'}->{'prtg_id'};
// Ignore if the PRTG ID is not set.
if (empty($prtg_id)) {
break;
}
switch ($json->{'event'}) {
case "deleted":
debug("Device was deleted. Pausing device in PRTG.");
prtg_api("/api/pause.htm?id=" . $prtg_id . "&pausemsg=" . urlencode("Deleted from NetBox") . "&action=0");
break;
case "updated":
// FIXME: Is this needed? This was probably only needed before we checked the event.
// e.g. if it was a "created" event, there would be no prechange snapshot.
if (!isset($json->{'snapshots'}->{'prechange'})) {
break;
}
// Device name has been changed.
// Update PRTG device name.
if ($json->{'snapshots'}->{'prechange'}->{'name'} !== $json->{'snapshots'}->{'postchange'}->{'name'}) {
debug("Device name has changed. Updating device name in PRTG.");
prtg_api("/api/rename.htm?id=" . $prtg_id . "&value=" . $json->{'snapshots'}->{'postchange'}->{'name'});
}
// Device status has been changed.
// Update PRTG device status (pause or resume).
if ($json->{'snapshots'}->{'prechange'}->{'status'} !== $json->{'snapshots'}->{'postchange'}->{'status'}) {
if ($json->{'snapshots'}->{'postchange'}->{'status'} === "active" || $json->{'snapshots'}->{'postchange'}->{'status'} === "staged") {
// A NetBox device status of either "active" or "staged" == unpause in PRTG.
debug("Device status has changed. Unpausing device in PRTG.");
prtg_api("/api/pause.htm?id=" . $prtg_id . "&action=1");
} else {
// Otherwise, pause the device in PRTG.
debug("Device status has changed. Pausing device in PRTG.");
prtg_api("/api/pause.htm?id=" . $prtg_id . "&pausemsg=" . urlencode("NetBox status: " . $json->{'snapshots'}->{'postchange'}->{'status'}) . "&action=0");
}
}
break;
default:
break;
}
break;
default:
break;
}
function get_request_header($header) {
return getallheaders()[$header];
}
function debug_enabled() {
// In the NetBox webook request, include X-Debug header with a value of true or false to enable or disable debugging.
return filter_var(get_request_header("X-Debug"), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
}
function debug($str) {
if (debug_enabled() === false) return;
$str = preg_replace("/(passhash=)(\d+)/", "$1REDACTED", $str);
file_put_contents("debug.txt", date("r") . ": " .$str . "\n", FILE_APPEND);
}
function netbox_api($url, $update = false) {
$curl = curl_init(get_request_header("X-NetBox-API-URL") . $url);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-type: application/json",
"Authorization: Token " . get_request_header("X-NetBox-API-Auth")));
if ($update !== false) {
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PATCH");
curl_setopt($curl, CURLOPT_POSTFIELDS, $update);
}
$response = curl_exec($curl);
$info = curl_getinfo($curl);
debug("Sending request to " . $info['url']);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
debug("NetBox API returned status: " . $status);
switch ($status) {
case 403:
debug("NetBox API authorization failed.");
exit();
break;
default:
break;
}
return json_decode($response);
}
function prtg_api($url) {
$curl = curl_init(get_request_header("X-PRTG-API-URL") . $url . "&" . get_request_header("X-PRTG-API-Auth"));
curl_setopt($curl, CURLOPT_HEADER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
// PRTG API is *terrible*. We need to determine if we're calling the duplicate object URL.
// If we are, we shouldn't follow the Location header automatically, because we need to parse the
// device ID from this header.
if (preg_match("/^\/api\/duplicateobject\.htm/", $url)) {
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, false);
} else {
// Otherwise, we should follow the Location header automatically.
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
}
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($curl);
$info = curl_getinfo($curl);
debug("Sending request to " . $info['url']);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
debug("PRTG API returned status: " . $status);
switch ($status) {
case 401:
debug("PRTG API username or passhash is incorrect.");
exit();
break;
case 302:
// If we called the duplicate object URL and we got a 302 response, we need to parse
// out the Location header to get the duplicated device's ID.
// We return this as JSON, formatted for sending to NetBox as a PATCH request.
if (preg_match("/^\/api\/duplicateobject\.htm/", $url)) {
if (preg_match("/Location: \/device.htm\?id=(\d+)\r\n/", $response, $matches)) {
return json_encode(array(
"custom_fields" => array(
"prtg_id" => intval($matches[1])
)
));
}
}
break;
default:
break;
}
}
?>