bdf263e2e659586cc356764774c460f5e50ab016
4 * This file contains frontend functions for RackTables.
8 // Interface function's special.
9 $nextorder['odd'] = 'even';
10 $nextorder['even'] = 'odd';
12 // address allocation type
15 'regular' => 'Connected',
16 'virtual' => 'Loopback',
20 // address allocation code, IPv4 addresses and objects view
24 'virtual' => '<strong>L</strong>',
25 'shared' => '<strong>S</strong>',
26 'router' => '<strong>R</strong>',
28 // address allocation code, IPv4 networks view
32 'virtual' => '<strong>L:</strong>',
33 'router' => '<strong>R:</strong>',
37 function renderIndex ()
41 <table border
=0 cellpadding
=0 cellspacing
=0 width
='100%'>
44 <div style
='text-align: center; margin: 10px; '>
45 <table width
='100%' cellspacing
=0 cellpadding
=30 class=mainmenu border
=0>
48 <h1
><a href
='<?php echo $root; ?>?page=rackspace'>Rackspace
<br
>
49 <?php
printImageHREF ('rackspace'); ?
></a
></h1
>
52 <h1
><a href
='<?php echo $root; ?>?page=objects'>Objects
<br
>
53 <?php
printImageHREF ('objects'); ?
></a
></h1
>
56 <h1
><a href
='<?php echo $root; ?>?page=ipv4space'>IPv4 space
<br
>
57 <?php
printImageHREF ('ipv4space'); ?
></a
></h1
>
61 <table width
='100%' cellspacing
=0 cellpadding
=30 class=mainmenu border
=0>
64 <h1
><a href
='<?php echo $root; ?>?page=config'>Configuration
<br
>
65 <?php
printImageHREF ('config'); ?
></a
></h1
>
68 <h1
><a href
='<?php echo $root; ?>?page=reports'>Reports
<br
>
69 <?php
printImageHREF ('reports'); ?
></a
></h1
>
72 <h1
><a href
='<?php echo $root; ?>?page=ipv4slb'>IPv4 SLB
<br
>
73 <?php
printImageHREF ('ipv4slb'); ?
></a
></h1
>
84 function renderRackspace ()
86 $tagfilter = getTagFilter();
87 $tagfilter_str = getTagFilterStr ($tagfilter);
88 echo "<table class=objview border=0 width='100%'><tr><td class=pcleft>";
89 renderTagFilterPortlet ($tagfilter, 'rack');
90 echo '</td><td class=pcright>';
91 echo '<table border=0 cellpadding=10 cellpadding=1>';
92 // generate thumb gallery
93 $rackrowList = getRackspace ($tagfilter);
94 global $root, $nextorder;
95 $rackwidth = getRackImageWidth();
97 foreach ($rackrowList as $rackrow)
99 echo "<tr class=row_${order}><th class=tdleft>";
100 echo "<a href='${root}?page=row&row_id=${rackrow['row_id']}${tagfilter_str}'>";
101 echo "${rackrow['row_name']}</a></th>";
102 $rackList = getRacksForRow ($rackrow['row_id'], $tagfilter);
103 echo "<td><table border=0 cellspacing=5><tr>";
104 foreach ($rackList as $rack)
106 echo "<td align=center><a href='${root}?page=rack&rack_id=${rack['id']}'>";
107 echo "<img border=0 width=${rackwidth} height=";
108 echo getRackImageHeight ($rack['height']);
109 echo " title='${rack['height']} units'";
110 echo "src='render_image.php?img=minirack&rack_id=${rack['id']}'>";
111 echo "<br>${rack['name']}</a></td>";
113 echo "</tr></table></tr>\n";
114 $order = $nextorder[$order];
117 echo "</td></tr></table>\n";
120 function renderRow ($row_id = 0)
124 showError ('Invalid row_id', __FUNCTION__
);
127 if (($rowInfo = getRackRowInfo ($row_id)) == NULL)
129 showError ('getRackRowInfo() failed', __FUNCTION__
);
132 $tagfilter = getTagFilter();
133 $rackList = getRacksForRow ($row_id, $tagfilter);
134 // Main layout starts.
135 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
137 // Left portlet with row information.
138 echo "<tr><td class=pcleft>";
139 startPortlet ($rowInfo['name']);
140 echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
141 echo "<tr><th width='50%' class=tdright>Racks:</th><td class=tdleft>${rowInfo['count']}</td></tr>\n";
142 echo "<tr><th width='50%' class=tdright>Units:</th><td class=tdleft>${rowInfo['sum']}</td></tr>\n";
143 echo "<tr><th width='50%' class=tdright>Utilization:</th><td class=tdleft>";
144 renderProgressBar (getRSUforRackRow ($rackList));
146 echo "</table><br>\n";
149 echo "</td><td class=pcright rowspan=2>";
151 global $root, $nextorder;
152 $rackwidth = getRackImageWidth() * getConfigVar ('ROW_SCALE');
154 startPortlet ('Racks');
155 echo "<table border=0 cellspacing=5 align='center'><tr>";
156 foreach ($rackList as $rack)
158 echo "<td align=center class=row_${order}><a href='${root}?page=rack&rack_id=${rack['id']}'>";
159 echo "<img border=0 width=${rackwidth} height=" . (getRackImageHeight ($rack['height']) * getConfigVar ('ROW_SCALE'));
160 echo " title='${rack['height']} units'";
161 echo "src='render_image.php?img=minirack&rack_id=${rack['id']}'>";
162 echo "<br>${rack['name']}</a></td>";
163 $order = $nextorder[$order];
165 echo "</tr></table>\n";
169 echo "<tr><td class=pcleft>";
170 renderTagFilterPortlet ($tagfilter, 'rack', 'row_id', $row_id);
171 echo "</td></tr></table>";
174 function showError ($info = '', $funcname = 'N/A')
177 echo "<div class=msg_error>An error has occured in [${funcname}]. ";
179 echo 'No additional information is available.';
181 echo "Additional information:<br><p>\n<pre>\n${info}\n</pre></p>";
182 echo "Go back or try starting from <a href='${root}'>index page</a>.<br></div>\n";
185 // This function renders rack as HTML table.
186 function renderRack ($rack_id = 0, $hl_obj_id = 0)
190 showError ('Invalid rack_id', __FUNCTION__
);
193 if (($rackData = getRackData ($rack_id)) == NULL)
195 showError ('getRackData() failed', __FUNCTION__
);
198 global $root, $pageno, $tabno;
199 markAllSpans ($rackData);
201 highlightObject ($rackData, $hl_obj_id);
202 markupObjectProblems ($rackData);
203 $prev_id = getPrevIDforRack ($rackData['row_id'], $rack_id);
204 $next_id = getNextIDforRack ($rackData['row_id'], $rack_id);
205 echo "<center><table border=0><tr valign=middle>";
206 echo "<td><h2><a href='${root}?page=row&row_id=${rackData['row_id']}'>${rackData['row_name']}</a> :</h2></td>";
207 // FIXME: use 'bypass'?
208 if ($prev_id != NULL)
210 echo "<td><a href='${root}?page=rack&rack_id=${prev_id}'>";
211 printImageHREF ('prev', 'previous rack');
214 echo "<td><h2><a href='${root}?page=rack&rack_id=${rackData['id']}'>${rackData['name']}</a></h2></td>";
215 if ($next_id != NULL)
217 echo "<td><a href='${root}?page=rack&rack_id=${next_id}'>";
218 printImageHREF ('next', 'next rack');
221 echo "</h2></td></tr></table>\n";
222 if ($rackData['left_is_front'] == 'yes')
223 $markup = array ('left' => 'Front', 'right' => 'Back');
225 $markup = array ('left' => 'Back', 'right' => 'Front');
226 echo "<table class=rack border=0 cellspacing=0 cellpadding=1>\n";
227 echo "<tr><th width='10%'> </th><th width='20%'>${markup['left']}</th>";
228 echo "<th width='50%'>Interior</th><th width='20%'>${markup['right']}</th></tr>\n";
229 for ($i = $rackData['height']; $i > 0; $i--)
231 echo '<tr><th>' . ($rackData['bottom_is_unit1'] == 'yes' ?
$i : $rackData['height'] - $i +
1) . '</th>';
232 for ($locidx = 0; $locidx < 3; $locidx++
)
234 if (isset ($rackData[$i][$locidx]['skipped']))
236 $state = $rackData[$i][$locidx]['state'];
237 echo "<td class=state_${state}";
238 if (isset ($rackData[$i][$locidx]['hl']))
239 echo $rackData[$i][$locidx]['hl'];
240 if (isset ($rackData[$i][$locidx]['colspan']))
241 echo ' colspan=' . $rackData[$i][$locidx]['colspan'];
242 if (isset ($rackData[$i][$locidx]['rowspan']))
243 echo ' rowspan=' . $rackData[$i][$locidx]['rowspan'];
248 $objectData = getObjectInfo ($rackData[$i][$locidx]['object_id']);
249 if (!empty ($objectData['asset_no']))
250 $prefix = "<div title='${objectData['asset_no']}";
252 $prefix = "<div title='no asset tag";
253 // Don't tell about label, if it matches common name.
254 if ($objectData['name'] != $objectData['label'] and !empty ($objectData['label']))
255 $suffix = ", visible label is \"${objectData['label']}\"'>";
258 echo $prefix . $suffix;
259 echo "<a href='${root}?page=object&object_id=${objectData['id']}'>${objectData['dname']}</a></div>";
262 echo '<div title="This rackspace does not exist"> </div>';
265 echo '<div title="Free rackspace"> </div>';
268 echo '<div title="Problematic rackspace, you CAN\'T mount here"> </div>';
271 echo '<div title="No data"> </div>';
278 echo "</table></center>\n";
281 function renderNewRackForm ($row_id)
283 global $pageno, $tabno;
285 $taglist = isset ($_REQUEST['taglist']) ?
$_REQUEST['taglist'] : array();
287 // Look for current submit.
288 if (isset ($_REQUEST['got_data']))
290 assertStringArg ('rack_name', __FUNCTION__
);
291 assertUIntArg ('rack_height1', __FUNCTION__
);
292 assertStringArg ('rack_comment', __FUNCTION__
, TRUE);
293 $name = $_REQUEST['rack_name'];
295 if (commitAddRack ($name, $_REQUEST['rack_height1'], $row_id, $_REQUEST['rack_comment'], $taglist) === TRUE)
296 $log[] = array ('code' => 'success', 'message' => "Added new rack '${name}'");
298 $log[] = array ('code' => 'error', 'message' => __FUNCTION__
. ': commitAddRack() failed');
300 elseif (isset ($_REQUEST['got_mdata']))
302 assertUIntArg ('rack_height2', __FUNCTION__
);
303 assertStringArg ('rack_names', __FUNCTION__
, TRUE);
304 // copy-and-paste from renderAddMultipleObjectsForm()
305 $names1 = explode ('\n', $_REQUEST['rack_names']);
307 foreach ($names1 as $line)
309 $parts = explode ('\r', $line);
311 if (empty ($parts[0]))
314 $names2[] = rtrim ($parts[0]);
316 foreach ($names2 as $cname)
317 if (commitAddRack ($cname, $_REQUEST['rack_height2'], $row_id, '', $taglist) === TRUE)
318 $log[] = array ('code' => 'success', 'message' => "Added new rack '${cname}'");
320 $log[] = array ('code' => 'error', 'message' => __FUNCTION__
. ': commitAddRack() failed');
324 echo "<table border=0 width='100%'><tr><td valign=top>";
325 // Render a form for the next.
326 startPortlet ('Add one');
328 echo "<input type=hidden name=page value=${pageno}>";
329 echo "<input type=hidden name=tab value=${tabno}>";
330 echo "<input type=hidden name=row_id value=${row_id}>";
331 echo '<table border=0 align=center>';
332 $defh = getConfigVar ('DEFAULT_RACK_HEIGHT');
335 echo "<tr><th class=tdright>Rack name (*):</th><td class=tdleft><input type=text name=rack_name tabindex=1></td></tr>\n";
336 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";
337 echo "<tr><th class=tdright>Comment:</th><td class=tdleft><input type=text name=rack_comment tabindex=3></td></tr>\n";
338 echo "<tr><td class=submit colspan=2><input type=submit name=got_data value='Add'></td></tr>\n";
343 echo '<td rowspan=2 valign=top>';
344 startPortlet ('Pre-assigned tags');
349 echo '<tr><td valign=top>';
350 startPortlet ('Add many');
351 echo '<table border=0 align=center>';
352 $defh = getConfigVar ('DEFAULT_RACK_HEIGHT');
355 echo "<tr><th class=tdright>Height in units (*):</th><td class=tdleft><input type=text name=rack_height2 value='${defh}'></td></tr>\n";
356 echo "<tr><th class=tdright>Rack names (*):</th><td class=tdleft><textarea name=rack_names cols=40 rows=25></textarea></td></tr>\n";
357 echo "<tr><td class=submit colspan=2><input type=submit name=got_mdata value='Add'></td></tr>\n";
358 echo '</form></table>';
364 function renderEditObjectForm ($object_id)
366 showMessageOrError();
368 global $pageno, $tabno, $root;
369 $object = getObjectInfo ($object_id);
372 showError ('getObjectInfo() failed', __FUNCTION__
);
375 echo '<table border=0 width=100%><tr>';
377 echo '<td class=pcleft>';
378 startPortlet ('Static attributes');
379 echo "<form method=post action='${root}process.php?page=${pageno}&tab=${tabno}&op=update'>";
380 echo "<input type=hidden name=object_id value=${object_id}>";
381 echo '<table border=0 align=center>';
382 echo "<tr><th class=tdright>Type:</th><td class=tdleft>";
383 printSelect (getObjectTypeList(), 'object_type_id', $object['objtype_id']);
386 echo "<tr><th class=tdright>Common name:</th><td class=tdleft><input type=text name=object_name value='${object['name']}'></td></tr>\n";
387 echo "<tr><th class=tdright>Visible label:</th><td class=tdleft><input type=text name=object_label value='${object['label']}'></td></tr>\n";
388 echo "<tr><th class=tdright>Asset tag:</th><td class=tdleft><input type=text name=object_asset_no value='${object['asset_no']}'></td></tr>\n";
389 echo "<tr><th class=tdright>Barcode:</th><td class=tdleft><input type=text name=object_barcode value='${object['barcode']}'></td></tr>\n";
390 echo "<tr><th class=tdright>Has problems:</th><td class=tdleft><input type=checkbox name=object_has_problems";
391 if ($object['has_problems'] == 'yes')
393 echo "></td></tr>\n";
394 echo "<tr><td colspan=2><b>Comment:</b><br><textarea name=object_comment rows=10 cols=80>${object['comment']}</textarea></td></tr>";
395 echo "<tr><th class=submit colspan=2>";
396 printImageHREF ('SAVE', 'Save changes', TRUE);
398 echo '</form></table><br>';
403 echo '<td class=pcright>';
404 startPortlet ('Optional attributes');
405 $values = getAttrValues ($object_id);
406 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable>\n";
407 echo "<tr><th> </th><th>Attribute</th><th>Value</th><th> </th></tr>\n";
408 echo "<form method=post action='${root}process.php?page=${pageno}&tab=${tabno}&op=updateStickers'>\n";
409 echo "<input type=hidden name=object_id value=${object_id}>\n";
410 echo '<input type=hidden name=num_attrs value=' . count($values) . ">\n";
413 foreach ($values as $record)
415 echo "<input type=hidden name=${i}_attr_id value=${record['id']}>";
417 if (!empty ($record['value']))
419 echo "<a href='${root}process.php?page=${pageno}&tab=${tabno}&op=clearSticker&object_id=${object_id}&attr_id=${record['id']}'>";
420 printImageHREF ('clear', 'Clear value');
426 echo "<td class=tdright>${record['name']}:</td><td class=tdleft>";
427 switch ($record['type'])
432 echo "<input type=text name=${i}_value value='${record['value']}'>";
435 $chapter = readChapter ($record['chapter_name']);
436 $chapter[0] = '-- NOT SET --';
437 printSelect ($chapter, "${i}_value", $record['key']);
443 echo "<tr><td colspan=3>";
444 printImageHREF ('SAVE', 'Save changes', TRUE);
453 echo '<td colspan=2>';
454 startPortlet ('history');
455 renderHistory ($pageno, $object_id);
459 echo '</tr></table>';
462 // This is a clone of renderEditObjectForm().
463 function renderEditRackForm ($rack_id)
466 if (isset ($_REQUEST['got_data']))
469 assertUIntArg ('rack_row_id', __FUNCTION__
);
470 assertUIntArg ('rack_height', __FUNCTION__
);
471 assertStringArg ('rack_name', __FUNCTION__
);
472 assertStringArg ('rack_comment', __FUNCTION__
, TRUE);
473 $row_id = $_REQUEST['rack_row_id'];
474 $height = $_REQUEST['rack_height'];
475 $name = $_REQUEST['rack_name'];
476 $comment = $_REQUEST['rack_comment'];
478 if (commitUpdateRack ($rack_id, $name, $height, $row_id, $comment) === TRUE)
479 $log[] = array ('code' => 'success', 'message' => "Updated rack '${name}'");
481 $log[] = array ('code' => 'error', 'message' => __FUNCTION__
. ': commitUpdateRack() failed');
482 resetThumbCache ($rack_id);
486 global $pageno, $tabno;
487 $rack = getRackData ($rack_id);
490 showError ('getRackData() failed', __FUNCTION__
);
494 // Render a form for the next.
495 startPortlet ('Rack attributes');
497 echo "<input type=hidden name=page value=${pageno}>";
498 echo "<input type=hidden name=tab value=${tabno}>";
499 echo "<input type=hidden name=rack_id value=${rack_id}>";
500 echo '<table border=0 align=center>';
501 echo "<tr><th class=tdright>Rack row:</th><td class=tdleft>";
502 printSelect (readChapter ('RackRow'), 'rack_row_id', $rack['row_id']);
504 echo "<tr><th class=tdright>Name (required):</th><td class=tdleft><input type=text name=rack_name value='${rack['name']}'></td></tr>\n";
505 echo "<tr><th class=tdright>Height (required):</th><td class=tdleft><input type=text name=rack_height value='${rack['height']}'></td></tr>\n";
506 echo "<tr><th class=tdright>Comment:</th><td class=tdleft><input type=text name=rack_comment value='${rack['comment']}'></td></tr>\n";
507 echo "<tr><td class=submit colspan=2><input type=submit name=got_data value='Update'></td></tr>\n";
508 echo '</form></table><br>';
511 startPortlet ('History');
512 renderHistory ($pageno, $rack_id);
516 // This is a helper for creators and editors.
517 function printSelect ($rowList, $select_name, $selected_id = 1)
519 // First collect all data for OPTGROUPs, then ouput it and dump
520 // the rest of records as is.
523 foreach ($rowList as $dict_key => $dict_value)
525 if (strpos ($dict_value, '%GSKIP%') !== FALSE)
527 $tmp = explode ('%GSKIP%', $dict_value, 2);
528 $optgroup[$tmp[0]][$dict_key] = $tmp[1];
530 elseif (strpos ($dict_value, '%GPASS%') !== FALSE)
532 $tmp = explode ('%GPASS%', $dict_value, 2);
533 $optgroup[$tmp[0]][$dict_key] = $tmp[1];
536 $other[$dict_key] = $dict_value;
538 echo "<select name=${select_name}>";
539 if (!count ($optgroup))
541 foreach ($other as $dict_key => $dict_value)
543 echo "<option value=${dict_key}";
544 if ($dict_key == $selected_id)
546 echo ">${dict_value}</option>";
551 foreach ($optgroup as $groupname => $groupdata)
553 echo "<optgroup label='${groupname}'>";
554 foreach ($groupdata as $dict_key => $dict_value)
556 echo "<option value=${dict_key}";
557 if ($dict_key == $selected_id)
559 echo ">${dict_value}</option>";
561 echo "</optgroup>\n";
565 echo "<optgroup label='other'>\n";
566 foreach ($other as $dict_key => $dict_value)
568 echo "<option value=${dict_key}";
569 if ($dict_key == $selected_id)
571 echo ">${dict_value}</option>";
573 echo "</optgroup>\n";
579 // used by renderGridForm() and renderRackPage()
580 function renderRackInfoPortlet ($rackData)
583 startPortlet ('summary');
584 echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
585 echo "<tr><th width='50%' class=tdright>Rack row:</th><td class=tdleft>${rackData['row_name']}</td></tr>\n";
586 echo "<tr><th width='50%' class=tdright>Name:</th><td class=tdleft>${rackData['name']}</td></tr>\n";
587 echo "<tr><th width='50%' class=tdright>Height:</th><td class=tdleft>${rackData['height']}</td></tr>\n";
588 echo "<tr><th width='50%' class=tdright>Utilization:</th><td class=tdleft>";
589 renderProgressBar (getRSUforRack ($rackData));
591 echo "<tr><th width='50%' class=tdright>Objects:</th><td class=tdleft>";
592 echo getObjectCount ($rackData);
594 printTagTRs ("${root}?page=rackspace&");
595 if (!empty ($rackData['comment']))
596 echo "<tr><th width='50%' class=tdright>Comment:</th><td class=tdleft>${rackData['comment']}</td></tr>\n";
601 // This is a universal editor of rack design/waste.
602 function renderGridForm ($rack_id = 0, $filter, $header, $submit, $state1, $state2)
606 showError ('Invalid rack_id', __FUNCTION__
);
609 if (($rackData = getRackData ($rack_id)) == NULL)
611 showError ('getRackData() failed', __FUNCTION__
);
615 global $root, $pageno, $tabno;
617 markupObjectProblems ($rackData);
619 // Process form submit.
620 if (isset ($_REQUEST['do_update']))
622 $log[] = processGridForm ($rackData, $state1, $state2);
624 $rackData = getRackData ($rack_id);
626 markupObjectProblems ($rackData);
629 // Render the result whatever it is.
631 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
632 echo "<tr><td colspan=2 align=center><h1>${rackData['name']}</h1></td></tr>\n";
634 // Left column with information portlet.
635 echo "<tr><td class=pcleft height='1%' width='50%'>";
636 renderRackInfoPortlet ($rackData);
638 echo "<td class=pcright>";
641 startPortlet ($header);
643 echo "<table class=rack border=0 cellspacing=0 cellpadding=1>\n";
644 echo "<tr><th width='10%'> </th><th width='20%'>Front</th>";
645 echo "<th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n";
646 echo "<form method=post action='${root}?'>\n";
647 echo "<input type=hidden name=page value=${pageno}>\n";
648 echo "<input type=hidden name=tab value=${tabno}>\n";
649 echo "<input type=hidden name=rack_id value=${rack_id}>\n";
650 markupAtomGrid ($rackData, $state2);
651 renderAtomGrid ($rackData);
652 echo "</table></center>\n";
653 echo "<br><input type=submit name=do_update value='${submit}'></form><br><br>\n";
655 echo "</td></tr></table>\n";
658 function renderRackDesign ($rack_id)
660 renderGridForm ($rack_id, 'applyRackDesignMask', 'Rack design', 'Set rack design', 'A', 'F');
663 function renderRackProblems ($rack_id = 0)
665 renderGridForm ($rack_id, 'applyRackProblemMask', 'Rack problems', 'Mark unusable atoms', 'F', 'U');
668 function startPortlet ($title = '')
670 echo "<div class=portlet><h2>${title}</h2>";
673 function finishPortlet ()
678 function printRefsOfType ($refs, $type, $eq)
682 foreach ($refs as $ref)
684 if ($eq($ref['type'], $type))
686 if ($gotone) echo ', ';
687 echo "<a href='${root}?page=object&object_id=${ref['object_id']}'>";
688 if (!empty ($ref['name']))
689 echo $ref['name'] . '@';
690 echo "${ref['object_name']}</a>";
696 function renderRackObject ($object_id = 0)
698 global $root, $nextorder, $aac;
701 showError ('Invalid object_id', __FUNCTION__
);
704 $info = getObjectInfo ($object_id);
707 showError ('getObjectInfo() failed', __FUNCTION__
);
710 // Main layout starts.
711 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
712 echo "<tr><td colspan=2 align=center><h1>${info['dname']}</h1></td></tr>\n";
713 // left column with uknown number of portlets
714 echo "<tr><td class=pcleft>";
715 startPortlet ('Object information');
716 echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
717 if (!empty ($info['name']))
718 echo "<tr><th width='50%' class=tdright>Common name:</th><td class=tdleft>${info['name']}</td></tr>\n";
719 elseif (in_array ($info['objtype_id'], explode (',', getConfigVar ('NAMEFUL_OBJTYPES'))))
720 echo "<tr><td colspan=2 class=msg_error>Common name is missing.</td></tr>\n";
721 echo "<tr><th width='50%' class=tdright>Object type:</th>";
722 echo "<td class=tdleft><a href='${root}?page=objgroup&group_id=${info['objtype_id']}&hl_object_id=${object_id}'>${info['objtype_name']}</a></td></tr>\n";
723 if (!empty ($info['asset_no']))
724 echo "<tr><th width='50%' class=tdright>Asset tag:</th><td class=tdleft>${info['asset_no']}</td></tr>\n";
725 elseif (in_array ($info['objtype_id'], explode (',', getConfigVar ('REQUIRE_ASSET_TAG_FOR'))))
726 echo "<tr><td colspan=2 class=msg_error>Asset tag is missing.</td></tr>\n";
727 if (!empty ($info['label']))
728 echo "<tr><th width='50%' class=tdright>Visible label:</th><td class=tdleft>${info['label']}</td></tr>\n";
729 if (!empty ($info['barcode']))
730 echo "<tr><th width='50%' class=tdright>Barcode:</th><td class=tdleft>${info['barcode']}</td></tr>\n";
731 if ($info['has_problems'] == 'yes')
732 echo "<tr><td colspan=2 class=msg_error>Has problems</td></tr>\n";
733 foreach (getAttrValues ($object_id, TRUE) as $record)
734 if (!empty ($record['value']))
735 echo "<tr><th width='50%' class=opt_attr_th>${record['name']}:</th><td class=tdleft>${record['a_value']}</td></tr>\n";
736 printTagTRs ("${root}?page=objgroup&group_id=${info['objtype_id']}&");
737 echo "</table><br>\n";
740 if (!empty ($info['comment']))
742 startPortlet ('Comment');
743 echo '<div class=commentblock>' . string_insert_hrefs ($info['comment']) . '</div>';
747 $ports = getObjectPortsAndLinks ($object_id);
750 startPortlet ('Ports and links');
751 usort($ports, 'sortByName');
755 if (isset ($_REQUEST['hl_port_id']))
757 assertUIntArg ('hl_port_id', __FUNCTION__
);
758 $hl_port_id = $_REQUEST['hl_port_id'];
760 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
761 echo "<tr><th>Local name</th><th>Visible label</th><th>Port type</th><th>L2 address</th>";
762 echo "<th>Rem. Object</th><th>Rem. port</th></tr>\n";
763 foreach ($ports as $port)
766 if ($hl_port_id == $port['id'])
767 echo ' class=port_highlight';
768 echo "><td>${port['name']}</td><td>${port['label']}</td><td>${port['type']}</td>";
769 echo "<td>${port['l2address']}</td>";
770 if ($port['remote_object_id'])
772 echo "<td><a href='${root}?page=object&object_id=${port['remote_object_id']}&hl_port_id=${port['remote_id']}'>${port['remote_object_name']}</a></td>";
773 echo "<td>${port['remote_name']}</td>";
775 elseif (!empty ($port['reservation_comment']))
777 echo "<td><b>Reserved;</b></td>";
778 echo "<td>${port['reservation_comment']}</td>";
781 echo '<td> </td><td> </td>';
784 echo "</table><br>\n";
788 $addresses = getObjectAddresses ($object_id);
789 usort($addresses, 'sortAddresses');
790 if (count ($addresses))
792 startPortlet ('IPv4 addresses');
793 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
794 echo "<tr><th>OS interface</th><th>IP address</th><th>description</th><th>misc</th></tr>\n";
796 if (isset ($_REQUEST['hl_ipv4_addr']))
798 assertIPv4Arg ('hl_ipv4_addr', __FUNCTION__
);
799 $hl_ipv4_addr = $_REQUEST['hl_ipv4_addr'];
801 foreach ($addresses as $addr)
803 if (strlen($addr['address_name'])>40)
804 $address_name = substr($addr['address_name'],0,38).'...';
806 $address_name = $addr['address_name'];
808 $virtnum = countRefsOfType($addr['references'], 'virtual', 'eq');
809 $sharednum = countRefsOfType($addr['references'], 'shared', 'eq');
810 $regnum = countRefsOfType($addr['references'], 'regular', 'eq');
811 $notvirtnum = countRefsOfType($addr['references'], 'virtual', 'neq');
814 if ($addr['address_reserved']=='yes')
815 echo ' class=trerror';
816 elseif ($addr['type']!='virtual' && $regnum>0)
817 echo ' class=trerror';
818 elseif ($addr['type']=='regular' && $sharednum>0)
819 echo ' class=trerror';
821 if ($hl_ipv4_addr == $addr['ip'])
822 echo ' class=port_highlight';
823 echo "><td class=tdleft>${addr['name']}</td><td class=tdleft>";
824 echo "<a href='${root}?page=ipaddress&ip=${addr['ip']}&hl_object_id=${object_id}'>";
825 echo "${addr['ip']}</a></td><td class='description'>$address_name</td><td class=tdleft>\n";
827 if ($addr['address_reserved']=='yes')
828 echo "<b>Reserved;</b> ";
830 echo $aac[$addr['type']];
831 switch ($addr['type'])
837 printRefsOfType($addr['references'], 'virtual', 'neq');
846 printRefsOfType($addr['references'], 'shared', 'eq');
852 printRefsOfType($addr['references'], 'virtual', 'eq');
857 echo " Collisions: ";
858 printRefsOfType($addr['references'], 'regular', 'eq');
865 printRefsOfType($addr['references'], 'virtual', 'eq');
870 echo " Collisions: ";
871 printRefsOfType($addr['references'], 'virtual', 'neq');
875 echo __FUNCTION__
. '(): internal error! ';
880 echo "</table><br>\n";
884 $forwards = getNATv4ForObject ($object_id);
885 if (count($forwards['in']) or count($forwards['out']))
887 startPortlet('NATv4');
889 if (count($forwards['out']))
892 echo "<h3>locally performed NAT</h3>";
894 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
895 echo "<tr><th>Proto</th><th>Match endpoint</th><th>Translate to</th><th>Target object</th><th>Rule comment</th></tr>\n";
897 foreach ($forwards['out'] as $pf)
901 foreach ($addresses as $addr)
902 if ($addr['ip'] == $pf['localip'])
908 echo "<tr class='$class'>";
909 echo "<td>${pf['proto']}</td><td class=tdleft>${name}: <a href='${root}?page=ipaddress&tab=default&ip=${pf['localip']}'>${pf['localip']}</a>:${pf['localport']}</td>";
910 echo "<td class=tdleft><a href='${root}?page=ipaddress&tab=default&ip=${pf['remoteip']}'>${pf['remoteip']}</a>:${pf['remoteport']}</td>";
911 $address = getIPv4Address ($pf['remoteip']);
912 echo "<td class='description'>";
913 if (count ($address['allocs']))
914 foreach($address['allocs'] as $bond)
915 echo "<a href='${root}?page=object&tab=default&object_id=${bond['object_id']}'>${bond['object_name']}(${bond['name']})</a> ";
916 elseif (!empty ($pf['remote_addr_name']))
917 echo '(' . $pf['remote_addr_name'] . ')';
918 echo "</td><td class='description'>${pf['description']}</td></tr>";
920 echo "</table><br><br>";
922 if (count($forwards['in']))
924 echo "<h3>arriving NAT connections</h3>";
925 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
926 echo "<tr><th>Matched endpoint</th><th>Source object</th><th>Translated to</th><th>Rule comment</th></tr>\n";
927 foreach ($forwards['in'] as $pf)
930 echo "<td>${pf['proto']}/<a href='${root}?page=ipaddress&tab=default&ip=${pf['localip']}'>${pf['localip']}</a>:${pf['localport']}</td>";
931 echo "<td class='description'><a href='${root}?page=object&tab=default&object_id=${pf['object_id']}'>${pf['object_name']}</a>";
932 echo "</td><td><a href='${root}?page=ipaddress&tab=default&ip=${pf['remoteip']}'>${pf['remoteip']}</a>:${pf['remoteport']}</td>";
933 echo "<td class='description'>${pf['description']}</td></tr>";
935 echo "</table><br><br>";
940 $pools = getRSPoolsForObject ($object_id);
944 startPortlet ('Real server pools');
945 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable>\n";
946 echo "<tr><th>VS</th><th>RS pool</th><th>RS</th><th>VS config</th><th>RS config</th></tr>\n";
947 foreach ($pools as $vs_id => $info)
949 echo "<tr valign=top class=row_${order}><td class=tdleft><a href='${root}?page=ipv4vs&vs_id=${vs_id}'>";
950 echo buildVServiceName ($info);
952 if (!empty ($info['name']))
953 echo "<br>${info['name']}";
954 echo "</td><td class=tdleft><a href='${root}?page=ipv4rsp&pool_id=${info['pool_id']}'>";
955 echo (empty ($info['pool_name']) ?
'ANONYMOUS' : $info['pool_name']);
956 echo '</a></td><td class=tdleft>' . $info['rscount'] . '</td>';
957 echo "<td class=tdleft><pre>${info['vsconfig']}</pre></td>";
958 echo "<td class=tdleft><pre>${info['rsconfig']}</pre></td>";
960 $order = $nextorder[$order];
967 // After left column we have (surprise!) right column with rackspace portled only.
968 echo "<td class=pcright>";
970 startPortlet ('Rackspace allocation');
971 // FIXME: now we call getRackData() twice
972 $racks = getResidentRacksData ($object_id);
973 foreach ($racks as $rackData)
974 renderRack ($rackData['id'], $object_id);
981 function renderRackMultiSelect ($sname, $racks, $selected)
983 // Transform the given flat list into a list of groups, each representing a rack row.
985 foreach ($racks as $rack)
986 if (!isset ($rdata[$rack['row_name']]))
987 $rdata[$rack['row_name']] = array ($rack['id'] => $rack['name']);
989 $rdata[$rack['row_name']][$rack['id']] = $rack['name'];
990 echo "<select name=${sname} multiple size=" . getConfigVar ('MAXSELSIZE') . " onchange='getElementById(\"racks\").submit()'>\n";
991 foreach ($rdata as $optgroup => $racklist)
993 echo "<optgroup label='${optgroup}'>";
994 foreach ($racklist as $rack_id => $rack_name)
996 echo "<option value=${rack_id}";
997 if (!(array_search ($rack_id, $selected) === FALSE))
999 echo">${rack_name}</option>\n";
1005 function showMessageOrError ()
1007 if (isset ($_REQUEST['message']))
1008 echo "<div class=msg_success>${_REQUEST['message']}</div>";
1009 elseif (isset ($_REQUEST['error']))
1010 echo "<div class=msg_error>${_REQUEST['error']}</div>";
1011 elseif (isset ($_REQUEST['log']))
1012 printLog (unserialize (base64_decode ($_REQUEST['log'])));
1015 // This function renders a form for port edition.
1016 function renderPortsForObject ($object_id = 0)
1018 global $root, $pageno, $tabno;
1019 if ($object_id <= 0)
1021 showError ('Invalid object_id', __FUNCTION__
);
1024 showMessageOrError();
1025 startPortlet ('Ports and interfaces');
1026 $ports = getObjectPortsAndLinks ($object_id);
1027 usort($ports, 'sortByName');
1028 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
1029 echo "<tr><th> </th><th>Local name</th><th>Visible label</th><th>Port type</th><th>L2 address</th>";
1030 echo "<th>Rem. object</th><th>Rem. port</th><th>(Un)link or (un)reserve</th><th> </th></tr>\n";
1031 foreach ($ports as $port)
1033 echo "<form action='${root}process.php'>";
1034 echo "<input type=hidden name=op value=editPort>";
1035 echo "<input type=hidden name=page value='${pageno}'>\n";
1036 echo "<input type=hidden name=tab value='${tabno}'>\n";
1037 echo "<input type=hidden name=port_id value='${port['id']}'>";
1038 echo "<input type=hidden name=object_id value='$object_id'>\n";
1039 echo "<tr><td><a href='${root}process.php?op=delPort&page=${pageno}&tab=${tabno}&port_id=${port['id']}&object_id=$object_id&port_name=${port['name']}'>";
1040 printImageHREF ('delete', 'Unlink and Delete this port');
1042 echo "<td><input type=text name=name value='${port['name']}' size=8></td>";
1043 echo "<td><input type=text name=label value='${port['label']}' size=24></td>";
1044 echo "<td>${port['type']}</td>\n";
1045 echo "<td><input type=text name=l2address value='${port['l2address']}'></td>\n";
1046 if ($port['remote_object_id'])
1048 echo "<td><a href='${root}?page=object&object_id=${port['remote_object_id']}'>${port['remote_object_name']}</a></td>";
1049 echo "<td>${port['remote_name']}</td>";
1050 echo "<td><a href='${root}process.php?op=unlinkPort&page=${pageno}&tab=${tabno}&port_id=${port['id']}&object_id=$object_id&port_name=";
1051 echo urlencode ($port['name']);
1052 echo "&remote_port_name=${port['remote_name']}&remote_object_name=${port['remote_object_name']}'>";
1053 printImageHREF ('unlink', 'Unlink this port');
1056 elseif (!empty ($port['reservation_comment']))
1058 echo "<td><b>Reserved;</b></td>";
1059 echo "<td><input type=text name=reservation_comment value='${port['reservation_comment']}'></td>";
1060 echo "<td><a href='${root}process.php?op=useup&page=${pageno}&tab=${tabno}&port_id=${port['id']}&object_id=${object_id}'>";
1061 printImageHREF ('useup', 'Use up this port');
1066 echo "<td> </td><td> </td>";
1068 echo "<a href='javascript:;' onclick='window.open(\"${root}link_helper.php?port=${port['id']}&type=${port['type_id']}&object_id=$object_id&port_name=";
1069 echo urlencode ($port['name']);
1070 echo "\",\"findlink\",\"height=700, width=400, location=no, menubar=no, resizable=yes, scrollbars=no, status=no, titlebar=no, toolbar=no\");'>";
1071 printImageHREF ('link', 'Link this port');
1072 echo "</a> <input type=text name=reservation_comment>";
1076 printImageHREF ('save', 'Save changes', TRUE);
1077 echo "</td></form></tr>\n";
1079 echo "<form action='${root}process.php'><tr><td>";
1080 printImageHREF ('add', '', TRUE, 104);
1081 echo "</td><td><input type=text size=8 name=port_name tabindex=100></td>\n";
1082 echo "<td><input type=text size=24 name=port_label tabindex=101></td>";
1083 echo "<input type=hidden name=op value=addPort>\n";
1084 echo "<input type=hidden name=object_id value='${object_id}'>\n";
1085 echo "<input type=hidden name=page value='${pageno}'>\n";
1086 echo "<input type=hidden name=tab value='${tabno}'>\n";
1087 echo "<td><select name='port_type_id' tabindex=102>\n";
1088 $types = getPortTypes();
1089 $default_port_type = getConfigVar ('default_port_type');
1090 foreach ($types as $typeid => $typename)
1092 echo "<option value='${typeid}'";
1093 if ($typeid == $default_port_type)
1095 echo ">${typename}</option>\n";
1097 echo "</select></td>";
1098 echo "<td><input type=text name=port_l2address tabindex=103></td>\n";
1099 echo "<td colspan=4> </td></tr></form>";
1100 echo "</table><br>\n";
1103 startPortlet ('Add/update multiple ports');
1104 echo "<form action=${root}process.php method=post>";
1105 echo "<input type=hidden name=page value='${pageno}'>\n";
1106 echo "<input type=hidden name=tab value='${tabno}'>\n";
1107 echo "<input type=hidden name=object_id value='${object_id}'>\n";
1108 echo "<input type=hidden name=op value=addMultiPorts>";
1109 echo 'Format: <select name=format>';
1110 echo '<option value=c3600asy>Cisco 3600 async: sh line | inc TTY</option>';
1111 echo '<option value=fiwg selected>Foundry ServerIron/FastIron WorkGroup/Edge: sh int br</option>';
1112 echo '<option value=fisxii>Foundry FastIron SuperX/II4000: sh int br</option>';
1113 echo '<option value=ssv1>SSV:<interface name> <MAC address></option>';
1115 echo 'Default port type: ';
1116 echo "<select name=port_type>\n";
1117 foreach ($types as $typeid => $typename)
1119 echo "<option value='${typeid}'";
1120 if ($typeid == $default_port_type)
1122 echo ">${typename}</option>\n";
1125 echo "<input type=submit value='Parse output'><br>\n";
1126 echo "<textarea name=input cols=100 rows=50></textarea><br>\n";
1131 function renderIPv4ForObject ($object_id = 0)
1133 global $root, $pageno, $tabno, $aat;
1134 if ($object_id <= 0)
1136 showError ('Invalid object_id', __FUNCTION__
);
1139 showMessageOrError();
1140 startPortlet ('Allocations');
1141 $addresses = getObjectAddresses ($object_id);
1142 usort($addresses, 'sortAddresses');
1143 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
1144 echo "<tr><th> </th><th>OS interface</th><th>IP address</th><th>description</th><th>type</th><th>misc</th><th> </th></tr>\n";
1145 foreach ($addresses as $addr)
1147 if (strlen($addr['address_name'])>40)
1148 $address_name = substr($addr['address_name'],0,38).'...';
1150 $address_name = $addr['address_name'];
1152 $virtnum = countRefsOfType($addr['references'], 'virtual', 'eq');
1153 $sharednum = countRefsOfType($addr['references'], 'shared', 'eq');
1154 $regnum = countRefsOfType($addr['references'], 'regular', 'eq');
1155 $notvirtnum = countRefsOfType($addr['references'], 'virtual', 'neq');
1157 if ($addr['address_reserved']=='yes')
1159 elseif ($addr['type']!='virtual' && $regnum>0)
1161 elseif ($addr['type']=='regular' && $sharednum>0)
1166 echo "<form action='${root}process.php'>";
1167 echo "<input type=hidden name=page value='${pageno}'>\n";
1168 echo "<input type=hidden name=tab value='${tabno}'>\n";
1169 echo "<input type=hidden name=op value=updIPv4Allocation>";
1170 echo "<input type=hidden name=object_id value='$object_id'>";
1171 echo "<input type=hidden name=ip value='${addr['ip']}'>";
1172 echo "<tr class='$class'><td><a href='${root}process.php?op=delIPv4Allocation&page=${pageno}&tab=${tabno}&ip=${addr['ip']}&object_id=$object_id'>";
1173 printImageHREF ('delete', 'Delete this IPv4 address');
1175 echo "<td class=tdleft><input type='text' name='bond_name' value='${addr['name']}' size=10></td>";
1176 echo "<td class=tdleft><a href='${root}?page=ipaddress&ip=${addr['ip']}'>${addr['ip']}</a></td>";
1177 echo "<td class='description'>$address_name</td>\n<td>";
1178 printSelect ($aat, 'bond_type', $addr['type']);
1180 if ($addr['address_reserved']=='yes')
1181 echo "<b>Reserved</b>; ";
1183 if ($addr['type'] == 'virtual')
1185 if ($notvirtnum > 0)
1188 printRefsOfType($addr['references'], 'virtual', 'neq');
1191 elseif ($addr['type'] == 'shared')
1196 printRefsOfType($addr['references'], 'shared', 'eq');
1202 printRefsOfType($addr['references'], 'virtual', 'eq');
1207 echo " Collisions: ";
1208 printRefsOfType($addr['references'], 'regular', 'eq');
1217 printRefsOfType($addr['references'], 'virtual', 'eq');
1220 if ($notvirtnum > 0)
1222 echo " Collisions: ";
1223 printRefsOfType($addr['references'], 'virtual', 'neq');
1228 printImageHREF ('save', 'Save changes', TRUE);
1229 echo "</td></form></tr>\n";
1233 echo "<form action='${root}process.php'><tr><td>";
1234 printImageHREF ('add', 'Allocate new address', TRUE, 99);
1235 echo "</td><td class=tdleft>";
1236 echo "<input type='text' size='10' name='bond_name' tabindex=100></td>\n";
1237 echo "<input type=hidden name=page value='${pageno}'>\n";
1238 echo "<input type=hidden name=tab value='${tabno}'>\n";
1239 echo "<input type=hidden name=op value=addIPv4Allocation>\n";
1240 echo "<input type=hidden name=object_id value='$object_id'>\n";
1241 echo "<td class=tdleft><input type=text name='ip' tabindex=101>\n";
1242 echo "</td><td> </td><td>";
1243 printSelect ($aat, 'bond_type');
1244 echo "</td><td colspan=2> </td></tr></form>";
1245 echo "</table><br>\n";
1250 // Log structure versions:
1251 // 1: the whole structure is a list of code-message pairs
1252 // 2 and later: there's a "v" field set, which indicates the version
1253 // 2: there's a "m" list set to hold message code and optional arguments
1254 function printLog ($log)
1258 case !isset ($log['v']):
1259 case $log['v'] == 1:
1260 foreach ($log as $key => $record)
1262 echo "<div class=msg_${record['code']}>${record['message']}</div>";
1264 case $log['v'] == 2:
1267 0 => array ('code' => 'success', 'format' => 'Success: %s'),
1268 1 => array ('code' => 'success', 'format' => '%u new records done, %u already existed'),
1269 2 => array ('code' => 'success', 'format' => 'NATv4 rule was successfully added.'),
1270 3 => array ('code' => 'success', 'format' => 'NATv4 rule was successfully deleted.'),
1271 4 => array ('code' => 'success', 'format' => 'NATv4 rule was successfully updated'),
1272 5 => array ('code' => 'success', 'format' => 'Port %s was added successfully'),
1273 6 => array ('code' => 'success', 'format' => 'Port %s was updated successfully'),
1274 7 => array ('code' => 'success', 'format' => 'Port %s was deleted successfully'),
1275 8 => array ('code' => 'success', 'format' => 'Port %s successfully linked with port %s at object %s'),
1276 9 => array ('code' => 'success', 'format' => 'Port %s was successfully unlinked from %s@%s'),
1277 10 => array ('code' => 'success', 'format' => 'Added %u ports, updated %u ports, encountered %u errors.'),
1278 11 => array ('code' => 'success', 'format' => 'Reservation removed.'),
1279 12 => array ('code' => 'success', 'format' => 'allocation updated'),
1280 13 => array ('code' => 'success', 'format' => 'allocated'),
1281 14 => array ('code' => 'success', 'format' => 'deallocated'),
1282 15 => array ('code' => 'success', 'format' => 'Reset succeeded.'),
1283 16 => array ('code' => 'success', 'format' => 'Update done'),
1284 17 => array ('code' => 'success', 'format' => 'Update(s) succeeded.'),
1285 18 => array ('code' => 'success', 'format' => 'Load balancer was successfully added'),
1286 19 => array ('code' => 'success', 'format' => 'Load balancer was successfully deleted'),
1287 20 => array ('code' => 'success', 'format' => 'Load balancer info was successfully updated'),
1288 21 => array ('code' => 'success', 'format' => 'Generation complete'),
1289 22 => array ('code' => 'success', 'format' => 'Chained %u tags'),
1290 23 => array ('code' => 'success', 'format' => 'IPv4 prefix successfully added'),
1291 24 => array ('code' => 'success', 'format' => 'IPv4 prefix deleted'),
1292 25 => array ('code' => 'success', 'format' => 'IPv4 prefix updated'),
1293 26 => array ('code' => 'success', 'format' => '%u IP address(es) were successfully updated'),
1294 27 => array ('code' => 'success', 'format' => 'IPv4 address updated'),
1295 28 => array ('code' => 'success', 'format' => 'Virtual service was successfully created'),
1296 29 => array ('code' => 'success', 'format' => 'Virtual service was successfully deleted'),
1297 30 => array ('code' => 'success', 'format' => 'Virtual service was successfully updated'),
1298 31 => array ('code' => 'success', 'format' => 'RS pool was successfully created'),
1299 32 => array ('code' => 'success', 'format' => 'RS pool was successfully deleted'),
1300 33 => array ('code' => 'success', 'format' => 'RS pool was successfully updated'),
1301 34 => array ('code' => 'success', 'format' => 'Real server was successfully added'),
1302 35 => array ('code' => 'success', 'format' => 'Real server was successfully deleted'),
1303 36 => array ('code' => 'success', 'format' => 'Real server was successfully updated'),
1304 37 => array ('code' => 'success', 'format' => 'Successfully added %u real servers'),
1305 38 => array ('code' => 'success', 'format' => '%u real server(s) were successfully (de)activated'),
1306 39 => array ('code' => 'success', 'format' => 'User account %s updated.'),
1307 40 => array ('code' => 'success', 'format' => 'User account %s created.'),
1308 41 => array ('code' => 'success', 'format' => 'User account disabled.'),
1309 42 => array ('code' => 'success', 'format' => 'User account enabled.'),
1310 43 => array ('code' => 'success', 'format' => 'Saved successfully.'),
1311 44 => array ('code' => 'success', 'format' => '%s failures and %s successfull changes.'),
1312 45 => array ('code' => 'success', 'format' => "Attribute '%s' created."),
1313 46 => array ('code' => 'success', 'format' => 'Rename successful.'),
1314 47 => array ('code' => 'success', 'format' => 'Attribute was deleted.'),
1315 48 => array ('code' => 'success', 'format' => 'Supplement succeeded.'),
1316 49 => array ('code' => 'success', 'format' => 'Reduction succeeded.'),
1317 50 => array ('code' => 'success', 'format' => 'Reduction succeeded.'),
1318 51 => array ('code' => 'success', 'format' => 'Update succeeded.'),
1319 52 => array ('code' => 'success', 'format' => 'Supplement succeeded.'),
1320 53 => array ('code' => 'success', 'format' => 'Chapter was deleted.'),
1321 54 => array ('code' => 'success', 'format' => 'Chapter was updated.'),
1322 55 => array ('code' => 'success', 'format' => 'Chapter was added.'),
1323 56 => array ('code' => 'success', 'format' => 'Update succeeded.'),
1324 57 => array ('code' => 'success', 'format' => 'Reset complete'),
1325 58 => array ('code' => 'success', 'format' => "Successfully deleted tag ."),
1326 59 => array ('code' => 'success', 'format' => "Created tag '%s'."),
1327 60 => array ('code' => 'success', 'format' => "Updated tag '%s'."),
1328 61 => array ('code' => 'success', 'format' => 'Password changed successfully.'),
1329 62 => array ('code' => 'success', 'format' => 'gw: %s'),
1330 63 => array ('code' => 'success', 'format' => '%u change request(s) have been processed'),
1331 64 => array ('code' => 'success', 'format' => 'Port %s@%s has been assigned to VLAN %u'),
1333 100 => array ('code' => 'error', 'format' => 'Generic error: %s'),
1334 101 => array ('code' => 'error', 'format' => 'Port name cannot be empty'),
1335 102 => array ('code' => 'error', 'format' => "Error creating user account '%s'"),
1336 103 => array ('code' => 'error', 'format' => 'getHashByID() failed'),
1337 104 => array ('code' => 'error', 'format' => "Error updating user account '%s'"),
1338 105 => array ('code' => 'error', 'format' => 'Error enabling user account.'),
1339 106 => array ('code' => 'error', 'format' => 'Error disabling user account.'),
1340 107 => array ('code' => 'error', 'format' => 'Admin account cannot be disabled'),
1341 108 => array ('code' => 'error', 'format' => '%u failures and %u successfull changes.'),
1342 109 => array ('code' => 'error', 'format' => 'Update failed!'),
1343 110 => array ('code' => 'error', 'format' => 'Supplement failed!'),
1344 111 => array ('code' => 'error', 'format' => 'Reduction failed!'),
1345 112 => array ('code' => 'error', 'format' => 'Error adding chapter.'),
1346 113 => array ('code' => 'error', 'format' => 'Error updating chapter.'),
1347 114 => array ('code' => 'error', 'format' => 'Error deleting chapter.'),
1348 115 => array ('code' => 'error', 'format' => 'Error renaming attribute.'),
1349 116 => array ('code' => 'error', 'format' => 'Error creating attribute.'),
1350 117 => array ('code' => 'error', 'format' => 'Error deleting attribute.'),
1351 118 => array ('code' => 'error', 'format' => 'Supplement failed!'),
1352 119 => array ('code' => 'error', 'format' => 'Reduction failed!'),
1353 120 => array ('code' => 'error', 'format' => 'Reset failed!'),
1354 121 => array ('code' => 'error', 'format' => 'commitUpdateObject() failed'),
1355 122 => array ('code' => 'error', 'format' => 'One or more update(s) failed!'),
1356 123 => array ('code' => 'error', 'format' => 'Cannot process submitted data: unknown format code.'),
1357 124 => array ('code' => 'error', 'format' => 'Error removing reservation!'),
1358 125 => array ('code' => 'error', 'format' => "Update failed with error: '%s'"),
1359 126 => array ('code' => 'error', 'format' => 'addRStoRSPool() failed'),
1360 127 => array ('code' => 'error', 'format' => 'Added %u real servers and encountered %u errors'),
1361 128 => array ('code' => 'error', 'format' => 'commitDeleteRS() failed'),
1362 129 => array ('code' => 'error', 'format' => 'commitDeleteLB() failed'),
1363 130 => array ('code' => 'error', 'format' => 'commitDeleteVS() failed'),
1364 131 => array ('code' => 'error', 'format' => 'invalid format requested'),
1365 132 => array ('code' => 'error', 'format' => 'invalid protocol'),
1366 133 => array ('code' => 'error', 'format' => 'commitUpdateRS() failed'),
1367 134 => array ('code' => 'error', 'format' => 'commitUpdateLB() failed'),
1368 135 => array ('code' => 'error', 'format' => 'commitUpdateVS() failed'),
1369 136 => array ('code' => 'error', 'format' => 'addLBtoRSPool() failed'),
1370 137 => array ('code' => 'error', 'format' => 'addLBtoRSPool() failed'),
1371 138 => array ('code' => 'error', 'format' => 'commitDeleteRSPool() failed'),
1372 139 => array ('code' => 'error', 'format' => 'commitUpdateRSPool() failed'),
1373 140 => array ('code' => 'error', 'format' => 'Encountered %u errors, (de)activated %u real servers'),
1374 141 => array ('code' => 'error', 'format' => 'Encountered %u errors, updated %u IP address(es)'),
1375 142 => array ('code' => 'error', 'format' => 'executeAutoPorts() failed'),
1376 143 => array ('code' => 'error', 'format' => 'Tried chaining %u tags, but experienced %u errors.'),
1377 144 => array ('code' => 'error', 'format' => "Error deleting tag: '%s'"),
1378 145 => array ('code' => 'error', 'format' => "Invalid tag name '%s'"),
1379 146 => array ('code' => 'error', 'format' => "Tag '%s' (or similar name) already exists"),
1380 147 => array ('code' => 'error', 'format' => "Could not create tag '%s' because of error '%s'"),
1381 148 => array ('code' => 'error', 'format' => "Could not update tag '%s' because of error '%s'"),
1382 149 => array ('code' => 'error', 'format' => 'Turing test failed'),
1383 150 => array ('code' => 'error', 'format' => 'Can only change password under DB authentication.'),
1384 151 => array ('code' => 'error', 'format' => 'Old password doesn\'t match.'),
1385 152 => array ('code' => 'error', 'format' => 'New passwords don\'t match.'),
1386 153 => array ('code' => 'error', 'format' => 'Password change failed.'),
1387 154 => array ('code' => 'error', 'format' => "Verification error: %s"),
1388 155 => array ('code' => 'error', 'format' => 'Save failed.'),
1389 156 => array ('code' => 'error', 'format' => 'getSwitchVLANs() failed'),
1390 157 => array ('code' => 'error', 'format' => 'operation not permitted'),
1391 158 => array ('code' => 'error', 'format' => 'Ignoring malformed record #%u in form submit'),
1392 159 => array ('code' => 'error', 'format' => 'Permission denied moving port %s from VLAN%u to VLAN%u'),
1393 160 => array ('code' => 'error', 'format' => 'Invalid arguments'),
1394 161 => array ('code' => 'error', 'format' => 'Endpoint not found. Please either set FQDN attribute or assign an IP address to the object.'),
1395 162 => array ('code' => 'error', 'format' => 'More than one IP address is assigned to this object, please configure FQDN attribute.'),
1396 163 => array ('code' => 'error', 'format' => 'Failed to get any response from queryGateway() or the gateway died'),
1397 164 => array ('code' => 'error', 'format' => 'Gateway failure: %s.'),
1398 165 => array ('code' => 'error', 'format' => 'Gateway failure: malformed reply.'),
1399 166 => array ('code' => 'error', 'format' => 'gw: %s'),
1400 167 => array ('code' => 'error', 'format' => 'Could not find port %s'),
1401 168 => array ('code' => 'error', 'format' => 'Port %s is a trunk'),
1402 169 => array ('code' => 'error', 'format' => 'Failed to configure %s, connector returned code %u'),
1403 170 => array ('code' => 'error', 'format' => 'There is no network for IP address "%s"'),
1405 200 => array ('code' => 'warning', 'format' => 'generic warning: %s'),
1406 201 => array ('code' => 'warning', 'format' => 'nothing happened...'),
1407 202 => array ('code' => 'warning', 'format' => 'gw: %s'),
1408 203 => array ('code' => 'warning', 'format' => 'Port %s seems to be the first in VLAN %u at this switch.'),
1409 204 => array ('code' => 'warning', 'format' => 'Check uplink/downlink configuration for proper operation.'),
1410 205 => array ('code' => 'warning', 'format' => '%u change request(s) have been ignored'),
1412 // Handle the arguments. Is there any better way to do it?
1413 foreach ($log['m'] as $record)
1415 if (!isset ($record['c']) or !isset ($msginfo[$record['c']]))
1417 echo '<div class=msg_neutral>(this message was lost)</div>';
1420 if (isset ($record['a']))
1421 switch (count ($record['a']))
1426 $msginfo[$record['c']]['format'],
1433 $msginfo[$record['c']]['format'],
1441 $msginfo[$record['c']]['format'],
1451 $msginfo[$record['c']]['format'],
1460 $msgtext = $msginfo[$record['c']]['format'];
1461 echo '<div class=msg_' . $msginfo[$record['c']]['code'] . ">${msgtext}</div>";
1465 echo '<div class=msg_error>' . __FUNCTION__
. ': internal error</div>';
1471 The following conditions must be followed:
1472 1. We can mount onto free atoms only. This means: if any record for an atom
1473 already exists in RackSpace, it can't be used for mounting.
1474 2. We can't unmount from 'W' atoms. Operator should review appropriate comments
1475 and either delete them before unmounting or refuse to unmount the object.
1478 // We extensively use $_REQUEST in the function.
1479 function renderRackSpaceForObject ($object_id = 0)
1481 if ($object_id <= 0)
1483 showError ('Invalid object_id', __FUNCTION__
);
1486 $is_submit = isset ($_REQUEST['got_atoms']);
1487 $is_update = isset ($_REQUEST['rackmulti'][0]);
1488 $info = getObjectInfo ($object_id);
1491 showError ('getObjectInfo() failed', __FUNCTION__
);
1494 // Always process occupied racks plus racks chosen by user. First get racks with
1495 // already allocated rackspace...
1496 $workingRacksData = getResidentRacksData ($object_id);
1497 if ($workingRacksData === NULL)
1499 print_r ($workingRacksData);
1500 showError ('getResidentRacksData() failed', __FUNCTION__
);
1504 // ...and then add those chosen by user (if any).
1506 foreach ($_REQUEST['rackmulti'] as $cand_id)
1508 if (!isset ($workingRacksData[$cand_id]))
1510 $rackData = getRackData ($cand_id);
1511 if ($rackData == NULL)
1513 showError ('getRackData() failed', __FUNCTION__
);
1516 $workingRacksData[$cand_id] = $rackData;
1520 // Do it only once...
1521 foreach ($workingRacksData as &$rackData)
1522 applyObjectMountMask ($rackData, $object_id);
1523 // Now we workaround an old caveat: http://bugs.php.net/bug.php?id=37410
1526 // Here we process form submit by trying to save all submitted info to database.
1529 $oldMolecule = getMoleculeForObject ($object_id);
1530 $worldchanged = FALSE;
1532 foreach ($workingRacksData as $rack_id => $rackData)
1534 $logrecord = processGridForm ($rackData, 'F', 'T', $object_id);
1535 $log[] = $logrecord;
1536 if ($logrecord['code'] != 300)
1538 $worldchanged = TRUE;
1539 // Reload our working copy after form processing.
1540 $rackData = getRackData ($rack_id);
1541 if ($rackData == NULL)
1542 $log[] = array ('code' => 500, 'message' => 'Working copy update failed in ', __FUNCTION__
);
1543 applyObjectMountMask ($rackData, $object_id);
1544 $workingRacksData[$rack_id] = $rackData;
1550 $newMolecule = getMoleculeForObject ($object_id);
1551 $oc = count ($oldMolecule);
1552 $nc = count ($newMolecule);
1553 $omid = $oc ?
createMolecule ($oldMolecule) : 'NULL';
1554 $nmid = $nc ?
createMolecule ($newMolecule) : 'NULL';
1555 global $remote_username;
1556 $comment = empty ($_REQUEST['comment']) ?
'NULL' : "'${_REQUEST['comment']}'";
1558 "insert into MountOperation(object_id, old_molecule_id, new_molecule_id, user_name, comment) " .
1559 "values (${object_id}, ${omid}, ${nmid}, '${remote_username}', ${comment})";
1561 $result = $dbxlink->query ($query);
1562 if ($result == NULL)
1563 $log[] = array ('code' => 'error', 'message' => 'SQL query failed during history logging.');
1565 $log[] = array ('code' => 'success', 'message' => 'History logged.');
1570 // This is the time for rendering.
1571 global $root, $pageno, $tabno;
1572 echo "<form id='racks' action='${root}'>";
1573 echo "<input type=hidden name=page value='${pageno}'>\n";
1574 echo "<input type=hidden name=tab value='${tabno}'>\n";
1575 echo "<input type=hidden name=object_id value='${object_id}'>\n";
1576 // Main layout starts.
1577 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0><tr>";
1579 // Left portlet with rack list.
1580 echo "<td class=pcleft height='1%'>";
1581 startPortlet ('Racks');
1582 $allRacksData = getRacksForRow();
1583 if (count ($allRacksData) <= getConfigVar ('RACK_PRESELECT_THRESHOLD'))
1585 foreach (array_keys ($allRacksData) as $rack_id)
1587 $rackData = getRackData ($rack_id);
1588 if ($rackData == NULL)
1590 showError ('getRackData() failed', __FUNCTION__
);
1593 $workingRacksData[$rack_id] = $rackData;
1595 foreach ($workingRacksData as &$rackData)
1596 applyObjectMountMask ($rackData, $object_id);
1599 renderRackMultiSelect ('rackmulti[]', $allRacksData, array_keys ($workingRacksData));
1605 // Middle portlet with comment and submit.
1606 echo "<td class=pcleft>";
1607 startPortlet ('Comment');
1608 echo "<textarea name=comment rows=10 cols=40></textarea><br>\n";
1609 echo "<input type=submit value='Save' name=got_atoms>\n";
1615 // Right portlet with rendered racks. If this form submit is not final, we have to
1616 // reflect the former state of the grid in current form.
1617 echo "<td class=pcright rowspan=2 height='1%'>";
1618 startPortlet ('Working copy');
1619 echo '<table border=0 cellspacing=10 align=center><tr>';
1620 foreach ($workingRacksData as $rack_id => $rackData)
1622 // Order is important here: only original allocation is highlighted.
1623 highlightObject ($rackData, $object_id);
1624 markupAtomGrid ($rackData, 'T');
1625 // If we have a form processed, discard user input and show new database
1627 if (!$is_submit and $is_update)
1628 mergeGridFormToRack ($rackData);
1629 echo "<td valign=top>";
1630 echo "<center>\n<h2>${rackData['name']}</h2>\n";
1631 echo "<table class=rack border=0 cellspacing=0 cellpadding=1>\n";
1632 echo "<tr><th width='10%'> </th><th width='20%'>Front</th>";
1633 echo "<th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n";
1634 renderAtomGrid ($rackData);
1635 echo "<tr><th width='10%'> </th><th width='20%'>Front</th>";
1636 echo "<th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n";
1637 echo "</table></center>\n";
1640 echo "</tr></table>";
1645 echo "</tr></table>\n";
1648 function renderMolecule ($mdata, $object_id)
1651 $rackpack = array();
1653 foreach ($mdata as $rua)
1655 $rack_id = $rua['rack_id'];
1656 $unit_no = $rua['unit_no'];
1657 $atom = $rua['atom'];
1658 if (!isset ($rackpack[$rack_id]))
1660 $rackData = getRackData ($rack_id);
1661 for ($i = $rackData['height']; $i > 0; $i--)
1662 for ($locidx = 0; $locidx < 3; $locidx++
)
1663 $rackData[$i][$locidx]['state'] = 'F';
1664 $rackpack[$rack_id] = $rackData;
1666 $rackpack[$rack_id][$unit_no][$loclist[$atom]]['state'] = 'T';
1667 $rackpack[$rack_id][$unit_no][$loclist[$atom]]['object_id'] = $object_id;
1669 // now we have some racks to render
1670 foreach ($rackpack as $rackData)
1672 markAllSpans ($rackData);
1673 echo "<table class=molecule cellspacing=0>\n";
1674 echo "<caption>${rackData['name']}</caption>\n";
1675 echo "<tr><th width='10%'> </th><th width='20%'>Front</th><th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n";
1676 for ($i = $rackData['height']; $i > 0; $i--)
1678 echo "<tr><th>$i</th>";
1679 for ($locidx = 0; $locidx < 3; $locidx++
)
1681 $state = $rackData[$i][$locidx]['state'];
1682 echo "<td class=state_${state}> </td>\n";
1690 function renderUnmountedObjectsPortlet ()
1692 startPortlet ('Unmounted objects');
1693 $objs = getUnmountedObjects();
1696 showError ('getUnmountedObjects() failed', __FUNCTION__
);
1699 global $root, $nextorder;
1701 echo '<br><br><table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
1702 echo '<tr><th>Common name</th><th>Visible label</th><th>Asset number</th><th>Barcode</th></tr>';
1703 foreach ($objs as $obj)
1705 echo "<tr class=row_${order}><td><a href='${root}?page=object&object_id=${obj['id']}'>${obj['dname']}</a></td>";
1706 echo "<td>${obj['label']}</td>";
1707 echo "<td>${obj['asset_no']}</td>";
1708 echo "<td>${obj['barcode']}</td></tr>";
1709 $order = $nextorder[$order];
1711 echo "</table><br>\n";
1715 function renderProblematicObjectsPortlet ()
1717 startPortlet ('Problematic objects');
1718 $objs = getProblematicObjects();
1721 showError ('getProblematicObjects() failed', __FUNCTION__
);
1724 global $root, $nextorder;
1726 echo '<br><br><table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
1727 echo '<tr><th>Type</th><th>Common name</th></tr>';
1728 foreach ($objs as $obj)
1730 echo "<tr class=row_${order}><td>${obj['objtype_name']}</td>";
1731 echo "<td><a href='${root}?page=object&object_id=${obj['id']}'>${obj['dname']}</a></tr>";
1732 $order = $nextorder[$order];
1734 echo "</table><br>\n";
1738 function renderObjectSpace ()
1740 global $root, $taglist, $tagtree;
1741 echo "<table border=0 class=objectview>\n";
1742 echo "<tr><td class=pcleft width='50%'>";
1743 startPortlet ('View all by type');
1744 $groupInfo = getObjectGroupInfo();
1745 if ($groupInfo === NULL)
1747 showError ('getObjectGroupInfo() failed', __FUNCTION__
);
1750 if (count ($groupInfo) == 0)
1751 echo "No objects exist in DB";
1754 echo '<div align=left><ul>';
1755 foreach ($groupInfo as $gi)
1756 echo "<li><a href='${root}?page=objgroup&group_id=${gi['id']}'>${gi['name']}</a> (${gi['count']})</li>";
1761 echo '</td><td class=pcright>';
1763 startPortlet ('View all by tag');
1764 if (count ($taglist) == 0)
1765 echo "No tags exist in DB";
1767 renderTagCloud ('object');
1769 echo "</td></tr></table>\n";
1772 function renderObjectGroup ()
1774 global $root, $pageno, $tabno, $nextorder, $taglist, $tagtree;
1775 assertUIntArg ('group_id', __FUNCTION__
, TRUE);
1776 $group_id = $_REQUEST['group_id'];
1777 $tagfilter = getTagFilter();
1778 $tagfilter_str = getTagFilterStr ($tagfilter);
1779 echo "<table border=0 class=objectview>\n";
1780 echo "<tr><td class=pcleft width='25%'>";
1781 startPortlet ('change type');
1782 $groupInfo = getObjectGroupInfo();
1783 if ($groupInfo === NULL)
1785 showError ('getObjectGroupInfo() failed', __FUNCTION__
);
1788 if (count ($groupInfo) == 0)
1789 echo "No objects exist in DB";
1792 echo '<div align=left><ul>';
1793 foreach ($groupInfo as $gi)
1795 echo "<li><a href='${root}?page=${pageno}&group_id=${gi['id']}${tagfilter_str}'>";
1796 if ($gi['id'] == $group_id)
1798 echo "${gi['name']}</a>";
1799 if ($gi['id'] == $group_id)
1801 echo " (${gi['count']})";
1802 if ($gi['id'] == $group_id)
1810 echo '</td><td class=pcleft>';
1812 startPortlet ('Objects');
1813 $objects = getObjectList ($group_id, $tagfilter, getTFMode());
1814 if ($objects === NULL)
1816 showError ('getObjectList() failed', __FUNCTION__
);
1819 echo '<br><br><table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
1820 echo '<tr><th>Common name</th><th>Visible label</th><th>Asset tag</th><th>Barcode</th><th>Rack</th></tr>';
1822 foreach ($objects as $obj)
1824 if (isset ($_REQUEST['hl_object_id']) and $_REQUEST['hl_object_id'] == $obj['id'])
1825 $secondclass = 'tdleft port_highlight';
1827 $secondclass = 'tdleft';
1828 echo "<tr class=row_${order}><td class='${secondclass}'><a href='${root}?page=object&object_id=${obj['id']}'>${obj['dname']}</a></td>";
1829 echo "<td class='${secondclass}'>${obj['label']}</td>";
1830 echo "<td class='${secondclass}'>${obj['asset_no']}</td>";
1831 echo "<td class='${secondclass}'>${obj['barcode']}</td>";
1832 if ($obj['rack_id'])
1833 echo "<td class='${secondclass}'><a href='${root}?page=rack&rack_id=${obj['rack_id']}'>${obj['Rack_name']}</a></td>";
1835 echo "<td class='${secondclass}'>Unmounted</td>";
1837 $order = $nextorder[$order];
1842 echo "</td><td class=pcright width='25%'>";
1844 renderTagFilterPortlet ($tagfilter, 'object', 'group_id', $group_id);
1845 echo "</td></tr></table>\n";
1848 function renderEmptyPortsSelect ($port_id, $type_id)
1850 $ports = getEmptyPortsOfType($type_id);
1851 usort($ports, 'sortEmptyPorts');
1852 foreach ($ports as $port)
1854 if ($port_id == $port['Port_id'])
1856 echo "<option value='${port['Port_id']}' onclick='getElementById(\"remote_port_name\").value=\"${port['Port_name']}\"; getElementById(\"remote_object_name\").value=\"${port['Object_name']}\";'>${port['Object_name']} ${port['Port_name']}</option>\n";
1860 function renderAllIPv4Allocations ()
1862 $addresses = getAllIPv4Allocations();
1863 usort($addresses, 'sortObjectAddressesAndNames');
1864 foreach ($addresses as $address)
1866 echo "<option value='${address['ip']}' onclick='getElementById(\"ip\").value=\"${address['ip']}\";'>${address['object_name']} ${address['name']} ${address['ip']}</option>\n";
1870 // History viewer for history-enabled simple dictionaries.
1871 function renderHistory ($object_type, $object_id)
1873 switch ($object_type)
1876 $query = "select ctime, user_name, name, deleted, comment from RackRowHistory where id = ${object_id} order by ctime";
1877 $header = '<tr><th>change time</th><th>author</th><th>rack row name</th><th>is deleted?</th><th>rack row comment</th></tr>';
1882 "select ctime, user_name, rh.name, rh.deleted, d.dict_value as name, rh.height, rh.comment " .
1883 "from RackHistory as rh left join Dictionary as d on rh.row_id = d.dict_key " .
1884 "natural join Chapter " .
1885 "where chapter_name = 'RackRow' and rh.id = ${object_id} order by ctime";
1886 $header = '<tr><th>change time</th><th>author</th><th>rack name</th><th>is deleted?</th><th>rack row name</th><th>rack height</th><th>rack comment</th></tr>';
1891 "select ctime, user_name, name, label, barcode, asset_no, deleted, has_problems, dict_value, comment " .
1892 "from RackObjectHistory inner join Dictionary on objtype_id = dict_key natural join Chapter " .
1893 "where chapter_name = 'RackObjectType' and id=${object_id} order by ctime";
1894 $header = '<tr><th>change time</th><th>author</th><th>common name</th><th>visible label</th><th>barcode</th><th>asset no</th><th>is deleted?</th><th>has problems?</th><th>object type</th><th>comment</th></tr>';
1898 showError ("Uknown object type '${object_type}'", __FUNCTION__
);
1902 $result = $dbxlink->query ($query);
1903 if ($result == NULL)
1905 showError ('SQL query failed', __FUNCTION__
);
1908 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
1912 while ($row = $result->fetch (PDO
::FETCH_NUM
))
1914 echo "<tr class=row_${order}><td>${row[0]}</td>";
1915 for ($i = 1; $i <= $extra; $i++
)
1916 echo "<td>" . $row[$i] . "</td>";
1918 $order = $nextorder[$order];
1920 echo "</table><br>\n";
1923 function renderRackspaceHistory ()
1925 global $root, $nextorder, $pageno, $tabno;
1927 $history = getRackspaceHistory();
1928 // Show the last operation by default.
1929 if (isset ($_REQUEST['op_id']))
1930 $op_id = $_REQUEST['op_id'];
1931 elseif (isset ($history[0]['mo_id']))
1932 $op_id = $history[0]['mo_id'];
1939 list ($omid, $nmid) = getOperationMolecules ($op_id);
1941 // Main layout starts.
1942 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
1944 // Left top portlet with old allocation.
1945 echo "<tr><td class=pcleft>";
1946 startPortlet ('Old allocation');
1949 $oldMolecule = getMolecule ($omid);
1950 renderMolecule ($oldMolecule, $object_id);
1956 echo '</td><td class=pcright>';
1958 // Right top portlet with new allocation
1959 startPortlet ('New allocation');
1962 $newMolecule = getMolecule ($nmid);
1963 renderMolecule ($newMolecule, $object_id);
1969 echo '</td></tr><tr><td colspan=2>';
1971 // Bottom portlet with list
1973 startPortlet ('Rackspace allocation history');
1974 echo "<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>\n";
1975 echo "<tr><th>timestamp</th><th>author</th><th>rack object ID</th><th>rack object type</th><th>rack object name</th><th>comment</th></tr>\n";
1976 foreach ($history as $row)
1978 if ($row['mo_id'] == $op_id)
1981 $class = "row_${order}";
1982 echo "<tr class=${class}><td><a href='${root}?page=${pageno}&tab=${tabno}&op_id=${row['mo_id']}'>${row['ctime']}</a></td>";
1983 echo "<td>${row['user_name']}</td>";
1984 echo "<td>${row['ro_id']}</td><td>${row['objtype_name']}</td><td>${row['name']}</td><td>${row['comment']}</td>\n";
1986 $order = $nextorder[$order];
1991 echo '</td></tr></table>';
1995 function renderAddressspace ()
1997 global $root, $pageno;
1999 echo "<table border=0 class=objectview>\n";
2000 echo "<tr><td class=pcleft>";
2002 startPortlet ('Networks');
2003 echo "<table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
2004 $tagfilter = getTagFilter();
2005 $addrspaceList = getAddressspaceList ($tagfilter, getTFMode());
2006 echo "<tr><th>prefix</th><th>name/tags</th><th>utilization</th></tr>\n";
2007 foreach ($addrspaceList as $iprange)
2009 $netdata = getIPv4Network ($iprange['id']);
2010 $prefixtags = loadIPv4PrefixTags ($iprange['id']);
2011 $total = ($netdata['ip_bin'] |
$netdata['mask_bin_inv']) - ($netdata['ip_bin'] & $netdata['mask_bin']) +
1;
2012 $used = count ($netdata['addrlist']);
2013 echo "<tr valign=top><td class=tdleft><a href='${root}?page=iprange&id=${iprange['id']}'>${iprange['ip']}/${netdata['mask']}</a></td>";
2014 echo "<td class=tdleft>${netdata['name']}";
2015 if (count ($prefixtags))
2018 echo serializeTags ($prefixtags, "${root}?page=${pageno}&");
2020 echo "</td><td class=tdcenter>";
2021 renderProgressBar ($used/$total);
2022 echo "<br><small>${used}/${total}</small></td></tr>";
2026 echo '</td><td class=pcright>';
2027 renderTagFilterPortlet ($tagfilter, 'ipv4net');
2028 echo "</td></tr></table>\n";
2031 function renderIPv4SLB ()
2033 global $root, $page, $nextorder;
2035 startPortlet ('SLB configuration');
2036 echo "<table border=0 width='100%'><tr>";
2037 foreach (array ('ipv4vslist', 'ipv4rsplist', 'rservers', 'lbs') as $pno)
2038 echo "<td><h3><a href='${root}?page=${pno}'>" . $page[$pno]['title'] . "</a></h3></td>";
2039 echo '</tr></table>';
2042 $summary = getSLBSummary();
2043 startPortlet ('SLB tactical overview');
2044 // A single id-keyed array isn't used here to preserve existing
2045 // order of LBs returned by getSLBSummary()
2048 foreach ($summary as $vipdata)
2049 foreach (array_keys ($vipdata['lblist']) as $lb_object_id)
2050 if (!in_array ($lb_object_id, $lblist))
2052 $oi = getObjectInfo ($lb_object_id);
2053 $lbdname[$lb_object_id] = $oi['dname'];
2054 $lblist[] = $lb_object_id;
2056 if (!count ($summary))
2057 echo 'none configured';
2061 echo "<table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
2062 echo "<tr><th>VS ↓ LB →</th>";
2063 foreach ($lblist as $lb_object_id)
2064 echo "<th><a href='${root}?page=object&tab=default&object_id=${lb_object_id}'>" . $lbdname[$lb_object_id] . "</a></th>";
2066 foreach ($summary as $vsid => $vsdata)
2068 echo "<tr class=row_${order}><td class=tdleft><a href='$root?page=ipv4vs&tab=default&vs_id=${vsid}'>";
2069 echo buildVServiceName ($vsdata);
2071 if (!empty ($vsdata['name']))
2072 echo "<br>${vsdata['name']}";
2074 foreach ($lblist as $lb_object_id)
2076 echo '<td class=tdleft>';
2077 if (!isset ($vsdata['lblist'][$lb_object_id]))
2081 echo $vsdata['lblist'][$lb_object_id]['size'];
2082 echo " (<a href='${root}?page=ipv4rsp&pool_id=";
2083 echo $vsdata['lblist'][$lb_object_id]['id'] . "'>";
2084 echo $vsdata['lblist'][$lb_object_id]['name'] . '</a>)';
2089 $order = $nextorder[$order];
2096 function renderAddNewRange ()
2098 global $root, $pageno, $tabno;
2099 showMessageOrError();
2101 startPortlet ("Add new");
2102 echo "<table class='widetable' border=0 cellpadding=10 align='center'>\n";
2103 echo "<tr><th>prefix</th><th>name</th><th>connected network</th><th>assign tags</th><th> </th></tr>\n";
2104 echo "<form name='add_new_range' action='${root}process.php'>\n";
2105 echo "<input type=hidden name=op value=addIPv4Prefix>\n";
2106 echo "<input type=hidden name=page value='${pageno}'>\n";
2107 echo "<input type=hidden name=tab value='${tabno}'>\n";
2108 echo "<tr valign=top><td class='tdcenter'><input type=text name='range' size=18 class='live-validate' tabindex=1></td>\n";
2109 echo "<td class='tdcenter'><input type=text name='name' size='20' tabindex=2></td>\n";
2110 echo "<td class='tdcenter'><input type=checkbox name='is_bcast' tabindex=3 checked></td>\n";
2113 echo "</td><td class=tdcenter>";
2114 printImageHREF ('CREATE', 'Add a new network', TRUE, 4);
2115 echo "</td></tr>\n";
2116 echo "</form></table><br><br>\n";
2119 startPortlet ("Manage existing");
2120 echo "<table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
2121 $addrspaceList = getAddressspaceList();
2122 echo "<tr><th> </th><th>prefix</th><th>name</th><th>utilization</th></tr>";
2123 foreach ($addrspaceList as $iprange)
2125 $netdata = getIPv4Network ($iprange['id']);
2126 $usedips = count ($netdata['addrlist']);
2127 $totalips = ($netdata['ip_bin'] |
$netdata['mask_bin_inv']) - ($netdata['ip_bin'] & $netdata['mask_bin']) +
1;
2128 echo "<tr valign=top><td>";
2131 echo "<a href='${root}process.php?op=delIPv4Prefix&page=${pageno}&tab=${tabno}&id=${iprange['id']}'>";
2132 printImageHREF ('delete', 'Delete this IP range');
2136 printImageHREF ('nodelete', 'There are IP addresses allocated or reserved');
2137 echo "</td>\n<td class=tdleft><a href='${root}?page=iprange&id=${iprange['id']}'>";
2138 echo "${netdata['ip']}/${netdata['mask']}</a></td><td class=tdleft>${netdata['name']}";
2139 echo "</td><td class=tdcenter>";
2140 renderProgressBar ($usedips / $totalips);
2141 echo "<br><small>${usedips}/${totalips}</small></td></tr>\n";
2147 function renderIPv4Network ($id)
2149 global $root, $pageno, $tabno, $aac2;
2150 $netmaskbylen = array
2152 32 => '255.255.255.255',
2153 31 => '255.255.255.254',
2154 30 => '255.255.255.252',
2155 29 => '255.255.255.248',
2156 28 => '255.255.255.240',
2157 27 => '255.255.255.224',
2158 26 => '255.255.255.192',
2159 25 => '255.255.255.128',
2160 24 => '255.255.255.0',
2161 23 => '255.255.254.0',
2162 22 => '255.255.252.0',
2163 21 => '255.255.248.0',
2164 20 => '255.255.240.0',
2165 19 => '255.255.224.0',
2166 18 => '255.255.192.0',
2167 17 => '255.255.128.0',
2168 16 => '255.255.0.0',
2169 15 => '255.254.0.0',
2170 14 => '255.252.0.0',
2171 13 => '255.248.0.0',
2172 12 => '255.240.0.0',
2173 11 => '255.224.0.0',
2174 10 => '255.192.0.0',
2185 $wildcardbylen = array
2202 17 => '0.0.127.255',
2204 15 => '0.1.255.255',
2205 14 => '0.3.255.255',
2206 13 => '0.7.255.255',
2207 12 => '0.15.255.255',
2208 11 => '0.31.255.255',
2209 10 => '0.63.255.255',
2210 9 => '0.127.255.255',
2211 8 => '0.255.255.255',
2212 7 => '1.255.255.255',
2213 6 => '3.255.255.255',
2214 5 => '7.255.255.255',
2215 4 => '15.255.255.255',
2216 3 => '31.255.255.255',
2217 2 => '63.255.255.255',
2218 1 => '127.255.255.255'
2220 $maxperpage = getConfigVar ('IPV4_ADDRS_PER_PAGE');
2221 if (isset($_REQUEST['pg']))
2222 $page = $_REQUEST['pg'];
2226 $range = getIPv4Network ($id);
2227 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
2228 echo "<tr><td colspan=2 align=center><h1>${range['ip']}/${range['mask']}</h1><h2>${range['name']}</h2></td></tr>\n";
2230 echo "<tr><td class=pcleft width='50%'>";
2231 startPortlet ('summary');
2232 $total = ($range['ip_bin'] |
$range['mask_bin_inv']) - ($range['ip_bin'] & $range['mask_bin']) +
1;
2233 $used = count ($range['addrlist']);
2234 echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
2235 echo "<tr><th width='50%' class=tdright>Utilization:</th><td class=tdleft>";
2236 renderProgressBar ($used/$total);
2237 echo " ${used}/${total}</td></tr>\n";
2238 echo "<tr><th width='50%' class=tdright>Netmask:</th><td class=tdleft>";
2239 echo $netmaskbylen[$range['mask']];
2240 echo "</td></tr>\n";
2241 echo "<tr><th width='50%' class=tdright>Wildcard bits:</th><td class=tdleft>";
2242 echo $wildcardbylen[$range['mask']];
2243 echo "</td></tr>\n";
2244 printTagTRs ("${root}?page=ipv4space&");
2245 echo "</table><br>\n";
2249 echo "<td class=pcright>";
2250 startPortlet ('details');
2251 $startip = $range['ip_bin'] & $range['mask_bin'];
2252 $endip = $range['ip_bin'] |
$range['mask_bin_inv'];
2253 $realstartip = $startip;
2254 $realendip = $endip;
2256 if($endip - $startip > $maxperpage)
2258 $numpages = ($endip - $startip)/$maxperpage;
2259 $startip = $startip +
$page * $maxperpage;
2260 $endip = $startip +
$maxperpage-1;
2264 echo '<h3>' . long2ip ($startip) . ' ~ ' . long2ip ($endip) . '</h3>';
2265 for ($i=0; $i<$numpages; $i++
)
2270 echo "<a href='${root}?page=${pageno}&tab=${tabno}&id=$id&pg=$i'>$i</a> ";
2274 echo "<table class='widetable' border=0 cellspacing=0 cellpadding=5 align='center' width='100%'>\n";
2275 echo "<tr><th>Address</th><th>Name</th><th>Allocation</th></tr>\n";
2278 for ($ip = $startip; $ip <= $endip; $ip++
) :
2279 if (isset ($_REQUEST['hl_ipv4_addr']) and ip2long ($_REQUEST['hl_ipv4_addr']) == $ip)
2280 $secondstyle = 'tdleft port_highlight';
2282 $secondstyle = 'tdleft';
2283 if (!isset ($range['addrlist'][$ip]))
2285 echo "<tr><td class=tdleft><a href='${root}?page=ipaddress&ip=" . long2ip ($ip) . "'>" . long2ip ($ip);
2286 echo "</a></td><td class='${secondstyle}'> </td><td class='${secondstyle}'> </td></tr>\n";
2289 $addr = $range['addrlist'][$ip];
2290 echo "<tr class='${addr['class']}'>";
2292 echo "<td class=tdleft><a href='${root}?page=ipaddress&ip=${addr['ip']}'>${addr['ip']}</a></td>";
2293 echo "<td class='${secondstyle}'>${addr['name']}</td><td class='${secondstyle}'>";
2296 if ( $addr['reserved'] == 'yes')
2298 echo "<strong>RESERVED</strong> ";
2301 foreach ($range['addrlist'][$ip]['allocs'] as $ref)
2303 echo $delim . $aac2[$ref['type']];
2304 echo "<a href='${root}?page=object&object_id=${ref['object_id']}";
2305 echo "&hl_ipv4_addr=${addr['ip']}'>";
2306 echo $ref['name'] . (empty ($ref['name']) ?
'' : '@');
2307 echo "${ref['object_name']}</a>";
2315 foreach ($range['addrlist'][$ip]['lblist'] as $ref)
2319 echo "${delim}<a href='${root}?page=object&object_id=${ref['object_id']}'>";
2320 echo "${ref['object_name']}</a>:<a href='${root}?page=ipv4vs&vs_id=${ref['vs_id']}'>";
2321 echo "${ref['vport']}/${ref['proto']}</a>→";
2329 foreach ($range['addrlist'][$ip]['rslist'] as $ref)
2333 echo "${delim}→${ref['rsport']}@<a href='${root}?page=ipv4rsp&pool_id=${ref['rspool_id']}'>";
2334 echo "${ref['rspool_name']}</a>";
2337 echo "</td></tr>\n";
2343 echo "</td></tr></table>\n";
2346 function renderIPv4NetworkProperties ($id)
2348 global $root, $pageno, $tabno;
2349 showMessageOrError();
2350 $netdata = getIPv4NetworkInfo ($id);
2351 echo "<center><h1>${netdata['ip']}/${netdata['mask']}</h1></center>\n";
2352 echo "<table border=0 cellpadding=10 cellpadding=1 align='center'>\n";
2353 echo "<form action='${root}process.php'><input type=hidden name=op value=editRange>";
2354 echo "<input type=hidden name=page value='${pageno}'>\n";
2355 echo "<input type=hidden name=tab value='${tabno}'>\n";
2356 echo "<input type=hidden name=id value='${id}'>";
2357 echo "<tr><td class='tdright'>Name:</td><td class='tdleft'><input type=text name=name size=20 value='${netdata['name']}'></tr>";
2358 echo "<tr><td colspan=2 class=tdcenter>";
2359 printImageHREF ('SAVE', 'Save changes', TRUE);
2360 echo "</td></form></tr></table>\n";
2364 function renderIPv4Address ($dottedquad)
2367 $address = getIPv4Address ($dottedquad);
2368 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
2369 echo "<tr><td colspan=2 align=center><h1>${dottedquad}</h1></td></tr>\n";
2370 if (!empty ($address['name']))
2371 echo "<tr><td colspan=2 align=center><h2>${address['name']}</h2></td></tr>\n";
2373 echo "<tr><td class=pcleft>";
2374 startPortlet ('summary');
2375 echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
2376 echo "<tr><th width='50%' class=tdright>Allocations:</th><td class=tdleft>" . count ($address['bonds']) . "</td></tr>\n";
2377 echo "<tr><th width='50%' class=tdright>Originated NAT connections:</th><td class=tdleft>" . count ($address['outpf']) . "</td></tr>\n";
2378 echo "<tr><th width='50%' class=tdright>Arriving NAT connections:</th><td class=tdleft>" . count ($address['inpf']) . "</td></tr>\n";
2379 echo "<tr><th width='50%' class=tdright>SLB virtual services:</th><td class=tdleft>" . count ($address['vslist']) . "</td></tr>\n";
2380 echo "<tr><th width='50%' class=tdright>SLB real servers:</th><td class=tdleft>" . count ($address['rslist']) . "</td></tr>\n";
2382 echo "</table><br>\n";
2386 echo "<td class=pcright>";
2388 if (!empty ($address['class']))
2390 startPortlet ('allocations');
2391 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center' width='100%'>\n";
2392 echo "<tr><th>object</th><th>OS interface</th><th>allocation type</th></tr>\n";
2393 $class = $address['class'];
2394 // render all allocation records for this address the same way
2395 if ($address['reserved'] == 'yes')
2396 echo "<tr class='${class}'><td colspan=2> </td><td class=tdleft><strong>RESERVED</strong></td></tr>";
2397 foreach ($address['allocs'] as $bond)
2399 if (isset ($_REQUEST['hl_object_id']) and $_REQUEST['hl_object_id'] == $bond['object_id'])
2400 $secondclass = 'tdleft port_highlight';
2402 $secondclass = 'tdleft';
2403 echo "<tr class='$class'><td class=tdleft><a href='${root}?page=object&object_id=${bond['object_id']}";
2404 echo "&hl_ipv4_addr=${dottedquad}'>${bond['object_name']}</td><td class='${secondclass}'>${bond['name']}</td><td class='${secondclass}'><strong>";
2405 echo $aat[$bond['type']];
2406 echo "</strong></td></tr>\n";
2408 echo "</table><br><br>";
2412 if (count ($address['lblist']))
2414 startPortlet ('Virtual services (' . count ($address['lblist']) . ')');
2415 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center' width='100%'>\n";
2416 echo "<tr><th>VS</th><th>name</th></tr>\n";
2417 foreach ($address['lblist'] as $vsinfo)
2419 echo "<tr><td class=tdleft><a href='${root}?page=ipv4vs&vs_id=${vsinfo['vs_id']}'>";
2420 echo buildVServiceName ($vsinfo) . "</a></td><td class=tdleft>";
2421 echo $vsinfo['name'] . "</td></tr>\n";
2423 echo "</table><br><br>";
2427 if (count ($address['rslist']))
2429 startPortlet ('Real servers (' . count ($address['rslist']) . ')');
2430 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center' width='100%'>\n";
2431 echo "<tr><th> </th><th>port</th><th>RS pool</th></tr>\n";
2432 foreach ($address['rslist'] as $rsinfo)
2435 if ($rsinfo['inservice'] == 'yes')
2436 printImageHREF ('inservice', 'in service');
2438 printImageHREF ('notinservice', 'NOT in service');
2439 echo "</td><td class=tdleft>${rsinfo['rsport']}</td><td class=tdleft><a href='${root}?page=ipv4rsp&pool_id=${rsinfo['rspool_id']}'>";
2440 echo $rsinfo['rspool_name'] . "</a></td></tr>\n";
2442 echo "</table><br><br>";
2446 if (count ($address['outpf']))
2448 startPortlet ('departing NAT rules');
2449 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center' width='100%'>\n";
2450 echo "<tr><th>proto</th><th>from</th><th>to</th><th>comment</th></tr>\n";
2451 foreach ($address['outpf'] as $rule)
2452 echo "<tr><td>${rule['proto']}</td><td>${rule['localip']}:${rule['localport']}</td><td>${rule['remoteip']}:${rule['localport']}</td><td>${rule['description']}</td></tr>";
2457 if (count ($address['inpf']))
2459 startPortlet ('arriving NAT rules');
2460 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center' width='100%'>\n";
2461 echo "<tr><th>proto</th><th>from</th><th>to</th><th>comment</th></tr>\n";
2462 foreach ($address['inpf'] as $rule)
2463 echo "<tr><td>${rule['proto']}</td><td>${rule['localip']}:${rule['localport']}</td><td>${rule['remoteip']}:${rule['localport']}</td><td>${rule['description']}</td></tr>";
2472 function renderIPv4AddressProperties ($dottedquad)
2474 global $pageno, $tabno, $root;
2475 showMessageOrError();
2476 $address = getIPv4Address ($dottedquad);
2477 echo "<center><h1>$dottedquad</h1></center>\n";
2478 startPortlet ('update');
2479 echo "<table border=0 cellpadding=10 cellpadding=1 align='center'>\n";
2480 echo "<form action='${root}process.php'><input type=hidden name=op value=editAddress>";
2481 echo "<input type=hidden name=page value='${pageno}'>\n";
2482 echo "<input type=hidden name=tab value='${tabno}'>\n";
2483 echo "<input type=hidden name=ip value='${dottedquad}'>";
2484 echo "<tr><td class='tdright'>Name:</td><td class='tdleft'><input type=text name=name size=20 value='${address['name']}'></tr>";
2485 echo "<td class='tdright'>Reserved:</td><td class='tdleft'><input type=checkbox name=reserved size=20 ";
2486 echo ($address['reserved']=='yes') ?
'checked' : '';
2487 echo "></tr><tr><td colspan=2 class='tdcenter'>";
2488 printImageHREF ('SAVE', 'Save changes', TRUE);
2489 echo "</td></form></tr></table>\n";
2491 if (empty ($address['name']) and $address['reserved'] == 'no')
2493 startPortlet ('release');
2494 echo "<form action='${root}process.php?page=${pageno}&tab=${tabno}&op=editAddress' method=post>";
2495 echo "<input type=hidden name=ip value='${dottedquad}'>";
2496 echo "<input type=hidden name=name value=''>";
2497 echo "<input type=hidden name=reserved value=''>";
2498 echo "<input type=submit value='release'></form>";
2502 function renderIPv4AddressAllocations ($dottedquad)
2504 showMessageOrError();
2505 global $pageno, $tabno, $root, $aat;
2507 $address = getIPv4Address ($dottedquad);
2508 $class = $address['class'];
2509 echo "<center><h1>${dottedquad}</h1></center>\n";
2510 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
2511 echo "<tr><th> </th><th>object</th><th>OS interface</th><th>allocation type</th><th> </th></tr>\n";
2513 if ($address['reserved'] == 'yes')
2514 echo "<tr class='${class}'><td colspan=3> </td><td class=tdleft><strong>RESERVED</strong></td><td> </td></tr>";
2515 foreach ($address['allocs'] as $bond)
2517 echo "<tr class='$class'><form action='${root}process.php'>";
2518 echo "<input type=hidden name=op value='updIPv4Allocation'>";
2519 echo "<input type=hidden name=page value='${pageno}'>";
2520 echo "<input type=hidden name=tab value='${tabno}'>";
2521 echo "<input type=hidden name=ip value='$dottedquad'>";
2522 echo "<input type=hidden name=object_id value='${bond['object_id']}'>";
2523 echo "<td><a href='${root}process.php?op=delIPv4Allocation&page=${pageno}&tab=${tabno}&ip=${dottedquad}&object_id=${bond['object_id']}'>";
2524 printImageHREF ('delete', 'Unallocate address');
2526 echo "<td><a href='${root}?page=object&object_id=${bond['object_id']}&hl_ipv4_addr=${dottedquad}'>${bond['object_name']}</td>";
2527 echo "<td><input type='text' name='bond_name' value='${bond['name']}' size=10></td><td>";
2528 printSelect ($aat, 'bond_type', $bond['type']);
2530 printImageHREF ('save', 'Save changes', TRUE);
2531 echo "</td></form></tr>\n";
2533 echo "<form action='${root}process.php'><input type='hidden' name='op' value='addIPv4Allocation'>";
2534 echo "<input type=hidden name=page value='${pageno}'>\n";
2535 echo "<input type=hidden name=tab value='${tabno}'>\n";
2536 echo "<input type='hidden' name='ip' value='${dottedquad}'>";
2538 printImageHREF ('add', 'new allocation', TRUE);
2539 echo "</td><td><select name='object_id'>";
2541 foreach (explode (',', getConfigVar ('IPV4_PERFORMERS')) as $type)
2542 foreach (getNarrowObjectList ($type) as $object)
2543 echo "<option value='${object['id']}'>${object['dname']}</option>";
2545 echo "</select></td><td><input type='text' name='bond_name' value='' size=10></td><td>";
2546 printSelect ($aat, 'bond_type');
2547 echo "</td><td> </td></form></tr>";
2548 echo "</table><br><br>";
2552 function renderNATv4ForObject ($object_id = 0)
2554 global $pageno, $tabno, $root;
2556 $info = getObjectInfo ($object_id);
2557 $forwards = getNATv4ForObject ($object_id);
2558 $addresses = getObjectAddresses ($object_id);
2559 showMessageOrError();
2560 echo "<center><h2>locally performed NAT</h2></center>";
2562 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
2563 echo "<tr><th></th><th>Match endpoint</th><th>Translate to</th><th>Target object</th><th>Comment</th><th> </th></tr>\n";
2565 foreach ($forwards['out'] as $pf)
2569 foreach ($addresses as $addr)
2570 if ($addr['ip'] == $pf['localip'])
2573 $name = $addr['name'];
2577 echo "<tr class='$class'>";
2578 echo "<td><a href='${root}process.php?op=delNATv4Rule&localip=${pf['localip']}&localport=${pf['localport']}&remoteip=${pf['remoteip']}&remoteport=${pf['remoteport']}&proto=${pf['proto']}&object_id=$object_id&page=${pageno}&tab=${tabno}'>";
2579 printImageHREF ('delete', 'Delete NAT rule');
2581 echo "<td>${pf['proto']}/${name}: <a href='${root}?page=ipaddress&tab=default&ip=${pf['localip']}'>${pf['localip']}</a>:${pf['localport']}";
2582 if (!empty ($pf['local_addr_name']))
2583 echo ' (' . $pf['local_addr_name'] . ')';
2585 echo "<td><a href='${root}?page=ipaddress&tab=default&ip=${pf['remoteip']}'>${pf['remoteip']}</a>:${pf['remoteport']}</td>";
2587 $address = getIPv4Address ($pf['remoteip']);
2589 echo "<td class='description'>";
2590 if (count ($address['allocs']))
2591 foreach ($address['allocs'] as $bond)
2592 echo "<a href='${root}?page=object&tab=default&object_id=${bond['object_id']}'>${bond['object_name']}(${bond['name']})</a> ";
2593 elseif (!empty ($pf['remote_addr_name']))
2594 echo '(' . $pf['remote_addr_name'] . ')';
2595 echo "</td><form action='${root}process.php'><input type=hidden name=op value=updNATv4Rule><input type=hidden name=page value='${pageno}'>";
2596 echo "<input type=hidden name=tab value='${tabno}'><input type='hidden' name='object_id' value='$object_id'>";
2597 echo "<input type='hidden' name='localip' value='${pf['localip']}'><input type='hidden' name='localport' value='${pf['localport']}'>";
2598 echo "<input type='hidden' name='remoteip' value='${pf['remoteip']}'><input type='hidden' name='remoteport' value='${pf['remoteport']}'>";
2599 echo "<input type='hidden' name='proto' value='${pf['proto']}'><td class='description'>";
2600 echo "<input type='text' name='description' value='${pf['description']}'></td><td>";
2601 printImageHREF ('save', 'Save changes', TRUE);
2602 echo "</td></form></tr>";
2604 echo "<form action='${root}process.php'><input type='hidden' name=op value=addNATv4Rule>";
2605 echo "<input type='hidden' name='object_id' value='$object_id'>";
2606 echo "<input type=hidden name=page value='${pageno}'>\n";
2607 echo "<input type=hidden name=tab value='${tabno}'>\n";
2608 echo "<tr align='center'><td>";
2609 printImageHREF ('add', 'Add new NAT rule', TRUE);
2611 printSelect (array ('TCP' => 'TCP', 'UDP' => 'UDP'), 'proto');
2612 echo "<select name='localip' tabindex=1>";
2614 foreach ($addresses as $addr)
2615 echo "<option value='${addr['ip']}'>" . (empty ($addr['name']) ?
'' : "${addr['name']}: ") .
2616 "${addr['ip']}" . (empty ($addr['address_name']) ?
'' : " (${addr['address_name']})") . "</option>";
2618 echo "</select>:<input type='text' name='localport' size='4' tabindex=2></td>";
2619 echo "<td><input type='text' name='remoteip' id='remoteip' size='10' tabindex=3>";
2620 echo "<a href='javascript:;' onclick='window.open(\"${root}/find_object_ip_helper.php\", \"findobjectip\", \"height=700, width=400, location=no, menubar=no, resizable=yes, scrollbars=no, status=no, titlebar=no, toolbar=no\");'>";
2621 printImageHREF ('find', 'Find object');
2623 echo ":<input type='text' name='remoteport' size='4' tabindex=4></td><td></td>";
2624 echo "<td colspan=1><input type='text' name='description' size='20' tabindex=5></td><td> </td></tr>";
2627 echo "</table><br><br>";
2629 echo "<center><h2>arriving NAT connections</h2></center>";
2630 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
2631 echo "<tr><th></th><th>Source</th><th>Source objects</th><th>Target</th><th>Description</th></tr>\n";
2633 foreach ($forwards['in'] as $pf)
2635 echo "<tr><td><a href='${root}process.php?op=delNATv4Rule&localip=${pf['localip']}&localport=${pf['localport']}&remoteip=${pf['remoteip']}&remoteport=${pf['remoteport']}&proto=${pf['proto']}&object_id=${pf['object_id']}&page=${pageno}&tab=${tabno}'>";
2636 printImageHREF ('delete', 'Delete NAT rule');
2638 echo "<td>${pf['proto']}/<a href='${root}?page=ipaddress&tab=default&ip=${pf['localip']}'>${pf['localip']}</a>:${pf['localport']}</td>";
2639 echo "<td class='description'><a href='${root}?page=object&tab=default&object_id=${pf['object_id']}'>${pf['object_name']}</a>";
2640 echo "</td><td><a href='${root}?page=ipaddress&tab=default&ip=${pf['remoteip']}'>${pf['remoteip']}</a>:${pf['remoteport']}</td>";
2641 echo "<td class='description'>${pf['description']}</td></tr>";
2644 echo "</table><br><br>";
2647 function renderAddMultipleObjectsForm ()
2649 global $root, $pageno, $tabno, $nextorder;
2652 $global_type_id = 0;
2654 $asset_no = array();
2655 $keepvalues1 = $keepvalues2 = FALSE;
2657 // Look for current submit.
2658 if (isset ($_REQUEST['got_fast_data']))
2660 $taglist = isset ($_REQUEST['taglist']) ?
$_REQUEST['taglist'] : array();
2661 $keepvalues1 = TRUE;
2662 $max = getConfigVar ('MASSCOUNT');
2663 for ($i = 0; $i < $max; $i++
)
2665 if (!isset ($_REQUEST["${i}_object_type_id"]))
2667 $log[] = array ('code' => 'error', 'message' => "Submitted form is invalid at line " . $i +
1);
2670 assertUIntArg ("${i}_object_type_id", __FUNCTION__
, TRUE);
2671 assertStringArg ("${i}_object_name", __FUNCTION__
, TRUE);
2672 assertStringArg ("${i}_object_label", __FUNCTION__
, TRUE);
2673 assertStringArg ("${i}_object_asset_no", __FUNCTION__
, TRUE);
2674 assertStringArg ("${i}_object_barcode", __FUNCTION__
, TRUE);
2675 $type_id[$i] = $_REQUEST["${i}_object_type_id"];
2676 // Save user input for possible rendering.
2677 $name[$i] = $_REQUEST["${i}_object_name"];
2678 $label[$i] = $_REQUEST["${i}_object_label"];
2679 $asset_no[$i] = $_REQUEST["${i}_object_asset_no"];
2680 $barcode[$i] = $_REQUEST["${i}_object_barcode"];
2682 // It's better to skip silently, than to print a notice.
2683 if ($type_id[$i] == 0)
2685 if (commitAddObject ($name[$i], $label[$i], $barcode[$i], $type_id[$i], $asset_no[$i], $taglist) === TRUE)
2686 $log[] = array ('code' => 'success', 'message' => "Added new object '${name[$i]}'");
2688 $log[] = array ('code' => 'error', 'message' => __FUNCTION__
. ': commitAddObject() failed');
2691 elseif (isset ($_REQUEST['got_very_fast_data']))
2693 $taglist = isset ($_REQUEST['taglist']) ?
$_REQUEST['taglist'] : array();
2694 $keepvalues2 = TRUE;
2695 assertUIntArg ('global_type_id', __FUNCTION__
, TRUE);
2696 assertStringArg ('namelist', __FUNCTION__
, TRUE);
2697 $global_type_id = $_REQUEST['global_type_id'];
2698 if ($global_type_id == 0)
2700 if (!empty ($_REQUEST['namelist']))
2701 $log[] = array ('code' => 'error', 'message' => 'Object type is not selected, check the form below');
2703 $log[] = array ('code' => 'error', 'message' => 'Empty form has been ignored. Cheers.');
2707 // The name extractor below was stolen from ophandlers.php:addMultiPorts()
2708 $names1 = explode ('\n', $_REQUEST['namelist']);
2710 foreach ($names1 as $line)
2712 $parts = explode ('\r', $line);
2714 if (empty ($parts[0]))
2717 $names2[] = rtrim ($parts[0]);
2719 foreach ($names2 as $cname)
2720 if (commitAddObject ($cname, '', '', $global_type_id, '', $taglist) === TRUE)
2721 $log[] = array ('code' => 'success', 'message' => "Added new object '${cname}'");
2723 $log[] = array ('code' => 'error', 'message' => "Could not add '${cname}'");
2728 // Render a form for the next.
2729 $typelist = getObjectTypeList();
2730 $typelist[0] = 'select type...';
2732 startPortlet ('Distinct types, same tags');
2733 $max = getConfigVar ('MASSCOUNT');
2734 echo "<form name=fastform method=post action='${root}?page=${pageno}&tab=${tabno}'>";
2735 echo '<table border=0 align=center>';
2736 echo "<tr><th>Object type</th><th>Common name</th><th>Visible label</th>";
2737 echo "<th>Asset tag</th><th>Barcode</th><th>Tags</th></tr>\n";
2738 // If a user forgot to select object type on input, we keep his
2739 // previous input in the form.
2740 for ($i = 0; $i < $max; $i++
)
2743 // Don't employ DEFAULT_OBJECT_TYPE to avoid creating ghost records for pre-selected empty rows.
2744 printSelect ($typelist, "${i}_object_type_id", 0);
2746 echo "<td><input type=text size=30 name=${i}_object_name";
2747 if ($keepvalues1 and isset ($name[$i]) and (!isset ($type_id[$i]) or $type_id[$i] == 0))
2748 echo " value='${name[$i]}'";
2750 echo "<td><input type=text size=30 name=${i}_object_label";
2751 if ($keepvalues1 and isset ($label[$i]) and (!isset ($type_id[$i]) or $type_id[$i] == 0))
2752 echo " value='${label[$i]}'";
2754 echo "<td><input type=text size=20 name=${i}_object_asset_no";
2755 if ($keepvalues1 and isset ($asset_no[$i]) and (!isset ($type_id[$i]) or $type_id[$i] == 0))
2756 echo " value='${asset_no[$i]}'";
2758 echo "<td><input type=text size=10 name=${i}_object_barcode";
2759 if ($keepvalues1 and isset ($barcode[$i]) and (!isset ($type_id[$i]) or $type_id[$i] == 0))
2760 echo " value='${barcode[$i]}'";
2764 echo "<td valign=top rowspan=${max}>";
2770 echo "<tr><td class=submit colspan=5><input type=submit name=got_fast_data value='Go!'></td></tr>\n";
2771 echo "</form></table>\n";
2774 startPortlet ('Same type, same tags');
2775 echo "<form name=veryfastform method=post action='${root}?page=${pageno}&tab=${tabno}'>";
2776 echo "<table border=0 align=center><tr><th>names</th><th>type</th></tr>";
2777 echo "<tr><td rowspan=3><textarea name=namelist cols=40 rows=25>\n";
2778 if ($keepvalues2 and $global_type_id == 0)
2779 echo $_REQUEST['namelist'];
2780 echo "</textarea></td><td valign=top>";
2781 printSelect ($typelist, "global_type_id", getConfigVar ('DEFAULT_OBJECT_TYPE'));
2783 echo "<tr><th>Tags</th></tr>";
2784 echo "<tr><td valign=top>";
2787 echo "<tr><td colspan=2><input type=submit name=got_very_fast_data value='Go!'></td></tr></table>\n";
2792 function printGreeting ()
2794 global $remote_username, $accounts, $root;
2795 $account = $accounts[$remote_username];
2796 echo "Hello, ${account['user_realname']}. This is RackTables " . CODE_VERSION
. ". Click <a href='${root}?logout'>here</a> to logout.";
2799 function renderSearchResults ()
2801 global $remote_username, $root;
2802 $terms = trim ($_REQUEST['q']);
2805 showError ('Search string cannot be empty.', __FUNCTION__
);
2808 if (!permitted ('objects', 'default'))
2810 showError ('You are not authorized for viewing information about objects.', __FUNCTION__
);
2814 // If we search for L2 address, we can either find one or find none.
2817 preg_match ('/^[0-9a-f][0-9a-f]?:[0-9a-f][0-9a-f]?:[0-9a-f][0-9a-f]?:[0-9a-f][0-9a-f]?:[0-9a-f][0-9a-f]?:[0-9a-f][0-9a-f]?$/i', $terms) or
2818 preg_match ('/^[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]$/i', $terms) or
2819 preg_match ('/^[0-9a-f][0-9a-f][0-9a-f][0-9a-f].[0-9a-f][0-9a-f][0-9a-f][0-9a-f].[0-9a-f][0-9a-f][0-9a-f][0-9a-f]$/i', $terms) or
2820 // STP bridge ID: bridge priotity + port MAC address. Cut off first 4 chars and look for MAC address.
2821 preg_match ('/^[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]$/i', $terms)
2823 // Search for L2 address.
2825 $terms = str_replace ('.', '', $terms);
2826 $terms = str_replace (':', '', $terms);
2827 $terms = substr ($terms, -12);
2828 $result = searchByl2address ($terms);
2829 if ($result !== NULL)
2833 $summary['port'][] = $result;
2836 elseif (preg_match ('/^[0-9][0-9]?[0-9]?\.[0-9]?[0-9]?[0-9]?\.[0-9][0-9]?[0-9]?\.[0-9]?[0-9]?[0-9]?$/i', $terms))
2837 // Search for IP address.
2839 if (NULL !== getIPv4AddressNetworkId ($terms))
2842 $lasthit = 'ipv4address1';
2843 $summary['ipv4address1'][] = $terms;
2847 // Search for objects, addresses, networks, virtual services and RS pools by their description.
2849 $tmp = getObjectSearchResults ($terms);
2852 $nhits +
= count ($tmp);
2853 $lasthit = 'object';
2854 $summary['object'] = $tmp;
2856 $tmp = getIPv4AddressSearchResult ($terms);
2859 $nhits +
= count ($tmp);
2860 $lasthit = 'ipv4address2';
2861 $summary['ipv4address2'] = $tmp;
2863 $tmp = getIPv4PrefixSearchResult ($terms);
2866 $nhits +
= count ($tmp);
2867 $lasthit = 'ipv4network';
2868 $summary['ipv4network'] = $tmp;
2870 $tmp = getIPv4RSPoolSearchResult ($terms);
2873 $nhits +
= count ($tmp);
2874 $lasthit = 'ipv4rspool';
2875 $summary['ipv4rspool'] = $tmp;
2877 $tmp = getIPv4VServiceSearchResult ($terms);
2880 $nhits +
= count ($tmp);
2881 $lasthit = 'ipv4vs';
2882 $summary['ipv4vs'] = $tmp;
2884 $tmp = getAccountSearchResult ($terms);
2887 $nhits +
= count ($tmp);
2889 $summary['user'] = $tmp;
2893 echo "<center><h2>Nothing found for '${terms}'</h2></center>";
2894 elseif ($nhits == 1)
2896 $record = current ($summary[$lasthit]);
2900 echo "<script language='Javascript'>document.location='${root}?page=object";
2901 echo "&hl_port_id=" . $record['port_id'];
2902 echo "&object_id=" . $record['object_id'] . "';//</script>";
2904 case 'ipv4address1':
2905 echo "<script language='Javascript'>document.location='${root}?page=ipaddress";
2906 echo "&ip=${record}";
2907 echo "';//</script>";
2909 case 'ipv4address2':
2910 echo "<script language='Javascript'>document.location='${root}?page=ipaddress";
2911 echo "&ip=${record['ip']}";
2912 echo "';//</script>";
2915 echo "<script language='Javascript'>document.location='${root}?page=iprange";
2916 echo "&id=${record['id']}";
2917 echo "';//</script>";
2920 echo "<script language='Javascript'>document.location='${root}?page=object&object_id=${record['id']}';//</script>";
2923 echo "<script language='Javascript'>document.location='${root}?page=ipv4rsp&pool_id=${record['pool_id']}';//</script>";
2926 echo "<script language='Javascript'>document.location='${root}?page=ipv4vs&vs_id=${record['id']}';//</script>";
2929 echo "<script language='Javascript'>document.location='${root}?page=user&user_id=${record['user_id']}';//</script>";
2938 echo "<center><h2>${nhits} result(s) found for '${terms}'</h2></center>";
2939 foreach ($summary as $where => $what)
2943 startPortlet ("<a href='${root}?page=objects'>Objects</a>");
2944 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
2945 echo '<tr><th>Common name</th><th>Visible label</th><th>Asset tag</th><th>barcode</th></tr>';
2946 foreach ($what as $obj)
2948 echo "<tr class=row_${order}><td><a href=\"${root}?page=object&object_id=${obj['id']}\">${obj['dname']}</a></td>";
2949 echo "<td>${obj['label']}</td>";
2950 echo "<td>${obj['asset_no']}</td>";
2951 echo "<td>${obj['barcode']}</td></tr>";
2952 $order = $nextorder[$order];
2958 startPortlet ("<a href='${root}?page=ipv4space'>IPv4 networks</a>");
2959 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
2960 echo '<tr><th>network</th><th>name/tags</th></tr>';
2961 foreach ($what as $net)
2963 $prefixtags = loadIPv4PrefixTags ($net['id']);
2964 echo "<tr class=row_${order} valign=top><td class=tdleft><a href='${root}?page=iprange&id=${net['id']}'>${net['ip']}";
2965 echo '/' . $net['mask'] . '</a></td>';
2966 echo "<td class=tdleft>${net['name']}";
2967 if (count ($prefixtags))
2970 echo serializeTags ($prefixtags, "${root}?page=ipv4space&");
2973 $order = $nextorder[$order];
2978 case 'ipv4address2':
2979 startPortlet ('IPv4 addresses');
2980 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
2981 echo '<tr><th>Address</th><th>Descritpion</th></tr>';
2982 foreach ($what as $addr)
2984 echo "<tr class=row_${order}><td class=tdleft><a href='${root}?page=ipaddress&ip=${addr['ip']}'>";
2985 echo "${addr['ip']}</a></td>";
2986 echo "<td class=tdleft>${addr['name']}</td></tr>";
2987 $order = $nextorder[$order];
2993 startPortlet ("<a href='${root}?page=ipv4rsplist'>RS pools</a>");
2994 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
2995 foreach ($what as $rspool)
2997 echo "<tr class=row_${order}><td class=tdleft><a href='${root}?page=ipv4rsp&pool_id=${rspool['pool_id']}'>";
2998 echo buildRSPoolName ($rspool);
2999 echo "</a></td></tr>";
3000 $order = $nextorder[$order];
3006 startPortlet ("<a href='${root}?page=ipv4vslist'>Virtual services</a>");
3007 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
3008 echo '<tr><th>VS</th><th>Descritpion</th></tr>';
3009 foreach ($what as $vs)
3011 echo "<tr class=row_${order}><td class=tdleft><a href='${root}?page=ipv4vs&vs_id=${vs['id']}'>";
3012 echo buildVServiceName ($vs);
3013 echo "</a></td><td class=tdleft>${vs['name']}</td></tr>";
3014 $order = $nextorder[$order];
3020 startPortlet ("<a href='${root}?page=userlist'>Users</a>");
3021 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
3022 echo '<tr><th>username</th><th>realname</th></tr>';
3023 foreach ($what as $item)
3025 echo "<tr class=row_${order}><td class=tdleft><a href='${root}?page=user&user_id=${item['user_id']}'>";
3026 echo $item['user_name'];
3027 echo "</a></td><td class=tdleft>${item['user_realname']}</td></tr>";
3028 $order = $nextorder[$order];
3037 // This function prints a table of checkboxes to aid the user in toggling mount atoms
3038 // from one state to another. The first argument is rack data as
3039 // produced by getRackData(), the second is the value used for the 'unckecked' state
3040 // and the third is the value used for 'checked' state.
3042 // for mounting an object: printAtomGrid ($data, 'F', 'T')
3043 // for changing rack design: printAtomGrid ($data, 'A', 'F')
3044 // for adding rack problem: printAtomGrid ($data, 'F', 'U')
3045 // for adding object problem: printAtomGrid ($data, 'T', 'W')
3047 function renderAtomGrid ($data)
3049 $rack_id = $data['id'];
3050 for ($unit_no = $data['height']; $unit_no > 0; $unit_no--)
3052 echo "<tr><th>${unit_no}</th>";
3053 for ($locidx = 0; $locidx < 3; $locidx++
)
3055 $state = $data[$unit_no][$locidx]['state'];