3 # This file is a part of RackTables, a datacenter and server room management
4 # framework. See accompanying file "COPYING" for the full copyright and
5 # licensing information.
9 * This file contains frontend functions for RackTables.
13 require_once 'ajax-interface.php';
14 require_once 'slb-interface.php';
16 // Interface function's special.
17 $nextorder['odd'] = 'even';
18 $nextorder['even'] = 'odd';
20 // address allocation type
23 'regular' => 'Connected',
24 'virtual' => 'Loopback',
28 // address allocation code, IPv4 addresses and objects view
32 'virtual' => '<span class="aac">L</span>',
33 'shared' => '<span class="aac">S</span>',
34 'router' => '<span class="aac">R</span>',
36 // address allocation code, IPv4 networks view
40 'virtual' => '<strong>L:</strong>',
41 'shared' => '<strong>S:</strong>',
42 'router' => '<strong>R:</strong>',
55 'compulsory' => 'permanent',
56 # 'alien' => 'never touch',
59 // This may be populated later onsite, report rendering function will use it.
60 // See the $systemreport for structure.
61 $localreports = array();
67 'html' => 'htmlmixed',
74 'uint' => '[U] unsigned integer',
75 'float' => '[F] floating point',
76 'string' => '[S] string',
77 'dict' => '[D] dictionary record',
81 $quick_links = NULL; // you can override this in your local.php, but first initialize it with getConfiguredQuickLinks()
83 function renderQuickLinks()
86 if (! isset ($quick_links))
87 $quick_links = getConfiguredQuickLinks();
88 echo '<ul class="qlinks">';
89 foreach ($quick_links as $link)
90 echo '<li><a href="' . $link['href'] . '">' . str_replace (' ', ' ', $link['title']) . '</a></li>';
94 function renderInterfaceHTML ($pageno, $tabno, $payload)
96 ?
><!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
97 <html xmlns
="http://www.w3.org/1999/xhtml" xml
:lang
="en" lang
="en">
98 <head
><title
><?php
echo getTitle ($pageno); ?
></title
>
99 <?php
printPageHeaders(); ?
>
102 <div
class="maintable">
103 <div
class="mainheader">
104 <div style
="float: right" class=greeting
><a href
='index.php?page=myaccount&tab=default'><?php
global $remote_displayname; echo $remote_displayname ?
></a
> [ <a href
='?logout'>logout
</a
> ]</div
>
105 <?php
echo getConfigVar ('enterprise') ?
> RackTables
<a href
="http://racktables.org" title
="Visit RackTables site"><?php
echo CODE_VERSION ?
></a
><?php
renderQuickLinks() ?
>
107 <div
class="menubar"><?php
showPathAndSearch ($pageno, $tabno); ?
></div
>
108 <div
class="tabbar"><?php
showTabs ($pageno, $tabno); ?
></div
>
109 <div
class="msgbar"><?php
showMessageOrError(); ?
></div
>
110 <div
class="pagebar"><?php
echo $payload; ?
></div
>
118 function renderIndexItem ($ypageno)
120 echo (! permitted ($ypageno)) ?
" <td> </td>\n" :
122 " <h1><a href='" . makeHref (array ('page' => $ypageno)) . "'>" .
123 getPageName ($ypageno) . "<br>\n" . getImageHREF ($ypageno) .
128 function renderIndex ()
132 <table border
=0 cellpadding
=0 cellspacing
=0 width
='100%'>
135 <div style
='text-align: center; margin: 10px; '>
136 <table width
='100%' cellspacing
=0 cellpadding
=20 class=mainmenu border
=0>
138 foreach ($indexlayout as $row)
141 foreach ($row as $column)
142 if ($column === NULL)
143 echo '<td> </td>';
145 renderIndexItem ($column);
157 function getRenderedAlloc ($object_id, $alloc)
162 'td_name_suffix' => '',
165 'td_routed_by' => '',
168 $dottedquad = $alloc['addrinfo']['ip'];
169 $ip_bin = $alloc['addrinfo']['ip_bin'];
172 if (isset ($_REQUEST['hl_ip']))
174 $hl_ip_bin = ip_parse ($_REQUEST['hl_ip']);
175 addAutoScrollScript ("ip-" . $_REQUEST['hl_ip']);
178 $ret['tr_class'] = $alloc['addrinfo']['class'];
179 if ($hl_ip_bin === $ip_bin)
180 $ret['tr_class'] .= ' highlight';
182 // render IP change history
185 if (isset ($alloc['addrinfo']['last_log']))
187 $log = $alloc['addrinfo']['last_log'];
188 $ip_title = "title='" .
191 $log['user'] . ', ' . formatAge ($log['time']),
194 $ip_class = 'hover-history underline';
197 // render IP address td
199 $netinfo = spotNetworkByIP ($ip_bin);
200 $ret['td_ip'] = "<td class='tdleft'>";
201 if (isset ($netinfo))
203 $title = $dottedquad;
204 if (getConfigVar ('EXT_IPV4_VIEW') != 'yes')
205 $title .= '/' . $netinfo['mask'];
206 $ret['td_ip'] .= "<a name='ip-$dottedquad' class='$ip_class' $ip_title href='" .
210 'page' => 'ipaddress',
211 'hl_object_id' => $object_id,
217 $ret['td_ip'] .= "<span class='$ip_class' $ip_title>$dottedquad</span>";
218 $ret['td_ip'] .= $aac[$alloc['type']];
219 if (strlen ($alloc['addrinfo']['name']))
220 $ret['td_ip'] .= ' (' . niftyString ($alloc['addrinfo']['name']) . ')';
221 $ret['td_ip'] .= '</td>';
223 // render network and routed_by tds
224 $td_class = 'tdleft';
225 if (! isset ($netinfo))
227 $ret['td_network'] = "<td class='$td_class sparenetwork'>N/A</td>";
228 $ret['td_routed_by'] = $ret['td_network'];
232 $ret['td_network'] = "<td class='$td_class'>" .
233 getOutputOf ('renderCell', $netinfo) . '</td>';
235 // render "routed by" td
236 if ($display_routers = (getConfigVar ('IPV4_TREE_RTR_AS_CELL') == 'none'))
237 $ret['td_routed_by'] = '';
240 loadIPAddrList ($netinfo);
241 $other_routers = array();
242 foreach (findRouters ($netinfo['own_addrlist']) as $router)
243 if ($router['id'] != $object_id)
244 $other_routers[] = $router;
245 if (count ($other_routers))
246 $ret['td_routed_by'] = getOutputOf ('printRoutersTD', $other_routers, $display_routers);
248 $ret['td_routed_by'] = "<td class='$td_class'> </td>";
253 $ret['td_peers'] = "<td class='$td_class'>";
255 if ($alloc['addrinfo']['reserved'] == 'yes')
257 $ret['td_peers'] .= $prefix . '<strong>RESERVED</strong>';
260 foreach ($alloc['addrinfo']['allocs'] as $allocpeer)
262 if ($allocpeer['object_id'] == $object_id)
264 $ret['td_peers'] .= $prefix . "<a href='" . makeHref (array ('page' => 'object', 'object_id' => $allocpeer['object_id'])) . "'>";
265 if (isset ($allocpeer['osif']) and strlen ($allocpeer['osif']))
266 $ret['td_peers'] .= $allocpeer['osif'] . '@';
267 $ret['td_peers'] .= $allocpeer['object_name'] . '</a>';
270 $ret['td_peers'] .= '</td>';
275 function renderLocationFilterPortlet ()
277 // Recursive function used to build the location tree
278 function renderLocationCheckbox ($subtree, $level = 0)
280 $self = __FUNCTION__
;
282 foreach ($subtree as $location_id => $location)
284 echo "<div class=tagbox style='text-align:left; padding-left:" . ($level * 16) . "px;'>";
285 $checked = (! isset ($_SESSION['locationFilter']) ||
in_array ($location['id'], $_SESSION['locationFilter'])) ?
'checked' : '';
286 echo "<label><input type=checkbox name='location_id[]' class=${level} value='${location['id']}'${checked} onClick=checkAll(this)>${location['name']}";
288 if ($location['kidc'])
290 echo "<a id='lfa" . $location['id'] . "' onclick=\"expand('${location['id']}')\" href\"#\" > - </a>";
291 echo "<div id='lfd" . $location['id'] . "'>";
292 $self ($location['kids'], $level +
1);
300 function checkAll(bx) {
301 for (var tbls=document.getElementsByTagName("table"), i=tbls.length; i--;)
302 if (tbls[i].id == "locationFilter") {
303 var bxs=tbls[i].getElementsByTagName("input");
305 for (var j=0; j<bxs.length; j++) {
306 if(in_tree == false && bxs[j].value == bx.value)
308 else if(parseInt(bxs[j].className) <= parseInt(bx.className))
310 if (bxs[j].type=="checkbox" && in_tree == true)
311 bxs[j].checked = bx.checked;
316 function collapseAll(bx) {
317 for (var tbls=document.getElementsByTagName("table"), i=tbls.length; i--;)
318 if (tbls[i].id == "locationFilter") {
319 var bxs=tbls[i].getElementsByTagName("div");
320 //loop through divs to hide unchecked
321 for (var j=0; j<bxs.length; j++) {
323 var in_div=bxs[j].getElementsByTagName("input");
324 //loop through input to find if any is checked
325 for (var k=0; k<in_div.length; k++) {
326 if(in_div[k].type="checkbox") {
327 if (in_div[k].checked == true) {
335 // nothing selected and element id is lfd, collapse it
336 if (is_checked == false && !bxs[j].id.indexOf("lfd"))
337 expand(bxs[j].id.substr(3));
342 function expand(id) {
343 var divid = document.getElementById("lfd" + id);
344 var iconid = document.getElementById("lfa" + id);
345 if (divid.style.display == 'none') {
346 divid.style.display = 'block';
347 iconid.innerHTML = ' - ';
349 divid.style.display = 'none';
350 iconid.innerHTML = ' + ';
355 startPortlet ('Location filter');
357 <table border=0 align=center cellspacing=0 class="tagtree" id="locationFilter">
359 <input type=hidden name=page value=rackspace>
360 <input type=hidden name=tab value=default>
361 <input type=hidden name=changeLocationFilter value=true>
364 $locationlist = listCells ('location');
365 if (count ($locationlist))
367 echo "<tr><td class=tagbox style='padding-left: 0px'><label>";
368 echo "<input type=checkbox name='location' onClick=checkAll(this)> Toggle all";
369 echo "<img src=?module=chrome&uri=pix/1x1t.gif onLoad=collapseAll(this)>"; // dirty hack to collapse all when page is displayed
370 echo "</label></td></tr>\n";
371 echo "<tr><td class=tagbox><hr>\n";
372 renderLocationCheckbox (treeFromList ($locationlist));
373 echo "<hr></td></tr>\n";
375 printImageHREF ('setfilter', 'set filter', TRUE);
380 echo "<tr><td class='tagbox sparenetwork'>(no locations exist)</td></tr>\n";
382 printImageHREF ('setfilter gray');
386 echo "</form></table>\n";
390 function renderRackspace ()
392 // Handle the location filter
394 if (isset ($_REQUEST['changeLocationFilter']))
395 unset ($_SESSION['locationFilter']);
396 if (isset ($_REQUEST['location_id']))
397 $_SESSION['locationFilter'] = $_REQUEST['location_id'];
400 echo "<table class=objview border=0 width='100%'><tr><td class=pcleft>";
402 $found_racks = array();
403 $cellfilter = getCellFilter();
404 if (! ($cellfilter['is_empty'] && !isset ($_SESSION['locationFilter']) && renderEmptyResults ($cellfilter, 'racks', getEntitiesCount ('rack'))))
408 foreach (getAllRows() as $row_id => $rowInfo)
410 $rackList = applyCellFilter ('rack', $cellfilter, $row_id);
411 $found_racks = array_merge ($found_racks, $rackList);
413 'location_id' => $rowInfo['location_id'],
414 'location_name' => $rowInfo['location_name'],
416 'row_name' => $rowInfo['name'],
419 $rackCount +
= count($rackList);
422 if (! renderEmptyResults($cellfilter, 'racks', $rackCount))
424 // generate thumb gallery
426 $rackwidth = getRackImageWidth();
427 // Zero value effectively disables the limit.
428 $maxPerRow = getConfigVar ('RACKS_PER_ROW');
431 echo "<h2>No rows found</h2>\n";
434 echo '<table border=0 cellpadding=10 class=cooltable>';
435 echo '<tr><th class=tdleft>Location</th><th class=tdleft>Row</th><th class=tdleft>Racks</th></tr>';
436 foreach ($rows as $row)
438 $location_id = $row['location_id'];
439 $row_id = $row['row_id'];
440 $row_name = $row['row_name'];
441 $rackList = $row['racks'];
444 $location_id != '' and isset ($_SESSION['locationFilter']) and !in_array ($location_id, $_SESSION['locationFilter']) or
445 empty ($rackList) and ! $cellfilter['is_empty']
449 echo "<tr class=row_${order}><th class=tdleft>";
454 if ($locationIdx == 20)
456 showWarning ("Warning: There is likely a circular reference in the location tree. Investigate location ${location_id}.");
459 $parentLocation = spotEntity ('location', $location_id);
460 $locationTree = "» <a href='" .
461 makeHref(array('page'=>'location', 'location_id'=>$parentLocation['id'])) .
462 "${cellfilter['urlextra']}'>${parentLocation['name']}</a> " .
464 $location_id = $parentLocation['parent_id'];
467 $locationTree = substr ($locationTree, 8);
469 echo "</th><th class=tdleft><a href='".makeHref(array('page'=>'row', 'row_id'=>$row_id))."${cellfilter['urlextra']}'>${row_name}</a></th>";
470 echo "<th class=tdleft><table border=0 cellspacing=5><tr>";
471 if (! count ($rackList))
472 echo '<td>(empty row)</td>';
474 foreach ($rackList as $rack)
476 if ($rackListIdx > 0 and $maxPerRow > 0 and $rackListIdx %
$maxPerRow == 0)
478 echo '</tr></table></th></tr>';
479 echo "<tr class=row_${order}><th class=tdleft></th><th class=tdleft>${row_name} (continued)";
480 echo "</th><th class=tdleft><table border=0 cellspacing=5><tr>";
482 echo "<td align=center valign=bottom><a href='".makeHref(array('page'=>'rack', 'rack_id'=>$rack['id']))."'>";
483 echo "<img border=0 width=${rackwidth} height=";
484 echo getRackImageHeight ($rack['height']);
485 echo " title='${rack['height']} units'";
486 echo "src='?module=image&img=minirack&rack_id=${rack['id']}'>";
487 echo "<br>${rack['name']}</a></td>";
490 $order = $nextorder[$order];
491 echo "</tr></table></th></tr>\n";
497 echo '</td><td class=pcright width="25%">';
498 renderCellFilterPortlet ($cellfilter, 'rack', $found_racks);
500 renderLocationFilterPortlet ();
501 echo "</td></tr></table>\n";
504 function renderLocationRowForEditor ($subtree, $level = 0)
506 $self = __FUNCTION__
;
507 foreach ($subtree as $locationinfo)
509 echo "<tr><td align=left style='padding-left: " . ($locationinfo['kidc'] ?
$level : ($level +
1) * 16) . "px;'>";
510 if ($locationinfo['kidc'])
511 printImageHREF ('node-expanded-static');
512 if ($locationinfo['refcnt'] > 0 ||
$locationinfo['kidc'] > 0)
513 printImageHREF ('nodestroy');
515 echo getOpLink (array ('op' => 'deleteLocation', 'location_id' => $locationinfo['id']), '', 'destroy', 'Delete location');
516 echo '</td><td class=tdleft>';
517 printOpFormIntro ('updateLocation', array ('location_id' => $locationinfo['id']));
518 $parent = isset ($locationinfo['parent_id']) ?
$locationinfo['parent_id'] : 0;
521 array ( $parent => $parent ?
htmlspecialchars ($locationinfo['parent_name']) : '-- NONE --'),
522 array ('name' => 'parent_id', 'id' => 'locationid_' . $locationinfo['id'], 'class' => 'locationlist-popup'),
526 echo "</td><td class=tdleft>";
527 echo "<input type=text size=48 name=name value='${locationinfo['name']}'>";
528 echo '</td><td>' . getImageHREF ('save', 'Save changes', TRUE) . "</form></td></tr>\n";
529 if ($locationinfo['kidc'])
530 $self ($locationinfo['kids'], $level +
1);
534 function renderLocationSelectTree ($selected_id = NULL)
536 echo '<option value=0>-- NONE --</option>';
537 $locationlist = listCells ('location');
538 foreach (treeFromList ($locationlist) as $location)
540 echo "<option value=${location['id']} style='font-weight: bold' ";
541 if ($location['id'] == $selected_id )
543 echo ">${location['name']}</option>";
544 printLocationChildrenSelectOptions ($location, 0, $selected_id);
549 function renderRackspaceLocationEditor ()
552 function locationeditor_showselectbox(e) {
553 $(this).load('index.php', {module: 'ajax', ac: 'get-location-select', locationid: this.id});
554 $(this).unbind('mousedown', locationeditor_showselectbox);
556 $(document).ready(function () {
557 $('select.locationlist-popup').bind('mousedown', locationeditor_showselectbox);
562 function printNewItemTR ()
564 printOpFormIntro ('addLocation');
566 printImageHREF ('create', 'Add new location', TRUE);
567 echo '</td><td><select name=parent_id tabindex=100>';
568 renderLocationSelectTree ();
569 echo '</td><td><input type=text size=48 name=name tabindex=101></td><td>';
570 printImageHREF ('create', 'Add new location', TRUE, 102);
571 echo "</td></tr></form>\n";
574 startPortlet ('Locations');
575 echo "<table border=0 cellspacing=0 cellpadding=5 align=center class=widetable>\n";
576 echo "<tr><th> </th><th>Parent</th><th>Name</th><th> </th></tr>\n";
577 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
580 $locations = listCells ('location');
581 renderLocationRowForEditor (treeFromList ($locations));
583 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
585 echo "</table><br>\n";
589 function renderRackspaceRowEditor ()
591 function printNewItemTR ()
593 printOpFormIntro ('addRow');
595 printImageHREF ('create', 'Add new row', TRUE);
596 echo '</td><td><select name=location_id tabindex=100>';
597 renderLocationSelectTree ();
598 echo '</td><td><input type=text name=name tabindex=100></td><td>';
599 printImageHREF ('create', 'Add new row', TRUE, 102);
600 echo '</td></tr></form>';
602 startPortlet ('Rows');
603 echo "<table border=0 cellspacing=0 cellpadding=5 align=center class=widetable>\n";
604 echo "<tr><th> </th><th>Location</th><th>Name</th><th> </th></tr>\n";
605 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
607 foreach (getAllRows() as $row_id => $rowInfo)
610 if ($rc = $rowInfo['rackc'])
611 printImageHREF ('nodestroy', "${rc} rack(s) here");
613 echo getOpLink (array('op'=>'deleteRow', 'row_id'=>$row_id), '', 'destroy', 'Delete row');
614 printOpFormIntro ('updateRow', array ('row_id' => $row_id));
616 echo '<select name=location_id tabindex=100>';
617 renderLocationSelectTree ($rowInfo['location_id']);
618 echo "</td><td><input type=text name=name value='${rowInfo['name']}' tabindex=100></td><td>";
619 printImageHREF ('save', 'Save changes', TRUE);
620 echo "</form></td></tr>\n";
622 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
624 echo "</table><br>\n";
628 function renderRow ($row_id)
630 $rowInfo = getRowInfo ($row_id);
631 $cellfilter = getCellFilter();
632 $rackList = applyCellFilter ('rack', $cellfilter, $row_id);
635 $summary['Name'] = $rowInfo['name'];
636 if ($rowInfo['location_id'])
637 $summary['Location'] = mkA ($rowInfo['location'], 'location', $rowInfo['location_id']);
638 $summary['Racks'] = $rowInfo['count'];
639 $summary['Units'] = $rowInfo['sum'];
640 $summary['% used'] = getProgressBar (getRSUforRow ($rackList));
641 foreach (getAttrValues ($row_id) as $record)
644 $record['value'] != '' and
645 permitted (NULL, NULL, NULL, array (array ('tag' => '$attr_' . $record['id'])))
647 $summary['{sticker}' . $record['name']] = formatAttributeValue ($record);
649 // Main layout starts.
650 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
652 // Left portlet with row information.
653 echo "<tr><td class=pcleft>";
654 renderEntitySummary ($rowInfo, 'Summary', $summary);
655 renderCellFilterPortlet ($cellfilter, 'rack', $rackList, array ('row_id' => $row_id));
656 renderFilesPortlet ('row',$row_id);
657 echo "</td><td class=pcright>";
660 $rackwidth = getRackImageWidth() * getConfigVar ('ROW_SCALE');
661 // Maximum number of racks per row is proportionally less, but at least 1.
662 $maxPerRow = max (floor (getConfigVar ('RACKS_PER_ROW') / getConfigVar ('ROW_SCALE')), 1);
665 startPortlet ('Racks');
666 echo "<table border=0 cellspacing=5 align='center'><tr>";
667 foreach ($rackList as $rack)
669 if ($rackListIdx %
$maxPerRow == 0)
671 if ($rackListIdx > 0)
675 $class = ($rack['has_problems'] == 'yes') ?
'error' : $order;
676 echo "<td align=center valign=bottom class=row_${class}><a href='".makeHref(array('page'=>'rack', 'rack_id'=>$rack['id']))."'>";
677 echo "<img border=0 width=${rackwidth} height=" . (getRackImageHeight ($rack['height']) * getConfigVar ('ROW_SCALE'));
678 echo " title='${rack['height']} units'";
679 echo "src='?module=image&img=midirack&rack_id=${rack['id']}&scale=" . getConfigVar ('ROW_SCALE') . "'>";
680 echo "<br>${rack['name']}</a></td>";
681 $order = $nextorder[$order];
684 echo "</tr></table>\n";
686 echo "</td></tr></table>";
689 function renderEditRowForm ($row_id)
691 $row = getRowInfo ($row_id);
693 startPortlet ('Attributes');
694 printOpFormIntro ('updateRow');
695 echo '<table border=0 align=center>';
696 echo '<tr><td> </td><th class=tdright>Location:</th><td class=tdleft>';
697 $locations = array ();
698 $locations[0] = '-- NOT SET --';
699 foreach (listCells ('location') as $id => $locationInfo)
700 $locations[$id] = $locationInfo['name'];
701 natcasesort ($locations);
702 printSelect ($locations, array ('name' => 'location_id'), $row['location_id']);
704 echo "<tr><td> </td><th class=tdright>Name (required):</th><td class=tdleft><input type=text name=name value='${row['name']}'></td></tr>\n";
706 // optional attributes
707 $values = getAttrValues ($row_id);
708 $num_attrs = count ($values);
709 echo "<input type=hidden name=num_attrs value=${num_attrs}>\n";
711 foreach ($values as $record)
713 echo "<input type=hidden name=${i}_attr_id value=${record['id']}>";
715 if (strlen ($record['value']))
716 echo getOpLink (array('op'=>'clearSticker', 'attr_id'=>$record['id']), '', 'clear', 'Clear value', 'need-confirmation');
720 echo "<th class=sticker>${record['name']}:</th><td class=tdleft>";
721 switch ($record['type'])
726 echo "<input type=text name=${i}_value value='${record['value']}'>";
729 $chapter = readChapter ($record['chapter_id'], 'o');
730 $chapter[0] = '-- NOT SET --';
731 $chapter = cookOptgroups ($chapter, 1562, $record['key']);
732 printNiftySelect ($chapter, array ('name' => "${i}_value"), $record['key']);
738 if ($row['count'] == 0)
740 echo '<tr><td> </td><th class=tdright>Actions:</th><td class=tdleft>';
741 echo getOpLink (array ('op'=>'deleteRow'), '', 'destroy', 'Delete row', 'need-confirmation');
742 echo " </td></tr>\n";
744 echo "<tr><td class=submit colspan=3>";
745 printImageHREF ('SAVE', 'Save changes', TRUE);
747 echo '</form></table><br>';
750 startPortlet ('History');
751 renderObjectHistory ($row_id);
755 // Used by renderRack()
756 function printObjectDetailsForRenderRack ($object_id, $hl_obj_id = 0)
758 $objectData = spotEntity ('object', $object_id);
759 if (strlen ($objectData['asset_no']))
760 $prefix = "<div title='${objectData['asset_no']}";
762 $prefix = "<div title='no asset tag";
763 // Don't tell about label, if it matches common name.
765 if ($objectData['name'] != $objectData['label'] and strlen ($objectData['label']))
766 $body = ", visible label is \"${objectData['label']}\"";
767 // Display list of child objects, if any
768 $objectChildren = getEntityRelatives ('children', 'object', $objectData['id']);
769 $slotRows = $slotCols = $slotInfo = $slotData = $slotTitle = $slotClass = array ();
770 if (count($objectChildren) > 0)
772 foreach ($objectChildren as $child)
774 $childNames[] = $child['name'];
775 $childData = spotEntity ('object', $child['entity_id']);
776 $attrData = getAttrValues ($child['entity_id']);
777 $numRows = $numCols = 1;
778 if (isset ($attrData[2])) // HW type
780 extractLayout ($attrData[2]);
781 if (isset ($attrData[2]['rows']))
783 $numRows = $attrData[2]['rows'];
784 $numCols = $attrData[2]['cols'];
787 if (isset ($attrData['28'])) // slot number
789 $slot = $attrData['28']['value'];
790 if (preg_match ('/\d+/', $slot, $matches))
792 $slotRows[$slot] = $numRows;
793 $slotCols[$slot] = $numCols;
794 $slotInfo[$slot] = $child['name'];
795 $slotData[$slot] = $child['entity_id'];
796 if (strlen ($childData['asset_no']))
797 $slotTitle[$slot] = "<div title='${childData['asset_no']}";
799 $slotTitle[$slot] = "<div title='no asset tag";
800 if (strlen ($childData['label']) and $childData['label'] != $child['name'])
801 $slotTitle[$slot] .= ", visible label is \"${childData['label']}\"";
802 $slotTitle[$slot] .= "'>";
803 $slotClass[$slot] = 'state_T';
804 if ($childData['has_problems'] == 'yes')
805 $slotClass[$slot] = 'state_Tw';
806 if ($child['entity_id'] == $hl_obj_id)
807 $slotClass[$slot] = 'state_Th';
810 natsort($childNames);
811 $suffix = sprintf(", contains %s'>", implode(', ', $childNames));
815 echo "${prefix}${body}${suffix}" . mkA ($objectData['dname'], 'object', $objectData['id']) . '</div>';
816 if (in_array ($objectData['objtype_id'], array (1502,1503))) // server chassis, network chassis
818 $objAttr = getAttrValues ($objectData['id']);
819 if (isset ($objAttr[2])) // HW type
821 extractLayout ($objAttr[2]);
822 if (isset ($objAttr[2]['rows']))
824 $rows = $objAttr[2]['rows'];
825 $cols = $objAttr[2]['cols'];
826 $layout = $objAttr[2]['layout'];
827 echo "<table width='100%' border='1'>";
828 for ($r = 0; $r < $rows; $r++
)
831 for ($c = 0; $c < $cols; $c++
)
833 $s = ($r * $cols) +
$c +
1;
834 if (isset ($slotData[$s]))
836 if ($slotData[$s] >= 0)
838 for ($lr = 0; $lr < $slotRows[$s]; $lr++
)
839 for ($lc = 0; $lc < $slotCols[$s]; $lc++
)
841 $skip = ($lr * $cols) +
$lc;
843 $slotData[$s +
$skip] = -1;
846 if ($slotRows[$s] > 1)
847 echo " rowspan=$slotRows[$s]";
848 if ($slotCols[$s] > 1)
849 echo " colspan=$slotCols[$s]";
850 echo " class='${slotClass[$s]}'>${slotTitle[$s]}";
853 $tmp = substr ($slotInfo[$s], 0, 1);
854 foreach (str_split (substr ($slotInfo[$s], 1)) as $letter)
855 $tmp .= '<br>' . $letter;
856 $slotInfo[$s] = $tmp;
858 echo mkA ($slotInfo[$s], 'object', $slotData[$s]);
863 echo "<td class='state_F'><div title=\"Free slot\"> </div></td>";
873 // This function renders rack as HTML table.
874 function renderRack ($rack_id, $hl_obj_id = 0)
876 $rackData = spotEntity ('rack', $rack_id);
877 amplifyCell ($rackData);
878 markAllSpans ($rackData);
880 highlightObject ($rackData, $hl_obj_id);
881 $prev_id = getPrevIDforRack ($rackData['row_id'], $rack_id);
882 $next_id = getNextIDforRack ($rackData['row_id'], $rack_id);
883 echo "<center><table border=0><tr valign=middle>";
884 echo '<td><h2>' . mkA ($rackData['row_name'], 'row', $rackData['row_id']) . ' :</h2></td>';
885 if ($prev_id != NULL)
886 echo '<td>' . mkA (getImageHREF ('prev', 'previous rack'), 'rack', $prev_id) . '</td>';
887 echo '<td><h2>' . mkA ($rackData['name'], 'rack', $rackData['id']) . '</h2></td>';
888 if ($next_id != NULL)
889 echo '<td>' . mkA (getImageHREF ('next', 'next rack'), 'rack', $next_id) . '</td>';
890 echo "</h2></td></tr></table>\n";
891 echo "<table class=rack border=0 cellspacing=0 cellpadding=1>\n";
892 echo "<tr><th width='10%'> </th><th width='20%'>Front</th>";
893 echo "<th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n";
894 for ($i = $rackData['height']; $i > 0; $i--)
896 echo "<tr><th>" . inverseRackUnit ($i, $rackData) . "</th>";
897 for ($locidx = 0; $locidx < 3; $locidx++
)
899 if (isset ($rackData[$i][$locidx]['skipped']))
901 $state = $rackData[$i][$locidx]['state'];
902 echo "<td class='atom state_${state}";
903 if (isset ($rackData[$i][$locidx]['hl']))
904 echo $rackData[$i][$locidx]['hl'];
906 if (isset ($rackData[$i][$locidx]['colspan']))
907 echo ' colspan=' . $rackData[$i][$locidx]['colspan'];
908 if (isset ($rackData[$i][$locidx]['rowspan']))
909 echo ' rowspan=' . $rackData[$i][$locidx]['rowspan'];
914 printObjectDetailsForRenderRack ($rackData[$i][$locidx]['object_id'], $hl_obj_id);
917 echo '<div title="This rackspace does not exist"> </div>';
920 echo '<div title="Free rackspace"> </div>';
923 echo '<div title="Problematic rackspace, you CAN\'T mount here"> </div>';
926 echo '<div title="No data"> </div>';
934 // Get a list of all of objects Zero-U mounted to this rack
935 $zeroUObjects = getEntityRelatives('children', 'rack', $rack_id);
936 if (count ($zeroUObjects) > 0)
938 echo "<br><table width='75%' class=rack border=0 cellspacing=0 cellpadding=1>\n";
939 echo "<tr><th>Zero-U:</th></tr>\n";
940 foreach ($zeroUObjects as $zeroUObject)
942 $state = ($zeroUObject['entity_id'] == $hl_obj_id) ?
'Th' : 'T';
943 echo "<tr><td class='atom state_${state}'>";
944 printObjectDetailsForRenderRack($zeroUObject['entity_id']);
952 function renderRackSortForm ($row_id)
954 includeJQueryUI (false);
958 $("#sortRacks").sortable({
959 update : function () {
960 serial = $('#sortRacks').sortable('serialize');
962 url: 'index.php?module=ajax&ac=upd-rack-sort-order',
973 startPortlet ('Racks');
974 echo "<table border=0 cellspacing=0 cellpadding=5 align=center class=widetable>\n";
975 echo "<tr><th>Drag to change order</th></tr>\n";
976 echo "<tr><td><ul class='uflist' id='sortRacks'>\n";
977 foreach (getRacks($row_id) as $rack_id => $rackInfo)
978 echo "<li id=racks_${rack_id}>${rackInfo['name']}</li>\n";
979 echo "</ul></td></tr></table>\n";
983 function renderNewRackForm ($row_id)
985 $default_height = getConfigVar ('DEFAULT_RACK_HEIGHT');
986 if ($default_height == 0)
987 $default_height = '';
988 startPortlet ('Add one');
989 printOpFormIntro ('addRack', array ('got_data' => 'TRUE'));
990 echo '<table border=0 align=center>';
991 echo "<tr><th class=tdright>Name (required):</th><td class=tdleft><input type=text name=name tabindex=1></td>";
992 echo "<td rowspan=4>Tags:<br>";
995 echo "<tr><th class=tdright>Height in units (required):</th><td class=tdleft><input type=text name=height1 tabindex=2 value='${default_height}'></td></tr>\n";
996 echo "<tr><th class=tdright>Asset tag:</th><td class=tdleft><input type=text name=asset_no tabindex=4></td></tr>\n";
997 echo "<tr><td class=submit colspan=2>";
998 printImageHREF ('CREATE', 'Add', TRUE);
999 echo "</td></tr></table></form>";
1002 startPortlet ('Add many');
1003 printOpFormIntro ('addRack', array ('got_mdata' => 'TRUE'));
1004 echo '<table border=0 align=center>';
1005 echo "<tr><th class=tdright>Height in units (*):</th><td class=tdleft><input type=text name=height2 value='${default_height}'></td>";
1006 echo "<td rowspan=3 valign=top>Assign tags:<br>";
1008 echo "</td></tr>\n";
1009 echo "<tr><th class=tdright>Rack names (required):</th><td class=tdleft><textarea name=names cols=40 rows=25></textarea></td></tr>\n";
1010 echo "<tr><td class=submit colspan=2>";
1011 printImageHREF ('CREATE', 'Add', TRUE);
1012 echo '</form></table>';
1016 function renderEditObjectForm()
1019 $object_id = getBypassValue();
1020 $object = spotEntity ('object', $object_id);
1022 printOpFormIntro ('update');
1024 // static attributes
1025 echo '<table border=0 cellspacing=0 cellpadding=3 align=center>';
1026 echo "<tr><td> </td><th colspan=2><h2>Attributes</h2></th></tr>";
1027 echo '<tr><td> </td><th class=tdright>Type:</th><td class=tdleft>';
1028 printSelect (getObjectTypeChangeOptions ($object['id']), array ('name' => 'object_type_id'), $object['objtype_id']);
1031 echo "<tr><td> </td><th class=tdright>Common name:</th><td class=tdleft><input type=text name=object_name value='${object['name']}'></td></tr>\n";
1032 echo "<tr><td> </td><th class=tdright>Visible label:</th><td class=tdleft><input type=text name=object_label value='${object['label']}'></td></tr>\n";
1033 echo "<tr><td> </td><th class=tdright>Asset tag:</th><td class=tdleft><input type=text name=object_asset_no value='${object['asset_no']}'></td></tr>\n";
1034 echo "<tr><td> </td><th class=tdright>Tags:</th><td class=tdleft>";
1036 echo "</td></tr>\n";
1038 if (objectTypeMayHaveParent ($object['objtype_id']))
1040 $parents = getEntityRelatives ('parents', 'object', $object_id);
1041 foreach ($parents as $link_id => $parent_details)
1044 $label = count($parents) > 1 ?
'Containers:' : 'Container:';
1045 echo "<tr><td> </td>";
1046 echo "<th class=tdright>${label}</th><td class=tdleft>";
1047 echo mkA ($parent_details['name'], 'object', $parent_details['entity_id']);
1048 echo " ";
1049 echo getOpLink (array('op'=>'unlinkObjects', 'link_id'=>$link_id), '', 'cut', 'Unlink container');
1050 echo "</td></tr>\n";
1053 echo "<tr><td> </td>";
1054 echo "<th class=tdright>Select container:</th><td class=tdleft>";
1056 $helper_args = array ('object_id' => $object_id);
1057 $popup_args = 'height=700, width=400, location=no, menubar=no, '.
1058 'resizable=yes, scrollbars=yes, status=no, titlebar=no, toolbar=no';
1059 echo " onclick='window.open(\"" . makeHrefForHelper ('objlist', $helper_args);
1060 echo "\",\"findlink\",\"${popup_args}\");'>";
1061 printImageHREF ('attach', 'Select a container');
1062 echo "</span></td></tr>\n";
1064 // optional attributes
1066 $values = getAttrValues ($object_id);
1067 if (count($values) > 0)
1069 foreach ($values as $record)
1071 if (! permitted (NULL, NULL, NULL, array (
1072 array ('tag' => '$attr_' . $record['id']),
1073 array ('tag' => '$any_op'),
1076 echo "<input type=hidden name=${i}_attr_id value=${record['id']}>";
1078 if (strlen ($record['value']))
1079 echo getOpLink (array('op'=>'clearSticker', 'attr_id'=>$record['id']), '', 'clear', 'Clear value', 'need-confirmation');
1083 echo "<th class=sticker>${record['name']}";
1084 if ($record['type'] == 'date')
1085 echo ' (' . datetimeFormatHint (getConfigVar ('DATETIME_FORMAT')) . ')';
1086 echo ':</th><td class=tdleft>';
1087 switch ($record['type'])
1092 echo "<input type=text name=${i}_value value='${record['value']}'>";
1095 $chapter = readChapter ($record['chapter_id'], 'o');
1096 $chapter[0] = '-- NOT SET --';
1097 $chapter = cookOptgroups ($chapter, $object['objtype_id'], $record['key']);
1098 printNiftySelect ($chapter, array ('name' => "${i}_value"), $record['key']);
1101 $date_value = $record['value'] ?
datetimestrFromTimestamp ($record['value']) : '';
1102 echo "<input type=text name=${i}_value value='${date_value}'>";
1105 echo "</td></tr>\n";
1109 echo '<input type=hidden name=num_attrs value=' . $i . ">\n";
1110 echo "<tr><td> </td><th class=tdright>Has problems:</th><td class=tdleft><input type=checkbox name=object_has_problems";
1111 if ($object['has_problems'] == 'yes')
1113 echo "></td></tr>\n";
1114 echo "<tr><td> </td><th class=tdright>Actions:</th><td class=tdleft>";
1115 echo getOpLink (array ('op'=>'deleteObject', 'page'=>'depot', 'tab'=>'addmore', 'object_id'=>$object_id), '' ,'destroy', 'Delete object', 'need-confirmation');
1117 echo getOpLink (array ('op'=>'resetObject'), '' ,'clear', 'Reset (cleanup) object', 'need-confirmation');
1118 echo "</td></tr>\n";
1119 echo "<tr><td colspan=3><b>Comment:</b><br><textarea name=object_comment rows=10 cols=80>${object['comment']}</textarea></td></tr>";
1121 echo "<tr><th class=submit colspan=3>";
1122 printImageHREF ('SAVE', 'Save changes', TRUE);
1123 echo "</form></th></tr></table>\n";
1126 echo '<table border=0 width=100%><tr><td>';
1127 startPortlet ('history');
1128 renderObjectHistory ($object_id);
1130 echo '</td></tr></table>';
1133 function renderEditRackForm ($rack_id)
1136 $rack = spotEntity ('rack', $rack_id);
1137 amplifyCell ($rack);
1139 startPortlet ('Attributes');
1140 printOpFormIntro ('updateRack');
1141 echo '<table border=0 align=center>';
1142 echo "<tr><td> </td><th class=tdright>Rack row:</th><td class=tdleft>";
1143 foreach (getAllRows () as $row_id => $rowInfo)
1145 $trail = getLocationTrail ($rowInfo['location_id'], FALSE);
1146 $rows[$row_id] = empty ($trail) ?
$rowInfo['name'] : $rowInfo['name'] . ' [' . $trail . ']';
1148 natcasesort ($rows);
1149 printSelect ($rows, array ('name' => 'row_id'), $rack['row_id']);
1150 echo "</td></tr>\n";
1151 echo "<tr><td> </td><th class=tdright>Name (required):</th><td class=tdleft><input type=text name=name value='${rack['name']}'></td></tr>\n";
1152 echo "<tr><td> </td><th class=tdright>Height (required):</th><td class=tdleft><input type=text name=height value='${rack['height']}'></td></tr>\n";
1153 echo "<tr><td> </td><th class=tdright>Asset tag:</th><td class=tdleft><input type=text name=asset_no value='${rack['asset_no']}'></td></tr>\n";
1154 echo "<tr><td> </td><th class=tdright>Tags:</th><td class=tdleft>";
1156 echo "</td></tr>\n";
1157 // optional attributes
1158 $values = getAttrValues ($rack_id);
1159 $num_attrs = count($values);
1160 $num_attrs = $num_attrs-2; // subtract for the 'height' and 'sort_order' attributes
1161 echo "<input type=hidden name=num_attrs value=${num_attrs}>\n";
1163 foreach ($values as $record)
1165 // Skip the 'height' attribute as it's already displayed as a required field
1166 // Also skip the 'sort_order' attribute
1167 if ($record['id'] == 27 or $record['id'] == 29)
1169 echo "<input type=hidden name=${i}_attr_id value=${record['id']}>";
1171 if (strlen ($record['value']))
1172 echo getOpLink (array('op'=>'clearSticker', 'attr_id'=>$record['id']), '', 'clear', 'Clear value', 'need-confirmation');
1176 echo "<th class=sticker>${record['name']}:</th><td class=tdleft>";
1177 switch ($record['type'])
1182 echo "<input type=text name=${i}_value value='${record['value']}'>";
1185 $chapter = readChapter ($record['chapter_id'], 'o');
1186 $chapter[0] = '-- NOT SET --';
1187 $chapter = cookOptgroups ($chapter, 1560, $record['key']);
1188 printNiftySelect ($chapter, array ('name' => "${i}_value"), $record['key']);
1191 echo "</td></tr>\n";
1194 echo "<tr><td> </td><th class=tdright>Has problems:</th><td class=tdleft><input type=checkbox name=has_problems";
1195 if ($rack['has_problems'] == 'yes')
1197 echo "></td></tr>\n";
1198 if ($rack['isDeletable'])
1200 echo "<tr><td> </td><th class=tdright>Actions:</th><td class=tdleft>";
1201 echo getOpLink (array ('op'=>'deleteRack'), '', 'destroy', 'Delete rack', 'need-confirmation');
1202 echo " </td></tr>\n";
1204 echo "<tr><td colspan=3><b>Comment:</b><br><textarea name=comment rows=10 cols=80>${rack['comment']}</textarea></td></tr>";
1205 echo "<tr><td class=submit colspan=3>";
1206 printImageHREF ('SAVE', 'Save changes', TRUE);
1207 echo "</td></tr>\n";
1208 echo '</form></table><br>';
1211 startPortlet ('History');
1212 renderObjectHistory ($rack_id);
1216 // used by renderGridForm() and renderRackPage()
1217 function renderRackInfoPortlet ($rackData)
1220 $summary['Rack row'] = mkA ($rackData['row_name'], 'row', $rackData['row_id']);
1221 $summary['Name'] = $rackData['name'];
1222 $summary['Height'] = $rackData['height'];
1223 if (strlen ($rackData['asset_no']))
1224 $summary['Asset tag'] = $rackData['asset_no'];
1225 if ($rackData['has_problems'] == 'yes')
1226 $summary[] = array ('<tr><td colspan=2 class=msg_error>Has problems</td></tr>');
1227 // Display populated attributes, but skip 'height' since it's already displayed above
1228 // and skip 'sort_order' because it's modified using AJAX
1229 foreach (getAttrValues ($rackData['id']) as $record)
1230 if ($record['id'] != 27 && $record['id'] != 29 && strlen ($record['value']))
1231 $summary['{sticker}' . $record['name']] = formatAttributeValue ($record);
1232 $summary['% used'] = getProgressBar (getRSUforRack ($rackData));
1233 $summary['Objects'] = count ($rackData['mountedObjects']);
1234 $summary['tags'] = '';
1235 if (strlen ($rackData['comment']))
1236 $summary['Comment'] = $rackData['comment'];
1237 renderEntitySummary ($rackData, 'summary', $summary);
1240 // This is a universal editor of rack design/waste.
1241 // FIXME: switch to using printOpFormIntro()
1242 function renderGridForm ($rack_id, $filter, $header, $submit, $state1, $state2)
1244 $rackData = spotEntity ('rack', $rack_id);
1245 amplifyCell ($rackData);
1246 $filter ($rackData);
1248 // Render the result whatever it is.
1250 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
1251 echo "<tr><td colspan=2 align=center><h1>${rackData['name']}</h1></td></tr>\n";
1253 // Left column with information portlet.
1254 echo "<tr><td class=pcleft height='1%' width='50%'>";
1255 renderRackInfoPortlet ($rackData);
1257 echo "<td class=pcright>";
1260 startPortlet ($header);
1261 addJS ('js/racktables.js');
1263 echo "<table class=rack border=0 cellspacing=0 cellpadding=1>\n";
1264 echo "<tr><th width='10%'> </th>";
1265 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '0', ${rackData['height']})\">Front</a></th>";
1266 echo "<th width='50%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '1', ${rackData['height']})\">Interior</a></th>";
1267 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '2', ${rackData['height']})\">Back</a></th></tr>\n";
1268 printOpFormIntro ('updateRack');
1269 markupAtomGrid ($rackData, $state2);
1270 renderAtomGrid ($rackData);
1271 echo "</table></center>\n";
1272 echo "<br><input type=submit name=do_update value='${submit}'></form><br><br>\n";
1274 echo "</td></tr></table>\n";
1277 function renderRackDesign ($rack_id)
1279 renderGridForm ($rack_id, 'applyRackDesignMask', 'Rack design', 'Set rack design', 'A', 'F');
1282 function renderRackProblems ($rack_id)
1284 renderGridForm ($rack_id, 'applyRackProblemMask', 'Rack problems', 'Mark unusable atoms', 'F', 'U');
1287 function renderObjectPortRow ($port, $is_highlighted)
1290 if ($is_highlighted)
1291 echo ' class=highlight';
1292 $a_class = isEthernetPort ($port) ?
'port-menu' : '';
1293 echo "><td class='tdleft' NOWRAP><a name='port-${port['id']}' class='interactive-portname nolink $a_class'>${port['name']}</a></td>";
1294 echo "<td class=tdleft>${port['label']}</td>";
1295 echo "<td class=tdleft>" . formatPortIIFOIF ($port) . "</td><td class=tdleft><tt>${port['l2address']}</tt></td>";
1296 if ($port['remote_object_id'])
1298 echo "<td class=tdleft>" .
1299 formatPortLink ($port['remote_object_id'], $port['remote_object_name'], $port['remote_id'], NULL) .
1301 echo "<td class=tdleft>" . formatLoggedSpan ($port['last_log'], $port['remote_name'], 'underline') . "</td>";
1302 $editable = permitted ('object', 'ports', 'editPort')
1305 echo "<td class=tdleft><span class='rsvtext $editable id-${port['id']} op-upd-reservation-cable'>${port['cableid']}</span></td>";
1308 echo implode ('', formatPortReservation ($port)) . '<td></td>';
1312 function renderObject ($object_id)
1314 global $nextorder, $virtual_obj_types;
1315 $info = spotEntity ('object', $object_id);
1316 amplifyCell ($info);
1317 // Main layout starts.
1318 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
1319 echo "<tr><td colspan=2 align=center><h1>${info['dname']}</h1></td></tr>\n";
1320 // left column with uknown number of portlets
1321 echo "<tr><td class=pcleft>";
1323 // display summary portlet
1325 if (strlen ($info['name']))
1326 $summary['Common name'] = $info['name'];
1327 elseif (considerConfiguredConstraint ($info, 'NAMEWARN_LISTSRC'))
1328 $summary[] = array ('<tr><td colspan=2 class=msg_error>Common name is missing.</td></tr>');
1329 $summary['Object type'] = '<a href="' . makeHref (array (
1332 'cfe' => '{$typeid_' . $info['objtype_id'] . '}'
1333 )) . '">' . decodeObjectType ($info['objtype_id'], 'o') . '</a>';
1334 if (strlen ($info['label']))
1335 $summary['Visible label'] = $info['label'];
1336 if (strlen ($info['asset_no']))
1337 $summary['Asset tag'] = $info['asset_no'];
1338 elseif (considerConfiguredConstraint ($info, 'ASSETWARN_LISTSRC'))
1339 $summary[] = array ('<tr><td colspan=2 class=msg_error>Asset tag is missing.</td></tr>');
1340 $parents = getEntityRelatives ('parents', 'object', $object_id);
1341 if (count ($parents))
1343 $fmt_parents = array();
1344 foreach ($parents as $parent)
1345 $fmt_parents[] = "<a href='".makeHref(array('page'=>$parent['page'], $parent['id_name'] => $parent['entity_id']))."'>${parent['name']}</a>";
1346 $summary[count($parents) > 1 ?
'Containers' : 'Container'] = implode ('<br>', $fmt_parents);
1348 $children = getEntityRelatives ('children', 'object', $object_id);
1349 if (count ($children))
1351 $fmt_children = array();
1352 foreach ($children as $child)
1353 $fmt_children[] = "<a href='".makeHref(array('page'=>$child['page'], $child['id_name']=>$child['entity_id']))."'>${child['name']}</a>";
1354 $summary['Contains'] = implode ('<br>', $fmt_children);
1356 if ($info['has_problems'] == 'yes')
1357 $summary[] = array ('<tr><td colspan=2 class=msg_error>Has problems</td></tr>');
1358 foreach (getAttrValues ($object_id) as $record)
1361 strlen ($record['value']) and
1362 permitted (NULL, NULL, NULL, array (array ('tag' => '$attr_' . $record['id'])))
1364 $summary['{sticker}' . $record['name']] = formatAttributeValue ($record);
1365 $summary[] = array (getOutputOf ('printTagTRs',
1374 'cfe' => '{$typeid_' . $info['objtype_id'] . '}',
1378 renderEntitySummary ($info, 'summary', $summary);
1380 if (strlen ($info['comment']))
1382 startPortlet ('Comment');
1383 echo '<div class=commentblock>' . string_insert_hrefs ($info['comment']) . '</div>';
1387 $logrecords = getLogRecordsForObject ($_REQUEST['object_id']);
1388 if (count ($logrecords))
1390 startPortlet ('log records');
1391 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable width='100%'>";
1393 foreach ($logrecords as $row)
1395 echo "<tr class=row_${order} valign=top>";
1396 echo '<td class=tdleft>' . $row['date'] . '<br>' . $row['user'] . '</td>';
1397 echo '<td class="logentry">' . string_insert_hrefs (htmlspecialchars ($row['content'], ENT_NOQUOTES
)) . '</td>';
1399 $order = $nextorder[$order];
1405 switchportInfoJS ($object_id); // load JS code to make portnames interactive
1406 renderFilesPortlet ('object', $object_id);
1408 if (count ($info['ports']))
1410 startPortlet ('ports and links');
1412 if (isset ($_REQUEST['hl_port_id']))
1414 assertUIntArg ('hl_port_id');
1415 $hl_port_id = $_REQUEST['hl_port_id'];
1416 addAutoScrollScript ("port-$hl_port_id");
1418 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>";
1419 echo '<tr><th class=tdleft>Local name</th><th class=tdleft>Visible label</th>';
1420 echo '<th class=tdleft>Interface</th><th class=tdleft>L2 address</th>';
1421 echo '<th class=tdcenter colspan=2>Remote object and port</th>';
1422 echo '<th class=tdleft>Cable ID</th></tr>';
1423 foreach ($info['ports'] as $port)
1424 callHook ('renderObjectPortRow', $port, ($hl_port_id == $port['id']));
1425 if (permitted (NULL, 'ports', 'set_reserve_comment'))
1426 addJS ('js/inplace-edit.js');
1427 echo "</table><br>";
1431 if (count ($info['ipv4']) +
count ($info['ipv6']))
1433 startPortlet ('IP addresses');
1434 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
1435 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
1436 echo "<tr><th>OS interface</th><th>IP address</th><th>network</th><th>routed by</th><th>peers</th></tr>\n";
1438 echo "<tr><th>OS interface</th><th>IP address</th><th>peers</th></tr>\n";
1440 // group IP allocations by interface name instead of address family
1441 $allocs_by_iface = array();
1442 foreach (array ('ipv4', 'ipv6') as $ip_v)
1443 foreach ($info[$ip_v] as $ip_bin => $alloc)
1444 $allocs_by_iface[$alloc['osif']][$ip_bin] = $alloc;
1446 // sort allocs array by portnames
1447 foreach (sortPortList ($allocs_by_iface) as $iface_name => $alloclist)
1449 $is_first_row = TRUE;
1450 foreach ($alloclist as $alloc)
1452 $rendered_alloc = callHook ('getRenderedAlloc', $object_id, $alloc);
1453 echo "<tr class='${rendered_alloc['tr_class']}' valign=top>";
1455 // display iface name, same values are grouped into single cell
1458 $rowspan = count ($alloclist) > 1 ?
'rowspan="' . count ($alloclist) . '"' : '';
1459 echo "<td class=tdleft $rowspan>" . $iface_name . $rendered_alloc['td_name_suffix'] . "</td>";
1460 $is_first_row = FALSE;
1462 echo $rendered_alloc['td_ip'];
1463 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
1465 echo $rendered_alloc['td_network'];
1466 echo $rendered_alloc['td_routed_by'];
1468 echo $rendered_alloc['td_peers'];
1473 echo "</table><br>\n";
1477 $forwards = $info['nat4'];
1478 if (count($forwards['in']) or count($forwards['out']))
1480 startPortlet('NATv4');
1482 if (count($forwards['out']))
1485 echo "<h3>locally performed NAT</h3>";
1487 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
1488 echo "<tr><th>Proto</th><th>Match endpoint</th><th>Translate to</th><th>Target object</th><th>Rule comment</th></tr>\n";
1490 foreach ($forwards['out'] as $pf)
1494 if (isset ($alloclist [$pf['localip']]))
1496 $class = $alloclist [$pf['localip']]['addrinfo']['class'];
1497 $osif = $alloclist [$pf['localip']]['osif'] . ': ';
1499 echo "<tr class='$class'>";
1500 echo "<td>${pf['proto']}</td><td class=tdleft>${osif}" . getRenderedIPPortPair ($pf['localip'], $pf['localport']) . "</td>";
1501 echo "<td class=tdleft>" . getRenderedIPPortPair ($pf['remoteip'], $pf['remoteport']) . "</td>";
1502 $address = getIPAddress (ip4_parse ($pf['remoteip']));
1503 echo "<td class='description'>";
1504 if (count ($address['allocs']))
1505 foreach($address['allocs'] as $bond)
1506 echo mkA ("${bond['object_name']}(${bond['name']})", 'object', $bond['object_id']) . ' ';
1507 elseif (strlen ($pf['remote_addr_name']))
1508 echo '(' . $pf['remote_addr_name'] . ')';
1509 echo "</td><td class='description'>${pf['description']}</td></tr>";
1511 echo "</table><br><br>";
1513 if (count($forwards['in']))
1515 echo "<h3>arriving NAT connections</h3>";
1516 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
1517 echo "<tr><th>Matched endpoint</th><th>Source object</th><th>Translated to</th><th>Rule comment</th></tr>\n";
1518 foreach ($forwards['in'] as $pf)
1521 echo "<td>${pf['proto']}/" . getRenderedIPPortPair ($pf['localip'], $pf['localport']) . "</td>";
1522 echo '<td class="description">' . mkA ($pf['object_name'], 'object', $pf['object_id']);
1523 echo "</td><td>" . getRenderedIPPortPair ($pf['remoteip'], $pf['remoteport']) . "</td>";
1524 echo "<td class='description'>${pf['description']}</td></tr>";
1526 echo "</table><br><br>";
1531 renderSLBTriplets2 ($info);
1532 renderSLBTriplets ($info);
1535 // After left column we have (surprise!) right column with rackspace portlet only.
1536 echo "<td class=pcright>";
1537 if (!in_array($info['objtype_id'], $virtual_obj_types))
1539 // rackspace portlet
1540 startPortlet ('rackspace allocation');
1541 foreach (getResidentRacksData ($object_id, FALSE) as $rack_id)
1542 renderRack ($rack_id, $object_id);
1550 function renderRackMultiSelect ($sname, $racks, $selected)
1552 // Transform the given flat list into a list of groups, each representing a rack row.
1554 foreach ($racks as $rack)
1556 $trail = getLocationTrail ($rack['location_id'], FALSE);
1558 $row_name = $trail . ' : ' . $rack['row_name'];
1560 $row_name = $rack['row_name'];
1561 $rdata[$row_name][$rack['id']] = $rack['name'];
1563 echo "<select name=${sname} multiple size=" . getConfigVar ('MAXSELSIZE') . " onchange='getElementsByName(\"updateObjectAllocation\")[0].submit()'>\n";
1564 $row_names = array_keys ($rdata);
1565 natsort ($row_names);
1566 foreach ($row_names as $optgroup)
1568 echo "<optgroup label='${optgroup}'>";
1569 foreach ($rdata[$optgroup] as $rack_id => $rack_name)
1571 echo "<option value=${rack_id}";
1572 if (!(array_search ($rack_id, $selected) === FALSE))
1574 echo">${rack_name}</option>\n";
1580 // This function renders a form for port edition.
1581 function renderPortsForObject ($object_id)
1583 $prefs = getPortListPrefs();
1584 function printNewItemTR ($prefs)
1586 printOpFormIntro ('addPort');
1588 printImageHREF ('add', 'add a port', TRUE);
1589 echo "</td><td class='tdleft'><input type=text size=8 name=port_name tabindex=100></td>\n";
1590 echo "<td><input type=text name=port_label tabindex=101></td><td>";
1591 printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type_id', 'tabindex' => 102), $prefs['selected']);
1592 echo "<td><input type=text name=port_l2address tabindex=103 size=18 maxlength=24></td>\n";
1593 echo "<td colspan=4> </td><td>";
1594 printImageHREF ('add', 'add a port', TRUE, 104);
1595 echo "</td></tr></form>";
1597 if (getConfigVar('ENABLE_MULTIPORT_FORM') == 'yes' ||
getConfigVar('ENABLE_BULKPORT_FORM') == 'yes' )
1598 startPortlet ('Ports and interfaces');
1601 $object = spotEntity ('object', $object_id);
1602 amplifyCell ($object);
1603 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes' && getConfigVar('ENABLE_BULKPORT_FORM') == 'yes'){
1604 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
1605 echo "<tr><th> </th><th class=tdleft>Local name</th><th class=tdleft>Visible label</th><th class=tdleft>Interface</th><th class=tdleft>Start Number</th>";
1606 echo "<th class=tdleft>Count</th><th> </th></tr>\n";
1607 printOpFormIntro ('addBulkPorts');
1609 printImageHREF ('add', 'add ports', TRUE);
1610 echo "</td><td><input type=text size=8 name=port_name tabindex=105></td>\n";
1611 echo "<td><input type=text name=port_label tabindex=106></td><td>";
1612 printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type_id', 'tabindex' => 107), $prefs['selected']);
1613 echo "<td><input type=text name=port_numbering_start tabindex=108 size=3 maxlength=3></td>\n";
1614 echo "<td><input type=text name=port_numbering_count tabindex=109 size=3 maxlength=3></td>\n";
1615 echo "<td> </td><td>";
1616 printImageHREF ('add', 'add ports', TRUE, 110);
1617 echo "</td></tr></form>";
1618 echo "</table><br>\n";
1621 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
1622 echo "<tr><th> </th><th class=tdleft>Local name</th><th class=tdleft>Visible label</th><th class=tdleft>Interface</th><th class=tdleft>L2 address</th>";
1623 echo "<th class=tdcenter colspan=2>Remote object and port</th><th>Cable ID</th><th class=tdcenter>(Un)link or (un)reserve</th><th> </th></tr>\n";
1624 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
1625 printNewItemTR ($prefs);
1628 echo getOpLink (array ('op'=>'deleteAll'), 'Clear port list', 'clear', '', 'need-confirmation');
1630 if (isset ($_REQUEST['hl_port_id']))
1632 assertUIntArg ('hl_port_id');
1633 $hl_port_id = intval ($_REQUEST['hl_port_id']);
1634 addAutoScrollScript ("port-$hl_port_id");
1636 switchportInfoJS ($object_id); // load JS code to make portnames interactive
1637 foreach ($object['ports'] as $port)
1639 $tr_class = isset ($hl_port_id) && $hl_port_id == $port['id'] ?
'class="highlight"' : '';
1640 printOpFormIntro ('editPort', array ('port_id' => $port['id']));
1641 echo "<tr $tr_class><td><a name='port-${port['id']}' href='".makeHrefProcess(array('op'=>'delPort', 'port_id'=>$port['id']))."'>";
1642 printImageHREF ('delete', 'Unlink and Delete this port');
1644 $a_class = isEthernetPort ($port) ?
'port-menu' : '';
1645 echo "<td class='tdleft' NOWRAP><input type=text name=name class='interactive-portname $a_class' value='${port['name']}' size=8></td>";
1646 echo "<td><input type=text name=label value='${port['label']}'></td>";
1648 if ($port['iif_id'] != 1)
1649 echo '<label>' . $port['iif_name'] . ' ';
1650 printSelect (getExistingPortTypeOptions ($port['id']), array ('name' => 'port_type_id'), $port['oif_id']);
1651 if ($port['iif_id'] != 1)
1655 // 18 is enough to fit 6-byte MAC address in its longest form,
1656 // while 24 should be Ok for WWN
1657 echo "<td><input type=text name=l2address value='${port['l2address']}' size=18 maxlength=24></td>\n";
1658 if ($port['remote_object_id'])
1661 formatLoggedSpan ($port['last_log'], formatPortLink ($port['remote_object_id'], $port['remote_object_name'], $port['remote_id'], NULL)) .
1663 echo "<td> " . formatLoggedSpan ($port['last_log'], $port['remote_name'], 'underline') .
1664 "<input type=hidden name=reservation_comment value=''></td>";
1665 echo "<td><input type=text name=cable value='${port['cableid']}'></td>";
1666 echo "<td class=tdcenter>";
1667 echo getOpLink (array('op'=>'unlinkPort', 'port_id'=>$port['id'], ), '', 'cut', 'Unlink this port');
1670 elseif (strlen ($port['reservation_comment']))
1672 echo "<td>" . formatLoggedSpan ($port['last_log'], 'Reserved:', 'strong underline') . "</td>";
1673 echo "<td><input type=text name=reservation_comment value='${port['reservation_comment']}'></td>";
1675 echo "<td class=tdcenter>";
1676 echo getOpLink (array('op'=>'useup', 'port_id'=>$port['id']), '', 'clear', 'Use up this port');
1681 $in_rack = getConfigVar ('NEAREST_RACKS_CHECKBOX');
1682 echo "<td> </td><td> </td><td> </td><td class=tdcenter><span";
1683 $helper_args = array
1685 'port' => $port['id'],
1686 'in_rack' => ($in_rack == "yes" ?
"on" : "")
1688 $popup_args = 'height=700, width=400, location=no, menubar=no, '.
1689 'resizable=yes, scrollbars=yes, status=no, titlebar=no, toolbar=no';
1690 echo " ondblclick='window.open(\"" . makeHrefForHelper ('portlist', $helper_args);
1691 echo "\",\"findlink\",\"${popup_args}\");'";
1693 echo " onclick='window.open(\"" . makeHrefForHelper ('portlist', $helper_args);
1694 echo "\",\"findlink\",\"${popup_args}\");'";
1698 printImageHREF ('plug', 'Link this port');
1700 echo " <input type=text name=reservation_comment></td>\n";
1703 printImageHREF ('save', 'Save changes', TRUE);
1704 echo "</td></form></tr>\n";
1706 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
1707 printNewItemTR ($prefs);
1708 echo "</table><br>\n";
1709 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes' && getConfigVar('ENABLE_BULKPORT_FORM') == 'yes'){
1710 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
1711 echo "<tr><th> </th><th class=tdleft>Local name</th><th class=tdleft>Visible label</th><th class=tdleft>Interface</th><th class=tdleft>Start Number</th>";
1712 echo "<th class=tdleft>Count</th><th> </th></tr>\n";
1713 printOpFormIntro ('addBulkPorts');
1715 printImageHREF ('add', 'add ports', TRUE);
1716 echo "</td><td><input type=text size=8 name=port_name tabindex=105></td>\n";
1717 echo "<td><input type=text name=port_label tabindex=106></td><td>";
1718 printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type_id', 'tabindex' => 107), $prefs['selected']);
1719 echo "<td><input type=text name=port_numbering_start tabindex=108 size=3 maxlength=3></td>\n";
1720 echo "<td><input type=text name=port_numbering_count tabindex=109 size=3 maxlength=3></td>\n";
1721 echo "<td> </td><td>";
1722 printImageHREF ('add', 'add ports', TRUE, 110);
1723 echo "</td></tr></form>";
1724 echo "</table><br>\n";
1726 if (getConfigVar('ENABLE_MULTIPORT_FORM') == 'yes')
1728 if (getConfigVar('ENABLE_MULTIPORT_FORM') != 'yes')
1731 startPortlet ('Add/update multiple ports');
1732 printOpFormIntro ('addMultiPorts');
1733 echo 'Format: <select name=format tabindex=201>';
1734 echo '<option value=c3600asy>Cisco 3600 async: sh line | inc TTY</option>';
1735 echo '<option value=fiwg selected>Foundry ServerIron/FastIron WorkGroup/Edge: sh int br</option>';
1736 echo '<option value=fisxii>Foundry FastIron SuperX/II4000: sh int br</option>';
1737 echo '<option value=ssv1>SSV:<interface name> <MAC address></option>';
1739 echo 'Default port type: ';
1740 printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type', 'tabindex' => 202), $prefs['selected']);
1741 echo "<input type=submit value='Parse output' tabindex=204><br>\n";
1742 echo "<textarea name=input cols=100 rows=50 tabindex=203></textarea><br>\n";
1747 function renderIPForObject ($object_id)
1749 function printNewItemTR ($default_type)
1752 printOpFormIntro ('add');
1753 echo "<tr><td>"; // left btn
1754 printImageHREF ('add', 'allocate', TRUE);
1756 echo "<td class=tdleft><input type='text' size='10' name='bond_name' tabindex=100></td>\n"; // if-name
1757 echo "<td class=tdleft><input type=text name='ip' tabindex=101></td>\n"; // IP
1758 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
1759 echo "<td colspan=2> </td>"; // network, routed by
1761 printSelect ($aat, array ('name' => 'bond_type', 'tabindex' => 102), $default_type); // type
1762 echo "</td><td> </td><td>"; // misc
1763 printImageHREF ('add', 'allocate', TRUE, 103); // right btn
1764 echo "</td></tr></form>";
1767 startPortlet ('Allocations');
1768 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'><tr>\n";
1769 echo '<th> </th>';
1770 echo '<th>OS interface</th>';
1771 echo '<th>IP address</th>';
1772 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
1774 echo '<th>network</th>';
1775 echo '<th>routed by</th>';
1777 echo '<th>type</th>';
1778 echo '<th>misc</th>';
1779 echo '<th> </th>';
1782 $alloc_list = ''; // most of the output is stored here
1783 $used_alloc_types = array();
1784 foreach (getObjectIPAllocations ($object_id) as $alloc)
1786 if (! isset ($used_alloc_types[$alloc['type']]))
1787 $used_alloc_types[$alloc['type']] = 0;
1788 $used_alloc_types[$alloc['type']]++
;
1790 $rendered_alloc = callHook ('getRenderedAlloc', $object_id, $alloc);
1791 $alloc_list .= getOutputOf ('printOpFormIntro', 'upd', array ('ip' => $alloc['addrinfo']['ip']));
1792 $alloc_list .= "<tr class='${rendered_alloc['tr_class']}' valign=top>";
1794 $alloc_list .= "<td>" . getOpLink (array ('op' => 'del', 'ip' => $alloc['addrinfo']['ip']), '', 'delete', 'Delete this IP address') . "</td>";
1795 $alloc_list .= "<td class=tdleft><input type='text' name='bond_name' value='${alloc['osif']}' size=10>" . $rendered_alloc['td_name_suffix'] . "</td>";
1796 $alloc_list .= $rendered_alloc['td_ip'];
1797 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
1799 $alloc_list .= $rendered_alloc['td_network'];
1800 $alloc_list .= $rendered_alloc['td_routed_by'];
1802 $alloc_list .= '<td>' . getSelect ($aat, array ('name' => 'bond_type'), $alloc['type']) . "</td>";
1803 $alloc_list .= $rendered_alloc['td_peers'];
1804 $alloc_list .= "<td>" .getImageHREF ('save', 'Save changes', TRUE) . "</td>";
1806 $alloc_list .= "</form></tr>\n";
1808 asort ($used_alloc_types, SORT_NUMERIC
);
1809 $most_popular_type = empty ($used_alloc_types) ?
'regular' : array_last (array_keys ($used_alloc_types));
1811 if ($list_on_top = (getConfigVar ('ADDNEW_AT_TOP') != 'yes'))
1813 printNewItemTR ($most_popular_type);
1817 echo "</table><br>\n";
1821 // This function is deprecated. Do not rely on its internals,
1822 // it will probably be removed in the next major relese.
1823 // Use new showError, showWarning, showSuccess functions.
1824 // Log array is stored in global $log_messages. Its format is simple: plain ordered array
1825 // with values having keys 'c' (both message code and severity) and 'a' (sprintf arguments array)
1826 function showMessageOrError ()
1828 global $log_messages;
1831 if (isset ($_SESSION['log']))
1833 $log_messages = array_merge ($_SESSION['log'], $log_messages);
1834 unset ($_SESSION['log']);
1838 if (empty ($log_messages))
1842 // records 0~99 with success messages
1843 0 => array ('code' => 'success', 'format' => '%s'),
1844 5 => array ('code' => 'success', 'format' => 'added record "%s" successfully'),
1845 6 => array ('code' => 'success', 'format' => 'updated record "%s" successfully'),
1846 7 => array ('code' => 'success', 'format' => 'deleted record "%s" successfully'),
1847 8 => array ('code' => 'success', 'format' => 'Port %s successfully linked with %s'),
1848 10 => array ('code' => 'success', 'format' => 'Added %u ports, updated %u ports, encountered %u errors.'),
1849 21 => array ('code' => 'success', 'format' => 'Generation complete'),
1850 26 => array ('code' => 'success', 'format' => 'updated %u records successfully'),
1851 37 => array ('code' => 'success', 'format' => 'added %u records successfully'),
1852 38 => array ('code' => 'success', 'format' => 'removed %u records successfully'),
1853 43 => array ('code' => 'success', 'format' => 'Saved successfully.'),
1854 44 => array ('code' => 'success', 'format' => '%s failures and %s successfull changes.'),
1855 48 => array ('code' => 'success', 'format' => 'added a record successfully'),
1856 49 => array ('code' => 'success', 'format' => 'deleted a record successfully'),
1857 51 => array ('code' => 'success', 'format' => 'updated a record successfully'),
1858 57 => array ('code' => 'success', 'format' => 'Reset complete'),
1859 63 => array ('code' => 'success', 'format' => '%u change request(s) have been processed'),
1860 67 => array ('code' => 'success', 'format' => "Tag rolling done, %u objects involved"),
1861 71 => array ('code' => 'success', 'format' => 'File "%s" was linked successfully'),
1862 72 => array ('code' => 'success', 'format' => 'File was unlinked successfully'),
1863 82 => array ('code' => 'success', 'format' => "Bulk port creation was successful. %u ports created, %u failed"),
1864 87 => array ('code' => 'success', 'format' => '802.1Q recalculate: %d ports changed on %d switches'),
1865 // records 100~199 with fatal error messages
1866 100 => array ('code' => 'error', 'format' => '%s'),
1867 109 => array ('code' => 'error', 'format' => 'failed updating a record'),
1868 131 => array ('code' => 'error', 'format' => 'invalid format requested'),
1869 141 => array ('code' => 'error', 'format' => 'Encountered %u errors, updated %u record(s)'),
1870 149 => array ('code' => 'error', 'format' => 'Turing test failed'),
1871 150 => array ('code' => 'error', 'format' => 'Can only change password under DB authentication.'),
1872 151 => array ('code' => 'error', 'format' => 'Old password doesn\'t match.'),
1873 152 => array ('code' => 'error', 'format' => 'New passwords don\'t match.'),
1874 154 => array ('code' => 'error', 'format' => "Verification error: %s"),
1875 155 => array ('code' => 'error', 'format' => 'Save failed.'),
1876 159 => array ('code' => 'error', 'format' => 'Permission denied moving port %s from VLAN%u to VLAN%u'),
1877 161 => array ('code' => 'error', 'format' => 'Endpoint not found. Please either set FQDN attribute or assign an IP address to the object.'),
1878 162 => array ('code' => 'error', 'format' => 'More than one IP address is assigned to this object, please configure FQDN attribute.'),
1879 170 => array ('code' => 'error', 'format' => 'There is no network for IP address "%s"'),
1880 172 => array ('code' => 'error', 'format' => 'Malformed request'),
1881 179 => array ('code' => 'error', 'format' => 'Expired form has been declined.'),
1882 188 => array ('code' => 'error', 'format' => "Fatal SNMP failure"),
1883 189 => array ('code' => 'error', 'format' => "Unknown OID '%s'"),
1884 191 => array ('code' => 'error', 'format' => "deploy was blocked due to conflicting configuration versions"),
1886 // records 200~299 with warnings
1887 200 => array ('code' => 'warning', 'format' => '%s'),
1888 201 => array ('code' => 'warning', 'format' => 'nothing happened...'),
1889 206 => array ('code' => 'warning', 'format' => '%s is not empty'),
1890 207 => array ('code' => 'warning', 'format' => 'File upload failed, error: %s'),
1892 // records 300~399 with notices
1893 300 => array ('code' => 'neutral', 'format' => '%s'),
1896 // Handle the arguments. Is there any better way to do it?
1897 foreach ($log_messages as $record)
1899 if (!isset ($record['c']) or !isset ($msginfo[$record['c']]))
1901 $prefix = isset ($record['c']) ?
$record['c'] . ': ' : '';
1902 echo "<div class=msg_neutral>(${prefix}this message was lost)</div>";
1905 if (isset ($record['a']))
1906 switch (count ($record['a']))
1911 $msginfo[$record['c']]['format'],
1918 $msginfo[$record['c']]['format'],
1926 $msginfo[$record['c']]['format'],
1936 $msginfo[$record['c']]['format'],
1945 $msgtext = $msginfo[$record['c']]['format'];
1946 echo '<div class=msg_' . $msginfo[$record['c']]['code'] . ">${msgtext}</div>";
1948 $log_messages = array();
1951 // renders two tables: port link status and learned MAC list
1952 function renderPortsInfo($object_id)
1956 if (permitted (NULL, NULL, 'get_link_status'))
1957 $linkStatus = queryDevice ($object_id, 'getportstatus');
1959 showWarning ("You don't have permission to view ports link status");
1961 if (permitted (NULL, NULL, 'get_mac_list'))
1962 $macList = sortPortList (queryDevice ($object_id, 'getmaclist'));
1964 showWarning ("You don't have permission to view learned MAC list");
1966 catch (RTGatewayError
$e)
1968 showError ($e->getMessage());
1973 echo "<table width='100%'><tr>";
1974 if (! empty ($linkStatus))
1976 echo "<td valign='top' width='50%'>";
1977 startPortlet('Link status');
1978 echo "<table width='80%' class='widetable' cellspacing=0 cellpadding='5px' align='center'><tr><th>Port<th><th>Link status<th>Link info</tr>";
1980 foreach ($linkStatus as $pn => $link)
1982 switch ($link['status'])
1985 $img_filename = 'link-up.png';
1988 $img_filename = 'link-down.png';
1991 $img_filename = 'link-disabled.png';
1994 $img_filename = '1x1t.gif';
1997 echo "<tr class='row_$order'>";
1998 $order = $nextorder[$order];
2000 echo '<td>' . '<img width=16 height=16 src="?module=chrome&uri=pix/' . $img_filename . '">';
2001 echo '<td>' . $link['status'];
2003 if (isset ($link['speed']))
2004 $info .= $link['speed'];
2005 if (isset ($link['duplex']))
2007 if (! empty ($info))
2009 $info .= $link['duplex'];
2011 echo '<td>' . $info;
2014 echo "</table></td>";
2018 if (! empty ($macList))
2020 echo "<td valign='top' width='50%'>";
2021 $rendered_macs = '';
2023 $rendered_macs .= "<table width='80%' class='widetable' cellspacing=0 cellpadding='5px' align='center'><tr><th>MAC<th>Vlan<th>Port</tr>";
2025 foreach ($macList as $pn => $list)
2027 $order = $nextorder[$order];
2028 foreach ($list as $item)
2031 $rendered_macs .= "<tr class='row_$order'>";
2032 $rendered_macs .= '<td style="font-family: monospace">' . $item['mac'];
2033 $rendered_macs .= '<td>' . $item['vid'];
2034 $rendered_macs .= '<td>' . $pn;
2035 $rendered_macs .= '</tr>';
2038 $rendered_macs .= "</table></td>";
2040 startPortlet("Learned MACs ($mac_count)");
2041 echo $rendered_macs;
2045 echo "</td></tr></table>";
2049 The following conditions must be met:
2050 1. We can mount onto free atoms only. This means: if any record for an atom
2051 already exists in RackSpace, it can't be used for mounting.
2052 2. We can't unmount from 'W' atoms. Operator should review appropriate comments
2053 and either delete them before unmounting or refuse to unmount the object.
2055 function renderRackSpaceForObject ($object_id)
2057 // Always process occupied racks plus racks chosen by user. First get racks with
2058 // already allocated rackspace...
2059 $workingRacksData = getResidentRacksData ($object_id);
2060 // ...and then add those chosen by user (if any).
2061 if (isset($_REQUEST['rackmulti']))
2062 foreach ($_REQUEST['rackmulti'] as $cand_id)
2063 if (!isset ($workingRacksData[$cand_id]))
2065 $rackData = spotEntity ('rack', $cand_id);
2066 amplifyCell ($rackData);
2067 $workingRacksData[$cand_id] = $rackData;
2070 // Get a list of all of this object's parents,
2071 // then trim the list to only include parents that are racks
2072 $objectParents = getEntityRelatives('parents', 'object', $object_id);
2073 $parentRacks = array();
2074 foreach ($objectParents as $parentData)
2075 if ($parentData['entity_type'] == 'rack')
2076 $parentRacks[] = $parentData['entity_id'];
2078 // Main layout starts.
2079 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0><tr>";
2081 // Left portlet with rack list.
2082 echo "<td class=pcleft height='1%'>";
2083 startPortlet ('Racks');
2084 $allRacksData = listCells ('rack');
2086 // filter rack list to match only racks having common tags with the object (reducing $allRacksData)
2087 if (! isset ($_REQUEST['show_all_racks']) and getConfigVar ('FILTER_RACKLIST_BY_TAGS') == 'yes')
2089 $matching_racks = array();
2090 $object = spotEntity ('object', $object_id);
2091 $matched_tags = array();
2092 foreach ($allRacksData as $rack)
2093 foreach ($object['etags'] as $tag)
2094 if (tagOnChain ($tag, $rack['etags']) or tagOnChain ($tag, $rack['itags']))
2096 $matching_racks[$rack['id']] = $rack;
2097 $matched_tags[$tag['id']] = $tag;
2100 // add current object's racks even if they dont match filter
2101 foreach ($workingRacksData as $rack_id => $rack)
2102 if (! isset ($matching_racks[$rack_id]))
2103 $matching_racks[$rack_id] = $rack;
2104 // if matching racks found, and rack list is reduced, show 'show all' link
2105 if (count ($matching_racks) and count ($matching_racks) != count ($allRacksData))
2108 foreach ($matched_tags as $tag)
2109 $filter_text .= (empty ($filter_text) ?
'' : ' or ') . '{' . $tag['tag'] . '}';
2110 $href_show_all = trim($_SERVER['REQUEST_URI'], '&');
2111 $href_show_all .= htmlspecialchars('&show_all_racks=1');
2112 echo "(filtered by <span class='filter-text'>$filter_text</span>, <a href='$href_show_all'>show all</a>)<p>";
2113 $allRacksData = $matching_racks;
2117 if (count ($allRacksData) <= getConfigVar ('RACK_PRESELECT_THRESHOLD'))
2118 foreach ($allRacksData as $rack)
2119 if (!array_key_exists ($rack['id'], $workingRacksData))
2121 amplifyCell ($rack);
2122 $workingRacksData[$rack['id']] = $rack;
2124 foreach (array_keys ($workingRacksData) as $rackId)
2125 applyObjectMountMask ($workingRacksData[$rackId], $object_id);
2126 printOpFormIntro ('updateObjectAllocation');
2127 renderRackMultiSelect ('rackmulti[]', $allRacksData, array_keys ($workingRacksData));
2132 // Middle portlet with comment and submit.
2133 echo "<td class=pcleft>";
2134 startPortlet ('Comment (for Rackspace History)');
2135 echo "<textarea name=comment rows=10 cols=40></textarea><br>\n";
2136 echo "<input type=submit value='Save' name=got_atoms>\n";
2141 // Right portlet with rendered racks. If this form submit is not final, we have to
2142 // reflect the former state of the grid in current form.
2143 echo "<td class=pcright rowspan=2 height='1%'>";
2144 startPortlet ('Working copy');
2145 includeJQueryUI (false);
2146 addJS ('js/racktables.js');
2147 addJS ('js/bulkselector.js');
2148 echo '<table border=0 cellspacing=10 align=center><tr>';
2149 foreach ($workingRacksData as $rack_id => $rackData)
2151 // Order is important here: only original allocation is highlighted.
2152 highlightObject ($rackData, $object_id);
2153 markupAtomGrid ($rackData, 'T');
2154 // If we have a form processed, discard user input and show new database
2156 if (isset ($_REQUEST['rackmulti'][0])) // is an update
2157 mergeGridFormToRack ($rackData);
2158 echo "<td valign=top>";
2159 echo "<center>\n<h2>${rackData['name']}</h2>\n";
2160 echo "<table class=rack id=selectableRack border=0 cellspacing=0 cellpadding=1>\n";
2161 echo "<tr><th width='10%'> </th>";
2162 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '0', ${rackData['height']})\">Front</a></th>";
2163 echo "<th width='50%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '1', ${rackData['height']})\">Interior</a></th>";
2164 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '2', ${rackData['height']})\">Back</a></th></tr>\n";
2165 renderAtomGrid ($rackData);
2166 echo "<tr><th width='10%'> </th>";
2167 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '0', ${rackData['height']})\">Front</a></th>";
2168 echo "<th width='50%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '1', ${rackData['height']})\">Interior</a></th>";
2169 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '2', ${rackData['height']})\">Back</a></th></tr>\n";
2170 echo "</table>\n<br>\n";
2171 // Determine zero-u checkbox status.
2172 // If form has been submitted, use form data, otherwise use DB data.
2173 if (isset($_REQUEST['op']))
2174 $checked = isset($_REQUEST['zerou_'.$rack_id]) ?
'checked' : '';
2176 $checked = in_array($rack_id, $parentRacks) ?
'checked' : '';
2177 echo "<label for=zerou_${rack_id}>Zero-U:</label> <input type=checkbox ${checked} name=zerou_${rack_id} id=zerou_${rack_id}>\n<br><br>\n";
2178 echo "<input type='button' onclick='uncheckAll();' value='Uncheck all'>\n";
2179 echo '</center></td>';
2181 echo "</tr></table>";
2186 echo "</tr></table>\n";
2189 function renderMolecule ($mdata, $object_id)
2192 $rackpack = array();
2194 foreach ($mdata as $rua)
2196 $rack_id = $rua['rack_id'];
2197 $unit_no = $rua['unit_no'];
2198 $atom = $rua['atom'];
2199 if (!isset ($rackpack[$rack_id]))
2201 $rackData = spotEntity ('rack', $rack_id);
2202 amplifyCell ($rackData);
2203 for ($i = $rackData['height']; $i > 0; $i--)
2204 for ($locidx = 0; $locidx < 3; $locidx++
)
2205 $rackData[$i][$locidx]['state'] = 'F';
2206 $rackpack[$rack_id] = $rackData;
2208 $rackpack[$rack_id][$unit_no][$loclist[$atom]]['state'] = 'T';
2209 $rackpack[$rack_id][$unit_no][$loclist[$atom]]['object_id'] = $object_id;
2211 // now we have some racks to render
2212 foreach ($rackpack as $rackData)
2214 markAllSpans ($rackData);
2215 echo "<table class=molecule cellspacing=0>\n";
2216 echo "<caption>${rackData['name']}</caption>\n";
2217 echo "<tr><th width='10%'> </th><th width='20%'>Front</th><th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n";
2218 for ($i = $rackData['height']; $i > 0; $i--)
2220 echo "<tr><th>" . inverseRackUnit ($i, $rackData) . "</th>";
2221 for ($locidx = 0; $locidx < 3; $locidx++
)
2223 $state = $rackData[$i][$locidx]['state'];
2224 echo "<td class='atom state_${state}'> </td>\n";
2232 function renderDepot ()
2234 global $pageno, $nextorder;
2235 $cellfilter = getCellFilter();
2237 $objects_count = getEntitiesCount ('object');
2239 echo "<table border=0 class=objectview>\n";
2240 echo "<tr><td class=pcleft>";
2242 if ($objects_count == 0)
2243 echo '<h2>No objects exist</h2>';
2244 // 1st attempt: do not fetch all objects if cellfilter is empty and rendering empty result is enabled
2245 elseif (! ($cellfilter['is_empty'] && renderEmptyResults ($cellfilter, 'objects', $objects_count)))
2247 $objects = applyCellFilter ('object', $cellfilter);
2248 // 2nd attempt: do not render all fetched objects if rendering empty result is enabled
2249 if (! renderEmptyResults ($cellfilter, 'objects', count($objects)))
2251 startPortlet ('Objects (' . count ($objects) . ')');
2252 echo '<br><br><table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
2253 echo '<tr><th>Common name</th><th>Visible label</th><th>Asset tag</th><th>Row/Rack or Container</th></tr>';
2255 # gather IDs of all objects and fetch rackspace info in one pass
2257 foreach ($objects as $obj)
2258 $idlist[] = $obj['id'];
2259 $mountinfo = getMountInfo ($idlist);
2260 $containerinfo = getContainerInfo ($idlist);
2261 foreach ($objects as $obj)
2263 $problem = ($obj['has_problems'] == 'yes') ?
'has_problems' : '';
2264 echo "<tr class='row_${order} tdleft ${problem}' valign=top><td>" . mkA ("<strong>${obj['dname']}</strong>", 'object', $obj['id']);
2265 if (count ($obj['etags']))
2266 echo '<br><small>' . serializeTags ($obj['etags'], makeHref(array('page'=>$pageno, 'tab'=>'default')) . '&') . '</small>';
2267 echo "</td><td>${obj['label']}</td>";
2268 echo "<td>${obj['asset_no']}</td>";
2270 if (array_key_exists ($obj['id'], $containerinfo))
2271 foreach ($containerinfo[$obj['id']] as $ci)
2272 $places[] = mkA ($ci['container_dname'], 'object', $ci['container_id']);
2273 if (array_key_exists ($obj['id'], $mountinfo))
2274 foreach ($mountinfo[$obj['id']] as $mi)
2275 $places[] = mkA ($mi['row_name'], 'row', $mi['row_id']) . '/' . mkA ($mi['rack_name'], 'rack', $mi['rack_id']);
2276 if (! count ($places))
2277 $places[] = 'Unmounted';
2278 echo "<td>" . implode (', ', $places) . '</td>';
2280 $order = $nextorder[$order];
2287 echo "</td><td class=pcright width='25%'>";
2289 renderCellFilterPortlet ($cellfilter, 'object', $objects);
2290 echo "</td></tr></table>\n";
2293 // This function returns TRUE if the result set is too big to be rendered, and no filter is set.
2294 // In this case it renders the describing message instead.
2295 function renderEmptyResults($cellfilter, $entities_name, $count = NULL)
2297 if (!$cellfilter['is_empty'])
2299 if (isset ($_REQUEST['show_all_objects']))
2301 $max = intval(getConfigVar('MAX_UNFILTERED_ENTITIES'));
2302 if (0 == $max ||
$count <= $max)
2305 $href_show_all = trim($_SERVER['REQUEST_URI'], '&');
2306 $href_show_all .= htmlspecialchars('&show_all_objects=1');
2307 $suffix = isset ($count) ?
" ($count)" : '';
2309 <p>Please set a filter to display the corresponging $entities_name.
2310 <br><a href="$href_show_all">Show all $entities_name$suffix</a>
2315 // History viewer for history-enabled simple dictionaries.
2316 function renderObjectHistory ($object_id)
2320 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
2321 echo '<tr><th>change time</th><th>author</th><th>name</th><th>visible label</th><th>asset no</th><th>has problems?</th><th>comment</th></tr>';
2322 $result = usePreparedSelectBlade
2324 'SELECT ctime, user_name, name, label, asset_no, has_problems, comment FROM ObjectHistory WHERE id=? ORDER BY ctime',
2327 while ($row = $result->fetch (PDO
::FETCH_NUM
))
2329 echo "<tr class=row_${order}><td>${row[0]}</td>";
2330 for ($i = 1; $i <= 6; $i++
)
2331 echo "<td>" . $row[$i] . "</td>";
2333 $order = $nextorder[$order];
2335 echo "</table><br>\n";
2338 function renderRackspaceHistory ()
2340 global $nextorder, $pageno, $tabno;
2342 $history = getRackspaceHistory();
2343 // Show the last operation by default.
2344 if (isset ($_REQUEST['op_id']))
2345 $op_id = $_REQUEST['op_id'];
2346 elseif (isset ($history[0]['mo_id']))
2347 $op_id = $history[0]['mo_id'];
2354 list ($omid, $nmid) = getOperationMolecules ($op_id);
2356 // Main layout starts.
2357 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
2359 // Left top portlet with old allocation.
2360 echo "<tr><td class=pcleft>";
2361 startPortlet ('Old allocation');
2364 $oldMolecule = getMolecule ($omid);
2365 renderMolecule ($oldMolecule, $object_id);
2371 echo '</td><td class=pcright>';
2373 // Right top portlet with new allocation
2374 startPortlet ('New allocation');
2377 $newMolecule = getMolecule ($nmid);
2378 renderMolecule ($newMolecule, $object_id);
2384 echo '</td></tr><tr><td colspan=2>';
2386 // Bottom portlet with list
2388 startPortlet ('Rackspace allocation history');
2389 echo "<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>\n";
2390 echo "<tr><th>timestamp</th><th>author</th><th>object</th><th>comment</th></tr>\n";
2391 foreach ($history as $row)
2393 if ($row['mo_id'] == $op_id)
2396 $class = "row_${order}";
2397 echo "<tr class=${class}><td><a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'op_id'=>$row['mo_id']))."'>${row['ctime']}</a></td>";
2398 echo "<td>${row['user_name']}</td><td>";
2399 renderCell (spotEntity ('object', $row['ro_id']));
2400 echo '</td><td>' . niftyString ($row['comment'], 0) . '</td></tr>';
2401 $order = $nextorder[$order];
2406 echo '</td></tr></table>';
2409 function renderIPSpaceRecords ($tree, $baseurl, $target = 0, $level = 1)
2411 $self = __FUNCTION__
;
2412 $knight = (getConfigVar ('IPV4_ENABLE_KNIGHT') == 'yes');
2414 // scroll page to the highlighted item
2415 if ($target && isset ($_REQUEST['hl_net']))
2416 addAutoScrollScript ("net-$target");
2418 foreach ($tree as $item)
2420 if ($display_routers = (getConfigVar ('IPV4_TREE_RTR_AS_CELL') != 'none'))
2421 loadIPAddrList ($item); // necessary to compute router list and address counter
2423 if (isset ($item['id']))
2425 $decor = array ('indent' => $level);
2426 if ($item['symbol'] == 'node-collapsed')
2427 $decor['symbolurl'] = "${baseurl}&eid=${item['id']}&hl_net=1";
2428 elseif ($item['symbol'] == 'node-expanded')
2429 $decor['symbolurl'] = $baseurl . ($item['parent_id'] ?
"&eid=${item['parent_id']}&hl_net=1" : '');
2431 if ($target == $item['id'] && isset ($_REQUEST['hl_net']))
2433 $decor['tdclass'] = ' highlight';
2434 $tr_class = $decor['tdclass'];
2436 echo "<tr valign=top class=\"$tr_class\">";
2437 printIPNetInfoTDs ($item, $decor);
2439 // capacity and usage
2440 echo "<td class=tdcenter>";
2441 echo getRenderedIPNetCapacity ($item);
2444 if ($display_routers)
2445 printRoutersTD (findRouters ($item['own_addrlist']), getConfigVar ('IPV4_TREE_RTR_AS_CELL'));
2447 if ($item['symbol'] == 'node-expanded' or $item['symbol'] == 'node-expanded-static')
2448 $self ($item['kids'], $baseurl, $target, $level +
1);
2452 // non-allocated (spare) IP range
2453 echo "<tr valign=top>";
2454 printIPNetInfoTDs ($item, array ('indent' => $level, 'knight' => $knight, 'tdclass' => 'sparenetwork'));
2456 // capacity and usage
2457 echo "<td class=tdcenter>";
2458 echo getRenderedIPNetCapacity ($item);
2460 if ($display_routers)
2467 function renderIPSpace()
2469 global $pageno, $tabno;
2470 $realm = ($pageno == 'ipv4space' ?
'ipv4net' : 'ipv6net');
2471 $cellfilter = getCellFilter();
2473 // expand request can take either natural values or "ALL". Zero means no expanding.
2474 $eid = isset ($_REQUEST['eid']) ?
$_REQUEST['eid'] : 0;
2476 echo "<table border=0 class=objectview>\n";
2477 echo "<tr><td class=pcleft>";
2480 if (! ($cellfilter['is_empty'] && ! $eid && renderEmptyResults($cellfilter, 'IP nets', getEntitiesCount ($realm))))
2483 foreach (listCells ($realm) as $net)
2485 if (isset ($top) and IPNetContains ($top, $net))
2487 elseif (! count ($cellfilter['expression']) or judgeCell ($net, $cellfilter['expression']))
2491 $netlist[$net['id']] = $net;
2493 $netcount = count ($netlist);
2494 $tree = prepareIPTree ($netlist, $eid);
2496 if (! renderEmptyResults($cellfilter, 'IP nets', count($tree)))
2498 startPortlet ("networks (${netcount})");
2500 $all = "<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'eid'=>'ALL')) .
2501 $cellfilter['urlextra'] . "'>expand all</a>";
2502 $none = "<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'eid'=>'NONE')) .
2503 $cellfilter['urlextra'] . "'>collapse all</a>";
2504 $auto = "<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno)) .
2505 $cellfilter['urlextra'] . "'>auto-collapse</a>";
2508 echo 'auto-collapsing at threshold ' . getConfigVar ('TREE_THRESHOLD') . " ($all / $none)";
2509 elseif ($eid === 'ALL')
2510 echo "expanding all ($auto / $none)";
2511 elseif ($eid === 'NONE')
2512 echo "collapsing all ($all / $auto)";
2515 $netinfo = spotEntity ($realm, $eid);
2516 echo "expanding ${netinfo['ip']}/${netinfo['mask']} ($auto / $all / $none)";
2518 echo "</h4><table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
2519 echo "<tr><th>prefix</th><th>name/tags</th><th>capacity</th>";
2520 if (getConfigVar ('IPV4_TREE_RTR_AS_CELL') != 'none')
2521 echo "<th>routed by</th>";
2523 $baseurl = makeHref(array('page'=>$pageno, 'tab'=>$tabno)) . $cellfilter['urlextra'];
2524 renderIPSpaceRecords ($tree, $baseurl, $eid);
2530 echo '</td><td class=pcright>';
2531 renderCellFilterPortlet ($cellfilter, $realm, $netlist);
2532 echo "</td></tr></table>\n";
2535 function renderIPSpaceEditor()
2538 $realm = ($pageno == 'ipv4space' ?
'ipv4net' : 'ipv6net');
2539 $net_page = $realm; // 'ipv4net', 'ipv6net'
2540 $addrspaceList = listCells ($realm);
2541 startPortlet ('Manage existing (' . count ($addrspaceList) . ')');
2542 if (count ($addrspaceList))
2544 echo "<table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
2545 echo "<tr><th> </th><th>prefix</th><th>name</th><th>capacity</th></tr>";
2546 foreach ($addrspaceList as $netinfo)
2548 echo "<tr valign=top><td>";
2549 if (! isIPNetworkEmpty ($netinfo))
2550 printImageHREF ('nodestroy', 'There are ' . count ($netinfo['addrlist']) . ' allocations inside');
2552 echo getOpLink (array ('op' => 'del', 'id' => $netinfo['id']), '', 'destroy', 'Delete this prefix');
2553 echo '</td><td class=tdleft>' . mkA ("${netinfo['ip']}/${netinfo['mask']}", $net_page, $netinfo['id']) . '</td>';
2554 echo '<td class=tdleft>' . niftyString ($netinfo['name']);
2555 if (count ($netinfo['etags']))
2556 echo '<br><small>' . serializeTags ($netinfo['etags']) . '</small>';
2558 echo getRenderedIPNetCapacity ($netinfo);
2566 function renderIPNewNetForm ()
2569 if ($pageno == 'ipv6space')
2572 $regexp = '^[a-fA-F0-9:]*:[a-fA-F0-9:\.]*/\d{1,3}$';
2577 $regexp = '^(\d{1,3}\.){3}\d{1,3}/\d{1,2}$';
2580 // IP prefix validator
2581 addJS ('js/live_validation.js');
2582 $regexp = addslashes ($regexp);
2584 $(document).ready(function () {
2585 $('form#add input[name="range"]').attr('match', '$regexp');
2591 startPortlet ('Add new');
2592 printOpFormIntro ('add');
2593 echo '<table border=0 cellpadding=5 cellspacing=0 align=center>';
2596 $prefix_value = empty ($_REQUEST['set-prefix']) ?
'' : $_REQUEST['set-prefix'];
2597 echo "<th class=tdright>Prefix:</th><td class=tdleft><input type=text name='range' size=36 class='live-validate' tabindex=1 value='${prefix_value}'></td>";
2598 echo '<tr><th class=tdright>VLAN:</th><td class=tdleft>';
2599 echo getOptionTree ('vlan_ck', getAllVLANOptions(), array ('select_class' => 'vertical', 'tabindex' => 2)) . '</td></tr>';
2600 echo "<tr><th class=tdright>Name:</th><td class=tdleft><input type=text name='name' size='20' tabindex=3></td></tr>";
2601 echo '<tr><th class=tdright>Tags:</th><td class="tdleft">';
2604 echo '<tr><td class=tdright><input type=checkbox name="is_connected" tabindex=4></td><th class=tdleft>reserve subnet-router anycast address</th></tr>';
2605 echo "<tr><td colspan=2>";
2606 printImageHREF ('CREATE', 'Add a new network', TRUE, 5);
2608 echo "</table></form><br><br>\n";
2612 function getRenderedIPNetBacktrace ($range)
2614 if (getConfigVar ('EXT_IPV4_VIEW') != 'yes')
2617 $v = ($range['realm'] == 'ipv4net') ?
4 : 6;
2618 $space = "ipv${v}space"; // ipv4space, ipv6space
2619 $tag = "\$ip${v}netid_"; // $ip4netid_, $ip6netid_
2622 // Build a backtrace from all parent networks.
2623 $clen = $range['mask'];
2624 $backtrace = array();
2625 $backtrace['→'] = $range;
2627 while (NULL !== ($upperid = getIPAddressNetworkId ($range['ip_bin'], $clen)))
2629 $upperinfo = spotEntity ($range['realm'], $upperid);
2630 $clen = $upperinfo['mask'];
2632 $backtrace[$key] = $upperinfo;
2634 foreach (array_reverse ($backtrace) as $arrow => $ainfo)
2636 $link = '<a href="' . makeHref (array (
2640 'cfe' => '{' . $tag . $ainfo['id'] . '}',
2642 'eid' => $range['id'],
2643 )) . '" title="View IP tree with this net as root">' . $arrow . '</a>';
2644 $ret[] = array ($link, getOutputOf ('renderCell', $ainfo));
2649 function renderIPNetwork ($id)
2652 $realm = $pageno; // 'ipv4net', 'ipv6net'
2653 $range = spotEntity ($realm, $id);
2654 loadIPAddrList ($range);
2655 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
2656 echo "<tr><td colspan=2 align=center><h1>${range['ip']}/${range['mask']}</h1><h2>";
2657 echo htmlspecialchars ($range['name'], ENT_QUOTES
, 'UTF-8') . "</h2></td></tr>\n";
2659 echo "<tr><td class=pcleft width='50%'>";
2661 // render summary portlet
2663 $summary['%% used'] = getRenderedIPNetCapacity ($range);
2664 $summary = getRenderedIPNetBacktrace ($range) +
$summary;
2665 if ($realm == 'ipv4net')
2667 $summary[] = array ('Netmask:', ip4_format ($range['mask_bin']));
2668 $summary[] = array ('Netmask:', "0x" . strtoupper (implode ('', unpack ('H*', $range['mask_bin']))));
2669 $summary['Wildcard bits'] = ip4_format ( ~
$range['mask_bin']);
2672 $reuse_domain = considerConfiguredConstraint ($range, '8021Q_MULTILINK_LISTSRC');
2673 $domainclass = array();
2674 foreach (array_count_values (reduceSubarraysToColumn ($range['8021q'], 'domain_id')) as $domain_id => $vlan_count)
2675 $domainclass[$domain_id] = $vlan_count == 1 ?
'' : ($reuse_domain ?
'{trwarning}' : '{trerror}');
2676 foreach ($range['8021q'] as $item)
2677 $summary[] = array ($domainclass[$item['domain_id']] . 'VLAN:', formatVLANAsHyperlink (getVLANInfo ($item['domain_id'] . '-' . $item['vlan_id'])));
2678 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes' and count ($routers = findRouters ($range['addrlist'])))
2680 $summary['Routed by'] = '';
2681 foreach ($routers as $rtr)
2682 $summary['Routed by'] .= getOutputOf ('renderRouterCell', $rtr['ip_bin'], $rtr['iface'], spotEntity ('object', $rtr['id']));
2684 $summary['tags'] = '';
2685 renderEntitySummary ($range, 'summary', $summary);
2687 if (strlen ($range['comment']))
2689 startPortlet ('Comment');
2690 echo '<div class=commentblock>' . string_insert_hrefs (htmlspecialchars ($range['comment'], ENT_QUOTES
, 'UTF-8')) . '</div>';
2694 renderFilesPortlet ($realm, $id);
2697 echo "<td class=pcright>";
2698 startPortlet ('details');
2699 renderIPNetworkAddresses ($range);
2701 echo "</td></tr></table>\n";
2704 // Used solely by renderSeparator
2705 function renderEmptyIPv6 ($ip_bin, $hl_ip)
2708 if ($ip_bin === $hl_ip)
2709 $class .= ' highlight';
2710 $fmt = ip6_format ($ip_bin);
2711 echo "<tr class='$class'><td><a name='ip-$fmt' href='" . makeHref (array ('page' => 'ipaddress', 'ip' => $fmt)) . "'>" . $fmt;
2712 $editable = permitted ('ipaddress', 'properties', 'editAddress')
2715 echo "</a></td><td><span class='rsvtext $editable id-$fmt op-upd-ip-name'></span></td>";
2716 echo "<td><span class='rsvtext $editable id-$fmt op-upd-ip-comment'></span></td><td> </td></tr>\n";
2719 // Renders empty table line to shrink empty IPv6 address ranges.
2720 // If the range consists of single address, renders the address instead of empty line.
2721 // Renders address $hl_ip inside the range.
2722 // Used solely by renderIPv6NetworkAddresses
2723 function renderSeparator ($first, $last, $hl_ip)
2725 $self = __FUNCTION__
;
2726 if (strcmp ($first, $last) > 0)
2728 if ($first == $last)
2729 renderEmptyIPv6 ($first, $hl_ip);
2730 elseif (isset ($hl_ip) && strcmp ($hl_ip, $first) >= 0 && strcmp ($hl_ip, $last) <= 0)
2731 { // $hl_ip is inside the range $first - $last
2732 $self ($first, ip_prev ($hl_ip), $hl_ip);
2733 renderEmptyIPv6 ($hl_ip, $hl_ip);
2734 $self (ip_next ($hl_ip), $last, $hl_ip);
2737 echo "<tr><td colspan=4 class=tdleft></td></tr>\n";
2740 // calculates page number that contains given $ip (used by renderIPv6NetworkAddresses)
2741 function getPageNumOfIPv6 ($list, $ip_bin, $maxperpage)
2743 if (intval ($maxperpage) <= 0 ||
count ($list) <= $maxperpage)
2745 $keys = array_keys ($list);
2746 for ($i = 1; $i <= count ($keys); $i++
)
2747 if (strcmp ($keys[$i-1], $ip_bin) >= 0)
2748 return intval ($i / $maxperpage);
2749 return intval (count ($list) / $maxperpage);
2752 function renderIPNetworkAddresses ($range)
2754 switch (strlen ($range['ip_bin']))
2756 case 4: return renderIPv4NetworkAddresses ($range);
2757 case 16: return renderIPv6NetworkAddresses ($range);
2758 default: throw new InvalidArgException ("range['ip_bin']", $range['ip_bin']);
2762 function renderIPv4NetworkAddresses ($range)
2764 global $pageno, $tabno, $aac2;
2765 $startip = ip4_bin2int ($range['ip_bin']);
2766 $endip = ip4_bin2int (ip_last ($range));
2768 if (isset ($_REQUEST['hl_ip']))
2770 $hl_ip = ip4_bin2int (ip4_parse ($_REQUEST['hl_ip']));
2771 addAutoScrollScript ('ip-' . $_REQUEST['hl_ip']); // scroll page to highlighted ip
2775 $maxperpage = getConfigVar ('IPV4_ADDRS_PER_PAGE');
2776 $address_count = $endip - $startip +
1;
2778 $rendered_pager = '';
2779 if ($address_count > $maxperpage && $maxperpage > 0)
2781 $page = isset ($_REQUEST['pg']) ?
$_REQUEST['pg'] : (isset ($hl_ip) ?
intval (($hl_ip - $startip) / $maxperpage) : 0);
2782 if ($numpages = ceil ($address_count / $maxperpage))
2784 echo '<h3>' . ip4_format (ip4_int2bin ($startip)) . ' ~ ' . ip4_format (ip4_int2bin ($endip)) . '</h3>';
2785 for ($i = 0; $i < $numpages; $i++
)
2787 $rendered_pager .= "<b>$i</b> ";
2789 $rendered_pager .= "<a href='".makeHref (array ('page' => $pageno, 'tab' => $tabno, 'id' => $range['id'], 'pg' => $i)) . "'>$i</a> ";
2791 $startip = $startip +
$page * $maxperpage;
2792 $endip = min ($startip +
$maxperpage - 1, $endip);
2795 echo $rendered_pager;
2796 echo "<table class='widetable' border=0 cellspacing=0 cellpadding=5 align='center' width='100%'>\n";
2797 echo "<tr><th>Address</th><th>Name</th><th>Comment</th><th>Allocation</th></tr>\n";
2799 markupIPAddrList ($range['addrlist']);
2800 for ($ip = $startip; $ip <= $endip; $ip++
)
2802 $ip_bin = ip4_int2bin ($ip);
2803 $dottedquad = ip4_format ($ip_bin);
2804 $tr_class = (isset ($hl_ip) && $hl_ip == $ip ?
'highlight' : '');
2805 if (isset ($range['addrlist'][$ip_bin]))
2806 $addr = $range['addrlist'][$ip_bin];
2809 echo "<tr class='tdleft $tr_class'><td class=tdleft><a name='ip-$dottedquad' href='" . makeHref(array(