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