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