7c940e002e37991c21c402bc7837ab418bdbf11a
[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 renderSLBTriplets ($info);
1287 echo "</td>\n";
1288
1289 // After left column we have (surprise!) right column with rackspace portlet only.
1290 echo "<td class=pcright>";
1291 if (!in_array($info['objtype_id'], $virtual_obj_types))
1292 {
1293 // rackspace portlet
1294 startPortlet ('rackspace allocation');
1295 foreach (getResidentRacksData ($object_id, FALSE) as $rack_id)
1296 renderRack ($rack_id, $object_id);
1297 echo '<br>';
1298 finishPortlet();
1299 }
1300 echo "</td></tr>";
1301 echo "</table>\n";
1302 }
1303
1304 function renderRackMultiSelect ($sname, $racks, $selected)
1305 {
1306 // Transform the given flat list into a list of groups, each representing a rack row.
1307 $rdata = array();
1308 foreach ($racks as $rack)
1309 {
1310 $row_name = ($rack['location_id']) ? $rack['location_name'] . '/' . $rack['row_name'] : $rack['row_name'];
1311 $rdata[$row_name][$rack['id']] = $rack['name'];
1312 }
1313 echo "<select name=${sname} multiple size=" . getConfigVar ('MAXSELSIZE') . " onchange='getElementsByName(\"updateObjectAllocation\")[0].submit()'>\n";
1314 foreach ($rdata as $optgroup => $racklist)
1315 {
1316 echo "<optgroup label='${optgroup}'>";
1317 foreach ($racklist as $rack_id => $rack_name)
1318 {
1319 echo "<option value=${rack_id}";
1320 if (!(array_search ($rack_id, $selected) === FALSE))
1321 echo ' selected';
1322 echo">${rack_name}</option>\n";
1323 }
1324 }
1325 echo "</select>\n";
1326 }
1327
1328 // This function renders a form for port edition.
1329 function renderPortsForObject ($object_id)
1330 {
1331 $prefs = getPortListPrefs();
1332 function printNewItemTR ($prefs)
1333 {
1334 printOpFormIntro ('addPort');
1335 echo "<tr><td>";
1336 printImageHREF ('add', 'add a port', TRUE);
1337 echo "</td><td class='tdleft'><input type=text size=8 name=port_name tabindex=100></td>\n";
1338 echo "<td><input type=text name=port_label tabindex=101></td><td>";
1339 printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type_id', 'tabindex' => 102), $prefs['selected']);
1340 echo "<td><input type=text name=port_l2address tabindex=103 size=18 maxlength=24></td>\n";
1341 echo "<td colspan=4>&nbsp;</td><td>";
1342 printImageHREF ('add', 'add a port', TRUE, 104);
1343 echo "</td></tr></form>";
1344 }
1345 if (getConfigVar('ENABLE_MULTIPORT_FORM') == 'yes' || getConfigVar('ENABLE_BULKPORT_FORM') == 'yes' )
1346 startPortlet ('Ports and interfaces');
1347 else
1348 echo '<br>';
1349 $object = spotEntity ('object', $object_id);
1350 amplifyCell ($object);
1351 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes' && getConfigVar('ENABLE_BULKPORT_FORM') == 'yes'){
1352 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
1353 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>";
1354 echo "<th class=tdleft>Count</th><th>&nbsp;</th></tr>\n";
1355 printOpFormIntro ('addBulkPorts');
1356 echo "<tr><td>";
1357 printImageHREF ('add', 'add ports', TRUE);
1358 echo "</td><td><input type=text size=8 name=port_name tabindex=105></td>\n";
1359 echo "<td><input type=text name=port_label tabindex=106></td><td>";
1360 printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type_id', 'tabindex' => 107), $prefs['selected']);
1361 echo "<td><input type=text name=port_numbering_start tabindex=108 size=3 maxlength=3></td>\n";
1362 echo "<td><input type=text name=port_numbering_count tabindex=109 size=3 maxlength=3></td>\n";
1363 echo "<td>&nbsp;</td><td>";
1364 printImageHREF ('add', 'add ports', TRUE, 110);
1365 echo "</td></tr></form>";
1366 echo "</table><br>\n";
1367 }
1368
1369 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
1370 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>";
1371 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";
1372 if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
1373 printNewItemTR ($prefs);
1374
1375 // clear ports link
1376 echo getOpLink (array ('op'=>'deleteAll'), 'Clear port list', 'clear', '', 'need-confirmation');
1377
1378 if (isset ($_REQUEST['hl_port_id']))
1379 {
1380 assertUIntArg ('hl_port_id');
1381 $hl_port_id = intval ($_REQUEST['hl_port_id']);
1382 addAutoScrollScript ("port-$hl_port_id");
1383 }
1384 switchportInfoJS ($object_id); // load JS code to make portnames interactive
1385 foreach ($object['ports'] as $port)
1386 {
1387 $tr_class = isset ($hl_port_id) && $hl_port_id == $port['id'] ? 'class="highlight"' : '';
1388 printOpFormIntro ('editPort', array ('port_id' => $port['id']));
1389 echo "<tr $tr_class><td><a name='port-${port['id']}' href='".makeHrefProcess(array('op'=>'delPort', 'port_id'=>$port['id']))."'>";
1390 printImageHREF ('delete', 'Unlink and Delete this port');
1391 echo "</a></td>\n";
1392 $a_class = isEthernetPort ($port) ? 'port-menu' : '';
1393 echo "<td class='tdleft' NOWRAP><input type=text name=name class='interactive-portname $a_class' value='${port['name']}' size=8></td>";
1394 echo "<td><input type=text name=label value='${port['label']}'></td>";
1395 if (!$port['remote_object_id'])
1396 {
1397 echo '<td>';
1398 if ($port['iif_id'] != 1)
1399 echo '<label>' . $port['iif_name'] . ' ';
1400 printSelect (getExistingPortTypeOptions ($port['id']), array ('name' => 'port_type_id'), $port['oif_id']);
1401 if ($port['iif_id'] != 1)
1402 echo '</label>';
1403 echo '</td>';
1404 }
1405 else
1406 {
1407 echo "<input type=hidden name=port_type_id value='${port['oif_id']}'><td class=tdleft>";
1408 echo formatPortIIFOIF ($port) . '</td>';
1409 }
1410 // 18 is enough to fit 6-byte MAC address in its longest form,
1411 // while 24 should be Ok for WWN
1412 echo "<td><input type=text name=l2address value='${port['l2address']}' size=18 maxlength=24></td>\n";
1413 if ($port['remote_object_id'])
1414 {
1415 echo "<td>" .
1416 formatLoggedSpan ($port['last_log'], formatPortLink ($port['remote_object_id'], $port['remote_object_name'], $port['remote_id'], NULL)) .
1417 "</td>";
1418 echo "<td> " . formatLoggedSpan ($port['last_log'], $port['remote_name'], 'underline') .
1419 "<input type=hidden name=reservation_comment value=''></td>";
1420 echo "<td><input type=text name=cable value='${port['cableid']}'></td>";
1421 echo "<td class=tdcenter>";
1422 echo getOpLink (array('op'=>'unlinkPort', 'port_id'=>$port['id'], ), '', 'cut', 'Unlink this port');
1423 echo "</td>";
1424 }
1425 elseif (strlen ($port['reservation_comment']))
1426 {
1427 echo "<td>" . formatLoggedSpan ($port['last_log'], 'Reserved:', 'strong underline') . "</td>";
1428 echo "<td><input type=text name=reservation_comment value='${port['reservation_comment']}'></td>";
1429 echo "<td></td>";
1430 echo "<td class=tdcenter>";
1431 echo getOpLink (array('op'=>'useup', 'port_id'=>$port['id']), '', 'clear', 'Use up this port');
1432 echo "</td>";
1433 }
1434 else
1435 {
1436 $in_rack = getConfigVar ('NEAREST_RACKS_CHECKBOX');
1437 echo "<td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td class=tdcenter><span";
1438 $helper_args = array
1439 (
1440 'port' => $port['id'],
1441 'in_rack' => ($in_rack == "yes" ? "on" : "")
1442 );
1443 $popup_args = 'height=700, width=400, location=no, menubar=no, '.
1444 'resizable=yes, scrollbars=yes, status=no, titlebar=no, toolbar=no';
1445 echo " ondblclick='window.open(\"" . makeHrefForHelper ('portlist', $helper_args);
1446 echo "\",\"findlink\",\"${popup_args}\");'";
1447 // end of onclick=
1448 echo " onclick='window.open(\"" . makeHrefForHelper ('portlist', $helper_args);
1449 echo "\",\"findlink\",\"${popup_args}\");'";
1450 // end of onclick=
1451 echo '>';
1452 // end of <a>
1453 printImageHREF ('plug', 'Link this port');
1454 echo "</span>";
1455 echo " <input type=text name=reservation_comment></td>\n";
1456 }
1457 echo "<td>";
1458 printImageHREF ('save', 'Save changes', TRUE);
1459 echo "</td></form></tr>\n";
1460 }
1461 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
1462 printNewItemTR ($prefs);
1463 echo "</table><br>\n";
1464 if (getConfigVar ('ADDNEW_AT_TOP') != 'yes' && getConfigVar('ENABLE_BULKPORT_FORM') == 'yes'){
1465 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
1466 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>";
1467 echo "<th class=tdleft>Count</th><th>&nbsp;</th></tr>\n";
1468 printOpFormIntro ('addBulkPorts');
1469 echo "<tr><td>";
1470 printImageHREF ('add', 'add ports', TRUE);
1471 echo "</td><td><input type=text size=8 name=port_name tabindex=105></td>\n";
1472 echo "<td><input type=text name=port_label tabindex=106></td><td>";
1473 printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type_id', 'tabindex' => 107), $prefs['selected']);
1474 echo "<td><input type=text name=port_numbering_start tabindex=108 size=3 maxlength=3></td>\n";
1475 echo "<td><input type=text name=port_numbering_count tabindex=109 size=3 maxlength=3></td>\n";
1476 echo "<td>&nbsp;</td><td>";
1477 printImageHREF ('add', 'add ports', TRUE, 110);
1478 echo "</td></tr></form>";
1479 echo "</table><br>\n";
1480 }
1481 if (getConfigVar('ENABLE_MULTIPORT_FORM') == 'yes')
1482 finishPortlet();
1483 if (getConfigVar('ENABLE_MULTIPORT_FORM') != 'yes')
1484 return;
1485
1486 startPortlet ('Add/update multiple ports');
1487 printOpFormIntro ('addMultiPorts');
1488 echo 'Format: <select name=format tabindex=201>';
1489 echo '<option value=c3600asy>Cisco 3600 async: sh line | inc TTY</option>';
1490 echo '<option value=fiwg selected>Foundry ServerIron/FastIron WorkGroup/Edge: sh int br</option>';
1491 echo '<option value=fisxii>Foundry FastIron SuperX/II4000: sh int br</option>';
1492 echo '<option value=ssv1>SSV:&lt;interface name&gt; &lt;MAC address&gt;</option>';
1493 echo "</select>";
1494 echo 'Default port type: ';
1495 printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type', 'tabindex' => 202), $prefs['selected']);
1496 echo "<input type=submit value='Parse output' tabindex=204><br>\n";
1497 echo "<textarea name=input cols=100 rows=50 tabindex=203></textarea><br>\n";
1498 echo '</form>';
1499 finishPortlet();
1500 }
1501
1502 function renderIPForObject ($object_id)
1503 {
1504 function printNewItemTR ($default_type)
1505 {
1506 global $aat;
1507 printOpFormIntro ('add');
1508 echo "<tr><td>"; // left btn
1509 printImageHREF ('add', 'allocate', TRUE);
1510 echo "</td>";
1511 echo "<td class=tdleft><input type='text' size='10' name='bond_name' tabindex=100></td>\n"; // if-name
1512 echo "<td class=tdleft><input type=text name='ip' tabindex=101></td>\n"; // IP
1513 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
1514 echo "<td colspan=2>&nbsp;</td>"; // network, routed by
1515 echo '<td>';
1516 printSelect ($aat, array ('name' => 'bond_type', 'tabindex' => 102), $default_type); // type
1517 echo "</td><td>&nbsp;</td><td>"; // misc
1518 printImageHREF ('add', 'allocate', TRUE, 103); // right btn
1519 echo "</td></tr></form>";
1520 }
1521 global $aat;
1522 startPortlet ('Allocations');
1523 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'><tr>\n";
1524 echo '<th>&nbsp;</th>';
1525 echo '<th>OS interface</th>';
1526 echo '<th>IP address</th>';
1527 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
1528 {
1529 echo '<th>network</th>';
1530 echo '<th>routed by</th>';
1531 }
1532 echo '<th>type</th>';
1533 echo '<th>misc</th>';
1534 echo '<th>&nbsp</th>';
1535 echo '</tr>';
1536
1537 $alloc_list = ''; // most of the output is stored here
1538 $used_alloc_types = array();
1539 foreach (getObjectIPAllocations ($object_id) as $alloc)
1540 {
1541 if (! isset ($used_alloc_types[$alloc['type']]))
1542 $used_alloc_types[$alloc['type']] = 0;
1543 $used_alloc_types[$alloc['type']]++;
1544
1545 $rendered_alloc = callHook ('getRenderedAlloc', $object_id, $alloc);
1546 $alloc_list .= getOutputOf ('printOpFormIntro', 'upd', array ('ip' => $alloc['addrinfo']['ip']));
1547 $alloc_list .= "<tr class='${rendered_alloc['tr_class']}' valign=top>";
1548
1549 $alloc_list .= "<td>" . getOpLink (array ('op' => 'del', 'ip' => $alloc['addrinfo']['ip']), '', 'delete', 'Delete this IP address') . "</td>";
1550 $alloc_list .= "<td class=tdleft><input type='text' name='bond_name' value='${alloc['osif']}' size=10>" . $rendered_alloc['td_name_suffix'] . "</td>";
1551 $alloc_list .= $rendered_alloc['td_ip'];
1552 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
1553 {
1554 $alloc_list .= $rendered_alloc['td_network'];
1555 $alloc_list .= $rendered_alloc['td_routed_by'];
1556 }
1557 $alloc_list .= '<td>' . getSelect ($aat, array ('name' => 'bond_type'), $alloc['type']) . "</td>";
1558 $alloc_list .= $rendered_alloc['td_peers'];
1559 $alloc_list .= "<td>" .getImageHREF ('save', 'Save changes', TRUE) . "</td>";
1560
1561 $alloc_list .= "</form></tr>\n";
1562 }
1563 asort ($used_alloc_types, SORT_NUMERIC);
1564 $most_popular_type = empty ($used_alloc_types) ? 'regular' : array_last (array_keys ($used_alloc_types));
1565
1566 if ($list_on_top = (getConfigVar ('ADDNEW_AT_TOP') != 'yes'))
1567 echo $alloc_list;
1568 printNewItemTR ($most_popular_type);
1569 if (! $list_on_top)
1570 echo $alloc_list;
1571
1572 echo "</table><br>\n";
1573 finishPortlet();
1574 }
1575
1576 // This function is deprecated. Do not rely on its internals,
1577 // it will probably be removed in the next major relese.
1578 // Use new showError, showWarning, showSuccess functions.
1579 // Log array is stored in global $log_messages. Its format is simple: plain ordered array
1580 // with values having keys 'c' (both message code and severity) and 'a' (sprintf arguments array)
1581 function showMessageOrError ()
1582 {
1583 global $log_messages;
1584
1585 @session_start();
1586 if (isset ($_SESSION['log']))
1587 {
1588 $log_messages = array_merge ($_SESSION['log'], $log_messages);
1589 unset ($_SESSION['log']);
1590 }
1591 session_commit();
1592
1593 if (empty ($log_messages))
1594 return;
1595 $msginfo = array
1596 (
1597 // records 0~99 with success messages
1598 0 => array ('code' => 'success', 'format' => '%s'),
1599 5 => array ('code' => 'success', 'format' => 'added record "%s" successfully'),
1600 6 => array ('code' => 'success', 'format' => 'updated record "%s" successfully'),
1601 7 => array ('code' => 'success', 'format' => 'deleted record "%s" successfully'),
1602 8 => array ('code' => 'success', 'format' => 'Port %s successfully linked with %s'),
1603 10 => array ('code' => 'success', 'format' => 'Added %u ports, updated %u ports, encountered %u errors.'),
1604 21 => array ('code' => 'success', 'format' => 'Generation complete'),
1605 26 => array ('code' => 'success', 'format' => 'updated %u records successfully'),
1606 37 => array ('code' => 'success', 'format' => 'added %u records successfully'),
1607 38 => array ('code' => 'success', 'format' => 'removed %u records successfully'),
1608 43 => array ('code' => 'success', 'format' => 'Saved successfully.'),
1609 44 => array ('code' => 'success', 'format' => '%s failures and %s successfull changes.'),
1610 48 => array ('code' => 'success', 'format' => 'added a record successfully'),
1611 49 => array ('code' => 'success', 'format' => 'deleted a record successfully'),
1612 51 => array ('code' => 'success', 'format' => 'updated a record successfully'),
1613 57 => array ('code' => 'success', 'format' => 'Reset complete'),
1614 63 => array ('code' => 'success', 'format' => '%u change request(s) have been processed'),
1615 67 => array ('code' => 'success', 'format' => "Tag rolling done, %u objects involved"),
1616 71 => array ('code' => 'success', 'format' => 'File "%s" was linked successfully'),
1617 72 => array ('code' => 'success', 'format' => 'File was unlinked successfully'),
1618 82 => array ('code' => 'success', 'format' => "Bulk port creation was successful. %u ports created, %u failed"),
1619 87 => array ('code' => 'success', 'format' => '802.1Q recalculate: %d ports changed on %d switches'),
1620 // records 100~199 with fatal error messages
1621 100 => array ('code' => 'error', 'format' => '%s'),
1622 109 => array ('code' => 'error', 'format' => 'failed updating a record'),
1623 131 => array ('code' => 'error', 'format' => 'invalid format requested'),
1624 141 => array ('code' => 'error', 'format' => 'Encountered %u errors, updated %u record(s)'),
1625 149 => array ('code' => 'error', 'format' => 'Turing test failed'),
1626 150 => array ('code' => 'error', 'format' => 'Can only change password under DB authentication.'),
1627 151 => array ('code' => 'error', 'format' => 'Old password doesn\'t match.'),
1628 152 => array ('code' => 'error', 'format' => 'New passwords don\'t match.'),
1629 154 => array ('code' => 'error', 'format' => "Verification error: %s"),
1630 155 => array ('code' => 'error', 'format' => 'Save failed.'),
1631 159 => array ('code' => 'error', 'format' => 'Permission denied moving port %s from VLAN%u to VLAN%u'),
1632 161 => array ('code' => 'error', 'format' => 'Endpoint not found. Please either set FQDN attribute or assign an IP address to the object.'),
1633 162 => array ('code' => 'error', 'format' => 'More than one IP address is assigned to this object, please configure FQDN attribute.'),
1634 170 => array ('code' => 'error', 'format' => 'There is no network for IP address "%s"'),
1635 172 => array ('code' => 'error', 'format' => 'Malformed request'),
1636 179 => array ('code' => 'error', 'format' => 'Expired form has been declined.'),
1637 188 => array ('code' => 'error', 'format' => "Fatal SNMP failure"),
1638 189 => array ('code' => 'error', 'format' => "Unknown OID '%s'"),
1639 191 => array ('code' => 'error', 'format' => "deploy was blocked due to conflicting configuration versions"),
1640
1641 // records 200~299 with warnings
1642 200 => array ('code' => 'warning', 'format' => '%s'),
1643 201 => array ('code' => 'warning', 'format' => 'nothing happened...'),
1644 206 => array ('code' => 'warning', 'format' => '%s is not empty'),
1645 207 => array ('code' => 'warning', 'format' => 'File upload failed, error: %s'),
1646
1647 // records 300~399 with notices
1648 300 => array ('code' => 'neutral', 'format' => '%s'),
1649
1650 );
1651 // Handle the arguments. Is there any better way to do it?
1652 foreach ($log_messages as $record)
1653 {
1654 if (!isset ($record['c']) or !isset ($msginfo[$record['c']]))
1655 {
1656 $prefix = isset ($record['c']) ? $record['c'] . ': ' : '';
1657 echo "<div class=msg_neutral>(${prefix}this message was lost)</div>";
1658 continue;
1659 }
1660 if (isset ($record['a']))
1661 switch (count ($record['a']))
1662 {
1663 case 1:
1664 $msgtext = sprintf
1665 (
1666 $msginfo[$record['c']]['format'],
1667 $record['a'][0]
1668 );
1669 break;
1670 case 2:
1671 $msgtext = sprintf
1672 (
1673 $msginfo[$record['c']]['format'],
1674 $record['a'][0],
1675 $record['a'][1]
1676 );
1677 break;
1678 case 3:
1679 $msgtext = sprintf
1680 (
1681 $msginfo[$record['c']]['format'],
1682 $record['a'][0],
1683 $record['a'][1],
1684 $record['a'][2]
1685 );
1686 break;
1687 case 4:
1688 default:
1689 $msgtext = sprintf
1690 (
1691 $msginfo[$record['c']]['format'],
1692 $record['a'][0],
1693 $record['a'][1],
1694 $record['a'][2],
1695 $record['a'][3]
1696 );
1697 break;
1698 }
1699 else
1700 $msgtext = $msginfo[$record['c']]['format'];
1701 echo '<div class=msg_' . $msginfo[$record['c']]['code'] . ">${msgtext}</div>";
1702 }
1703 $log_messages = array();
1704 }
1705
1706 // renders two tables: port link status and learned MAC list
1707 function renderPortsInfo($object_id)
1708 {
1709 try
1710 {
1711 if (permitted (NULL, NULL, 'get_link_status'))
1712 $linkStatus = queryDevice ($object_id, 'getportstatus');
1713 else
1714 showWarning ("You don't have permission to view ports link status");
1715
1716 if (permitted (NULL, NULL, 'get_mac_list'))
1717 $macList = sortPortList (queryDevice ($object_id, 'getmaclist'));
1718 else
1719 showWarning ("You don't have permission to view learned MAC list");
1720 }
1721 catch (RTGatewayError $e)
1722 {
1723 showError ($e->getMessage());
1724 return;
1725 }
1726
1727 global $nextorder;
1728 echo "<table width='100%'><tr>";
1729 if (! empty ($linkStatus))
1730 {
1731 echo "<td valign='top' width='50%'>";
1732 startPortlet('Link status');
1733 echo "<table width='80%' class='widetable' cellspacing=0 cellpadding='5px' align='center'><tr><th>Port<th><th>Link status<th>Link info</tr>";
1734 $order = 'even';
1735 foreach ($linkStatus as $pn => $link)
1736 {
1737 switch ($link['status'])
1738 {
1739 case 'up':
1740 $img_filename = 'link-up.png';
1741 break;
1742 case 'down':
1743 $img_filename = 'link-down.png';
1744 break;
1745 case 'disabled':
1746 $img_filename = 'link-disabled.png';
1747 break;
1748 default:
1749 $img_filename = '1x1t.gif';
1750 }
1751
1752 echo "<tr class='row_$order'>";
1753 $order = $nextorder[$order];
1754 echo '<td>' . $pn;
1755 echo '<td>' . '<img width=16 height=16 src="?module=chrome&uri=pix/' . $img_filename . '">';
1756 echo '<td>' . $link['status'];
1757 $info = '';
1758 if (isset ($link['speed']))
1759 $info .= $link['speed'];
1760 if (isset ($link['duplex']))
1761 {
1762 if (! empty ($info))
1763 $info .= ', ';
1764 $info .= $link['duplex'];
1765 }
1766 echo '<td>' . $info;
1767 echo '</tr>';
1768 }
1769 echo "</table></td>";
1770 finishPortlet();
1771 }
1772
1773 if (! empty ($macList))
1774 {
1775 echo "<td valign='top' width='50%'>";
1776 $rendered_macs = '';
1777 $mac_count = 0;
1778 $rendered_macs .= "<table width='80%' class='widetable' cellspacing=0 cellpadding='5px' align='center'><tr><th>MAC<th>Vlan<th>Port</tr>";
1779 $order = 'even';
1780 foreach ($macList as $pn => $list)
1781 {
1782 $order = $nextorder[$order];
1783 foreach ($list as $item)
1784 {
1785 ++$mac_count;
1786 $rendered_macs .= "<tr class='row_$order'>";
1787 $rendered_macs .= '<td style="font-family: monospace">' . $item['mac'];
1788 $rendered_macs .= '<td>' . $item['vid'];
1789 $rendered_macs .= '<td>' . $pn;
1790 $rendered_macs .= '</tr>';
1791 }
1792 }
1793 $rendered_macs .= "</table></td>";
1794
1795 startPortlet("Learned MACs ($mac_count)");
1796 echo $rendered_macs;
1797 finishPortlet();
1798 }
1799
1800 echo "</td></tr></table>";
1801 }
1802
1803 /*
1804 The following conditions must be met:
1805 1. We can mount onto free atoms only. This means: if any record for an atom
1806 already exists in RackSpace, it can't be used for mounting.
1807 2. We can't unmount from 'W' atoms. Operator should review appropriate comments
1808 and either delete them before unmounting or refuse to unmount the object.
1809 */
1810 function renderRackSpaceForObject ($object_id)
1811 {
1812 // Always process occupied racks plus racks chosen by user. First get racks with
1813 // already allocated rackspace...
1814 $workingRacksData = getResidentRacksData ($object_id);
1815 // ...and then add those chosen by user (if any).
1816 if (isset($_REQUEST['rackmulti']))
1817 foreach ($_REQUEST['rackmulti'] as $cand_id)
1818 if (!isset ($workingRacksData[$cand_id]))
1819 {
1820 $rackData = spotEntity ('rack', $cand_id);
1821 amplifyCell ($rackData);
1822 $workingRacksData[$cand_id] = $rackData;
1823 }
1824
1825 // Get a list of all of this object's parents,
1826 // then trim the list to only include parents which are racks
1827 $objectParents = getEntityRelatives('parents', 'object', $object_id);
1828 $parentRacks = array();
1829 foreach ($objectParents as $parentData)
1830 if ($parentData['entity_type'] == 'rack')
1831 $parentRacks[] = $parentData['entity_id'];
1832
1833 // Main layout starts.
1834 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0><tr>";
1835
1836 // Left portlet with rack list.
1837 echo "<td class=pcleft height='1%'>";
1838 startPortlet ('Racks');
1839 $allRacksData = listCells ('rack');
1840
1841 // filter rack list to match only racks having common tags with the object (reducing $allRacksData)
1842 if (! isset ($_REQUEST['show_all_racks']) and getConfigVar ('FILTER_RACKLIST_BY_TAGS') == 'yes')
1843 {
1844 $matching_racks = array();
1845 $object = spotEntity ('object', $object_id);
1846 $matched_tags = array();
1847 foreach ($allRacksData as $rack)
1848 foreach ($object['etags'] as $tag)
1849 if (tagOnChain ($tag, $rack['etags']) or tagOnChain ($tag, $rack['itags']))
1850 {
1851 $matching_racks[$rack['id']] = $rack;
1852 $matched_tags[$tag['id']] = $tag;
1853 break;
1854 }
1855 // add current object's racks even if they dont match filter
1856 foreach ($workingRacksData as $rack_id => $rack)
1857 if (! isset ($matching_racks[$rack_id]))
1858 $matching_racks[$rack_id] = $rack;
1859 // if matching racks found, and rack list is reduced, show 'show all' link
1860 if (count ($matching_racks) and count ($matching_racks) != count ($allRacksData))
1861 {
1862 $filter_text = '';
1863 foreach ($matched_tags as $tag)
1864 $filter_text .= (empty ($filter_text) ? '' : ' or ') . '{' . $tag['tag'] . '}';
1865 $href_show_all = trim($_SERVER['REQUEST_URI'], '&');
1866 $href_show_all .= htmlspecialchars('&show_all_racks=1');
1867 echo "(filtered by <span class='filter-text'>$filter_text</span>, <a href='$href_show_all'>show all</a>)<p>";
1868 $allRacksData = $matching_racks;
1869 }
1870 }
1871
1872 if (count ($allRacksData) <= getConfigVar ('RACK_PRESELECT_THRESHOLD'))
1873 foreach ($allRacksData as $rack)
1874 if (!array_key_exists ($rack['id'], $workingRacksData))
1875 {
1876 amplifyCell ($rack);
1877 $workingRacksData[$rack['id']] = $rack;
1878 }
1879 foreach (array_keys ($workingRacksData) as $rackId)
1880 applyObjectMountMask ($workingRacksData[$rackId], $object_id);
1881 printOpFormIntro ('updateObjectAllocation');
1882 renderRackMultiSelect ('rackmulti[]', $allRacksData, array_keys ($workingRacksData));
1883 echo "<br><br>";
1884 finishPortlet();
1885 echo "</td>";
1886
1887 // Middle portlet with comment and submit.
1888 echo "<td class=pcleft>";
1889 startPortlet ('Comment (for Rackspace History)');
1890 echo "<textarea name=comment rows=10 cols=40></textarea><br>\n";
1891 echo "<input type=submit value='Save' name=got_atoms>\n";
1892 echo "<br><br>";
1893 finishPortlet();
1894 echo "</td>";
1895
1896 // Right portlet with rendered racks. If this form submit is not final, we have to
1897 // reflect the former state of the grid in current form.
1898 echo "<td class=pcright rowspan=2 height='1%'>";
1899 startPortlet ('Working copy');
1900 addJS ('js/racktables.js');
1901 echo '<table border=0 cellspacing=10 align=center><tr>';
1902 foreach ($workingRacksData as $rack_id => $rackData)
1903 {
1904 // Order is important here: only original allocation is highlighted.
1905 highlightObject ($rackData, $object_id);
1906 markupAtomGrid ($rackData, 'T');
1907 // If we have a form processed, discard user input and show new database
1908 // contents.
1909 if (isset ($_REQUEST['rackmulti'][0])) // is an update
1910 mergeGridFormToRack ($rackData);
1911 echo "<td valign=top>";
1912 echo "<center>\n<h2>${rackData['name']}</h2>\n";
1913 echo "<table class=rack border=0 cellspacing=0 cellpadding=1>\n";
1914 echo "<tr><th width='10%'>&nbsp;</th>";
1915 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '0', ${rackData['height']})\">Front</a></th>";
1916 echo "<th width='50%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '1', ${rackData['height']})\">Interior</a></th>";
1917 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '2', ${rackData['height']})\">Back</a></th></tr>\n";
1918 renderAtomGrid ($rackData);
1919 echo "<tr><th width='10%'>&nbsp;</th>";
1920 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '0', ${rackData['height']})\">Front</a></th>";
1921 echo "<th width='50%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '1', ${rackData['height']})\">Interior</a></th>";
1922 echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '2', ${rackData['height']})\">Back</a></th></tr>\n";
1923 echo "</table>\n<br>\n";
1924 // Determine zero-u checkbox status.
1925 // If form has been submitted, use form data, otherwise use DB data.
1926 if (isset($_REQUEST['op']))
1927 $checked = isset($_REQUEST['zerou_'.$rack_id]) ? 'checked' : '';
1928 else
1929 $checked = in_array($rack_id, $parentRacks) ? 'checked' : '';
1930 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";
1931 echo "<input type='button' onclick='uncheckAll();' value='Uncheck all'>\n";
1932 echo '</center></td>';
1933 }
1934 echo "</tr></table>";
1935 finishPortlet();
1936 echo "</td>\n";
1937
1938 echo "</form>\n";
1939 echo "</tr></table>\n";
1940 }
1941
1942 function renderMolecule ($mdata, $object_id)
1943 {
1944 // sort data out
1945 $rackpack = array();
1946 global $loclist;
1947 foreach ($mdata as $rua)
1948 {
1949 $rack_id = $rua['rack_id'];
1950 $unit_no = $rua['unit_no'];
1951 $atom = $rua['atom'];
1952 if (!isset ($rackpack[$rack_id]))
1953 {
1954 $rackData = spotEntity ('rack', $rack_id);
1955 amplifyCell ($rackData);
1956 for ($i = $rackData['height']; $i > 0; $i--)
1957 for ($locidx = 0; $locidx < 3; $locidx++)
1958 $rackData[$i][$locidx]['state'] = 'F';
1959 $rackpack[$rack_id] = $rackData;
1960 }
1961 $rackpack[$rack_id][$unit_no][$loclist[$atom]]['state'] = 'T';
1962 $rackpack[$rack_id][$unit_no][$loclist[$atom]]['object_id'] = $object_id;
1963 }
1964 // now we have some racks to render
1965 foreach ($rackpack as $rackData)
1966 {
1967 markAllSpans ($rackData);
1968 echo "<table class=molecule cellspacing=0>\n";
1969 echo "<caption>${rackData['name']}</caption>\n";
1970 echo "<tr><th width='10%'>&nbsp;</th><th width='20%'>Front</th><th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n";
1971 for ($i = $rackData['height']; $i > 0; $i--)
1972 {
1973 echo "<tr><th>" . inverseRackUnit ($i, $rackData) . "</th>";
1974 for ($locidx = 0; $locidx < 3; $locidx++)
1975 {
1976 $state = $rackData[$i][$locidx]['state'];
1977 echo "<td class='atom state_${state}'>&nbsp;</td>\n";
1978 }
1979 echo "</tr>\n";
1980 }
1981 echo "</table>\n";
1982 }
1983 }
1984
1985 function renderDepot ()
1986 {
1987 global $pageno, $nextorder;
1988 $cellfilter = getCellFilter();
1989 $objects = filterCellList (listCells ('object'), $cellfilter['expression']);
1990
1991 echo "<table border=0 class=objectview>\n";
1992 echo "<tr><td class=pcleft>";
1993
1994 if (! renderEmptyResults ($cellfilter, 'objects', count($objects)))
1995 {
1996 if (count($objects) > 0)
1997 {
1998 startPortlet ('Objects (' . count ($objects) . ')');
1999 echo '<br><br><table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
2000 echo '<tr><th>Common name</th><th>Visible label</th><th>Asset tag</th><th>Row/Rack or Container</th></tr>';
2001 $order = 'odd';
2002 # gather IDs of all objects and fetch rackspace info in one pass
2003 $idlist = array();
2004 foreach ($objects as $obj)
2005 $idlist[] = $obj['id'];
2006 $mountinfo = getMountInfo ($idlist);
2007 foreach ($objects as $obj)
2008 {
2009 echo "<tr class='row_${order} tdleft' valign=top><td>" . mkA ("<strong>${obj['dname']}</strong>", 'object', $obj['id']);
2010 if (count ($obj['etags']))
2011 echo '<br><small>' . serializeTags ($obj['etags'], makeHref(array('page'=>$pageno, 'tab'=>'default')) . '&') . '</small>';
2012 echo "</td><td>${obj['label']}</td>";
2013 echo "<td>${obj['asset_no']}</td>";
2014 $places = array();
2015 if ($obj['container_id'])
2016 $places[] = mkA ($obj['container_dname'], 'object', $obj['container_id']);
2017 elseif (! array_key_exists ($obj['id'], $mountinfo))
2018 $places[] = 'Unmounted';
2019 else
2020 foreach ($mountinfo[$obj['id']] as $mi)
2021 $places[] = mkA ($mi['row_name'], 'row', $mi['row_id']) . '/' . mkA ($mi['rack_name'], 'rack', $mi['rack_id']);
2022 echo "<td>" . implode (', ', $places) . '</td>';
2023 echo '</tr>';
2024 $order = $nextorder[$order];
2025 }
2026 echo '</table>';
2027 finishPortlet();
2028 }
2029 else
2030 echo '<h2>No objects exist</h2>';
2031 }
2032
2033 echo "</td><td class=pcright width='25%'>";
2034
2035 renderCellFilterPortlet ($cellfilter, 'object', $objects);
2036 echo "</td></tr></table>\n";
2037 }
2038
2039 // This function returns TRUE if the result set is too big to be rendered, and no filter is set.
2040 // In this case it renders the describing message instead.
2041 function renderEmptyResults($cellfilter, $entities_name, $count = NULL)
2042 {
2043 if (!$cellfilter['is_empty'])
2044 return FALSE;
2045 if (isset ($_REQUEST['show_all_objects']))
2046 return FALSE;
2047 $max = intval(getConfigVar('MAX_UNFILTERED_ENTITIES'));
2048 if (0 == $max || $count <= $max)
2049 return FALSE;
2050
2051 $href_show_all = trim($_SERVER['REQUEST_URI'], '&');
2052 $href_show_all .= htmlspecialchars('&show_all_objects=1');
2053 $suffix = isset ($count) ? " ($count)" : '';
2054 echo <<<END
2055 <p>Please set a filter to display the corresponging $entities_name.
2056 <br><a href="$href_show_all">Show all $entities_name$suffix</a>
2057 END;
2058 return TRUE;
2059 }
2060
2061 // History viewer for history-enabled simple dictionaries.
2062 function renderObjectHistory ($object_id)
2063 {
2064 $order = 'odd';
2065 global $nextorder;
2066 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
2067 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>';
2068 $result = usePreparedSelectBlade
2069 (
2070 'SELECT ctime, user_name, name, label, asset_no, has_problems, comment FROM ObjectHistory WHERE id=? ORDER BY ctime',
2071 array ($object_id)
2072 );
2073 while ($row = $result->fetch (PDO::FETCH_NUM))
2074 {
2075 echo "<tr class=row_${order}><td>${row[0]}</td>";
2076 for ($i = 1; $i <= 6; $i++)
2077 echo "<td>" . $row[$i] . "</td>";
2078 echo "</tr>\n";
2079 $order = $nextorder[$order];
2080 }
2081 echo "</table><br>\n";
2082 }
2083
2084 function renderRackspaceHistory ()
2085 {
2086 global $nextorder, $pageno, $tabno;
2087 $order = 'odd';
2088 $history = getRackspaceHistory();
2089 // Show the last operation by default.
2090 if (isset ($_REQUEST['op_id']))
2091 $op_id = $_REQUEST['op_id'];
2092 elseif (isset ($history[0]['mo_id']))
2093 $op_id = $history[0]['mo_id'];
2094 else $op_id = NULL;
2095
2096 $omid = NULL;
2097 $nmid = NULL;
2098 $object_id = 1;
2099 if ($op_id)
2100 list ($omid, $nmid) = getOperationMolecules ($op_id);
2101
2102 // Main layout starts.
2103 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
2104
2105 // Left top portlet with old allocation.
2106 echo "<tr><td class=pcleft>";
2107 startPortlet ('Old allocation');
2108 if ($omid)
2109 {
2110 $oldMolecule = getMolecule ($omid);
2111 renderMolecule ($oldMolecule, $object_id);
2112 }
2113 else
2114 echo "nothing";
2115 finishPortlet();
2116
2117 echo '</td><td class=pcright>';
2118
2119 // Right top portlet with new allocation
2120 startPortlet ('New allocation');
2121 if ($nmid)
2122 {
2123 $newMolecule = getMolecule ($nmid);
2124 renderMolecule ($newMolecule, $object_id);
2125 }
2126 else
2127 echo "nothing";
2128 finishPortlet();
2129
2130 echo '</td></tr><tr><td colspan=2>';
2131
2132 // Bottom portlet with list
2133
2134 startPortlet ('Rackspace allocation history');
2135 echo "<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>\n";
2136 echo "<tr><th>timestamp</th><th>author</th><th>object</th><th>comment</th></tr>\n";
2137 foreach ($history as $row)
2138 {
2139 if ($row['mo_id'] == $op_id)
2140 $class = 'hl';
2141 else
2142 $class = "row_${order}";
2143 echo "<tr class=${class}><td><a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'op_id'=>$row['mo_id']))."'>${row['ctime']}</a></td>";
2144 echo "<td>${row['user_name']}</td><td>";
2145 renderCell (spotEntity ('object', $row['ro_id']));
2146 echo '</td><td>' . niftyString ($row['comment'], 0) . '</td></tr>';
2147 $order = $nextorder[$order];
2148 }
2149 echo "</table>\n";
2150 finishPortlet();
2151
2152 echo '</td></tr></table>';
2153 }
2154
2155 function renderIPSpaceRecords ($tree, $baseurl, $target = 0, $level = 1)
2156 {
2157 $self = __FUNCTION__;
2158 $knight = (getConfigVar ('IPV4_ENABLE_KNIGHT') == 'yes');
2159
2160 // scroll page to the highlighted item
2161 if ($target && isset ($_REQUEST['hl_net']))
2162 addAutoScrollScript ("net-$target");
2163
2164 foreach ($tree as $item)
2165 {
2166 if ($display_routers = (getConfigVar ('IPV4_TREE_RTR_AS_CELL') != 'none'))
2167 loadIPAddrList ($item); // necessary to compute router list and address counter
2168
2169 if (isset ($item['id']))
2170 {
2171 $decor = array ('indent' => $level);
2172 if ($item['symbol'] == 'node-collapsed')
2173 $decor['symbolurl'] = "${baseurl}&eid=${item['id']}&hl_net=1";
2174 elseif ($item['symbol'] == 'node-expanded')
2175 $decor['symbolurl'] = $baseurl . ($item['parent_id'] ? "&eid=${item['parent_id']}&hl_net=1" : '');
2176 $tr_class = '';
2177 if ($target == $item['id'] && isset ($_REQUEST['hl_net']))
2178 {
2179 $decor['tdclass'] = ' highlight';
2180 $tr_class = $decor['tdclass'];
2181 }
2182 echo "<tr valign=top class=\"$tr_class\">";
2183 printIPNetInfoTDs ($item, $decor);
2184
2185 // capacity and usage
2186 echo "<td class=tdcenter>";
2187 echo getRenderedIPNetCapacity ($item);
2188 echo "</td>";
2189
2190 if ($display_routers)
2191 printRoutersTD (findRouters ($item['addrlist']), getConfigVar ('IPV4_TREE_RTR_AS_CELL'));
2192 echo "</tr>";
2193 if ($item['symbol'] == 'node-expanded' or $item['symbol'] == 'node-expanded-static')
2194 $self ($item['kids'], $baseurl, $target, $level + 1);
2195 }
2196 else
2197 {
2198 // non-allocated (spare) IP range
2199 echo "<tr valign=top>";
2200 printIPNetInfoTDs ($item, array ('indent' => $level, 'knight' => $knight, 'tdclass' => 'sparenetwork'));
2201
2202 // capacity and usage
2203 echo "<td class=tdcenter>";
2204 echo getRenderedIPNetCapacity ($item);
2205 echo "</td>";
2206 if ($display_routers)
2207 echo "<td></td>";
2208 echo "</tr>";
2209 }
2210 }
2211 }
2212
2213 function renderIPSpace()
2214 {
2215 global $pageno, $tabno;
2216 $realm = ($pageno == 'ipv4space' ? 'ipv4net' : 'ipv6net');
2217 $cellfilter = getCellFilter();
2218 $top = NULL;
2219 $netlist = array();
2220 foreach (listCells ($realm) as $net)
2221 {
2222 if (isset ($top) and IPNetContains ($top, $net))
2223 ;
2224 elseif (! count ($cellfilter['expression']) or judgeCell ($net, $cellfilter['expression']))
2225 $top = $net;
2226 else
2227 continue;
2228 $netlist[$net['id']] = $net;
2229 }
2230 $netcount = count ($netlist);
2231 // expand request can take either natural values or "ALL". Zero means no expanding.
2232 $eid = isset ($_REQUEST['eid']) ? $_REQUEST['eid'] : 0;
2233 $tree = prepareIPTree ($netlist, $eid);
2234
2235 echo "<table border=0 class=objectview>\n";
2236 echo "<tr><td class=pcleft>";
2237 if (! renderEmptyResults($cellfilter, 'IP nets', count($tree)))
2238 {
2239 startPortlet ("networks (${netcount})");
2240 echo '<h4>';
2241 $all = "<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'eid'=>'ALL')) .
2242 $cellfilter['urlextra'] . "'>expand&nbsp;all</a>";
2243 $none = "<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'eid'=>'NONE')) .
2244 $cellfilter['urlextra'] . "'>collapse&nbsp;all</a>";
2245 $auto = "<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno)) .
2246 $cellfilter['urlextra'] . "'>auto-collapse</a>";
2247
2248 if ($eid === 0)
2249 echo 'auto-collapsing at threshold ' . getConfigVar ('TREE_THRESHOLD') . " ($all / $none)";
2250 elseif ($eid === 'ALL')
2251 echo "expanding all ($auto / $none)";
2252 elseif ($eid === 'NONE')
2253 echo "collapsing all ($all / $auto)";
2254 else
2255 {
2256 $netinfo = spotEntity ($realm, $eid);
2257 echo "expanding ${netinfo['ip']}/${netinfo['mask']} ($auto / $all / $none)";
2258 }
2259 echo "</h4><table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
2260 echo "<tr><th>prefix</th><th>name/tags</th><th>capacity</th>";
2261 if (getConfigVar ('IPV4_TREE_RTR_AS_CELL') != 'none')
2262 echo "<th>routed by</th>";
2263 echo "</tr>\n";
2264 $baseurl = makeHref(array('page'=>$pageno, 'tab'=>$tabno)) . $cellfilter['urlextra'];
2265 renderIPSpaceRecords ($tree, $baseurl, $eid);
2266 echo "</table>\n";
2267 finishPortlet();
2268 }
2269
2270 echo '</td><td class=pcright>';
2271 renderCellFilterPortlet ($cellfilter, 'ipv4net', $netlist);
2272 echo "</td></tr></table>\n";
2273 }
2274
2275 function renderIPSpaceEditor()
2276 {
2277 global $pageno;
2278 $realm = ($pageno == 'ipv4space' ? 'ipv4net' : 'ipv6net');
2279 $net_page = $realm; // 'ipv4net', 'ipv6net'
2280 $addrspaceList = listCells ($realm);
2281 startPortlet ('Manage existing (' . count ($addrspaceList) . ')');
2282 if (count ($addrspaceList))
2283 {
2284 echo "<table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
2285 echo "<tr><th>&nbsp;</th><th>prefix</th><th>name</th><th>capacity</th></tr>";
2286 foreach ($addrspaceList as $netinfo)
2287 {
2288 echo "<tr valign=top><td>";
2289 if (! isIPNetworkEmpty ($netinfo))
2290 printImageHREF ('nodestroy', 'There are ' . count ($netinfo['addrlist']) . ' allocations inside');
2291 else
2292 echo getOpLink (array ('op' => 'del', 'id' => $netinfo['id']), '', 'destroy', 'Delete this prefix');
2293 echo '</td><td class=tdleft>' . mkA ("${netinfo['ip']}/${netinfo['mask']}", $net_page, $netinfo['id']) . '</td>';
2294 echo '<td class=tdleft>' . niftyString ($netinfo['name']);
2295 if (count ($netinfo['etags']))
2296 echo '<br><small>' . serializeTags ($netinfo['etags']) . '</small>';
2297 echo '</td><td>';
2298 echo getRenderedIPNetCapacity ($netinfo);
2299 echo '</tr>';
2300 }
2301 echo "</table>";
2302 finishPortlet();
2303 }
2304 }
2305
2306 function renderIPNewNetForm ()
2307 {
2308 global $pageno;
2309 if ($pageno == 'ipv6space')
2310 {
2311 $realm = 'ipv6net';
2312 $regexp = '^[a-fA-F0-9:]*:[a-fA-F0-9:\.]*/\d{1,3}$';
2313 }
2314 else
2315 {
2316 $realm = 'ipv4net';
2317 $regexp = '^(\d{1,3}\.){3}\d{1,3}/\d{1,2}$';
2318 }
2319
2320 // IP prefix validator
2321 addJS ('js/live_validation.js');
2322 $regexp = addslashes ($regexp);
2323 addJS (<<<END
2324 $(document).ready(function () {
2325 $('form#add' input[name="range"]).attr('match', '$regexp');
2326 Validate.init();
2327 });
2328 END
2329 , TRUE);
2330
2331 startPortlet ('Add new');
2332 echo '<table border=0 cellpadding=10 align=center>';
2333 printOpFormIntro ('add');
2334 // tags column
2335 echo '<tr><td rowspan=5><h3>assign tags</h3>';
2336 renderNewEntityTags ($realm);
2337 echo '</td>';
2338 // inputs column
2339 $prefix_value = empty ($_REQUEST['set-prefix']) ? '' : $_REQUEST['set-prefix'];
2340 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>";
2341 echo '<tr><th class=tdright>VLAN</th><td class=tdleft>';
2342 echo getOptionTree ('vlan_ck', getAllVLANOptions(), array ('select_class' => 'vertical', 'tabindex' => 2)) . '</td></tr>';
2343 echo "<tr><th class=tdright>name</th><td class=tdleft><input type=text name='name' size='20' tabindex=3></td></tr>";
2344 echo '<tr><td class=tdright><input type=checkbox name="is_connected" tabindex=4></td><th class=tdleft>reserve subnet-router anycast address</th></tr>';
2345 echo "<tr><td colspan=2>";
2346 printImageHREF ('CREATE', 'Add a new network', TRUE, 5);
2347 echo '</td></tr>';
2348 echo "</form></table><br><br>\n";
2349 finishPortlet();
2350 }
2351
2352 function getRenderedIPNetBacktrace ($range)
2353 {
2354 if (getConfigVar ('EXT_IPV4_VIEW') != 'yes')
2355 return array();
2356
2357 $v = ($range['realm'] == 'ipv4net') ? 4 : 6;
2358 $space = "ipv${v}space"; // ipv4space, ipv6space
2359 $tag = "\$ip${v}netid_"; // $ip4netid_, $ip6netid_
2360
2361 $ret = array();
2362 // Build a backtrace from all parent networks.
2363 $clen = $range['mask'];
2364 $backtrace = array();
2365 $backtrace['&rarr;'] = $range;
2366 $key = '';
2367 while (NULL !== ($upperid = getIPAddressNetworkId ($range['ip_bin'], $clen)))
2368 {
2369 $upperinfo = spotEntity ($range['realm'], $upperid);
2370 $clen = $upperinfo['mask'];
2371 $key .= '&uarr;';
2372 $backtrace[$key] = $upperinfo;
2373 }
2374 foreach (array_reverse ($backtrace) as $arrow => $ainfo)
2375 {
2376 $link = '<a href="' . makeHref (array (
2377 'page' => $space,
2378 'tab' => 'default',
2379 'clear-cf' => '',
2380 'cfe' => '{' . $tag . $ainfo['id'] . '}',
2381 'hl_net' => 1,
2382 'eid' => $range['id'],
2383 )) . '" title="View IP tree with this net as root">' . $arrow . '</a>';
2384 $ret[] = array ($link, getOutputOf ('renderCell', $ainfo));
2385 }
2386 return $ret;
2387 }
2388
2389 function renderIPNetwork ($id)
2390 {
2391 global $pageno;
2392 $realm = $pageno; // 'ipv4net', 'ipv6net'
2393 $range = spotEntity ($realm, $id);
2394 loadIPAddrList ($range);
2395 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
2396 echo "<tr><td colspan=2 align=center><h1>${range['ip']}/${range['mask']}</h1><h2>";
2397 echo htmlspecialchars ($range['name'], ENT_QUOTES, 'UTF-8') . "</h2></td></tr>\n";
2398
2399 echo "<tr><td class=pcleft width='50%'>";
2400
2401 // render summary portlet
2402 $summary = array();
2403 $summary['%% used'] = getRenderedIPNetCapacity ($range);
2404 $summary = getRenderedIPNetBacktrace ($range) + $summary;
2405 if ($realm == 'ipv4net')
2406 {
2407 $summary[] = array ('Netmask:', ip4_format ($range['mask_bin']));
2408 $summary[] = array ('Netmask:', "0x" . strtoupper (implode ('', unpack ('H*', $range['mask_bin']))));
2409 $summary['Wildcard bits'] = ip4_format ( ~ $range['mask_bin']);
2410 }
2411
2412 $reuse_domain = considerConfiguredConstraint ($range, '8021Q_MULTILINK_LISTSRC');
2413 $domainclass = array();
2414 foreach (array_count_values (reduceSubarraysToColumn ($range['8021q'], 'domain_id')) as $domain_id => $vlan_count)
2415 $domainclass[$domain_id] = $vlan_count == 1 ? '' : ($reuse_domain ? '{trwarning}' : '{trerror}');
2416 foreach ($range['8021q'] as $item)
2417 $summary[] = array ($domainclass[$item['domain_id']] . 'VLAN:', formatVLANAsHyperlink (getVLANInfo ($item['domain_id'] . '-' . $item['vlan_id'])));
2418 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes' and count ($routers = findRouters ($range['addrlist'])))
2419 {
2420 $summary['Routed by'] = '';
2421 foreach ($routers as $rtr)
2422 $summary['Routed by'] .= getOutputOf ('renderRouterCell', $rtr['ip_bin'], $rtr['iface'], spotEntity ('object', $rtr['id']));
2423 }
2424 $summary['tags'] = '';
2425 renderEntitySummary ($range, 'summary', $summary);
2426
2427 if (strlen ($range['comment']))
2428 {
2429 startPortlet ('Comment');
2430 echo '<div class=commentblock>' . string_insert_hrefs (htmlspecialchars ($range['comment'], ENT_QUOTES, 'UTF-8')) . '</div>';
2431 finishPortlet ();
2432 }
2433
2434 renderFilesPortlet ($realm, $id);
2435 echo "</td>\n";
2436
2437 echo "<td class=pcright>";
2438 startPortlet ('details');
2439 renderIPNetworkAddresses ($range);
2440 finishPortlet();
2441 echo "</td></tr></table>\n";
2442 }
2443
2444 // Used solely by renderSeparator
2445 function renderEmptyIPv6 ($ip_bin, $hl_ip)
2446 {
2447 $class = 'tdleft';
2448 if ($ip_bin === $hl_ip)
2449 $class .= ' highlight';
2450 $fmt = ip6_format ($ip_bin);
2451 echo "<tr class='$class'><td><a class='ancor' name='ip-$fmt' href='" . makeHref (array ('page' => 'ipaddress', 'ip' => $fmt)) . "'>" . $fmt;
2452 $editable = permitted ('ipaddress', 'properties', 'editAddress')
2453 ? 'editable'
2454 : '';
2455 echo "</a></td><td><span class='rsvtext $editable id-$fmt op-upd-ip-name'></span></td>";
2456 echo "<td><span class='rsvtext $editable id-$fmt op-upd-ip-comment'></span></td><td>&nbsp;</td></tr>\n";
2457 }
2458
2459 // Renders empty table line to shrink empty IPv6 address ranges.
2460 // If the range consists of single address, renders the address instead of empty line.
2461 // Renders address $hl_ip inside the range.
2462 // Used solely by renderIPv6NetworkAddresses
2463 function renderSeparator ($first, $last, $hl_ip)
2464 {
2465 $self = __FUNCTION__;
2466 if (strcmp ($first, $last) > 0)
2467 return;
2468 if ($first == $last)
2469 renderEmptyIPv6 ($first, $hl_ip);
2470 elseif (isset ($hl_ip) && strcmp ($hl_ip, $first) >= 0 && strcmp ($hl_ip, $last) <= 0)
2471 { // $hl_ip is inside the range $first - $last
2472 $self ($first, ip_prev ($hl_ip), $hl_ip);
2473 renderEmptyIPv6 ($hl_ip, $hl_ip);
2474 $self (ip_next ($hl_ip), $last, $hl_ip);
2475 }
2476 else
2477 echo "<tr><td colspan=4 class=tdleft></td></tr>\n";
2478 }
2479
2480 // calculates page number which contains given $ip (used by renderIPv6NetworkAddresses)
2481 function getPageNumOfIPv6 ($list, $ip_bin, $maxperpage)
2482 {
2483 if (intval ($maxperpage) <= 0 || count ($list) <= $maxperpage)
2484 return 0;
2485 $keys = array_keys ($list);
2486 for ($i = 1; $i <= count ($keys); $i++)
2487 if (strcmp ($keys[$i-1], $ip_bin) >= 0)
2488 return intval ($i / $maxperpage);
2489 return intval (count ($list) / $maxperpage);
2490 }
2491
2492 function renderIPNetworkAddresses ($range)
2493 {
2494 switch (strlen ($range['ip_bin']))
2495 {
2496 case 4: return renderIPv4NetworkAddresses ($range);
2497 case 16: return renderIPv6NetworkAddresses ($range);
2498 default: throw new InvalidArgException ("range['ip_bin']", $range['ip_bin']);
2499 }
2500 }
2501
2502 function renderIPv4NetworkAddresses ($range)
2503 {
2504 global $pageno, $tabno, $aac2;
2505 $startip = ip4_bin2int ($range['ip_bin']);
2506 $endip = ip4_bin2int (ip_last ($range));
2507
2508 if (isset ($_REQUEST['hl_ip']))
2509 {
2510 $hl_ip = ip4_bin2int (ip4_parse ($_REQUEST['hl_ip']));
2511 addAutoScrollScript ('ip-' . $_REQUEST['hl_ip']); // scroll page to highlighted ip
2512 }
2513
2514 // pager
2515 $maxperpage = getConfigVar ('IPV4_ADDRS_PER_PAGE');
2516 $address_count = $endip - $startip + 1;
2517 $page = 0;
2518 $rendered_pager = '';
2519 if ($address_count > $maxperpage && $maxperpage > 0)
2520 {
2521 $page = isset ($_REQUEST['pg']) ? $_REQUEST['pg'] : (isset ($hl_ip) ? intval (($hl_ip - $startip) / $maxperpage) : 0);
2522 if ($numpages = ceil ($address_count / $maxperpage))
2523 {
2524 echo '<h3>' . ip4_format (ip4_int2bin ($startip)) . ' ~ ' . ip4_format (ip4_int2bin ($endip)) . '</h3>';
2525 for ($i = 0; $i < $numpages; $i++)
2526 if ($i == $page)
2527 $rendered_pager .= "<b>$i</b> ";
2528 else
2529 $rendered_pager .= "<a href='".makeHref (array ('page' => $pageno, 'tab' => $tabno, 'id' => $range['id'], 'pg' => $i)) . "'>$i</a> ";
2530 }
2531 $startip = $startip + $page * $maxperpage;
2532 $endip = min ($startip + $maxperpage - 1, $endip);
2533 }
2534
2535 echo $rendered_pager;
2536 echo "<table class='widetable' border=0 cellspacing=0 cellpadding=5 align='center' width='100%'>\n";
2537 echo "<tr><th>Address</th><th>Name</th><th>Comment</th><th>Allocation</th></tr>\n";
2538
2539 markupIPAddrList ($range['addrlist']);
2540 for ($ip = $startip; $ip <= $endip; $ip++)
2541 {
2542 $ip_bin = ip4_int2bin ($ip);
2543 $dottedquad = ip4_format ($ip_bin);
2544 $tr_class = (isset ($hl_ip) && $hl_ip == $ip ? 'highlight' : '');
2545 if (isset ($range['addrlist'][$ip_bin]))
2546 $addr = $range['addrlist'][$ip_bin];
2547 else
2548 {
2549 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>";
2550 $editable = permitted ('ipaddress', 'properties', 'editAddress')
2551 ? 'editable'
2552 : '';
2553 echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-name'></span></td>";
2554 echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-comment'></span></td><td></td></tr>\n";
2555 continue;
2556 }
2557 // render IP change history
2558 $title = '';
2559 $history_class = '';
2560 if (isset ($addr['last_log']))
2561 {
2562 $title = ' title="' . htmlspecialchars ($addr['last_log']['user'] . ', ' . formatAge ($addr['last_log']['time']) , ENT_QUOTES) . '"';
2563 $history_class = 'hover-history underline';
2564 }
2565 $tr_class .= ' ' . $addr['class'];
2566 echo "<tr class='tdleft $tr_class'>";
2567 echo "<td><a class='ancor $history_class' $title name='ip-$dottedquad' href='".makeHref(array('page'=>'ipaddress', 'ip'=>$addr['ip']))."'>${addr['ip']}</a></td>";
2568 $editable =
2569 (empty ($addr['allocs']) || !empty ($addr['name']) || !empty ($addr['comment']))
2570 && permitted ('ipaddress', 'properties', 'editAddress')
2571 ? 'editable'
2572 : '';
2573 echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-name'>${addr['name']}</span></td>";
2574 echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-comment'>${addr['comment']}</span></td>";
2575 echo "<td>";
2576 $delim = '';
2577 if ( $addr['reserved'] == 'yes')
2578 {
2579 echo "<strong>RESERVED</strong> ";
2580 $delim = '; ';
2581 }
2582 foreach ($addr['allocs'] as $ref)
2583 {
2584 echo $delim . $aac2[$ref['type']];
2585 echo "<a href='".makeHref(array('page'=>'object', 'object_id'=>$ref['object_id'], 'tab' => 'default', 'hl_ip'=>$addr['ip']))."'>";
2586 echo $ref['name'] . (!strlen ($ref['name']) ? '' : '@');
2587 echo "${ref['object_name']}</a>";
2588 $delim = '; ';
2589 }
2590 if ($delim != '')
2591 $delim = '<br>';
2592 foreach ($addr['vslist'] as $vs_id)
2593 {
2594 $vs = spotEntity ('ipv4vs', $vs_id);
2595 echo $delim . mkA ("${vs['name']}:${vs['vport']}/${vs['proto']}", 'ipv4vs', $vs['id']) . '&rarr;';
2596 $delim = '<br>';
2597 }
2598 foreach ($addr['rsplist'] as $rsp_id)
2599 {
2600 $rsp = spotEntity ('ipv4rspool', $rsp_id);
2601 echo "${delim}&rarr;" . mkA ($rsp['name'], 'ipv4rspool', $rsp['id']);
2602 $delim = '<br>';
2603 }
2604 echo "</td></tr>\n";
2605 }
2606 // end of iteration
2607 if (permitted (NULL, NULL, 'set_reserve_comment'))
2608 addJS ('js/inplace-edit.js');
2609
2610 echo "</table>";
2611 if (! empty ($rendered_pager))
2612 echo '<p>' . $rendered_pager . '</p>';
2613 }
2614
2615 function renderIPv6NetworkAddresses ($netinfo)
2616 {
2617 global $pageno, $tabno, $aac2;
2618 echo "<table class='widetable' border=0 cellspacing=0 cellpadding=5 align='center' width='100%'>\n";
2619 echo "<tr><th>Address</th><th>Name</th><th>Comment</th><th>Allocation</th></tr>\n";
2620
2621 $hl_ip = NULL;
2622 if (isset ($_REQUEST['hl_ip']))
2623 {
2624 $hl_ip = ip6_parse ($_REQUEST['hl_ip']);
2625 addAutoScrollScript ('ip-' . ip6_format ($hl_ip));
2626 }
2627
2628 $addresses = $netinfo['addrlist'];
2629 ksort ($addresses);
2630 markupIPAddrList ($addresses);
2631
2632 // pager
2633 $maxperpage = getConfigVar ('IPV4_ADDRS_PER_PAGE');
2634 if (count ($addresses) > $maxperpage && $maxperpage > 0)
2635 {
2636 $page = isset ($_REQUEST['pg']) ? $_REQUEST['pg'] : (isset ($hl_ip) ? getPageNumOfIPv6 ($addresses, $hl_ip, $maxperpage) : 0);
2637 $numpages = ceil (count ($addresses) / $maxperpage);
2638 echo "<center><h3>$numpages pages:</h3>";
2639 for ($i=0; $i<$numpages; $i++)
2640 {
2641 if ($i == $page)
2642 echo "<b>$i</b> ";
2643 else
2644 echo "<a href='" . makeHref (array ('page' => $pageno, 'tab' => $tabno, 'id' => $netinfo['id'], 'pg' => $i)) . "'>$i</a> ";
2645 }
2646 echo "</center>";
2647 }
2648
2649 $i = 0;
2650 $interruped = FALSE;
2651 $prev_ip = ip_prev ($netinfo['ip_bin']);
2652 foreach ($addresses as $ip_bin => $addr)
2653 {
2654 if (isset ($page))
2655 {
2656 ++$i;
2657 if ($i <= $maxperpage * $page)
2658 continue;
2659 elseif ($i > $maxperpage * ($page + 1))
2660 {
2661 $interruped = TRUE;
2662 break;
2663 }
2664 }
2665
2666 if ($ip_bin != ip_next ($prev_ip))
2667 renderSeparator (ip_next ($prev_ip), ip_prev ($ip_bin), $hl_ip);
2668 $prev_ip = $ip_bin;
2669
2670 // render IP change history
2671 $title = '';
2672 $history_class = '';
2673 if (isset ($addr['last_log']))
2674 {
2675 $title = ' title="' . htmlspecialchars ($addr['last_log']['user'] . ', ' . formatAge ($addr['last_log']['time']) , ENT_QUOTES) . '"';
2676 $history_class = 'hover-history underline';
2677 }
2678
2679 $tr_class = $addr['class'] . ' tdleft' . ($hl_ip === $ip_bin ? ' highlight' : '');
2680 echo "<tr class='$tr_class'>";
2681 echo "<td><a class='ancor $history_class' $title name='ip-${addr['ip']}' href='" . makeHref (array ('page' => 'ipaddress', 'ip' => $addr['ip'])) . "'>${addr['ip']}</a></td>";
2682 $editable =
2683 (empty ($addr['allocs']) || !empty ($addr['name'])
2684 && permitted ('ipaddress', 'properties', 'editAddress')
2685 ? 'editable'
2686 : '');
2687 echo "<td><span class='rsvtext $editable id-${addr['ip']} op-upd-ip-name'>${addr['name']}</span></td>";
2688 echo "<td><span class='rsvtext $editable id-${addr['ip']} op-upd-ip-comment'>${addr['comment']}</span></td><td>";
2689 $delim = '';
2690 if ( $addr['reserved'] == 'yes')
2691 {
2692 echo "<strong>RESERVED</strong> ";
2693 $delim = '; ';
2694 }
2695 foreach ($addr['allocs'] as $ref)
2696 {
2697 echo $delim . $aac2[$ref['type']];
2698 echo "<a href='".makeHref(array('page'=>'object', 'object_id'=>$ref['object_id'], 'tab' => 'default', 'hl_ip'=>$addr['ip']))."'>";
2699 echo $ref['name'] . (!strlen ($ref['name']) ? '' : '@');
2700 echo "${ref['object_name']}</a>";
2701 $delim = '; ';
2702 }
2703 if ($delim != '')
2704 $delim = '<br>';
2705 foreach ($addr['vslist'] as $vs_id)
2706 {
2707 $vs = spotEntity ('ipv4vs', $vs_id);
2708 echo $delim . mkA ("${vs['name']}:${vs['vport']}/${vs['proto']}", 'ipv4vs', $vs['id']) . '&rarr;';
2709 $delim = '<br>';
2710 }
2711 foreach ($addr['rsplist'] as $rsp_id)
2712 {
2713 $rsp = spotEntity ('ipv4rspool', $rsp_id);
2714 echo "${delim}&rarr;" . mkA ($rsp['name'], 'ipv4rspool', $rsp['id']);
2715 $delim = '<br>';
2716 }
2717 echo "</td></tr>\n";
2718 }
2719 if (! $interruped)
2720 renderSeparator (ip_next ($prev_ip), ip_last ($netinfo), $hl_ip);
2721 if (isset ($page))
2722 { // bottom pager
2723 echo "<tr><td colspan=3>";
2724 if ($page > 0)
2725 echo "<a href='" . makeHref (array ('page' => $pageno, 'tab' => $tabno, 'id' => $netinfo['id'], 'pg' => $page - 1)) . "'><< prev</a> ";
2726 if ($page < $numpages - 1)
2727 echo "<a href='" . makeHref (array ('page' => $pageno, 'tab' => $tabno, 'id' => $netinfo['id'], 'pg' => $page + 1)) . "'>next >></a> ";
2728 echo "</td></tr>";
2729 }
2730 echo "</table>";
2731 if (permitted (NULL, NULL, 'set_reserve_comment'))
2732 addJS ('js/inplace-edit.js');
2733 }
2734
2735 function renderIPNetworkProperties ($id)
2736 {
2737 global $pageno;
2738 $netdata = spotEntity ($pageno, $id);
2739 echo "<center><h1>${netdata['ip']}/${netdata['mask']}</h1></center>\n";
2740 echo "<table border=0 cellpadding=10 cellpadding=1 align='center'>\n";
2741 printOpFormIntro ('editRange');
2742 echo '<tr><td class=tdright><label for=nameinput>Name:</label></td>';
2743 echo "<td class=tdleft><input type=text name=name id=nameinput size=80 maxlength=255 value='";
2744 echo htmlspecialchars ($netdata['name'], ENT_QUOTES, 'UTF-8') . "'></tr>";
2745 echo '<tr><td class=tdright><label for=commentinput>Comment:</label></td>';
2746 echo "<td class=tdleft><textarea name=comment id=commentinput cols=80 rows=25>\n";
2747 echo htmlspecialchars ($netdata['comment'], ENT_QUOTES, 'UTF-8') . "</textarea></tr>";
2748 echo "<tr><td colspan=2 class=tdcenter>";
2749 printImageHREF ('SAVE', 'Save changes', TRUE);
2750 echo "</td></form></tr></table>\n";
2751
2752 echo '<center>';
2753 if (! isIPNetworkEmpty ($netdata))
2754 echo getOpLink (NULL, 'delete this prefix', 'nodestroy', 'There are ' . count ($netdata['addrlist']) . ' allocations inside');
2755 else
2756 echo getOpLink (array('op'=>'del','id'=>$id), 'delete this prefix', 'destroy');
2757 echo '</center>';
2758 }
2759
2760 function renderIPAddress ($ip_bin)
2761 {
2762 global $aat, $nextorder;
2763 $address = getIPAddress ($ip_bin);
2764 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
2765 echo "<tr><td colspan=2 align=center><h1>${address['ip']}</h1></td></tr>\n";
2766
2767 echo "<tr><td class=pcleft>";
2768
2769 $summary = array();
2770 if (strlen ($address['name']))
2771 $summary['Name'] = $address['name'];
2772 if (strlen ($address['comment']))
2773 $summary['Comment'] = $address['comment'];
2774 $summary['Reserved'] = $address['reserved'];
2775 $summary['Allocations'] = count ($address['allocs']);
2776 if (isset ($address['outpf']))
2777 $summary['Originated NAT connections'] = count ($address['outpf']);
2778 if (isset ($address['inpf']))
2779 $summary['Arriving NAT connections'] = count ($address['inpf']);
2780 renderEntitySummary ($address, 'summary', $summary);
2781
2782 // render SLB portlet