a3072f0ce28c5230c03621f4a013d3dd904ad5d1
[racktables-incomplete-works] / wwwroot / inc / interface.php
1 <?php
2
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.
6
7 /*
8 *
9 * This file contains frontend functions for RackTables.
10 *
11 */
12
13 require_once 'ajax-interface.php';
14 require_once 'slb-interface.php';
15
16 // Interface function's special.
17 $nextorder['odd'] = 'even';
18 $nextorder['even'] = 'odd';
19
20 // address allocation type
21 $aat = array
22 (
23 'regular' => 'Connected',
24 'virtual' => 'Loopback',
25 'shared' => 'Shared',
26 'router' => 'Router',
27 );
28 // address allocation code, IPv4 addresses and objects view
29 $aac = array
30 (
31 'regular' => '',
32 'virtual' => '<span class="aac">L</span>',
33 'shared' => '<span class="aac">S</span>',
34 'router' => '<span class="aac">R</span>',
35 );
36 // address allocation code, IPv4 networks view
37 $aac2 = array
38 (
39 'regular' => '',
40 'virtual' => '<strong>L:</strong>',
41 'shared' => '<strong>S:</strong>',
42 'router' => '<strong>R:</strong>',
43 );
44
45 $vtdecoder = array
46 (
47 'ondemand' => '',
48 'compulsory' => 'P',
49 # 'alien' => 'NT',
50 );
51
52 $vtoptions = array
53 (
54 'ondemand' => 'auto',
55 'compulsory' => 'permanent',
56 # 'alien' => 'never touch',
57 );
58
59 // This may be populated later onsite, report rendering function will use it.
60 // See the $systemreport for structure.
61 $localreports = array();
62
63 $CodePressMap = array
64 (
65 'sql' => 'sql',
66 'php' => 'php',
67 'html' => 'htmlmixed',
68 'css' => 'css',
69 'js' => 'javascript',
70 );
71
72 $attrtypes = array
73 (
74 'uint' => '[U] unsigned integer',
75 'float' => '[F] floating point',
76 'string' => '[S] string',
77 'dict' => '[D] dictionary record',
78 'date' => '[T] date'
79 );
80
81 $quick_links = NULL; // you can override this in your local.php, but first initialize it with getConfiguredQuickLinks()
82
83 function renderQuickLinks()
84 {
85 global $quick_links;
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 (' ', '&nbsp;', $link['title']) . '</a></li>';
91 echo '</ul>';
92 }
93
94 function renderInterfaceHTML ($pageno, $tabno, $payload)
95 {
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(); ?>
100 </head>
101 <body>
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() ?>
106 </div>
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>
111 </div>
112 </body>
113 </html>
114 <?php
115 }
116
117 // Main menu.
118 function renderIndexItem ($ypageno)
119 {
120 echo (! permitted ($ypageno)) ? " <td>&nbsp;</td>\n" :
121 " <td>\n" .
122 " <h1><a href='" . makeHref (array ('page' => $ypageno)) . "'>" .
123 getPageName ($ypageno) . "<br>\n" . getImageHREF ($ypageno) .
124 "</a></h1>\n" .
125 " </td>\n";
126 }
127
128 function renderIndex ()
129 {
130 global $indexlayout;
131 ?>
132 <table border=0 cellpadding=0 cellspacing=0 width='100%'>
133 <tr>
134 <td>
135 <div style='text-align: center; margin: 10px; '>
136 <table width='100%' cellspacing=0 cellpadding=20 class=mainmenu border=0>
137 <?php
138 foreach ($indexlayout as $row)
139 {
140 echo '<tr>';
141 foreach ($row as $column)
142 if ($column === NULL)
143 echo '<td>&nbsp;</td>';
144 else
145 renderIndexItem ($column);
146 echo '</tr>';
147 }
148 ?>
149 </table>
150 </div>
151 </td>
152 </tr>
153 </table>
154 <?php
155 }
156
157 function getRenderedAlloc ($object_id, $alloc)
158 {
159 $ret = array
160 (
161 'tr_class' => '',
162 'td_name_suffix' => '',
163 'td_ip' => '',
164 'td_network' => '',
165 'td_routed_by' => '',
166 'td_peers' => '',
167 );
168 $dottedquad = $alloc['addrinfo']['ip'];
169 $ip_bin = $alloc['addrinfo']['ip_bin'];
170
171 $hl_ip_bin = NULL;
172 if (isset ($_REQUEST['hl_ip']))
173 {
174 $hl_ip_bin = ip_parse ($_REQUEST['hl_ip']);
175 addAutoScrollScript ("ip-" . $_REQUEST['hl_ip']);
176 }
177
178 $ret['tr_class'] = $alloc['addrinfo']['class'];
179 if ($hl_ip_bin === $ip_bin)
180 $ret['tr_class'] .= ' highlight';
181
182 // render IP change history
183 $ip_title = '';
184 $ip_class = '';
185 if (isset ($alloc['addrinfo']['last_log']))
186 {
187 $log = $alloc['addrinfo']['last_log'];
188 $ip_title = "title='" .
189 htmlspecialchars
190 (
191 $log['user'] . ', ' . formatAge ($log['time']),
192 ENT_QUOTES
193 ) . "'";
194 $ip_class = 'hover-history underline';
195 }
196
197 // render IP address td
198 global $aac;
199 $netinfo = spotNetworkByIP ($ip_bin);
200 $ret['td_ip'] = "<td class='tdleft'>";
201 if (isset ($netinfo))
202 {
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='" .
207 makeHref (
208 array
209 (
210 'page' => 'ipaddress',
211 'hl_object_id' => $object_id,
212 'ip' => $dottedquad,
213 )
214 ) . "'>$title</a>";
215 }
216 else
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>';
222
223 // render network and routed_by tds
224 $td_class = 'tdleft';
225 if (! isset ($netinfo))
226 {
227 $ret['td_network'] = "<td class='$td_class sparenetwork'>N/A</td>";
228 $ret['td_routed_by'] = $ret['td_network'];
229 }
230 else
231 {
232 $ret['td_network'] = "<td class='$td_class'>" .
233 getOutputOf ('renderCell', $netinfo) . '</td>';
234
235 // render "routed by" td
236 if ($display_routers = (getConfigVar ('IPV4_TREE_RTR_AS_CELL') == 'none'))
237 $ret['td_routed_by'] = '';
238 else
239 {
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);
247 else
248 $ret['td_routed_by'] = "<td class='$td_class'>&nbsp;</td>";
249 }
250 }
251
252 // render peers td
253 $ret['td_peers'] = "<td class='$td_class'>";
254 $prefix = '';
255 if ($alloc['addrinfo']['reserved'] == 'yes')
256 {
257 $ret['td_peers'] .= $prefix . '<strong>RESERVED</strong>';
258 $prefix = '; ';
259 }
260 foreach ($alloc['addrinfo']['allocs'] as $allocpeer)
261 {
262 if ($allocpeer['object_id'] == $object_id)
263 continue;
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>';
268 $prefix = '; ';
269 }
270 $ret['td_peers'] .= '</td>';
271
272 return $ret;
273 }
274
275 function renderLocationFilterPortlet ()
276 {
277 // Recursive function used to build the location tree
278 function renderLocationCheckbox ($subtree, $level = 0)
279 {
280 $self = __FUNCTION__;
281
282 foreach ($subtree as $location_id => $location)
283 {
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']}";
287 echo '</label>';
288 if ($location['kidc'])
289 {
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);
293 echo '</div>';
294 }
295 echo '</div>';
296 }
297 }
298
299 addJS(<<<END
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");
304 var in_tree = false;
305 for (var j=0; j<bxs.length; j++) {
306 if(in_tree == false && bxs[j].value == bx.value)
307 in_tree = true;
308 else if(parseInt(bxs[j].className) <= parseInt(bx.className))
309 in_tree = false;
310 if (bxs[j].type=="checkbox" && in_tree == true)
311 bxs[j].checked = bx.checked;
312 }
313 }
314 }
315
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++) {
322 var is_checked = -1;
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) {
328 is_checked = true;
329 break;
330 }
331 else
332 is_checked = false;
333 }
334 }
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));
338 }
339 }
340 }
341
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 = ' - ';
348 } else {
349 divid.style.display = 'none';
350 iconid.innerHTML = ' + ';
351 }
352 }
353 END
354 ,TRUE);
355 startPortlet ('Location filter');
356 echo <<<END
357 <table border=0 align=center cellspacing=0 class="tagtree" id="locationFilter">
358 <form method=post>
359 <input type=hidden name=page value=rackspace>
360 <input type=hidden name=tab value=default>
361 <input type=hidden name=changeLocationFilter value=true>
362 END;
363
364 $locationlist = listCells ('location');
365 if (count ($locationlist))
366 {
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";
374 echo '<tr><td>';
375 printImageHREF ('setfilter', 'set filter', TRUE);
376 echo "</td></tr>\n";
377 }
378 else
379 {
380 echo "<tr><td class='tagbox sparenetwork'>(no locations exist)</td></tr>\n";
381 echo "<tr><td>";
382 printImageHREF ('setfilter gray');
383 echo "</td></tr>\n";
384 }
385
386 echo "</form></table>\n";
387 finishPortlet ();
388 }
389
390 function renderRackspace ()
391 {
392 // Handle the location filter
393 @session_start();
394 if (isset ($_REQUEST['changeLocationFilter']))
395 unset ($_SESSION['locationFilter']);
396 if (isset ($_REQUEST['location_id']))
397 $_SESSION['locationFilter'] = $_REQUEST['location_id'];
398 session_commit();
399
400 echo "<table class=objview border=0 width='100%'><tr><td class=pcleft>";
401
402 $found_racks = array();
403 $cellfilter = getCellFilter();
404 if (! ($cellfilter['is_empty'] && !isset ($_SESSION['locationFilter']) && renderEmptyResults ($cellfilter, 'racks', getEntitiesCount ('rack'))))
405 {
406 $rows = array();
407 $rackCount = 0;
408 foreach (getAllRows() as $row_id => $rowInfo)
409 {
410 $rackList = applyCellFilter ('rack', $cellfilter, $row_id);
411 $found_racks = array_merge ($found_racks, $rackList);
412 $rows[] = array (
413 'location_id' => $rowInfo['location_id'],
414 'location_name' => $rowInfo['location_name'],
415 'row_id' => $row_id,
416 'row_name' => $rowInfo['name'],
417 'racks' => $rackList
418 );
419 $rackCount += count($rackList);
420 }
421
422 if (! renderEmptyResults($cellfilter, 'racks', $rackCount))
423 {
424 // generate thumb gallery
425 global $nextorder;
426 $rackwidth = getRackImageWidth();
427 // Zero value effectively disables the limit.
428 $maxPerRow = getConfigVar ('RACKS_PER_ROW');
429 $order = 'odd';
430 if (! count ($rows))
431 echo "<h2>No rows found</h2>\n";
432 else
433 {
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)
437 {
438 $location_id = $row['location_id'];
439 $row_id = $row['row_id'];
440 $row_name = $row['row_name'];
441 $rackList = $row['racks'];
442
443 if (
444 $location_id != '' and isset ($_SESSION['locationFilter']) and !in_array ($location_id, $_SESSION['locationFilter']) or
445 empty ($rackList) and ! $cellfilter['is_empty']
446 )
447 continue;
448 $rackListIdx = 0;
449 echo "<tr class=row_${order}><th class=tdleft>";
450 $locationIdx = 0;
451 $locationTree = '';
452 while ($location_id)
453 {
454 if ($locationIdx == 20)
455 {
456 showWarning ("Warning: There is likely a circular reference in the location tree. Investigate location ${location_id}.");
457 break;
458 }
459 $parentLocation = spotEntity ('location', $location_id);
460 $locationTree = "&raquo; <a href='" .
461 makeHref(array('page'=>'location', 'location_id'=>$parentLocation['id'])) .
462 "${cellfilter['urlextra']}'>${parentLocation['name']}</a> " .
463 $locationTree;
464 $location_id = $parentLocation['parent_id'];
465 $locationIdx++;
466 }
467 $locationTree = substr ($locationTree, 8);
468 echo $locationTree;
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>';
473 else
474 foreach ($rackList as $rack)
475 {
476 if ($rackListIdx > 0 and $maxPerRow > 0 and $rackListIdx % $maxPerRow == 0)
477 {
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>";
481 }
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>";
488 $rackListIdx++;
489 }
490 $order = $nextorder[$order];
491 echo "</tr></table></th></tr>\n";
492 }
493 echo "</table>\n";
494 }
495 }
496 }
497 echo '</td><td class=pcright width="25%">';
498 renderCellFilterPortlet ($cellfilter, 'rack', $found_racks);
499 echo "<br>\n";
500 renderLocationFilterPortlet ();
501 echo "</td></tr></table>\n";
502 }
503
504 function renderLocationRowForEditor ($subtree, $level = 0)
505 {
506 $self = __FUNCTION__;
507 foreach ($subtree as $locationinfo)
508 {
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');
514 else
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;
519 echo getSelect
520 (
521 array ( $parent => $parent ? htmlspecialchars ($locationinfo['parent_name']) : '-- NONE --'),
522 array ('name' => 'parent_id', 'id' => 'locationid_' . $locationinfo['id'], 'class' => 'locationlist-popup'),
523 $parent,
524 FALSE
525 );
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);
531 }
532 }
533
534 function renderLocationSelectTree ($selected_id = NULL)
535 {
536 echo '<option value=0>-- NONE --</option>';
537 $locationlist = listCells ('location');
538 foreach (treeFromList ($locationlist) as $location)
539 {
540 echo "<option value=${location['id']} style='font-weight: bold' ";
541 if ($location['id'] == $selected_id )
542 echo ' selected';
543 echo ">${location['name']}</option>";
544 printLocationChildrenSelectOptions ($location, 0, $selected_id);
545 }
546 echo '</select>';
547 }
548
549 function renderRackspaceLocationEditor ()
550 {
551 $js = <<<JSTXT
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);
555 }
556 $(document).ready(function () {
557 $('select.locationlist-popup').bind('mousedown', locationeditor_showselectbox);
558 });
559 JSTXT;
560
561 addJS($js, TRUE );
562 function printNewItemTR ()
563 {
564 printOpFormIntro ('addLocation');
565 echo '<tr><td>';
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";
572 }
573
574 startPortlet ('Locations');
575 echo "<table border=0 cellspacing=0 cellpadding=5 align=center class=widetable>\n";
576 echo "<tr><th>&nbsp;</th><th>Parent</th><th>Name</th><th>&nbsp;</th></tr>\n";
577 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
578 printNewItemTR();
579
580 $locations = listCells ('location');
581 renderLocationRowForEditor (treeFromList ($locations));
582
583 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
584 printNewItemTR();
585 echo "</table><br>\n";
586 finishPortlet();
587 }
588
589 function renderRackspaceRowEditor ()
590 {
591 function printNewItemTR ()
592 {
593 printOpFormIntro ('addRow');
594 echo '<tr><td>';
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>';
601 }
602 startPortlet ('Rows');
603 echo "<table border=0 cellspacing=0 cellpadding=5 align=center class=widetable>\n";
604 echo "<tr><th>&nbsp;</th><th>Location</th><th>Name</th><th>&nbsp;</th></tr>\n";
605 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
606 printNewItemTR ();
607 foreach (getAllRows() as $row_id => $rowInfo)
608 {
609 echo '<tr><td>';
610 if ($rc = $rowInfo['rackc'])
611 printImageHREF ('nodestroy', "${rc} rack(s) here");
612 else
613 echo getOpLink (array('op'=>'deleteRow', 'row_id'=>$row_id), '', 'destroy', 'Delete row');
614 printOpFormIntro ('updateRow', array ('row_id' => $row_id));
615 echo '</td><td>';
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";
621 }
622 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
623 printNewItemTR ();
624 echo "</table><br>\n";
625 finishPortlet();
626 }
627
628 function renderRow ($row_id)
629 {
630 $rowInfo = getRowInfo ($row_id);
631 $cellfilter = getCellFilter();
632 $rackList = applyCellFilter ('rack', $cellfilter, $row_id);
633 // Main layout starts.
634 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
635
636 // Left portlet with row information.
637 echo "<tr><td class=pcleft>";
638 startPortlet ($rowInfo['name']);
639 echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
640 if ($rowInfo['location_id'])
641 echo "<tr><th width='50%' class=tdright>Location:</th><td class=tdleft>".mkA ($rowInfo['location'], 'location', $rowInfo['location_id'])."</td></tr>\n";
642 echo "<tr><th width='50%' class=tdright>Racks:</th><td class=tdleft>${rowInfo['count']}</td></tr>\n";
643 echo "<tr><th width='50%' class=tdright>Units:</th><td class=tdleft>${rowInfo['sum']}</td></tr>\n";
644 echo "<tr><th width='50%' class=tdright>% used:</th><td class=tdleft>";
645 renderProgressBar (getRSUforRow ($rackList));
646 echo "</td></tr>\n";
647 echo "</table><br>\n";
648 finishPortlet();
649 renderCellFilterPortlet ($cellfilter, 'rack', $rackList, array ('row_id' => $row_id));
650
651 renderFilesPortlet ('row',$row_id);
652 echo "</td><td class=pcright>";
653
654 global $nextorder;
655 $rackwidth = getRackImageWidth() * getConfigVar ('ROW_SCALE');
656 // Maximum number of racks per row is proportionally less, but at least 1.
657 $maxPerRow = max (floor (getConfigVar ('RACKS_PER_ROW') / getConfigVar ('ROW_SCALE')), 1);
658 $rackListIdx = 0;
659 $order = 'odd';
660 startPortlet ('Racks');
661 echo "<table border=0 cellspacing=5 align='center'><tr>";
662 foreach ($rackList as $rack)
663 {
664 if ($rackListIdx % $maxPerRow == 0)
665 {
666 if ($rackListIdx > 0)
667 echo '</tr>';
668 echo '<tr>';
669 }
670 $class = ($rack['has_problems'] == 'yes') ? 'error' : $order;
671 echo "<td align=center valign=bottom class=row_${class}><a href='".makeHref(array('page'=>'rack', 'rack_id'=>$rack['id']))."'>";
672 echo "<img border=0 width=${rackwidth} height=" . (getRackImageHeight ($rack['height']) * getConfigVar ('ROW_SCALE'));
673 echo " title='${rack['height']} units'";
674 echo "src='?module=image&img=midirack&rack_id=${rack['id']}&scale=" . getConfigVar ('ROW_SCALE') . "'>";
675 echo "<br>${rack['name']}</a></td>";
676 $order = $nextorder[$order];
677 $rackListIdx++;
678 }
679 echo "</tr></table>\n";
680 finishPortlet();
681 echo "</td></tr></table>";
682 }
683
684 // Used by renderRack()
685 function printObjectDetailsForRenderRack ($object_id, $hl_obj_id = 0)
686 {
687 $objectData = spotEntity ('object', $object_id);
688 if (strlen ($objectData['asset_no']))
689 $prefix = "<div title='${objectData['asset_no']}";
690 else
691 $prefix = "<div title='no asset tag";
692 // Don't tell about label, if it matches common name.
693 $body = '';
694 if ($objectData['name'] != $objectData['label'] and strlen ($objectData['label']))
695 $body = ", visible label is \"${objectData['label']}\"";
696 // Display list of child objects, if any
697 $objectChildren = getEntityRelatives ('children', 'object', $objectData['id']);
698 $slotRows = $slotCols = $slotInfo = $slotData = $slotTitle = $slotClass = array ();
699 if (count($objectChildren) > 0)
700 {
701 foreach ($objectChildren as $child)
702 {
703 $childNames[] = $child['name'];
704 $childData = spotEntity ('object', $child['entity_id']);
705 $attrData = getAttrValues ($child['entity_id']);
706 $numRows = $numCols = 1;
707 if (isset ($attrData[2])) // HW type
708 {
709 extractLayout ($attrData[2]);
710 if (isset ($attrData[2]['rows']))
711 {
712 $numRows = $attrData[2]['rows'];
713 $numCols = $attrData[2]['cols'];
714 }
715 }
716 if (isset ($attrData['28'])) // slot number
717 {
718 $slot = $attrData['28']['value'];
719 if (preg_match ('/\d+/', $slot, $matches))
720 $slot = $matches[0];
721 $slotRows[$slot] = $numRows;
722 $slotCols[$slot] = $numCols;
723 $slotInfo[$slot] = $child['name'];
724 $slotData[$slot] = $child['entity_id'];
725 if (strlen ($childData['asset_no']))
726 $slotTitle[$slot] = "<div title='${childData['asset_no']}";
727 else
728 $slotTitle[$slot] = "<div title='no asset tag";
729 if (strlen ($childData['label']) and $childData['label'] != $child['name'])
730 $slotTitle[$slot] .= ", visible label is \"${childData['label']}\"";
731 $slotTitle[$slot] .= "'>";
732 $slotClass[$slot] = 'state_T';
733 if ($childData['has_problems'] == 'yes')
734 $slotClass[$slot] = 'state_Tw';
735 if ($child['entity_id'] == $hl_obj_id)
736 $slotClass[$slot] = 'state_Th';
737 }
738 }
739 natsort($childNames);
740 $suffix = sprintf(", contains %s'>", implode(', ', $childNames));
741 }
742 else
743 $suffix = "'>";
744 echo "${prefix}${body}${suffix}" . mkA ($objectData['dname'], 'object', $objectData['id']) . '</div>';
745 if (in_array ($objectData['objtype_id'], array (1502,1503))) // server chassis, network chassis
746 {
747 $objAttr = getAttrValues ($objectData['id']);
748 if (isset ($objAttr[2])) // HW type
749 {
750 extractLayout ($objAttr[2]);
751 if (isset ($objAttr[2]['rows']))
752 {
753 $rows = $objAttr[2]['rows'];
754 $cols = $objAttr[2]['cols'];
755 $layout = $objAttr[2]['layout'];
756 echo "<table width='100%' border='1'>";
757 for ($r = 0; $r < $rows; $r++)
758 {
759 echo '<tr>';
760 for ($c = 0; $c < $cols; $c++)
761 {
762 $s = ($r * $cols) + $c + 1;
763 if (isset ($slotData[$s]))
764 {
765 if ($slotData[$s] >= 0)
766 {
767 for ($lr = 0; $lr < $slotRows[$s]; $lr++)
768 for ($lc = 0; $lc < $slotCols[$s]; $lc++)
769 {
770 $skip = ($lr * $cols) + $lc;
771 if ($skip > 0)
772 $slotData[$s + $skip] = -1;
773 }
774 echo '<td';
775 if ($slotRows[$s] > 1)
776 echo " rowspan=$slotRows[$s]";
777 if ($slotCols[$s] > 1)
778 echo " colspan=$slotCols[$s]";
779 echo " class='${slotClass[$s]}'>${slotTitle[$s]}";
780 if ($layout == 'V')
781 {
782 $tmp = substr ($slotInfo[$s], 0, 1);
783 foreach (str_split (substr ($slotInfo[$s], 1)) as $letter)
784 $tmp .= '<br>' . $letter;
785 $slotInfo[$s] = $tmp;
786 }
787 echo mkA ($slotInfo[$s], 'object', $slotData[$s]);
788 echo '</div></td>';
789 }
790 }
791 else
792 echo "<td class='state_F'><div title=\"Free slot\">&nbsp;</div></td>";
793 }
794 echo '</tr>';
795 }
796 echo '</table>';
797 }
798 }
799 }
800 }
801
802 // This function renders rack as HTML table.
803 function renderRack ($rack_id, $hl_obj_id = 0)
804 {
805 $rackData = spotEntity ('rack', $rack_id);
806 amplifyCell ($rackData);
807 markAllSpans ($rackData);
808 if ($hl_obj_id > 0)
809 highlightObject ($rackData, $hl_obj_id);
810 $prev_id = getPrevIDforRack ($rackData['row_id'], $rack_id);
811 $next_id = getNextIDforRack ($rackData['row_id'], $rack_id);
812 echo "<center><table border=0><tr valign=middle>";
813 echo '<td><h2>' . mkA ($rackData['row_name'], 'row', $rackData['row_id']) . ' :</h2></td>';
814 if ($prev_id != NULL)
815 echo '<td>' . mkA (getImageHREF ('prev', 'previous rack'), 'rack', $prev_id) . '</td>';
816 echo '<td><h2>' . mkA ($rackData['name'], 'rack', $rackData['id']) . '</h2></td>';
817 if ($next_id != NULL)
818 echo '<td>' . mkA (getImageHREF ('next', 'next rack'), 'rack', $next_id) . '</td>';
819 echo "</h2></td></tr></table>\n";
820 echo "<table class=rack border=0 cellspacing=0 cellpadding=1>\n";
821 echo "<tr><th width='10%'>&nbsp;</th><th width='20%'>Front</th>";
822 echo "<th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n";
823 for ($i = $rackData['height']; $i > 0; $i--)
824 {
825 echo "<tr><th>" . inverseRackUnit ($i, $rackData) . "</th>";
826 for ($locidx = 0; $locidx < 3; $locidx++)
827 {
828 if (isset ($rackData[$i][$locidx]['skipped']))
829 continue;
830 $state = $rackData[$i][$locidx]['state'];
831 echo "<td class='atom state_${state}";
832 if (isset ($rackData[$i][$locidx]['hl']))
833 echo $rackData[$i][$locidx]['hl'];
834 echo "'";
835 if (isset ($rackData[$i][$locidx]['colspan']))
836 echo ' colspan=' . $rackData[$i][$locidx]['colspan'];
837 if (isset ($rackData[$i][$locidx]['rowspan']))
838 echo ' rowspan=' . $rackData[$i][$locidx]['rowspan'];
839 echo ">";
840 switch ($state)
841 {
842 case 'T':
843 printObjectDetailsForRenderRack ($rackData[$i][$locidx]['object_id'], $hl_obj_id);
844 break;
845 case 'A':
846 echo '<div title="This rackspace does not exist">&nbsp;</div>';
847 break;
848 case 'F':
849 echo '<div title="Free rackspace">&nbsp;</div>';
850 break;
851 case 'U':
852 echo '<div title="Problematic rackspace, you CAN\'T mount here">&nbsp;</div>';
853 break;
854 default:
855 echo '<div title="No data">&nbsp;</div>';
856 break;
857 }
858 echo '</td>';
859 }
860 echo "</tr>\n";
861 }
862 echo "</table>\n";
863 // Get a list of all of objects Zero-U mounted to this rack
864 $zeroUObjects = getEntityRelatives('children', 'rack', $rack_id);
865 if (count ($zeroUObjects) > 0)
866 {
867 echo "<br><table width='75%' class=rack border=0 cellspacing=0 cellpadding=1>\n";
868 echo "<tr><th>Zero-U:</th></tr>\n";
869 foreach ($zeroUObjects as $zeroUObject)
870 {
871 $state = ($zeroUObject['entity_id'] == $hl_obj_id) ? 'Th' : 'T';
872 echo "<tr><td class='atom state_${state}'>";
873 printObjectDetailsForRenderRack($zeroUObject['entity_id']);
874 echo "</td></tr>\n";
875 }
876 echo "</table>\n";
877 }
878 echo "</center>\n";
879 }
880
881 function renderRackSortForm ($row_id)
882 {
883 includeJQueryUI (false);
884 $js = <<<JSTXT
885 $(document).ready(
886 function () {
887 $("#sortRacks").sortable({
888 update : function () {
889 serial = $('#sortRacks').sortable('serialize');
890 $.ajax({
891 url: 'index.php?module=ajax&ac=upd-rack-sort-order',
892 type: 'post',
893 data: serial,
894 });
895 }
896 });
897 }
898 );
899 JSTXT;
900 addJS($js, true);
901
902 startPortlet ('Racks');
903 echo "<table border=0 cellspacing=0 cellpadding=5 align=center class=widetable>\n";
904 echo "<tr><th>Drag to change order</th></tr>\n";
905 echo "<tr><td><ul class='uflist' id='sortRacks'>\n";
906 foreach (getRacks($row_id) as $rack_id => $rackInfo)
907 echo "<li id=racks_${rack_id}>${rackInfo['name']}</li>\n";
908 echo "</ul></td></tr></table>\n";
909 finishPortlet();
910 }
911
912 function renderNewRackForm ($row_id)
913 {
914 $default_height = getConfigVar ('DEFAULT_RACK_HEIGHT');
915 if ($default_height == 0)
916 $default_height = '';
917 startPortlet ('Add one');
918 printOpFormIntro ('addRack', array ('got_data' => 'TRUE'));
919 echo '<table border=0 align=center>';
920 echo "<tr><th class=tdright>Name (required):</th><td class=tdleft><input type=text name=name tabindex=1></td>";
921 echo "<td rowspan=4>Tags:<br>";
922 printTagsPicker ();
923 echo "</td></tr>\n";
924 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";
925 echo "<tr><th class=tdright>Asset tag:</th><td class=tdleft><input type=text name=asset_no tabindex=4></td></tr>\n";
926 echo "<tr><td class=submit colspan=2>";
927 printImageHREF ('CREATE', 'Add', TRUE);
928 echo "</td></tr></table></form>";
929 finishPortlet();
930
931 startPortlet ('Add many');
932 printOpFormIntro ('addRack', array ('got_mdata' => 'TRUE'));
933 echo '<table border=0 align=center>';
934 echo "<tr><th class=tdright>Height in units (*):</th><td class=tdleft><input type=text name=height2 value='${default_height}'></td>";
935 echo "<td rowspan=3 valign=top>Assign tags:<br>";
936 printTagsPicker ();
937 echo "</td></tr>\n";
938 echo "<tr><th class=tdright>Rack names (required):</th><td class=tdleft><textarea name=names cols=40 rows=25></textarea></td></tr>\n";
939 echo "<tr><td class=submit colspan=2>";
940 printImageHREF ('CREATE', 'Add', TRUE);
941 echo '</form></table>';
942 finishPortlet();
943 }
944
945 function renderEditObjectForm()
946 {
947 global $pageno;
948 $object_id = getBypassValue();
949 $object = spotEntity ('object', $object_id);
950 startPortlet ();
951 printOpFormIntro ('update');
952
953 // static attributes
954 echo '<table border=0 cellspacing=0 cellpadding=3 align=center>';
955 echo "<tr><td>&nbsp;</td><th colspan=2><h2>Attributes</h2></th></tr>";
956 echo '<tr><td>&nbsp;</td><th class=tdright>Type:</th><td class=tdleft>';
957 printSelect (getObjectTypeChangeOptions ($object['id']), array ('name' => 'object_type_id'), $object['objtype_id']);
958 echo '</td></tr>';
959 // baseline info
960 echo "<tr><td>&nbsp;</td><th class=tdright>Common name:</th><td class=tdleft><input type=text name=object_name value='${object['name']}'></td></tr>\n";
961 echo "<tr><td>&nbsp;</td><th class=tdright>Visible label:</th><td class=tdleft><input type=text name=object_label value='${object['label']}'></td></tr>\n";
962 echo "<tr><td>&nbsp;</td><th class=tdright>Asset tag:</th><td class=tdleft><input type=text name=object_asset_no value='${object['asset_no']}'></td></tr>\n";
963 echo "<tr><td>&nbsp;</td><th class=tdright>Tags:</th><td class=tdleft>";
964 printTagsPicker ();
965 echo "</td></tr>\n";
966 // parent selection
967 if (objectTypeMayHaveParent ($object['objtype_id']))
968 {
969 $parents = getEntityRelatives ('parents', 'object', $object_id);
970 foreach ($parents as $link_id => $parent_details)
971 {
972 if (!isset($label))
973 $label = count($parents) > 1 ? 'Containers:' : 'Container:';
974 echo "<tr><td>&nbsp;</td>";
975 echo "<th class=tdright>${label}</th><td class=tdleft>";
976 echo mkA ($parent_details['name'], 'object', $parent_details['entity_id']);
977 echo "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
978 echo getOpLink (array('op'=>'unlinkObjects', 'link_id'=>$link_id), '', 'cut', 'Unlink container');
979 echo "</td></tr>\n";
980 $label = '&nbsp;';
981 }
982 echo "<tr><td>&nbsp;</td>";
983 echo "<th class=tdright>Select container:</th><td class=tdleft>";
984 echo "<span";
985 $helper_args = array ('object_id' => $object_id);
986 $popup_args = 'height=700, width=400, location=no, menubar=no, '.
987 'resizable=yes, scrollbars=yes, status=no, titlebar=no, toolbar=no';
988 echo " onclick='window.open(\"" . makeHrefForHelper ('objlist', $helper_args);
989 echo "\",\"findlink\",\"${popup_args}\");'>";
990 printImageHREF ('attach', 'Select a container');
991 echo "</span></td></tr>\n";
992 }
993 // optional attributes
994 $i = 0;
995 $values = getAttrValues ($object_id);
996 if (count($values) > 0)
997 {
998 foreach ($values as $record)
999 {
1000 if (! permitted (NULL, NULL, NULL, array (
1001 array ('tag' => '$attr_' . $record['id']),
1002 array ('tag' => '$any_op'),
1003 )))
1004 continue;
1005 echo "<input type=hidden name=${i}_attr_id value=${record['id']}>";
1006 echo '<tr><td>';
1007 if (strlen ($record['value']))
1008 echo getOpLink (array('op'=>'clearSticker', 'attr_id'=>$record['id']), '', 'clear', 'Clear value', 'need-confirmation');
1009 else
1010 echo '&nbsp;';
1011 echo '</td>';
1012 echo "<th class=sticker>${record['name']}";
1013 if ($record['type'] == 'date')
1014 echo ' (' . datetimeFormatHint (getConfigVar ('DATETIME_FORMAT')) . ')';
1015 echo ':</th><td class=tdleft>';
1016 switch ($record['type'])
1017 {
1018 case 'uint':
1019 case 'float':
1020 case 'string':
1021 echo "<input type=text name=${i}_value value='${record['value']}'>";
1022 break;
1023 case 'dict':
1024 $chapter = readChapter ($record['chapter_id'], 'o');
1025 $chapter[0] = '-- NOT SET --';
1026 $chapter = cookOptgroups ($chapter, $object['objtype_id'], $record['key']);
1027 printNiftySelect ($chapter, array ('name' => "${i}_value"), $record['key']);
1028 break;
1029 case 'date':
1030 $date_value = $record['value'] ? datetimestrFromTimestamp ($record['value']) : '';
1031 echo "<input type=text name=${i}_value value='${date_value}'>";
1032 break;
1033 }
1034 echo "</td></tr>\n";
1035 $i++;
1036 }
1037 }
1038 echo '<input type=hidden name=num_attrs value=' . $i . ">\n";
1039 echo "<tr><td>&nbsp;</td><th class=tdright>Has problems:</th><td class=tdleft><input type=checkbox name=object_has_problems";
1040 if ($object['has_problems'] == 'yes')
1041 echo ' checked';
1042 echo "></td></tr>\n";
1043 echo "<tr><td>&nbsp;</td><th class=tdright>Actions:</th><td class=tdleft>";
1044 echo getOpLink (array ('op'=>'deleteObject', 'page'=>'depot', 'tab'=>'addmore', 'object_id'=>$object_id), '' ,'destroy', 'Delete object', 'need-confirmation');
1045 echo "&nbsp;";
1046 echo getOpLink (array ('op'=>'resetObject'), '' ,'clear', 'Reset (cleanup) object', 'need-confirmation');
1047 echo "</td></tr>\n";
1048 echo "<tr><td colspan=3><b>Comment:</b><br><textarea name=object_comment rows=10 cols=80>${object['comment']}</textarea></td></tr>";
1049
1050 echo "<tr><th class=submit colspan=3>";
1051 printImageHREF ('SAVE', 'Save changes', TRUE);
1052 echo "</form></th></tr></table>\n";
1053 finishPortlet();
1054
1055 echo '<table border=0 width=100%><tr><td>';
1056 startPortlet ('history');
1057 renderObjectHistory ($object_id);
1058 finishPortlet();
1059 echo '</td></tr></table>';
1060 }
1061
1062 function renderEditRackForm ($rack_id)
1063 {
1064 global $pageno;
1065 $rack = spotEntity ('rack', $rack_id);
1066 amplifyCell ($rack);
1067
1068 startPortlet ('Attributes');
1069 printOpFormIntro ('updateRack');
1070 echo '<table border=0 align=center>';
1071 echo "<tr><td>&nbsp;</td><th class=tdright>Rack row:</th><td class=tdleft>";
1072 foreach (getAllRows () as $row_id => $rowInfo)
1073 {
1074 $trail = getLocationTrail ($rowInfo['location_id'], FALSE);
1075 $rows[$row_id] = empty ($trail) ? $rowInfo['name'] : $rowInfo['name'] . ' [' . $trail . ']';
1076 }
1077 natcasesort ($rows);
1078 printSelect ($rows, array ('name' => 'row_id'), $rack['row_id']);
1079 echo "</td></tr>\n";
1080 echo "<tr><td>&nbsp;</td><th class=tdright>Name (required):</th><td class=tdleft><input type=text name=name value='${rack['name']}'></td></tr>\n";
1081 echo "<tr><td>&nbsp;</td><th class=tdright>Height (required):</th><td class=tdleft><input type=text name=height value='${rack['height']}'></td></tr>\n";
1082 echo "<tr><td>&nbsp;</td><th class=tdright>Asset tag:</th><td class=tdleft><input type=text name=asset_no value='${rack['asset_no']}'></td></tr>\n";
1083 echo "<tr><td>&nbsp;</td><th class=tdright>Tags:</th><td class=tdleft>";
1084 printTagsPicker ();
1085 echo "</td></tr>\n";
1086 // optional attributes
1087 $values = getAttrValues ($rack_id);
1088 $num_attrs = count($values);
1089 $num_attrs = $num_attrs-2; // subtract for the 'height' and 'sort_order' attributes
1090 echo "<input type=hidden name=num_attrs value=${num_attrs}>\n";
1091 $i = 0;
1092 foreach ($values as $record)
1093 {
1094 // Skip the 'height' attribute as it's already displayed as a required field
1095 // Also skip the 'sort_order' attribute
1096 if ($record['id'] == 27 or $record['id'] == 29)
1097 continue;
1098 echo "<input type=hidden name=${i}_attr_id value=${record['id']}>";
1099 echo '<tr><td>';
1100 if (strlen ($record['value']))
1101 echo getOpLink (array('op'=>'clearSticker', 'attr_id'=>$record['id']), '', 'clear', 'Clear value', 'need-confirmation');
1102 else
1103 echo '&nbsp;';
1104 echo '</td>';
1105 echo "<th class=sticker>${record['name']}:</th><td class=tdleft>";
1106 switch ($record['type'])
1107 {
1108 case 'uint':
1109 case 'float':
1110 case 'string':
1111 echo "<input type=text name=${i}_value value='${record['value']}'>";
1112 break;
1113 case 'dict':
1114 $chapter = readChapter ($record['chapter_id'], 'o');
1115 $chapter[0] = '-- NOT SET --';
1116 $chapter = cookOptgroups ($chapter, 1560, $record['key']);
1117 printNiftySelect ($chapter, array ('name' => "${i}_value"), $record['key']);
1118 break;
1119 }
1120 echo "</td></tr>\n";
1121 $i++;
1122 }
1123 echo "<tr><td>&nbsp;</td><th class=tdright>Has problems:</th><td class=tdleft><input type=checkbox name=has_problems";
1124 if ($rack['has_problems'] == 'yes')
1125 echo ' checked';
1126 echo "></td></tr>\n";
1127 if ($rack['isDeletable'])
1128 {
1129 echo "<tr><td>&nbsp;</td><th class=tdright>Actions:</th><td class=tdleft>";
1130 echo getOpLink (array ('op'=>'deleteRack'), '', 'destroy', 'Delete rack', 'need-confirmation');
1131 echo "&nbsp;</td></tr>\n";
1132 }
1133 echo "<tr><td colspan=3><b>Comment:</b><br><textarea name=comment rows=10 cols=80>${rack['comment']}</textarea></td></tr>";
1134 echo "<tr><td class=submit colspan=3>";
1135 printImageHREF ('SAVE', 'Save changes', TRUE);
1136 echo "</td></tr>\n";
1137 echo '</form></table><br>';
1138 finishPortlet();
1139
1140 startPortlet ('History');
1141 renderObjectHistory ($rack_id);
1142 finishPortlet();
1143 }
1144
1145 // used by renderGridForm() and renderRackPage()
1146 function renderRackInfoPortlet ($rackData)
1147 {
1148 $summary = array();
1149 $summary['Rack row'] = mkA ($rackData['row_name'], 'row', $rackData['row_id']);
1150 $summary['Name'] = $rackData['name'];
1151 $summary['Height'] = $rackData['height'];
1152 if (strlen ($rackData['asset_no']))
1153 $summary['Asset tag'] = $rackData['asset_no'];
1154 if ($rackData['has_problems'] == 'yes')
1155 $summary[] = array ('<tr><td colspan=2 class=msg_error>Has problems</td></tr>');
1156 // Display populated attributes, but skip 'height' since it's already displayed above
1157 // and skip 'sort_order' because it's modified using AJAX
1158 foreach (getAttrValues ($rackData['id']) as $record)
1159 if ($record['id'] != 27 && $record['id'] != 29 && strlen ($record['value']))
1160 $summary['{sticker}' . $record['name']] = formatAttributeValue ($record);
1161 $summary['% used'] = getProgressBar (getRSUforRack ($rackData));
1162 $summary['Objects'] = count ($rackData['mountedObjects']);
1163 $summary['tags'] = '';
1164 if (strlen ($rackData['comment']))
1165 $summary['Comment'] = $rackData['comment'];
1166 renderEntitySummary ($rackData, 'summary', $summary);
1167 }
1168
1169 // This is a universal editor of rack design/waste.
1170 // FIXME: switch to using printOpFormIntro()
1171 function renderGridForm ($rack_id, $filter, $header, $submit, $state1, $state2)
1172 {
1173 $rackData = spotEntity ('rack', $rack_id);
1174 amplifyCell ($rackData);
1175 $filter ($rackData);
1176
1177 // Render the result whatever it is.
1178 // Main layout.
1179 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
1180 echo "<tr><td colspan=2 align=center><h1>${rackData['name']}</h1></td></tr>\n";
1181
1182 // Left column with information portlet.
1183 echo "<tr><td class=pcleft height='1%' width='50%'>";
1184 renderRackInfoPortlet ($rackData);
1185 echo "</td>\n";
1186 echo "<td class=pcright>";
1187
1188 // Grid form.
1189 startPortlet ($header);
1190 addJS ('js/racktables.js');
1191 echo "<center>\n";
1192 echo "<table class=rack border=0 cellspacing=0 cellpadding=1>\n";
1193 echo "<tr><th width='10%'>&nbsp;</th>";
1194 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '0', ${rackData['height']})\">Front</a></th>";
1195 echo "<th width='50%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '1', ${rackData['height']})\">Interior</a></th>";
1196 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '2', ${rackData['height']})\">Back</a></th></tr>\n";
1197 printOpFormIntro ('updateRack');
1198 markupAtomGrid ($rackData, $state2);
1199 renderAtomGrid ($rackData);
1200 echo "</table></center>\n";
1201 echo "<br><input type=submit name=do_update value='${submit}'></form><br><br>\n";
1202 finishPortlet();
1203 echo "</td></tr></table>\n";
1204 }
1205
1206 function renderRackDesign ($rack_id)
1207 {
1208 renderGridForm ($rack_id, 'applyRackDesignMask', 'Rack design', 'Set rack design', 'A', 'F');
1209 }
1210
1211 function renderRackProblems ($rack_id)
1212 {
1213 renderGridForm ($rack_id, 'applyRackProblemMask', 'Rack problems', 'Mark unusable atoms', 'F', 'U');
1214 }
1215
1216 function renderObjectPortRow ($port, $is_highlighted)
1217 {
1218 echo '<tr';
1219 if ($is_highlighted)
1220 echo ' class=highlight';
1221 $a_class = isEthernetPort ($port) ? 'port-menu' : '';
1222 echo "><td class='tdleft' NOWRAP><a name='port-${port['id']}' class='interactive-portname nolink $a_class'>${port['name']}</a></td>";
1223 echo "<td class=tdleft>${port['label']}</td>";
1224 echo "<td class=tdleft>" . formatPortIIFOIF ($port) . "</td><td class=tdleft><tt>${port['l2address']}</tt></td>";
1225 if ($port['remote_object_id'])
1226 {
1227 echo "<td class=tdleft>" .
1228 formatPortLink ($port['remote_object_id'], $port['remote_object_name'], $port['remote_id'], NULL) .
1229 "</td>";
1230 echo "<td class=tdleft>" . formatLoggedSpan ($port['last_log'], $port['remote_name'], 'underline') . "</td>";
1231 $editable = permitted ('object', 'ports', 'editPort')
1232 ? 'editable'
1233 : '';
1234 echo "<td class=tdleft><span class='rsvtext $editable id-${port['id']} op-upd-reservation-cable'>${port['cableid']}</span></td>";
1235 }
1236 else
1237 echo implode ('', formatPortReservation ($port)) . '<td></td>';
1238 echo "</tr>";
1239 }
1240
1241 function renderObject ($object_id)
1242 {
1243 global $nextorder, $virtual_obj_types;
1244 $info = spotEntity ('object', $object_id);
1245 amplifyCell ($info);
1246 // Main layout starts.
1247 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
1248 echo "<tr><td colspan=2 align=center><h1>${info['dname']}</h1></td></tr>\n";
1249 // left column with uknown number of portlets
1250 echo "<tr><td class=pcleft>";
1251
1252 // display summary portlet
1253 $summary = array();
1254 if (strlen ($info['name']))
1255 $summary['Common name'] = $info['name'];
1256 elseif (considerConfiguredConstraint ($info, 'NAMEWARN_LISTSRC'))
1257 $summary[] = array ('<tr><td colspan=2 class=msg_error>Common name is missing.</td></tr>');
1258 $summary['Object type'] = '<a href="' . makeHref (array (
1259 'page' => 'depot',
1260 'tab' => 'default',
1261 'cfe' => '{$typeid_' . $info['objtype_id'] . '}'
1262 )) . '">' . decodeObjectType ($info['objtype_id'], 'o') . '</a>';
1263 if (strlen ($info['label']))
1264 $summary['Visible label'] = $info['label'];
1265 if (strlen ($info['asset_no']))
1266 $summary['Asset tag'] = $info['asset_no'];
1267 elseif (considerConfiguredConstraint ($info, 'ASSETWARN_LISTSRC'))
1268 $summary[] = array ('<tr><td colspan=2 class=msg_error>Asset tag is missing.</td></tr>');
1269 $parents = getEntityRelatives ('parents', 'object', $object_id);
1270 if (count ($parents))
1271 {
1272 $fmt_parents = array();
1273 foreach ($parents as $parent)
1274 $fmt_parents[] = "<a href='".makeHref(array('page'=>$parent['page'], $parent['id_name'] => $parent['entity_id']))."'>${parent['name']}</a>";
1275 $summary[count($parents) > 1 ? 'Containers' : 'Container'] = implode ('<br>', $fmt_parents);
1276 }
1277 $children = getEntityRelatives ('children', 'object', $object_id);
1278 if (count ($children))
1279 {
1280 $fmt_children = array();
1281 foreach ($children as $child)
1282 $fmt_children[] = "<a href='".makeHref(array('page'=>$child['page'], $child['id_name']=>$child['entity_id']))."'>${child['name']}</a>";
1283 $summary['Contains'] = implode ('<br>', $fmt_children);
1284 }
1285 if ($info['has_problems'] == 'yes')
1286 $summary[] = array ('<tr><td colspan=2 class=msg_error>Has problems</td></tr>');
1287 foreach (getAttrValues ($object_id) as $record)
1288 if
1289 (
1290 strlen ($record['value']) and
1291 permitted (NULL, NULL, NULL, array (array ('tag' => '$attr_' . $record['id'])))
1292 )
1293 $summary['{sticker}' . $record['name']] = formatAttributeValue ($record);
1294 $summary[] = array (getOutputOf ('printTagTRs',
1295 $info,
1296 makeHref
1297 (
1298 array
1299 (
1300 'page'=>'depot',
1301 'tab'=>'default',
1302 'andor' => 'and',
1303 'cfe' => '{$typeid_' . $info['objtype_id'] . '}',
1304 )
1305 )."&"
1306 ));
1307 renderEntitySummary ($info, 'summary', $summary);
1308
1309 if (strlen ($info['comment']))
1310 {
1311 startPortlet ('Comment');
1312 echo '<div class=commentblock>' . string_insert_hrefs ($info['comment']) . '</div>';
1313 finishPortlet ();
1314 }
1315
1316 $logrecords = getLogRecordsForObject ($_REQUEST['object_id']);
1317 if (count ($logrecords))
1318 {
1319 startPortlet ('log records');
1320 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable width='100%'>";
1321 $order = 'odd';
1322 foreach ($logrecords as $row)
1323 {
1324 echo "<tr class=row_${order} valign=top>";
1325 echo '<td class=tdleft>' . $row['date'] . '<br>' . $row['user'] . '</td>';
1326 echo '<td class="logentry">' . string_insert_hrefs (htmlspecialchars ($row['content'], ENT_NOQUOTES)) . '</td>';
1327 echo '</tr>';
1328 $order = $nextorder[$order];
1329 }
1330 echo '</table>';
1331 finishPortlet();
1332 }
1333
1334 switchportInfoJS ($object_id); // load JS code to make portnames interactive
1335 renderFilesPortlet ('object', $object_id);
1336
1337 if (count ($info['ports']))
1338 {
1339 startPortlet ('ports and links');
1340 $hl_port_id = 0;
1341 if (isset ($_REQUEST['hl_port_id']))
1342 {
1343 assertUIntArg ('hl_port_id');
1344 $hl_port_id = $_REQUEST['hl_port_id'];
1345 addAutoScrollScript ("port-$hl_port_id");
1346 }
1347 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>";
1348 echo '<tr><th class=tdleft>Local name</th><th class=tdleft>Visible label</th>';
1349 echo '<th class=tdleft>Interface</th><th class=tdleft>L2 address</th>';
1350 echo '<th class=tdcenter colspan=2>Remote object and port</th>';
1351 echo '<th class=tdleft>Cable ID</th></tr>';
1352 foreach ($info['ports'] as $port)
1353 callHook ('renderObjectPortRow', $port, ($hl_port_id == $port['id']));
1354 if (permitted (NULL, 'ports', 'set_reserve_comment'))
1355 addJS ('js/inplace-edit.js');
1356 echo "</table><br>";
1357 finishPortlet();
1358 }
1359
1360 if (count ($info['ipv4']) + count ($info['ipv6']))
1361 {
1362 startPortlet ('IP addresses');
1363 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
1364 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
1365 echo "<tr><th>OS interface</th><th>IP address</th><th>network</th><th>routed by</th><th>peers</th></tr>\n";
1366 else
1367 echo "<tr><th>OS interface</th><th>IP address</th><th>peers</th></tr>\n";
1368
1369 // group IP allocations by interface name instead of address family
1370 $allocs_by_iface = array();
1371 foreach (array ('ipv4', 'ipv6') as $ip_v)
1372 foreach ($info[$ip_v] as $ip_bin => $alloc)
1373 $allocs_by_iface[$alloc['osif']][$ip_bin] = $alloc;
1374
1375 // sort allocs array by portnames
1376 foreach (sortPortList ($allocs_by_iface) as $iface_name => $alloclist)
1377 {
1378 $is_first_row = TRUE;
1379 foreach ($alloclist as $alloc)
1380 {
1381 $rendered_alloc = callHook ('getRenderedAlloc', $object_id, $alloc);
1382 echo "<tr class='${rendered_alloc['tr_class']}' valign=top>";
1383
1384 // display iface name, same values are grouped into single cell
1385 if ($is_first_row)
1386 {
1387 $rowspan = count ($alloclist) > 1 ? 'rowspan="' . count ($alloclist) . '"' : '';
1388 echo "<td class=tdleft $rowspan>" . $iface_name . $rendered_alloc['td_name_suffix'] . "</td>";
1389 $is_first_row = FALSE;
1390 }
1391 echo $rendered_alloc['td_ip'];
1392 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
1393 {
1394 echo $rendered_alloc['td_network'];
1395 echo $rendered_alloc['td_routed_by'];
1396 }
1397 echo $rendered_alloc['td_peers'];
1398
1399 echo "</tr>\n";
1400 }
1401 }
1402 echo "</table><br>\n";
1403 finishPortlet();
1404 }
1405
1406 $forwards = $info['nat4'];
1407 if (count($forwards['in']) or count($forwards['out']))
1408 {
1409 startPortlet('NATv4');
1410
1411 if (count($forwards['out']))
1412 {
1413
1414 echo "<h3>locally performed NAT</h3>";
1415
1416 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
1417 echo "<tr><th>Proto</th><th>Match endpoint</th><th>Translate to</th><th>Target object</th><th>Rule comment</th></tr>\n";
1418
1419 foreach ($forwards['out'] as $pf)
1420 {
1421 $class = 'trerror';
1422 $osif = '';
1423 if (isset ($alloclist [$pf['localip']]))
1424 {
1425 $class = $alloclist [$pf['localip']]['addrinfo']['class'];
1426 $osif = $alloclist [$pf['localip']]['osif'] . ': ';
1427 }
1428 echo "<tr class='$class'>";
1429 echo "<td>${pf['proto']}</td><td class=tdleft>${osif}" . getRenderedIPPortPair ($pf['localip'], $pf['localport']) . "</td>";
1430 echo "<td class=tdleft>" . getRenderedIPPortPair ($pf['remoteip'], $pf['remoteport']) . "</td>";
1431 $address = getIPAddress (ip4_parse ($pf['remoteip']));
1432 echo "<td class='description'>";
1433 if (count ($address['allocs']))
1434 foreach($address['allocs'] as $bond)
1435 echo mkA ("${bond['object_name']}(${bond['name']})", 'object', $bond['object_id']) . ' ';
1436 elseif (strlen ($pf['remote_addr_name']))
1437 echo '(' . $pf['remote_addr_name'] . ')';
1438 echo "</td><td class='description'>${pf['description']}</td></tr>";
1439 }
1440 echo "</table><br><br>";
1441 }
1442 if (count($forwards['in']))
1443 {
1444 echo "<h3>arriving NAT connections</h3>";
1445 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
1446 echo "<tr><th>Matched endpoint</th><th>Source object</th><th>Translated to</th><th>Rule comment</th></tr>\n";
1447 foreach ($forwards['in'] as $pf)
1448 {
1449 echo "<tr>";
1450 echo "<td>${pf['proto']}/" . getRenderedIPPortPair ($pf['localip'], $pf['localport']) . "</td>";
1451 echo '<td class="description">' . mkA ($pf['object_name'], 'object', $pf['object_id']);
1452 echo "</td><td>" . getRenderedIPPortPair ($pf['remoteip'], $pf['remoteport']) . "</td>";
1453 echo "<td class='description'>${pf['description']}</td></tr>";
1454 }
1455 echo "</table><br><br>";
1456 }
1457 finishPortlet();
1458 }
1459
1460 renderSLBTriplets2 ($info);
1461 renderSLBTriplets ($info);
1462 echo "</td>\n";
1463
1464 // After left column we have (surprise!) right column with rackspace portlet only.
1465 echo "<td class=pcright>";
1466 if (!in_array($info['objtype_id'], $virtual_obj_types))
1467 {
1468 // rackspace portlet
1469 startPortlet ('rackspace allocation');
1470 foreach (getResidentRacksData ($object_id, FALSE) as $rack_id)
1471 renderRack ($rack_id, $object_id);
1472 echo '<br>';
1473 finishPortlet();
1474 }
1475 echo "</td></tr>";
1476 echo "</table>\n";
1477 }
1478
1479 function renderRackMultiSelect ($sname, $racks, $selected)
1480 {
1481 // Transform the given flat list into a list of groups, each representing a rack row.
1482 $rdata = array();
1483 foreach ($racks as $rack)
1484 {
1485 $trail = getLocationTrail ($rack['location_id'], FALSE);
1486 if(!empty ($trail))
1487 $row_name = $trail . ' : ' . $rack['row_name'];
1488 else
1489 $row_name = $rack['row_name'];
1490 $rdata[$row_name][$rack['id']] = $rack['name'];
1491 }
1492 echo "<select name=${sname} multiple size=" . getConfigVar ('MAXSELSIZE') . " onchange='getElementsByName(\"updateObjectAllocation\")[0].submit()'>\n";
1493 $row_names = array_keys ($rdata);
1494 natsort ($row_names);
1495 foreach ($row_names as $optgroup)
1496 {
1497 echo "<optgroup label='${optgroup}'>";
1498 foreach ($rdata[$optgroup] as $rack_id => $rack_name)
1499 {
1500 echo "<option value=${rack_id}";
1501 if (!(array_search ($rack_id, $selected) === FALSE))
1502 echo ' selected';
1503 echo">${rack_name}</option>\n";
1504 }
1505 }
1506 echo "</select>\n";
1507 }
1508
1509 // This function renders a form for port edition.
1510 function renderPortsForObject ($object_id)
1511 {
1512 $prefs = getPortListPrefs();
1513 function printNewItemTR ($prefs)
1514 {
1515 printOpFormIntro ('addPort');
1516 echo "<tr><td>";
1517 printImageHREF ('add', 'add a port', TRUE);
1518 echo "</td><td class='tdleft'><input type=text size=8 name=port_name tabindex=100></td>\n";
1519 echo "<td><input type=text name=port_label tabindex=101></td><td>";
1520 printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type_id', 'tabindex' => 102), $prefs['selected']);
1521 echo "<td><input type=text name=port_l2address tabindex=103 size=18 maxlength=24></td>\n";
1522 echo "<td colspan=4>&nbsp;</td><td>";
1523 printImageHREF ('add', 'add a port', TRUE, 104);
1524 echo "</td></tr></form>";
1525 }
1526 if (getConfigVar('ENABLE_MULTIPORT_FORM') == 'yes' || getConfigVar('ENABLE_BULKPORT_FORM') == 'yes' )
1527 startPortlet ('Ports and interfaces');
1528 else
1529 echo '<br>';
1530 $object = spotEntity ('object', $object_id);
1531 amplifyCell ($object);
1532 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes' && getConfigVar('ENABLE_BULKPORT_FORM') == 'yes'){
1533 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
1534 echo "<tr><th>&nbsp;</th><th class=tdleft>Local name</th><th class=tdleft>Visible label</th><th class=tdleft>Interface</th><th class=tdleft>Start Number</th>";
1535 echo "<th class=tdleft>Count</th><th>&nbsp;</th></tr>\n";
1536 printOpFormIntro ('addBulkPorts');
1537 echo "<tr><td>";
1538 printImageHREF ('add', 'add ports', TRUE);
1539 echo "</td><td><input type=text size=8 name=port_name tabindex=105></td>\n";
1540 echo "<td><input type=text name=port_label tabindex=106></td><td>";
1541 printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type_id', 'tabindex' => 107), $prefs['selected']);
1542 echo "<td><input type=text name=port_numbering_start tabindex=108 size=3 maxlength=3></td>\n";
1543 echo "<td><input type=text name=port_numbering_count tabindex=109 size=3 maxlength=3></td>\n";
1544 echo "<td>&nbsp;</td><td>";
1545 printImageHREF ('add', 'add ports', TRUE, 110);
1546 echo "</td></tr></form>";
1547 echo "</table><br>\n";
1548 }
1549
1550 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
1551 echo "<tr><th>&nbsp;</th><th class=tdleft>Local name</th><th class=tdleft>Visible label</th><th class=tdleft>Interface</th><th class=tdleft>L2 address</th>";
1552 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>&nbsp;</th></tr>\n";
1553 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
1554 printNewItemTR ($prefs);
1555
1556 // clear ports link
1557 echo getOpLink (array ('op'=>'deleteAll'), 'Clear port list', 'clear', '', 'need-confirmation');
1558
1559 if (isset ($_REQUEST['hl_port_id']))
1560 {
1561 assertUIntArg ('hl_port_id');
1562 $hl_port_id = intval ($_REQUEST['hl_port_id']);
1563 addAutoScrollScript ("port-$hl_port_id");
1564 }
1565 switchportInfoJS ($object_id); // load JS code to make portnames interactive
1566 foreach ($object['ports'] as $port)
1567 {
1568 $tr_class = isset ($hl_port_id) && $hl_port_id == $port['id'] ? 'class="highlight"' : '';
1569 printOpFormIntro ('editPort', array ('port_id' => $port['id']));
1570 echo "<tr $tr_class><td><a name='port-${port['id']}' href='".makeHrefProcess(array('op'=>'delPort', 'port_id'=>$port['id']))."'>";
1571 printImageHREF ('delete', 'Unlink and Delete this port');
1572 echo "</a></td>\n";
1573 $a_class = isEthernetPort ($port) ? 'port-menu' : '';
1574 echo "<td class='tdleft' NOWRAP><input type=text name=name class='interactive-portname $a_class' value='${port['name']}' size=8></td>";
1575 echo "<td><input type=text name=label value='${port['label']}'></td>";
1576 echo '<td>';
1577 if ($port['iif_id'] != 1)
1578 echo '<label>' . $port['iif_name'] . ' ';
1579 printSelect (getExistingPortTypeOptions ($port['id']), array ('name' => 'port_type_id'), $port['oif_id']);
1580 if ($port['iif_id'] != 1)
1581 echo '</label>';
1582 echo '</td>';
1583
1584 // 18 is enough to fit 6-byte MAC address in its longest form,
1585 // while 24 should be Ok for WWN
1586 echo "<td><input type=text name=l2address value='${port['l2address']}' size=18 maxlength=24></td>\n";
1587 if ($port['remote_object_id'])
1588 {
1589 echo "<td>" .
1590 formatLoggedSpan ($port['last_log'], formatPortLink ($port['remote_object_id'], $port['remote_object_name'], $port['remote_id'], NULL)) .
1591 "</td>";
1592 echo "<td> " . formatLoggedSpan ($port['last_log'], $port['remote_name'], 'underline') .
1593 "<input type=hidden name=reservation_comment value=''></td>";
1594 echo "<td><input type=text name=cable value='${port['cableid']}'></td>";
1595 echo "<td class=tdcenter>";
1596 echo getOpLink (array('op'=>'unlinkPort', 'port_id'=>$port['id'], ), '', 'cut', 'Unlink this port');
1597 echo "</td>";
1598 }
1599 elseif (strlen ($port['reservation_comment']))
1600 {
1601 echo "<td>" . formatLoggedSpan ($port['last_log'], 'Reserved:', 'strong underline') . "</td>";
1602 echo "<td><input type=text name=reservation_comment value='${port['reservation_comment']}'></td>";
1603 echo "<td></td>";
1604 echo "<td class=tdcenter>";
1605 echo getOpLink (array('op'=>'useup', 'port_id'=>$port['id']), '', 'clear', 'Use up this port');
1606 echo "</td>";
1607 }
1608 else
1609 {
1610 $in_rack = getConfigVar ('NEAREST_RACKS_CHECKBOX');
1611 echo "<td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td class=tdcenter><span";
1612 $helper_args = array
1613 (
1614 'port' => $port['id'],
1615 'in_rack' => ($in_rack == "yes" ? "on" : "")
1616 );
1617 $popup_args = 'height=700, width=400, location=no, menubar=no, '.
1618 'resizable=yes, scrollbars=yes, status=no, titlebar=no, toolbar=no';
1619 echo " ondblclick='window.open(\"" . makeHrefForHelper ('portlist', $helper_args);
1620 echo "\",\"findlink\",\"${popup_args}\");'";
1621 // end of onclick=
1622 echo " onclick='window.open(\"" . makeHrefForHelper ('portlist', $helper_args);
1623 echo "\",\"findlink\",\"${popup_args}\");'";
1624 // end of onclick=
1625 echo '>';
1626 // end of <a>
1627 printImageHREF ('plug', 'Link this port');
1628 echo "</span>";
1629 echo " <input type=text name=reservation_comment></td>\n";
1630 }
1631 echo "<td>";
1632 printImageHREF ('save', 'Save changes', TRUE);
1633 echo "</td></form></tr>\n";
1634 }
1635 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
1636 printNewItemTR ($prefs);
1637 echo "</table><br>\n";
1638 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes' && getConfigVar('ENABLE_BULKPORT_FORM') == 'yes'){
1639 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
1640 echo "<tr><th>&nbsp;</th><th class=tdleft>Local name</th><th class=tdleft>Visible label</th><th class=tdleft>Interface</th><th class=tdleft>Start Number</th>";
1641 echo "<th class=tdleft>Count</th><th>&nbsp;</th></tr>\n";
1642 printOpFormIntro ('addBulkPorts');
1643 echo "<tr><td>";
1644 printImageHREF ('add', 'add ports', TRUE);
1645 echo "</td><td><input type=text size=8 name=port_name tabindex=105></td>\n";
1646 echo "<td><input type=text name=port_label tabindex=106></td><td>";
1647 printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type_id', 'tabindex' => 107), $prefs['selected']);
1648 echo "<td><input type=text name=port_numbering_start tabindex=108 size=3 maxlength=3></td>\n";
1649 echo "<td><input type=text name=port_numbering_count tabindex=109 size=3 maxlength=3></td>\n";
1650 echo "<td>&nbsp;</td><td>";
1651 printImageHREF ('add', 'add ports', TRUE, 110);
1652 echo "</td></tr></form>";
1653 echo "</table><br>\n";
1654 }
1655 if (getConfigVar('ENABLE_MULTIPORT_FORM') == 'yes')
1656 finishPortlet();
1657 if (getConfigVar('ENABLE_MULTIPORT_FORM') != 'yes')
1658 return;
1659
1660 startPortlet ('Add/update multiple ports');
1661 printOpFormIntro ('addMultiPorts');
1662 echo 'Format: <select name=format tabindex=201>';
1663 echo '<option value=c3600asy>Cisco 3600 async: sh line | inc TTY</option>';
1664 echo '<option value=fiwg selected>Foundry ServerIron/FastIron WorkGroup/Edge: sh int br</option>';
1665 echo '<option value=fisxii>Foundry FastIron SuperX/II4000: sh int br</option>';
1666 echo '<option value=ssv1>SSV:&lt;interface name&gt; &lt;MAC address&gt;</option>';
1667 echo "</select>";
1668 echo 'Default port type: ';
1669 printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type', 'tabindex' => 202), $prefs['selected']);
1670 echo "<input type=submit value='Parse output' tabindex=204><br>\n";
1671 echo "<textarea name=input cols=100 rows=50 tabindex=203></textarea><br>\n";
1672 echo '</form>';
1673 finishPortlet();
1674 }
1675
1676 function renderIPForObject ($object_id)
1677 {
1678 function printNewItemTR ($default_type)
1679 {
1680 global $aat;
1681 printOpFormIntro ('add');
1682 echo "<tr><td>"; // left btn
1683 printImageHREF ('add', 'allocate', TRUE);
1684 echo "</td>";
1685 echo "<td class=tdleft><input type='text' size='10' name='bond_name' tabindex=100></td>\n"; // if-name
1686 echo "<td class=tdleft><input type=text name='ip' tabindex=101></td>\n"; // IP
1687 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
1688 echo "<td colspan=2>&nbsp;</td>"; // network, routed by
1689 echo '<td>';
1690 printSelect ($aat, array ('name' => 'bond_type', 'tabindex' => 102), $default_type); // type
1691 echo "</td><td>&nbsp;</td><td>"; // misc
1692 printImageHREF ('add', 'allocate', TRUE, 103); // right btn
1693 echo "</td></tr></form>";
1694 }
1695 global $aat;
1696 startPortlet ('Allocations');
1697 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'><tr>\n";
1698 echo '<th>&nbsp;</th>';
1699 echo '<th>OS interface</th>';
1700 echo '<th>IP address</th>';
1701 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
1702 {
1703 echo '<th>network</th>';
1704 echo '<th>routed by</th>';
1705 }
1706 echo '<th>type</th>';
1707 echo '<th>misc</th>';
1708 echo '<th>&nbsp;</th>';
1709 echo '</tr>';
1710
1711 $alloc_list = ''; // most of the output is stored here
1712 $used_alloc_types = array();
1713 foreach (getObjectIPAllocations ($object_id) as $alloc)
1714 {
1715 if (! isset ($used_alloc_types[$alloc['type']]))
1716 $used_alloc_types[$alloc['type']] = 0;
1717 $used_alloc_types[$alloc['type']]++;
1718
1719 $rendered_alloc = callHook ('getRenderedAlloc', $object_id, $alloc);
1720 $alloc_list .= getOutputOf ('printOpFormIntro', 'upd', array ('ip' => $alloc['addrinfo']['ip']));
1721 $alloc_list .= "<tr class='${rendered_alloc['tr_class']}' valign=top>";
1722
1723 $alloc_list .= "<td>" . getOpLink (array ('op' => 'del', 'ip' => $alloc['addrinfo']['ip']), '', 'delete', 'Delete this IP address') . "</td>";
1724 $alloc_list .= "<td class=tdleft><input type='text' name='bond_name' value='${alloc['osif']}' size=10>" . $rendered_alloc['td_name_suffix'] . "</td>";
1725 $alloc_list .= $rendered_alloc['td_ip'];
1726 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
1727 {
1728 $alloc_list .= $rendered_alloc['td_network'];
1729 $alloc_list .= $rendered_alloc['td_routed_by'];
1730 }
1731 $alloc_list .= '<td>' . getSelect ($aat, array ('name' => 'bond_type'), $alloc['type']) . "</td>";
1732 $alloc_list .= $rendered_alloc['td_peers'];
1733 $alloc_list .= "<td>" .getImageHREF ('save', 'Save changes', TRUE) . "</td>";
1734
1735 $alloc_list .= "</form></tr>\n";
1736 }
1737 asort ($used_alloc_types, SORT_NUMERIC);
1738 $most_popular_type = empty ($used_alloc_types) ? 'regular' : array_last (array_keys ($used_alloc_types));
1739
1740 if ($list_on_top = (getConfigVar ('ADDNEW_AT_TOP') != 'yes'))
1741 echo $alloc_list;
1742 printNewItemTR ($most_popular_type);
1743 if (! $list_on_top)
1744 echo $alloc_list;
1745
1746 echo "</table><br>\n";
1747 finishPortlet();
1748 }
1749
1750 // This function is deprecated. Do not rely on its internals,
1751 // it will probably be removed in the next major relese.
1752 // Use new showError, showWarning, showSuccess functions.
1753 // Log array is stored in global $log_messages. Its format is simple: plain ordered array
1754 // with values having keys 'c' (both message code and severity) and 'a' (sprintf arguments array)
1755 function showMessageOrError ()
1756 {
1757 global $log_messages;
1758
1759 @session_start();
1760 if (isset ($_SESSION['log']))
1761 {
1762 $log_messages = array_merge ($_SESSION['log'], $log_messages);
1763 unset ($_SESSION['log']);
1764 }
1765 session_commit();
1766
1767 if (empty ($log_messages))
1768 return;
1769 $msginfo = array
1770 (
1771 // records 0~99 with success messages
1772 0 => array ('code' => 'success', 'format' => '%s'),
1773 5 => array ('code' => 'success', 'format' => 'added record "%s" successfully'),
1774 6 => array ('code' => 'success', 'format' => 'updated record "%s" successfully'),
1775 7 => array ('code' => 'success', 'format' => 'deleted record "%s" successfully'),
1776 8 => array ('code' => 'success', 'format' => 'Port %s successfully linked with %s'),
1777 10 => array ('code' => 'success', 'format' => 'Added %u ports, updated %u ports, encountered %u errors.'),
1778 21 => array ('code' => 'success', 'format' => 'Generation complete'),
1779 26 => array ('code' => 'success', 'format' => 'updated %u records successfully'),
1780 37 => array ('code' => 'success', 'format' => 'added %u records successfully'),
1781 38 => array ('code' => 'success', 'format' => 'removed %u records successfully'),
1782 43 => array ('code' => 'success', 'format' => 'Saved successfully.'),
1783 44 => array ('code' => 'success', 'format' => '%s failures and %s successfull changes.'),
1784 48 => array ('code' => 'success', 'format' => 'added a record successfully'),
1785 49 => array ('code' => 'success', 'format' => 'deleted a record successfully'),
1786 51 => array ('code' => 'success', 'format' => 'updated a record successfully'),
1787 57 => array ('code' => 'success', 'format' => 'Reset complete'),
1788 63 => array ('code' => 'success', 'format' => '%u change request(s) have been processed'),
1789 67 => array ('code' => 'success', 'format' => "Tag rolling done, %u objects involved"),
1790 71 => array ('code' => 'success', 'format' => 'File "%s" was linked successfully'),
1791 72 => array ('code' => 'success', 'format' => 'File was unlinked successfully'),
1792 82 => array ('code' => 'success', 'format' => "Bulk port creation was successful. %u ports created, %u failed"),
1793 87 => array ('code' => 'success', 'format' => '802.1Q recalculate: %d ports changed on %d switches'),
1794 // records 100~199 with fatal error messages
1795 100 => array ('code' => 'error', 'format' => '%s'),
1796 109 => array ('code' => 'error', 'format' => 'failed updating a record'),
1797 131 => array ('code' => 'error', 'format' => 'invalid format requested'),
1798 141 => array ('code' => 'error', 'format' => 'Encountered %u errors, updated %u record(s)'),
1799 149 => array ('code' => 'error', 'format' => 'Turing test failed'),
1800 150 => array ('code' => 'error', 'format' => 'Can only change password under DB authentication.'),
1801 151 => array ('code' => 'error', 'format' => 'Old password doesn\'t match.'),
1802 152 => array ('code' => 'error', 'format' => 'New passwords don\'t match.'),
1803 154 => array ('code' => 'error', 'format' => "Verification error: %s"),
1804 155 => array ('code' => 'error', 'format' => 'Save failed.'),
1805 159 => array ('code' => 'error', 'format' => 'Permission denied moving port %s from VLAN%u to VLAN%u'),
1806 161 => array ('code' => 'error', 'format' => 'Endpoint not found. Please either set FQDN attribute or assign an IP address to the object.'),
1807 162 => array ('code' => 'error', 'format' => 'More than one IP address is assigned to this object, please configure FQDN attribute.'),
1808 170 => array ('code' => 'error', 'format' => 'There is no network for IP address "%s"'),
1809 172 => array ('code' => 'error', 'format' => 'Malformed request'),
1810 179 => array ('code' => 'error', 'format' => 'Expired form has been declined.'),
1811 188 => array ('code' => 'error', 'format' => "Fatal SNMP failure"),
1812 189 => array ('code' => 'error', 'format' => "Unknown OID '%s'"),
1813 191 => array ('code' => 'error', 'format' => "deploy was blocked due to conflicting configuration versions"),
1814
1815 // records 200~299 with warnings
1816 200 => array ('code' => 'warning', 'format' => '%s'),
1817 201 => array ('code' => 'warning', 'format' => 'nothing happened...'),
1818 206 => array ('code' => 'warning', 'format' => '%s is not empty'),
1819 207 => array ('code' => 'warning', 'format' => 'File upload failed, error: %s'),
1820
1821 // records 300~399 with notices
1822 300 => array ('code' => 'neutral', 'format' => '%s'),
1823
1824 );
1825 // Handle the arguments. Is there any better way to do it?
1826 foreach ($log_messages as $record)
1827 {
1828 if (!isset ($record['c']) or !isset ($msginfo[$record['c']]))
1829 {
1830 $prefix = isset ($record['c']) ? $record['c'] . ': ' : '';
1831 echo "<div class=msg_neutral>(${prefix}this message was lost)</div>";
1832 continue;
1833 }
1834 if (isset ($record['a']))
1835 switch (count ($record['a']))
1836 {
1837 case 1:
1838 $msgtext = sprintf
1839 (
1840 $msginfo[$record['c']]['format'],
1841 $record['a'][0]
1842 );
1843 break;
1844 case 2:
1845 $msgtext = sprintf
1846 (
1847 $msginfo[$record['c']]['format'],
1848 $record['a'][0],
1849 $record['a'][1]
1850 );
1851 break;
1852 case 3:
1853 $msgtext = sprintf
1854 (
1855 $msginfo[$record['c']]['format'],
1856 $record['a'][0],
1857 $record['a'][1],
1858 $record['a'][2]
1859 );
1860 break;
1861 case 4:
1862 default:
1863 $msgtext = sprintf
1864 (
1865 $msginfo[$record['c']]['format'],
1866 $record['a'][0],
1867 $record['a'][1],
1868 $record['a'][2],
1869 $record['a'][3]
1870 );
1871 break;
1872 }
1873 else
1874 $msgtext = $msginfo[$record['c']]['format'];
1875 echo '<div class=msg_' . $msginfo[$record['c']]['code'] . ">${msgtext}</div>";
1876 }
1877 $log_messages = array();
1878 }
1879
1880 // renders two tables: port link status and learned MAC list
1881 function renderPortsInfo($object_id)
1882 {
1883 try
1884 {
1885 if (permitted (NULL, NULL, 'get_link_status'))
1886 $linkStatus = queryDevice ($object_id, 'getportstatus');
1887 else
1888 showWarning ("You don't have permission to view ports link status");
1889
1890 if (permitted (NULL, NULL, 'get_mac_list'))
1891 $macList = sortPortList (queryDevice ($object_id, 'getmaclist'));
1892 else
1893 showWarning ("You don't have permission to view learned MAC list");
1894 }
1895 catch (RTGatewayError $e)
1896 {
1897 showError ($e->getMessage());
1898 return;
1899 }
1900
1901 global $nextorder;
1902 echo "<table width='100%'><tr>";
1903 if (! empty ($linkStatus))
1904 {
1905 echo "<td valign='top' width='50%'>";
1906 startPortlet('Link status');
1907 echo "<table width='80%' class='widetable' cellspacing=0 cellpadding='5px' align='center'><tr><th>Port<th><th>Link status<th>Link info</tr>";
1908 $order = 'even';
1909 foreach ($linkStatus as $pn => $link)
1910 {
1911 switch ($link['status'])
1912 {
1913 case 'up':
1914 $img_filename = 'link-up.png';
1915 break;
1916 case 'down':
1917 $img_filename = 'link-down.png';
1918 break;
1919 case 'disabled':
1920 $img_filename = 'link-disabled.png';
1921 break;
1922 default:
1923 $img_filename = '1x1t.gif';
1924 }
1925
1926 echo "<tr class='row_$order'>";
1927 $order = $nextorder[$order];
1928 echo '<td>' . $pn;
1929 echo '<td>' . '<img width=16 height=16 src="?module=chrome&uri=pix/' . $img_filename . '">';
1930 echo '<td>' . $link['status'];
1931 $info = '';
1932 if (isset ($link['speed']))
1933 $info .= $link['speed'];
1934 if (isset ($link['duplex']))
1935 {
1936 if (! empty ($info))
1937 $info .= ', ';
1938 $info .= $link['duplex'];
1939 }
1940 echo '<td>' . $info;
1941 echo '</tr>';
1942 }
1943 echo "</table></td>";
1944 finishPortlet();
1945 }
1946
1947 if (! empty ($macList))
1948 {
1949 echo "<td valign='top' width='50%'>";
1950 $rendered_macs = '';
1951 $mac_count = 0;
1952 $rendered_macs .= "<table width='80%' class='widetable' cellspacing=0 cellpadding='5px' align='center'><tr><th>MAC<th>Vlan<th>Port</tr>";
1953 $order = 'even';
1954 foreach ($macList as $pn => $list)
1955 {
1956 $order = $nextorder[$order];
1957 foreach ($list as $item)
1958 {
1959 ++$mac_count;
1960 $rendered_macs .= "<tr class='row_$order'>";
1961 $rendered_macs .= '<td style="font-family: monospace">' . $item['mac'];
1962 $rendered_macs .= '<td>' . $item['vid'];
1963 $rendered_macs .= '<td>' . $pn;
1964 $rendered_macs .= '</tr>';
1965 }
1966 }
1967 $rendered_macs .= "</table></td>";
1968
1969 startPortlet("Learned MACs ($mac_count)");
1970 echo $rendered_macs;
1971 finishPortlet();
1972 }
1973
1974 echo "</td></tr></table>";
1975 }
1976
1977 /*
1978 The following conditions must be met:
1979 1. We can mount onto free atoms only. This means: if any record for an atom
1980 already exists in RackSpace, it can't be used for mounting.
1981 2. We can't unmount from 'W' atoms. Operator should review appropriate comments
1982 and either delete them before unmounting or refuse to unmount the object.
1983 */
1984 function renderRackSpaceForObject ($object_id)
1985 {
1986 // Always process occupied racks plus racks chosen by user. First get racks with
1987 // already allocated rackspace...
1988 $workingRacksData = getResidentRacksData ($object_id);
1989 // ...and then add those chosen by user (if any).
1990 if (isset($_REQUEST['rackmulti']))
1991 foreach ($_REQUEST['rackmulti'] as $cand_id)
1992 if (!isset ($workingRacksData[$cand_id]))
1993 {
1994 $rackData = spotEntity ('rack', $cand_id);
1995 amplifyCell ($rackData);
1996 $workingRacksData[$cand_id] = $rackData;
1997 }
1998
1999 // Get a list of all of this object's parents,
2000 // then trim the list to only include parents that are racks
2001 $objectParents = getEntityRelatives('parents', 'object', $object_id);
2002 $parentRacks = array();
2003 foreach ($objectParents as $parentData)
2004 if ($parentData['entity_type'] == 'rack')
2005 $parentRacks[] = $parentData['entity_id'];
2006
2007 // Main layout starts.
2008 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0><tr>";
2009
2010 // Left portlet with rack list.
2011 echo "<td class=pcleft height='1%'>";
2012 startPortlet ('Racks');
2013 $allRacksData = listCells ('rack');
2014
2015 // filter rack list to match only racks having common tags with the object (reducing $allRacksData)
2016 if (! isset ($_REQUEST['show_all_racks']) and getConfigVar ('FILTER_RACKLIST_BY_TAGS') == 'yes')
2017 {
2018 $matching_racks = array();
2019 $object = spotEntity ('object', $object_id);
2020 $matched_tags = array();
2021 foreach ($allRacksData as $rack)
2022 foreach ($object['etags'] as $tag)
2023 if (tagOnChain ($tag, $rack['etags']) or tagOnChain ($tag, $rack['itags']))
2024 {
2025 $matching_racks[$rack['id']] = $rack;
2026 $matched_tags[$tag['id']] = $tag;
2027 break;
2028 }
2029 // add current object's racks even if they dont match filter
2030 foreach ($workingRacksData as $rack_id => $rack)
2031 if (! isset ($matching_racks[$rack_id]))
2032 $matching_racks[$rack_id] = $rack;
2033 // if matching racks found, and rack list is reduced, show 'show all' link
2034 if (count ($matching_racks) and count ($matching_racks) != count ($allRacksData))
2035 {
2036 $filter_text = '';
2037 foreach ($matched_tags as $tag)
2038 $filter_text .= (empty ($filter_text) ? '' : ' or ') . '{' . $tag['tag'] . '}';
2039 $href_show_all = trim($_SERVER['REQUEST_URI'], '&');
2040 $href_show_all .= htmlspecialchars('&show_all_racks=1');
2041 echo "(filtered by <span class='filter-text'>$filter_text</span>, <a href='$href_show_all'>show all</a>)<p>";
2042 $allRacksData = $matching_racks;
2043 }
2044 }
2045
2046 if (count ($allRacksData) <= getConfigVar ('RACK_PRESELECT_THRESHOLD'))
2047 foreach ($allRacksData as $rack)
2048 if (!array_key_exists ($rack['id'], $workingRacksData))
2049 {
2050 amplifyCell ($rack);
2051 $workingRacksData[$rack['id']] = $rack;
2052 }
2053 foreach (array_keys ($workingRacksData) as $rackId)
2054 applyObjectMountMask ($workingRacksData[$rackId], $object_id);
2055 printOpFormIntro ('updateObjectAllocation');
2056 renderRackMultiSelect ('rackmulti[]', $allRacksData, array_keys ($workingRacksData));
2057 echo "<br><br>";
2058 finishPortlet();
2059 echo "</td>";
2060
2061 // Middle portlet with comment and submit.
2062 echo "<td class=pcleft>";
2063 startPortlet ('Comment (for Rackspace History)');
2064 echo "<textarea name=comment rows=10 cols=40></textarea><br>\n";
2065 echo "<input type=submit value='Save' name=got_atoms>\n";
2066 echo "<br><br>";
2067 finishPortlet();
2068 echo "</td>";
2069
2070 // Right portlet with rendered racks. If this form submit is not final, we have to
2071 // reflect the former state of the grid in current form.
2072 echo "<td class=pcright rowspan=2 height='1%'>";
2073 startPortlet ('Working copy');
2074 includeJQueryUI (false);
2075 addJS ('js/racktables.js');
2076 addJS ('js/bulkselector.js');
2077 echo '<table border=0 cellspacing=10 align=center><tr>';
2078 foreach ($workingRacksData as $rack_id => $rackData)
2079 {
2080 // Order is important here: only original allocation is highlighted.
2081 highlightObject ($rackData, $object_id);
2082 markupAtomGrid ($rackData, 'T');
2083 // If we have a form processed, discard user input and show new database
2084 // contents.
2085 if (isset ($_REQUEST['rackmulti'][0])) // is an update
2086 mergeGridFormToRack ($rackData);
2087 echo "<td valign=top>";
2088 echo "<center>\n<h2>${rackData['name']}</h2>\n";
2089 echo "<table class=rack id=selectableRack border=0 cellspacing=0 cellpadding=1>\n";
2090 echo "<tr><th width='10%'>&nbsp;</th>";
2091 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '0', ${rackData['height']})\">Front</a></th>";
2092 echo "<th width='50%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '1', ${rackData['height']})\">Interior</a></th>";
2093 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '2', ${rackData['height']})\">Back</a></th></tr>\n";
2094 renderAtomGrid ($rackData);
2095 echo "<tr><th width='10%'>&nbsp;</th>";
2096 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '0', ${rackData['height']})\">Front</a></th>";
2097 echo "<th width='50%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '1', ${rackData['height']})\">Interior</a></th>";
2098 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '2', ${rackData['height']})\">Back</a></th></tr>\n";
2099 echo "</table>\n<br>\n";
2100 // Determine zero-u checkbox status.
2101 // If form has been submitted, use form data, otherwise use DB data.
2102 if (isset($_REQUEST['op']))
2103 $checked = isset($_REQUEST['zerou_'.$rack_id]) ? 'checked' : '';
2104 else
2105 $checked = in_array($rack_id, $parentRacks) ? 'checked' : '';
2106 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";
2107 echo "<input type='button' onclick='uncheckAll();' value='Uncheck all'>\n";
2108 echo '</center></td>';
2109 }
2110 echo "</tr></table>";
2111 finishPortlet();
2112 echo "</td>\n";
2113
2114 echo "</form>\n";
2115 echo "</tr></table>\n";
2116 }
2117
2118 function renderMolecule ($mdata, $object_id)
2119 {
2120 // sort data out
2121 $rackpack = array();
2122 global $loclist;
2123 foreach ($mdata as $rua)
2124 {
2125 $rack_id = $rua['rack_id'];
2126 $unit_no = $rua['unit_no'];
2127 $atom = $rua['atom'];
2128 if (!isset ($rackpack[$rack_id]))
2129 {
2130 $rackData = spotEntity ('rack', $rack_id);
2131 amplifyCell ($rackData);
2132 for ($i = $rackData['height']; $i > 0; $i--)
2133 for ($locidx = 0; $locidx < 3; $locidx++)
2134 $rackData[$i][$locidx]['state'] = 'F';
2135 $rackpack[$rack_id] = $rackData;
2136 }
2137 $rackpack[$rack_id][$unit_no][$loclist[$atom]]['state'] = 'T';
2138 $rackpack[$rack_id][$unit_no][$loclist[$atom]]['object_id'] = $object_id;
2139 }
2140 // now we have some racks to render
2141 foreach ($rackpack as $rackData)
2142 {
2143 markAllSpans ($rackData);
2144 echo "<table class=molecule cellspacing=0>\n";
2145 echo "<caption>${rackData['name']}</caption>\n";
2146 echo "<tr><th width='10%'>&nbsp;</th><th width='20%'>Front</th><th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n";
2147 for ($i = $rackData['height']; $i > 0; $i--)
2148 {
2149 echo "<tr><th>" . inverseRackUnit ($i, $rackData) . "</th>";
2150 for ($locidx = 0; $locidx < 3; $locidx++)
2151 {
2152 $state = $rackData[$i][$locidx]['state'];
2153 echo "<td class='atom state_${state}'>&nbsp;</td>\n";
2154 }
2155 echo "</tr>\n";
2156 }
2157 echo "</table>\n";
2158 }
2159 }
2160
2161 function renderDepot ()
2162 {
2163 global $pageno, $nextorder;
2164 $cellfilter = getCellFilter();
2165 $objects = array();
2166 $objects_count = getEntitiesCount ('object');
2167
2168 echo "<table border=0 class=objectview>\n";
2169 echo "<tr><td class=pcleft>";
2170
2171 if ($objects_count == 0)
2172 echo '<h2>No objects exist</h2>';
2173 // 1st attempt: do not fetch all objects if cellfilter is empty and rendering empty result is enabled
2174 elseif (! ($cellfilter['is_empty'] && renderEmptyResults ($cellfilter, 'objects', $objects_count)))
2175 {
2176 $objects = applyCellFilter ('object', $cellfilter);
2177 // 2nd attempt: do not render all fetched objects if rendering empty result is enabled
2178 if (! renderEmptyResults ($cellfilter, 'objects', count($objects)))
2179 {
2180 startPortlet ('Objects (' . count ($objects) . ')');
2181 echo '<br><br><table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
2182 echo '<tr><th>Common name</th><th>Visible label</th><th>Asset tag</th><th>Row/Rack or Container</th></tr>';
2183 $order = 'odd';
2184 # gather IDs of all objects and fetch rackspace info in one pass
2185 $idlist = array();
2186 foreach ($objects as $obj)
2187 $idlist[] = $obj['id'];
2188 $mountinfo = getMountInfo ($idlist);
2189 $containerinfo = getContainerInfo ($idlist);
2190 foreach ($objects as $obj)
2191 {
2192 $problem = ($obj['has_problems'] == 'yes') ? 'has_problems' : '';
2193 echo "<tr class='row_${order} tdleft ${problem}' valign=top><td>" . mkA ("<strong>${obj['dname']}</strong>", 'object', $obj['id']);
2194 if (count ($obj['etags']))
2195 echo '<br><small>' . serializeTags ($obj['etags'], makeHref(array('page'=>$pageno, 'tab'=>'default')) . '&') . '</small>';
2196 echo "</td><td>${obj['label']}</td>";
2197 echo "<td>${obj['asset_no']}</td>";
2198 $places = array();
2199 if (array_key_exists ($obj['id'], $containerinfo))
2200 foreach ($containerinfo[$obj['id']] as $ci)
2201 $places[] = mkA ($ci['container_dname'], 'object', $ci['container_id']);
2202 if (array_key_exists ($obj['id'], $mountinfo))
2203 foreach ($mountinfo[$obj['id']] as $mi)
2204 $places[] = mkA ($mi['row_name'], 'row', $mi['row_id']) . '/' . mkA ($mi['rack_name'], 'rack', $mi['rack_id']);
2205 if (! count ($places))
2206 $places[] = 'Unmounted';
2207 echo "<td>" . implode (', ', $places) . '</td>';
2208 echo '</tr>';
2209 $order = $nextorder[$order];
2210 }
2211 echo '</table>';
2212 finishPortlet();
2213 }
2214 }
2215
2216 echo "</td><td class=pcright width='25%'>";
2217
2218 renderCellFilterPortlet ($cellfilter, 'object', $objects);
2219 echo "</td></tr></table>\n";
2220 }
2221
2222 // This function returns TRUE if the result set is too big to be rendered, and no filter is set.
2223 // In this case it renders the describing message instead.
2224 function renderEmptyResults($cellfilter, $entities_name, $count = NULL)
2225 {
2226 if (!$cellfilter['is_empty'])
2227 return FALSE;
2228 if (isset ($_REQUEST['show_all_objects']))
2229 return FALSE;
2230 $max = intval(getConfigVar('MAX_UNFILTERED_ENTITIES'));
2231 if (0 == $max || $count <= $max)
2232 return FALSE;
2233
2234 $href_show_all = trim($_SERVER['REQUEST_URI'], '&');
2235 $href_show_all .= htmlspecialchars('&show_all_objects=1');
2236 $suffix = isset ($count) ? " ($count)" : '';
2237 echo <<<END
2238 <p>Please set a filter to display the corresponging $entities_name.
2239 <br><a href="$href_show_all">Show all $entities_name$suffix</a>
2240 END;
2241 return TRUE;
2242 }
2243
2244 // History viewer for history-enabled simple dictionaries.
2245 function renderObjectHistory ($object_id)
2246 {
2247 $order = 'odd';
2248 global $nextorder;
2249 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
2250 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>';
2251 $result = usePreparedSelectBlade
2252 (
2253 'SELECT ctime, user_name, name, label, asset_no, has_problems, comment FROM ObjectHistory WHERE id=? ORDER BY ctime',
2254 array ($object_id)
2255 );
2256 while ($row = $result->fetch (PDO::FETCH_NUM))
2257 {
2258 echo "<tr class=row_${order}><td>${row[0]}</td>";
2259 for ($i = 1; $i <= 6; $i++)
2260 echo "<td>" . $row[$i] . "</td>";
2261 echo "</tr>\n";
2262 $order = $nextorder[$order];
2263 }
2264 echo "</table><br>\n";
2265 }
2266
2267 function renderRackspaceHistory ()
2268 {
2269 global $nextorder, $pageno, $tabno;
2270 $order = 'odd';
2271 $history = getRackspaceHistory();
2272 // Show the last operation by default.
2273 if (isset ($_REQUEST['op_id']))
2274 $op_id = $_REQUEST['op_id'];
2275 elseif (isset ($history[0]['mo_id']))
2276 $op_id = $history[0]['mo_id'];
2277 else $op_id = NULL;
2278
2279 $omid = NULL;
2280 $nmid = NULL;
2281 $object_id = 1;
2282 if ($op_id)
2283 list ($omid, $nmid) = getOperationMolecules ($op_id);
2284
2285 // Main layout starts.
2286 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
2287
2288 // Left top portlet with old allocation.
2289 echo "<tr><td class=pcleft>";
2290 startPortlet ('Old allocation');
2291 if ($omid)
2292 {
2293 $oldMolecule = getMolecule ($omid);
2294 renderMolecule ($oldMolecule, $object_id);
2295 }
2296 else
2297 echo "nothing";
2298 finishPortlet();
2299
2300 echo '</td><td class=pcright>';
2301
2302 // Right top portlet with new allocation
2303 startPortlet ('New allocation');
2304 if ($nmid)
2305 {
2306 $newMolecule = getMolecule ($nmid);
2307 renderMolecule ($newMolecule, $object_id);
2308 }
2309 else
2310 echo "nothing";
2311 finishPortlet();
2312
2313 echo '</td></tr><tr><td colspan=2>';
2314
2315 // Bottom portlet with list
2316
2317 startPortlet ('Rackspace allocation history');
2318 echo "<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>\n";
2319 echo "<tr><th>timestamp</th><th>author</th><th>object</th><th>comment</th></tr>\n";
2320 foreach ($history as $row)
2321 {
2322 if ($row['mo_id'] == $op_id)
2323 $class = 'hl';
2324 else
2325 $class = "row_${order}";
2326 echo "<tr class=${class}><td><a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'op_id'=>$row['mo_id']))."'>${row['ctime']}</a></td>";
2327 echo "<td>${row['user_name']}</td><td>";
2328 renderCell (spotEntity ('object', $row['ro_id']));
2329 echo '</td><td>' . niftyString ($row['comment'], 0) . '</td></tr>';
2330 $order = $nextorder[$order];
2331 }
2332 echo "</table>\n";
2333 finishPortlet();
2334
2335 echo '</td></tr></table>';
2336 }
2337
2338 function renderIPSpaceRecords ($tree, $baseurl, $target = 0, $level = 1)
2339 {
2340 $self = __FUNCTION__;
2341 $knight = (getConfigVar ('IPV4_ENABLE_KNIGHT') == 'yes');
2342
2343 // scroll page to the highlighted item
2344 if ($target && isset ($_REQUEST['hl_net']))
2345 addAutoScrollScript ("net-$target");
2346
2347 foreach ($tree as $item)
2348 {
2349 if ($display_routers = (getConfigVar ('IPV4_TREE_RTR_AS_CELL') != 'none'))
2350 loadIPAddrList ($item); // necessary to compute router list and address counter
2351
2352 if (isset ($item['id']))
2353 {
2354 $decor = array ('indent' => $level);
2355 if ($item['symbol'] == 'node-collapsed')
2356 $decor['symbolurl'] = "${baseurl}&eid=${item['id']}&hl_net=1";
2357 elseif ($item['symbol'] == 'node-expanded')
2358 $decor['symbolurl'] = $baseurl . ($item['parent_id'] ? "&eid=${item['parent_id']}&hl_net=1" : '');
2359 $tr_class = '';
2360 if ($target == $item['id'] && isset ($_REQUEST['hl_net']))
2361 {
2362 $decor['tdclass'] = ' highlight';
2363 $tr_class = $decor['tdclass'];
2364 }
2365 echo "<tr valign=top class=\"$tr_class\">";
2366 printIPNetInfoTDs ($item, $decor);
2367
2368 // capacity and usage
2369 echo "<td class=tdcenter>";
2370 echo getRenderedIPNetCapacity ($item);
2371 echo "</td>";
2372
2373 if ($display_routers)
2374 printRoutersTD (findRouters ($item['own_addrlist']), getConfigVar ('IPV4_TREE_RTR_AS_CELL'));
2375 echo "</tr>";
2376 if ($item['symbol'] == 'node-expanded' or $item['symbol'] == 'node-expanded-static')
2377 $self ($item['kids'], $baseurl, $target, $level + 1);
2378 }
2379 else
2380 {
2381 // non-allocated (spare) IP range
2382 echo "<tr valign=top>";
2383 printIPNetInfoTDs ($item, array ('indent' => $level, 'knight' => $knight, 'tdclass' => 'sparenetwork'));
2384
2385 // capacity and usage
2386 echo "<td class=tdcenter>";
2387 echo getRenderedIPNetCapacity ($item);
2388 echo "</td>";
2389 if ($display_routers)
2390 echo "<td></td>";
2391 echo "</tr>";
2392 }
2393 }
2394 }
2395
2396 function renderIPSpace()
2397 {
2398 global $pageno, $tabno;
2399 $realm = ($pageno == 'ipv4space' ? 'ipv4net' : 'ipv6net');
2400 $cellfilter = getCellFilter();
2401
2402 // expand request can take either natural values or "ALL". Zero means no expanding.
2403 $eid = isset ($_REQUEST['eid']) ? $_REQUEST['eid'] : 0;
2404
2405 echo "<table border=0 class=objectview>\n";
2406 echo "<tr><td class=pcleft>";
2407
2408 $netlist = array();
2409 if (! ($cellfilter['is_empty'] && ! $eid && renderEmptyResults($cellfilter, 'IP nets', getEntitiesCount ($realm))))
2410 {
2411 $top = NULL;
2412 foreach (listCells ($realm) as $net)
2413 {
2414 if (isset ($top) and IPNetContains ($top, $net))
2415 ;
2416 elseif (! count ($cellfilter['expression']) or judgeCell ($net, $cellfilter['expression']))
2417 $top = $net;
2418 else
2419 continue;
2420 $netlist[$net['id']] = $net;
2421 }
2422 $netcount = count ($netlist);
2423 $tree = prepareIPTree ($netlist, $eid);
2424
2425 if (! renderEmptyResults($cellfilter, 'IP nets', count($tree)))
2426 {
2427 startPortlet ("networks (${netcount})");
2428 echo '<h4>';
2429 $all = "<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'eid'=>'ALL')) .
2430 $cellfilter['urlextra'] . "'>expand&nbsp;all</a>";
2431 $none = "<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'eid'=>'NONE')) .
2432 $cellfilter['urlextra'] . "'>collapse&nbsp;all</a>";
2433 $auto = "<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno)) .
2434 $cellfilter['urlextra'] . "'>auto-collapse</a>";
2435
2436 if ($eid === 0)
2437 echo 'auto-collapsing at threshold ' . getConfigVar ('TREE_THRESHOLD') . " ($all / $none)";
2438 elseif ($eid === 'ALL')
2439 echo "expanding all ($auto / $none)";
2440 elseif ($eid === 'NONE')
2441 echo "collapsing all ($all / $auto)";
2442 else
2443 {
2444 $netinfo = spotEntity ($realm, $eid);
2445 echo "expanding ${netinfo['ip']}/${netinfo['mask']} ($auto / $all / $none)";
2446 }
2447 echo "</h4><table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
2448 echo "<tr><th>prefix</th><th>name/tags</th><th>capacity</th>";
2449 if (getConfigVar ('IPV4_TREE_RTR_AS_CELL') != 'none')
2450 echo "<th>routed by</th>";
2451 echo "</tr>\n";
2452 $baseurl = makeHref(array('page'=>$pageno, 'tab'=>$tabno)) . $cellfilter['urlextra'];
2453 renderIPSpaceRecords ($tree, $baseurl, $eid);
2454 echo "</table>\n";
2455 finishPortlet();
2456 }
2457 }
2458
2459 echo '</td><td class=pcright>';
2460 renderCellFilterPortlet ($cellfilter, $realm, $netlist);
2461 echo "</td></tr></table>\n";
2462 }
2463
2464 function renderIPSpaceEditor()
2465 {
2466 global $pageno;
2467 $realm = ($pageno == 'ipv4space' ? 'ipv4net' : 'ipv6net');
2468 $net_page = $realm; // 'ipv4net', 'ipv6net'
2469 $addrspaceList = listCells ($realm);
2470 startPortlet ('Manage existing (' . count ($addrspaceList) . ')');
2471 if (count ($addrspaceList))
2472 {
2473 echo "<table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
2474 echo "<tr><th>&nbsp;</th><th>prefix</th><th>name</th><th>capacity</th></tr>";
2475 foreach ($addrspaceList as $netinfo)
2476 {
2477 echo "<tr valign=top><td>";
2478 if (! isIPNetworkEmpty ($netinfo))
2479 printImageHREF ('nodestroy', 'There are ' . count ($netinfo['addrlist']) . ' allocations inside');
2480 else
2481 echo getOpLink (array ('op' => 'del', 'id' => $netinfo['id']), '', 'destroy', 'Delete this prefix');
2482 echo '</td><td class=tdleft>' . mkA ("${netinfo['ip']}/${netinfo['mask']}", $net_page, $netinfo['id']) . '</td>';
2483 echo '<td class=tdleft>' . niftyString ($netinfo['name']);
2484 if (count ($netinfo['etags']))
2485 echo '<br><small>' . serializeTags ($netinfo['etags']) . '</small>';
2486 echo '</td><td>';
2487 echo getRenderedIPNetCapacity ($netinfo);
2488 echo '</tr>';
2489 }
2490 echo "</table>";
2491 finishPortlet();
2492 }
2493 }
2494
2495 function renderIPNewNetForm ()
2496 {
2497 global $pageno;
2498 if ($pageno == 'ipv6space')
2499 {
2500 $realm = 'ipv6net';
2501 $regexp = '^[a-fA-F0-9:]*:[a-fA-F0-9:\.]*/\d{1,3}$';
2502 }
2503 else
2504 {
2505 $realm = 'ipv4net';
2506 $regexp = '^(\d{1,3}\.){3}\d{1,3}/\d{1,2}$';
2507 }
2508
2509 // IP prefix validator
2510 addJS ('js/live_validation.js');
2511 $regexp = addslashes ($regexp);
2512 addJS (<<<END
2513 $(document).ready(function () {
2514 $('form#add input[name="range"]').attr('match', '$regexp');
2515 Validate.init();
2516 });
2517 END
2518 , TRUE);
2519
2520 startPortlet ('Add new');
2521 printOpFormIntro ('add');
2522 echo '<table border=0 cellpadding=5 cellspacing=0 align=center>';
2523
2524 // inputs column
2525 $prefix_value = empty ($_REQUEST['set-prefix']) ? '' : $_REQUEST['set-prefix'];
2526 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>";
2527 echo '<tr><th class=tdright>VLAN:</th><td class=tdleft>';
2528 echo getOptionTree ('vlan_ck', getAllVLANOptions(), array ('select_class' => 'vertical', 'tabindex' => 2)) . '</td></tr>';
2529 echo "<tr><th class=tdright>Name:</th><td class=tdleft><input type=text name='name' size='20' tabindex=3></td></tr>";
2530 echo '<tr><th class=tdright>Tags:</th><td class="tdleft">';
2531 printTagsPicker ();
2532 echo '</td></tr>';
2533 echo '<tr><td class=tdright><input type=checkbox name="is_connected" tabindex=4></td><th class=tdleft>reserve subnet-router anycast address</th></tr>';
2534 echo "<tr><td colspan=2>";
2535 printImageHREF ('CREATE', 'Add a new network', TRUE, 5);
2536 echo '</td></tr>';
2537 echo "</table></form><br><br>\n";
2538 finishPortlet();
2539 }
2540
2541 function getRenderedIPNetBacktrace ($range)
2542 {
2543 if (getConfigVar ('EXT_IPV4_VIEW') != 'yes')
2544 return array();
2545
2546 $v = ($range['realm'] == 'ipv4net') ? 4 : 6;
2547 $space = "ipv${v}space"; // ipv4space, ipv6space
2548 $tag = "\$ip${v}netid_"; // $ip4netid_, $ip6netid_
2549
2550 $ret = array();
2551 // Build a backtrace from all parent networks.
2552 $clen = $range['mask'];
2553 $backtrace = array();
2554 $backtrace['&rarr;'] = $range;
2555 $key = '';
2556 while (NULL !== ($upperid = getIPAddressNetworkId ($range['ip_bin'], $clen)))
2557 {
2558 $upperinfo = spotEntity ($range['realm'], $upperid);
2559 $clen = $upperinfo['mask'];
2560 $key .= '&uarr;';
2561 $backtrace[$key] = $upperinfo;
2562 }
2563 foreach (array_reverse ($backtrace) as $arrow => $ainfo)
2564 {
2565 $link = '<a href="' . makeHref (array (
2566 'page' => $space,
2567 'tab' => 'default',
2568 'clear-cf' => '',
2569 'cfe' => '{' . $tag . $ainfo['id'] . '}',
2570 'hl_net' => 1,
2571 'eid' => $range['id'],
2572 )) . '" title="View IP tree with this net as root">' . $arrow . '</a>';
2573 $ret[] = array ($link, getOutputOf ('renderCell', $ainfo));
2574 }
2575 return $ret;
2576 }
2577
2578 function renderIPNetwork ($id)
2579 {
2580 global $pageno;
2581 $realm = $pageno; // 'ipv4net', 'ipv6net'
2582 $range = spotEntity ($realm, $id);
2583 loadIPAddrList ($range);
2584 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
2585 echo "<tr><td colspan=2 align=center><h1>${range['ip']}/${range['mask']}</h1><h2>";
2586 echo htmlspecialchars ($range['name'], ENT_QUOTES, 'UTF-8') . "</h2></td></tr>\n";
2587
2588 echo "<tr><td class=pcleft width='50%'>";
2589
2590 // render summary portlet
2591 $summary = array();
2592 $summary['%% used'] = getRenderedIPNetCapacity ($range);
2593 $summary = getRenderedIPNetBacktrace ($range) + $summary;
2594 if ($realm == 'ipv4net')
2595 {
2596 $summary[] = array ('Netmask:', ip4_format ($range['mask_bin']));
2597 $summary[] = array ('Netmask:', "0x" . strtoupper (implode ('', unpack ('H*', $range['mask_bin']))));
2598 $summary['Wildcard bits'] = ip4_format ( ~ $range['mask_bin']);
2599 }
2600
2601 $reuse_domain = considerConfiguredConstraint ($range, '8021Q_MULTILINK_LISTSRC');
2602 $domainclass = array();
2603 foreach (array_count_values (reduceSubarraysToColumn ($range['8021q'], 'domain_id')) as $domain_id => $vlan_count)
2604 $domainclass[$domain_id] = $vlan_count == 1 ? '' : ($reuse_domain ? '{trwarning}' : '{trerror}');
2605 foreach ($range['8021q'] as $item)
2606 $summary[] = array ($domainclass[$item['domain_id']] . 'VLAN:', formatVLANAsHyperlink (getVLANInfo ($item['domain_id'] . '-' . $item['vlan_id'])));
2607 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes' and count ($routers = findRouters ($range['addrlist'])))
2608 {
2609 $summary['Routed by'] = '';
2610 foreach ($routers as $rtr)
2611 $summary['Routed by'] .= getOutputOf ('renderRouterCell', $rtr['ip_bin'], $rtr['iface'], spotEntity ('object', $rtr['id']));
2612 }
2613 $summary['tags'] = '';
2614 renderEntitySummary ($range, 'summary', $summary);
2615
2616 if (strlen ($range['comment']))
2617 {
2618 startPortlet ('Comment');
2619 echo '<div class=commentblock>' . string_insert_hrefs (htmlspecialchars ($range['comment'], ENT_QUOTES, 'UTF-8')) . '</div>';
2620 finishPortlet ();
2621 }
2622
2623 renderFilesPortlet ($realm, $id);
2624 echo "</td>\n";
2625
2626 echo "<td class=pcright>";
2627 startPortlet ('details');
2628 renderIPNetworkAddresses ($range);
2629 finishPortlet();
2630 echo "</td></tr></table>\n";
2631 }
2632
2633 // Used solely by renderSeparator
2634 function renderEmptyIPv6 ($ip_bin, $hl_ip)
2635 {
2636 $class = 'tdleft';
2637 if ($ip_bin === $hl_ip)
2638 $class .= ' highlight';
2639 $fmt = ip6_format ($ip_bin);
2640 echo "<tr class='$class'><td><a name='ip-$fmt' href='" . makeHref (array ('page' => 'ipaddress', 'ip' => $fmt)) . "'>" . $fmt;
2641 $editable = permitted ('ipaddress', 'properties', 'editAddress')
2642 ? 'editable'
2643 : '';
2644 echo "</a></td><td><span class='rsvtext $editable id-$fmt op-upd-ip-name'></span></td>";
2645 echo "<td><span class='rsvtext $editable id-$fmt op-upd-ip-comment'></span></td><td>&nbsp;</td></tr>\n";
2646 }
2647
2648 // Renders empty table line to shrink empty IPv6 address ranges.
2649 // If the range consists of single address, renders the address instead of empty line.
2650 // Renders address $hl_ip inside the range.
2651 // Used solely by renderIPv6NetworkAddresses
2652 function renderSeparator ($first, $last, $hl_ip)
2653 {
2654 $self = __FUNCTION__;
2655 if (strcmp ($first, $last) > 0)
2656 return;
2657 if ($first == $last)
2658 renderEmptyIPv6 ($first, $hl_ip);
2659 elseif (isset ($hl_ip) && strcmp ($hl_ip, $first) >= 0 && strcmp ($hl_ip, $last) <= 0)
2660 { // $hl_ip is inside the range $first - $last
2661 $self ($first, ip_prev ($hl_ip), $hl_ip);
2662 renderEmptyIPv6 ($hl_ip, $hl_ip);
2663 $self (ip_next ($hl_ip), $last, $hl_ip);
2664 }
2665 else
2666 echo "<tr><td colspan=4 class=tdleft></td></tr>\n";
2667 }
2668
2669 // calculates page number that contains given $ip (used by renderIPv6NetworkAddresses)
2670 function getPageNumOfIPv6 ($list, $ip_bin, $maxperpage)
2671 {
2672 if (intval ($maxperpage) <= 0 || count ($list) <= $maxperpage)
2673 return 0;
2674 $keys = array_keys ($list);
2675 for ($i = 1; $i <= count ($keys); $i++)
2676 if (strcmp ($keys[$i-1], $ip_bin) >= 0)
2677 return intval ($i / $maxperpage);
2678 return intval (count ($list) / $maxperpage);
2679 }
2680
2681 function renderIPNetworkAddresses ($range)
2682 {
2683 switch (strlen ($range['ip_bin']))
2684 {
2685 case 4: return renderIPv4NetworkAddresses ($range);
2686 case 16: return renderIPv6NetworkAddresses ($range);
2687 default: throw new InvalidArgException ("range['ip_bin']", $range['ip_bin']);
2688 }
2689 }
2690
2691 function renderIPv4NetworkAddresses ($range)
2692 {
2693 global $pageno, $tabno, $aac2;
2694 $startip = ip4_bin2int ($range['ip_bin']);
2695 $endip = ip4_bin2int (ip_last ($range));
2696
2697 if (isset ($_REQUEST['hl_ip']))
2698 {
2699 $hl_ip = ip4_bin2int (ip4_parse ($_REQUEST['hl_ip']));
2700 addAutoScrollScript ('ip-' . $_REQUEST['hl_ip']); // scroll page to highlighted ip
2701 }
2702
2703 // pager
2704 $maxperpage = getConfigVar ('IPV4_ADDRS_PER_PAGE');
2705 $address_count = $endip - $startip + 1;
2706 $page = 0;
2707 $rendered_pager = '';
2708 if ($address_count > $maxperpage && $maxperpage > 0)
2709 {
2710 $page = isset ($_REQUEST['pg']) ? $_REQUEST['pg'] : (isset ($hl_ip) ? intval (($hl_ip - $startip) / $maxperpage) : 0);
2711 if ($numpages = ceil ($address_count / $maxperpage))
2712 {
2713 echo '<h3>' . ip4_format (ip4_int2bin ($startip)) . ' ~ ' . ip4_format (ip4_int2bin ($endip)) . '</h3>';
2714 for ($i = 0; $i < $numpages; $i++)
2715 if ($i == $page)
2716 $rendered_pager .= "<b>$i</b> ";
2717 else
2718 $rendered_pager .= "<a href='".makeHref (array ('page' => $pageno, 'tab' => $tabno, 'id' => $range['id'], 'pg' => $i)) . "'>$i</a> ";
2719 }
2720 $startip = $startip + $page * $maxperpage;
2721 $endip = min ($startip + $maxperpage - 1, $endip);
2722 }
2723
2724 echo $rendered_pager;
2725 echo "<table class='widetable' border=0 cellspacing=0 cellpadding=5 align='center' width='100%'>\n";
2726 echo "<tr><th>Address</th><th>Name</th><th>Comment</th><th>Allocation</th></tr>\n";
2727
2728 markupIPAddrList ($range['addrlist']);
2729 for ($ip = $startip; $ip <= $endip; $ip++)
2730 {
2731 $ip_bin = ip4_int2bin ($ip);
2732 $dottedquad = ip4_format ($ip_bin);
2733 $tr_class = (isset ($hl_ip) && $hl_ip == $ip ? 'highlight' : '');
2734 if (isset ($range['addrlist'][$ip_bin]))
2735 $addr = $range['addrlist'][$ip_bin];
2736 else
2737 {
2738 echo "<tr class='tdleft $tr_class'><td class=tdleft><a name='ip-$dottedquad' href='" . makeHref(array('page'=>'ipaddress', 'ip' => $dottedquad)) . "'>$dottedquad</a></td>";
2739 $editable = permitted ('ipaddress', 'properties', 'editAddress')
2740 ? 'editable'
2741 : '';
2742 echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-name'></span></td>";
2743 echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-comment'></span></td><td></td></tr>\n";
2744 continue;
2745 }
2746 // render IP change history
2747 $title = '';
2748 $history_class = '';
2749 if (isset ($addr['last_log']))
2750 {
2751 $title = ' title="' . htmlspecialchars ($addr['last_log']['user'] . ', ' . formatAge ($addr['last_log']['time']) , ENT_QUOTES) . '"';
2752 $history_class = 'hover-history underline';
2753 }
2754 $tr_class .= ' ' . $addr['class'];
2755 echo "<tr class='tdleft $tr_class'>";
2756 echo "<td><a class='$history_class' $title name='ip-$dottedquad' href='".makeHref(array('page'=>'ipaddress', 'ip'=>$addr['ip']))."'>${addr['ip']}</a></td>";
2757 $editable =
2758 (empty ($addr['allocs']) || !empty ($addr['name']) || !empty ($addr['comment']))
2759 && permitted ('ipaddress', 'properties', 'editAddress')
2760 ? 'editable'
2761 : '';
2762 echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-name'>${addr['name']}</span></td>";
2763 echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-comment'>${addr['comment']}</span></td>";
2764 echo "<td>";
2765 $delim = '';
2766 if ( $addr['reserved'] == 'yes')
2767 {
2768 echo "<strong>RESERVED</strong> ";
2769 $delim = '; ';
2770 }
2771 foreach ($addr['allocs'] as $ref)
2772 {
2773 echo $delim . $aac2[$ref['type']];
2774 echo "<a href='".makeHref(array('page'=>'object', 'object_id'=>$ref['object_id'], 'tab' => 'default', 'hl_ip'=>$addr['ip']))."'>";
2775 echo $ref['name'] . (!strlen ($ref['name']) ? '' : '@');
2776 echo "${ref['object_name']}</a>";
2777 $delim = '; ';
2778 }
2779 if ($delim != '')
2780 $delim = '<br>';
2781 foreach ($addr['vslist'] as $vs_id)
2782 {
2783 $vs = spotEntity ('ipv4vs', $vs_id);
2784 echo $delim . mkA ("${vs['name']}:${vs['vport']}/${vs['proto']}", 'ipv4vs', $vs['id']) . '&rarr;';
2785 $delim = '<br>';
2786 }
2787 foreach ($addr['vsglist'] as $vs_id)
2788 {
2789 $vs = spotEntity ('ipvs', $vs_id);
2790 echo $delim . mkA ($vs['name'], 'ipvs', $vs['id']) . '&rarr;';
2791 $delim = '<br>';
2792 }
2793 foreach ($addr['rsplist'] as $rsp_id)