update snmpgeneric.php for 0.20.x
[racktables-contribs] / linkmgmt.php
CommitLineData
9276dc97
ME
1<?php
2/*
3 * Link Management
4 *
5 * Displays links between Ports.
6 * Allows you to create/delete front and backend links between ports
7 * Link object backend ports by name (e.g. handy for patch panels)
8 * Change CableIDs
9 * Change Port Reservation Comment
10 *
11 *
12 * e.g.
13 * (Object)>[port] -- front --> [port]<(Object) == back == > (Object)>[port] -- front --> [port]<(Object)
14 *
15 *
16 *
17 * INSTALL:
18 *
19 * - create LinkBackend Table
20
21CREATE TABLE `LinkBackend` (
22 `porta` int(10) unsigned NOT NULL DEFAULT '0',
23 `portb` int(10) unsigned NOT NULL DEFAULT '0',
24 `cable` char(64) DEFAULT NULL,
25 PRIMARY KEY (`porta`,`portb`),
26 UNIQUE KEY `porta` (`porta`),
27 UNIQUE KEY `portb` (`portb`),
28 CONSTRAINT `LinkBackend-FK-a` FOREIGN KEY (`porta`) REFERENCES `Port` (`id`) ON DELETE CASCADE,
29 CONSTRAINT `LinkBackend-FK-b` FOREIGN KEY (`portb`) REFERENCES `Port` (`id`) ON DELETE CASCADE
30) ENGINE=InnoDB DEFAULT CHARSET=utf8;
31
32 * - copy linkmgmt.php to inc/ directory
33 * - copy jquery.jeditable.mini.js to js/ directory
34 * - add "include 'inc/linkmgmt.php';" to inc/local.php
35 *
36 * TESTED on FreeBSD 9.0, nginx/1.0.11, php 5.3.9
37 * and RackTables 0.19.11
38 *
39 * (c)2012 Maik Ehinger <m.ehinger@ltur.de>
40 */
41
42/*************************
43 * Change Log
44 *
45 * 15.01.12 new loopdetection
46 * 18.01.12 code cleanups
47 * 23.01.12 add href to printport
48 * 24.01.12 add opHelp
49 * 25.01.12 max loop count handling changed
50 * add port label to port tooltip
51 * 28.02.12 changed printportlistrow() first from TRUE to FALSE
52 * add portlist::hasbackend()
53 * 29.02.12 fix update cable id for backend links
54 * add linkmgmt_commitUpdatePortLink
55 * 04.03.12 add set_reserve_comment and set_link permission handling
56 *
57 *
58 */
59
60/*************************
61 * TODO
62 *
63 * - code cleanups
64 * - bug fixing
65 *
66 * - csv list
67 *
68 * - fix $opspec_list for unlink
69 *
70 */
71
72require_once 'inc/popup.php';
73
74$tab['object']['linkmgmt'] = 'Link Management';
75$tabhandler['object']['linkmgmt'] = 'linkmgmt_tabhandler';
76//$trigger['object']['linkmgmt'] = 'linkmgmt_tabtrigger';
77
78$ophandler['object']['linkmgmt']['update'] = 'linkmgmt_opupdate';
79$ophandler['object']['linkmgmt']['unlinkPort'] = 'linkmgmt_opunlinkPort';
80$ophandler['object']['linkmgmt']['PortLinkDialog'] = 'linkmgmt_opPortLinkDialog';
81$ophandler['object']['linkmgmt']['Help'] = 'linkmgmt_opHelp';
82
83
84/* -------------------------------------------------- */
85
86$lm_cache = array(
87 'allowcomment' => TRUE, /* RackCode ${op_set_reserve_comment} */
88 'allowlink' => TRUE, /* RackCode ${op_set_link} */
89 'rackinfo' => array(),
90 );
91
92/* -------------------------------------------------- */
93
94//function linkmgmt_tabtrigger() {
95// return 'std';
96//} /* linkmgmt_tabtrigger */
97
98/* -------------------------------------------------- */
99
100function linkmgmt_opHelp() {
101?>
102 <table cellspacing=10><tr><th>Help</th><tr>
103 <tr><td width=150></td><td width=150 style="font-weight:bold;color:<?php echo portlist::CURRENT_OBJECT_BGCOLOR; ?>">Current Object</td></tr>
104 <tr><td></td><td bgcolor=<?php echo portlist::CURRENT_PORT_BGCOLOR; ?>>[current port]</td></tr>
105 <tr><td>front link</td><td>[port]<(Object)</td><td>back link</td></tr>
106 <tr><td>back link</td><td>(Object)>[port]</td><td>front link</td></tr>
107 <tr><td></td><td><pre>----></pre></td><td>Front link</td></tr>
108 <tr><td></td><td><pre>====></pre></td><td>Backend link</td></tr>
109 <tr><td></td><td>Link Symbol</td><td>Create new link</td></tr>
110 <tr><td></td><td>Cut Symbol</td><td>Delete link</td></tr>
111
112 </table>
113
114<?php
115 exit;
116} /* opHelp */
117
118/* -------------------------------------------------- */
119
120function linkmgmt_opupdate() {
121
122 if(!isset($_POST['id']))
123 exit;
124
125 $ids = explode('_',$_POST['id'],3);
126 $retval = strip_tags($_POST['value']);
127
128 if(isset($ids[1])) {
129 if(permitted(NULL, NULL, 'set_link'))
130 if(isset($ids[2]) && $ids[2] == 'back')
131 linkmgmt_commitUpdatePortLink($ids[0], $retval, TRUE);
132 else
133 linkmgmt_commitUpdatePortLink($ids[0], $retval);
134 else
135 $retval = "Permission denied!";
136 } else {
137 if(permitted(NULL, NULL, 'set_reserve_comment'))
138 commitUpdatePortComment($ids[0], $retval);
139 else
140 $retval = "Permission denied!";
141 }
142
143 /* return what jeditable should display after edit */
144 echo $retval;
145
146 exit;
147} /* opupdate */
148
149/* -------------------------------------------------- */
150
151/* similar to commitUpatePortLink in database.php with backend support */
152function linkmgmt_commitUpdatePortLink($port_id, $cable = NULL, $backend = FALSE) {
153
154 /* TODO check permissions */
155
156 if($backend)
157 $table = 'LinkBackend';
158 else
159 $table = 'Link';
160
161 return usePreparedUpdateBlade
162 (
163 $table,
164 array ('cable' => mb_strlen ($cable) ? $cable : NULL),
165 array ('porta' => $port_id, 'portb' => $port_id),
166 'OR'
167 );
168} /* linkmgmt_commitUpdatePortLink */
169
170/* -------------------------------------------------- */
171
172function linkmgmt_opunlinkPort() {
173 $port_id = $_REQUEST['port_id'];
174 $linktype = $_REQUEST['linktype'];
175
176 /* check permissions */
177 if(!permitted(NULL, NULL, 'set_link')) {
178 exit;
179 }
180
181 if($linktype == 'back')
182 $table = 'LinkBackend';
183 else
184 $table = 'Link';
185
186 $retval = usePreparedDeleteBlade ($table, array('porta' => $port_id, 'portb' => $port_id), 'OR');
187
188 if($retval == 0)
189 echo " Link not found";
190 else
191 echo " $retval Links deleted";
192
193 header('Location: ?page='.$_REQUEST['page'].'&tab='.$_REQUEST['tab'].'&object_id='.$_REQUEST['object_id']);
194 exit;
195} /* opunlinkPort */
196
197/* -------------------------------------------------- */
198
199function linkmgmt_oplinkPort() {
200
201 $linktype = $_REQUEST['linktype'];
202 $cable = $_REQUEST['cable'];
203
204 /* check permissions */
205 if(!permitted(NULL, NULL, 'set_link')) {
206 echo("Permission denied!");
207 return;
208 }
209
210 if(!isset($_REQUEST['link_list'])) {
211 //portlist::var_dump_html($_REQUEST);
212 $porta = $_REQUEST['port'];
213 $portb = $_REQUEST['remote_port'];
214
215 $link_list[] = "${porta}_${portb}";
216 } else
217 $link_list = $_REQUEST['link_list'];
218
219 foreach($link_list as $link){
220
221 $ids = preg_split('/[^0-9]/',$link);
222 $porta = $ids[0];;
223 $portb = $ids[1];
224
225 $ret = linkmgmt_linkPorts($porta, $portb, $linktype, $cable);
226
227 error_log("$ret - $porta - $portb");
228 $port_info = getPortInfo ($porta);
229 $remote_port_info = getPortInfo ($portb);
230 showSuccess(
231 sprintf
232 (
233 'Port %s %s successfully linked with port %s %s',
234 formatPortLink ($port_info['id'], $port_info['name'], NULL, NULL),
235 $linktype,
236 formatPort ($remote_port_info),
237 $linktype
238 )
239 );
240 }
241
242
243
244 addJS (<<<END
245window.opener.location.reload(true);
246window.close();
247END
248 , TRUE);
249
250 return;
251} /* oplinkPort */
252
253/* -------------------------------------------------- */
254
255/*
256 * same as in database.php extendend with linktype
257 */
258function linkmgmt_linkPorts ($porta, $portb, $linktype, $cable = NULL)
259{
260 if ($porta == $portb)
261 throw new InvalidArgException ('porta/portb', $porta, "Ports can't be the same");
262
263 if($linktype == 'back')
264 $table = 'LinkBackend';
265 else
266 $table = 'Link';
267
268 global $dbxlink;
269 $dbxlink->exec ('LOCK TABLES '.$table.' WRITE');
270 $result = usePreparedSelectBlade
271 (
272 'SELECT COUNT(*) FROM '.$table.' WHERE porta IN (?,?) OR portb IN (?,?)',
273 array ($porta, $portb, $porta, $portb)
274 );
275 if ($result->fetchColumn () != 0)
276 {
277 $dbxlink->exec ('UNLOCK TABLES');
278 return "$linktype Port ${porta} or ${portb} is already linked";
279 }
280 $result->closeCursor ();
281 if ($porta > $portb)
282 {
283 $tmp = $porta;
284 $porta = $portb;
285 $portb = $tmp;
286 }
287 $ret = FALSE !== usePreparedInsertBlade
288 (
289 $table,
290 array
291 (
292 'porta' => $porta,
293 'portb' => $portb,
294 'cable' => mb_strlen ($cable) ? $cable : ''
295 )
296 );
297 $dbxlink->exec ('UNLOCK TABLES');
298 $ret = $ret and FALSE !== usePreparedExecuteBlade
299 (
300 'UPDATE Port SET reservation_comment=NULL WHERE id IN(?, ?)',
301 array ($porta, $portb)
302 );
303 return $ret ? '' : 'query failed';
304}
305
306/* -------------------------------------------------- */
307
308/*
309 * similar to renderPopupHTML in popup.php
310 */
311function linkmgmt_opPortLinkDialog() {
312// portlist::var_dump_html($_REQUEST);
313header ('Content-Type: text/html; charset=UTF-8');
314?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
315<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" style="height: 100%;">
316<?php
317
318 $text = '<div style="background-color: #f0f0f0; border: 1px solid #3c78b5; padding: 10px; text-align: center;
319 margin: 5px;">';
320
321 if(permitted(NULL,NULL,"set_link"))
322 if (isset ($_REQUEST['do_link'])) {
323 $text .= getOutputOf ('linkmgmt_oplinkPort');
324 }
325 else
326 if(isset($_REQUEST['byname']))
327 $text .= getOutputOf ('linkmgmt_renderPopupPortSelectorbyName');
328 else
329 $text .= getOutputOf ('linkmgmt_renderPopupPortSelector');
330 else
331 $text .= "Permission denied!";
332
333 $text .= '</div>';
334
335 echo '<head><title>RackTables pop-up</title>';
336 printPageHeaders();
337 echo '</head>';
338 echo '<body style="height: 100%;">' . $text . '</body>';
339?>
340</html>
341<?php
342 exit;
343} /* opPortLinkDialog */
344
345/* -------------------------------------------------- */
346
347/*
348 * like findSparePorts in popup.php extended with linktype
349 */
350function linkmgmt_findSparePorts($port_info, $filter, $linktype) {
351
352 // all ports with no backend link
353 /* port:object -> front linked port:object */
354 $query = 'select Port.id, CONCAT(RackObject.name, " : ", Port.name,
355 IFNULL(CONCAT(" -- ", Link.cable," --> ",lnkPort.name, " : ", lnkObject.name),"") )
356 from Port
357 left join LinkBackend on Port.id in (LinkBackend.porta,LinkBackend.portb)
358 left join RackObject on RackObject.id = Port.object_id
359 left join Link on Port.id in (Link.porta, Link.portb)
360 left join Port as lnkPort on lnkPort.id = ((Link.porta ^ Link.portb) ^ Port.id)
361 left join RackObject as lnkObject on lnkObject.id = lnkPort.object_id';
362
363 $qparams = array();
364
365 // self and linked ports filter
366 $query .= " WHERE Port.id <> ? ".
367 "AND LinkBackend.porta is NULL ";
368 $qparams[] = $port_info['id'];
369
370 // rack filter
371 if (! empty ($filter['racks']))
372 {
373 $query .= 'AND Port.object_id IN (SELECT DISTINCT object_id FROM RackSpace WHERE rack_id IN (' .
374 questionMarks (count ($filter['racks'])) . ')) ';
375 $qparams = array_merge ($qparams, $filter['racks']);
376 }
377
378 // objectname filter
379 if (! empty ($filter['objects']))
380 {
381 $query .= 'AND RackObject.name like ? ';
382 $qparams[] = '%' . $filter['objects'] . '%';
383 }
384 // portname filter
385 if (! empty ($filter['ports']))
386 {
387 $query .= 'AND Port.name LIKE ? ';
388 $qparams[] = '%' . $filter['ports'] . '%';
389 }
390 // ordering
391 $query .= ' ORDER BY RackObject.name';
392
393
394 $result = usePreparedSelectBlade ($query, $qparams);
395
396 $row = $result->fetchAll(PDO::FETCH_GROUP|PDO::FETCH_UNIQUE|PDO::FETCH_COLUMN);
397
398 /* [id] => displaystring */
399 return $row;
400
401} /* findSparePorts */
402
403/* -------------------------------------------------- */
404
405/*
406 * similar to findSparePorts but finds Ports with same name
407 */
408function linkmgmt_findSparePortsbyName($object_id, $remote_object, $linktype) {
409
410 // all ports with same name on object and remote_object and without existing backend link
411 $query = 'select CONCAT(Port.id,"_",rPort.id), CONCAT(RackObject.name, " : ", Port.name, " -?-> ", rPort.name, " : ", rObject.name)
412 from Port
413 left join LinkBackend on Port.id in (LinkBackend.porta,LinkBackend.portb)
414 left join RackObject on RackObject.id = Port.object_id
415 left join Port as rPort on rPort.name = Port.Name
416 left join RackObject as rObject on rObject.id = rPort.object_id
417 left join LinkBackend as rLinkBackend on rPort.id in (rLinkBackend.porta, rLinkBackend.portb)';
418
419 $qparams = array();
420
421 // self and linked ports filter
422 $query .= " WHERE Port.object_id = ? ".
423 "AND rPort.object_id = ? ".
424 "AND LinkBackend.porta is NULL ".
425 "AND rLinkBackend.porta is NULL ";
426 $qparams[] = $object_id;
427 $qparams[] = $remote_object;
428
429 // ordering
430 $query .= ' ORDER BY Port.name';
431
432 $result = usePreparedSelectBlade ($query, $qparams);
433
434 $row = $result->fetchAll(PDO::FETCH_GROUP|PDO::FETCH_UNIQUE|PDO::FETCH_COLUMN);
435
436 /* [id] => displaystring */
437 return $row;
438
439} /* findSparePortsbyName */
440
441/* -------------------------------------------------- */
442
443/*
444 * like renderPopupPortSelector in popup.php extenden with linktype
445 */
446function linkmgmt_renderPopupPortSelector()
447{
448 assertUIntArg ('port');
449 $port_id = $_REQUEST['port'];
450 $linktype = $_REQUEST['linktype'];
451 $object_id = $_REQUEST['object_id'];
452 $port_info = getPortInfo ($port_id);
453 $in_rack = isset ($_REQUEST['in_rack']);
454
455// portlist::var_dump_html($port_info);
456// portlist::var_dump_html($_REQUEST);
457
458 // fill port filter structure
459 $filter = array
460 (
461 'racks' => array(),
462 'objects' => '',
463 'ports' => '',
464 );
465 if (isset ($_REQUEST['filter-obj']))
466 $filter['objects'] = $_REQUEST['filter-obj'];
467 if (isset ($_REQUEST['filter-port']))
468 $filter['ports'] = $_REQUEST['filter-port'];
469 if ($in_rack)
470 {
471 $object = spotEntity ('object', $port_info['object_id']);
472 if ($object['rack_id'])
473 $filter['racks'] = getProximateRacks ($object['rack_id'], getConfigVar ('PROXIMITY_RANGE'));
474 }
475 $spare_ports = array();
476 if
477 (
478 $in_rack ||
479 ! empty ($filter['objects']) ||
480 ! empty ($filter['ports'])
481 )
482 $spare_ports = linkmgmt_findSparePorts ($port_info, $filter, $linktype);
483
484 // display search form
485 echo 'Link '.$linktype.' of ' . formatPort ($port_info) . ' to...';
486 echo '<form method=POST>';
487 startPortlet ($linktype.' Port list filter');
488 // echo '<input type=hidden name="module" value="popup">';
489 // echo '<input type=hidden name="helper" value="portlist">';
490
491 echo '<input type=hidden name="port" value="' . $port_id . '">';
492 echo '<table align="center" valign="bottom"><tr>';
493 echo '<td class="tdleft"><label>Object name:<br><input type=text size=8 name="filter-obj" value="' . htmlspecialchars ($filter['objects'], ENT_QUOTES) . '"></label></td>';
494 echo '<td class="tdleft"><label>Port name:<br><input type=text size=6 name="filter-port" value="' . htmlspecialchars ($filter['ports'], ENT_QUOTES) . '"></label></td>';
495 echo '<td class="tdleft" valign="bottom"><label><input type=checkbox name="in_rack"' . ($in_rack ? ' checked' : '') . '>Nearest racks</label></td>';
496 echo '<td valign="bottom"><input type=submit value="show '.$linktype.' ports"></td>';
497 echo '</tr></table>';
498 finishPortlet();
499
500 // display results
501 startPortlet ('Compatible spare '.$linktype.' ports');
502 echo('back Object:Port -- front cableID --> front Port:Object');
503
504 if (empty ($spare_ports))
505 echo '(nothing found)';
506 else
507 {
508 echo getSelect ($spare_ports, array ('name' => 'remote_port', 'size' => getConfigVar ('MAXSELSIZE')), NULL, FALSE);
509 echo "<p>$linktype Cable ID: <input type=text id=cable name=cable>";
510 echo "<p><input type='submit' value='Link $linktype' name='do_link'>";
511 }
512 finishPortlet();
513 echo '</form>';
514
515} /* linkmgmt_renderPopUpPortSelector */
516
517/* -------------------------------------------------- */
518
519/*
520 * similar to renderPopupPortSelector but let you select the destination object
521 * and displays possible backend links with ports of the same name
522 */
523function linkmgmt_renderPopupPortSelectorbyName()
524{
525 $linktype = $_REQUEST['linktype'];
526 $object_id = $_REQUEST['object_id'];
527
528 $object = spotEntity ('object', $object_id);
529
530 if(isset($_REQUEST['remote_object']))
531 $remote_object = $_REQUEST['remote_object'];
532 else
533 $remote_object = NULL;
534
535 if($remote_object)
536 $link_list = linkmgmt_findSparePortsbyName($object_id, $remote_object, $linktype);
537
538 // display search form
539 echo 'Link '.$linktype.' of ' . formatPortLink($object_id, $object['name'], NULL, NULL) . ' Ports by Name to...';
540 echo '<form method=POST>';
541 startPortlet ('Object list');
542
543 $objectlist = getNarrowObjectList();
544
545 /* remove self from list */
546 unset($objectlist[$object_id]);
547
548 echo '<table align="center" valign="bottom"><tr>';
549 echo getSelect ($objectlist, array ('name' => 'remote_object', 'size' => getConfigVar ('MAXSELSIZE')), NULL, FALSE);
550 echo '<td valign="bottom"><input type=submit value="show '.$linktype.' ports"></td>';
551 echo '</tr></table>';
552 finishPortlet();
553
554 // display results
555 startPortlet ('Possible Backend Link List');
556 echo "Select links to create:<br>";
557 if (empty ($link_list))
558 echo '(nothing found)';
559 else
560 {
561 echo getSelect ($link_list, array ('name' => 'link_list[]', 'multiple' => 'multiple','size' => getConfigVar ('MAXSELSIZE')), NULL, FALSE);
562 echo "<p>$linktype Cable ID: <input type=text id=cable name=cable>";
563 echo "<p><input type='submit' value='Link $linktype' name='do_link'>";
564 }
565 finishPortlet();
566 echo '</form>';
567
568} /* linkmgmt_renderPopUpPortSelector */
569
570/* ------------------------------------------------ */
571
572function linkmgmt_tabhandler($object_id) {
573 global $lm_cache;
574
575 $target = makeHrefProcess(portlist::urlparams('op','update'));
576
577 addJS('js/jquery.jeditable.mini.js');
578
579 /* TODO if (permitted (NULL, 'ports', 'set_reserve_comment')) */
580 /* TODO Link / unlink permissions */
581
582 $lm_cache['allowcomment'] = permitted(NULL, NULL, 'set_reserve_comment'); /* RackCode {$op_set_reserve_comment} */
583 $lm_cache['allowlink'] = permitted(NULL, NULL, 'set_link'); /* RackCode {$op_set_link} */
584
585 //portlist::var_dump_html($lm_cache);
586
587 /* init jeditable fields/tags */
588 if($lm_cache['allowcomment'])
589 addJS('$(document).ready(function() { $(".editcmt").editable("'.$target.'",{placeholder : "add comment"}); });' , TRUE);
590
591 if($lm_cache['allowlink'])
592 addJS('$(document).ready(function() { $(".editcable").editable("'.$target.'",{placeholder : "edit cableID"}); });' , TRUE);
593
594
595 /* linkmgmt for current object */
596 linkmgmt_renderObjectLinks($object_id);
597
598 /* linkmgmt for every child */
599 //$parents = getEntityRelatives ('parents', 'object', $object_id);
600 $children = getEntityRelatives ('children', 'object', $object_id); //'entity_id'
601
602 //portlist::var_dump_html($children);
603
604 foreach($children as $child) {
605 echo '<h1>Links for Child: '.$child['name'].'</h1>';
606 linkmgmt_renderObjectLinks($child['entity_id']);
607 }
608
609// $plist->var_dump_html($plist->list);
610
611
612 return;
613
614} /* tabhandler */
615
616/* -------------------------------------------------- */
617function linkmgmt_renderObjectLinks($object_id) {
618
619 $object = spotEntity ('object', $object_id);
620 $object['attr'] = getAttrValues($object_id);
621
622 /* get ports */
623 /* calls getObjectPortsAndLinks */
624 amplifyCell ($object);
625
626 //$ports = getObjectPortsAndLinks($object_id);
627 $ports = $object['ports'];
628
629
630 /* URL param handling */
631 if(isset($_GET['allports'])) {
632 $allports = $_GET['allports'];
633 } else
634 $allports = FALSE;
635
636 if(isset($_GET['allback'])) {
637 $allback = $_GET['allback'];
638 } else
639 $allback = FALSE;
640
641 echo '<table><tr>';
642
643 if($allports) {
644
645 echo '<td width=200><a href="'.makeHref(portlist::urlparams('allports','0','0'))
646 .'">Hide Ports without link</a></td>';
647 } else
648 echo '<td width=200><a href="'.makeHref(portlist::urlparams('allports','1','0'))
649 .'">Show All Ports</a></td>';
650
651 echo '<td width=200><span onclick=window.open("'.makeHrefProcess(portlist::urlparamsarray(
652 array('op' => 'PortLinkDialog','linktype' => 'back','byname' => '1'))).'","name","height=800,width=400,scrollbars=yes");><a>Link Object Ports by Name</a></span></td>';
653
654 if($allback) {
655
656 echo '<td width=200><a href="'.makeHref(portlist::urlparams('allback','0','0'))
657 .'">Collapse Backend Links on same Object</a></td>';
658 } else
659 echo '<td width=200><a href="'.makeHref(portlist::urlparams('allback','1','0'))
660 .'">Expand Backend Links on same Object</a></td>';
661
662 /* Help */
663 echo '<td width=200><span onclick=window.open("'.makeHrefProcess(portlist::urlparamsarray(
664 array('op' => 'Help'))).'","name","height=400,width=500");><a>Help</a></span></td>';
665
666 if(isset($_REQUEST['hl_port_id']))
667 $hl_port_id = $_REQUEST['hl_port_id'];
668 else
669 $hl_port_id = NULL;
670
671 echo '</tr></table>';
672
673 echo '<br><br><table>';
674
675 /* switch display order depending on backend links */
676 $first = portlist::hasbackend($object_id);
677
678 foreach($ports as $port) {
679
680 $plist = new portlist($port, $object_id, $allports, $allback);
681
682 $plist->printportlistrow($first, $hl_port_id);
683
684 }
685
686 echo "</table>";
687
688} /* renderObjectLinks */
689
690/* --------------------------------------------------- */
691/* -------------------------------------------------- */
692
693/*
694 * Portlist class
695 * gets all linked ports to spezified port
696 * and prints this list as table row
697 *
698 */
699class portlist {
700
701 public $list = array();
702
703 private $object_id;
704 private $port_id;
705 private $port;
706
707 private $first_id;
708 private $front_count;
709
710 private $last_id;
711 private $back_count;
712
713 private $count = 0;
714
715 private $allback = FALSE;
716
717 const B2B_LINK_BGCOLOR = '#d8d8d8';
718 const CURRENT_PORT_BGCOLOR = '#ffff99';
719 const CURRENT_OBJECT_BGCOLOR = '#ff0000';
720 const HL_PORT_BGCOLOR = '#00ff00';
721
722 /* Possible LOOP detected after count links print only */
723 const MAX_LOOP_COUNT = 13;
724
725 private $loopcount;
726
727 function __construct($port, $object_id, $allports = FALSE, $allback = FALSE) {
728
729
730 $this->object_id = $object_id;
731
732 $this->port = $port;
733
734 $port_id = $port['id'];
735
736 $this->port_id = $port_id;
737
738 $this->first_id = $port_id;
739 $this->last_id = $port_id;
740
741 $this->allback = $allback;
742
743 /* Front Port */
744 $this->count = 0;
745 $this->_getportlist($this->_getportdata($port_id),FALSE);
746 $this->front_count = $this->count;
747
748 /* Back Port */
749 $this->count = 0;
750 $this->_getportlist($this->_getportdata($port_id), TRUE, FALSE);
751 $this->back_count = $this->count;
752
753 $this->count = $this->front_count + $this->back_count;
754
755
756 if(!$allports)
757 if($this->count == 0 || ( ($this->count == 1) && (!empty($this->list[$port_id]['back'])) ) ) {
758 $this->list = array();
759 $this->first_id = NULL;
760 }
761
762 //$this->var_dump_html($this->list);
763
764 } /* __construct */
765
766
767 /*
768 * gets front and back port of src_port
769 * and adds it to the list
770 */
771 /* !!! recursive */
772 function _getportlist(&$src_port, $back = FALSE, $first = TRUE) {
773
774 $id = $src_port['id'];
775
776 if($back)
777 $linktype = 'back';
778 else
779 $linktype = 'front';
780
781 if(!empty($src_port[$linktype])) {
782
783 $dst_port_id = $src_port[$linktype]['id'];
784
785 if(!$this->_loopdetect($src_port,$dst_port_id,$linktype)) {
786 //error_log("no loop $linktype>".$dst_port_id);
787 $this->count++;
788 $this->_getportlist($this->_getportdata($dst_port_id), !$back, $first);
789 }
790 } else {
791 if($first) {
792 $this->first_id = $id;
793 // $this->front_count = $this->count; /* doesn't work on loops */
794 } else {
795 $this->last_id = $id;
796 // $this->back_count = $this->count; /* doesn't work on loops */
797 }
798
799 }
800
801 } /* _getportlist */
802
803 /*
804 * as name suggested
805 */
806 function _loopdetect(&$src_port, $dst_port_id, $linktype) {
807
808 /* */
809 if(array_key_exists($dst_port_id, $this->list)) {
810
811 $dst_port = $this->list[$dst_port_id];
812
813 $src_port[$linktype]['loop'] = $dst_port_id;
814
815 // echo "LOOP :".$src_port['id']."-->".$dst_port_id;
816
817 return TRUE;
818
819 } else {
820 //error_log(__FUNCTION__."$dst_port_id not exists");
821 return FALSE;
822 }
823
824 } /* _loopdetect */
825
826 /*
827 * get all data for one port
828 * name, object, front link, back link
829 */
830 function &_getportdata($port_id) {
831 /* sql bitwise xor: porta ^ portb */
832 //select cable, ((porta ^ portb) ^ 4556) as port from Link where (4556 in (porta, portb));
833
834 //error_log("_getportdata $port_id");
835
836 /* TODO single sql ? */
837
838 $result = usePreparedSelectBlade
839 (
840 'SELECT Port.id, Port.name, Port.label, Port.type, Port.l2address, Port.object_id, Port.reservation_comment,
841 RackObject.name as "obj_name"
842 from Port
843 join RackObject on RackObject.id = Port.object_id
844 where Port.id = ?',
845 array($port_id)
846 );
847 $datarow = $result->fetchAll(PDO::FETCH_ASSOC);
848
849 $result = usePreparedSelectBlade
850 (
851 'SELECT Port.id, Link.cable, Port.name,
852 CONCAT(Link.porta,"_",Link.portb) as link_id from Link
853 join Port
854 where (? in (Link.porta,Link.portb)) and ((Link.porta ^ Link.portb) ^ ? ) = Port.id',
855 array($port_id, $port_id)
856 );
857 $frontrow = $result->fetchAll(PDO::FETCH_ASSOC);
858
859 $result = usePreparedSelectBlade
860 (
861 'SELECT Port.id, LinkBackend.cable, Port.name,
862 CONCAT(LinkBackend.porta,"_",LinkBackend.portb,"_back") as link_id from LinkBackend
863 join Port
864 where (? in (LinkBackend.porta,LinkBackend.portb)) and ((LinkBackend.porta ^ LinkBackend.portb) ^ ? ) = Port.id',
865 array($port_id, $port_id)
866 );
867 $backrow = $result->fetchAll(PDO::FETCH_ASSOC);
868
869 $retval = $datarow[0];
870
871 if(!empty($frontrow))
872 $retval['front']= $frontrow[0];
873 else
874 $retval['front'] = array();
875
876 if(!empty($backrow))
877 $retval['back'] = $backrow[0];
878 else
879 $retval['back'] = array();
880
881 // $this->var_dump_html($retval);
882
883 /* return reference */
884 return ($this->list[$port_id] = &$retval);
885
886 } /* _getportdata */
887
888 /*
889 */
890 function printport(&$port) {
891 /* set bgcolor for current port */
892 if($port['id'] == $this->port_id) {
893 $bgcolor = 'bgcolor='.self::CURRENT_PORT_BGCOLOR;
894 $idtag = ' id='.$port['id'];
895 } else {
896 $bgcolor = '';
897 $idtag = '';
898 }
899
900 $mac = trim(preg_replace('/(..)/','$1:',$port['l2address']),':');
901
902 $title = "Label: ${port['label']}\nMAC: $mac\nPortID: ${port['id']}";
903
904 echo '<td'.$idtag.' align=center '.$bgcolor.' title="'.$title.'"><pre>[<a href="'
905 .makeHref(array('page'=>'object', 'tab' => 'linkmgmt', 'object_id' => $port['object_id'], 'hl_port_id' => $port['id']))
906 .'#'.$port['id']
907 .'">'.$port['name'].'</a>]</pre></td>';
908
909 } /* printport */
910
911 /*
912 */
913 function printcomment(&$port) {
914
915 if(!empty($port['reservation_comment'])) {
916 $prefix = '<b>Reserved: </b>';
917 } else
918 $prefix = '';
919
920 echo '<td>'.$prefix.'<i><a class="editcmt" id='.$port['id'].'>'.$port['reservation_comment'].'</a></i></td>';
921
922 } /* printComment */
923
924
925 /*
926 */
927 function printobject($object_id, $object_name) {
928 if($object_id == $this->object_id) {
929 $color='color: '.self::CURRENT_OBJECT_BGCOLOR;
930 } else {
931 $color='';
932 }
933
934 echo '<td><table align=center cellpadding=5 cellspacing=0 border=1><tr><td align=center><a style="font-weight:bold;'
935 .$color.'" href="'.makeHref(array('page'=>'object', 'tab' => 'linkmgmt', 'object_id' => $object_id))
936 .'"><pre>'.$object_name.'</pre></a><pre>'.$this->_getRackInfo($object_id, 'font-size:80%')
937 .'</pre></td></tr></table></td>';
938
939 } /* printobject */
940
941 /*
942 */
943 function printlink(&$link, $linktype) {
944
945 if($linktype == 'back')
946 $arrow = '====>';
947 else
948 $arrow = '---->';
949
950 /* link */
951 echo '<td align=center>';
952
953 echo '<pre><a class="editcable" id='.$link['link_id'].'>'.$link['cable']
954 ."</a></pre><pre>$arrow</pre>"
955 .$this->_printUnLinkPort($link['id'], $linktype);
956
957 echo '</td>';
958 } /* printlink */
959
960 /*
961 * print cableID dst_port:dst_object
962 */
963 function _printportlink($port_id, &$link, $back = FALSE) {
964
965 //$port_id = $link['id'];
966
967 $port = $this->list[$port_id];
968 $object_id = $port['object_id'];
969 $obj_name = $port['obj_name'];
970
971 $loop = FALSE;
972
973 if($back) {
974 $linktype = 'back';
975 } else {
976 $linktype = 'front';
977 }
978
979 $sameobject = FALSE;
980
981 if(isset($link['loop']))
982 $loop = TRUE;
983
984 if($link != NULL) {
985
986 $src_port_id = $port[$linktype]['id'];
987 $src_object_id = $this->list[$src_port_id]['object_id'];
988
989 if(!$this->allback && $object_id == $src_object_id && $back) {
990 $sameobject = TRUE;
991 } else {
992 $this->printlink($link, $linktype);
993 }
994
995 } else {
996 $this->_LinkPort($port_id, $linktype);
997
998 if(!$back)
999 $this->printcomment($port);
1000 }
1001
1002 if($back) {
1003 if(!$sameobject)
1004 $this->printobject($object_id,$obj_name);
1005 echo "<td>></td>";
1006
1007 /* align ports nicely */
1008 if($port['id'] == $this->port_id)
1009 echo '</td></tr></table></td><td><table align=left><tr>';
1010 }
1011
1012 /* print [portname] */
1013 $this->printport($port);
1014
1015 if($loop)
1016 echo '<td bgcolor=#ff9966>LOOP</td>';
1017
1018 if(!$back) {
1019
1020 /* align ports nicely */
1021 if($port['id'] == $this->port_id)
1022 echo '</td></tr></table></td><td><table align=left><tr>';
1023
1024 echo "<td><</td>";
1025 $this->printobject($object_id,$obj_name);
1026
1027 if(empty($port['back']))
1028 $this->_LinkPort($port_id, 'back');
1029 } else
1030 if( ($port['id'] != $this->port_id) && empty($port['front'])) {
1031 $this->printcomment($port);
1032 $this->_LinkPort($port_id, 'front');
1033 }
1034
1035 if($loop) {
1036 if(isset($link['loopmaxcount']))
1037 $reason = " (MAX LOOP COUNT reached)";
1038 else
1039 $reason = '';
1040
1041 showWarning("Possible Loop on Port ($linktype) ".$port['name'].$reason);
1042 return FALSE;
1043 }
1044
1045 return TRUE;
1046
1047 } /* _printport */
1048
1049 /*
1050 * print <tr>..</tr>
1051 */
1052 function printportlistrow($first = TRUE, $hl_port_id = NULL) {
1053
1054 $this->loopcount = 0;
1055
1056 if($this->first_id == NULL)
1057 return;
1058
1059 if($first)
1060 $id = $this->first_id;
1061 else
1062 $id = $this->last_id;
1063
1064
1065 if($hl_port_id == $this->port_id)
1066 $hlbgcolor = "bgcolor=".self::HL_PORT_BGCOLOR;
1067 else
1068 $hlbgcolor = "";
1069
1070 $link = NULL;
1071
1072 $port = $this->list[$id];
1073
1074 $title = "linkcount: ".$this->count." (".$this->front_count."/".$this->back_count.")";
1075
1076 /* Current Port */
1077 echo '<tr '.$hlbgcolor.'><td nowrap="nowrap" bgcolor='.self::CURRENT_PORT_BGCOLOR.' title="'.$title.'">'.$this->port['name'].': </td>';
1078
1079 echo "<td><table align=right><tr><td>";
1080
1081 $back = !empty($this->list[$id]['front']);
1082
1083 $this->_printportlink($id, $link, $back);
1084
1085 $this->_printportlist($id, !$back);
1086 echo "</td></tr></table></td></tr>";
1087
1088 /* horizontal line */
1089 echo '<tr><td height=1 colspan=3 bgcolor=#e0e0e0></td></tr>';
1090
1091 } /* printportlist */
1092
1093 /*
1094 * print <td>
1095 * prints all ports in a list starting with start_port_id
1096 */
1097 /* !!! recursive */
1098 function _printportlist($src_port_id, $back = FALSE) {
1099
1100 if($back)
1101 $linktype = 'back';
1102 else
1103 $linktype = 'front';
1104
1105 $link = &$this->list[$src_port_id][$linktype];
1106
1107 if(!empty($link)) {
1108 $dst_port_id = $link['id'];
1109
1110 $this->loopcount++;
1111
1112 if($this->loopcount > self::MAX_LOOP_COUNT) {
1113 // $src_port_name = $this->list[$src_port_id]['name'];
1114 // $dst_port_name = $this->list[$dst_port_id]['name'];
1115
1116 $link['loop'] = $dst_port_id;
1117 $link['loopmaxcount'] = $dst_port_id;
1118
1119 /* loop warning is handeld in _printportlink() */
1120 //showWarning("MAX LOOP COUNT reached $src_port_name -> $dst_port_name".self::MAX_LOOP_COUNT);
1121 //return; /* return after _printportlink */
1122 }
1123
1124 if(!$this->_printportlink($dst_port_id, $link, $back))
1125 return;
1126
1127 $this->_printportlist($dst_port_id,!$back);
1128 }
1129
1130
1131 } /* _printportlist */
1132
1133 /*
1134 * returns linked Row / Rack Info for object_id
1135 *
1136 */
1137 function _getRackInfo($object_id, $style = '') {
1138 global $lm_cache;
1139
1140 $rackinfocache = $lm_cache['rackinfo'];
1141
1142 /* if not in cache get it */
1143 if(!array_key_exists($object_id,$rackinfocache)) {
1144
1145 /* SQL from database.php SQLSchema 'object' */
1146 $result = usePreparedSelectBlade
1147 (
1148 'SELECT rack_id, Rack.name as Rack_name, row_id, RackRow.name as Row_name
1149 FROM RackSpace
1150 LEFT JOIN EntityLink on RackSpace.object_id = EntityLink.parent_entity_id
1151 JOIN Rack on Rack.id = RackSpace.rack_id
1152 JOIN RackRow on RackRow.id = Rack.row_id
1153 WHERE ( RackSpace.object_id = ? ) or (EntityLink.child_entity_id = ?)
1154 ORDER by rack_id asc limit 1',
1155 array($object_id, $object_id)
1156 );
1157 $row = $result->fetchAll(PDO::FETCH_ASSOC);
1158
1159 if(!empty($row)) {
1160
1161 $rackinfocache[$object_id] = $row[0];
1162 }
1163
1164 }
1165
1166 $obj = &$rackinfocache[$object_id];
1167
1168 if(empty($obj))
1169 return '<span style="'.$style.'">Unmounted</span>';
1170 else
1171 return '<a style="'.$style.'" href='.makeHref(array('page'=>'row', 'row_id'=>$obj['row_id'])).'>'.$obj['Row_name']
1172 .'</a>/<a style="'.$style.'" href='.makeHref(array('page'=>'rack', 'rack_id'=>$obj['rack_id'])).'>'
1173 .$obj['Rack_name'].'</a>';
1174
1175 } /* _getRackInfo */
1176
1177
1178 /*
1179 * return link symbol
1180 *
1181 */
1182 function _LinkPort($port_id, $linktype = 'front') {
1183 global $lm_cache;
1184
1185 if(!$lm_cache['allowlink'])
1186 return;
1187
1188 $helper_args = array
1189 (
1190 'port' => $port_id,
1191 );
1192
1193 echo "<td align=center>";
1194
1195 if($linktype == 'front') {
1196
1197 echo "<span";
1198 $popup_args = 'height=700, width=400, location=no, menubar=no, '.
1199 'resizable=yes, scrollbars=yes, status=no, titlebar=no, toolbar=no';
1200 echo " ondblclick='window.open(\"" . makeHrefForHelper ('portlist', $helper_args);
1201 echo "\",\"findlink\",\"${popup_args}\");'";
1202 // end of onclick=
1203 echo " onclick='window.open(\"" . makeHrefForHelper ('portlist', $helper_args);
1204 echo "\",\"findlink\",\"${popup_args}\");'";
1205 // end of onclick=
1206 echo '>';
1207 printImageHREF ('plug', 'Link this port');
1208 echo "</span>";
1209
1210 } else {
1211 /* backend link */
1212
1213 echo '<span onclick=window.open("'.makeHrefProcess(portlist::urlparamsarray(
1214 array('op' => 'PortLinkDialog','port' => $port_id,'linktype' => $linktype))).'","name","height=800,width=400");'
1215 .'>';
1216 printImageHREF ('plug', $linktype.' Link this port');
1217 echo "</span>";
1218
1219 }
1220
1221 echo "</td>";
1222
1223 } /* _LinkPort */
1224
1225 /*
1226 * return link cut symbol
1227 *
1228 * TODO $opspec_list
1229 */
1230 function _printUnLinkPort($port_id, $linktype) {
1231 global $lm_cache;
1232
1233 if(!$lm_cache['allowlink'])
1234 return '';
1235
1236 $src_port = $this->list[$port_id];
1237
1238 $link = $src_port[$linktype];
1239
1240 $dst_port = $this->list[$link['id']];
1241
1242 /* use RT unlink for front link, linkmgmt unlink for back links */
1243 if($linktype == 'back')
1244 $tab = 'linkmgmt';
1245 else
1246 $tab = 'ports';
1247
1248
1249 return '<a href='.
1250 makeHrefProcess(array(
1251 'op'=>'unlinkPort',
1252 'port_id'=>$port_id,
1253 'object_id'=>$this->object_id,
1254 'tab' => $tab,
1255 'linktype' => $linktype)).
1256 ' onclick="return confirm(\'unlink ports '.$src_port['name']. ' -> '.$dst_port['name']
1257 .' ('.$linktype.') with cable ID: '.$src_port[$linktype]['cable'].'?\');">'.
1258 getImageHREF ('cut', $linktype.' Unlink this port').'</a>';
1259
1260 } /* _printUnLinkPort */
1261
1262
1263 /*
1264 *
1265 */
1266 function urlparams($name, $value, $defaultvalue = NULL) {
1267
1268 $urlparams = $_GET;
1269
1270 if($value == $defaultvalue) {
1271
1272 /* remove param */
1273 unset($urlparams[$name]);
1274
1275 } else {
1276
1277 $urlparams[$name] = $value;
1278
1279 }
1280
1281 return $urlparams;
1282
1283 } /* urlparams */
1284
1285 /*
1286 * $params = array('name' => 'value', ...)
1287 */
1288 function urlparamsarray($params) {
1289
1290 $urlparams = $_GET;
1291
1292 foreach($params as $name => $value) {
1293
1294 if($value == NULL) {
1295
1296 /* remove param */
1297 unset($urlparams[$name]);
1298
1299 } else {
1300
1301 $urlparams[$name] = $value;
1302
1303 }
1304 }
1305
1306 return $urlparams;
1307
1308 } /* urlparamsarray */
1309
1310 /* */
1311 function hasbackend($object_id) {
1312 /* sql bitwise xor: porta ^ portb */
1313 //select cable, ((porta ^ portb) ^ 4556) as port from Link where (4556 in (porta, portb));
1314
1315 $result = usePreparedSelectBlade
1316 (
1317 'SELECT count(*) from Port
1318 join LinkBackend on (porta = id or portb = id )
1319 where object_id = ?',
1320 array($object_id)
1321 );
1322 $retval = $result->fetchColumn();
1323
1324 return $retval != 0;
1325
1326 } /* hasbackend */
1327
1328 /* for debugging only */
1329 function var_dump_html(&$var) {
1330 echo "<pre>------------------Start Var Dump -------------------------\n";
1331 var_dump($var);
1332 echo "\n---------------------END Var Dump ------------------------</pre>";
1333 }
1334
1335} /* portlist */
1336
1337/* -------------------------------------------------- */
1338
1339?>