Release of grains plugin to racktables-contribs
[racktables-contribs] / nodeping.php
CommitLineData
82d35faa
AD
1<?php
2/*
3**************
4* Overview *
5**************
6Version 0.2
7Written by adoom42
8Integrate with NodePing: https://nodeping.com/
9 - Display check information when viewing an object.
10 - A single check may be associated with multiple objects.
11 - Multiple accounts are supported.
12It has been tested with RackTables 0.20.4.
13
14******************
15* Installation *
16******************
171. Place this file in the RackTables plugins directory.
18
192. Download the NodePing API from https://github.com/NodePing/NodePing_php.
20 Place the file in the plugins directory, and name it nodeping_api.inc
21 so RackTables does not treat it as a module.
22 You may need to uncomment this line within the NodePingRequest class:
23 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
24
253. Create these tables:
26CREATE TABLE `NodePingAccount` (
27 `id` int(10) unsigned NOT NULL auto_increment,
28 `name` char(50) NOT NULL,
29 `token` char(255) NOT NULL,
30 PRIMARY KEY (`id`)
31) ENGINE=InnoDB;
32
33CREATE TABLE `NodePingCheck` (
34 `id` int(10) unsigned NOT NULL auto_increment,
35 `account_id` int(10) unsigned NOT NULL,
36 `np_check_id` char(255) NOT NULL,
37 `label` char(255) NOT NULL,
38 `type` char(50) NOT NULL,
39 `target` text NOT NULL,
40 `check_interval` smallint(3) unsigned NOT NULL,
41 PRIMARY KEY (`id`),
42 UNIQUE KEY `np_check_id` (`np_check_id`),
43 CONSTRAINT `NodePingCheck-FK-account_id` FOREIGN KEY (`account_id`) REFERENCES `NodePingAccount` (`id`)
44) ENGINE=InnoDB;
45
46CREATE TABLE `NodePingLink` (
47 `id` int(10) unsigned NOT NULL auto_increment,
48 `check_id` int(10) unsigned NOT NULL,
49 `object_id` int(10) unsigned NOT NULL,
50 PRIMARY KEY (`id`),
51 UNIQUE KEY `NodePingLink-unique` (`check_id`,`object_id`),
52 CONSTRAINT `NodePingLink-FK-check_id` FOREIGN KEY (`check_id`) REFERENCES `NodePingCheck` (`id`) ON DELETE CASCADE,
53 CONSTRAINT `NodePingLink-FK-object_id` FOREIGN KEY (`object_id`) REFERENCES `Object` (`id`) ON DELETE CASCADE
54) ENGINE=InnoDB;
55
56
57******************
58* Usage *
59******************
601. Navigate to 'Configuration -> NodePing' and add your account(s).
61
622. Navigate to the NodePing tab of an object and add a new check.
63 You will now be able to associate the check with other objects.
64 Click the link in the Type column to see more details.
65
66
67******************
68* History *
69******************
700.1 - 2013-06-02 - Initial version by adoom42
710.2 - 2013-06-03 - Visual layout changes
72*/
73
74require_once 'nodeping_api.inc';
75
76$tab['object']['nodeping'] = 'NodePing';
77$tabhandler['object']['nodeping'] = 'renderNodePingChecks';
78$trigger['object']['nodeping'] = 'triggerNodePingChecks';
79$ophandler['object']['nodeping']['add'] = 'addNodePingCheck';
80$ophandler['object']['nodeping']['upd'] = 'updateNodePingCheck';
81$ophandler['object']['nodeping']['link'] = 'tableHandler';
82$ophandler['object']['nodeping']['unlink'] = 'tableHandler';
83$ophandler['object']['nodeping']['del'] = 'tableHandler';
84
85$page['nodeping']['title'] = 'NodePing';
86$page['nodeping']['parent'] = 'config';
87$tab['nodeping']['default'] = 'View';
88$tab['nodeping']['accounts'] = 'Edit accounts';
89$tabhandler['nodeping']['default'] = 'renderNodePingAccountsViewer';
90$tabhandler['nodeping']['accounts'] = 'renderNodePingAccountsEditor';
91$ophandler['nodeping']['accounts']['add'] = 'tableHandler';
92$ophandler['nodeping']['accounts']['upd'] = 'tableHandler';
93$ophandler['nodeping']['accounts']['del'] = 'tableHandler';
94
95$opspec_list['nodeping-accounts-add'] = array
96(
97 'table' => 'NodePingAccount',
98 'action' => 'INSERT',
99 'arglist' => array
100 (
101 array ('url_argname' => 'name', 'assertion' => 'string'),
102 array ('url_argname' => 'token', 'assertion' => 'string'),
103 ),
104);
105$opspec_list['nodeping-accounts-del'] = array
106(
107 'table' => 'NodePingAccount',
108 'action' => 'DELETE',
109 'arglist' => array
110 (
111 array ('url_argname' => 'id', 'assertion' => 'uint'),
112 ),
113);
114$opspec_list['nodeping-accounts-upd'] = array
115(
116 'table' => 'NodePingAccount',
117 'action' => 'UPDATE',
118 'set_arglist' => array
119 (
120 array ('url_argname' => 'name', 'assertion' => 'string'),
121 array ('url_argname' => 'token', 'assertion' => 'string'),
122 ),
123 'where_arglist' => array
124 (
125 array ('url_argname' => 'id', 'assertion' => 'uint'),
126 ),
127);
128$opspec_list['object-nodeping-link'] = array
129(
130 'table' => 'NodePingLink',
131 'action' => 'INSERT',
132 'arglist' => array
133 (
134 array ('url_argname' => 'check_id', 'assertion' => 'uint'),
135 array ('url_argname' => 'object_id', 'assertion' => 'uint'),
136 ),
137);
138$opspec_list['object-nodeping-unlink'] = array
139(
140 'table' => 'NodePingLink',
141 'action' => 'DELETE',
142 'arglist' => array
143 (
144 array ('url_argname' => 'link_id', 'table_colname' => 'id', 'assertion' => 'uint'),
145 ),
146);
147$opspec_list['object-nodeping-del'] = array
148(
149 'table' => 'NodePingCheck',
150 'action' => 'DELETE',
151 'arglist' => array
152 (
153 array ('url_argname' => 'check_id', 'table_colname' => 'id', 'assertion' => 'uint'),
154 ),
155);
156
157function triggerNodePingChecks ()
158{
159 if (! count (getNodePingAccounts ()))
160 return '';
161 return 'std';
162}
163
164function renderNodePingAccountsViewer ()
165{
166 $accounts = getNodePingAccounts ();
167 startPortlet ('NodePing accounts (' . count ($accounts) . ')');
168 echo '<table cellspacing=0 cellpadding=5 align=center class=widetable>';
169 echo '<tr><th>Name</th><th>API Token</th><th>Checks</th></tr>';
170 foreach ($accounts as $account)
171 {
172 echo "<tr><td>${account['name']}</td>";
173 echo "<td>${account['token']}</td>";
174 echo "<td class=tdcenter>${account['num_checks']}</td></tr>\n";
175 }
176 echo "</table>\n";
177 finishPortlet();
178}
179
180function renderNodePingAccountsEditor ()
181{
182 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable>\n";
183 echo "<tr><th>&nbsp;</th><th>Name</th><th>API Token</th><th>Checks</th><th>&nbsp;</th></tr>\n";
184 printOpFormIntro ('add');
185 echo '<tr><td>';
186 printImageHREF ('add', 'add account', TRUE);
187 echo '</td>';
188 echo '<td><input type=text size=20 name=name tabindex=101></td>';
189 echo '<td><input type=text size=40 name=token tabindex=102></td>';
190 echo '<td>&nbsp;</td><td>';
191 printImageHREF ('add', 'add account', TRUE);
192 echo "</td></tr></form>\n";
193
194 foreach (getNodePingAccounts () as $account)
195 {
196 printOpFormIntro ('upd', array ('id' => $account['id']));
197 echo '<tr><td>';
198 if ($account['num_checks'])
199 printImageHREF ('nodelete', 'cannot delete, checks exist');
200 else
201 {
202 echo '<a href="' . makeHrefProcess (array ('op' => 'del', 'id' => $account['id'])) . '">';
203 echo getImageHREF ('delete', 'delete this account') . '</a>';
204 }
205 echo '</td>';
206 echo '<td><input type=text size=20 name=name value="' . $account['name'] . '"></td>';
207 echo '<td><input type=text size=40 name=token value="' . $account['token'] . '"></td>';
208 echo "<td class=tdcenter>${account['num_checks']}</td>";
209 echo '<td>' . getImageHREF ('save', 'update this account', TRUE) . '</td>';
210 echo '</tr></form>';
211 }
212 echo "</table>\n";
213}
214
215function renderNodePingChecks ($object_id)
216{
217 $accounts = getNodePingAccounts ();
218 $account_options = array();
219 foreach ($accounts as $account)
220 $account_options[$account['id']] = $account['name'];
221 startPortlet ('Add new check');
222 echo "<table cellspacing=0 cellpadding=5 align='center'>\n";
223 echo "<tr><th>&nbsp;</th><th>Account</th><th>Check ID</th><th></th><th>&nbsp;</th></tr>\n";
224 printOpFormIntro ('add');
225 echo '<tr><td>';
226 printImageHREF ('add', 'add check', TRUE);
227 echo '</td><td>' . getSelect ($account_options, array ('name' => 'account_id'));
228 echo '</td><td><input type=text size=25 name=np_check_id tabindex=101></td><td>';
229 printImageHREF ('add', 'add check', TRUE);
230 echo "</td></tr></form></table>\n";
231 finishPortlet();
232
233 $checks = getUnlinkedNodePingChecks ($object_id);
234 if (count ($checks) > 0)
235 {
236 $check_options = array();
237 foreach ($checks as $check)
238 $check_options[$check['id']] = sprintf("%s - %s", $check['label'], $check['type']);
239 startPortlet ('Link existing check (' . count ($checks) . ')');
240 echo "<table cellspacing=0 cellpadding=5 align='center'>\n";
241 printOpFormIntro ('link');
242 echo '<tr><td>' . getSelect ($check_options, array ('name' => 'check_id'));
243 echo '</td><td class=tdleft>';
244 printImageHREF ('ATTACH', 'Link check', TRUE);
245 echo "</td></tr></form></table>\n";
246 finishPortlet();
247 }
248
249 addJs (<<<END
250function toggleVisibility(tbodyId) {
251 $("#" + tbodyId).toggle();
252}
253END
254 , TRUE);
255 $checks = getNodePingChecks ($object_id);
256 startPortlet ('NodePing checks (' . count ($checks) . ')');
257 if (count ($checks))
258 {
259 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable>\n";
260 echo "<tr><th>&nbsp;</th><th>Type</th><th>Label</th><th>Interval</th><th>Reason</th><th>Result</th><th>Unlink</th><th>&nbsp;</th></tr>\n";
261 $token = '';
262 foreach ($checks as $check)
263 {
264 printOpFormIntro ('upd', array ('check_id' => $check['check_id']));
265 echo '<tr><td><a href="' . makeHrefProcess (array ('op' => 'del', 'check_id' => $check['check_id'])) . '">';
266 echo getImageHREF ('delete', 'Unlink and delete this check') . '</a></td>';
267 echo "<td><a href=\"#\" onclick=\"toggleVisibility('${check['check_id']}');\">${check['type']}</a></td>";
268 echo "<td>${check['label']}</td>";
269 echo "<td>${check['check_interval']}</td>";
270 // re-use a nodeping object if it already exists and is using the same token as this check
271 if ($check['token'] != $token)
272 $nodeping = new NodePingClient (array ('token' => $check['token']));
273 $token = $check['token'];
274 $np_result_raw = $nodeping->result->get (array ('id' => $check['np_check_id'], 'limit' => 5, 'clean' => true));
275 if (isset ($np_result_raw['error']))
276 echo "<td colspan=5>Error: ${check_status_raw['error']}</td>";
277 else
278 {
279 $np_result = $np_result_raw[0];
280 if ($np_result['su'])
281 {
282 $reason = '';
283 $result_str = 'PASS';
284 $result_class = 'msg_success';
285 }
286 else
287 {
288 $reason = $np_result['sc'];
289 $result_str = 'FAIL';
290 $result_class = 'msg_error';
291 }
292 echo "<td>${reason}</td>";
293 echo "<td><span class='${result_class}'>${result_str}</span></td>";
294 }
295 echo '<td class=center><a href="' . makeHrefProcess (array ('op' => 'unlink', 'link_id' => $check['link_id'])) . '">';
296 echo getImageHREF ('cut', 'Unlink this check') . '</a></td>';
297 echo '<td class=tdleft>';
298 printImageHREF ('save', 'Save changes', TRUE);
299 echo "</td></tr>\n";
300 echo "<tbody id='${check['check_id']}' style='display:none;'><tr><td colspan=8>";
301 echo '<table cellspacing=0 cellpadding=5 align=left>';
302 // override the td styling so it doesn't have a border
303 echo '<tr><th>Account</th><td align=left style="border-top: 0px;">'. getSelect ($account_options, array ('name' => 'account_id'), $check['account_id']) . '</td></tr>';
304 echo '<tr><th>Check ID</th><td align=left style="border-top: 0px;"><input type=text size=25 name=np_check_id value="' . $check['np_check_id'] . '"></td></tr>';
305 echo "<tr><th>Target</th><td align=left style=\"border-top:0px; word-wrap:break-word; max-width:250px;\">${check['target']}</td></tr>";
306 echo '</table></form>';
307 echo '<table cellspacing=0 cellpadding=5 align=right>';
308 echo '<tr><th colspan=5>Last 5 Results</th></tr>';
309 echo '<tr><th>Time</th><th>Loc</th><th>Run Time</th><th>Response</th><th>Result</th></tr>';
310 foreach ($np_result_raw as $np_row)
311 {
312 // time is reported in miliseconds, so trim off the last 3 digits
313 printf ('<tr><td>%s</td>', date ('H:i:s A', substr ($np_row['s'], 0, -3)));
314 printf ('<td>%s</td>', strtoupper ($np_row['l'][$np_row['s']]));
315 if ($np_row['su'])
316 {
317 $result_str = 'PASS';
318 $result_class = 'msg_success';
319 }
320 else
321 {
322 $result_str = 'FAIL';
323 $result_class = 'msg_error';
324 }
325 echo "<td>${np_row['rt']}</td>";
326 echo "<td>${np_row['sc']}</td>";
327 echo "<td><span class='${result_class}'>${result_str}</span></td></tr>";
328 }
329 echo '</table>';
330 echo "</td></tr></tbody>\n";
331 }
332 echo "</table>\n";
333 }
334 finishPortlet();
335}
336
337function getNodePingAccount ($account_id)
338{
339 $result = usePreparedSelectBlade ('SELECT * FROM NodePingAccount WHERE id = ?', array ($account_id));
340 return $result->fetch (PDO::FETCH_ASSOC);
341}
342
343function getNodePingAccounts ()
344{
345 $result = usePreparedSelectBlade
346 (
347 'SELECT NPA.id, name, token, COUNT(NPC.id) as num_checks ' .
348 'FROM NodePingAccount NPA ' .
349 'LEFT JOIN NodePingCheck NPC ON NPA.id = NPC.account_id ' .
350 'GROUP BY NPA.id ORDER BY name'
351 );
352 return reindexById ($result->fetchAll (PDO::FETCH_ASSOC));
353}
354
355function getNodePingCheck ($check_id)
356{
357 $result = usePreparedSelectBlade ('SELECT * FROM NodePingCheck WHERE id = ?', array ($check_id));
358 $row = $result->fetch (PDO::FETCH_ASSOC);
359 return $row[0];
360}
361
362function getNodePingChecks ($object_id)
363{
364 $result = usePreparedSelectBlade
365 (
366 'SELECT NPL.id AS link_id, NPL.check_id, NPC.account_id, NPA.name AS account_name, NPA.token, NPC.np_check_id, ' .
367 'NPC.label, NPC.type, NPC.target, NPC.check_interval ' .
368 'FROM NodePingLink NPL ' .
369 'LEFT JOIN NodePingCheck NPC ON NPL.check_id = NPC.id ' .
370 'LEFT JOIN NodePingAccount NPA ON NPC.account_id = NPA.id ' .
371 'WHERE NPL.object_id = ?',
372 array ($object_id)
373 );
374 return reindexById ($result->fetchAll (PDO::FETCH_ASSOC), 'link_id');
375}
376
377function getUnlinkedNodePingChecks ($object_id)
378{
379 $result = usePreparedSelectBlade
380 (
381 'SELECT id, label, target, type ' .
382 'FROM NodePingCheck ' .
383 'WHERE id NOT IN (SELECT check_id FROM NodePingLink WHERE object_id = ?) ' .
384 'ORDER BY label, target, type',
385 array ($object_id)
386 );
387 return reindexById ($result->fetchAll (PDO::FETCH_ASSOC));
388}
389
390$msgcode['addNodePingCheck']['OK'] = 5;
391$msgcode['addNodePingCheck']['ERR1'] = 100;
392function addNodePingCheck ()
393{
394 assertUIntArg ('account_id');
395 assertStringArg ('np_check_id');
396 $account = getNodePingAccount ($_REQUEST['account_id']);
397 $nodeping = new NodePingClient (array ('token' => $account['token']));
398 $np_check = $nodeping->check->get (array ('id' => $_REQUEST['np_check_id'], 'limit' => 1, 'clean' => true));
399 if (isset ($np_check['error']))
400 return showFuncMessage (__FUNCTION__, 'ERR1', array ('Error: ' . $np_check['error']));
401 usePreparedInsertBlade
402 (
403 'NodePingCheck',
404 array
405 (
406 'account_id' => $_REQUEST['account_id'],
407 'np_check_id' => $_REQUEST['np_check_id'],
408 'label' => $np_check['label'],
409 'type' => $np_check['type'],
410 'target' => $np_check['parameters']['target'],
411 'check_interval' => $np_check['interval']
412 )
413 );
414 $check_id = lastInsertID();
415 global $sic;
416 usePreparedInsertBlade
417 (
418 'NodePingLink',
419 array
420 (
421 'check_id' => $check_id,
422 'object_id' => $sic['object_id'],
423 )
424 );
425 return showFuncMessage (__FUNCTION__, 'OK', array (htmlspecialchars ($np_check['label'])));
426}
427
428$msgcode['updateNodePingCheck']['OK'] = 6;
429$msgcode['updateNodePingCheck']['ERR1'] = 100;
430function updateNodePingCheck ()
431{
432 assertUIntArg ('check_id');
433 assertUIntArg ('account_id');
434 assertStringArg ('np_check_id');
435 $check = getNodePingCheck ($_REQUEST['check_id']);
436 $account = getNodePingAccount ($_REQUEST['account_id']);
437 $nodeping = new NodePingClient (array ('token' => $account['token']));
438 $np_check = $nodeping->check->get (array ('id' => $_REQUEST['np_check_id'], 'limit' => 1, 'clean' => true));
439 if (isset ($check['error']))
440 return showFuncMessage (__FUNCTION__, 'ERR1', array ('Error: ' . $np_check['error']));
441 usePreparedUpdateBlade
442 (
443 'NodePingCheck',
444 array
445 (
446 'account_id' => $_REQUEST['account_id'],
447 'np_check_id' => $_REQUEST['np_check_id'],
448 'label' => $np_check['label'],
449 'type' => $np_check['type'],
450 'target' => $np_check['parameters']['target'],
451 'check_interval' => $np_check['interval']
452 ),
453 array ('id' => $_REQUEST['check_id'])
454 );
455 return showFuncMessage (__FUNCTION__, 'OK', array (htmlspecialchars ($np_check['label'])));
456}
457?>