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