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