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