RTSNMPDevice: handle SNMP versions stricter
[racktables] / wwwroot / inc / interface.php
CommitLineData
b325120a 1<?php
cddbb9fd
DO
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
e673ee24
DO
7/*
8*
9* This file contains frontend functions for RackTables.
10*
11*/
12
e82deb48 13require_once 'ajax-interface.php';
defd92d8 14require_once 'slb-interface.php';
65e557dd 15
9c0b0016
DO
16// Interface function's special.
17$nextorder['odd'] = 'even';
18$nextorder['even'] = 'odd';
19
52c836b1
DO
20// address allocation type
21$aat = array
22(
23 'regular' => 'Connected',
24 'virtual' => 'Loopback',
25 'shared' => 'Shared',
26 'router' => 'Router',
2f96a91a 27 'point2point' => 'Point-to-point',
52c836b1 28);
beb9e88a 29// address allocation code, IPv4 addresses and objects view
9d5f6a80 30$aac_right = array
52c836b1
DO
31(
32 'regular' => '',
9d5f6a80
AA
33 'virtual' => '<span class="aac-right" title="' . $aat['virtual'] . '">L</span>',
34 'shared' => '<span class="aac-right" title="' . $aat['shared'] . '">S</span>',
35 'router' => '<span class="aac-right" title="' . $aat['router'] . '">R</span>',
2f96a91a 36 'point2point' => '<span class="aac-right" title="' . $aat['point2point'] . '">P</span>',
52c836b1 37);
beb9e88a 38// address allocation code, IPv4 networks view
9d5f6a80 39$aac_left = array
beb9e88a
DO
40(
41 'regular' => '',
9d5f6a80
AA
42 'virtual' => '<span class="aac-left" title="' . $aat['virtual'] . '">L:</span>',
43 'shared' => '<span class="aac-left" title="' . $aat['shared'] . '">S:</span>',
44 'router' => '<span class="aac-left" title="' . $aat['router'] . '">R:</span>',
2f96a91a 45 'point2point' => '<span class="aac-left" title="' . $aat['point2point'] . '">P:</span>',
beb9e88a 46);
52c836b1 47
0dabdc53
DO
48$vtdecoder = array
49(
50 'ondemand' => '',
54b7ced3
DO
51 'compulsory' => 'P',
52# 'alien' => 'NT',
0dabdc53
DO
53);
54
55$vtoptions = array
56(
54b7ced3
DO
57 'ondemand' => 'auto',
58 'compulsory' => 'permanent',
59# 'alien' => 'never touch',
0dabdc53
DO
60);
61
e5c4506d
DO
62// This may be populated later onsite, report rendering function will use it.
63// See the $systemreport for structure.
64$localreports = array();
d6adad3e 65
8d4f7d18
DO
66$attrtypes = array
67(
68 'uint' => '[U] unsigned integer',
69 'float' => '[F] floating point',
70 'string' => '[S] string',
86ff26ae
DO
71 'dict' => '[D] dictionary record',
72 'date' => '[T] date'
8d4f7d18
DO
73);
74
5eb81cf8
AD
75function showLogoutURL ()
76{
55eefced 77 $https = (isset ($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 's' : '';
5eb81cf8
AD
78 $port = (! in_array ($_SERVER['SERVER_PORT'], array (80, 443))) ? ':' . $_SERVER['SERVER_PORT'] : '';
79 $pathinfo = pathinfo ($_SERVER['REQUEST_URI']);
80 $dirname = $pathinfo['dirname'];
81 // add a trailing slash if the installation resides in a subdirectory
82 if ($dirname != '/')
83 $dirname .= '/';
84 printf ('http%s://logout@%s%s?logout', $https, $_SERVER['SERVER_NAME'], $dirname);
85}
86
a1d72d2e
AA
87$quick_links = NULL; // you can override this in your local.php, but first initialize it with getConfiguredQuickLinks()
88
89function renderQuickLinks()
90{
91 global $quick_links;
92 if (! isset ($quick_links))
93 $quick_links = getConfiguredQuickLinks();
94 echo '<ul class="qlinks">';
95 foreach ($quick_links as $link)
96 echo '<li><a href="' . $link['href'] . '">' . str_replace (' ', '&nbsp;', $link['title']) . '</a></li>';
97 echo '</ul>';
98}
99
f97df464
DO
100function renderInterfaceHTML ($pageno, $tabno, $payload)
101{
102?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
103<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
104<head><title><?php echo getTitle ($pageno); ?></title>
105<?php printPageHeaders(); ?>
106</head>
107<body>
b2937330
AA
108<div class="maintable">
109 <div class="mainheader">
832fdbb9 110 <div style="float: right" class=greeting><?php global $remote_displayname; echo mkA ($remote_displayname, 'myaccount', NULL, 'default'); ?> [ <a href='<?php showLogoutURL(); ?>'>logout</a> ]</div>
a1d72d2e 111 <?php echo getConfigVar ('enterprise') ?> RackTables <a href="http://racktables.org" title="Visit RackTables site"><?php echo CODE_VERSION ?></a><?php renderQuickLinks() ?>
b2937330 112 </div>
d688a63f 113 <div class="menubar"><?php showPathAndSearch ($pageno, $tabno); ?></div>
b2937330
AA
114 <div class="tabbar"><?php showTabs ($pageno, $tabno); ?></div>
115 <div class="msgbar"><?php showMessageOrError(); ?></div>
116 <div class="pagebar"><?php echo $payload; ?></div>
117</div>
f97df464
DO
118</body>
119</html>
120<?php
121}
122
e673ee24 123// Main menu.
f2168c4b
DO
124function renderIndexItem ($ypageno)
125{
126 echo (! permitted ($ypageno)) ? " <td>&nbsp;</td>\n" :
127 " <td>\n" .
128 " <h1><a href='" . makeHref (array ('page' => $ypageno)) . "'>" .
129 getPageName ($ypageno) . "<br>\n" . getImageHREF ($ypageno) .
130 "</a></h1>\n" .
131 " </td>\n";
4b680876
DO
132}
133
e673ee24
DO
134function renderIndex ()
135{
67c5c049 136 global $indexlayout;
e673ee24
DO
137?>
138<table border=0 cellpadding=0 cellspacing=0 width='100%'>
139 <tr>
140 <td>
141 <div style='text-align: center; margin: 10px; '>
a544d2c4 142 <table width='100%' cellspacing=0 cellpadding=20 class=mainmenu border=0>
4b680876 143<?php
67c5c049
DO
144foreach ($indexlayout as $row)
145{
146 echo '<tr>';
147 foreach ($row as $column)
148 if ($column === NULL)
149 echo '<td>&nbsp;</td>';
150 else
151 renderIndexItem ($column);
152 echo '</tr>';
153}
154?>
e673ee24
DO
155 </table>
156 </div>
157 </td>
158 </tr>
159</table>
b325120a 160<?php
e673ee24
DO
161}
162
f3505b35
AA
163function getRenderedAlloc ($object_id, $alloc)
164{
165 $ret = array
166 (
167 'tr_class' => '',
40c9fc94 168 'td_name_suffix' => '',
f3505b35
AA
169 'td_ip' => '',
170 'td_network' => '',
171 'td_routed_by' => '',
172 'td_peers' => '',
173 );
174 $dottedquad = $alloc['addrinfo']['ip'];
4318ced5 175 $ip_bin = $alloc['addrinfo']['ip_bin'];
f3505b35 176
4318ced5
AA
177 $hl_ip_bin = NULL;
178 if (isset ($_REQUEST['hl_ip']))
f3505b35 179 {
4318ced5
AA
180 $hl_ip_bin = ip_parse ($_REQUEST['hl_ip']);
181 addAutoScrollScript ("ip-" . $_REQUEST['hl_ip']);
f3505b35
AA
182 }
183
184 $ret['tr_class'] = $alloc['addrinfo']['class'];
4318ced5 185 if ($hl_ip_bin === $ip_bin)
5c717ce5 186 $ret['tr_class'] .= ' highlight';
dec748f6 187
68c91b9c
AA
188 // render IP change history
189 $ip_title = '';
190 $ip_class = '';
191 if (isset ($alloc['addrinfo']['last_log']))
192 {
193 $log = $alloc['addrinfo']['last_log'];
194 $ip_title = "title='" .
195 htmlspecialchars
196 (
197 $log['user'] . ', ' . formatAge ($log['time']),
198 ENT_QUOTES
199 ) . "'";
200 $ip_class = 'hover-history underline';
201 }
202
f3505b35 203 // render IP address td
9d5f6a80 204 global $aac_right;
4318ced5
AA
205 $netinfo = spotNetworkByIP ($ip_bin);
206 $ret['td_ip'] = "<td class='tdleft'>";
207 if (isset ($netinfo))
208 {
209 $title = $dottedquad;
210 if (getConfigVar ('EXT_IPV4_VIEW') != 'yes')
211 $title .= '/' . $netinfo['mask'];
68c91b9c 212 $ret['td_ip'] .= "<a name='ip-$dottedquad' class='$ip_class' $ip_title href='" .
f3505b35
AA
213 makeHref (
214 array
215 (
4318ced5 216 'page' => 'ipaddress',
f3505b35
AA
217 'hl_object_id' => $object_id,
218 'ip' => $dottedquad,
219 )
4318ced5
AA
220 ) . "'>$title</a>";
221 }
f3505b35 222 else
68c91b9c 223 $ret['td_ip'] .= "<span class='$ip_class' $ip_title>$dottedquad</span>";
9d5f6a80 224 $ret['td_ip'] .= $aac_right[$alloc['type']];
33973968 225 if ($alloc['addrinfo']['name'] != '')
a0bdf6dc 226 $ret['td_ip'] .= ' (' . stringForLabel ($alloc['addrinfo']['name']) . ')';
f3505b35
AA
227 $ret['td_ip'] .= '</td>';
228
229 // render network and routed_by tds
4318ced5
AA
230 $td_class = 'tdleft';
231 if (! isset ($netinfo))
f3505b35
AA
232 {
233 $ret['td_network'] = "<td class='$td_class sparenetwork'>N/A</td>";
234 $ret['td_routed_by'] = $ret['td_network'];
235 }
236 else
237 {
238 $ret['td_network'] = "<td class='$td_class'>" .
239 getOutputOf ('renderCell', $netinfo) . '</td>';
240
98350e52
AA
241 // render "routed by" td
242 if ($display_routers = (getConfigVar ('IPV4_TREE_RTR_AS_CELL') == 'none'))
9d5f6a80 243 $ret['td_routed_by'] = '<td>&nbsp;</td>';
f3505b35 244 else
98350e52 245 {
98350e52 246 $other_routers = array();
6063fab7 247 foreach (findNetRouters ($netinfo) as $router)
98350e52
AA
248 if ($router['id'] != $object_id)
249 $other_routers[] = $router;
250 if (count ($other_routers))
251 $ret['td_routed_by'] = getOutputOf ('printRoutersTD', $other_routers, $display_routers);
252 else
253 $ret['td_routed_by'] = "<td class='$td_class'>&nbsp;</td>";
254 }
f3505b35 255 }
dec748f6 256
f3505b35
AA
257 // render peers td
258 $ret['td_peers'] = "<td class='$td_class'>";
259 $prefix = '';
e749a34f 260 $separator = '; ';
f3505b35
AA
261 if ($alloc['addrinfo']['reserved'] == 'yes')
262 {
263 $ret['td_peers'] .= $prefix . '<strong>RESERVED</strong>';
e749a34f 264 $prefix = $separator;
f3505b35
AA
265 }
266 foreach ($alloc['addrinfo']['allocs'] as $allocpeer)
2f96a91a
AA
267 if ($allocpeer['object_id'] != $object_id)
268 {
269 $ret['td_peers'] .= $prefix . makeIPAllocLink ($ip_bin, $allocpeer);
270 $prefix = $separator;
271 }
272 elseif ($allocpeer['type'] == 'point2point' && isset ($netinfo))
273 {
274 // show PtP peers in the IP network
6063fab7
AA
275 $addrlist = isset ($netinfo['own_addrlist']) ? $netinfo['own_addrlist'] : getIPAddrList ($netinfo, IPSCAN_DO_ALLOCS);
276 foreach (getPtPNeighbors ($ip_bin, $addrlist) as $p_ip_bin => $p_alloc_list)
2f96a91a
AA
277 foreach ($p_alloc_list as $p_alloc)
278 {
279 $ret['td_peers'] .= $prefix . '&harr;&nbsp;' . makeIPAllocLink ($p_ip_bin, $p_alloc);
280 $prefix = $separator;
281 }
282 }
283
f3505b35
AA
284 $ret['td_peers'] .= '</td>';
285
286 return $ret;
287}
288
e1add254
AD
289function renderLocationFilterPortlet ()
290{
e1add254 291 // Recursive function used to build the location tree
2056822d 292 function renderLocationCheckbox ($subtree, $level = 0)
e1add254
AD
293 {
294 $self = __FUNCTION__;
e1add254 295
2056822d 296 foreach ($subtree as $location_id => $location)
e1add254 297 {
9f68b666 298 echo "<div class=tagbox style='text-align:left; padding-left:" . ($level * 16) . "px;'>";
950dfa1f 299 $checked = (! isset ($_SESSION['locationFilter']) || in_array ($location['id'], $_SESSION['locationFilter'])) ? 'checked' : '';
9c88bba9 300 echo "<label><input type=checkbox name='location_id[]' class=${level} value='${location['id']}'${checked} onClick=checkAll(this)>${location['name']}";
9f68b666 301 echo '</label>';
2056822d 302 if ($location['kidc'])
9f68b666
AD
303 {
304 echo "<a id='lfa" . $location['id'] . "' onclick=\"expand('${location['id']}')\" href\"#\" > - </a>";
305 echo "<div id='lfd" . $location['id'] . "'>";
2056822d 306 $self ($location['kids'], $level + 1);
9f68b666
AD
307 echo '</div>';
308 }
309 echo '</div>';
e1add254
AD
310 }
311 }
312
9c88bba9
AD
313 addJS(<<<END
314function checkAll(bx) {
315 for (var tbls=document.getElementsByTagName("table"), i=tbls.length; i--;)
4e9e1b7a 316 if (tbls[i].id == "locationFilter") {
9c88bba9
AD
317 var bxs=tbls[i].getElementsByTagName("input");
318 var in_tree = false;
9f68b666 319 for (var j=0; j<bxs.length; j++) {
9c88bba9
AD
320 if(in_tree == false && bxs[j].value == bx.value)
321 in_tree = true;
322 else if(parseInt(bxs[j].className) <= parseInt(bx.className))
323 in_tree = false;
324 if (bxs[j].type=="checkbox" && in_tree == true)
325 bxs[j].checked = bx.checked;
326 }
327 }
328}
9f68b666
AD
329
330function collapseAll(bx) {
331 for (var tbls=document.getElementsByTagName("table"), i=tbls.length; i--;)
332 if (tbls[i].id == "locationFilter") {
333 var bxs=tbls[i].getElementsByTagName("div");
334 //loop through divs to hide unchecked
335 for (var j=0; j<bxs.length; j++) {
336 var is_checked = -1;
337 var in_div=bxs[j].getElementsByTagName("input");
338 //loop through input to find if any is checked
339 for (var k=0; k<in_div.length; k++) {
340 if(in_div[k].type="checkbox") {
341 if (in_div[k].checked == true) {
342 is_checked = true;
343 break;
344 }
345 else
346 is_checked = false;
347 }
348 }
349 // nothing selected and element id is lfd, collapse it
350 if (is_checked == false && !bxs[j].id.indexOf("lfd"))
351 expand(bxs[j].id.substr(3));
352 }
353 }
354}
355
356function expand(id) {
357 var divid = document.getElementById("lfd" + id);
358 var iconid = document.getElementById("lfa" + id);
359 if (divid.style.display == 'none') {
360 divid.style.display = 'block';
361 iconid.innerHTML = ' - ';
362 } else {
363 divid.style.display = 'none';
364 iconid.innerHTML = ' + ';
365 }
366}
9c88bba9
AD
367END
368 ,TRUE);
e1add254
AD
369 startPortlet ('Location filter');
370 echo <<<END
9c88bba9 371<table border=0 align=center cellspacing=0 class="tagtree" id="locationFilter">
6b816bde 372 <form method=post>
e1add254
AD
373 <input type=hidden name=page value=rackspace>
374 <input type=hidden name=tab value=default>
375 <input type=hidden name=changeLocationFilter value=true>
376END;
2056822d
AA
377
378 $locationlist = listCells ('location');
e1add254
AD
379 if (count ($locationlist))
380 {
9c88bba9
AD
381 echo "<tr><td class=tagbox style='padding-left: 0px'><label>";
382 echo "<input type=checkbox name='location' onClick=checkAll(this)> Toggle all";
1341dc93 383 echo "<img src=?module=chrome&uri=pix/1x1t.gif onLoad=collapseAll(this)>"; // dirty hack to collapse all when page is displayed
9c88bba9 384 echo "</label></td></tr>\n";
9f68b666 385 echo "<tr><td class=tagbox><hr>\n";
d6409c53 386 renderLocationCheckbox (treeFromList (addTraceToNodes ($locationlist)));
9f68b666
AD
387 echo "<hr></td></tr>\n";
388 echo '<tr><td>';
e1add254
AD
389 printImageHREF ('setfilter', 'set filter', TRUE);
390 echo "</td></tr>\n";
391 }
392 else
393 {
394 echo "<tr><td class='tagbox sparenetwork'>(no locations exist)</td></tr>\n";
395 echo "<tr><td>";
396 printImageHREF ('setfilter gray');
397 echo "</td></tr>\n";
398 }
399
400 echo "</form></table>\n";
401 finishPortlet ();
402}
403
d9bad31a
AD
404function rackspaceCmp ($a, $b)
405{
406 $ret = strnatcasecmp ($a['location_tree'], $b['location_tree']);
407 if (!$ret)
408 $ret = strnatcasecmp ($a['row_name'], $b['row_name']);
409 return $ret;
410}
411
150effa7 412function getRackThumbLink ($rack, $scale = 1, $object_id = NULL)
e10d9597
DO
413{
414 if (! is_int ($scale) || $scale <= 0)
415 throw new InvalidArgException ('scale', $scale, 'must be a natural number');
416 $width = getRackImageWidth() * $scale;
417 $height = getRackImageHeight ($rack['height']) * $scale;
418 $title = "${rack['height']} units";
419 $src = '?module=image' .
150effa7
DO
420 ($scale == 1 && $object_id === NULL ? '&img=minirack' : "&img=midirack&scale=${scale}") .
421 "&rack_id=${rack['id']}" .
422 ($object_id === NULL ? '' : "&object_id=${object_id}");
e10d9597 423 $img = "<img border=0 width=${width} height=${height} title='${title}' src='${src}'>";
168c2acb 424 return mkA ($img, 'rack', $rack['id']);
e10d9597
DO
425}
426
e673ee24
DO
427function renderRackspace ()
428{
e1add254 429 // Handle the location filter
0a00b344 430 startSession();
e1add254
AD
431 if (isset ($_REQUEST['changeLocationFilter']))
432 unset ($_SESSION['locationFilter']);
433 if (isset ($_REQUEST['location_id']))
434 $_SESSION['locationFilter'] = $_REQUEST['location_id'];
5d6352df 435 session_commit();
e1add254 436
950dfa1f
AA
437 echo "<table class=objview border=0 width='100%'><tr><td class=pcleft>";
438
95857b5c 439 $found_racks = array();
a8efc03e 440 $cellfilter = getCellFilter();
950dfa1f 441 if (! ($cellfilter['is_empty'] && !isset ($_SESSION['locationFilter']) && renderEmptyResults ($cellfilter, 'racks', getEntitiesCount ('rack'))))
e1add254 442 {
950dfa1f
AA
443 $rows = array();
444 $rackCount = 0;
524f8a7b 445 foreach (listCells ('row') as $row_id => $rowInfo)
950dfa1f 446 {
2b16c179 447 $rackList = applyCellFilter ('rack', $cellfilter, $row_id);
950dfa1f 448 $found_racks = array_merge ($found_racks, $rackList);
d9bad31a
AD
449 $location_id = $rowInfo['location_id'];
450 $locationIdx = 0;
451 // contains location names in the form of 'grandparent parent child', used for sorting
452 $locationTree = '';
453 // contains location names as well as links
454 $hrefLocationTree = '';
455 while ($location_id)
456 {
457 if ($locationIdx == 20)
458 {
459 showWarning ("Warning: There is likely a circular reference in the location tree. Investigate location ${location_id}.");
460 break;
461 }
462 $parentLocation = spotEntity ('location', $location_id);
463 $locationTree = sprintf ('%s %s', $parentLocation['name'], $locationTree);
464 $hrefLocationTree = "&raquo; <a href='" .
465 makeHref(array('page'=>'location', 'location_id'=>$parentLocation['id'])) .
466 "${cellfilter['urlextra']}'>${parentLocation['name']}</a> " .
467 $hrefLocationTree;
468 $location_id = $parentLocation['parent_id'];
469 $locationIdx++;
470 }
471 $hrefLocationTree = substr ($hrefLocationTree, 8);
950dfa1f
AA
472 $rows[] = array (
473 'location_id' => $rowInfo['location_id'],
d9bad31a
AD
474 'location_tree' => $locationTree,
475 'href_location_tree' => $hrefLocationTree,
950dfa1f
AA
476 'row_id' => $row_id,
477 'row_name' => $rowInfo['name'],
478 'racks' => $rackList
479 );
480 $rackCount += count($rackList);
481 }
1ebbf889 482
d9bad31a
AD
483 // sort by location, then by row
484 usort ($rows, 'rackspaceCmp');
485
950dfa1f 486 if (! renderEmptyResults($cellfilter, 'racks', $rackCount))
1ebbf889 487 {
950dfa1f
AA
488 // generate thumb gallery
489 global $nextorder;
950dfa1f
AA
490 // Zero value effectively disables the limit.
491 $maxPerRow = getConfigVar ('RACKS_PER_ROW');
492 $order = 'odd';
18733c4a
AD
493 if (! count ($rows))
494 echo "<h2>No rows found</h2>\n";
495 else
e1add254 496 {
950dfa1f
AA
497 echo '<table border=0 cellpadding=10 class=cooltable>';
498 echo '<tr><th class=tdleft>Location</th><th class=tdleft>Row</th><th class=tdleft>Racks</th></tr>';
499 foreach ($rows as $row)
c08915c7 500 {
950dfa1f 501 $rackList = $row['racks'];
d1d19f79 502 $location_id = $row['location_id'];
950dfa1f
AA
503
504 if (
55eefced
DO
505 $location_id != '' && isset ($_SESSION['locationFilter']) && ! in_array ($location_id, $_SESSION['locationFilter']) ||
506 empty ($rackList) && ! $cellfilter['is_empty']
950dfa1f
AA
507 )
508 continue;
509 $rackListIdx = 0;
d9bad31a
AD
510 echo "<tr class=row_${order}><th class=tdleft>${row['href_location_tree']}</th>";
511 echo "<th class=tdleft><a href='".makeHref(array('page'=>'row', 'row_id'=>$row['row_id']))."${cellfilter['urlextra']}'>${row['row_name']}</a></th>";
950dfa1f 512 echo "<th class=tdleft><table border=0 cellspacing=5><tr>";
18733c4a
AD
513 if (! count ($rackList))
514 echo '<td>(empty row)</td>';
950dfa1f
AA
515 else
516 foreach ($rackList as $rack)
e1add254 517 {
55eefced 518 if ($rackListIdx > 0 && $maxPerRow > 0 && $rackListIdx % $maxPerRow == 0)
950dfa1f
AA
519 {
520 echo '</tr></table></th></tr>';
d9bad31a 521 echo "<tr class=row_${order}><th class=tdleft></th><th class=tdleft>${row['row_name']} (continued)";
950dfa1f
AA
522 echo "</th><th class=tdleft><table border=0 cellspacing=5><tr>";
523 }
168c2acb
DO
524 echo '<td align=center valign=bottom>' . getRackThumbLink ($rack);
525 echo '<br>' . mkA (stringForLabel ($rack['name']), 'rack', $rack['id']) . '</td>';
950dfa1f 526 $rackListIdx++;
e1add254 527 }
950dfa1f
AA
528 $order = $nextorder[$order];
529 echo "</tr></table></th></tr>\n";
530 }
531 echo "</table>\n";
e1add254 532 }
1ebbf889 533 }
e673ee24 534 }
14ad4f4a
DO
535 echo '</td><td class=pcright width="25%">';
536 renderCellFilterPortlet ($cellfilter, 'rack', $found_racks);
e1add254
AD
537 echo "<br>\n";
538 renderLocationFilterPortlet ();
489a7502 539 echo "</td></tr></table>\n";
e673ee24
DO
540}
541
2056822d 542function renderLocationRowForEditor ($subtree, $level = 0)
e1add254
AD
543{
544 $self = __FUNCTION__;
2056822d
AA
545 foreach ($subtree as $locationinfo)
546 {
547 echo "<tr><td align=left style='padding-left: " . ($locationinfo['kidc'] ? $level : ($level + 1) * 16) . "px;'>";
548 if ($locationinfo['kidc'])
549 printImageHREF ('node-expanded-static');
550 if ($locationinfo['refcnt'] > 0 || $locationinfo['kidc'] > 0)
551 printImageHREF ('nodestroy');
552 else
10f5133a 553 echo getOpLink (array ('op' => 'deleteLocation', 'location_id' => $locationinfo['id']), '', 'destroy', 'Delete location');
2056822d
AA
554 echo '</td><td class=tdleft>';
555 printOpFormIntro ('updateLocation', array ('location_id' => $locationinfo['id']));
556 $parent = isset ($locationinfo['parent_id']) ? $locationinfo['parent_id'] : 0;
557 echo getSelect
558 (
559 array ( $parent => $parent ? htmlspecialchars ($locationinfo['parent_name']) : '-- NONE --'),
560 array ('name' => 'parent_id', 'id' => 'locationid_' . $locationinfo['id'], 'class' => 'locationlist-popup'),
561 $parent,
562 FALSE
563 );
564 echo "</td><td class=tdleft>";
565 echo "<input type=text size=48 name=name value='${locationinfo['name']}'>";
566 echo '</td><td>' . getImageHREF ('save', 'Save changes', TRUE) . "</form></td></tr>\n";
567 if ($locationinfo['kidc'])
568 $self ($locationinfo['kids'], $level + 1);
569 }
e1add254
AD
570}
571
82fa45a9 572function renderLocationSelectTree ($select_name, $selected_id = NULL)
eda41675 573{
82fa45a9 574 echo "<select name='${select_name}'>";
eda41675 575 echo '<option value=0>-- NONE --</option>';
359ea9f9 576 $locationlist = listCells ('location');
d6409c53 577 foreach (treeFromList (addTraceToNodes ($locationlist)) as $location)
eda41675
AD
578 {
579 echo "<option value=${location['id']} style='font-weight: bold' ";
580 if ($location['id'] == $selected_id )
581 echo ' selected';
582 echo ">${location['name']}</option>";
e3648fa6 583 printLocationChildrenSelectOptions ($location, $selected_id);
eda41675
AD
584 }
585 echo '</select>';
586}
587
e1add254
AD
588function renderRackspaceLocationEditor ()
589{
b090b2da
RQ
590 $js = <<<JSTXT
591 function locationeditor_showselectbox(e) {
592 $(this).load('index.php', {module: 'ajax', ac: 'get-location-select', locationid: this.id});
593 $(this).unbind('mousedown', locationeditor_showselectbox);
594 }
595 $(document).ready(function () {
596 $('select.locationlist-popup').bind('mousedown', locationeditor_showselectbox);
597 });
598JSTXT;
599
600 addJS($js, TRUE );
e1add254
AD
601 function printNewItemTR ()
602 {
e1add254 603 printOpFormIntro ('addLocation');
eda41675 604 echo '<tr><td>';
e1add254 605 printImageHREF ('create', 'Add new location', TRUE);
82fa45a9
DO
606 echo '</td><td>';
607 renderLocationSelectTree ('parent_id');
04c61e7e
AB
608 echo '</td><td><input type=text size=48 name=name></td><td>';
609 printImageHREF ('create', 'Add new location', TRUE);
e1add254
AD
610 echo "</td></tr></form>\n";
611 }
e1add254
AD
612
613 startPortlet ('Locations');
614 echo "<table border=0 cellspacing=0 cellpadding=5 align=center class=widetable>\n";
615 echo "<tr><th>&nbsp;</th><th>Parent</th><th>Name</th><th>&nbsp;</th></tr>\n";
616 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
617 printNewItemTR();
2056822d 618
1e0f13f3 619 $locations = listCells ('location');
d6409c53 620 renderLocationRowForEditor (treeFromList (addTraceToNodes ($locations)));
2056822d 621
e1add254
AD
622 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
623 printNewItemTR();
624 echo "</table><br>\n";
625 finishPortlet();
626}
627
345fd640
AD
628function renderRackspaceRowEditor ()
629{
eda41675 630 function printNewItemTR ()
345fd640
AD
631 {
632 printOpFormIntro ('addRow');
eda41675 633 echo '<tr><td>';
7be51fea 634 printImageHREF ('create', 'Add new row', TRUE);
04eee8d2
VS
635 echo '</td><td>&nbsp;';
636 echo '</td><td>&nbsp;';
82fa45a9
DO
637 echo '</td><td>';
638 renderLocationSelectTree ('location_id');
04c61e7e
AB
639 echo '</td><td><input type=text name=name></td><td>';
640 printImageHREF ('create', 'Add new row', TRUE);
aca7e169 641 echo '</td><td>&nbsp;';
34f5d4eb 642 echo '</td><td>&nbsp;</td></tr></form>';
345fd640 643 }
d732e47e 644 startPortlet ('Rows');
345fd640 645 echo "<table border=0 cellspacing=0 cellpadding=5 align=center class=widetable>\n";
34f5d4eb 646 echo "<tr><th>&nbsp;</th><th># Racks</th><th># Devices</th><th>Location</th><th>Name</th><th>&nbsp;</th><th>&nbsp;</th><th>Row link</th></tr>\n";
345fd640 647 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
eda41675 648 printNewItemTR ();
524f8a7b 649 foreach (listCells ('row') as $row_id => $rowInfo)
345fd640 650 {
eda41675 651 echo '<tr><td>';
04eee8d2
VS
652 $rc = $rowInfo['rackc'];
653 $delete_racks_str = $rc ? " and $rc rack(s)" : '';
654 echo getOpLink (array ('op'=>'deleteRow', 'row_id'=>$row_id), '', 'destroy', 'Delete row'.$delete_racks_str, 'need-confirmation');
c40666f5 655 printOpFormIntro ('updateRow', array ('row_id' => $row_id));
34f5d4eb 656 echo '</td><td class=tdright>';
04eee8d2 657 echo $rc;
34f5d4eb 658 echo '</td><td class=tdright>';
04eee8d2
VS
659 echo getRowMountsCount ($row_id);
660 echo '</td><td>';
82fa45a9 661 renderLocationSelectTree ('location_id', $rowInfo['location_id']);
04c61e7e 662 echo "</td><td><input type=text name=name value='${rowInfo['name']}'></td><td>";
7be51fea 663 printImageHREF ('save', 'Save changes', TRUE);
524f8a7b 664 echo "</form></td>";
34f5d4eb
DO
665 echo '<td>&nbsp;</td>';
666 echo '<td class=tdleft>' . mkCellA ($rowInfo) . '</td>';
524f8a7b 667 echo "</tr>\n";
345fd640
AD
668 }
669 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
eda41675 670 printNewItemTR ();
345fd640
AD
671 echo "</table><br>\n";
672 finishPortlet();
673}
674
d10401bf 675function renderRow ($row_id)
e673ee24 676{
e16b666c 677 $rowInfo = getRowInfo ($row_id);
a8efc03e 678 $cellfilter = getCellFilter();
2b16c179 679 $rackList = applyCellFilter ('rack', $cellfilter, $row_id);
138655f5
AD
680
681 $summary = array ();
682 $summary['Name'] = $rowInfo['name'];
683 if ($rowInfo['location_id'])
684 $summary['Location'] = mkA ($rowInfo['location'], 'location', $rowInfo['location_id']);
685 $summary['Racks'] = $rowInfo['count'];
686 $summary['Units'] = $rowInfo['sum'];
687 $summary['% used'] = getProgressBar (getRSUforRow ($rackList));
249c78b2 688 foreach (getAttrValuesSorted ($row_id) as $record)
138655f5
AD
689 if
690 (
55eefced 691 $record['value'] != '' &&
138655f5
AD
692 permitted (NULL, NULL, NULL, array (array ('tag' => '$attr_' . $record['id'])))
693 )
5b908204 694 $summary['{sticker}' . $record['name']] = formatAttributeValue ($record, 1561);
138655f5 695
e673ee24
DO
696 // Main layout starts.
697 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
698
699 // Left portlet with row information.
700 echo "<tr><td class=pcleft>";
138655f5 701 renderEntitySummary ($rowInfo, 'Summary', $summary);
7f297114 702 renderCellFilterPortlet ($cellfilter, 'rack', $rackList, array ('row_id' => $row_id));
6ccfd4bd 703 renderFilesPortlet ('row',$row_id);
48325652 704 echo "</td><td class=pcright>";
e673ee24 705
4fbb5a00 706 global $nextorder;
f5883ec1
DO
707 // Maximum number of racks per row is proportionally less, but at least 1.
708 $maxPerRow = max (floor (getConfigVar ('RACKS_PER_ROW') / getConfigVar ('ROW_SCALE')), 1);
709 $rackListIdx = 0;
e673ee24
DO
710 $order = 'odd';
711 startPortlet ('Racks');
712 echo "<table border=0 cellspacing=5 align='center'><tr>";
64b95774 713 foreach ($rackList as $rack)
e673ee24 714 {
f5883ec1
DO
715 if ($rackListIdx % $maxPerRow == 0)
716 {
717 if ($rackListIdx > 0)
718 echo '</tr>';
719 echo '<tr>';
720 }
9b8174d7 721 $class = ($rack['has_problems'] == 'yes') ? 'error' : $order;
168c2acb
DO
722 echo "<td align=center valign=bottom class=row_${class}>" .
723 getRackThumbLink ($rack, getConfigVar ('ROW_SCALE')) .
724 '<br>' . mkA (stringForLabel ($rack['name']), 'rack', $rack['id']) . '</td>';
e673ee24 725 $order = $nextorder[$order];
f5883ec1 726 $rackListIdx++;
e673ee24
DO
727 }
728 echo "</tr></table>\n";
729 finishPortlet();
e673ee24
DO
730 echo "</td></tr></table>";
731}
732
5ff78aff
DO
733function renderEditAttributeTRs ($update_op, $values, $objtype_id, $skip_ids = array())
734{
735 $datehint = ' (' . datetimeFormatHint (getConfigVar ('DATETIME_FORMAT')) . ')';
736 $i = 0;
737 foreach ($values as $record)
738 {
739 $annex = array (array ('tag' => '$attr_' . $record['id']));
740 $can_view = permitted (NULL, NULL, NULL, $annex);
741 if (in_array ($record['id'], $skip_ids) || ! $can_view)
742 continue;
743 $can_update = permitted (NULL, NULL, $update_op, $annex);
744 $can_clear = permitted (NULL, NULL, 'clearSticker', $annex);
745 // Ability to update ultimately includes ability to set to an empty value,
746 // i.e. to clear, but making the check this way in the ophandler is complicated,
747 // so let's keep it consistently imperfect for the time being and maybe
748 // fix it later.
749 $clear_html = ($record['value'] != '' && ($can_clear /* || $can_update*/)) ?
750 getOpLink (array ('op' => 'clearSticker', 'attr_id' => $record['id']), '', 'clear', 'Clear value', 'need-confirmation') :
751 '&nbsp;';
752 echo "<tr><td>${clear_html}</td>";
753 echo '<th class=sticker>' . $record['name'] . ($record['type'] == 'date' ? $datehint : '') . ':</th>';
754 echo '<td class=tdleft>';
755 switch ($record['type'])
756 {
757 case 'uint':
758 case 'float':
759 case 'string':
760 $ro_or_rw = $can_update ? "name=${i}_value" : 'disabled';
761 echo "<input type=text ${ro_or_rw} value='${record['value']}'>";
762 break;
763 case 'date':
764 $ro_or_rw = $can_update ? "name=${i}_value" : 'disabled';
765 $date_value = $record['value'] ? datetimestrFromTimestamp ($record['value']) : '';
766 echo "<input type=text ${ro_or_rw} value='${date_value}'>";
767 break;
768 case 'dict':
769 $ro_or_rw = $can_update ? array ('name' => "${i}_value") : array ('name' => "${i}_value", 'disabled' => 1);
770 $chapter = readChapter ($record['chapter_id'], 'o');
771 $chapter[0] = '-- NOT SET --';
772 $chapter = cookOptgroups ($chapter, $objtype_id, $record['key']);
773 printNiftySelect ($chapter, $ro_or_rw, $record['key']);
774 break;
775 default:
776 throw new InvalidArgException ('record[type]', $record['type']);
777 } // switch
778 if ($can_update)
779 {
780 echo "<input type=hidden name=${i}_attr_id value=${record['id']}>";
781 $i++;
782 }
783 echo '</td></tr>';
784 } // foreach
785 echo "<input type=hidden name=num_attrs value=${i}>";
786}
787
d10401bf 788function renderEditRowForm ($row_id)
138655f5
AD
789{
790 $row = getRowInfo ($row_id);
791
792 startPortlet ('Attributes');
793 printOpFormIntro ('updateRow');
794 echo '<table border=0 align=center>';
795 echo '<tr><td>&nbsp;</td><th class=tdright>Location:</th><td class=tdleft>';
796 $locations = array ();
797 $locations[0] = '-- NOT SET --';
798 foreach (listCells ('location') as $id => $locationInfo)
799 $locations[$id] = $locationInfo['name'];
800 natcasesort ($locations);
801 printSelect ($locations, array ('name' => 'location_id'), $row['location_id']);
802 echo "</td></tr>\n";
803 echo "<tr><td>&nbsp;</td><th class=tdright>Name (required):</th><td class=tdleft><input type=text name=name value='${row['name']}'></td></tr>\n";
5ff78aff 804 renderEditAttributeTRs ('updateRow', getAttrValuesSorted ($row_id), 1561);
138655f5
AD
805 if ($row['count'] == 0)
806 {
807 echo '<tr><td>&nbsp;</td><th class=tdright>Actions:</th><td class=tdleft>';
808 echo getOpLink (array ('op'=>'deleteRow'), '', 'destroy', 'Delete row', 'need-confirmation');
809 echo "&nbsp;</td></tr>\n";
810 }
811 echo "<tr><td class=submit colspan=3>";
812 printImageHREF ('SAVE', 'Save changes', TRUE);
813 echo "</td></tr>\n";
814 echo '</form></table><br>';
815 finishPortlet();
816
817 startPortlet ('History');
818 renderObjectHistory ($row_id);
819 finishPortlet();
820}
821
0a7feebb 822// Used by renderRack()
84feb87b 823function printObjectDetailsForRenderRack ($object_id, $hl_obj_id = 0)
0a7feebb
AD
824{
825 $objectData = spotEntity ('object', $object_id);
33973968 826 if ($objectData['asset_no'] != '')
0a7feebb
AD
827 $prefix = "<div title='${objectData['asset_no']}";
828 else
829 $prefix = "<div title='no asset tag";
830 // Don't tell about label, if it matches common name.
831 $body = '';
55eefced 832 if ($objectData['name'] != $objectData['label'] && $objectData['label'] != '')
0a7feebb
AD
833 $body = ", visible label is \"${objectData['label']}\"";
834 // Display list of child objects, if any
c17a36f0 835 $objectChildren = getChildren ($objectData, 'object');
5a7bf292 836 $slotRows = $slotCols = $slotInfo = $slotData = $slotTitle = $slotClass = array ();
0a7feebb
AD
837 if (count($objectChildren) > 0)
838 {
c17a36f0 839 foreach ($objectChildren as $childData)
84feb87b 840 {
c17a36f0
AA
841 $childNames[] = $childData['name'];
842 $attrData = getAttrValues ($childData['id']);
be28528c
M
843 $numRows = $numCols = 1;
844 if (isset ($attrData[2])) // HW type
845 {
846 extractLayout ($attrData[2]);
847 if (isset ($attrData[2]['rows']))
848 {
849 $numRows = $attrData[2]['rows'];
850 $numCols = $attrData[2]['cols'];
851 }
852 }
05abd358 853 if (isset ($attrData['28'])) // slot number
84feb87b
AD
854 {
855 $slot = $attrData['28']['value'];
be28528c
M
856 if (preg_match ('/\d+/', $slot, $matches))
857 $slot = $matches[0];
858 $slotRows[$slot] = $numRows;
859 $slotCols[$slot] = $numCols;
c17a36f0
AA
860 $slotInfo[$slot] = $childData['dname'];
861 $slotData[$slot] = $childData['id'];
33973968 862 if ($childData['asset_no'] != '')
84feb87b
AD
863 $slotTitle[$slot] = "<div title='${childData['asset_no']}";
864 else
865 $slotTitle[$slot] = "<div title='no asset tag";
55eefced 866 if ($childData['label'] != '' && $childData['label'] != $childData['dname'])
84feb87b
AD
867 $slotTitle[$slot] .= ", visible label is \"${childData['label']}\"";
868 $slotTitle[$slot] .= "'>";
5a7bf292 869 $slotClass[$slot] = 'state_T';
c17a36f0 870 if ($childData['id'] == $hl_obj_id)
0cdfc55c
DO
871 $slotClass[$slot] .= 'h';
872 if ($childData['has_problems'] == 'yes')
873 $slotClass[$slot] .= 'w';
84feb87b
AD
874 }
875 }
0a7feebb
AD
876 natsort($childNames);
877 $suffix = sprintf(", contains %s'>", implode(', ', $childNames));
878 }
879 else
880 $suffix = "'>";
6d8424f8 881 echo "${prefix}${body}${suffix}" . mkCellA ($objectData) . '</div>';
84feb87b
AD
882 if (in_array ($objectData['objtype_id'], array (1502,1503))) // server chassis, network chassis
883 {
884 $objAttr = getAttrValues ($objectData['id']);
885 if (isset ($objAttr[2])) // HW type
886 {
887 extractLayout ($objAttr[2]);
888 if (isset ($objAttr[2]['rows']))
889 {
890 $rows = $objAttr[2]['rows'];
891 $cols = $objAttr[2]['cols'];
892 $layout = $objAttr[2]['layout'];
893 echo "<table width='100%' border='1'>";
894 for ($r = 0; $r < $rows; $r++)
895 {
896 echo '<tr>';
897 for ($c = 0; $c < $cols; $c++)
898 {
899 $s = ($r * $cols) + $c + 1;
900 if (isset ($slotData[$s]))
901 {
be28528c 902 if ($slotData[$s] >= 0)
84feb87b 903 {
be28528c
M
904 for ($lr = 0; $lr < $slotRows[$s]; $lr++)
905 for ($lc = 0; $lc < $slotCols[$s]; $lc++)
906 {
907 $skip = ($lr * $cols) + $lc;
908 if ($skip > 0)
909 $slotData[$s + $skip] = -1;
910 }
911 echo '<td';
912 if ($slotRows[$s] > 1)
913 echo " rowspan=$slotRows[$s]";
914 if ($slotCols[$s] > 1)
915 echo " colspan=$slotCols[$s]";
5a7bf292 916 echo " class='${slotClass[$s]}'>${slotTitle[$s]}";
be28528c
M
917 if ($layout == 'V')
918 {
3e393bcc
AY
919 $tmp = mb_substr($slotInfo[$s], 0, 1);
920 for($i = 1; $i < mb_strlen($slotInfo[$s]); $i++)
921 {
922 $tmp .= '<br>' . mb_substr($slotInfo[$s], $i, 1);
923 }
be28528c
M
924 $slotInfo[$s] = $tmp;
925 }
926 echo mkA ($slotInfo[$s], 'object', $slotData[$s]);
927 echo '</div></td>';
84feb87b 928 }
84feb87b
AD
929 }
930 else
931 echo "<td class='state_F'><div title=\"Free slot\">&nbsp;</div></td>";
932 }
933 echo '</tr>';
934 }
935 echo '</table>';
936 }
937 }
938 }
0a7feebb
AD
939}
940
e673ee24 941// This function renders rack as HTML table.
7e1db771 942function renderRack ($rack_id, $hl_obj_id = 0)
e673ee24 943{
61a1d996
DO
944 $rackData = spotEntity ('rack', $rack_id);
945 amplifyCell ($rackData);
e673ee24
DO
946 markAllSpans ($rackData);
947 if ($hl_obj_id > 0)
948 highlightObject ($rackData, $hl_obj_id);
736acd8d 949 $neighbors = getRackNeighbors ($rackData['row_id'], $rack_id);
eda8b3ce
DO
950 $prev_id = $neighbors['prev'];
951 $next_id = $neighbors['next'];
d48d8820 952 echo "<center><table border=0><tr valign=middle>";
ad3e5e7e 953 echo '<td><h2>' . mkA ($rackData['row_name'], 'row', $rackData['row_id']) . ' :</h2></td>';
e673ee24 954 if ($prev_id != NULL)
ad3e5e7e
DO
955 echo '<td>' . mkA (getImageHREF ('prev', 'previous rack'), 'rack', $prev_id) . '</td>';
956 echo '<td><h2>' . mkA ($rackData['name'], 'rack', $rackData['id']) . '</h2></td>';
e673ee24 957 if ($next_id != NULL)
ad3e5e7e 958 echo '<td>' . mkA (getImageHREF ('next', 'next rack'), 'rack', $next_id) . '</td>';
d48d8820 959 echo "</h2></td></tr></table>\n";
e673ee24 960 echo "<table class=rack border=0 cellspacing=0 cellpadding=1>\n";
d08147d6
DO
961 echo "<tr><th width='10%'>&nbsp;</th><th width='20%'>Front</th>";
962 echo "<th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n";
e673ee24
DO
963 for ($i = $rackData['height']; $i > 0; $i--)
964 {
4dcd770e 965 echo "<tr><th>" . inverseRackUnit ($i, $rackData) . "</th>";
e673ee24
DO
966 for ($locidx = 0; $locidx < 3; $locidx++)
967 {
968 if (isset ($rackData[$i][$locidx]['skipped']))
969 continue;
970 $state = $rackData[$i][$locidx]['state'];
65e557dd 971 echo "<td class='atom state_${state}";
e673ee24
DO
972 if (isset ($rackData[$i][$locidx]['hl']))
973 echo $rackData[$i][$locidx]['hl'];
65e557dd 974 echo "'";
e673ee24
DO
975 if (isset ($rackData[$i][$locidx]['colspan']))
976 echo ' colspan=' . $rackData[$i][$locidx]['colspan'];
977 if (isset ($rackData[$i][$locidx]['rowspan']))
978 echo ' rowspan=' . $rackData[$i][$locidx]['rowspan'];
979 echo ">";
980 switch ($state)
981 {
982 case 'T':
84feb87b 983 printObjectDetailsForRenderRack ($rackData[$i][$locidx]['object_id'], $hl_obj_id);
e673ee24
DO
984 break;
985 case 'A':
986 echo '<div title="This rackspace does not exist">&nbsp;</div>';
987 break;
988 case 'F':
989 echo '<div title="Free rackspace">&nbsp;</div>';
990 break;
991 case 'U':
992 echo '<div title="Problematic rackspace, you CAN\'T mount here">&nbsp;</div>';
993 break;
994 default:
995 echo '<div title="No data">&nbsp;</div>';
996 break;
997 }
998 echo '</td>';
999 }
1000 echo "</tr>\n";
1001 }
0a7feebb
AD
1002 echo "</table>\n";
1003 // Get a list of all of objects Zero-U mounted to this rack
c17a36f0
AA
1004 $zeroUObjects = getChildren ($rackData, 'object');
1005 uasort ($zeroUObjects, 'compare_name');
a20a4e3c
DO
1006 if (count ($zeroUObjects) > 0)
1007 {
0a7feebb
AD
1008 echo "<br><table width='75%' class=rack border=0 cellspacing=0 cellpadding=1>\n";
1009 echo "<tr><th>Zero-U:</th></tr>\n";
1010 foreach ($zeroUObjects as $zeroUObject)
1011 {
c17a36f0 1012 $state = ($zeroUObject['id'] == $hl_obj_id) ? 'Th' : 'T';
a2037cdd
DO
1013 if ($zeroUObject['has_problems'] == 'yes')
1014 $state .= 'w';
0a7feebb 1015 echo "<tr><td class='atom state_${state}'>";
c17a36f0 1016 printObjectDetailsForRenderRack($zeroUObject['id']);
0a7feebb
AD
1017 echo "</td></tr>\n";
1018 }
1019 echo "</table>\n";
1020 }
1021 echo "</center>\n";
e673ee24
DO
1022}
1023
d10401bf 1024function renderRackSortForm ($row_id)
42504426 1025{
b090b2da
RQ
1026 includeJQueryUI (false);
1027 $js = <<<JSTXT
1028 $(document).ready(
1029 function () {
1030 $("#sortRacks").sortable({
1031 update : function () {
1032 serial = $('#sortRacks').sortable('serialize');
1033 $.ajax({
824886b2 1034 url: 'index.php?module=ajax&ac=upd-rack-sort-order&row_id=${row_id}',
b090b2da
RQ
1035 type: 'post',
1036 data: serial,
1037 });
1038 }
1039 });
1040 }
42504426 1041 );
b090b2da
RQ
1042JSTXT;
1043 addJS($js, true);
42504426
AD
1044
1045 startPortlet ('Racks');
1046 echo "<table border=0 cellspacing=0 cellpadding=5 align=center class=widetable>\n";
1047 echo "<tr><th>Drag to change order</th></tr>\n";
34f5d4eb 1048 echo "<tr><td class=tdleft><ul class='uflist' id='sortRacks'>\n";
42504426
AD
1049 foreach (getRacks($row_id) as $rack_id => $rackInfo)
1050 echo "<li id=racks_${rack_id}>${rackInfo['name']}</li>\n";
1051 echo "</ul></td></tr></table>\n";
1052 finishPortlet();
1053}
1054
78ba6f56 1055function renderNewRackForm()
e673ee24 1056{
9b8174d7
AD
1057 $default_height = getConfigVar ('DEFAULT_RACK_HEIGHT');
1058 if ($default_height == 0)
1059 $default_height = '';
50b4ba85 1060 startPortlet ('Add one');
6b552311 1061 printOpFormIntro ('addRack', array ('mode' => 'one'));
e673ee24 1062 echo '<table border=0 align=center>';
04c61e7e
AB
1063 echo "<tr><th class=tdright>Name (required):</th><td class=tdleft><input type=text name=name></td>";
1064 echo "<tr><th class=tdright>Height in units (required):</th><td class=tdleft><input type=text name=height1 value='${default_height}'></td></tr>\n";
1065 echo "<tr><th class=tdright>Asset tag:</th><td class=tdleft><input type=text name=asset_no></td></tr>\n";
1066 echo "<tr><th class=tdright>Tags:</td><td class=tdleft>";
e7b84015 1067 printTagsPicker ();
72d52730 1068 echo "</td></tr>\n";
f19c75d6
DO
1069 echo "<tr><td class=submit colspan=2>";
1070 printImageHREF ('CREATE', 'Add', TRUE);
1071 echo "</td></tr></table></form>";
406b54bd 1072 finishPortlet();
406b54bd 1073
50b4ba85 1074 startPortlet ('Add many');
6b552311 1075 printOpFormIntro ('addRack', array ('mode' => 'many'));
50b4ba85 1076 echo '<table border=0 align=center>';
9b8174d7 1077 echo "<tr><th class=tdright>Height in units (*):</th><td class=tdleft><input type=text name=height2 value='${default_height}'></td>";
04c61e7e 1078 echo "<tr><th class=tdright>Assign tags:</td><td class=tdleft>";
e7b84015 1079 printTagsPicker ();
72d52730 1080 echo "</td></tr>\n";
9b8174d7 1081 echo "<tr><th class=tdright>Rack names (required):</th><td class=tdleft><textarea name=names cols=40 rows=25></textarea></td></tr>\n";
f19c75d6
DO
1082 echo "<tr><td class=submit colspan=2>";
1083 printImageHREF ('CREATE', 'Add', TRUE);
e673ee24
DO
1084 echo '</form></table>';
1085 finishPortlet();
1086}
1087
3825c4db 1088function renderEditObjectForm()
e673ee24 1089{
42422859 1090 global $pageno;
3825c4db 1091 $object_id = getBypassValue();
fb6e2f57 1092 $object = spotEntity ('object', $object_id);
cdd3efe9 1093 startPortlet ();
43fb6eaf 1094 printOpFormIntro ('update');
cdd3efe9
AD
1095
1096 // static attributes
e10f583a
DO
1097 echo '<table border=0 cellspacing=0 cellpadding=3 align=center>';
1098 echo "<tr><td>&nbsp;</td><th colspan=2><h2>Attributes</h2></th></tr>";
3825c4db
DO
1099 echo '<tr><td>&nbsp;</td><th class=tdright>Type:</th><td class=tdleft>';
1100 printSelect (getObjectTypeChangeOptions ($object['id']), array ('name' => 'object_type_id'), $object['objtype_id']);
1101 echo '</td></tr>';
22bb04da 1102 // baseline info
e10f583a 1103 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";
42422859
AD
1104 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";
1105 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";
e7b84015
AB
1106 echo "<tr><td>&nbsp;</td><th class=tdright>Tags:</th><td class=tdleft>";
1107 printTagsPicker ();
1108 echo "</td></tr>\n";
0682218d 1109 // parent selection
9b8174d7 1110 if (objectTypeMayHaveParent ($object['objtype_id']))
0682218d 1111 {
9563f56f 1112 $parents = getParents ($object, 'object');
af8916e9
AD
1113 // lookup the human-readable object type, sort by it
1114 foreach ($parents as $parent_id => $parent)
1115 $parents[$parent_id]['object_type'] = decodeObjectType ($parent['objtype_id']);
1116 $grouped_parents = groupBy ($parents, 'object_type');
1117 ksort ($grouped_parents);
1118 foreach ($grouped_parents as $parents_group)
0682218d 1119 {
9563f56f 1120 uasort ($parents_group, 'compare_name');
af8916e9 1121 $label = $parents_group[key ($parents_group)]['object_type'] . (count($parents_group) > 1 ? ' containers:' : ' container:');
9563f56f 1122 foreach ($parents_group as $link_id => $parent_cell)
8526b4cc 1123 {
8526b4cc
J
1124 echo "<tr><td>&nbsp;</td>";
1125 echo "<th class=tdright>${label}</th><td class=tdleft>";
9563f56f 1126 echo mkCellA ($parent_cell);
8526b4cc
J
1127 echo "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
1128 echo getOpLink (array('op'=>'unlinkObjects', 'link_id'=>$link_id), '', 'cut', 'Unlink container');
1129 echo "</td></tr>\n";
1130 $label = '&nbsp;';
1131 }
0682218d
AD
1132 }
1133 echo "<tr><td>&nbsp;</td>";
1134 echo "<th class=tdright>Select container:</th><td class=tdleft>";
5d4ca0f3 1135 echo getPopupLink ('objlist', array(), 'findlink', 'attach', 'Select a container');
de55c069 1136 echo "</td></tr>\n";
0682218d 1137 }
5ff78aff 1138 renderEditAttributeTRs ('update', getAttrValuesSorted ($object_id), $object['objtype_id']);
f5b9c21a
DO
1139 echo '<tr><td>&nbsp;</td><th class=tdright><label for=object_has_problems>Has problems:</label></th>';
1140 echo '<td class=tdleft><input type=checkbox name=object_has_problems id=object_has_problems';
e10f583a
DO
1141 if ($object['has_problems'] == 'yes')
1142 echo ' checked';
1143 echo "></td></tr>\n";
dec748f6 1144 echo "<tr><td>&nbsp;</td><th class=tdright>Actions:</th><td class=tdleft>";
10f5133a 1145 echo getOpLink (array ('op'=>'deleteObject', 'page'=>'depot', 'tab'=>'addmore', 'object_id'=>$object_id), '' ,'destroy', 'Delete object', 'need-confirmation');
abd1e9ac 1146 echo "&nbsp;";
10f5133a 1147 echo getOpLink (array ('op'=>'resetObject'), '' ,'clear', 'Reset (cleanup) object', 'need-confirmation');
abd1e9ac 1148 echo "</td></tr>\n";
e10f583a 1149 echo "<tr><td colspan=3><b>Comment:</b><br><textarea name=object_comment rows=10 cols=80>${object['comment']}</textarea></td></tr>";
cdd3efe9 1150
e10f583a 1151 echo "<tr><th class=submit colspan=3>";
5bbbeaa2 1152 printImageHREF ('SAVE', 'Save changes', TRUE);
cdd3efe9 1153 echo "</form></th></tr></table>\n";
e673ee24 1154 finishPortlet();
e673ee24 1155
cdd3efe9 1156 echo '<table border=0 width=100%><tr><td>';
e673ee24 1157 startPortlet ('history');
9b8174d7 1158 renderObjectHistory ($object_id);
e673ee24 1159 finishPortlet();
cdd3efe9 1160 echo '</td></tr></table>';
e673ee24
DO
1161}
1162
d10401bf 1163function renderEditRackForm ($rack_id)
e673ee24 1164{
0c2b7c4a 1165 global $pageno;
61a1d996
DO
1166 $rack = spotEntity ('rack', $rack_id);
1167 amplifyCell ($rack);
e673ee24 1168
9b8174d7 1169 startPortlet ('Attributes');
7056988c 1170 printOpFormIntro ('updateRack');
e673ee24 1171 echo '<table border=0 align=center>';
9b8174d7 1172 echo "<tr><td>&nbsp;</td><th class=tdright>Rack row:</th><td class=tdleft>";
524f8a7b 1173 foreach (listCells ('row') as $row_id => $rowInfo)
64a973a7
AD
1174 {
1175 $trail = getLocationTrail ($rowInfo['location_id'], FALSE);
1176 $rows[$row_id] = empty ($trail) ? $rowInfo['name'] : $rowInfo['name'] . ' [' . $trail . ']';
1177 }
1178 natcasesort ($rows);
e1add254 1179 printSelect ($rows, array ('name' => 'row_id'), $rack['row_id']);
e673ee24 1180 echo "</td></tr>\n";
9b8174d7
AD
1181 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";
1182 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";
9b8174d7 1183 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";
e7b84015
AB
1184 echo "<tr><td>&nbsp;</td><th class=tdright>Tags:</th><td class=tdleft>";
1185 printTagsPicker ();
1186 echo "</td></tr>\n";
5ff78aff 1187 renderEditAttributeTRs ('updateRack', getAttrValuesSorted ($rack_id), 1560, array (27, 29));
9b8174d7
AD
1188 echo "<tr><td>&nbsp;</td><th class=tdright>Has problems:</th><td class=tdleft><input type=checkbox name=has_problems";
1189 if ($rack['has_problems'] == 'yes')
1190 echo ' checked';
1191 echo "></td></tr>\n";
04eee8d2 1192 echo "<tr><td>&nbsp;</td><th class=tdright>Actions:</th><td class=tdleft>";
c495997f 1193 if ($rack['isDeletable'])
c8187437 1194 {
10f5133a 1195 echo getOpLink (array ('op'=>'deleteRack'), '', 'destroy', 'Delete rack', 'need-confirmation');
04eee8d2 1196 echo "&nbsp;";
c8187437 1197 }
04eee8d2
VS
1198 else
1199 {
1200 echo getOpLink (array ('op'=>'cleanRack'), '' ,'clear', 'Reset (cleanup) rack mounts', 'need-confirmation');
1201 echo "&nbsp;";
1202 }
1203 echo "</td></tr>\n";
9b8174d7
AD
1204 echo "<tr><td colspan=3><b>Comment:</b><br><textarea name=comment rows=10 cols=80>${rack['comment']}</textarea></td></tr>";
1205 echo "<tr><td class=submit colspan=3>";
7056988c
DO
1206 printImageHREF ('SAVE', 'Save changes', TRUE);
1207 echo "</td></tr>\n";
e673ee24
DO
1208 echo '</form></table><br>';
1209 finishPortlet();
dec748f6 1210
e673ee24 1211 startPortlet ('History');
9b8174d7 1212 renderObjectHistory ($rack_id);
e673ee24
DO
1213 finishPortlet();
1214}
1215
6b9bdb08
AA
1216// populates the $summary array with the sum of power attributes of the objects mounted into the rack
1217function populateRackPower ($rackData, &$summary)
1218{
1219 $power_attrs = array(
1220 7, // 'float','max. current, Ampers'
1221 13, // 'float','max power, Watts'
1222 );
1223 $sum = array();
1224 if (! isset ($rackData['mountedObjects']))
1225 amplifyCell ($rackData);
1226 foreach ($rackData['mountedObjects'] as $object_id)
1227 {
1228 $attrs = getAttrValues ($object_id);
1229 foreach ($power_attrs as $attr_id)
1230 if (isset ($attrs[$attr_id]) && $attrs[$attr_id]['type'] == 'float')
1231 {
1232 if (! isset ($sum[$attr_id]))
1233 {
1234 $sum[$attr_id]['sum'] = 0.0;
1235 $sum[$attr_id]['name'] = $attrs[$attr_id]['name'];
1236 }
1237 $sum[$attr_id]['sum'] += $attrs[$attr_id]['value'];
1238 }
1239 }
1240 foreach ($sum as $attr)
1241 if ($attr['sum'] > 0.0)
1242 $summary[$attr['name']] = $attr['sum'];
1243}
1244
254673dd
DO
1245// used by renderGridForm() and renderRackPage()
1246function renderRackInfoPortlet ($rackData)
1247{
646272be 1248 $summary = array();
67cfe546 1249 $summary['Rack row'] = mkA ($rackData['row_name'], 'row', $rackData['row_id']);
646272be
AA
1250 $summary['Name'] = $rackData['name'];
1251 $summary['Height'] = $rackData['height'];
33973968 1252 if ($rackData['asset_no'] != '')
646272be 1253 $summary['Asset tag'] = $rackData['asset_no'];
9b8174d7 1254 if ($rackData['has_problems'] == 'yes')
646272be 1255 $summary[] = array ('<tr><td colspan=2 class=msg_error>Has problems</td></tr>');
6b9bdb08 1256 populateRackPower ($rackData, $summary);
42504426
AD
1257 // Display populated attributes, but skip 'height' since it's already displayed above
1258 // and skip 'sort_order' because it's modified using AJAX
249c78b2 1259 foreach (getAttrValuesSorted ($rackData['id']) as $record)
5b908204
DO
1260 if
1261 (
1262 $record['id'] != 27 && $record['id'] != 29 &&
1263 $record['value'] != '' &&
1264 permitted (NULL, NULL, NULL, array (array ('tag' => '$attr_' . $record['id'])))
1265 )
1266 $summary['{sticker}' . $record['name']] = formatAttributeValue ($record, 1560);
646272be
AA
1267 $summary['% used'] = getProgressBar (getRSUforRack ($rackData));
1268 $summary['Objects'] = count ($rackData['mountedObjects']);
1269 $summary['tags'] = '';
646272be 1270 renderEntitySummary ($rackData, 'summary', $summary);
0602fc27
DO
1271 if ($rackData['comment'] != '')
1272 {
1273 startPortlet ('Comment');
1274 echo '<div class=commentblock>' . string_insert_hrefs ($rackData['comment']) . '</div>';
1275 finishPortlet ();
1276 }
254673dd
DO
1277}
1278
e673ee24 1279// This is a universal editor of rack design/waste.
7056988c 1280// FIXME: switch to using printOpFormIntro()
7e1db771 1281function renderGridForm ($rack_id, $filter, $header, $submit, $state1, $state2)
e673ee24 1282{
61a1d996
DO
1283 $rackData = spotEntity ('rack', $rack_id);
1284 amplifyCell ($rackData);
254673dd 1285 $filter ($rackData);
e673ee24 1286
e673ee24
DO
1287 // Render the result whatever it is.
1288 // Main layout.
1289 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
1290 echo "<tr><td colspan=2 align=center><h1>${rackData['name']}</h1></td></tr>\n";
1291
1292 // Left column with information portlet.
1293 echo "<tr><td class=pcleft height='1%' width='50%'>";
254673dd 1294 renderRackInfoPortlet ($rackData);
e673ee24 1295 echo "</td>\n";
bb09cca0 1296 echo "<td class=pcright>";
e673ee24
DO
1297
1298 // Grid form.
c26d97b6 1299 $is_ro = !rackModificationPermitted ($rackData, 'updateRack');
e673ee24 1300 startPortlet ($header);
65e557dd 1301 addJS ('js/racktables.js');
e673ee24 1302 echo "<center>\n";
c26d97b6
VS
1303 $read_only_text = $is_ro ? '(read-only)' : '&nbsp;';
1304 echo "<p style='color: red; margin-top:0px'>${read_only_text}</p>\n";
e673ee24 1305 echo "<table class=rack border=0 cellspacing=0 cellpadding=1>\n";
57c69e9c 1306 echo "<tr><th width='10%'>&nbsp;</th>";
bd0bfb76
AD
1307 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '0', ${rackData['height']})\">Front</a></th>";
1308 echo "<th width='50%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '1', ${rackData['height']})\">Interior</a></th>";
1309 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '2', ${rackData['height']})\">Back</a></th></tr>\n";
4fbb5a00 1310 printOpFormIntro ('updateRack');
e673ee24 1311 markupAtomGrid ($rackData, $state2);
c26d97b6 1312 renderAtomGrid ($rackData, $is_ro);
e673ee24
DO
1313 echo "</table></center>\n";
1314 echo "<br><input type=submit name=do_update value='${submit}'></form><br><br>\n";
1315 finishPortlet();
bb09cca0 1316 echo "</td></tr></table>\n";
e673ee24
DO
1317}
1318
1319function renderRackDesign ($rack_id)
1320{
bb09cca0 1321 renderGridForm ($rack_id, 'applyRackDesignMask', 'Rack design', 'Set rack design', 'A', 'F');
e673ee24
DO
1322}
1323
7e1db771 1324function renderRackProblems ($rack_id)
e673ee24 1325{
bb09cca0 1326 renderGridForm ($rack_id, 'applyRackProblemMask', 'Rack problems', 'Mark unusable atoms', 'F', 'U');
e673ee24
DO
1327}
1328
40c9fc94
AA
1329function renderObjectPortRow ($port, $is_highlighted)
1330{
8579b51b
AA
1331 // highlight port name with yellow if it's name is not canonical
1332 $canon_pn = shortenPortName ($port['name'], $port['object_id']);
1333 $name_class = $canon_pn == $port['name'] ? '' : 'trwarning';
1334
90bf1755
DO
1335 echo '<tr';
1336 if ($is_highlighted)
1337 echo ' class=highlight';
40c9fc94 1338 $a_class = isEthernetPort ($port) ? 'port-menu' : '';
8579b51b 1339 echo "><td class='tdleft $name_class' NOWRAP><a name='port-${port['id']}' class='interactive-portname nolink $a_class'>${port['name']}</a></td>";
40c9fc94
AA
1340 echo "<td class=tdleft>${port['label']}</td>";
1341 echo "<td class=tdleft>" . formatPortIIFOIF ($port) . "</td><td class=tdleft><tt>${port['l2address']}</tt></td>";
0b09238d 1342 if ($port['remote_object_id'])
90bf1755 1343 {
f4d00faf 1344 $dname = formatObjectDisplayedName ($port['remote_object_name'], $port['remote_object_tid']);
0b09238d 1345 echo "<td class=tdleft>" .
f4d00faf 1346 formatPortLink ($port['remote_object_id'], $dname, $port['remote_id'], NULL) .
0b09238d
DO
1347 "</td>";
1348 echo "<td class=tdleft>" . formatLoggedSpan ($port['last_log'], $port['remote_name'], 'underline') . "</td>";
1349 $editable = permitted ('object', 'ports', 'editPort')
1350 ? 'editable'
1351 : '';
1352 echo "<td class=tdleft><span class='rsvtext $editable id-${port['id']} op-upd-reservation-cable'>${port['cableid']}</span></td>";
40c9fc94 1353 }
90bf1755
DO
1354 else
1355 echo implode ('', formatPortReservation ($port)) . '<td></td>';
0b09238d 1356 echo "</tr>";
40c9fc94
AA
1357}
1358
d10401bf 1359function renderObject ($object_id)
e673ee24 1360{
8dc2a6c8 1361 global $nextorder, $virtual_obj_types;
fb6e2f57 1362 $info = spotEntity ('object', $object_id);
94fe6370 1363 amplifyCell ($info);
e673ee24
DO
1364 // Main layout starts.
1365 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
1366 echo "<tr><td colspan=2 align=center><h1>${info['dname']}</h1></td></tr>\n";
3a243872 1367 // A mandatory left column with varying number of portlets.
e673ee24 1368 echo "<tr><td class=pcleft>";
646272be
AA
1369
1370 // display summary portlet
1371 $summary = array();
33973968 1372 if ($info['name'] != '')
646272be 1373 $summary['Common name'] = $info['name'];
94fe6370 1374 elseif (considerConfiguredConstraint ($info, 'NAMEWARN_LISTSRC'))
646272be
AA
1375 $summary[] = array ('<tr><td colspan=2 class=msg_error>Common name is missing.</td></tr>');
1376 $summary['Object type'] = '<a href="' . makeHref (array (
341fd895
DO
1377 'page' => 'depot',
1378 'tab' => 'default',
1379 'cfe' => '{$typeid_' . $info['objtype_id'] . '}'
eb11ba46 1380 )) . '">' . decodeObjectType ($info['objtype_id']) . '</a>';
33973968 1381 if ($info['label'] != '')
646272be 1382 $summary['Visible label'] = $info['label'];
33973968 1383 if ($info['asset_no'] != '')
646272be 1384 $summary['Asset tag'] = $info['asset_no'];
d4e8ddeb 1385 elseif (considerConfiguredConstraint ($info, 'ASSETWARN_LISTSRC'))
646272be 1386 $summary[] = array ('<tr><td colspan=2 class=msg_error>Asset tag is missing.</td></tr>');
9563f56f 1387 $parents = getParents ($info, 'object');
af8916e9
AD
1388 // lookup the human-readable object type, sort by it
1389 foreach ($parents as $parent_id => $parent)
1390 $parents[$parent_id]['object_type'] = decodeObjectType ($parent['objtype_id']);
1391 $grouped_parents = groupBy ($parents, 'object_type');
1392 ksort ($grouped_parents);
1393 foreach ($grouped_parents as $parents_group)
0682218d 1394 {
9563f56f 1395 uasort ($parents_group, 'compare_name');
af8916e9 1396 $label = $parents_group[key ($parents_group)]['object_type'] . (count($parents_group) > 1 ? ' containers' : ' container');
9563f56f
AA
1397 $fmt_parents = array();
1398 foreach ($parents_group as $parent)
1399 $fmt_parents[] = mkCellA ($parent);
af8916e9 1400 $summary[$label] = implode ('<br>', $fmt_parents);
0682218d 1401 }
9563f56f
AA
1402 $children = getChildren ($info, 'object');
1403 foreach (groupBy ($children, 'objtype_id') as $objtype_id => $children_group)
42fb3aa2 1404 {
9563f56f
AA
1405 uasort ($children_group, 'compare_name');
1406 $fmt_children = array();
1407 foreach ($children_group as $child)
1408 $fmt_children[] = mkCellA ($child);
1409 $summary["Contains " . strtolower(decodeObjectType ($objtype_id))] = implode ('<br>', $fmt_children);
42fb3aa2 1410 }
e673ee24 1411 if ($info['has_problems'] == 'yes')
646272be 1412 $summary[] = array ('<tr><td colspan=2 class=msg_error>Has problems</td></tr>');
249c78b2 1413 foreach (getAttrValuesSorted ($object_id) as $record)
4969aa31
DO
1414 if
1415 (
55eefced 1416 $record['value'] != '' &&
4969aa31
DO
1417 permitted (NULL, NULL, NULL, array (array ('tag' => '$attr_' . $record['id'])))
1418 )
5b908204 1419 $summary['{sticker}' . $record['name']] = formatAttributeValue ($record, $info['objtype_id']);
a2c597ea
AA
1420 $summary[] = array (getOutputOf ('printTagTRs',
1421 $info,
1422 makeHref
1423 (
1424 array
1425 (
1426 'page'=>'depot',
1427 'tab'=>'default',
1428 'andor' => 'and',
1429 'cfe' => '{$typeid_' . $info['objtype_id'] . '}',
1430 )
1431 )."&"
1432 ));
0b09238d 1433 renderEntitySummary ($info, 'summary', $summary);
e673ee24 1434
33973968 1435 if ($info['comment'] != '')
e673ee24
DO
1436 {
1437 startPortlet ('Comment');
6cc5d6cd 1438 echo '<div class=commentblock>' . string_insert_hrefs ($info['comment']) . '</div>';
e673ee24
DO
1439 finishPortlet ();
1440 }
1441
b5700329
AA
1442 $logrecords = getLogRecordsForObject ($_REQUEST['object_id']);
1443 if (count ($logrecords))
9a90adc4
DO
1444 {
1445 startPortlet ('log records');
1446 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable width='100%'>";
1447 $order = 'odd';
b5700329 1448 foreach ($logrecords as $row)
9a90adc4
DO
1449 {
1450 echo "<tr class=row_${order} valign=top>";
1451 echo '<td class=tdleft>' . $row['date'] . '<br>' . $row['user'] . '</td>';
0b8d8309 1452 echo '<td class="logentry">' . string_insert_hrefs (htmlspecialchars ($row['content'], ENT_NOQUOTES)) . '</td>';
9a90adc4
DO
1453 echo '</tr>';
1454 $order = $nextorder[$order];
1455 }
1456 echo '</table>';
1457 finishPortlet();
1458 }
1459
65e557dd 1460 switchportInfoJS ($object_id); // load JS code to make portnames interactive
e1ae3fb4
AD
1461 renderFilesPortlet ('object', $object_id);
1462
9f75e165 1463 if (count ($info['ports']))
e673ee24 1464 {
0b09238d 1465 startPortlet ('ports and links');
9f75e165
DO
1466 $hl_port_id = 0;
1467 if (isset ($_REQUEST['hl_port_id']))
e673ee24 1468 {
0cc24e9a 1469 assertUIntArg ('hl_port_id');
9f75e165 1470 $hl_port_id = $_REQUEST['hl_port_id'];
65e557dd 1471 addAutoScrollScript ("port-$hl_port_id");
9f75e165 1472 }
0b09238d 1473 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>";
9f75e165 1474 echo '<tr><th class=tdleft>Local name</th><th class=tdleft>Visible label</th>';
0d59a51c 1475 echo '<th class=tdleft>Interface</th><th class=tdleft>L2 address</th>';
0c7c9f8b 1476 echo '<th class=tdcenter colspan=2>Remote object and port</th>';
0b09238d 1477 echo '<th class=tdleft>Cable ID</th></tr>';
9f75e165 1478 foreach ($info['ports'] as $port)
40c9fc94 1479 callHook ('renderObjectPortRow', $port, ($hl_port_id == $port['id']));
fd5edda8 1480 if (permitted (NULL, 'ports', 'set_reserve_comment'))
a8dc2982 1481 addJS ('js/inplace-edit.js');
9f75e165 1482 echo "</table><br>";
e673ee24
DO
1483 finishPortlet();
1484 }
85970da2 1485
21ee3351 1486 if (count ($info['ipv4']) + count ($info['ipv6']))
e673ee24 1487 {
21ee3351 1488 startPortlet ('IP addresses');
e673ee24 1489 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
e9446e3b 1490 if ('yes' == $ext_ipv4_view = getConfigVar ('EXT_IPV4_VIEW'))
9d5f6a80 1491 echo "<tr class=tdleft><th>OS interface</th><th>IP address</th><th>network</th><th>routed by</th><th>peers</th></tr>\n";
83fdf85f 1492 else
9d5f6a80 1493 echo "<tr class=tdleft><th>OS interface</th><th>IP address</th><th>peers</th></tr>\n";
21ee3351
AA
1494
1495 // group IP allocations by interface name instead of address family
1496 $allocs_by_iface = array();
1497 foreach (array ('ipv4', 'ipv6') as $ip_v)
4318ced5
AA
1498 foreach ($info[$ip_v] as $ip_bin => $alloc)
1499 $allocs_by_iface[$alloc['osif']][$ip_bin] = $alloc;
dec748f6 1500
21ee3351
AA
1501 // sort allocs array by portnames
1502 foreach (sortPortList ($allocs_by_iface) as $iface_name => $alloclist)
1503 {
1504 $is_first_row = TRUE;
f3505b35 1505 foreach ($alloclist as $alloc)
b90c3907 1506 {
40c9fc94 1507 $rendered_alloc = callHook ('getRenderedAlloc', $object_id, $alloc);
f3505b35 1508 echo "<tr class='${rendered_alloc['tr_class']}' valign=top>";
21ee3351 1509
f3505b35 1510 // display iface name, same values are grouped into single cell
21ee3351
AA
1511 if ($is_first_row)
1512 {
1513 $rowspan = count ($alloclist) > 1 ? 'rowspan="' . count ($alloclist) . '"' : '';
40c9fc94 1514 echo "<td class=tdleft $rowspan>" . $iface_name . $rendered_alloc['td_name_suffix'] . "</td>";
21ee3351
AA
1515 $is_first_row = FALSE;
1516 }
f3505b35 1517 echo $rendered_alloc['td_ip'];
e9446e3b 1518 if ($ext_ipv4_view == 'yes')
83fdf85f 1519 {
f3505b35
AA
1520 echo $rendered_alloc['td_network'];
1521 echo $rendered_alloc['td_routed_by'];
21ee3351 1522 }
f3505b35
AA
1523 echo $rendered_alloc['td_peers'];
1524
1525 echo "</tr>\n";
b90c3907 1526 }
e673ee24
DO
1527 }
1528 echo "</table><br>\n";
1529 finishPortlet();
1530 }
1531
94fe6370 1532 $forwards = $info['nat4'];
55eefced 1533 if (count ($forwards['in']) || count ($forwards['out']))
e673ee24 1534 {
f28fbe8b 1535 startPortlet('NATv4');
e673ee24
DO
1536
1537 if (count($forwards['out']))
1538 {
1539
f28fbe8b 1540 echo "<h3>locally performed NAT</h3>";
e673ee24 1541
105a3bc8 1542 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
f28fbe8b 1543 echo "<tr><th>Proto</th><th>Match endpoint</th><th>Translate to</th><th>Target object</th><th>Rule comment</th></tr>\n";
e673ee24
DO
1544
1545 foreach ($forwards['out'] as $pf)
1546 {
2c817354
DO
1547 $class = 'trerror';
1548 $osif = '';
6a3c2dc5
AA
1549 $localip_bin = ip_parse ($pf['localip']);
1550 if (array_key_exists ($localip_bin, $info['ipv4']))
2c817354 1551 {
6a3c2dc5
AA
1552 $class = $info['ipv4'][$localip_bin]['addrinfo']['class'];
1553 $osif = $info['ipv4'][$localip_bin]['osif'] . ': ';
2c817354 1554 }
e673ee24 1555 echo "<tr class='$class'>";
7419401e
AA
1556 echo "<td>${pf['proto']}</td><td class=tdleft>${osif}" . getRenderedIPPortPair ($pf['localip'], $pf['localport']) . "</td>";
1557 echo "<td class=tdleft>" . getRenderedIPPortPair ($pf['remoteip'], $pf['remoteport']) . "</td>";
4318ced5 1558 $address = getIPAddress (ip4_parse ($pf['remoteip']));
e673ee24 1559 echo "<td class='description'>";
53ef3908
DO
1560 if (count ($address['allocs']))
1561 foreach($address['allocs'] as $bond)
ad3e5e7e 1562 echo mkA ("${bond['object_name']}(${bond['name']})", 'object', $bond['object_id']) . ' ';
33973968 1563 elseif ($pf['remote_addr_name'] != '')
f28fbe8b 1564 echo '(' . $pf['remote_addr_name'] . ')';
53ef3908 1565 echo "</td><td class='description'>${pf['description']}</td></tr>";
e673ee24
DO
1566 }
1567 echo "</table><br><br>";
1568 }
1569 if (count($forwards['in']))
1570 {
f28fbe8b 1571 echo "<h3>arriving NAT connections</h3>";
105a3bc8 1572 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
f28fbe8b 1573 echo "<tr><th>Matched endpoint</th><th>Source object</th><th>Translated to</th><th>Rule comment</th></tr>\n";
e673ee24
DO
1574 foreach ($forwards['in'] as $pf)
1575 {
1576 echo "<tr>";
7419401e 1577 echo "<td>${pf['proto']}/" . getRenderedIPPortPair ($pf['localip'], $pf['localport']) . "</td>";
ad3e5e7e 1578 echo '<td class="description">' . mkA ($pf['object_name'], 'object', $pf['object_id']);
7419401e 1579 echo "</td><td>" . getRenderedIPPortPair ($pf['remoteip'], $pf['remoteport']) . "</td>";
e673ee24
DO
1580 echo "<td class='description'>${pf['description']}</td></tr>";
1581 }
e673ee24
DO
1582 echo "</table><br><br>";
1583 }
1584 finishPortlet();
1585 }
1586
eacc0983 1587 renderSLBTriplets2 ($info);
defd92d8 1588 renderSLBTriplets ($info);
e673ee24
DO
1589 echo "</td>\n";
1590
3a243872
DO
1591 // A conditional right column with the rackspace portlet only.
1592 if
1593 (
1594 ! in_array ($info['objtype_id'], $virtual_obj_types) &&
1595 count ($rack_ids = getResidentRacksData ($object_id, FALSE))
1596 )
0682218d 1597 {
3a243872 1598 echo '<td class=pcright>';
0682218d 1599 startPortlet ('rackspace allocation');
3a243872 1600 foreach ($rack_ids as $rack_id)
0682218d
AD
1601 renderRack ($rack_id, $object_id);
1602 echo '<br>';
1603 finishPortlet();
3a243872 1604 echo '</td>';
0682218d 1605 }
3a243872 1606 echo "<tr></table>\n";
e673ee24
DO
1607}
1608
1609function renderRackMultiSelect ($sname, $racks, $selected)
1610{
04571888
DO
1611 // Transform the given flat list into a list of groups, each representing a rack row.
1612 $rdata = array();
e673ee24 1613 foreach ($racks as $rack)
d016010a 1614 {
b956dd24 1615 if ('' != $trail = getLocationTrail ($rack['location_id'], FALSE))
7b6ae79a
AD
1616 $row_name = $trail . ' : ' . $rack['row_name'];
1617 else
1618 $row_name = $rack['row_name'];
d016010a
AD
1619 $rdata[$row_name][$rack['id']] = $rack['name'];
1620 }
4fbb5a00 1621 echo "<select name=${sname} multiple size=" . getConfigVar ('MAXSELSIZE') . " onchange='getElementsByName(\"updateObjectAllocation\")[0].submit()'>\n";
acfc0d89
AA
1622 $row_names = array_keys ($rdata);
1623 natsort ($row_names);
1624 foreach ($row_names as $optgroup)
e673ee24 1625 {
04571888 1626 echo "<optgroup label='${optgroup}'>";
acfc0d89 1627 foreach ($rdata[$optgroup] as $rack_id => $rack_name)
04571888
DO
1628 {
1629 echo "<option value=${rack_id}";
1630 if (!(array_search ($rack_id, $selected) === FALSE))
1631 echo ' selected';
1632 echo">${rack_name}</option>\n";
1633 }
e673ee24
DO
1634 }
1635 echo "</select>\n";
1636}
1637
e673ee24 1638// This function renders a form for port edition.
d10401bf 1639function renderPortsForObject ($object_id)
e673ee24 1640{
3153a326
DO
1641 $prefs = getPortListPrefs();
1642 function printNewItemTR ($prefs)
39b4abd0
DO
1643 {
1644 printOpFormIntro ('addPort');
1645 echo "<tr><td>";
f5ff50f5 1646 printImageHREF ('add', 'add a port', TRUE);
7b30e187 1647 echo "</td><td class='tdleft'><input type=text size=16 name=port_name></td>\n";
04c61e7e 1648 echo "<td><input type=text name=port_label></td><td>";
759b21d2 1649 printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type_id'), $prefs['selected']);
04c61e7e 1650 echo "<td><input type=text name=port_l2address size=18 maxlength=24></td>\n";
318c48a8 1651 echo "<td colspan=4>&nbsp;</td><td>";
04c61e7e 1652 printImageHREF ('add', 'add a port', TRUE);
9318d2ef 1653 echo "</td></tr></form>";
39b4abd0 1654 }
70c0cb08
DO
1655
1656 function printBulkForm ($prefs)
1657 {
a1fc539a
RF
1658 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
1659 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>";
1660 echo "<th class=tdleft>Count</th><th>&nbsp;</th></tr>\n";
1661 printOpFormIntro ('addBulkPorts');
1662 echo "<tr><td>";
1663 printImageHREF ('add', 'add ports', TRUE);
04c61e7e
AB
1664 echo "</td><td><input type=text size=8 name=port_name></td>\n";
1665 echo "<td><input type=text name=port_label></td><td>";
759b21d2 1666 printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type_id'), $prefs['selected']);
04c61e7e
AB
1667 echo "<td><input type=text name=port_numbering_start size=3 maxlength=3></td>\n";
1668 echo "<td><input type=text name=port_numbering_count size=3 maxlength=3></td>\n";
0b09238d 1669 echo "<td>&nbsp;</td><td>";
04c61e7e 1670 printImageHREF ('add', 'add ports', TRUE);
a1fc539a
RF
1671 echo "</td></tr></form>";
1672 echo "</table><br>\n";
1673 }
dec748f6 1674
70c0cb08
DO
1675 startPortlet ('Ports and interfaces');
1676 $object = spotEntity ('object', $object_id);
1677 amplifyCell ($object);
1678 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes' && getConfigVar ('ENABLE_BULKPORT_FORM') == 'yes')
1679 printBulkForm ($prefs);
1680
0b09238d 1681 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
0d59a51c 1682 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>";
0b09238d 1683 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";
39b4abd0 1684 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
3153a326 1685 printNewItemTR ($prefs);
45ff9012 1686
0b09238d
DO
1687 // clear ports link
1688 echo getOpLink (array ('op'=>'deleteAll'), 'Clear port list', 'clear', '', 'need-confirmation');
1689
8579b51b
AA
1690 // rename ports link
1691 $n_ports_to_rename = 0;
1692 foreach ($object['ports'] as $port)
1693 if ($port['name'] != shortenPortName ($port['name'], $object['id']))
1694 $n_ports_to_rename++;
1695 if ($n_ports_to_rename)
bd2dcd32 1696 echo '<p>' . getOpLink (array ('op'=>'renameAll'), "Auto-rename $n_ports_to_rename port(s)", 'recalc', 'Use RackTables naming convention for this device type') . '</p>';
8579b51b 1697
00276508
AA
1698 if (isset ($_REQUEST['hl_port_id']))
1699 {
1700 assertUIntArg ('hl_port_id');
1701 $hl_port_id = intval ($_REQUEST['hl_port_id']);
65e557dd 1702 addAutoScrollScript ("port-$hl_port_id");
00276508 1703 }
d10401bf 1704 switchportInfoJS ($object_id); // load JS code to make portnames interactive
9f75e165 1705 foreach ($object['ports'] as $port)
e673ee24 1706 {
8579b51b
AA
1707 // highlight port name with yellow if it's name is not canonical
1708 $canon_pn = shortenPortName ($port['name'], $port['object_id']);
1709 $name_class = $canon_pn == $port['name'] ? '' : 'trwarning';
1710
5c717ce5 1711 $tr_class = isset ($hl_port_id) && $hl_port_id == $port['id'] ? 'class="highlight"' : '';
7056988c 1712 printOpFormIntro ('editPort', array ('port_id' => $port['id']));
d0d40671 1713 echo "<tr $tr_class><td><a name='port-${port['id']}' href='".makeHrefProcess(array('op'=>'delPort', 'port_id'=>$port['id']))."'>";
e673ee24
DO
1714 printImageHREF ('delete', 'Unlink and Delete this port');
1715 echo "</a></td>\n";
65e557dd 1716 $a_class = isEthernetPort ($port) ? 'port-menu' : '';
7b30e187 1717 echo "<td class='tdleft $name_class' NOWRAP><input type=text name=name class='interactive-portname $a_class' value='${port['name']}' size=16></td>";
cd3775e9 1718 echo "<td><input type=text name=label value='${port['label']}'></td>";
70c0cb08 1719 echo '<td class=tdleft>';
8e021b86
AA
1720 if ($port['iif_id'] != 1)
1721 echo '<label>' . $port['iif_name'] . ' ';
4f968fa8 1722 $port_type_opts = array();
78b59ab3 1723 if (! $port['linked'])
759b21d2 1724 $port_type_opts = getUnlinkedPortTypeOptions ($port['iif_id']);
78b59ab3 1725 else
4f968fa8
AA
1726 foreach (getExistingPortTypeOptions ($port) as $oif_id => $opt_str)
1727 $port_type_opts[$port['iif_name']][$port['iif_id'] . '-' . $oif_id] = $opt_str;
4f968fa8 1728 printNiftySelect ($port_type_opts, array ('name' => 'port_type_id'), $port['iif_id'] . '-' . $port['oif_id']);
8e021b86
AA
1729 if ($port['iif_id'] != 1)
1730 echo '</label>';
1731 echo '</td>';
1732
cd3775e9
DO
1733 // 18 is enough to fit 6-byte MAC address in its longest form,
1734 // while 24 should be Ok for WWN
1735 echo "<td><input type=text name=l2address value='${port['l2address']}' size=18 maxlength=24></td>\n";
0b09238d 1736 if ($port['remote_object_id'])
90bf1755 1737 {
f4d00faf
DO
1738 $dname = formatObjectDisplayedName ($port['remote_object_name'], $port['remote_object_tid']);
1739 echo "<td class=tdleft>" .
1740 formatLoggedSpan ($port['last_log'], formatPortLink ($port['remote_object_id'], $dname, $port['remote_id'], NULL)) .
0b09238d 1741 "</td>";
f4d00faf 1742 echo "<td class=tdleft> " . formatLoggedSpan ($port['last_log'], $port['remote_name'], 'underline') .
0b09238d
DO
1743 "<input type=hidden name=reservation_comment value=''></td>";
1744 echo "<td><input type=text name=cable value='${port['cableid']}'></td>";
1745 echo "<td class=tdcenter>";
1746 echo getOpLink (array('op'=>'unlinkPort', 'port_id'=>$port['id'], ), '', 'cut', 'Unlink this port');
1747 echo "</td>";
e673ee24 1748 }
33973968 1749 elseif ($port['reservation_comment'] != '')
e673ee24 1750 {
0b09238d 1751 echo "<td>" . formatLoggedSpan ($port['last_log'], 'Reserved:', 'strong underline') . "</td>";
e673ee24 1752 echo "<td><input type=text name=reservation_comment value='${port['reservation_comment']}'></td>";
318c48a8 1753 echo "<td></td>";
10f5133a
AA
1754 echo "<td class=tdcenter>";
1755 echo getOpLink (array('op'=>'useup', 'port_id'=>$port['id']), '', 'clear', 'Use up this port');
1756 echo "</td>";
e673ee24
DO
1757 }
1758 else
1759 {
6b1ca530 1760 $in_rack = getConfigVar ('NEAREST_RACKS_CHECKBOX');
de55c069
AA
1761 echo "<td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td class=tdcenter>";
1762 echo getPopupLink ('portlist', array ('port' => $port['id'], 'in_rack' => ($in_rack == "yes" ? "on" : "")), 'findlink', 'plug', '', 'Link this port');
0b09238d 1763 echo " <input type=text name=reservation_comment></td>\n";
90bf1755 1764 }
0b09238d
DO
1765 echo "<td>";
1766 printImageHREF ('save', 'Save changes', TRUE);
1767 echo "</td></form></tr>\n";
e673ee24 1768 }
39b4abd0 1769 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
3153a326 1770 printNewItemTR ($prefs);
e673ee24 1771 echo "</table><br>\n";
70c0cb08
DO
1772 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes' && getConfigVar ('ENABLE_BULKPORT_FORM') == 'yes')
1773 printBulkForm ($prefs);
e673ee24 1774 finishPortlet();
70c0cb08
DO
1775
1776 if (getConfigVar ('ENABLE_MULTIPORT_FORM') == 'yes' && permitted (NULL, NULL, 'addMultiPorts'))
1777 {
1778 startPortlet ('Add/update multiple ports');
1779 printOpFormIntro ('addMultiPorts');
1780 $formats = array
1781 (
1782 'ssv1' => 'SSV:<interface name> [<MAC address>]',
1783 );
1784 echo 'Format: ' . getSelect ($formats, array ('name' => 'format'), 'ssv1') . ' ';
1785 echo 'Default port type: ';
1786 printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type'), $prefs['selected']);
1787 echo "<input type=submit value='Parse output'><br>\n";
1788 echo "<textarea name=input cols=100 rows=50></textarea><br>\n";
1789 echo '</form>';
1790 finishPortlet();
1791 }
e673ee24
DO
1792}
1793
d10401bf 1794function renderIPForObject ($object_id)
e673ee24 1795{
15e27821 1796 function printNewItemTR ($default_type, $object_id)
21ee3351
AA
1797 {
1798 global $aat;
15e27821 1799
1800 includeJQueryUI (TRUE);
1801
1802 addJS (<<<JSEND
1803 $(document).ready( function() {
1804 $('[name="bond_name"]').autocomplete({
1805 source: "?module=ajax&ac=autocomplete&realm=bond_name&object_id=$object_id",
1806 //minLength: 3,
1807 focus: function(event, ui) {
1808 if( ui.item.value == '' )
1809 event.preventDefault();
1810 },
1811 select: function(event, ui) {
1812 if( ui.item.value == '' )
1813 event.preventDefault();
1814 }
1815 });
1816 });
1817JSEND
1818 , TRUE);
4318ced5
AA
1819 printOpFormIntro ('add');
1820 echo "<tr><td>"; // left btn
dec748f6 1821 printImageHREF ('add', 'allocate', TRUE);
21ee3351 1822 echo "</td>";
04c61e7e
AB
1823 echo "<td class=tdleft><input type='text' size='10' name='bond_name'></td>\n"; // if-name
1824 echo "<td class=tdleft><input type=text name='ip'></td>\n"; // IP
4318ced5
AA
1825 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
1826 echo "<td colspan=2>&nbsp;</td>"; // network, routed by
1827 echo '<td>';
04c61e7e 1828 printSelect ($aat, array ('name' => 'bond_type'), $default_type); // type
4318ced5 1829 echo "</td><td>&nbsp;</td><td>"; // misc
04c61e7e 1830 printImageHREF ('add', 'allocate', TRUE); // right btn
21ee3351
AA
1831 echo "</td></tr></form>";
1832 }
21ee3351 1833 global $aat;
0d5ef6f0 1834
21ee3351 1835 startPortlet ('Allocations');
4318ced5
AA
1836 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'><tr>\n";
1837 echo '<th>&nbsp;</th>';
1838 echo '<th>OS interface</th>';
1839 echo '<th>IP address</th>';
21ee3351 1840 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
4318ced5
AA
1841 {
1842 echo '<th>network</th>';
1843 echo '<th>routed by</th>';
1844 }
1845 echo '<th>type</th>';
1846 echo '<th>misc</th>';
b1b07891 1847 echo '<th>&nbsp;</th>';
4318ced5 1848 echo '</tr>';
21ee3351 1849
710ead7e
AA
1850 $alloc_list = ''; // most of the output is stored here
1851 $used_alloc_types = array();
e9446e3b 1852 $ext_ipv4_view = getConfigVar ('EXT_IPV4_VIEW');
4318ced5 1853 foreach (getObjectIPAllocations ($object_id) as $alloc)
21ee3351 1854 {
710ead7e
AA
1855 if (! isset ($used_alloc_types[$alloc['type']]))
1856 $used_alloc_types[$alloc['type']] = 0;
1857 $used_alloc_types[$alloc['type']]++;
1858
40c9fc94 1859 $rendered_alloc = callHook ('getRenderedAlloc', $object_id, $alloc);
4318ced5 1860 $alloc_list .= getOutputOf ('printOpFormIntro', 'upd', array ('ip' => $alloc['addrinfo']['ip']));
710ead7e 1861 $alloc_list .= "<tr class='${rendered_alloc['tr_class']}' valign=top>";
f3505b35 1862
10f5133a 1863 $alloc_list .= "<td>" . getOpLink (array ('op' => 'del', 'ip' => $alloc['addrinfo']['ip']), '', 'delete', 'Delete this IP address') . "</td>";
40c9fc94 1864 $alloc_list .= "<td class=tdleft><input type='text' name='bond_name' value='${alloc['osif']}' size=10>" . $rendered_alloc['td_name_suffix'] . "</td>";
710ead7e 1865 $alloc_list .= $rendered_alloc['td_ip'];
e9446e3b 1866 if ($ext_ipv4_view == 'yes')
21ee3351 1867 {
710ead7e
AA
1868 $alloc_list .= $rendered_alloc['td_network'];
1869 $alloc_list .= $rendered_alloc['td_routed_by'];
21ee3351 1870 }
710ead7e
AA
1871 $alloc_list .= '<td>' . getSelect ($aat, array ('name' => 'bond_type'), $alloc['type']) . "</td>";
1872 $alloc_list .= $rendered_alloc['td_peers'];
1873 $alloc_list .= "<td>" .getImageHREF ('save', 'Save changes', TRUE) . "</td>";
f3505b35 1874
710ead7e 1875 $alloc_list .= "</form></tr>\n";
21ee3351 1876 }
710ead7e 1877 asort ($used_alloc_types, SORT_NUMERIC);
589c027b 1878 $most_popular_type = ! count ($used_alloc_types) ? 'regular' : array_last (array_keys ($used_alloc_types));
710ead7e
AA
1879
1880 if ($list_on_top = (getConfigVar ('ADDNEW_AT_TOP') != 'yes'))
1881 echo $alloc_list;
15e27821 1882 printNewItemTR ($most_popular_type, $object_id);
710ead7e
AA
1883 if (! $list_on_top)
1884 echo $alloc_list;
21ee3351
AA
1885
1886 echo "</table><br>\n";
1887 finishPortlet();
f3505b35
AA
1888}
1889
08408472
AA
1890// This function is deprecated. Do not rely on its internals,
1891// it will probably be removed in the next major relese.
1892// Use new showError, showWarning, showSuccess functions.
dec748f6 1893// Log array is stored in global $log_messages. Its format is simple: plain ordered array
8ab645cf 1894// with values having keys 'c' (both message code and severity) and 'a' (sprintf arguments array)
1cb6adf5 1895function showMessageOrError ()
e673ee24 1896{
a2b16202
AA
1897 global $log_messages;
1898
0a00b344 1899 startSession();
a2b16202
AA
1900 if (isset ($_SESSION['log']))
1901 {
1902 $log_messages = array_merge ($_SESSION['log'], $log_messages);
1903 unset ($_SESSION['log']);
1904 }
1905 session_commit();
1906
1907 if (empty ($log_messages))
1cb6adf5 1908 return;
8ab645cf
AA
1909 $msginfo = array
1910 (
dec748f6 1911// records 0~99 with success messages
8ab645cf
AA
1912 0 => array ('code' => 'success', 'format' => '%s'),
1913 5 => array ('code' => 'success', 'format' => 'added record "%s" successfully'),
1914 6 => array ('code' => 'success', 'format' => 'updated record "%s" successfully'),
1915 7 => array ('code' => 'success', 'format' => 'deleted record "%s" successfully'),
1916 8 => array ('code' => 'success', 'format' => 'Port %s successfully linked with %s'),
493e13dd 1917 10 => array ('code' => 'success', 'format' => 'Added %u port(s), updated %u port(s), encountered %u error(s).'),
8ab645cf 1918 21 => array ('code' => 'success', 'format' => 'Generation complete'),
493e13dd
DO
1919 26 => array ('code' => 'success', 'format' => 'updated %u record(s) successfully'),
1920 37 => array ('code' => 'success', 'format' => 'added %u record(s) successfully'),
1921 38 => array ('code' => 'success', 'format' => 'removed %u record(s) successfully'),
8ab645cf 1922 43 => array ('code' => 'success', 'format' => 'Saved successfully.'),
493e13dd 1923 44 => array ('code' => 'success', 'format' => '%s failure(s) and %s successfull change(s).'),
8ab645cf
AA
1924 48 => array ('code' => 'success', 'format' => 'added a record successfully'),
1925 49 => array ('code' => 'success', 'format' => 'deleted a record successfully'),
1926 51 => array ('code' => 'success', 'format' => 'updated a record successfully'),
1927 57 => array ('code' => 'success', 'format' => 'Reset complete'),
04eee8d2 1928 58 => array ('code' => 'success', 'format' => '%u device(s) unmounted successfully'),
8ab645cf 1929 63 => array ('code' => 'success', 'format' => '%u change request(s) have been processed'),
493e13dd 1930 67 => array ('code' => 'success', 'format' => "Tag rolling done, %u object(s) involved"),
8ab645cf
AA
1931 71 => array ('code' => 'success', 'format' => 'File "%s" was linked successfully'),
1932 72 => array ('code' => 'success', 'format' => 'File was unlinked successfully'),
493e13dd
DO
1933 82 => array ('code' => 'success', 'format' => "Bulk port creation was successful. %u port(s) created, %u failed"),
1934 87 => array ('code' => 'success', 'format' => '802.1Q recalculate: %d port(s) changed on %d switch(es)'),
8628ae44 1935// records 100~199 with fatal error messages
8ab645cf
AA
1936 100 => array ('code' => 'error', 'format' => '%s'),
1937 109 => array ('code' => 'error', 'format' => 'failed updating a record'),
8ab645cf 1938 131 => array ('code' => 'error', 'format' => 'invalid format requested'),
493e13dd 1939 141 => array ('code' => 'error', 'format' => 'Encountered %u error(s), updated %u record(s)'),
8ab645cf
AA
1940 149 => array ('code' => 'error', 'format' => 'Turing test failed'),
1941 150 => array ('code' => 'error', 'format' => 'Can only change password under DB authentication.'),
1942 151 => array ('code' => 'error', 'format' => 'Old password doesn\'t match.'),
1943 152 => array ('code' => 'error', 'format' => 'New passwords don\'t match.'),
1944 154 => array ('code' => 'error', 'format' => "Verification error: %s"),
1945 155 => array ('code' => 'error', 'format' => 'Save failed.'),
1946 159 => array ('code' => 'error', 'format' => 'Permission denied moving port %s from VLAN%u to VLAN%u'),
8ab645cf
AA
1947 170 => array ('code' => 'error', 'format' => 'There is no network for IP address "%s"'),
1948 172 => array ('code' => 'error', 'format' => 'Malformed request'),
1949 179 => array ('code' => 'error', 'format' => 'Expired form has been declined.'),
8ab645cf 1950 191 => array ('code' => 'error', 'format' => "deploy was blocked due to conflicting configuration versions"),
f0ff4930 1951
8628ae44 1952// records 200~299 with warnings
8ab645cf
AA
1953 200 => array ('code' => 'warning', 'format' => '%s'),
1954 201 => array ('code' => 'warning', 'format' => 'nothing happened...'),
e1add254 1955 206 => array ('code' => 'warning', 'format' => '%s is not empty'),
7587edca 1956 207 => array ('code' => 'warning', 'format' => 'File upload failed, error: %s'),
57777e4a 1957
24d3182a 1958// records 300~399 with notices
8ab645cf 1959 300 => array ('code' => 'neutral', 'format' => '%s'),
24d3182a 1960
8ab645cf
AA
1961 );
1962 // Handle the arguments. Is there any better way to do it?
a2b16202 1963 foreach ($log_messages as $record)
8ab645cf 1964 {
55eefced 1965 if (! isset ($record['c']) || ! isset ($msginfo[$record['c']]))
8ab645cf 1966 {
41152018
AA
1967 $prefix = isset ($record['c']) ? $record['c'] . ': ' : '';
1968 echo "<div class=msg_neutral>(${prefix}this message was lost)</div>";
8ab645cf
AA
1969 continue;
1970 }
1971 if (isset ($record['a']))
1972 switch (count ($record['a']))
baf37d01 1973 {
8ab645cf
AA
1974 case 1:
1975 $msgtext = sprintf
1976 (
1977 $msginfo[$record['c']]['format'],
1978 $record['a'][0]
1979 );
1980 break;
1981 case 2:
1982 $msgtext = sprintf
1983 (
1984 $msginfo[$record['c']]['format'],
1985 $record['a'][0],
1986 $record['a'][1]
1987 );
1988 break;
1989 case 3:
1990 $msgtext = sprintf
1991 (
1992 $msginfo[$record['c']]['format'],
1993 $record['a'][0],
1994 $record['a'][1],
1995 $record['a'][2]
1996 );
1997 break;
1998 case 4:
1999 default:
2000 $msgtext = sprintf
2001 (
2002 $msginfo[$record['c']]['format'],
2003 $record['a'][0],
2004 $record['a'][1],
2005 $record['a'][2],
2006 $record['a'][3]
2007 );
2008 break;
baf37d01 2009 }
8ab645cf
AA
2010 else
2011 $msgtext = $msginfo[$record['c']]['format'];
2012 echo '<div class=msg_' . $msginfo[$record['c']]['code'] . ">${msgtext}</div>";
baf37d01 2013 }
a2b16202 2014 $log_messages = array();
e673ee24
DO
2015}
2016
65e557dd 2017// renders two tables: port link status and learned MAC list
d10401bf 2018function renderPortsInfo($object_id)
65e557dd 2019{
2d33a804 2020 $breed = detectDeviceBreed ($object_id);
03522bd8
AA
2021 try
2022 {
2023 if (permitted (NULL, NULL, 'get_link_status'))
2d33a804 2024 {
2025 if (validBreedFunction ($breed, 'getportstatus'))
2026 $linkStatus = queryDevice ($object_id, 'getportstatus');
2027 }
03522bd8
AA
2028 else
2029 showWarning ("You don't have permission to view ports link status");
2030
2031 if (permitted (NULL, NULL, 'get_mac_list'))
2d33a804 2032 {
2033 if (validBreedFunction ($breed, 'getmaclist'))
2034 $macList = sortPortList (queryDevice ($object_id, 'getmaclist'));
2035 }
03522bd8
AA
2036 else
2037 showWarning ("You don't have permission to view learned MAC list");
2038 }
2039 catch (RTGatewayError $e)
2040 {
2041 showError ($e->getMessage());
2042 return;
2043 }
2044
65e557dd
AA
2045 global $nextorder;
2046 echo "<table width='100%'><tr>";
03522bd8 2047 if (! empty ($linkStatus))
65e557dd 2048 {
03522bd8
AA
2049 echo "<td valign='top' width='50%'>";
2050 startPortlet('Link status');
c51492f5
DO
2051 echo "<table width='80%' class='widetable' cellspacing=0 cellpadding='5px' align='center'>";
2052 echo '<tr><th>Port</th><th>&nbsp;</th><th>Link status</th><th>Link info</th></tr>';
72c3bebc
DO
2053 $statusmap = array
2054 (
2055 'up' => 'link up',
2056 'down' => 'link down',
2057 'disabled' => 'link disabled',
2058 );
03522bd8
AA
2059 $order = 'even';
2060 foreach ($linkStatus as $pn => $link)
65e557dd 2061 {
03522bd8
AA
2062 echo "<tr class='row_$order'>";
2063 $order = $nextorder[$order];
c51492f5
DO
2064 echo '<td>' . $pn . '</td>';
2065 echo '<td>' . getImageHREF (array_fetch ($statusmap, $link['status'], '16x16t')) . '</td>';
2066 echo '<td>' . $link['status'] . '</td>';
03522bd8
AA
2067 $info = '';
2068 if (isset ($link['speed']))
2069 $info .= $link['speed'];
2070 if (isset ($link['duplex']))
2071 {
cfb42424 2072 if ($info != '')
03522bd8
AA
2073 $info .= ', ';
2074 $info .= $link['duplex'];
65e557dd 2075 }
c51492f5 2076 echo '<td>' . $info . '</td>';
03522bd8 2077 echo '</tr>';
65e557dd 2078 }
03522bd8
AA
2079 echo "</table></td>";
2080 finishPortlet();
65e557dd
AA
2081 }
2082
65e557dd
AA
2083 if (! empty ($macList))
2084 {
2085 echo "<td valign='top' width='50%'>";
2086 $rendered_macs = '';
2087 $mac_count = 0;
c51492f5
DO
2088 $rendered_macs .= "<table width='80%' class='widetable' cellspacing=0 cellpadding='5px' align='center'>";
2089 $rendered_macs .= '<tr><th>MAC address</th><th>VLAN</th><th>Port</th></tr>';
65e557dd
AA
2090 $order = 'even';
2091 foreach ($macList as $pn => $list)
2092 {
2093 $order = $nextorder[$order];
2094 foreach ($list as $item)
2095 {
2096 ++$mac_count;
2097 $rendered_macs .= "<tr class='row_$order'>";
c51492f5
DO
2098 $rendered_macs .= '<td style="font-family: monospace">' . $item['mac'] . '</td>';
2099 $rendered_macs .= '<td>' . $item['vid'] . '</td>';
2100 $rendered_macs .= '<td>' . $pn . '</td>';
65e557dd
AA
2101 $rendered_macs .= '</tr>';
2102 }
2103 }
2104 $rendered_macs .= "</table></td>";
dec748f6 2105
65e557dd
AA
2106 startPortlet("Learned MACs ($mac_count)");
2107 echo $rendered_macs;
2108 finishPortlet();
2109 }
2110
2111 echo "</td></tr></table>";
2112}
2113
e673ee24 2114/*
51c18782 2115The following conditions must be met:
e673ee24
DO
21161. We can mount onto free atoms only. This means: if any record for an atom
2117already exists in RackSpace, it can't be used for mounting.
21182. We can't unmount from 'W' atoms. Operator should review appropriate comments
2119and either delete them before unmounting or refuse to unmount the object.
2120*/
d10401bf 2121function renderRackSpaceForObject ($object_id)
e673ee24 2122{
e673ee24
DO
2123 // Always process occupied racks plus racks chosen by user. First get racks with
2124 // already allocated rackspace...
51c18782 2125 $workingRacksData = getResidentRacksData ($object_id);
e673ee24 2126 // ...and then add those chosen by user (if any).
2135fd83 2127 if (isset($_REQUEST['rackmulti']))
e673ee24 2128 foreach ($_REQUEST['rackmulti'] as $cand_id)
e673ee24
DO
2129 if (!isset ($workingRacksData[$cand_id]))
2130 {
0cc24e9a 2131 $rackData = spotEntity ('rack', $cand_id);
61a1d996 2132 amplifyCell ($rackData);
e673ee24
DO
2133 $workingRacksData[$cand_id] = $rackData;
2134 }
51690ad4 2135
c17a36f0
AA
2136 // Get a list of rack ids that are parents of this object.
2137 $object = spotEntity ('object', $object_id);
2138 $parentRacks = reduceSubarraysToColumn (getParents ($object, 'rack'), 'id');
0a7feebb 2139
e673ee24
DO
2140 // Main layout starts.
2141 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0><tr>";
2142
2143 // Left portlet with rack list.
2144 echo "<td class=pcleft height='1%'>";
2145 startPortlet ('Racks');
a8efc03e 2146 $allRacksData = listCells ('rack');
6d42599c
AA
2147
2148 // filter rack list to match only racks having common tags with the object (reducing $allRacksData)
55eefced 2149 if (! isset ($_REQUEST['show_all_racks']) && getConfigVar ('FILTER_RACKLIST_BY_TAGS') == 'yes')
6d42599c
AA
2150 {
2151 $matching_racks = array();
6d42599c
AA
2152 $matched_tags = array();
2153 foreach ($allRacksData as $rack)
01205bb6 2154 {
b51c1007 2155 $tag_chain = array_merge ($rack['etags'], $rack['itags']);
6d42599c 2156 foreach ($object['etags'] as $tag)
01205bb6 2157 if (tagOnChain ($tag, $tag_chain))
6d42599c
AA
2158 {
2159 $matching_racks[$rack['id']] = $rack;
2160 $matched_tags[$tag['id']] = $tag;
2161 break;
2162 }
01205bb6 2163 }
6d42599c
AA
2164 // add current object's racks even if they dont match filter
2165 foreach ($workingRacksData as $rack_id => $rack)
2166 if (! isset ($matching_racks[$rack_id]))
2167 $matching_racks[$rack_id] = $rack;
2168 // if matching racks found, and rack list is reduced, show 'show all' link
55eefced 2169 if (count ($matching_racks) && count ($matching_racks) != count ($allRacksData))
6d42599c 2170 {
1e9266ad 2171 $tmp = array();
6d42599c 2172 foreach ($matched_tags as $tag)
1e9266ad
DO
2173 $tmp[] = '{' . $tag['tag'] . '}';
2174 $filter_text = implode (' or ', $tmp);
6d42599c
AA
2175 $href_show_all = trim($_SERVER['REQUEST_URI'], '&');
2176 $href_show_all .= htmlspecialchars('&show_all_racks=1');
2177 echo "(filtered by <span class='filter-text'>$filter_text</span>, <a href='$href_show_all'>show all</a>)<p>";
2178 $allRacksData = $matching_racks;
2179 }
2180 }
2181
4b8d413e 2182 if (count ($allRacksData) <= getConfigVar ('RACK_PRESELECT_THRESHOLD'))
61a1d996 2183 foreach ($allRacksData as $rack)
51c18782
DO
2184 if (!array_key_exists ($rack['id'], $workingRacksData))
2185 {
2186 amplifyCell ($rack);
2187 $workingRacksData[$rack['id']] = $rack;
2188 }
2189 foreach (array_keys ($workingRacksData) as $rackId)
2190 applyObjectMountMask ($workingRacksData[$rackId], $object_id);
2191 printOpFormIntro ('updateObjectAllocation');
4b8d413e 2192 renderRackMultiSelect ('rackmulti[]', $allRacksData, array_keys ($workingRacksData));
51c18782 2193 echo "<br><br>";
e673ee24
DO
2194 finishPortlet();
2195 echo "</td>";
2196
2197 // Middle portlet with comment and submit.
2198 echo "<td class=pcleft>";
5c8bf2ba 2199 startPortlet ('Comment (for Rackspace History)');
e673ee24
DO
2200 echo "<textarea name=comment rows=10 cols=40></textarea><br>\n";
2201 echo "<input type=submit value='Save' name=got_atoms>\n";
51c18782 2202 echo "<br><br>";
e673ee24
DO
2203 finishPortlet();
2204 echo "</td>";
2205
2206 // Right portlet with rendered racks. If this form submit is not final, we have to
2207 // reflect the former state of the grid in current form.
2208 echo "<td class=pcright rowspan=2 height='1%'>";
2209 startPortlet ('Working copy');
e8b94513 2210 includeJQueryUI (false);
65e557dd 2211 addJS ('js/racktables.js');
c82023ad 2212 addJS ('js/bulkselector.js');
e673ee24
DO
2213 echo '<table border=0 cellspacing=10 align=center><tr>';
2214 foreach ($workingRacksData as $rack_id => $rackData)
2215 {
c26d97b6 2216 $is_ro = !rackModificationPermitted ($rackData, 'updateObjectAllocation');
e673ee24
DO
2217 // Order is important here: only original allocation is highlighted.
2218 highlightObject ($rackData, $object_id);
2219 markupAtomGrid ($rackData, 'T');
2220 // If we have a form processed, discard user input and show new database
2221 // contents.
c26d97b6 2222 if (!$is_ro && isset ($_REQUEST['rackmulti'][0])) // is an update
e673ee24
DO
2223 mergeGridFormToRack ($rackData);
2224 echo "<td valign=top>";
c26d97b6
VS
2225 echo "<center>\n<h2 style='margin:0px'>${rackData['name']}</h2>\n";
2226 $read_only_text = $is_ro ? '(read-only)' : '&nbsp;';
2227 echo "<p style='color: red; margin-top:0px'>${read_only_text}</p>\n";
e8b94513 2228 echo "<table class=rack id=selectableRack border=0 cellspacing=0 cellpadding=1>\n";
57c69e9c 2229 echo "<tr><th width='10%'>&nbsp;</th>";
bd0bfb76
AD
2230 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '0', ${rackData['height']})\">Front</a></th>";
2231 echo "<th width='50%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '1', ${rackData['height']})\">Interior</a></th>";
2232 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '2', ${rackData['height']})\">Back</a></th></tr>\n";
c26d97b6 2233 renderAtomGrid ($rackData, $is_ro);
57c69e9c 2234 echo "<tr><th width='10%'>&nbsp;</th>";
bd0bfb76
AD
2235 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '0', ${rackData['height']})\">Front</a></th>";
2236 echo "<th width='50%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '1', ${rackData['height']})\">Interior</a></th>";
2237 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '2', ${rackData['height']})\">Back</a></th></tr>\n";
0a7feebb
AD
2238 echo "</table>\n<br>\n";
2239 // Determine zero-u checkbox status.
2240 // If form has been submitted, use form data, otherwise use DB data.
c26d97b6 2241 if (!$is_ro && isset($_REQUEST['op']))
0a7feebb
AD
2242 $checked = isset($_REQUEST['zerou_'.$rack_id]) ? 'checked' : '';
2243 else
2244 $checked = in_array($rack_id, $parentRacks) ? 'checked' : '';
c26d97b6
VS
2245 $disabled_text = $is_ro ? ' disabled' : '';
2246 echo "<label for=zerou_${rack_id}>Zero-U:</label> <input type=checkbox ${checked} name=zerou_${rack_id} id=zerou_${rack_id}${disabled_text}>\n<br><br>\n";
bd0bfb76 2247 echo "<input type='button' onclick='uncheckAll();' value='Uncheck all'>\n";
0a7feebb 2248 echo '</center></td>';
e673ee24
DO
2249 }
2250 echo "</tr></table>";
2251 finishPortlet();
2252 echo "</td>\n";
2253
2254 echo "</form>\n";
2255 echo "</tr></table>\n";
2256}
2257
2258function renderMolecule ($mdata, $object_id)
2259{
2260 // sort data out
2261 $rackpack = array();
2262 global $loclist;
64b95774 2263 foreach ($mdata as $rua)
e673ee24
DO
2264 {
2265 $rack_id = $rua['rack_id'];
2266 $unit_no = $rua['unit_no'];
2267 $atom = $rua['atom'];
2268 if (!isset ($rackpack[$rack_id]))
2269 {
61a1d996
DO
2270 $rackData = spotEntity ('rack', $rack_id);
2271 amplifyCell ($rackData);
e673ee24
DO
2272 for ($i = $rackData['height']; $i > 0; $i--)
2273 for ($locidx = 0; $locidx < 3; $locidx++)
2274 $rackData[$i][$locidx]['state'] = 'F';
2275 $rackpack[$rack_id] = $rackData;
2276 }
2277 $rackpack[$rack_id][$unit_no][$loclist[$atom]]['state'] = 'T';
2278 $rackpack[$rack_id][$unit_no][$loclist[$atom]]['object_id'] = $object_id;
2279 }
2280 // now we have some racks to render
64b95774 2281 foreach ($rackpack as $rackData)
e673ee24
DO
2282 {
2283 markAllSpans ($rackData);
2284 echo "<table class=molecule cellspacing=0>\n";
2285 echo "<caption>${rackData['name']}</caption>\n";
2286 echo "<tr><th width='10%'>&nbsp;</th><th width='20%'>Front</th><th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n";
2287 for ($i = $rackData['height']; $i > 0; $i--)
2288 {
4dcd770e 2289 echo "<tr><th>" . inverseRackUnit ($i, $rackData) . "</th>";
e673ee24
DO
2290 for ($locidx = 0; $locidx < 3; $locidx++)
2291 {
2292 $state = $rackData[$i][$locidx]['state'];
65e557dd 2293 echo "<td class='atom state_${state}'>&nbsp;</td>\n";
e673ee24
DO
2294 }
2295 echo "</tr>\n";
2296 }
2297 echo "</table>\n";
2298 }
2299}
2300
23cdc7e9 2301function renderDepot ()
e673ee24 2302{
23cdc7e9 2303 global $pageno, $nextorder;
23cdc7e9 2304 $cellfilter = getCellFilter();
950dfa1f
AA
2305 $objects = array();
2306 $objects_count = getEntitiesCount ('object');
db8255ac 2307 $showobjecttype = (getConfigVar ('SHOW_OBJECTTYPE') == 'yes');
23cdc7e9
DO
2308
2309 echo "<table border=0 class=objectview>\n";
2310 echo "<tr><td class=pcleft>";
2311
950dfa1f
AA
2312 if ($objects_count == 0)
2313 echo '<h2>No objects exist</h2>';
2314 // 1st attempt: do not fetch all objects if cellfilter is empty and rendering empty result is enabled
2315 elseif (! ($cellfilter['is_empty'] && renderEmptyResults ($cellfilter, 'objects', $objects_count)))
e673ee24 2316 {
2b16c179 2317 $objects = applyCellFilter ('object', $cellfilter);
20506de3 2318 // 2nd attempt: do not render all fetched objects if rendering empty result is enabled
950dfa1f 2319 if (! renderEmptyResults ($cellfilter, 'objects', count($objects)))
1ebbf889 2320 {
4899096d
AD
2321 startPortlet ('Objects (' . count ($objects) . ')');
2322 echo '<br><br><table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
db8255ac
J
2323 echo '<tr><th>Common name</th>';
2324 if ($showobjecttype)
2325 echo '<th>Type</th>';
2326 echo '<th>Visible label</th><th>Asset tag</th><th>Row/Rack or Container</th></tr>';
4899096d 2327 $order = 'odd';
3f8a25d6
DO
2328 # gather IDs of all objects and fetch rackspace info in one pass
2329 $idlist = array();
2330 foreach ($objects as $obj)
2331 $idlist[] = $obj['id'];
2332 $mountinfo = getMountInfo ($idlist);
cae81598 2333 $containerinfo = getContainerInfo ($idlist);
4899096d
AD
2334 foreach ($objects as $obj)
2335 {
ec788aba
AD
2336 $problem = ($obj['has_problems'] == 'yes') ? 'has_problems' : '';
2337 echo "<tr class='row_${order} tdleft ${problem}' valign=top><td>" . mkA ("<strong>${obj['dname']}</strong>", 'object', $obj['id']);
4899096d
AD
2338 if (count ($obj['etags']))
2339 echo '<br><small>' . serializeTags ($obj['etags'], makeHref(array('page'=>$pageno, 'tab'=>'default')) . '&') . '</small>';
db8255ac
J
2340 echo '</td>';
2341 if ($showobjecttype)
9563f56f 2342 echo "<td>" . decodeObjectType ($obj['objtype_id']) . "</td>";
8526b4cc 2343 echo "<td>${obj['label']}</td>";
4318ced5 2344 echo "<td>${obj['asset_no']}</td>";
3f8a25d6 2345 $places = array();
cae81598
AD
2346 if (array_key_exists ($obj['id'], $containerinfo))
2347 foreach ($containerinfo[$obj['id']] as $ci)
20506de3 2348 $places[] = mkA ($ci['container_dname'], 'object', $ci['container_id']);
cae81598 2349 if (array_key_exists ($obj['id'], $mountinfo))
3f8a25d6
DO
2350 foreach ($mountinfo[$obj['id']] as $mi)
2351 $places[] = mkA ($mi['row_name'], 'row', $mi['row_id']) . '/' . mkA ($mi['rack_name'], 'rack', $mi['rack_id']);
cae81598
AD
2352 if (! count ($places))
2353 $places[] = 'Unmounted';
4318ced5 2354 echo "<td>" . implode (', ', $places) . '</td>';
4899096d
AD
2355 echo '</tr>';
2356 $order = $nextorder[$order];
2357 }
2358 echo '</table>';
2359 finishPortlet();
1ebbf889 2360 }
e673ee24 2361 }
23cdc7e9
DO
2362
2363 echo "</td><td class=pcright width='25%'>";
2364
95857b5c 2365 renderCellFilterPortlet ($cellfilter, 'object', $objects);
23cdc7e9 2366 echo "</td></tr></table>\n";
e673ee24
DO
2367}
2368
1ebbf889
AA
2369// This function returns TRUE if the result set is too big to be rendered, and no filter is set.
2370// In this case it renders the describing message instead.
2371function renderEmptyResults($cellfilter, $entities_name, $count = NULL)
2372{
2373 if (!$cellfilter['is_empty'])
2374 return FALSE;
2375 if (isset ($_REQUEST['show_all_objects']))
2376 return FALSE;
2377 $max = intval(getConfigVar('MAX_UNFILTERED_ENTITIES'));
2378 if (0 == $max || $count <= $max)
2379 return FALSE;
2380
2381 $href_show_all = trim($_SERVER['REQUEST_URI'], '&');
2382 $href_show_all .= htmlspecialchars('&show_all_objects=1');
2383 $suffix = isset ($count) ? " ($count)" : '';
2384 echo <<<END
2385<p>Please set a filter to display the corresponging $entities_name.
2386<br><a href="$href_show_all">Show all $entities_name$suffix</a>
2387END;
2388 return TRUE;
2389}
2390
e673ee24 2391// History viewer for history-enabled simple dictionaries.
9b8174d7 2392function renderObjectHistory ($object_id)
e673ee24 2393{
e673ee24
DO
2394 $order = 'odd';
2395 global $nextorder;
9b8174d7
AD
2396 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
2397 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>';
2398 $result = usePreparedSelectBlade
2399 (
2400 'SELECT ctime, user_name, name, label, asset_no, has_problems, comment FROM ObjectHistory WHERE id=? ORDER BY ctime',
2401 array ($object_id)
2402 );
e673ee24
DO
2403 while ($row = $result->fetch (PDO::FETCH_NUM))
2404 {
2405 echo "<tr class=row_${order}><td>${row[0]}</td>";
9b8174d7 2406 for ($i = 1; $i <= 6; $i++)
e673ee24
DO
2407 echo "<td>" . $row[$i] . "</td>";
2408 echo "</tr>\n";
2409 $order = $nextorder[$order];
2410 }
2411 echo "</table><br>\n";
2412}
2413
2414function renderRackspaceHistory ()
2415{
4fbb5a00 2416 global $nextorder, $pageno, $tabno;
e673ee24
DO
2417 $order = 'odd';
2418 $history = getRackspaceHistory();
2419 // Show the last operation by default.
2420 if (isset ($_REQUEST['op_id']))
2421 $op_id = $_REQUEST['op_id'];
2422 elseif (isset ($history[0]['mo_id']))
2423 $op_id = $history[0]['mo_id'];
2424 else $op_id = NULL;
dec748f6 2425
e673ee24
DO
2426 $omid = NULL;
2427 $nmid = NULL;
2428 $object_id = 1;
2429 if ($op_id)
2430 list ($omid, $nmid) = getOperationMolecules ($op_id);
2431
2432 // Main layout starts.
2433 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
2434
2435 // Left top portlet with old allocation.
2436 echo "<tr><td class=pcleft>";
2437 startPortlet ('Old allocation');
2438 if ($omid)
2439 {
2440 $oldMolecule = getMolecule ($omid);
2441 renderMolecule ($oldMolecule, $object_id);
2442 }
2443 else
2444 echo "nothing";
2445 finishPortlet();
2446
2447 echo '</td><td class=pcright>';
2448
2449 // Right top portlet with new allocation
2450 startPortlet ('New allocation');
2451 if ($nmid)
2452 {
2453 $newMolecule = getMolecule ($nmid);
2454 renderMolecule ($newMolecule, $object_id);
2455 }
2456 else
2457 echo "nothing";
2458 finishPortlet();
737a3f72 2459
e673ee24 2460 echo '</td></tr><tr><td colspan=2>';
737a3f72 2461
e673ee24
DO
2462 // Bottom portlet with list
2463
2464 startPortlet ('Rackspace allocation history');
2465 echo "<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>\n";
7fa7047a 2466 echo "<tr><th>timestamp</th><th>author</th><th>object</th><th>comment</th></tr>\n";
e673ee24
DO
2467 foreach ($history as $row)
2468 {
2469 if ($row['mo_id'] == $op_id)
2470 $class = 'hl';
2471 else
2472 $class = "row_${order}";
4fbb5a00 2473 echo "<tr class=${class}><td><a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'op_id'=>$row['mo_id']))."'>${row['ctime']}</a></td>";
7fa7047a
DO
2474 echo "<td>${row['user_name']}</td><td>";
2475 renderCell (spotEntity ('object', $row['ro_id']));
a0bdf6dc 2476 echo '</td><td>' . stringForTD ($row['comment'], 0) . '</td></tr>';
e673ee24
DO
2477 $order = $nextorder[$order];
2478 }
2479 echo "</table>\n";
2480 finishPortlet();
737a3f72 2481
e673ee24 2482 echo '</td></tr></table>';
e673ee24
DO
2483}
2484
4318ced5 2485function renderIPSpaceRecords ($tree, $baseurl, $target = 0, $level = 1)
d65353ad
DO
2486{
2487 $self = __FUNCTION__;
4318ced5 2488 $knight = (getConfigVar ('IPV4_ENABLE_KNIGHT') == 'yes');
774968ea 2489 $display_routers = (getConfigVar ('IPV4_TREE_RTR_AS_CELL') != 'none');
00276508
AA
2490
2491 // scroll page to the highlighted item
2492 if ($target && isset ($_REQUEST['hl_net']))
65e557dd 2493 addAutoScrollScript ("net-$target");
00276508 2494
d65353ad
DO
2495 foreach ($tree as $item)
2496 {
0137d53c
DO
2497 if (isset ($item['id']))
2498 {
1f54e1ba 2499 $decor = array ('indent' => $level);
fec0c8da 2500 if ($item['symbol'] == 'node-collapsed')
4318ced5 2501 $decor['symbolurl'] = "${baseurl}&eid=${item['id']}&hl_net=1";
fec0c8da 2502 elseif ($item['symbol'] == 'node-expanded')
4318ced5
AA
2503 $decor['symbolurl'] = $baseurl . ($item['parent_id'] ? "&eid=${item['parent_id']}&hl_net=1" : '');
2504 $tr_class = '';
21ee3351 2505 if ($target == $item['id'] && isset ($_REQUEST['hl_net']))
64347dcf 2506 {
5c717ce5 2507 $decor['tdclass'] = ' highlight';
4318ced5 2508 $tr_class = $decor['tdclass'];
64347dcf 2509 }
4318ced5
AA
2510 echo "<tr valign=top class=\"$tr_class\">";
2511 printIPNetInfoTDs ($item, $decor);
2512
2513 // capacity and usage
2514 echo "<td class=tdcenter>";
2515 echo getRenderedIPNetCapacity ($item);
64347dcf 2516 echo "</td>";
4318ced5
AA
2517
2518 if ($display_routers)
6063fab7 2519 printRoutersTD (findNetRouters ($item), getConfigVar ('IPV4_TREE_RTR_AS_CELL'));
0137d53c 2520 echo "</tr>";
55eefced 2521 if ($item['symbol'] == 'node-expanded' || $item['symbol'] == 'node-expanded-static')
4318ced5 2522 $self ($item['kids'], $baseurl, $target, $level + 1);
0137d53c 2523 }
26fc6e7c 2524 elseif (getConfigVar ('IPV4_TREE_SHOW_UNALLOCATED') == 'yes')
0137d53c 2525 {
4318ced5 2526 // non-allocated (spare) IP range
0137d53c 2527 echo "<tr valign=top>";
21ee3351 2528 printIPNetInfoTDs ($item, array ('indent' => $level, 'knight' => $knight, 'tdclass' => 'sparenetwork'));
00276508 2529
4318ced5 2530 // capacity and usage
21ee3351 2531 echo "<td class=tdcenter>";
4318ced5 2532 echo getRenderedIPNetCapacity ($item);
21ee3351 2533 echo "</td>";
4318ced5
AA
2534 if ($display_routers)
2535 echo "<td></td>";
21ee3351 2536 echo "</tr>";
21ee3351 2537 }
21ee3351
AA
2538 }
2539}
2540
4318ced5 2541function renderIPSpace()
e673ee24 2542{
4fbb5a00 2543 global $pageno, $tabno;
4318ced5 2544 $realm = ($pageno == 'ipv4space' ? 'ipv4net' : 'ipv6net');
31c941ec 2545 $cellfilter = getCellFilter();
21ee3351 2546
b99b4167
AA
2547 // expand request can take either natural values or "ALL". Zero means no expanding.
2548 $eid = isset ($_REQUEST['eid']) ? $_REQUEST['eid'] : 0;
2549
21ee3351
AA
2550 echo "<table border=0 class=objectview>\n";
2551 echo "<tr><td class=pcleft>";
950dfa1f
AA
2552
2553 $netlist = array();
b99b4167 2554 if (! ($cellfilter['is_empty'] && ! $eid && renderEmptyResults($cellfilter, 'IP nets', getEntitiesCount ($realm))))
21ee3351 2555 {
950dfa1f
AA
2556 $top = NULL;
2557 foreach (listCells ($realm) as $net)
21ee3351 2558 {
55eefced 2559 if (isset ($top) && IPNetContains ($top, $net))
950dfa1f 2560 ;
55eefced 2561 elseif (! count ($cellfilter['expression']) || judgeCell ($net, $cellfilter['expression']))
950dfa1f
AA
2562 $top = $net;
2563 else
2564 continue;
2565 $netlist[$net['id']] = $net;
2566 }
2567 $netcount = count ($netlist);
950dfa1f
AA
2568 $tree = prepareIPTree ($netlist, $eid);
2569
2570 if (! renderEmptyResults($cellfilter, 'IP nets', count($tree)))
2571 {
2572 startPortlet ("networks (${netcount})");
2573 echo '<h4>';
2574 $all = "<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'eid'=>'ALL')) .
2575 $cellfilter['urlextra'] . "'>expand&nbsp;all</a>";
2576 $none = "<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'eid'=>'NONE')) .
2577 $cellfilter['urlextra'] . "'>collapse&nbsp;all</a>";
2578 $auto = "<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno)) .
2579 $cellfilter['urlextra'] . "'>auto-collapse</a>";
2580
2581 if ($eid === 0)
2582 echo 'auto-collapsing at threshold ' . getConfigVar ('TREE_THRESHOLD') . " ($all / $none)";
2583 elseif ($eid === 'ALL')
2584 echo "expanding all ($auto / $none)";
2585 elseif ($eid === 'NONE')
2586 echo "collapsing all ($all / $auto)";
2587 else
2588 {
a0f0c0c7
AA
2589 try
2590 {
2591 $netinfo = spotEntity ($realm, $eid);
2592 echo "expanding ${netinfo['ip']}/${netinfo['mask']} ($auto / $all / $none)";
2593 }
2594 catch (EntityNotFoundException $e)
2595 {
2596 // ignore invalid eid error
2597 }
950dfa1f 2598 }
6edc799c 2599 echo "</h4><table class='widetable zebra' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
950dfa1f
AA
2600 echo "<tr><th>prefix</th><th>name/tags</th><th>capacity</th>";
2601 if (getConfigVar ('IPV4_TREE_RTR_AS_CELL') != 'none')
2602 echo "<th>routed by</th>";
2603 echo "</tr>\n";
2604 $baseurl = makeHref(array('page'=>$pageno, 'tab'=>$tabno)) . $cellfilter['urlextra'];
2605 renderIPSpaceRecords ($tree, $baseurl, $eid);
2606 echo "</table>\n";
2607 finishPortlet();
21ee3351 2608 }
21ee3351
AA
2609 }
2610
2611 echo '</td><td class=pcright>';
950dfa1f 2612 renderCellFilterPortlet ($cellfilter, $realm, $netlist);
21ee3351
AA
2613 echo "</td></tr></table>\n";
2614}
2615
4318ced5 2616function renderIPSpaceEditor()
21ee3351 2617{
4318ced5
AA
2618 global $pageno;
2619 $realm = ($pageno == 'ipv4space' ? 'ipv4net' : 'ipv6net');
4318ced5 2620 $addrspaceList = listCells ($realm);
93a49e5b
AA
2621 startPortlet ('Manage existing (' . count ($addrspaceList) . ')');
2622 if (count ($addrspaceList))
21ee3351 2623 {
21ee3351
AA
2624 echo "<table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
2625 echo "<tr><th>&nbsp;</th><th>prefix</th><th>name</th><th>capacity</th></tr>";
21ee3351
AA
2626 foreach ($addrspaceList as $netinfo)
2627 {
21ee3351 2628 echo "<tr valign=top><td>";
93a49e5b 2629 if (! isIPNetworkEmpty ($netinfo))
21ee3351
AA
2630 printImageHREF ('nodestroy', 'There are ' . count ($netinfo['addrlist']) . ' allocations inside');
2631 else
93a49e5b 2632 echo getOpLink (array ('op' => 'del', 'id' => $netinfo['id']), '', 'destroy', 'Delete this prefix');
6d8424f8 2633 echo '</td><td class=tdleft>' . mkCellA ($netinfo) . '</td>';
a0bdf6dc 2634 echo '<td class=tdleft>' . stringForTD ($netinfo['name']);
1f54e1ba
DO
2635 if (count ($netinfo['etags']))
2636 echo '<br><small>' . serializeTags ($netinfo['etags']) . '</small>';
2637 echo '</td><td>';
4318ced5 2638 echo getRenderedIPNetCapacity ($netinfo);
b1e39212 2639 echo '</tr>';
e673ee24 2640 }
04d619d0
DO
2641 echo "</table>";
2642 finishPortlet();
e673ee24 2643 }
93a49e5b
AA
2644}
2645
2646function renderIPNewNetForm ()
2647{
2648 global $pageno;
2649 if ($pageno == 'ipv6space')
2650 {
2651 $realm = 'ipv6net';
3495ec6e 2652 $regexp = '^[a-fA-F0-9:]*:[a-fA-F0-9:\.]*/\d{1,3}$';
93a49e5b
AA
2653 }
2654 else
2655 {
2656 $realm = 'ipv4net';
3495ec6e 2657 $regexp = '^(\d{1,3}\.){3}\d{1,3}/\d{1,2}$';
93a49e5b
AA
2658 }
2659
2660 // IP prefix validator
10f5133a 2661 addJS ('js/live_validation.js');
93a49e5b 2662 $regexp = addslashes ($regexp);
10f5133a 2663 addJS (<<<END
93a49e5b 2664$(document).ready(function () {
b895e6b4 2665 $('form#add input[name="range"]').attr('match', '$regexp');
93a49e5b
AA
2666 Validate.init();
2667});
2668END
2669 , TRUE);
dec748f6 2670
93a49e5b 2671 startPortlet ('Add new');
10f5133a 2672 printOpFormIntro ('add');
e7b84015
AB
2673 echo '<table border=0 cellpadding=5 cellspacing=0 align=center>';
2674
93a49e5b
AA
2675 // inputs column
2676 $prefix_value = empty ($_REQUEST['set-prefix']) ? '' : $_REQUEST['set-prefix'];
04c61e7e 2677 echo "<th class=tdright>Prefix:</th><td class=tdleft><input type=text name='range' size=36 class='live-validate' value='${prefix_value}'></td>";
e7b84015 2678 echo '<tr><th class=tdright>VLAN:</th><td class=tdleft>';
04c61e7e
AB
2679 echo getOptionTree ('vlan_ck', getAllVLANOptions(), array ('select_class' => 'vertical')) . '</td></tr>';
2680 echo "<tr><th class=tdright>Name:</th><td class=tdleft><input type=text name='name' size='20'></td></tr>";
e7b84015
AB
2681 echo '<tr><th class=tdright>Tags:</th><td class="tdleft">';
2682 printTagsPicker ();
2683 echo '</td></tr>';
38707670
DO
2684 echo '<tr><td class=tdright><input type=checkbox name="is_connected" id="is_connected"></td>';
2685 echo '<th class=tdleft><label for="is_connected">reserve subnet-router anycast address</label></th></tr>';
93a49e5b 2686 echo "<tr><td colspan=2>";
04c61e7e 2687 printImageHREF ('CREATE', 'Add a new network', TRUE);
93a49e5b 2688 echo '</td></tr>';
e7b84015 2689 echo "</table></form><br><br>\n";
93a49e5b 2690 finishPortlet();
e673ee24
DO
2691}
2692
4318ced5 2693function getRenderedIPNetBacktrace ($range)
e673ee24 2694{
4318ced5
AA
2695 if (getConfigVar ('EXT_IPV4_VIEW') != 'yes')
2696 return array();
e673ee24 2697
4318ced5
AA
2698 $v = ($range['realm'] == 'ipv4net') ? 4 : 6;
2699 $space = "ipv${v}space"; // ipv4space, ipv6space
2700 $tag = "\$ip${v}netid_"; // $ip4netid_, $ip6netid_
dec748f6 2701
4318ced5
AA
2702 $ret = array();
2703 // Build a backtrace from all parent networks.
2704 $clen = $range['mask'];
2705 $backtrace = array();
2706 $backtrace['&rarr;'] = $range;
2707 $key = '';
2708 while (NULL !== ($upperid = getIPAddressNetworkId ($range['ip_bin'], $clen)))
2709 {
2710 $upperinfo = spotEntity ($range['realm'], $upperid);
2711 $clen = $upperinfo['mask'];
2712 $key .= '&uarr;';
2713 $backtrace[$key] = $upperinfo;
2714 }
2715 foreach (array_reverse ($backtrace) as $arrow => $ainfo)
2716 {
2717 $link = '<a href="' . makeHref (array (
2718 'page' => $space,
2719 'tab' => 'default',
2720 'clear-cf' => '',
2721 'cfe' => '{' . $tag . $ainfo['id'] . '}',
2722 'hl_net' => 1,
2723 'eid' => $range['id'],
2724 )) . '" title="View IP tree with this net as root">' . $arrow . '</a>';
2725 $ret[] = array ($link, getOutputOf ('renderCell', $ainfo));
2726 }
2727 return $ret;
2728}
2729
d10401bf 2730function renderIPNetwork ($id)
4318ced5
AA
2731{
2732 global $pageno;
2733 $realm = $pageno; // 'ipv4net', 'ipv6net'
d10401bf 2734 $range = spotEntity ($realm, $id);
4318ced5 2735 loadIPAddrList ($range);
2034d968 2736 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
99ab184f
DO
2737 echo "<tr><td colspan=2 align=center><h1>${range['ip']}/${range['mask']}</h1><h2>";
2738 echo htmlspecialchars ($range['name'], ENT_QUOTES, 'UTF-8') . "</h2></td></tr>\n";
2034d968
DO
2739
2740 echo "<tr><td class=pcleft width='50%'>";
646272be
AA
2741
2742 // render summary portlet
2743 $summary = array();
4318ced5 2744 $summary['%% used'] = getRenderedIPNetCapacity ($range);
2b6b0038 2745 $summary = getRenderedIPNetBacktrace ($range) + $summary;
4318ced5 2746 if ($realm == 'ipv4net')
001e61fa 2747 {
4318ced5
AA
2748 $summary[] = array ('Netmask:', ip4_format ($range['mask_bin']));
2749 $summary[] = array ('Netmask:', "0x" . strtoupper (implode ('', unpack ('H*', $range['mask_bin']))));
2750 $summary['Wildcard bits'] = ip4_format ( ~ $range['mask_bin']);
001e61fa 2751 }
dec748f6 2752
11e3af31
DO
2753 $reuse_domain = considerConfiguredConstraint ($range, '8021Q_MULTILINK_LISTSRC');
2754 $domainclass = array();
2755 foreach (array_count_values (reduceSubarraysToColumn ($range['8021q'], 'domain_id')) as $domain_id => $vlan_count)
2756 $domainclass[$domain_id] = $vlan_count == 1 ? '' : ($reuse_domain ? '{trwarning}' : '{trerror}');
a5f9d1ca 2757 foreach ($range['8021q'] as $item)
3f642516 2758 $summary[] = array ($domainclass[$item['domain_id']] . 'VLAN:', formatVLANAsHyperlink (getVlanRow ($item['domain_id'] . '-' . $item['vlan_id'])));
55eefced 2759 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes' && count ($routers = findNetRouters ($range)))
04d619d0 2760 {
646272be
AA
2761 $summary['Routed by'] = '';
2762 foreach ($routers as $rtr)
4318ced5 2763 $summary['Routed by'] .= getOutputOf ('renderRouterCell', $rtr['ip_bin'], $rtr['iface'], spotEntity ('object', $rtr['id']));
04d619d0 2764 }
646272be
AA
2765 $summary['tags'] = '';
2766 renderEntitySummary ($range, 'summary', $summary);
e1ae3fb4 2767
33973968 2768 if ($range['comment'] != '')
99ab184f
DO
2769 {
2770 startPortlet ('Comment');
2771 echo '<div class=commentblock>' . string_insert_hrefs (htmlspecialchars ($range['comment'], ENT_QUOTES, 'UTF-8')) . '</div>';
2772 finishPortlet ();
2773 }
2774
d10401bf 2775 renderFilesPortlet ($realm, $id);
2034d968 2776 echo "</td>\n";
e673ee24 2777
2034d968
DO
2778 echo "<td class=pcright>";
2779 startPortlet ('details');
4318ced5
AA
2780 renderIPNetworkAddresses ($range);
2781 finishPortlet();
2782 echo "</td></tr></table>\n";
2783}
e673ee24 2784
4318ced5
AA
2785// Used solely by renderSeparator
2786function renderEmptyIPv6 ($ip_bin, $hl_ip)
2787{
2788 $class = 'tdleft';
2789 if ($ip_bin === $hl_ip)
5c717ce5 2790 $class .= ' highlight';
4318ced5 2791 $fmt = ip6_format ($ip_bin);
235124a6 2792 echo "<tr class='$class'><td><a name='ip-$fmt' href='" . makeHref (array ('page' => 'ipaddress', 'ip' => $fmt)) . "'>" . $fmt;
0b8d8309
AA
2793 $editable = permitted ('ipaddress', 'properties', 'editAddress')
2794 ? 'editable'
2795 : '';
cc2fa820
AD
2796 echo "</a></td><td><span class='rsvtext $editable id-$fmt op-upd-ip-name'></span></td>";
2797 echo "<td><span class='rsvtext $editable id-$fmt op-upd-ip-comment'></span></td><td>&nbsp;</td></tr>\n";
4318ced5
AA
2798}
2799
2800// Renders empty table line to shrink empty IPv6 address ranges.
2801// If the range consists of single address, renders the address instead of empty line.
2802// Renders address $hl_ip inside the range.
2803// Used solely by renderIPv6NetworkAddresses
2804function renderSeparator ($first, $last, $hl_ip)
2805{
2806 $self = __FUNCTION__;
2807 if (strcmp ($first, $last) > 0)
2808 return;
2809 if ($first == $last)
2810 renderEmptyIPv6 ($first, $hl_ip);
2811 elseif (isset ($hl_ip) && strcmp ($hl_ip, $first) >= 0 && strcmp ($hl_ip, $last) <= 0)
2812 { // $hl_ip is inside the range $first - $last
2813 $self ($first, ip_prev ($hl_ip), $hl_ip);
2814 renderEmptyIPv6 ($hl_ip, $hl_ip);
2815 $self (ip_next ($hl_ip), $last, $hl_ip);
2816 }
2817 else
cc2fa820 2818 echo "<tr><td colspan=4 class=tdleft></td></tr>\n";
4318ced5
AA
2819}
2820
75e7c0c6 2821// calculates page number that contains given $ip (used by renderIPv6NetworkAddresses)
4318ced5
AA
2822function getPageNumOfIPv6 ($list, $ip_bin, $maxperpage)
2823{
2824 if (intval ($maxperpage) <= 0 || count ($list) <= $maxperpage)
2825 return 0;
2826 $keys = array_keys ($list);
2827 for ($i = 1; $i <= count ($keys); $i++)
2828 if (strcmp ($keys[$i-1], $ip_bin) >= 0)
2829 return intval ($i / $maxperpage);
2830 return intval (count ($list) / $maxperpage);
2831}
2832
2833function renderIPNetworkAddresses ($range)
2834{
2835 switch (strlen ($range['ip_bin']))
2836 {
2837 case 4: return renderIPv4NetworkAddresses ($range);
2838 case 16: return renderIPv6NetworkAddresses ($range);
2839 default: throw new InvalidArgException ("range['ip_bin']", $range['ip_bin']);
2840 }
2841}
2842
247acd67
KZ
2843function renderIPv4NetworkPageLink ($rangeid, $page, $title)
2844{
2845 global $pageno, $tabno;
2846 return "<a href='".makeHref (array ('page' => $pageno, 'tab' => $tabno, 'id' => $rangeid, 'pg' => $page)) . "' title='".$title."'>".$page."</a> ";
2847}
2848
2849function renderIPv4NetworkPagination ($range, $page, $numpages)
2850{
2851 $rendered_pager = '';
2852 $startip = ip4_bin2int ($range['ip_bin']);
2853 $endip = ip4_bin2int (ip_last ($range));
2854 $rangeid = $range['id'];
2855 // Should make this configurable perhaps
2856 // How many pages before/after current page to show
2857 $prepostpagecount = 8;
2858 // Minimum pages where pagination does not happen
2859 $paginationat = 16; // 16 pages is a /20, 32 is a /19
2860 $maxperpage = getConfigVar ('IPV4_ADDRS_PER_PAGE');
2861 if ($numpages <= $paginationat)
2862 {
2863 // create original pagination
2864 for ($i = 0; $i < $numpages; $i++)
2865 if ($i == $page)
2866 $rendered_pager .= "<b>".$i."</b> ";
2867 else
2868 $rendered_pager .= renderIPv4NetworkPageLink($rangeid, $i, ip4_format(ip4_int2bin($startip + $i * $maxperpage)));
2869 }
2870 else // number of pages > page range, create ranged pagination
2871 {
2872 // page is within first subset
2873 if ($page - $prepostpagecount <= 1)
2874 {
2875 for ($i = 0; $i < $page; $i++)
2876 $rendered_pager .= renderIPv4NetworkPageLink($rangeid, $i, ip4_format(ip4_int2bin($startip + $i * $maxperpage)));
2877 }
2878 // render 0 ... [page - prepostpagecount] [page - prepostpagecount + 1] ... [page - 1]
2879 else
2880 {
2881 $rendered_pager .= renderIPv4NetworkPageLink($rangeid, 0, ip4_format(ip4_int2bin($startip)));
2882 $rendered_pager .= "... ";
2883 for ($i = $page - $prepostpagecount; $i < $page; $i++)
2884 $rendered_pager .= renderIPv4NetworkPageLink($rangeid, $i, ip4_format(ip4_int2bin($startip + $i * $maxperpage)));
2885 }
2886 // render current page
2887 $rendered_pager .= "<b>".$page."</b> ";
2888 // page is within last subset
2889 if ($page + $prepostpagecount >= $numpages-2)
2890 {
2891 for ($i = $page+1; $i < $numpages; $i++)
2892 $rendered_pager .= renderIPv4NetworkPageLink($rangeid, $i, ip4_format(ip4_int2bin($startip + $i * $maxperpage)));
2893 }
2894 // render [page + 1] [page + 2] ... [page + postpagecount] ... [end page]
2895 else
2896 {
2897 for ($i = $page+1; $i <= $page+$prepostpagecount; $i++)
2898 $rendered_pager .= renderIPv4NetworkPageLink($rangeid, $i, ip4_format(ip4_int2bin($startip + $i * $maxperpage)));
2899 $rendered_pager .= "... ";
2900 $rendered_pager .= renderIPv4NetworkPageLink($rangeid, ($numpages-1), ip4_format(ip4_int2bin($endip)));
2901 }
2902 }
2903 return $rendered_pager;
2904}
2905
4318ced5
AA
2906function renderIPv4NetworkAddresses ($range)
2907{
9d5f6a80 2908 global $pageno, $tabno, $aac_left;
4318ced5
AA
2909 $startip = ip4_bin2int ($range['ip_bin']);
2910 $endip = ip4_bin2int (ip_last ($range));
2911
2912 if (isset ($_REQUEST['hl_ip']))
00276508 2913 {
4318ced5
AA
2914 $hl_ip = ip4_bin2int (ip4_parse ($_REQUEST['hl_ip']));
2915 addAutoScrollScript ('ip-' . $_REQUEST['hl_ip']); // scroll page to highlighted ip
00276508
AA
2916 }
2917
79b57b18
AA
2918 // pager
2919 $maxperpage = getConfigVar ('IPV4_ADDRS_PER_PAGE');
2920 $address_count = $endip - $startip + 1;
2921 $page = 0;
446c25c3 2922 $rendered_pager = '';
79b57b18
AA
2923 if ($address_count > $maxperpage && $maxperpage > 0)
2924 {
2925 $page = isset ($_REQUEST['pg']) ? $_REQUEST['pg'] : (isset ($hl_ip) ? intval (($hl_ip - $startip) / $maxperpage) : 0);
2926 if ($numpages = ceil ($address_count / $maxperpage))
2927 {
4318ced5 2928 echo '<h3>' . ip4_format (ip4_int2bin ($startip)) . ' ~ ' . ip4_format (ip4_int2bin ($endip)) . '</h3>';
247acd67 2929 $rendered_pager = renderIPv4NetworkPagination ($range, $page, $numpages);
79b57b18
AA
2930 }
2931 $startip = $startip + $page * $maxperpage;
2932 $endip = min ($startip + $maxperpage - 1, $endip);
2933 }
2934
446c25c3 2935 echo $rendered_pager;
1ce89bdd 2936 echo "<table class='widetable' border=0 cellspacing=0 cellpadding=5 align='center' width='100%'>\n";
cc2fa820 2937 echo "<tr><th>Address</th><th>Name</th><th>Comment</th><th>Allocation</th></tr>\n";
e673ee24 2938
4318ced5
AA
2939 markupIPAddrList ($range['addrlist']);
2940 for ($ip = $startip; $ip <= $endip; $ip++)
2941 {
2942 $ip_bin = ip4_int2bin ($ip);
2943 $dottedquad = ip4_format ($ip_bin);
5c717ce5 2944 $tr_class = (isset ($hl_ip) && $hl_ip == $ip ? 'highlight' : '');
0cd7c0f6
AA
2945 if (isset ($range['addrlist'][$ip_bin]))
2946 $addr = $range['addrlist'][$ip_bin];
2947 else
e673ee24 2948 {
235124a6 2949 echo "<tr class='tdleft $tr_class'><td class=tdleft><a name='ip-$dottedquad' href='" . makeHref(array('page'=>'ipaddress', 'ip' => $dottedquad)) . "'>$dottedquad</a></td>";
0b8d8309
AA
2950 $editable = permitted ('ipaddress', 'properties', 'editAddress')
2951 ? 'editable'
2952 : '';
cc2fa820
AD
2953 echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-name'></span></td>";
2954 echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-comment'></span></td><td></td></tr>\n";
b2035dca
DO
2955 continue;
2956 }
68c91b9c
AA
2957 // render IP change history
2958 $title = '';
2959 $history_class = '';
2960 if (isset ($addr['last_log']))
2961 {
2962 $title = ' title="' . htmlspecialchars ($addr['last_log']['user'] . ', ' . formatAge ($addr['last_log']['time']) , ENT_QUOTES) . '"';
2963 $history_class = 'hover-history underline';
2964 }
4318ced5
AA
2965 $tr_class .= ' ' . $addr['class'];
2966 echo "<tr class='tdleft $tr_class'>";
235124a6 2967 echo "<td><a class='$history_class' $title name='ip-$dottedquad' href='".makeHref(array('page'=>'ipaddress', 'ip'=>$addr['ip']))."'>${addr['ip']}</a></td>";
0b8d8309 2968 $editable =
cc2fa820 2969 (empty ($addr['allocs']) || !empty ($addr['name']) || !empty ($addr['comment']))
0b8d8309
AA
2970 && permitted ('ipaddress', 'properties', 'editAddress')
2971 ? 'editable'
2972 : '';
cc2fa820
AD
2973 echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-name'>${addr['name']}</span></td>";
2974 echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-comment'>${addr['comment']}</span></td>";
0b8d8309 2975 echo "<td>";
b2035dca 2976 $delim = '';
b2035dca
DO
2977 if ( $addr['reserved'] == 'yes')
2978 {
2d318652 2979 echo "<strong>RESERVED</strong> ";
b2035dca
DO
2980 $delim = '; ';
2981 }
212b565a 2982 foreach ($addr['allocs'] as $ref)
b2035dca 2983 {
9d5f6a80 2984 echo $delim . $aac_left[$ref['type']];
e749a34f 2985 echo makeIPAllocLink ($ip_bin, $ref, TRUE);
b2035dca
DO
2986 $delim = '; ';
2987 }
2988 if ($delim != '')
e0d6e38e 2989 $delim = '<br>';
212b565a
AA
2990 foreach ($addr['vslist'] as $vs_id)
2991 {
2992 $vs = spotEntity ('ipv4vs', $vs_id);
ad3e5e7e 2993 echo $delim . mkA ("${vs['name']}:${vs['vport']}/${vs['proto']}", 'ipv4vs', $vs['id']) . '&rarr;';
212b565a
AA
2994 $delim = '<br>';
2995 }
eacc0983
AA
2996 foreach ($addr['vsglist'] as $vs_id)
2997 {
2998 $vs = spotEntity ('ipvs', $vs_id);
2999 echo $delim . mkA ($vs['name'], 'ipvs', $vs['id']) . '&rarr;';
3000 $delim = '<br>';
3001 }
212b565a
AA
3002 foreach ($addr['rsplist'] as $rsp_id)
3003 {
3004 $rsp = spotEntity ('ipv4rspool', $rsp_id);
ad3e5e7e 3005 echo "${delim}&rarr;" . mkA ($rsp['name'], 'ipv4rspool', $rsp['id']);
212b565a
AA
3006 $delim = '<br>';
3007 }
b2035dca 3008 echo "</td></tr>\n";
4318ced5 3009 }
2727c7df 3010 // end of iteration
a8dc2982
AA
3011 if (permitted (NULL, NULL, 'set_reserve_comment'))
3012 addJS ('js/inplace-edit.js');
e673ee24
DO
3013
3014 echo "</table>";
b956dd24 3015 if ($rendered_pager != '')
446c25c3 3016 echo '<p>' . $rendered_pager . '</p>';
21ee3351
AA
3017}
3018
3019function renderIPv6NetworkAddresses ($netinfo)
3020{
9d5f6a80 3021 global $pageno, $tabno, $aac_left;
1ce89bdd 3022 echo "<table class='widetable' border=0 cellspacing=0 cellpadding=5 align='center' width='100%'>\n";
cc2fa820 3023 echo "<tr><th>Address</th><th>Name</th><th>Comment</th><th>Allocation</th></tr>\n";
21ee3351 3024
4318ced5
AA
3025 $hl_ip = NULL;
3026 if (isset ($_REQUEST['hl_ip']))
3027 {
3028 $hl_ip = ip6_parse ($_REQUEST['hl_ip']);
3029 addAutoScrollScript ('ip-' . ip6_format ($hl_ip));
3030 }
21ee3351 3031
21ee3351
AA
3032 $addresses = $netinfo['addrlist'];
3033 ksort ($addresses);
4318ced5 3034 markupIPAddrList ($addresses);
21ee3351
AA
3035
3036 // pager
3037 $maxperpage = getConfigVar ('IPV4_ADDRS_PER_PAGE');
3038 if (count ($addresses) > $maxperpage && $maxperpage > 0)
3039 {
3040 $page = isset ($_REQUEST['pg']) ? $_REQUEST['pg'] : (isset ($hl_ip) ? getPageNumOfIPv6 ($addresses, $hl_ip, $maxperpage) : 0);
3041 $numpages = ceil (count ($addresses) / $maxperpage);
3042 echo "<center><h3>$numpages pages:</h3>";
3043 for ($i=0; $i<$numpages; $i++)
3044 {
3045 if ($i == $page)
3046 echo "<b>$i</b> ";
3047 else
3048 echo "<a href='" . makeHref (array ('page' => $pageno, 'tab' => $tabno, 'id' => $netinfo['id'], 'pg' => $i)) . "'>$i</a> ";
3049 }
3050 echo "</center>";
3051 }
3052
3053 $i = 0;
dec748f6 3054 $interruped = FALSE;
4318ced5
AA
3055 $prev_ip = ip_prev ($netinfo['ip_bin']);
3056 foreach ($addresses as $ip_bin => $addr)
21ee3351
AA
3057 {
3058 if (isset ($page))
3059 {
3060 ++$i;
3061 if ($i <= $maxperpage * $page)
3062 continue;
3063 elseif ($i > $maxperpage * ($page + 1))
3064 {
3065 $interruped = TRUE;
3066 break;
3067 }
3068 }
3069
4318ced5
AA
3070 if ($ip_bin != ip_next ($prev_ip))
3071 renderSeparator (ip_next ($prev_ip), ip_prev ($ip_bin), $hl_ip);
3072 $prev_ip = $ip_bin;
3073
3074 // render IP change history
3075 $title = '';
3076 $history_class = '';
3077 if (isset ($addr['last_log']))
3078 {
3079 $title = ' title="' . htmlspecialchars ($addr['last_log']['user'] . ', ' . formatAge ($addr['last_log']['time']) , ENT_QUOTES) . '"';
3080 $history_class = 'hover-history underline';
3081 }
3082
5c717ce5 3083 $tr_class = $addr['class'] . ' tdleft' . ($hl_ip === $ip_bin ? ' highlight' : '');
4318ced5 3084 echo "<tr class='$tr_class'>";
235124a6 3085 echo "<td><a class='$history_class' $title name='ip-${addr['ip']}' href='" . makeHref (array ('page' => 'ipaddress', 'ip' => $addr['ip'])) . "'>${addr['ip']}</a></td>";
0b8d8309
AA
3086 $editable =
3087 (empty ($addr['allocs']) || !empty ($addr['name'])
3088 && permitted ('ipaddress', 'properties', 'editAddress')
3089 ? 'editable'
3090 : '');
cc2fa820
AD
3091 echo "<td><span class='rsvtext $editable id-${addr['ip']} op-upd-ip-name'>${addr['name']}</span></td>";
3092 echo "<td><span class='rsvtext $editable id-${addr['ip']} op-upd-ip-comment'>${addr['comment']}</span></td><td>";
21ee3351 3093 $delim = '';
21ee3351
AA
3094 if ( $addr['reserved'] == 'yes')
3095 {
3096 echo "<strong>RESERVED</strong> ";
3097 $delim = '; ';
3098 }
3099 foreach ($addr['allocs'] as $ref)
3100 {
9d5f6a80 3101 echo $delim . $aac_left[$ref['type']];
e749a34f 3102 echo makeIPAllocLink ($ip_bin, $ref, TRUE);
21ee3351
AA
3103 $delim = '; ';
3104 }
3105 if ($delim != '')
71066ef1
AA
3106 $delim = '<br>';
3107 foreach ($addr['vslist'] as $vs_id)
3108 {
3109 $vs = spotEntity ('ipv4vs', $vs_id);
ad3e5e7e 3110 echo $delim . mkA ("${vs['name']}:${vs['vport']}/${vs['proto']}", 'ipv4vs', $vs['id']) . '&rarr;';
71066ef1
AA
3111 $delim = '<br>';
3112 }
eacc0983
AA
3113 foreach ($addr['vsglist'] as $vs_id)
3114 {
3115 $vs = spotEntity ('ipvs', $vs_id);
3116 echo $delim . mkA ($vs['name'], 'ipvs', $vs['id']) . '&rarr;';
3117 $delim = '<br>';
3118 }
71066ef1 3119 foreach ($addr['rsplist'] as $rsp_id)
21ee3351 3120 {
71066ef1 3121 $rsp = spotEntity ('ipv4rspool', $rsp_id);
ad3e5e7e 3122 echo "${delim}&rarr;" . mkA ($rsp['name'], 'ipv4rspool', $rsp['id']);
71066ef1 3123 $delim = '<br>';
21ee3351
AA
3124 }
3125 echo "</td></tr>\n";
3126 }
3127 if (! $interruped)
4318ced5 3128 renderSeparator (ip_next ($prev_ip), ip_last ($netinfo), $hl_ip);
21ee3351
AA
3129 if (isset ($page))
3130 { // bottom pager
3131 echo "<tr><td colspan=3>";
3132 if ($page > 0)
3133 echo "<a href='" . makeHref (array ('page' => $pageno, 'tab' => $tabno, 'id' => $netinfo['id'], 'pg' => $page - 1)) . "'><< prev</a> ";
3134 if ($page < $numpages - 1)
3135 echo "<a href='" . makeHref (array ('page' => $pageno, 'tab' => $tabno, 'id' => $netinfo['id'], 'pg' => $page + 1)) . "'>next >></a> ";
3136 echo "</td></tr>";
3137 }
3138 echo "</table>";