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