cb1ff9aee460def19cc0d20d86219ce20b668391
[racktables] / inc / interface.php
1 <?php
2 /*
3 *
4 * This file contains frontend functions for RackTables.
5 *
6 */
7
8 // Interface function's special.
9 $nextorder['odd'] = 'even';
10 $nextorder['even'] = 'odd';
11
12 // address allocation type
13 $aat = array
14 (
15 'regular' => 'Connected',
16 'virtual' => 'Loopback',
17 'shared' => 'Shared',
18 'router' => 'Router',
19 );
20 // address allocation code, IPv4 addresses and objects view
21 $aac = array
22 (
23 'regular' => '',
24 'virtual' => '<strong>L</strong>',
25 'shared' => '<strong>S</strong>',
26 'router' => '<strong>R</strong>',
27 );
28 // address allocation code, IPv4 networks view
29 $aac2 = array
30 (
31 'regular' => '',
32 'virtual' => '<strong>L:</strong>',
33 'router' => '<strong>R:</strong>',
34 );
35
36 // Let's have it here, so extensions can add their own images.
37 $image = array();
38 $image['error']['path'] = 'pix/error.png';
39 $image['error']['width'] = 76;
40 $image['error']['height'] = 17;
41 $image['logo']['path'] = 'pix/defaultlogo.png';
42 $image['logo']['width'] = 210;
43 $image['logo']['height'] = 40;
44 $image['rackspace']['path'] = 'pix/racks.png';
45 $image['rackspace']['width'] = 218;
46 $image['rackspace']['height'] = 200;
47 $image['objects']['path'] = 'pix/server.png';
48 $image['objects']['width'] = 218;
49 $image['objects']['height'] = 200;
50 $image['ipv4space']['path'] = 'pix/addressspace.png';
51 $image['ipv4space']['width'] = 218;
52 $image['ipv4space']['height'] = 200;
53 $image['ipv4slb']['path'] = 'pix/slb.png';
54 $image['ipv4slb']['width'] = 218;
55 $image['ipv4slb']['height'] = 200;
56 $image['config']['path'] = 'pix/configuration.png';
57 $image['config']['width'] = 218;
58 $image['config']['height'] = 200;
59 $image['reports']['path'] = 'pix/report.png';
60 $image['reports']['width'] = 218;
61 $image['reports']['height'] = 200;
62 $image['useup']['path'] = 'pix/tango-edit-clear.png';
63 $image['useup']['width'] = 16;
64 $image['useup']['height'] = 16;
65 $image['link']['path'] = 'pix/tango-network-wired.png';
66 $image['link']['width'] = 16;
67 $image['link']['height'] = 16;
68 $image['unlink']['path'] = 'pix/tango-edit-clear.png';
69 $image['unlink']['width'] = 16;
70 $image['unlink']['height'] = 16;
71 $image['add']['path'] = 'pix/tango-list-add.png';
72 $image['add']['width'] = 16;
73 $image['add']['height'] = 16;
74 $image['delete']['path'] = 'pix/tango-list-remove.png';
75 $image['delete']['width'] = 16;
76 $image['delete']['height'] = 16;
77 $image['nodelete']['path'] = 'pix/tango-list-remove-shadow.png';
78 $image['nodelete']['width'] = 16;
79 $image['nodelete']['height'] = 16;
80 $image['grant'] = $image['add'];
81 $image['revoke'] = $image['delete'];
82 $image['inservice']['path'] = 'pix/tango-emblem-system.png';
83 $image['inservice']['width'] = 16;
84 $image['inservice']['height'] = 16;
85 $image['notinservice']['path'] = 'pix/tango-dialog-error.png';
86 $image['notinservice']['width'] = 16;
87 $image['notinservice']['height'] = 16;
88 $image['blockuser'] = $image['inservice'];
89 $image['unblockuser'] = $image['notinservice'];
90 $image['find']['path'] = 'pix/tango-system-search.png';
91 $image['find']['width'] = 16;
92 $image['find']['height'] = 16;
93 $image['spacer']['path'] = 'pix/pixel.png';
94 $image['spacer']['width'] = 16;
95 $image['spacer']['height'] = 16;
96 $image['next']['path'] = 'pix/tango-go-next.png';
97 $image['next']['width'] = 32;
98 $image['next']['height'] = 32;
99 $image['prev']['path'] = 'pix/tango-go-previous.png';
100 $image['prev']['width'] = 32;
101 $image['prev']['height'] = 32;
102 $image['clear']['path'] = 'pix/tango-edit-clear.png';
103 $image['clear']['width'] = 16;
104 $image['clear']['height'] = 16;
105 $image['CLEAR']['path'] = 'pix/tango-edit-clear-big.png';
106 $image['CLEAR']['width'] = 32;
107 $image['CLEAR']['height'] = 32;
108 $image['save']['path'] = 'pix/tango-document-save.png';
109 $image['save']['width'] = 16;
110 $image['save']['height'] = 16;
111 $image['SAVE']['path'] = 'pix/tango-document-save-big.png';
112 $image['SAVE']['width'] = 32;
113 $image['SAVE']['height'] = 32;
114 $image['create']['path'] = 'pix/tango-document-new.png';
115 $image['create']['width'] = 16;
116 $image['create']['height'] = 16;
117 $image['CREATE']['path'] = 'pix/tango-document-new-big.png';
118 $image['CREATE']['width'] = 32;
119 $image['CREATE']['height'] = 32;
120 $image['DENIED']['path'] = 'pix/tango-dialog-error-big.png';
121 $image['DENIED']['width'] = 32;
122 $image['DENIED']['height'] = 32;
123
124 // This may be populated later onsite, report rendering function will use it.
125 // See the $systemreport for structure.
126 $localreports = array();
127
128 // Main menu.
129 function renderIndex ()
130 {
131 global $root;
132 ?>
133 <table border=0 cellpadding=0 cellspacing=0 width='100%'>
134 <tr>
135 <td>
136 <div style='text-align: center; margin: 10px; '>
137 <table width='100%' cellspacing=0 cellpadding=30 class=mainmenu border=0>
138 <tr>
139 <td>
140 <h1><a href='<?php echo $root; ?>?page=rackspace'>Rackspace<br>
141 <?php printImageHREF ('rackspace'); ?></a></h1>
142 </td>
143 <td>
144 <h1><a href='<?php echo $root; ?>?page=objects'>Objects<br>
145 <?php printImageHREF ('objects'); ?></a></h1>
146 </td>
147 <td>
148 <h1><a href='<?php echo $root; ?>?page=ipv4space'>IPv4 space<br>
149 <?php printImageHREF ('ipv4space'); ?></a></h1>
150 </td>
151 </tr>
152 </table>
153 <table width='100%' cellspacing=0 cellpadding=30 class=mainmenu border=0>
154 <tr>
155 <td>
156 <h1><a href='<?php echo $root; ?>?page=config'>Configuration<br>
157 <?php printImageHREF ('config'); ?></a></h1>
158 </td>
159 <td>
160 <h1><a href='<?php echo $root; ?>?page=reports'>Reports<br>
161 <?php printImageHREF ('reports'); ?></a></h1>
162 </td>
163 <td>
164 <h1><a href='<?php echo $root; ?>?page=ipv4slb'>IPv4 SLB<br>
165 <?php printImageHREF ('ipv4slb'); ?></a></h1>
166 </td>
167 </tr>
168 </table>
169 </div>
170 </td>
171 </tr>
172 </table>
173 <?php
174 }
175
176 function renderRackspace ()
177 {
178 $tagfilter = getTagFilter();
179 $tagfilter_str = getTagFilterStr ($tagfilter);
180 echo "<table class=objview border=0 width='100%'><tr><td class=pcleft>";
181 renderTagFilterPortlet ($tagfilter, 'rack');
182 echo '</td><td class=pcright>';
183 echo '<table border=0 cellpadding=10 cellpadding=1>';
184 // generate thumb gallery
185 $rackrowList = getRackspace ($tagfilter);
186 global $root, $nextorder;
187 $rackwidth = getRackImageWidth();
188 $order = 'odd';
189 foreach ($rackrowList as $rackrow)
190 {
191 echo "<tr class=row_${order}><th class=tdleft>";
192 echo "<a href='${root}?page=row&row_id=${rackrow['row_id']}${tagfilter_str}'>";
193 echo "${rackrow['row_name']}</a></th>";
194 $rackList = getRacksForRow ($rackrow['row_id'], $tagfilter);
195 echo "<td><table border=0 cellspacing=5><tr>";
196 foreach ($rackList as $rack)
197 {
198 echo "<td align=center><a href='${root}?page=rack&rack_id=${rack['id']}'>";
199 echo "<img border=0 width=${rackwidth} height=";
200 echo getRackImageHeight ($rack['height']);
201 echo " title='${rack['height']} units'";
202 echo "src='render_image.php?img=minirack&rack_id=${rack['id']}'>";
203 echo "<br>${rack['name']}</a></td>";
204 }
205 echo "</tr></table></tr>\n";
206 $order = $nextorder[$order];
207 }
208 echo "</table>\n";
209 echo "</td></tr></table>\n";
210 }
211
212 function renderRow ($row_id = 0)
213 {
214 if ($row_id == 0)
215 {
216 showError ('Invalid row_id', __FUNCTION__);
217 return;
218 }
219 if (($rowInfo = getRackRowInfo ($row_id)) == NULL)
220 {
221 showError ('getRackRowInfo() failed', __FUNCTION__);
222 return;
223 }
224 $tagfilter = getTagFilter();
225 $rackList = getRacksForRow ($row_id, $tagfilter);
226 // Main layout starts.
227 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
228
229 // Left portlet with row information.
230 echo "<tr><td class=pcleft>";
231 startPortlet ($rowInfo['name']);
232 echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
233 echo "<tr><th width='50%' class=tdright>Racks:</th><td class=tdleft>${rowInfo['count']}</td></tr>\n";
234 echo "<tr><th width='50%' class=tdright>Units:</th><td class=tdleft>${rowInfo['sum']}</td></tr>\n";
235 echo "<tr><th width='50%' class=tdright>%% used:</th><td class=tdleft>";
236 renderProgressBar (getRSUforRackRow ($rackList));
237 echo "</td></tr>\n";
238 echo "</table><br>\n";
239 finishPortlet();
240
241 echo "</td><td class=pcright rowspan=2>";
242
243 global $root, $nextorder;
244 $rackwidth = getRackImageWidth() * getConfigVar ('ROW_SCALE');
245 $order = 'odd';
246 startPortlet ('Racks');
247 echo "<table border=0 cellspacing=5 align='center'><tr>";
248 foreach ($rackList as $rack)
249 {
250 echo "<td align=center class=row_${order}><a href='${root}?page=rack&rack_id=${rack['id']}'>";
251 echo "<img border=0 width=${rackwidth} height=" . (getRackImageHeight ($rack['height']) * getConfigVar ('ROW_SCALE'));
252 echo " title='${rack['height']} units'";
253 echo "src='render_image.php?img=minirack&rack_id=${rack['id']}'>";
254 echo "<br>${rack['name']}</a></td>";
255 $order = $nextorder[$order];
256 }
257 echo "</tr></table>\n";
258 finishPortlet();
259 echo "</td></tr>";
260
261 echo "<tr><td class=pcleft>";
262 renderTagFilterPortlet ($tagfilter, 'rack', 'row_id', $row_id);
263 echo "</td></tr></table>";
264 }
265
266 function showError ($info = '', $location = 'N/A')
267 {
268 global $root;
269 if (preg_match ('/\.php$/', $location))
270 $location = basename ($location);
271 elseif ($location != 'N/A')
272 $location = $location . '()';
273 echo "<div class=msg_error>An error has occured in [${location}]. ";
274 if (empty ($info))
275 echo 'No additional information is available.';
276 else
277 echo "Additional information:<br><p>\n<pre>\n${info}\n</pre></p>";
278 echo "Go back or try starting from <a href='${root}'>index page</a>.<br></div>\n";
279 }
280
281 // This function renders rack as HTML table.
282 function renderRack ($rack_id = 0, $hl_obj_id = 0)
283 {
284 if ($rack_id == 0)
285 {
286 showError ('Invalid rack_id', __FUNCTION__);
287 return;
288 }
289 if (($rackData = getRackData ($rack_id)) == NULL)
290 {
291 showError ('getRackData() failed', __FUNCTION__);
292 return;
293 }
294 global $root, $pageno, $tabno;
295 markAllSpans ($rackData);
296 if ($hl_obj_id > 0)
297 highlightObject ($rackData, $hl_obj_id);
298 markupObjectProblems ($rackData);
299 $prev_id = getPrevIDforRack ($rackData['row_id'], $rack_id);
300 $next_id = getNextIDforRack ($rackData['row_id'], $rack_id);
301 echo "<center><table border=0><tr valign=middle>";
302 echo "<td><h2><a href='${root}?page=row&row_id=${rackData['row_id']}'>${rackData['row_name']}</a> :</h2></td>";
303 // FIXME: use 'bypass'?
304 if ($prev_id != NULL)
305 {
306 echo "<td><a href='${root}?page=rack&rack_id=${prev_id}'>";
307 printImageHREF ('prev', 'previous rack');
308 echo "</a></td>";
309 }
310 echo "<td><h2><a href='${root}?page=rack&rack_id=${rackData['id']}'>${rackData['name']}</a></h2></td>";
311 if ($next_id != NULL)
312 {
313 echo "<td><a href='${root}?page=rack&rack_id=${next_id}'>";
314 printImageHREF ('next', 'next rack');
315 echo "</a></td>";
316 }
317 echo "</h2></td></tr></table>\n";
318 if ($rackData['left_is_front'] == 'yes')
319 $markup = array ('left' => 'Front', 'right' => 'Back');
320 else
321 $markup = array ('left' => 'Back', 'right' => 'Front');
322 echo "<table class=rack border=0 cellspacing=0 cellpadding=1>\n";
323 echo "<tr><th width='10%'>&nbsp;</th><th width='20%'>${markup['left']}</th>";
324 echo "<th width='50%'>Interior</th><th width='20%'>${markup['right']}</th></tr>\n";
325 for ($i = $rackData['height']; $i > 0; $i--)
326 {
327 echo '<tr><th>' . ($rackData['bottom_is_unit1'] == 'yes' ? $i : $rackData['height'] - $i + 1) . '</th>';
328 for ($locidx = 0; $locidx < 3; $locidx++)
329 {
330 if (isset ($rackData[$i][$locidx]['skipped']))
331 continue;
332 $state = $rackData[$i][$locidx]['state'];
333 echo "<td class=state_${state}";
334 if (isset ($rackData[$i][$locidx]['hl']))
335 echo $rackData[$i][$locidx]['hl'];
336 if (isset ($rackData[$i][$locidx]['colspan']))
337 echo ' colspan=' . $rackData[$i][$locidx]['colspan'];
338 if (isset ($rackData[$i][$locidx]['rowspan']))
339 echo ' rowspan=' . $rackData[$i][$locidx]['rowspan'];
340 echo ">";
341 switch ($state)
342 {
343 case 'T':
344 $objectData = getObjectInfo ($rackData[$i][$locidx]['object_id']);
345 if (!empty ($objectData['asset_no']))
346 $prefix = "<div title='${objectData['asset_no']}";
347 else
348 $prefix = "<div title='no asset tag";
349 // Don't tell about label, if it matches common name.
350 if ($objectData['name'] != $objectData['label'] and !empty ($objectData['label']))
351 $suffix = ", visible label is \"${objectData['label']}\"'>";
352 else
353 $suffix = "'>";
354 echo $prefix . $suffix;
355 echo "<a href='${root}?page=object&object_id=${objectData['id']}'>${objectData['dname']}</a></div>";
356 break;
357 case 'A':
358 echo '<div title="This rackspace does not exist">&nbsp;</div>';
359 break;
360 case 'F':
361 echo '<div title="Free rackspace">&nbsp;</div>';
362 break;
363 case 'U':
364 echo '<div title="Problematic rackspace, you CAN\'T mount here">&nbsp;</div>';
365 break;
366 default:
367 echo '<div title="No data">&nbsp;</div>';
368 break;
369 }
370 echo '</td>';
371 }
372 echo "</tr>\n";
373 }
374 echo "</table></center>\n";
375 }
376
377 function renderNewRackForm ($row_id)
378 {
379 showMessageOrError();
380
381 startPortlet ('Add one');
382 printOpFormIntro ('addRack', array ('got_data' => 'TRUE'));
383 echo '<table border=0 align=center>';
384 $defh = getConfigVar ('DEFAULT_RACK_HEIGHT');
385 if ($defh == 0)
386 $defh = '';
387 echo "<tr><th class=tdright>Rack name (*):</th><td class=tdleft><input type=text name=rack_name tabindex=1></td>";
388 echo "<td rowspan=4>Assign tags:<br>";
389 renderTagSelect();
390 echo "</td></tr>\n";
391 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";
392 echo "<tr><th class=tdright>Comment:</th><td class=tdleft><input type=text name=rack_comment tabindex=3></td></tr>\n";
393 echo "<tr><td class=submit colspan=2>";
394 printImageHREF ('CREATE', 'Add', TRUE);
395 echo "</td></tr></table></form>";
396 finishPortlet();
397
398 startPortlet ('Add many');
399 printOpFormIntro ('addRack', array ('got_mdata' => 'TRUE'));
400 echo '<table border=0 align=center>';
401 $defh = getConfigVar ('DEFAULT_RACK_HEIGHT');
402 if ($defh == 0)
403 $defh = '';
404 echo "<tr><th class=tdright>Height in units (*):</th><td class=tdleft><input type=text name=rack_height2 value='${defh}'></td>";
405 echo "<td rowspan=3 valign=top>Assign tags:<br>";
406 renderTagSelect();
407 echo "</td></tr>\n";
408 echo "<tr><th class=tdright>Rack names (*):</th><td class=tdleft><textarea name=rack_names cols=40 rows=25></textarea></td></tr>\n";
409 echo "<tr><td class=submit colspan=2>";
410 printImageHREF ('CREATE', 'Add', TRUE);
411 echo '</form></table>';
412 finishPortlet();
413 }
414
415 function renderEditObjectForm ($object_id)
416 {
417 showMessageOrError();
418
419 global $pageno, $tabno, $root;
420 $object = getObjectInfo ($object_id);
421 if ($object == NULL)
422 {
423 showError ('getObjectInfo() failed', __FUNCTION__);
424 return;
425 }
426 echo '<table border=0 width=100%><tr>';
427
428 echo '<td class=pcleft>';
429 startPortlet ('Static attributes');
430 printOpFormIntro ('update');
431 echo '<table border=0 align=center>';
432 echo "<tr><th class=tdright>Type:</th><td class=tdleft>";
433 printSelect (getObjectTypeList(), 'object_type_id', $object['objtype_id']);
434 echo "</td></tr>\n";
435 // baseline info
436 echo "<tr><th class=tdright>Common name:</th><td class=tdleft><input type=text name=object_name value='${object['name']}'></td></tr>\n";
437 echo "<tr><th class=tdright>Visible label:</th><td class=tdleft><input type=text name=object_label value='${object['label']}'></td></tr>\n";
438 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";
439 echo "<tr><th class=tdright>Barcode:</th><td class=tdleft><input type=text name=object_barcode value='${object['barcode']}'></td></tr>\n";
440 echo "<tr><th class=tdright>Has problems:</th><td class=tdleft><input type=checkbox name=object_has_problems";
441 if ($object['has_problems'] == 'yes')
442 echo ' checked';
443 echo "></td></tr>\n";
444 echo "<tr><td colspan=2><b>Comment:</b><br><textarea name=object_comment rows=10 cols=80>${object['comment']}</textarea></td></tr>";
445 echo "<tr><th class=submit colspan=2>";
446 printImageHREF ('SAVE', 'Save changes', TRUE);
447 echo "</td></tr>\n";
448 echo '</form></table><br>';
449 finishPortlet();
450 echo '</td>';
451
452 // stickers
453 echo '<td class=pcright>';
454 startPortlet ('Optional attributes');
455 $values = getAttrValues ($object_id);
456 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable>\n";
457 echo "<tr><th>&nbsp;</th><th>Attribute</th><th>Value</th><th>&nbsp;</th></tr>\n";
458 printOpFormIntro ('updateStickers');
459 echo '<input type=hidden name=num_attrs value=' . count($values) . ">\n";
460
461 $i = 0;
462 foreach ($values as $record)
463 {
464 echo "<input type=hidden name=${i}_attr_id value=${record['id']}>";
465 echo '<tr><td>';
466 if (!empty ($record['value']))
467 {
468 echo "<a href='${root}process.php?page=${pageno}&tab=${tabno}&op=clearSticker&object_id=${object_id}&attr_id=${record['id']}'>";
469 printImageHREF ('clear', 'Clear value');
470 echo '</a>';
471 }
472 else
473 echo '&nbsp;';
474 echo '</td>';
475 echo "<td class=tdright>${record['name']}:</td><td class=tdleft>";
476 switch ($record['type'])
477 {
478 case 'uint':
479 case 'float':
480 case 'string':
481 echo "<input type=text name=${i}_value value='${record['value']}'>";
482 break;
483 case 'dict':
484 $chapter = readChapter ($record['chapter_name']);
485 $chapter[0] = '-- NOT SET --';
486 printSelect ($chapter, "${i}_value", $record['key']);
487 break;
488 }
489 echo "</td></tr>\n";
490 $i++;
491 }
492 echo "<tr><td colspan=3>";
493 printImageHREF ('SAVE', 'Save changes', TRUE);
494 echo "</td></tr>\n";
495 echo "</form>";
496 echo "</table>\n";
497 finishPortlet();
498 echo '</td>';
499
500 echo '</tr><tr>';
501
502 echo '<td colspan=2>';
503 startPortlet ('history');
504 renderHistory ($pageno, $object_id);
505 finishPortlet();
506 echo '</td>';
507
508 echo '</tr></table>';
509 }
510
511 // This is a clone of renderEditObjectForm().
512 function renderEditRackForm ($rack_id)
513 {
514 showMessageOrError();
515 global $pageno;
516 $rack = getRackData ($rack_id);
517 if ($rack == NULL)
518 {
519 showError ('getRackData() failed', __FUNCTION__);
520 return;
521 }
522
523 startPortlet ('Rack attributes');
524 printOpFormIntro ('updateRack');
525 echo '<table border=0 align=center>';
526 echo "<tr><th class=tdright>Rack row:</th><td class=tdleft>";
527 printSelect (readChapter ('RackRow'), 'rack_row_id', $rack['row_id']);
528 echo "</td></tr>\n";
529 echo "<tr><th class=tdright>Name (required):</th><td class=tdleft><input type=text name=rack_name value='${rack['name']}'></td></tr>\n";
530 echo "<tr><th class=tdright>Height (required):</th><td class=tdleft><input type=text name=rack_height value='${rack['height']}'></td></tr>\n";
531 echo "<tr><th class=tdright>Comment:</th><td class=tdleft><input type=text name=rack_comment value='${rack['comment']}'></td></tr>\n";
532 echo "<tr><td class=submit colspan=2>";
533 printImageHREF ('SAVE', 'Save changes', TRUE);
534 echo "</td></tr>\n";
535 echo '</form></table><br>';
536 finishPortlet();
537
538 startPortlet ('History');
539 renderHistory ($pageno, $rack_id);
540 finishPortlet();
541 }
542
543 // This is a helper for creators and editors.
544 function printSelect ($rowList, $select_name, $selected_id = 1)
545 {
546 // First collect all data for OPTGROUPs, then ouput it and dump
547 // the rest of records as is.
548 $optgroup = array();
549 $other = array();
550 foreach ($rowList as $dict_key => $dict_value)
551 {
552 if (strpos ($dict_value, '%GSKIP%') !== FALSE)
553 {
554 $tmp = explode ('%GSKIP%', $dict_value, 2);
555 $optgroup[$tmp[0]][$dict_key] = $tmp[1];
556 }
557 elseif (strpos ($dict_value, '%GPASS%') !== FALSE)
558 {
559 $tmp = explode ('%GPASS%', $dict_value, 2);
560 $optgroup[$tmp[0]][$dict_key] = $tmp[1];
561 }
562 else
563 $other[$dict_key] = $dict_value;
564 }
565 echo "<select name=${select_name}>";
566 if (!count ($optgroup))
567 {
568 foreach ($other as $dict_key => $dict_value)
569 {
570 echo "<option value=${dict_key}";
571 if ($dict_key == $selected_id)
572 echo ' selected';
573 echo ">${dict_value}</option>";
574 }
575 }
576 else
577 {
578 foreach ($optgroup as $groupname => $groupdata)
579 {
580 echo "<optgroup label='${groupname}'>";
581 foreach ($groupdata as $dict_key => $dict_value)
582 {
583 echo "<option value=${dict_key}";
584 if ($dict_key == $selected_id)
585 echo ' selected';
586 echo ">${dict_value}</option>";
587 }
588 echo "</optgroup>\n";
589 }
590 if (count ($other))
591 {
592 echo "<optgroup label='other'>\n";
593 foreach ($other as $dict_key => $dict_value)
594 {
595 echo "<option value=${dict_key}";
596 if ($dict_key == $selected_id)
597 echo ' selected';
598 echo ">${dict_value}</option>";
599 }
600 echo "</optgroup>\n";
601 }
602 }
603 echo "</select>";
604 }
605
606 // used by renderGridForm() and renderRackPage()
607 function renderRackInfoPortlet ($rackData)
608 {
609 global $root;
610 startPortlet ('summary');
611 echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
612 echo "<tr><th width='50%' class=tdright>Rack row:</th><td class=tdleft>${rackData['row_name']}</td></tr>\n";
613 echo "<tr><th width='50%' class=tdright>Name:</th><td class=tdleft>${rackData['name']}</td></tr>\n";
614 echo "<tr><th width='50%' class=tdright>Height:</th><td class=tdleft>${rackData['height']}</td></tr>\n";
615 echo "<tr><th width='50%' class=tdright>%% used:</th><td class=tdleft>";
616 renderProgressBar (getRSUforRack ($rackData));
617 echo "</td></tr>\n";
618 echo "<tr><th width='50%' class=tdright>Objects:</th><td class=tdleft>";
619 echo count (stuffInRackspace ($rackData));
620 echo "</td></tr>\n";
621 printTagTRs ("${root}?page=rackspace&");
622 if (!empty ($rackData['comment']))
623 echo "<tr><th width='50%' class=tdright>Comment:</th><td class=tdleft>${rackData['comment']}</td></tr>\n";
624 echo '</table>';
625 finishPortlet();
626 }
627
628 // This is a universal editor of rack design/waste.
629 // FIXME: switch to using printOpFormIntro()
630 function renderGridForm ($rack_id = 0, $filter, $header, $submit, $state1, $state2)
631 {
632 if ($rack_id == 0)
633 {
634 showError ('Invalid rack_id', __FUNCTION__);
635 return;
636 }
637 if (($rackData = getRackData ($rack_id)) == NULL)
638 {
639 showError ('getRackData() failed', __FUNCTION__);
640 return;
641 }
642
643 global $root, $pageno, $tabno;
644 $filter ($rackData);
645 markupObjectProblems ($rackData);
646
647 // Process form submit.
648 if (isset ($_REQUEST['do_update']))
649 {
650 $log[] = processGridForm ($rackData, $state1, $state2);
651 printLog ($log);
652 $rackData = getRackData ($rack_id);
653 $filter ($rackData);
654 markupObjectProblems ($rackData);
655 }
656
657 // Render the result whatever it is.
658 // Main layout.
659 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
660 echo "<tr><td colspan=2 align=center><h1>${rackData['name']}</h1></td></tr>\n";
661
662 // Left column with information portlet.
663 echo "<tr><td class=pcleft height='1%' width='50%'>";
664 renderRackInfoPortlet ($rackData);
665 echo "</td>\n";
666 echo "<td class=pcright>";
667
668 // Grid form.
669 startPortlet ($header);
670 echo "<center>\n";
671 echo "<table class=rack border=0 cellspacing=0 cellpadding=1>\n";
672 echo "<tr><th width='10%'>&nbsp;</th><th width='20%'>Front</th>";
673 echo "<th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n";
674 echo "<form method=post action='${root}?'>\n";
675 echo "<input type=hidden name=page value=${pageno}>\n";
676 echo "<input type=hidden name=tab value=${tabno}>\n";
677 echo "<input type=hidden name=rack_id value=${rack_id}>\n";
678 markupAtomGrid ($rackData, $state2);
679 renderAtomGrid ($rackData);
680 echo "</table></center>\n";
681 echo "<br><input type=submit name=do_update value='${submit}'></form><br><br>\n";
682 finishPortlet();
683 echo "</td></tr></table>\n";
684 }
685
686 function renderRackDesign ($rack_id)
687 {
688 renderGridForm ($rack_id, 'applyRackDesignMask', 'Rack design', 'Set rack design', 'A', 'F');
689 }
690
691 function renderRackProblems ($rack_id = 0)
692 {
693 renderGridForm ($rack_id, 'applyRackProblemMask', 'Rack problems', 'Mark unusable atoms', 'F', 'U');
694 }
695
696 function startPortlet ($title = '')
697 {
698 echo "<div class=portlet><h2>${title}</h2>";
699 }
700
701 function finishPortlet ()
702 {
703 echo "</div>\n";
704 }
705
706 function printRefsOfType ($refs, $type, $eq)
707 {
708 global $root;
709 $gotone=0;
710 foreach ($refs as $ref)
711 {
712 if ($eq($ref['type'], $type))
713 {
714 if ($gotone) echo ', ';
715 echo "<a href='${root}?page=object&object_id=${ref['object_id']}'>";
716 if (!empty ($ref['name']))
717 echo $ref['name'] . '@';
718 echo "${ref['object_name']}</a>";
719 $gotone=1;
720 }
721 }
722 }
723
724 function renderRackObject ($object_id = 0)
725 {
726 global $root, $nextorder, $aac;
727 if ($object_id <= 0)
728 {
729 showError ('Invalid object_id', __FUNCTION__);
730 return;
731 }
732 $info = getObjectInfo ($object_id);
733 if ($info == NULL)
734 {
735 showError ('getObjectInfo() failed', __FUNCTION__);
736 return;
737 }
738 // Main layout starts.
739 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
740 echo "<tr><td colspan=2 align=center><h1>${info['dname']}</h1></td></tr>\n";
741 // left column with uknown number of portlets
742 echo "<tr><td class=pcleft>";
743 startPortlet ('summary');
744 echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
745 if (!empty ($info['name']))
746 echo "<tr><th width='50%' class=tdright>Common name:</th><td class=tdleft>${info['name']}</td></tr>\n";
747 elseif (in_array ($info['objtype_id'], explode (',', getConfigVar ('NAMEFUL_OBJTYPES'))))
748 echo "<tr><td colspan=2 class=msg_error>Common name is missing.</td></tr>\n";
749 echo "<tr><th width='50%' class=tdright>Object type:</th>";
750 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";
751 if (!empty ($info['asset_no']))
752 echo "<tr><th width='50%' class=tdright>Asset tag:</th><td class=tdleft>${info['asset_no']}</td></tr>\n";
753 elseif (in_array ($info['objtype_id'], explode (',', getConfigVar ('REQUIRE_ASSET_TAG_FOR'))))
754 echo "<tr><td colspan=2 class=msg_error>Asset tag is missing.</td></tr>\n";
755 if (!empty ($info['label']))
756 echo "<tr><th width='50%' class=tdright>Visible label:</th><td class=tdleft>${info['label']}</td></tr>\n";
757 if (!empty ($info['barcode']))
758 echo "<tr><th width='50%' class=tdright>Barcode:</th><td class=tdleft>${info['barcode']}</td></tr>\n";
759 if ($info['has_problems'] == 'yes')
760 echo "<tr><td colspan=2 class=msg_error>Has problems</td></tr>\n";
761 foreach (getAttrValues ($object_id, TRUE) as $record)
762 if (!empty ($record['value']))
763 echo "<tr><th width='50%' class=opt_attr_th>${record['name']}:</th><td class=tdleft>${record['a_value']}</td></tr>\n";
764 printTagTRs ("${root}?page=objgroup&group_id=${info['objtype_id']}&");
765 echo "</table><br>\n";
766 finishPortlet();
767
768 if (!empty ($info['comment']))
769 {
770 startPortlet ('Comment');
771 echo '<div class=commentblock>' . string_insert_hrefs ($info['comment']) . '</div>';
772 finishPortlet ();
773 }
774
775 $ports = getObjectPortsAndLinks ($object_id);
776 if (count ($ports))
777 {
778 startPortlet ('ports and links');
779 usort($ports, 'sortByName');
780 if ($ports)
781 {
782 $hl_port_id = 0;
783 if (isset ($_REQUEST['hl_port_id']))
784 {
785 assertUIntArg ('hl_port_id', __FUNCTION__);
786 $hl_port_id = $_REQUEST['hl_port_id'];
787 }
788 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
789 echo "<tr><th>Local name</th><th>Visible label</th><th>Port type</th><th>L2 address</th>";
790 echo "<th>Rem. Object</th><th>Rem. port</th></tr>\n";
791 foreach ($ports as $port)
792 {
793 echo '<tr';
794 if ($hl_port_id == $port['id'])
795 echo ' class=port_highlight';
796 echo "><td>${port['name']}</td><td>${port['label']}</td><td>${port['type']}</td>";
797 echo "<td>${port['l2address']}</td>";
798 if ($port['remote_object_id'])
799 {
800 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>";
801 echo "<td>${port['remote_name']}</td>";
802 }
803 elseif (!empty ($port['reservation_comment']))
804 {
805 echo "<td><b>Reserved;</b></td>";
806 echo "<td>${port['reservation_comment']}</td>";
807 }
808 else
809 echo '<td>&nbsp;</td><td>&nbsp;</td>';
810 echo "</tr>\n";
811 }
812 echo "</table><br>\n";
813 }
814 finishPortlet();
815 }
816
817 $alloclist = getObjectIPv4Allocations ($object_id);
818 if (count ($alloclist))
819 {
820 startPortlet ('IPv4 addresses');
821 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
822 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
823 echo "<tr><th>OS interface</th><th>IP address</th><th colspan=2>network</th><th>routed by</th><th>peers</th></tr>\n";
824 else
825 echo "<tr><th>OS interface</th><th>IP address</th><th>peers</th></tr>\n";
826 $hl_ipv4_addr = '';
827 if (isset ($_REQUEST['hl_ipv4_addr']))
828 {
829 assertIPv4Arg ('hl_ipv4_addr', __FUNCTION__);
830 $hl_ipv4_addr = $_REQUEST['hl_ipv4_addr'];
831 }
832 foreach ($alloclist as $dottedquad => $alloc)
833 {
834 $address_name = niftyString ($alloc['addrinfo']['name']);
835 $class = $alloc['addrinfo']['class'];
836 $secondclass = ($hl_ipv4_addr == $dottedquad) ? 'tdleft port_highlight' : 'tdleft';
837 $netid = getIPv4AddressNetworkId ($dottedquad);
838 $netinfo = getIPv4NetworkInfo ($netid);
839 echo "<tr class='${class}' valign=top><td class=tdleft>${alloc['osif']}</td><td class='${secondclass}'>";
840 echo "<a href='${root}?page=ipaddress&ip=" . $dottedquad . "&hl_object_id=${object_id}'>${dottedquad}</a>";
841 if (getConfigVar ('EXT_IPV4_VIEW') != 'yes')
842 {
843 if (NULL === $netid)
844 $suffix = '/??';
845 else
846 echo '<small>/' . $netinfo['mask'] . '</small>';
847 }
848 echo '&nbsp;' . $aac[$alloc['type']];
849 if (!empty ($alloc['addrinfo']['name']))
850 echo '(' . niftyString ($alloc['addrinfo']['name']) . ')';
851 echo '</td>';
852 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
853 {
854 if (NULL === $netid)
855 echo '<td colspan=2>?</td>';
856 else
857 printIPv4NetInfoTDs ($netinfo, $secondclass);
858 echo "<td class='${secondclass}'>";
859 // FIXME: These cals are really heavy, replace them with a more appropriate dedicated function.
860 $netdata = getIPv4Network ($netid);
861 $newline = '';
862 foreach (findRouters ($netdata['addrlist']) as $router)
863 {
864 if ($router['id'] == $object_id)
865 continue;
866 echo $newline . $router['addr'] . ", <a href='${root}?page=object&object_id=${router['id']}&hl_ipv4_addr=${router['addr']}'>";
867 echo (empty ($router['iface']) ? '' : $router['iface'] . '@') . $router['dname'] . '</a>';
868 $routertags = loadRackObjectTags ($router['id']);
869 if (count ($routertags))
870 echo '<br><small>' . serializeTags ($routertags, "${root}?page=objects&tab=default&") . '</small>';
871 $newline = '<br>';
872 }
873 echo '</td>';
874 }
875 // peers
876 echo "<td class='${secondclass}'>\n";
877 $prefix = '';
878 if ($alloc['addrinfo']['reserved'] == 'yes')
879 {
880 echo $prefix . '<strong>RESERVED</strong>';
881 $prefix = '; ';
882 }
883 foreach ($alloc['addrinfo']['allocs'] as $allocpeer)
884 {
885 if ($allocpeer['object_id'] == $object_id)
886 continue;
887 echo $prefix . "<a href='${root}?page=object&object_id=${allocpeer['object_id']}'>";
888 if (!empty ($allocpeer['osif']))
889 echo $allocpeer['osif'] . '@';
890 echo $allocpeer['object_name'] . '</a>';
891 $prefix = '; ';
892 }
893 echo "</td></tr>\n";
894 }
895 echo "</table><br>\n";
896 finishPortlet();
897 }
898
899 $forwards = getNATv4ForObject ($object_id);
900 if (count($forwards['in']) or count($forwards['out']))
901 {
902 startPortlet('NATv4');
903
904 if (count($forwards['out']))
905 {
906
907 echo "<h3>locally performed NAT</h3>";
908
909 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
910 echo "<tr><th>Proto</th><th>Match endpoint</th><th>Translate to</th><th>Target object</th><th>Rule comment</th></tr>\n";
911
912 foreach ($forwards['out'] as $pf)
913 {
914 $class = 'trerror';
915 $osif = '';
916 if (isset ($alloclist [$pf['localip']]))
917 {
918 $class = $alloclist [$pf['localip']]['addrinfo']['class'];
919 $osif = $alloclist [$pf['localip']]['osif'] . ': ';
920 }
921 echo "<tr class='$class'>";
922 echo "<td>${pf['proto']}</td><td class=tdleft>${osif}<a href='${root}?page=ipaddress&tab=default&ip=${pf['localip']}'>${pf['localip']}</a>:${pf['localport']}</td>";
923 echo "<td class=tdleft><a href='${root}?page=ipaddress&tab=default&ip=${pf['remoteip']}'>${pf['remoteip']}</a>:${pf['remoteport']}</td>";
924 $address = getIPv4Address ($pf['remoteip']);
925 echo "<td class='description'>";
926 if (count ($address['allocs']))
927 foreach($address['allocs'] as $bond)
928 echo "<a href='${root}?page=object&tab=default&object_id=${bond['object_id']}'>${bond['object_name']}(${bond['name']})</a> ";
929 elseif (!empty ($pf['remote_addr_name']))
930 echo '(' . $pf['remote_addr_name'] . ')';
931 echo "</td><td class='description'>${pf['description']}</td></tr>";
932 }
933 echo "</table><br><br>";
934 }
935 if (count($forwards['in']))
936 {
937 echo "<h3>arriving NAT connections</h3>";
938 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
939 echo "<tr><th>Matched endpoint</th><th>Source object</th><th>Translated to</th><th>Rule comment</th></tr>\n";
940 foreach ($forwards['in'] as $pf)
941 {
942 echo "<tr>";
943 echo "<td>${pf['proto']}/<a href='${root}?page=ipaddress&tab=default&ip=${pf['localip']}'>${pf['localip']}</a>:${pf['localport']}</td>";
944 echo "<td class='description'><a href='${root}?page=object&tab=default&object_id=${pf['object_id']}'>${pf['object_name']}</a>";
945 echo "</td><td><a href='${root}?page=ipaddress&tab=default&ip=${pf['remoteip']}'>${pf['remoteip']}</a>:${pf['remoteport']}</td>";
946 echo "<td class='description'>${pf['description']}</td></tr>";
947 }
948 echo "</table><br><br>";
949 }
950 finishPortlet();
951 }
952
953 $pools = getRSPoolsForObject ($object_id);
954 if (count ($pools))
955 {
956 $order = 'odd';
957 startPortlet ('Real server pools');
958 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable>\n";
959 echo "<tr><th>VS</th><th>RS pool</th><th>RS</th><th>VS config</th><th>RS config</th></tr>\n";
960 foreach ($pools as $vs_id => $info)
961 {
962 echo "<tr valign=top class=row_${order}><td class=tdleft><a href='${root}?page=ipv4vs&vs_id=${vs_id}'>";
963 echo buildVServiceName ($info);
964 echo '</a>';
965 if (!empty ($info['name']))
966 echo "<br>${info['name']}";
967 echo "</td><td class=tdleft><a href='${root}?page=ipv4rsp&pool_id=${info['pool_id']}'>";
968 echo (empty ($info['pool_name']) ? 'ANONYMOUS' : $info['pool_name']);
969 echo '</a></td><td class=tdleft>' . $info['rscount'] . '</td>';
970 echo "<td class=tdleft><pre>${info['vsconfig']}</pre></td>";
971 echo "<td class=tdleft><pre>${info['rsconfig']}</pre></td>";
972 echo "</tr>\n";
973 $order = $nextorder[$order];
974 }
975 echo "</table>\n";
976 finishPortlet();
977 }
978 echo "</td>\n";
979
980 // After left column we have (surprise!) right column with rackspace portlet only.
981 echo "<td class=pcright>";
982 // rackspace portlet
983 startPortlet ('rackspace allocation');
984 // FIXME: now we call getRackData() twice
985 $racks = getResidentRacksData ($object_id);
986 foreach ($racks as $rackData)
987 renderRack ($rackData['id'], $object_id);
988 echo '<br>';
989 finishPortlet();
990 echo "</td></tr>";
991 echo "</table>\n";
992 }
993
994 function renderRackMultiSelect ($sname, $racks, $selected)
995 {
996 // Transform the given flat list into a list of groups, each representing a rack row.
997 $rdata = array();
998 foreach ($racks as $rack)
999 if (!isset ($rdata[$rack['row_name']]))
1000 $rdata[$rack['row_name']] = array ($rack['id'] => $rack['name']);
1001 else
1002 $rdata[$rack['row_name']][$rack['id']] = $rack['name'];
1003 echo "<select name=${sname} multiple size=" . getConfigVar ('MAXSELSIZE') . " onchange='getElementById(\"racks\").submit()'>\n";
1004 foreach ($rdata as $optgroup => $racklist)
1005 {
1006 echo "<optgroup label='${optgroup}'>";
1007 foreach ($racklist as $rack_id => $rack_name)
1008 {
1009 echo "<option value=${rack_id}";
1010 if (!(array_search ($rack_id, $selected) === FALSE))
1011 echo ' selected';
1012 echo">${rack_name}</option>\n";
1013 }
1014 }
1015 echo "</select>\n";
1016 }
1017
1018 function showMessageOrError ()
1019 {
1020 if (isset ($_REQUEST['message']))
1021 echo "<div class=msg_success>${_REQUEST['message']}</div>";
1022 elseif (isset ($_REQUEST['error']))
1023 echo "<div class=msg_error>${_REQUEST['error']}</div>";
1024 elseif (isset ($_REQUEST['log']))
1025 printLog (unserialize (base64_decode ($_REQUEST['log'])));
1026 }
1027
1028 // This function renders a form for port edition.
1029 function renderPortsForObject ($object_id = 0)
1030 {
1031 global $root, $pageno, $tabno;
1032 if ($object_id <= 0)
1033 {
1034 showError ('Invalid object_id', __FUNCTION__);
1035 return;
1036 }
1037 showMessageOrError();
1038 startPortlet ('Ports and interfaces');
1039 $ports = getObjectPortsAndLinks ($object_id);
1040 usort($ports, 'sortByName');
1041 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
1042 echo "<tr><th>&nbsp;</th><th>Local name</th><th>Visible label</th><th>Port type</th><th>L2 address</th>";
1043 echo "<th>Rem. object</th><th>Rem. port</th><th>(Un)link or (un)reserve</th><th>&nbsp;</th></tr>\n";
1044 foreach ($ports as $port)
1045 {
1046 printOpFormIntro ('editPort', array ('port_id' => $port['id']));
1047 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']}'>";
1048 printImageHREF ('delete', 'Unlink and Delete this port');
1049 echo "</a></td>\n";
1050 echo "<td><input type=text name=name value='${port['name']}' size=8></td>";
1051 echo "<td><input type=text name=label value='${port['label']}' size=24></td>";
1052 echo "<td>${port['type']}</td>\n";
1053 echo "<td><input type=text name=l2address value='${port['l2address']}'></td>\n";
1054 if ($port['remote_object_id'])
1055 {
1056 echo "<td><a href='${root}?page=object&object_id=${port['remote_object_id']}'>${port['remote_object_name']}</a></td>";
1057 echo "<td>${port['remote_name']}</td>";
1058 echo "<td><a href='${root}process.php?op=unlinkPort&page=${pageno}&tab=${tabno}&port_id=${port['id']}&object_id=$object_id&port_name=";
1059 echo urlencode ($port['name']);
1060 echo "&remote_port_name=${port['remote_name']}&remote_object_name=${port['remote_object_name']}'>";
1061 printImageHREF ('unlink', 'Unlink this port');
1062 echo "</a></td>";
1063 }
1064 elseif (!empty ($port['reservation_comment']))
1065 {
1066 echo "<td><b>Reserved;</b></td>";
1067 echo "<td><input type=text name=reservation_comment value='${port['reservation_comment']}'></td>";
1068 echo "<td><a href='${root}process.php?op=useup&page=${pageno}&tab=${tabno}&port_id=${port['id']}&object_id=${object_id}'>";
1069 printImageHREF ('useup', 'Use up this port');
1070 echo "</a></td>";
1071 }
1072 else
1073 {
1074 echo "<td>&nbsp;</td><td>&nbsp;</td>";
1075 echo "<td>";
1076 echo "<a href='javascript:;' onclick='window.open(\"${root}link_helper.php?port=${port['id']}&type=${port['type_id']}&object_id=$object_id&port_name=";
1077 echo urlencode ($port['name']);
1078 echo "\",\"findlink\",\"height=700, width=400, location=no, menubar=no, resizable=yes, scrollbars=no, status=no, titlebar=no, toolbar=no\");'>";
1079 printImageHREF ('link', 'Link this port');
1080 echo "</a> <input type=text name=reservation_comment>";
1081 echo "</td>\n";
1082 }
1083 echo "<td>";
1084 printImageHREF ('save', 'Save changes', TRUE);
1085 echo "</td></form></tr>\n";
1086 }
1087 printOpFormIntro ('addPort');
1088 echo "<tr><td>";
1089 printImageHREF ('add', '', TRUE, 104);
1090 echo "</td><td><input type=text size=8 name=port_name tabindex=100></td>\n";
1091 echo "<td><input type=text size=24 name=port_label tabindex=101></td>";
1092 echo "<td><select name='port_type_id' tabindex=102>\n";
1093 $types = getPortTypes();
1094 $default_port_type = getConfigVar ('default_port_type');
1095 foreach ($types as $typeid => $typename)
1096 {
1097 echo "<option value='${typeid}'";
1098 if ($typeid == $default_port_type)
1099 echo " selected";
1100 echo ">${typename}</option>\n";
1101 }
1102 echo "</select></td>";
1103 echo "<td><input type=text name=port_l2address tabindex=103></td>\n";
1104 echo "<td colspan=4>&nbsp;</td></tr></form>";
1105 echo "</table><br>\n";
1106 finishPortlet();
1107
1108 startPortlet ('Add/update multiple ports');
1109 printOpFormIntro ('addMultiPorts');
1110 echo 'Format: <select name=format>';
1111 echo '<option value=c3600asy>Cisco 3600 async: sh line | inc TTY</option>';
1112 echo '<option value=fiwg selected>Foundry ServerIron/FastIron WorkGroup/Edge: sh int br</option>';
1113 echo '<option value=fisxii>Foundry FastIron SuperX/II4000: sh int br</option>';
1114 echo '<option value=ssv1>SSV:&lt;interface name&gt; &lt;MAC address&gt;</option>';
1115 echo "</select>";
1116 echo 'Default port type: ';
1117 echo "<select name=port_type>\n";
1118 foreach ($types as $typeid => $typename)
1119 {
1120 echo "<option value='${typeid}'";
1121 if ($typeid == $default_port_type)
1122 echo " selected";
1123 echo ">${typename}</option>\n";
1124 }
1125 echo "</select>";
1126 echo "<input type=submit value='Parse output'><br>\n";
1127 echo "<textarea name=input cols=100 rows=50></textarea><br>\n";
1128 echo '</form>';
1129 finishPortlet();
1130 }
1131
1132 function renderIPv4ForObject ($object_id = 0)
1133 {
1134 global $root, $pageno, $tabno, $aat;
1135 if ($object_id <= 0)
1136 {
1137 showError ('Invalid object_id', __FUNCTION__);
1138 return;
1139 }
1140 showMessageOrError();
1141 startPortlet ('Allocations');
1142 $alloclist = getObjectIPv4Allocations ($object_id);
1143 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
1144 echo '<tr><th>&nbsp;</th><th>OS interface</th><th>IP address</th>';
1145 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
1146 echo '<th colspan=2>network</th><th>routed by</th>';
1147 echo '<th>type</th><th>misc</th><th>&nbsp</th></tr>';
1148 foreach ($alloclist as $dottedquad => $alloc)
1149 {
1150 $class = $alloc['addrinfo']['class'];
1151 $netid = getIPv4AddressNetworkId ($dottedquad);
1152 $netinfo = getIPv4NetworkInfo ($netid);
1153 printOpFormIntro ('updIPv4Allocation', array ('ip' => $dottedquad));
1154 echo "<tr class='$class' valign=top><td><a href='${root}process.php?op=delIPv4Allocation&page=${pageno}&tab=${tabno}&ip=${dottedquad}&object_id=$object_id'>";
1155 printImageHREF ('delete', 'Delete this IPv4 address');
1156 echo "</a></td>";
1157 echo "<td class=tdleft><input type='text' name='bond_name' value='${alloc['osif']}' size=10></td>";
1158 echo "<td class=tdleft><a href='${root}?page=ipaddress&ip=${dottedquad}'>${dottedquad}</a>";
1159 if (getConfigVar ('EXT_IPV4_VIEW') != 'yes')
1160 {
1161 if (NULL === $netid)
1162 $suffix = '/??';
1163 else
1164 echo '<small>/' . $netinfo['mask'] . '</small>';
1165 }
1166 echo '&nbsp;' . $aac[$alloc['type']];
1167 if (!empty ($alloc['addrinfo']['name']))
1168 echo '(' . niftyString ($alloc['addrinfo']['name']) . ')';
1169 echo '</td>';
1170 // FIXME: this a copy-and-paste from renderRackObject()
1171 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
1172 {
1173 if (NULL === $netid)
1174 echo '<td colspan=2>?</td>';
1175 else
1176 printIPv4NetInfoTDs ($netinfo);
1177 echo "<td class='${secondclass}'>";
1178 // FIXME: These cals are really heavy, replace them with a more appropriate dedicated function.
1179 $netdata = getIPv4Network ($netid);
1180 $newline = '';
1181 foreach (findRouters ($netdata['addrlist']) as $router)
1182 {
1183 if ($router['id'] == $object_id)
1184 continue;
1185 echo $newline . $router['addr'] . ", <a href='${root}?page=object&object_id=${router['id']}&hl_ipv4_addr=${router['addr']}'>";
1186 echo (empty ($router['iface']) ? '' : $router['iface'] . '@') . $router['dname'] . '</a>';
1187 $routertags = loadRackObjectTags ($router['id']);
1188 if (count ($routertags))
1189 echo '<br><small>' . serializeTags ($routertags, "${root}?page=objects&tab=default&") . '</small>';
1190 $newline = '<br>';
1191 }
1192 echo '</td>';
1193 }
1194 echo '<td>';
1195 printSelect ($aat, 'bond_type', $alloc['type']);
1196 echo "</td><td>";
1197 $prefix = '';
1198 if ($alloc['addrinfo']['reserved'] == 'yes')
1199 {
1200 echo $prefix . '<strong>RESERVED</strong>';
1201 $prefix = '; ';
1202 }
1203 foreach ($alloc['addrinfo']['allocs'] as $allocpeer)
1204 {
1205 if ($allocpeer['object_id'] == $object_id)
1206 continue;
1207 echo $prefix . "<a href='${root}?page=object&object_id=${allocpeer['object_id']}'>";
1208 if (!empty ($allocpeer['osif']))
1209 echo $allocpeer['osif'] . '@';
1210 echo $allocpeer['object_name'] . '</a>';
1211 $prefix = '; ';
1212 }
1213 echo "</td><td>";
1214 printImageHREF ('save', 'Save changes', TRUE);
1215 echo "</td></form></tr>\n";
1216 }
1217
1218 printOpFormIntro ('addIPv4Allocation');
1219 echo "<tr><td>";
1220 printImageHREF ('add', 'Allocate new address', TRUE, 99);
1221 echo "</td>";
1222 echo "<td class=tdleft><input type='text' size='10' name='bond_name' tabindex=100></td>\n";
1223 echo "<td class=tdleft><input type=text name='ip' tabindex=101></td>\n";
1224 echo "<td colspan=3>&nbsp;</td><td>";
1225 printSelect ($aat, 'bond_type');
1226 echo "</td><td colspan=2>&nbsp;</td></tr></form></table><br>\n";
1227 finishPortlet();
1228
1229 }
1230
1231 // Log structure versions:
1232 // 1: the whole structure is a list of code-message pairs
1233 // 2 and later: there's a "v" field set, which indicates the version
1234 // 2: there's a "m" list set to hold message code and optional arguments
1235 function printLog ($log)
1236 {
1237 switch (TRUE)
1238 {
1239 case !isset ($log['v']):
1240 case $log['v'] == 1:
1241 foreach ($log as $key => $record)
1242 if ($key !== 'v')
1243 echo "<div class=msg_${record['code']}>${record['message']}</div>";
1244 break;
1245 case $log['v'] == 2:
1246 $msginfo = array
1247 (
1248 0 => array ('code' => 'success', 'format' => 'Success: %s'),
1249 1 => array ('code' => 'success', 'format' => '%u new records done, %u already existed'),
1250 2 => array ('code' => 'success', 'format' => 'NATv4 rule was successfully added.'),
1251 3 => array ('code' => 'success', 'format' => 'NATv4 rule was successfully deleted.'),
1252 4 => array ('code' => 'success', 'format' => 'NATv4 rule was successfully updated'),
1253 5 => array ('code' => 'success', 'format' => 'Port %s was added successfully'),
1254 6 => array ('code' => 'success', 'format' => 'Port %s was updated successfully'),
1255 7 => array ('code' => 'success', 'format' => 'Port %s was deleted successfully'),
1256 8 => array ('code' => 'success', 'format' => 'Port %s successfully linked with port %s at object %s'),
1257 9 => array ('code' => 'success', 'format' => 'Port %s was successfully unlinked from %s@%s'),
1258 10 => array ('code' => 'success', 'format' => 'Added %u ports, updated %u ports, encountered %u errors.'),
1259 11 => array ('code' => 'success', 'format' => 'Reservation removed.'),
1260 12 => array ('code' => 'success', 'format' => 'allocation updated'),
1261 13 => array ('code' => 'success', 'format' => 'allocated'),
1262 14 => array ('code' => 'success', 'format' => 'deallocated'),
1263 15 => array ('code' => 'success', 'format' => 'Reset succeeded.'),
1264 16 => array ('code' => 'success', 'format' => 'Update done'),
1265 17 => array ('code' => 'success', 'format' => 'Update(s) succeeded.'),
1266 18 => array ('code' => 'success', 'format' => 'Load balancer was successfully added'),
1267 19 => array ('code' => 'success', 'format' => 'Load balancer was successfully deleted'),
1268 20 => array ('code' => 'success', 'format' => 'Load balancer info was successfully updated'),
1269 21 => array ('code' => 'success', 'format' => 'Generation complete'),
1270 22 => array ('code' => 'success', 'format' => 'Chained %u tags'),
1271 23 => array ('code' => 'success', 'format' => 'IPv4 prefix successfully added'),
1272 24 => array ('code' => 'success', 'format' => 'IPv4 prefix deleted'),
1273 25 => array ('code' => 'success', 'format' => 'IPv4 prefix updated'),
1274 26 => array ('code' => 'success', 'format' => '%u IP address(es) were successfully updated'),
1275 27 => array ('code' => 'success', 'format' => 'IPv4 address updated'),
1276 28 => array ('code' => 'success', 'format' => 'Virtual service was successfully created'),
1277 29 => array ('code' => 'success', 'format' => 'Virtual service was successfully deleted'),
1278 30 => array ('code' => 'success', 'format' => 'Virtual service was successfully updated'),
1279 31 => array ('code' => 'success', 'format' => 'RS pool was successfully created'),
1280 32 => array ('code' => 'success', 'format' => 'RS pool was successfully deleted'),
1281 33 => array ('code' => 'success', 'format' => 'RS pool was successfully updated'),
1282 34 => array ('code' => 'success', 'format' => 'Real server was successfully added'),
1283 35 => array ('code' => 'success', 'format' => 'Real server was successfully deleted'),
1284 36 => array ('code' => 'success', 'format' => 'Real server was successfully updated'),
1285 37 => array ('code' => 'success', 'format' => 'Successfully added %u real servers'),
1286 38 => array ('code' => 'success', 'format' => '%u real server(s) were successfully (de)activated'),
1287 39 => array ('code' => 'success', 'format' => 'User account %s updated.'),
1288 40 => array ('code' => 'success', 'format' => 'User account %s created.'),
1289 41 => array ('code' => 'success', 'format' => 'User account disabled.'),
1290 42 => array ('code' => 'success', 'format' => 'User account enabled.'),
1291 43 => array ('code' => 'success', 'format' => 'Saved successfully.'),
1292 44 => array ('code' => 'success', 'format' => '%s failures and %s successfull changes.'),
1293 45 => array ('code' => 'success', 'format' => "Attribute '%s' created."),
1294 46 => array ('code' => 'success', 'format' => 'Rename successful.'),
1295 47 => array ('code' => 'success', 'format' => 'Attribute was deleted.'),
1296 48 => array ('code' => 'success', 'format' => 'Supplement succeeded.'),
1297 49 => array ('code' => 'success', 'format' => 'Reduction succeeded.'),
1298 50 => array ('code' => 'success', 'format' => 'Reduction succeeded.'),
1299 51 => array ('code' => 'success', 'format' => 'Update succeeded.'),
1300 52 => array ('code' => 'success', 'format' => 'Supplement succeeded.'),
1301 53 => array ('code' => 'success', 'format' => 'Chapter was deleted.'),
1302 54 => array ('code' => 'success', 'format' => 'Chapter was updated.'),
1303 55 => array ('code' => 'success', 'format' => 'Chapter was added.'),
1304 56 => array ('code' => 'success', 'format' => 'Update succeeded.'),
1305 57 => array ('code' => 'success', 'format' => 'Reset complete'),
1306 58 => array ('code' => 'success', 'format' => "Successfully deleted tag ."),
1307 59 => array ('code' => 'success', 'format' => "Created tag '%s'."),
1308 60 => array ('code' => 'success', 'format' => "Updated tag '%s'."),
1309 61 => array ('code' => 'success', 'format' => 'Password changed successfully.'),
1310 62 => array ('code' => 'success', 'format' => 'gw: %s'),
1311 63 => array ('code' => 'success', 'format' => '%u change request(s) have been processed'),
1312 64 => array ('code' => 'success', 'format' => 'Port %s@%s has been assigned to VLAN %u'),
1313 65 => array ('code' => 'success', 'format' => "Added new rack '%s'"),
1314 66 => array ('code' => 'success', 'format' => "File sent Ok via handler '%s'"),
1315 67 => array ('code' => 'success', 'format' => "Tag rolling done, %u objects involved"),
1316 68 => array ('code' => 'success', 'format' => "Updated rack '%s'"),
1317
1318 100 => array ('code' => 'error', 'format' => 'Generic error: %s'),
1319 101 => array ('code' => 'error', 'format' => 'Port name cannot be empty'),
1320 102 => array ('code' => 'error', 'format' => "Error creating user account '%s'"),
1321 103 => array ('code' => 'error', 'format' => 'getHashByID() failed'),
1322 104 => array ('code' => 'error', 'format' => "Error updating user account '%s'"),
1323 105 => array ('code' => 'error', 'format' => 'Error enabling user account.'),
1324 106 => array ('code' => 'error', 'format' => 'Error disabling user account.'),
1325 107 => array ('code' => 'error', 'format' => 'Admin account cannot be disabled'),
1326 108 => array ('code' => 'error', 'format' => '%u failures and %u successfull changes.'),
1327 109 => array ('code' => 'error', 'format' => 'Update failed!'),
1328 110 => array ('code' => 'error', 'format' => 'Supplement failed!'),
1329 111 => array ('code' => 'error', 'format' => 'Reduction failed!'),
1330 112 => array ('code' => 'error', 'format' => 'Error adding chapter.'),
1331 113 => array ('code' => 'error', 'format' => 'Error updating chapter.'),
1332 114 => array ('code' => 'error', 'format' => 'Error deleting chapter.'),
1333 115 => array ('code' => 'error', 'format' => 'Error renaming attribute.'),
1334 116 => array ('code' => 'error', 'format' => 'Error creating attribute.'),
1335 117 => array ('code' => 'error', 'format' => 'Error deleting attribute.'),
1336 118 => array ('code' => 'error', 'format' => 'Supplement failed!'),
1337 119 => array ('code' => 'error', 'format' => 'Reduction failed!'),
1338 120 => array ('code' => 'error', 'format' => 'Reset failed!'),
1339 121 => array ('code' => 'error', 'format' => 'commitUpdateObject() failed'),
1340 122 => array ('code' => 'error', 'format' => 'One or more update(s) failed!'),
1341 123 => array ('code' => 'error', 'format' => 'Cannot process submitted data: unknown format code.'),
1342 124 => array ('code' => 'error', 'format' => 'Error removing reservation!'),
1343 125 => array ('code' => 'error', 'format' => "Update failed with error: '%s'"),
1344 126 => array ('code' => 'error', 'format' => 'addRStoRSPool() failed'),
1345 127 => array ('code' => 'error', 'format' => 'Added %u real servers and encountered %u errors'),
1346 128 => array ('code' => 'error', 'format' => 'commitDeleteRS() failed'),
1347 129 => array ('code' => 'error', 'format' => 'commitDeleteLB() failed'),
1348 130 => array ('code' => 'error', 'format' => 'commitDeleteVS() failed'),
1349 131 => array ('code' => 'error', 'format' => 'invalid format requested'),
1350 132 => array ('code' => 'error', 'format' => 'invalid protocol'),
1351 133 => array ('code' => 'error', 'format' => 'commitUpdateRS() failed'),
1352 134 => array ('code' => 'error', 'format' => 'commitUpdateLB() failed'),
1353 135 => array ('code' => 'error', 'format' => 'commitUpdateVS() failed'),
1354 136 => array ('code' => 'error', 'format' => 'addLBtoRSPool() failed'),
1355 137 => array ('code' => 'error', 'format' => 'addLBtoRSPool() failed'),
1356 138 => array ('code' => 'error', 'format' => 'commitDeleteRSPool() failed'),
1357 139 => array ('code' => 'error', 'format' => 'commitUpdateRSPool() failed'),
1358 140 => array ('code' => 'error', 'format' => 'Encountered %u errors, (de)activated %u real servers'),
1359 141 => array ('code' => 'error', 'format' => 'Encountered %u errors, updated %u IP address(es)'),
1360 142 => array ('code' => 'error', 'format' => 'executeAutoPorts() failed'),
1361 143 => array ('code' => 'error', 'format' => 'Tried chaining %u tags, but experienced %u errors.'),
1362 144 => array ('code' => 'error', 'format' => "Error deleting tag: '%s'"),
1363 145 => array ('code' => 'error', 'format' => "Invalid tag name '%s'"),
1364 146 => array ('code' => 'error', 'format' => "Tag '%s' (or similar name) already exists"),
1365 147 => array ('code' => 'error', 'format' => "Could not create tag '%s' because of error '%s'"),
1366 148 => array ('code' => 'error', 'format' => "Could not update tag '%s' because of error '%s'"),
1367 149 => array ('code' => 'error', 'format' => 'Turing test failed'),
1368 150 => array ('code' => 'error', 'format' => 'Can only change password under DB authentication.'),
1369 151 => array ('code' => 'error', 'format' => 'Old password doesn\'t match.'),
1370 152 => array ('code' => 'error', 'format' => 'New passwords don\'t match.'),
1371 153 => array ('code' => 'error', 'format' => 'Password change failed.'),
1372 154 => array ('code' => 'error', 'format' => "Verification error: %s"),
1373 155 => array ('code' => 'error', 'format' => 'Save failed.'),
1374 156 => array ('code' => 'error', 'format' => 'getSwitchVLANs() failed'),
1375 157 => array ('code' => 'error', 'format' => 'operation not permitted'),
1376 158 => array ('code' => 'error', 'format' => 'Ignoring malformed record #%u in form submit'),
1377 159 => array ('code' => 'error', 'format' => 'Permission denied moving port %s from VLAN%u to VLAN%u'),
1378 160 => array ('code' => 'error', 'format' => 'Invalid arguments'),
1379 161 => array ('code' => 'error', 'format' => 'Endpoint not found. Please either set FQDN attribute or assign an IP address to the object.'),
1380 162 => array ('code' => 'error', 'format' => 'More than one IP address is assigned to this object, please configure FQDN attribute.'),
1381 163 => array ('code' => 'error', 'format' => 'Failed to get any response from queryGateway() or the gateway died'),
1382 164 => array ('code' => 'error', 'format' => 'Gateway failure: %s.'),
1383 165 => array ('code' => 'error', 'format' => 'Gateway failure: malformed reply.'),
1384 166 => array ('code' => 'error', 'format' => 'gw: %s'),
1385 167 => array ('code' => 'error', 'format' => 'Could not find port %s'),
1386 168 => array ('code' => 'error', 'format' => 'Port %s is a trunk'),
1387 169 => array ('code' => 'error', 'format' => 'Failed to configure %s, connector returned code %u'),
1388 170 => array ('code' => 'error', 'format' => 'There is no network for IP address "%s"'),
1389 171 => array ('code' => 'error', 'format' => "Failed creating rack '%s'. Already exists in this row?"),
1390 172 => array ('code' => 'error', 'format' => 'Malformed request'),
1391 173 => array ('code' => 'error', 'format' => "Invalid IPv4 prefix '%s'"),
1392 174 => array ('code' => 'error', 'format' => 'Bad IPv4 address'),
1393 175 => array ('code' => 'error', 'format' => 'Invalid netmask'),
1394 176 => array ('code' => 'error', 'format' => 'This network already exists'),
1395 177 => array ('code' => 'error', 'format' => 'commitUpdateRack() failed'),
1396
1397 200 => array ('code' => 'warning', 'format' => 'generic warning: %s'),
1398 201 => array ('code' => 'warning', 'format' => 'nothing happened...'),
1399 202 => array ('code' => 'warning', 'format' => 'gw: %s'),
1400 203 => array ('code' => 'warning', 'format' => 'Port %s seems to be the first in VLAN %u at this switch.'),
1401 204 => array ('code' => 'warning', 'format' => 'Check uplink/downlink configuration for proper operation.'),
1402 205 => array ('code' => 'warning', 'format' => '%u change request(s) have been ignored'),
1403 );
1404 // Handle the arguments. Is there any better way to do it?
1405 foreach ($log['m'] as $record)
1406 {
1407 if (!isset ($record['c']) or !isset ($msginfo[$record['c']]))
1408 {
1409 echo '<div class=msg_neutral>(this message was lost)</div>';
1410 continue;
1411 }
1412 if (isset ($record['a']))
1413 switch (count ($record['a']))
1414 {
1415 case 1:
1416 $msgtext = sprintf
1417 (
1418 $msginfo[$record['c']]['format'],
1419 $record['a'][0]
1420 );
1421 break;
1422 case 2:
1423 $msgtext = sprintf
1424 (
1425 $msginfo[$record['c']]['format'],
1426 $record['a'][0],
1427 $record['a'][1]
1428 );
1429 break;
1430 case 3:
1431 $msgtext = sprintf
1432 (
1433 $msginfo[$record['c']]['format'],
1434 $record['a'][0],
1435 $record['a'][1],
1436 $record['a'][2]
1437 );
1438 break;
1439 case 4:
1440 default:
1441 $msgtext = sprintf
1442 (
1443 $msginfo[$record['c']]['format'],
1444 $record['a'][0],
1445 $record['a'][1],
1446 $record['a'][2],
1447 $record['a'][3]
1448 );
1449 break;
1450 }
1451 else
1452 $msgtext = $msginfo[$record['c']]['format'];
1453 echo '<div class=msg_' . $msginfo[$record['c']]['code'] . ">${msgtext}</div>";
1454 }
1455 break;
1456 default:
1457 echo '<div class=msg_error>' . __FUNCTION__ . ': internal error</div>';
1458 break;
1459 }
1460 }
1461
1462 /*
1463 The following conditions must be followed:
1464 1. We can mount onto free atoms only. This means: if any record for an atom
1465 already exists in RackSpace, it can't be used for mounting.
1466 2. We can't unmount from 'W' atoms. Operator should review appropriate comments
1467 and either delete them before unmounting or refuse to unmount the object.
1468 */
1469
1470 // We extensively use $_REQUEST in the function.
1471 // FIXME: move related code into ophandler
1472 function renderRackSpaceForObject ($object_id = 0)
1473 {
1474 if ($object_id <= 0)
1475 {
1476 showError ('Invalid object_id', __FUNCTION__);
1477 return;
1478 }
1479 $is_submit = isset ($_REQUEST['got_atoms']);
1480 $is_update = isset ($_REQUEST['rackmulti'][0]);
1481 $info = getObjectInfo ($object_id);
1482 if ($info == NULL)
1483 {
1484 showError ('getObjectInfo() failed', __FUNCTION__);
1485 return;
1486 }
1487 // Always process occupied racks plus racks chosen by user. First get racks with
1488 // already allocated rackspace...
1489 $workingRacksData = getResidentRacksData ($object_id);
1490 if ($workingRacksData === NULL)
1491 {
1492 print_r ($workingRacksData);
1493 showError ('getResidentRacksData() failed', __FUNCTION__);
1494 return;
1495 }
1496
1497 // ...and then add those chosen by user (if any).
1498 if ($is_update)
1499 foreach ($_REQUEST['rackmulti'] as $cand_id)
1500 {
1501 if (!isset ($workingRacksData[$cand_id]))
1502 {
1503 $rackData = getRackData ($cand_id);
1504 if ($rackData == NULL)
1505 {
1506 showError ('getRackData() failed', __FUNCTION__);
1507 return NULL;
1508 }
1509 $workingRacksData[$cand_id] = $rackData;
1510 }
1511 }
1512
1513 // Do it only once...
1514 foreach ($workingRacksData as &$rackData)
1515 applyObjectMountMask ($rackData, $object_id);
1516 // Now we workaround an old caveat: http://bugs.php.net/bug.php?id=37410
1517 unset ($rackData);
1518
1519 // Here we process form submit by trying to save all submitted info to database.
1520 if ($is_submit)
1521 {
1522 $oldMolecule = getMoleculeForObject ($object_id);
1523 $worldchanged = FALSE;
1524 $log = array();
1525 foreach ($workingRacksData as $rack_id => $rackData)
1526 {
1527 $logrecord = processGridForm ($rackData, 'F', 'T', $object_id);
1528 $log[] = $logrecord;
1529 if ($logrecord['code'] != 300)
1530 {
1531 $worldchanged = TRUE;
1532 // Reload our working copy after form processing.
1533 $rackData = getRackData ($rack_id);
1534 if ($rackData == NULL)
1535 $log[] = array ('code' => 500, 'message' => 'Working copy update failed in ', __FUNCTION__);
1536 applyObjectMountMask ($rackData, $object_id);
1537 $workingRacksData[$rack_id] = $rackData;
1538 }
1539 }
1540 if ($worldchanged)
1541 {
1542 // Log a record.
1543 $newMolecule = getMoleculeForObject ($object_id);
1544 $oc = count ($oldMolecule);
1545 $nc = count ($newMolecule);
1546 $omid = $oc ? createMolecule ($oldMolecule) : 'NULL';
1547 $nmid = $nc ? createMolecule ($newMolecule) : 'NULL';
1548 global $remote_username;
1549 $comment = empty ($_REQUEST['comment']) ? 'NULL' : "'${_REQUEST['comment']}'";
1550 $query =
1551 "insert into MountOperation(object_id, old_molecule_id, new_molecule_id, user_name, comment) " .
1552 "values (${object_id}, ${omid}, ${nmid}, '${remote_username}', ${comment})";
1553 global $dbxlink;
1554 $result = $dbxlink->query ($query);
1555 if ($result == NULL)
1556 $log[] = array ('code' => 'error', 'message' => 'SQL query failed during history logging.');
1557 else
1558 $log[] = array ('code' => 'success', 'message' => 'History logged.');
1559 }
1560 printLog ($log);
1561 }
1562
1563 // This is the time for rendering.
1564 global $root, $pageno, $tabno;
1565 echo "<form id='racks' action='${root}'>";
1566 echo "<input type=hidden name=page value='${pageno}'>\n";
1567 echo "<input type=hidden name=tab value='${tabno}'>\n";
1568 echo "<input type=hidden name=object_id value='${object_id}'>\n";
1569 // Main layout starts.
1570 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0><tr>";
1571
1572 // Left portlet with rack list.
1573 echo "<td class=pcleft height='1%'>";
1574 startPortlet ('Racks');
1575 $allRacksData = getRacksForRow();
1576 if (count ($allRacksData) <= getConfigVar ('RACK_PRESELECT_THRESHOLD'))
1577 {
1578 foreach (array_keys ($allRacksData) as $rack_id)
1579 {
1580 $rackData = getRackData ($rack_id);
1581 if ($rackData == NULL)
1582 {
1583 showError ('getRackData() failed', __FUNCTION__);
1584 return NULL;
1585 }
1586 $workingRacksData[$rack_id] = $rackData;
1587 }
1588 foreach ($workingRacksData as &$rackData)
1589 applyObjectMountMask ($rackData, $object_id);
1590 unset ($rackData);
1591 }
1592 renderRackMultiSelect ('rackmulti[]', $allRacksData, array_keys ($workingRacksData));
1593 echo "<br>";
1594 echo "<br>";
1595 finishPortlet();
1596 echo "</td>";
1597
1598 // Middle portlet with comment and submit.
1599 echo "<td class=pcleft>";
1600 startPortlet ('Comment');
1601 echo "<textarea name=comment rows=10 cols=40></textarea><br>\n";
1602 echo "<input type=submit value='Save' name=got_atoms>\n";
1603 echo "<br>";
1604 echo "<br>";
1605 finishPortlet();
1606 echo "</td>";
1607
1608 // Right portlet with rendered racks. If this form submit is not final, we have to
1609 // reflect the former state of the grid in current form.
1610 echo "<td class=pcright rowspan=2 height='1%'>";
1611 startPortlet ('Working copy');
1612 echo '<table border=0 cellspacing=10 align=center><tr>';
1613 foreach ($workingRacksData as $rack_id => $rackData)
1614 {
1615 // Order is important here: only original allocation is highlighted.
1616 highlightObject ($rackData, $object_id);
1617 markupAtomGrid ($rackData, 'T');
1618 // If we have a form processed, discard user input and show new database
1619 // contents.
1620 if (!$is_submit and $is_update)
1621 mergeGridFormToRack ($rackData);
1622 echo "<td valign=top>";
1623 echo "<center>\n<h2>${rackData['name']}</h2>\n";
1624 echo "<table class=rack border=0 cellspacing=0 cellpadding=1>\n";
1625 echo "<tr><th width='10%'>&nbsp;</th><th width='20%'>Front</th>";
1626 echo "<th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n";
1627 renderAtomGrid ($rackData);
1628 echo "<tr><th width='10%'>&nbsp;</th><th width='20%'>Front</th>";
1629 echo "<th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n";
1630 echo "</table></center>\n";
1631 echo '</td>';
1632 }
1633 echo "</tr></table>";
1634 finishPortlet();
1635 echo "</td>\n";
1636
1637 echo "</form>\n";
1638 echo "</tr></table>\n";
1639 }
1640
1641 function renderMolecule ($mdata, $object_id)
1642 {
1643 // sort data out
1644 $rackpack = array();
1645 global $loclist;
1646 foreach ($mdata as $rua)
1647 {
1648 $rack_id = $rua['rack_id'];
1649 $unit_no = $rua['unit_no'];
1650 $atom = $rua['atom'];
1651 if (!isset ($rackpack[$rack_id]))
1652 {
1653 $rackData = getRackData ($rack_id);
1654 for ($i = $rackData['height']; $i > 0; $i--)
1655 for ($locidx = 0; $locidx < 3; $locidx++)
1656 $rackData[$i][$locidx]['state'] = 'F';
1657 $rackpack[$rack_id] = $rackData;
1658 }
1659 $rackpack[$rack_id][$unit_no][$loclist[$atom]]['state'] = 'T';
1660 $rackpack[$rack_id][$unit_no][$loclist[$atom]]['object_id'] = $object_id;
1661 }
1662 // now we have some racks to render
1663 foreach ($rackpack as $rackData)
1664 {
1665 markAllSpans ($rackData);
1666 echo "<table class=molecule cellspacing=0>\n";
1667 echo "<caption>${rackData['name']}</caption>\n";
1668 echo "<tr><th width='10%'>&nbsp;</th><th width='20%'>Front</th><th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n";
1669 for ($i = $rackData['height']; $i > 0; $i--)
1670 {
1671 echo "<tr><th>$i</th>";
1672 for ($locidx = 0; $locidx < 3; $locidx++)
1673 {
1674 $state = $rackData[$i][$locidx]['state'];
1675 echo "<td class=state_${state}>&nbsp;</td>\n";
1676 }
1677 echo "</tr>\n";
1678 }
1679 echo "</table>\n";
1680 }
1681 }
1682
1683 function renderUnmountedObjectsPortlet ()
1684 {
1685 startPortlet ('Unmounted objects');
1686 $objs = getUnmountedObjects();
1687 if ($objs === NULL)
1688 {
1689 showError ('getUnmountedObjects() failed', __FUNCTION__);
1690 return;
1691 }
1692 global $root, $nextorder;
1693 $order = 'odd';
1694 echo '<br><br><table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
1695 echo '<tr><th>Common name</th><th>Visible label</th><th>Asset number</th><th>Barcode</th></tr>';
1696 foreach ($objs as $obj)
1697 {
1698 echo "<tr class=row_${order}><td><a href='${root}?page=object&object_id=${obj['id']}'>${obj['dname']}</a></td>";
1699 echo "<td>${obj['label']}</td>";
1700 echo "<td>${obj['asset_no']}</td>";
1701 echo "<td>${obj['barcode']}</td></tr>";
1702 $order = $nextorder[$order];
1703 }
1704 echo "</table><br>\n";
1705 finishPortlet();
1706 }
1707
1708 function renderProblematicObjectsPortlet ()
1709 {
1710 startPortlet ('Problematic objects');
1711 $objs = getProblematicObjects();
1712 if ($objs === NULL)
1713 {
1714 showError ('getProblematicObjects() failed', __FUNCTION__);
1715 return;
1716 }
1717 global $root, $nextorder;
1718 $order = 'odd';
1719 echo '<br><br><table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
1720 echo '<tr><th>Type</th><th>Common name</th></tr>';
1721 foreach ($objs as $obj)
1722 {
1723 echo "<tr class=row_${order}><td>${obj['objtype_name']}</td>";
1724 echo "<td><a href='${root}?page=object&object_id=${obj['id']}'>${obj['dname']}</a></tr>";
1725 $order = $nextorder[$order];
1726 }
1727 echo "</table><br>\n";
1728 finishPortlet();
1729 }
1730
1731 function renderObjectSpace ()
1732 {
1733 global $root, $taglist, $tagtree;
1734 echo "<table border=0 class=objectview>\n";
1735 echo "<tr><td class=pcleft width='50%'>";
1736 startPortlet ('View all by type');
1737 $groupInfo = getObjectGroupInfo();
1738 if ($groupInfo === NULL)
1739 {
1740 showError ('getObjectGroupInfo() failed', __FUNCTION__);
1741 return;
1742 }
1743 if (count ($groupInfo) == 0)
1744 echo "No objects exist in DB";
1745 else
1746 {
1747 echo '<div align=left><ul>';
1748 foreach ($groupInfo as $gi)
1749 echo "<li><a href='${root}?page=objgroup&group_id=${gi['id']}'>${gi['name']}</a> (${gi['count']})</li>";
1750 echo '</ul></div>';
1751 }
1752 finishPortlet();
1753
1754 echo '</td><td class=pcright>';
1755
1756 startPortlet ('View all by tag');
1757 if (count ($taglist) == 0)
1758 echo "No tags exist in DB";
1759 else
1760 renderTagCloud ('object');
1761 finishPortlet();
1762 echo "</td></tr></table>\n";
1763 }
1764
1765 function renderObjectGroup ()
1766 {
1767 global $root, $pageno, $tabno, $nextorder, $taglist, $tagtree;
1768 assertUIntArg ('group_id', __FUNCTION__, TRUE);
1769 $group_id = $_REQUEST['group_id'];
1770 $tagfilter = getTagFilter();
1771 $tagfilter_str = getTagFilterStr ($tagfilter);
1772 echo "<table border=0 class=objectview>\n";
1773 echo "<tr><td class=pcleft width='25%'>";
1774 startPortlet ('change type');
1775 $groupInfo = getObjectGroupInfo();
1776 if ($groupInfo === NULL)
1777 {
1778 showError ('getObjectGroupInfo() failed', __FUNCTION__);
1779 return;
1780 }
1781 if (count ($groupInfo) == 0)
1782 echo "No objects exist in DB";
1783 else
1784 {
1785 echo '<div align=left><ul>';
1786 foreach ($groupInfo as $gi)
1787 {
1788 echo "<li><a href='${root}?page=${pageno}&group_id=${gi['id']}${tagfilter_str}'>";
1789 if ($gi['id'] == $group_id)
1790 echo '<strong>';
1791 echo "${gi['name']}</a>";
1792 if ($gi['id'] == $group_id)
1793 echo '</strong>';
1794 echo " (${gi['count']})";
1795 if ($gi['id'] == $group_id)
1796 echo ' &larr;';
1797 echo "</li>";
1798 }
1799 echo '</ul></div>';
1800 }
1801 finishPortlet();
1802
1803 echo '</td><td class=pcleft>';
1804
1805 startPortlet ('Objects');
1806 $objects = getObjectList ($group_id, $tagfilter, getTFMode());
1807 if ($objects === NULL)
1808 {
1809 showError ('getObjectList() failed', __FUNCTION__);
1810 return;
1811 }
1812 echo '<br><br><table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
1813 echo '<tr><th>Common name</th><th>Visible label</th><th>Asset tag</th><th>Barcode</th><th>Rack</th></tr>';
1814 $order = 'odd';
1815 foreach ($objects as $obj)
1816 {
1817 if (isset ($_REQUEST['hl_object_id']) and $_REQUEST['hl_object_id'] == $obj['id'])
1818 $secondclass = 'tdleft port_highlight';
1819 else
1820 $secondclass = 'tdleft';
1821 echo "<tr class=row_${order}><td class='${secondclass}'><a href='${root}?page=object&object_id=${obj['id']}'>${obj['dname']}</a></td>";
1822 echo "<td class='${secondclass}'>${obj['label']}</td>";
1823 echo "<td class='${secondclass}'>${obj['asset_no']}</td>";
1824 echo "<td class='${secondclass}'>${obj['barcode']}</td>";
1825 if ($obj['rack_id'])
1826 echo "<td class='${secondclass}'><a href='${root}?page=rack&rack_id=${obj['rack_id']}'>${obj['Rack_name']}</a></td>";
1827 else
1828 echo "<td class='${secondclass}'>Unmounted</td>";
1829 echo '</tr>';
1830 $order = $nextorder[$order];
1831 }
1832 echo '</table>';
1833 finishPortlet();
1834
1835 echo "</td><td class=pcright width='25%'>";
1836
1837 renderTagFilterPortlet ($tagfilter, 'object', 'group_id', $group_id);
1838 echo "</td></tr></table>\n";
1839 }
1840
1841 function renderEmptyPortsSelect ($port_id, $type_id)
1842 {
1843 $ports = getEmptyPortsOfType($type_id);
1844 usort($ports, 'sortEmptyPorts');
1845 foreach ($ports as $port)
1846 {
1847 if ($port_id == $port['Port_id'])
1848 continue;
1849 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";
1850 }
1851 }
1852
1853 function renderAllIPv4Allocations ()
1854 {
1855 $addresses = getAllIPv4Allocations();
1856 usort($addresses, 'sortObjectAddressesAndNames');
1857 foreach ($addresses as $address)
1858 {
1859 echo "<option value='${address['ip']}' onclick='getElementById(\"ip\").value=\"${address['ip']}\";'>${address['object_name']} ${address['name']} ${address['ip']}</option>\n";
1860 }
1861 }
1862
1863 // History viewer for history-enabled simple dictionaries.
1864 function renderHistory ($object_type, $object_id)
1865 {
1866 switch ($object_type)
1867 {
1868 case 'row':
1869 $query = "select ctime, user_name, name, deleted, comment from RackRowHistory where id = ${object_id} order by ctime";
1870 $header = '<tr><th>change time</th><th>author</th><th>rack row name</th><th>is deleted?</th><th>rack row comment</th></tr>';
1871 $extra = 4;
1872 break;
1873 case 'rack':
1874 $query =
1875 "select ctime, user_name, rh.name, rh.deleted, d.dict_value as name, rh.height, rh.comment " .
1876 "from RackHistory as rh left join Dictionary as d on rh.row_id = d.dict_key " .
1877 "natural join Chapter " .
1878 "where chapter_name = 'RackRow' and rh.id = ${object_id} order by ctime";
1879 $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>';
1880 $extra = 6;
1881 break;
1882 case 'object':
1883 $query =
1884 "select ctime, user_name, name, label, barcode, asset_no, deleted, has_problems, dict_value, comment " .
1885 "from RackObjectHistory inner join Dictionary on objtype_id = dict_key natural join Chapter " .
1886 "where chapter_name = 'RackObjectType' and id=${object_id} order by ctime";
1887 $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>';
1888 $extra = 9;
1889 break;
1890 default:
1891 showError ("Uknown object type '${object_type}'", __FUNCTION__);
1892 return;
1893 }
1894 global $dbxlink;
1895 $result = $dbxlink->query ($query);
1896 if ($result == NULL)
1897 {
1898 showError ('SQL query failed', __FUNCTION__);
1899 return;
1900 }
1901 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
1902 $order = 'odd';
1903 global $nextorder;
1904 echo $header;
1905 while ($row = $result->fetch (PDO::FETCH_NUM))
1906 {
1907 echo "<tr class=row_${order}><td>${row[0]}</td>";
1908 for ($i = 1; $i <= $extra; $i++)
1909 echo "<td>" . $row[$i] . "</td>";
1910 echo "</tr>\n";
1911 $order = $nextorder[$order];
1912 }
1913 echo "</table><br>\n";
1914 }
1915
1916 function renderRackspaceHistory ()
1917 {
1918 global $root, $nextorder, $pageno, $tabno;
1919 $order = 'odd';
1920 $history = getRackspaceHistory();
1921 // Show the last operation by default.
1922 if (isset ($_REQUEST['op_id']))
1923 $op_id = $_REQUEST['op_id'];
1924 elseif (isset ($history[0]['mo_id']))
1925 $op_id = $history[0]['mo_id'];
1926 else $op_id = NULL;
1927
1928 $omid = NULL;
1929 $nmid = NULL;
1930 $object_id = 1;
1931 if ($op_id)
1932 list ($omid, $nmid) = getOperationMolecules ($op_id);
1933
1934 // Main layout starts.
1935 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
1936
1937 // Left top portlet with old allocation.
1938 echo "<tr><td class=pcleft>";
1939 startPortlet ('Old allocation');
1940 if ($omid)
1941 {
1942 $oldMolecule = getMolecule ($omid);
1943 renderMolecule ($oldMolecule, $object_id);
1944 }
1945 else
1946 echo "nothing";
1947 finishPortlet();
1948
1949 echo '</td><td class=pcright>';
1950
1951 // Right top portlet with new allocation
1952 startPortlet ('New allocation');
1953 if ($nmid)
1954 {
1955 $newMolecule = getMolecule ($nmid);
1956 renderMolecule ($newMolecule, $object_id);
1957 }
1958 else
1959 echo "nothing";
1960 finishPortlet();
1961
1962 echo '</td></tr><tr><td colspan=2>';
1963
1964 // Bottom portlet with list
1965
1966 startPortlet ('Rackspace allocation history');
1967 echo "<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>\n";
1968 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";
1969 foreach ($history as $row)
1970 {
1971 if ($row['mo_id'] == $op_id)
1972 $class = 'hl';
1973 else
1974 $class = "row_${order}";
1975 echo "<tr class=${class}><td><a href='${root}?page=${pageno}&tab=${tabno}&op_id=${row['mo_id']}'>${row['ctime']}</a></td>";
1976 echo "<td>${row['user_name']}</td>";
1977 echo "<td>${row['ro_id']}</td><td>${row['objtype_name']}</td><td>${row['name']}</td><td>${row['comment']}</td>\n";
1978 echo "</tr>\n";
1979 $order = $nextorder[$order];
1980 }
1981 echo "</table>\n";
1982 finishPortlet();
1983
1984 echo '</td></tr></table>';
1985
1986 }
1987
1988 function renderIPv4Space ()
1989 {
1990 global $root, $pageno;
1991
1992 echo "<table border=0 class=objectview>\n";
1993 echo "<tr><td class=pcleft>";
1994
1995 $tagfilter = getTagFilter();
1996 $addrspaceList = getAddressspaceList ($tagfilter, getTFMode());
1997 $tagcache = array();
1998 startPortlet ('networks (' . count ($addrspaceList) . ')');
1999 echo "<table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
2000 echo "<tr><th>prefix</th><th>name/tags</th><th>%% used</th>";
2001 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
2002 echo "<th>routed by</th>";
2003 echo "</tr>\n";
2004 foreach ($addrspaceList as $iprange)
2005 {
2006 $netdata = getIPv4Network ($iprange['id']);
2007 $total = ($netdata['ip_bin'] | $netdata['mask_bin_inv']) - ($netdata['ip_bin'] & $netdata['mask_bin']) + 1;
2008 $used = count ($netdata['addrlist']);
2009 echo "<tr valign=top>";
2010 printIPv4NetInfoTDs ($netdata);
2011 echo "<td class=tdcenter>";
2012 renderProgressBar ($used/$total);
2013 echo "<br><small>${used}/${total}</small></td>";
2014 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
2015 printRoutersTD (findRouters ($netdata['addrlist']), $tagcache);
2016 echo "</tr>";
2017 }
2018 echo "</table>\n";
2019 finishPortlet();
2020 echo '</td><td class=pcright>';
2021 renderTagFilterPortlet ($tagfilter, 'ipv4net');
2022 echo "</td></tr></table>\n";
2023 }
2024
2025 function renderIPv4SLB ()
2026 {
2027 global $root, $page, $nextorder;
2028
2029 startPortlet ('SLB configuration');
2030 echo "<table border=0 width='100%'><tr>";
2031 foreach (array ('ipv4vslist', 'ipv4rsplist', 'rservers', 'lbs') as $pno)
2032 echo "<td><h3><a href='${root}?page=${pno}'>" . $page[$pno]['title'] . "</a></h3></td>";
2033 echo '</tr></table>';
2034 finishPortlet();
2035
2036 $summary = getSLBSummary();
2037 startPortlet ('SLB tactical overview');
2038 // A single id-keyed array isn't used here to preserve existing
2039 // order of LBs returned by getSLBSummary()
2040 $lblist = array();
2041 $lbdname = array();
2042 foreach ($summary as $vipdata)
2043 foreach (array_keys ($vipdata['lblist']) as $lb_object_id)
2044 if (!in_array ($lb_object_id, $lblist))
2045 {
2046 $oi = getObjectInfo ($lb_object_id);
2047 $lbdname[$lb_object_id] = $oi['dname'];
2048 $lblist[] = $lb_object_id;
2049 }
2050 if (!count ($summary))
2051 echo 'none configured';
2052 else
2053 {
2054 $order = 'odd';
2055 echo "<table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
2056 echo "<tr><th>VS&nbsp;&darr; LB&nbsp;&rarr;</th>";
2057 foreach ($lblist as $lb_object_id)
2058 echo "<th><a href='${root}?page=object&tab=default&object_id=${lb_object_id}'>" . $lbdname[$lb_object_id] . "</a></th>";
2059 echo "</tr>\n";
2060 foreach ($summary as $vsid => $vsdata)
2061 {
2062 echo "<tr class=row_${order}><td class=tdleft><a href='$root?page=ipv4vs&tab=default&vs_id=${vsid}'>";
2063 echo buildVServiceName ($vsdata);
2064 echo '</a>';
2065 if (!empty ($vsdata['name']))
2066 echo "<br>${vsdata['name']}";
2067 echo "</td>";
2068 foreach ($lblist as $lb_object_id)
2069 {
2070 echo '<td class=tdleft>';
2071 if (!isset ($vsdata['lblist'][$lb_object_id]))
2072 echo '&nbsp;';
2073 else
2074 {
2075 echo $vsdata['lblist'][$lb_object_id]['size'];
2076 // echo " (<a href='${root}?page=ipv4rsp&pool_id=";
2077 // echo $vsdata['lblist'][$lb_object_id]['id'] . "'>";
2078 // echo $vsdata['lblist'][$lb_object_id]['name'] . '</a>)';
2079 }
2080 echo '</td>';
2081 }
2082 echo "</tr>\n";
2083 $order = $nextorder[$order];
2084 }
2085 echo "</table>\n";
2086 }
2087 finishPortlet ();
2088 }
2089
2090 function renderIPv4SpaceEditor ()
2091 {
2092 global $root, $pageno, $tabno;
2093 showMessageOrError();
2094
2095 // IPv4 validator
2096 ?>
2097 <script type="text/javascript">
2098 function init() {
2099 document.add_new_range.range.setAttribute('match', "^\\d\\d?\\d?\\.\\d\\d?\\d?\\.\\d\\d?\\d?\\.\\d\\d?\\d?\\/\\d\\d?$");
2100
2101 Validate.init();
2102 }
2103 window.onload=init;
2104 </script>
2105 <?php
2106
2107 startPortlet ("Add new");
2108 echo '<table border=0 cellpadding=10 align=center>';
2109 // This form requires a name, so JavaScript validator can find it.
2110 // No printOpFormIntro() hence
2111 echo "<form method=post name='add_new_range' action='${root}process.php'>\n";
2112 echo "<input type=hidden name=op value=addIPv4Prefix>\n";
2113 echo "<input type=hidden name=page value='${pageno}'>\n";
2114 echo "<input type=hidden name=tab value='${tabno}'>\n";
2115 // tags column
2116 echo '<tr><td rowspan=4><h3>assign tags</h3>';
2117 renderTagSelect();
2118 echo '</td>';
2119 // inputs column
2120 echo "<th class=tdright>prefix</th><td class=tdleft><input type=text name='range' size=18 class='live-validate' tabindex=1></td>";
2121 echo "<tr><th class=tdright>name</th><td class=tdleft><input type=text name='name' size='20' tabindex=2></td></tr>";
2122 echo "<tr><th class=tdright>connected network</th><td class=tdleft><input type=checkbox name='is_bcast' tabindex=3 checked></td></tr>";
2123 echo "<tr><td colspan=2>";
2124 printImageHREF ('CREATE', 'Add a new network', TRUE, 4);
2125 echo '</td></tr>';
2126 echo "</form></table><br><br>\n";
2127 finishPortlet();
2128
2129 $addrspaceList = getAddressspaceList();
2130 if (count ($addrspaceList))
2131 {
2132 startPortlet ('Manage existing (' . count ($addrspaceList) . ')');
2133 echo "<table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
2134 echo "<tr><th>&nbsp;</th><th>prefix</th><th>name</th><th>&nbsp;</th></tr>";
2135 foreach ($addrspaceList as $iprange)
2136 {
2137 $netdata = getIPv4Network ($iprange['id']);
2138 $usedips = count ($netdata['addrlist']);
2139 $totalips = ($netdata['ip_bin'] | $netdata['mask_bin_inv']) - ($netdata['ip_bin'] & $netdata['mask_bin']) + 1;
2140 echo "<form method=post action='${root}process.php?page=${pageno}&tab=${tabno}&op=updIPv4Prefix&id=${iprange['id']}'>";
2141 echo '<tr valign=top><td>';
2142 if ($usedips == 0)
2143 {
2144 echo "<a href='${root}process.php?op=delIPv4Prefix&page=${pageno}&tab=${tabno}&id=${iprange['id']}'>";
2145 printImageHREF ('delete', 'Delete this IP range');
2146 echo "</a>";
2147 }
2148 else
2149 printImageHREF ('nodelete', 'There are IP addresses allocated or reserved');
2150 echo "</td>\n<td class=tdleft>${netdata['ip']}/${netdata['mask']}</td>";
2151 echo "<td><input type=text name=name size=40 value='${netdata['name']}'>";
2152 echo "</td><td>";
2153 printImageHREF ('save', 'Save changes', TRUE);
2154 echo "</td></tr></form>\n";
2155 }
2156 echo "</table>";
2157 finishPortlet();
2158 }
2159 }
2160
2161 function renderIPv4Network ($id)
2162 {
2163 global $root, $pageno, $tabno, $aac2;
2164 $netmaskbylen = array
2165 (
2166 32 => '255.255.255.255',
2167 31 => '255.255.255.254',
2168 30 => '255.255.255.252',
2169 29 => '255.255.255.248',
2170 28 => '255.255.255.240',
2171 27 => '255.255.255.224',
2172 26 => '255.255.255.192',
2173 25 => '255.255.255.128',
2174 24 => '255.255.255.0',
2175 23 => '255.255.254.0',
2176 22 => '255.255.252.0',
2177 21 => '255.255.248.0',
2178 20 => '255.255.240.0',
2179 19 => '255.255.224.0',
2180 18 => '255.255.192.0',
2181 17 => '255.255.128.0',
2182 16 => '255.255.0.0',
2183 15 => '255.254.0.0',
2184 14 => '255.252.0.0',
2185 13 => '255.248.0.0',
2186 12 => '255.240.0.0',
2187 11 => '255.224.0.0',
2188 10 => '255.192.0.0',
2189 9 => '255.128.0.0',
2190 8 => '255.0.0.0',
2191 7 => '254.0.0.0',
2192 6 => '252.0.0.0',
2193 5 => '248.0.0.0',
2194 4 => '240.0.0.0',
2195 3 => '224.0.0.0',
2196 2 => '192.0.0.0',
2197 1 => '128.0.0.0'
2198 );
2199 $wildcardbylen = array
2200 (
2201 32 => '0.0.0.0',
2202 31 => '0.0.0.1',
2203 30 => '0.0.0.3',
2204 29 => '0.0.0.7',
2205 28 => '0.0.0.15',
2206 27 => '0.0.0.31',
2207 26 => '0.0.0.63',
2208 25 => '0.0.0.127',
2209 24 => '0.0.0.255',
2210 23 => '0.0.1.255',
2211 22 => '0.0.3.255',
2212 21 => '0.0.7.255',
2213 20 => '0.0.15.255',
2214 19 => '0.0.31.255',
2215 18 => '0.0.63.255',
2216 17 => '0.0.127.255',
2217 16 => '0.0.255.25',
2218 15 => '0.1.255.255',
2219 14 => '0.3.255.255',
2220 13 => '0.7.255.255',
2221 12 => '0.15.255.255',
2222 11 => '0.31.255.255',
2223 10 => '0.63.255.255',
2224 9 => '0.127.255.255',
2225 8 => '0.255.255.255',
2226 7 => '1.255.255.255',
2227 6 => '3.255.255.255',
2228 5 => '7.255.255.255',
2229 4 => '15.255.255.255',
2230 3 => '31.255.255.255',
2231 2 => '63.255.255.255',
2232 1 => '127.255.255.255'
2233 );
2234 $maxperpage = getConfigVar ('IPV4_ADDRS_PER_PAGE');
2235 if (isset($_REQUEST['pg']))
2236 $page = $_REQUEST['pg'];
2237 else
2238 $page=0;
2239
2240 $range = getIPv4Network ($id);
2241 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
2242 echo "<tr><td colspan=2 align=center><h1>${range['ip']}/${range['mask']}</h1><h2>${range['name']}</h2></td></tr>\n";
2243
2244 echo "<tr><td class=pcleft width='50%'>";
2245 startPortlet ('summary');
2246 $total = ($range['ip_bin'] | $range['mask_bin_inv']) - ($range['ip_bin'] & $range['mask_bin']) + 1;
2247 $used = count ($range['addrlist']);
2248 echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
2249
2250 echo "<tr><th width='50%' class=tdright>%% used:</th><td class=tdleft>";
2251 renderProgressBar ($used/$total);
2252 echo "&nbsp;${used}/${total}</td></tr>\n";
2253
2254 echo "<tr><th width='50%' class=tdright>Netmask:</th><td class=tdleft>";
2255 echo $netmaskbylen[$range['mask']];
2256 echo "</td></tr>\n";
2257
2258 echo "<tr><th width='50%' class=tdright>Wildcard bits:</th><td class=tdleft>";
2259 echo $wildcardbylen[$range['mask']];
2260 echo "</td></tr>\n";
2261
2262 $routers = findRouters ($range['addrlist']);
2263 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes' and count ($routers))
2264 {
2265 echo "<tr><th width='50%' class=tdright>Routed by:</th>";
2266 printRoutersTD ($routers);
2267 echo "</tr>\n";
2268 }
2269
2270 printTagTRs ("${root}?page=ipv4space&");
2271 echo "</table><br>\n";
2272 finishPortlet();
2273 echo "</td>\n";
2274
2275 echo "<td class=pcright>";
2276 startPortlet ('details');
2277 $startip = $range['ip_bin'] & $range['mask_bin'];
2278 $endip = $range['ip_bin'] | $range['mask_bin_inv'];
2279 $realstartip = $startip;
2280 $realendip = $endip;
2281 $numpages = 0;
2282 if($endip - $startip > $maxperpage)
2283 {
2284 $numpages = ($endip - $startip)/$maxperpage;
2285 $startip = $startip + $page * $maxperpage;
2286 $endip = $startip + $maxperpage-1;
2287 }
2288 echo "<center>";
2289 if ($numpages)
2290 echo '<h3>' . long2ip ($startip) . ' ~ ' . long2ip ($endip) . '</h3>';
2291 for ($i=0; $i<$numpages; $i++)
2292 {
2293 if ($i == $page)
2294 echo "<b>$i</b> ";
2295 else
2296 echo "<a href='${root}?page=${pageno}&tab=${tabno}&id=$id&pg=$i'>$i</a> ";
2297 }
2298 echo "</center>";
2299
2300 echo "<table class='widetable' border=0 cellspacing=0 cellpadding=5 align='center' width='100%'>\n";
2301 echo "<tr><th>Address</th><th>Name</th><th>Allocation</th></tr>\n";
2302
2303
2304 for ($ip = $startip; $ip <= $endip; $ip++) :
2305 if (isset ($_REQUEST['hl_ipv4_addr']) and ip2long ($_REQUEST['hl_ipv4_addr']) == $ip)
2306 $secondstyle = 'tdleft port_highlight';
2307 else
2308 $secondstyle = 'tdleft';
2309 if (!isset ($range['addrlist'][$ip]))
2310 {
2311 echo "<tr><td class=tdleft><a href='${root}?page=ipaddress&ip=" . long2ip ($ip) . "'>" . long2ip ($ip);
2312 echo "</a></td><td class='${secondstyle}'>&nbsp;</td><td class='${secondstyle}'>&nbsp;</td></tr>\n";
2313 continue;
2314 }
2315 $addr = $range['addrlist'][$ip];
2316 echo "<tr class='${addr['class']}'>";
2317
2318 echo "<td class=tdleft><a href='${root}?page=ipaddress&ip=${addr['ip']}'>${addr['ip']}</a></td>";
2319 echo "<td class='${secondstyle}'>${addr['name']}</td><td class='${secondstyle}'>";
2320 $delim = '';
2321 $prologue = '';
2322 if ( $addr['reserved'] == 'yes')
2323 {
2324 echo "<strong>RESERVED</strong> ";
2325 $delim = '; ';
2326 }
2327 foreach ($range['addrlist'][$ip]['allocs'] as $ref)
2328 {
2329 echo $delim . $aac2[$ref['type']];
2330 echo "<a href='${root}?page=object&object_id=${ref['object_id']}";
2331 echo "&hl_ipv4_addr=${addr['ip']}'>";
2332 echo $ref['name'] . (empty ($ref['name']) ? '' : '@');
2333 echo "${ref['object_name']}</a>";
2334 $delim = '; ';
2335 }
2336 if ($delim != '')
2337 {
2338 $delim = '';
2339 $prologue = '<br>';
2340 }
2341 foreach ($range['addrlist'][$ip]['lblist'] as $ref)
2342 {
2343 echo $prologue;
2344 $prologue = '';
2345 echo "${delim}<a href='${root}?page=object&object_id=${ref['object_id']}'>";
2346 echo "${ref['object_name']}</a>:<a href='${root}?page=ipv4vs&vs_id=${ref['vs_id']}'>";
2347 echo "${ref['vport']}/${ref['proto']}</a>&rarr;";
2348 $delim = '; ';
2349 }
2350 if ($delim != '')
2351 {
2352 $delim = '';
2353 $prologue = '<br>';
2354 }
2355 foreach ($range['addrlist'][$ip]['rslist'] as $ref)
2356 {
2357 echo $prologue;
2358 $prologue = '';
2359 echo "${delim}&rarr;${ref['rsport']}@<a href='${root}?page=ipv4rsp&pool_id=${ref['rspool_id']}'>";
2360 echo "${ref['rspool_name']}</a>";
2361 $delim = '; ';
2362 }
2363 echo "</td></tr>\n";
2364 endfor;
2365 // end of iteration
2366
2367 echo "</table>";
2368 finishPortlet();
2369 echo "</td></tr></table>\n";
2370 }
2371
2372 function renderIPv4NetworkProperties ($id)
2373 {
2374 showMessageOrError();
2375 $netdata = getIPv4NetworkInfo ($id);
2376 echo "<center><h1>${netdata['ip']}/${netdata['mask']}</h1></center>\n";
2377 echo "<table border=0 cellpadding=10 cellpadding=1 align='center'>\n";
2378 printOpFormIntro ('editRange');
2379 echo "<tr><td class='tdright'>Name:</td><td class='tdleft'><input type=text name=name size=20 value='${netdata['name']}'></tr>";
2380 echo "<tr><td colspan=2 class=tdcenter>";
2381 printImageHREF ('SAVE', 'Save changes', TRUE);
2382 echo "</td></form></tr></table>\n";
2383
2384 }
2385
2386 function renderIPv4Address ($dottedquad)
2387 {
2388 global $root, $aat;
2389 $address = getIPv4Address ($dottedquad);
2390 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
2391 echo "<tr><td colspan=2 align=center><h1>${dottedquad}</h1></td></tr>\n";
2392 if (!empty ($address['name']))
2393 echo "<tr><td colspan=2 align=center><h2>${address['name']}</h2></td></tr>\n";
2394
2395 echo "<tr><td class=pcleft>";
2396 startPortlet ('summary');
2397 echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
2398 echo "<tr><th width='50%' class=tdright>Allocations:</th><td class=tdleft>" . count ($address['allocs']) . "</td></tr>\n";
2399 echo "<tr><th width='50%' class=tdright>Originated NAT connections:</th><td class=tdleft>" . count ($address['outpf']) . "</td></tr>\n";
2400 echo "<tr><th width='50%' class=tdright>Arriving NAT connections:</th><td class=tdleft>" . count ($address['inpf']) . "</td></tr>\n";
2401 echo "<tr><th width='50%' class=tdright>SLB virtual services:</th><td class=tdleft>" . count ($address['lblist']) . "</td></tr>\n";
2402 echo "<tr><th width='50%' class=tdright>SLB real servers:</th><td class=tdleft>" . count ($address['rslist']) . "</td></tr>\n";
2403 printTagTRs();
2404 echo "</table><br>\n";
2405 finishPortlet();
2406 echo "</td>\n";
2407
2408 echo "<td class=pcright>";
2409
2410 if (!empty ($address['class']))
2411 {
2412 startPortlet ('allocations');
2413 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center' width='100%'>\n";
2414 echo "<tr><th>object</th><th>OS interface</th><th>allocation type</th></tr>\n";
2415 $class = $address['class'];
2416 // render all allocation records for this address the same way
2417 if ($address['reserved'] == 'yes')
2418 echo "<tr class='${class}'><td colspan=2>&nbsp;</td><td class=tdleft><strong>RESERVED</strong></td></tr>";
2419 foreach ($address['allocs'] as $bond)
2420 {
2421 if (isset ($_REQUEST['hl_object_id']) and $_REQUEST['hl_object_id'] == $bond['object_id'])
2422 $secondclass = 'tdleft port_highlight';
2423 else
2424 $secondclass = 'tdleft';
2425 echo "<tr class='$class'><td class=tdleft><a href='${root}?page=object&object_id=${bond['object_id']}";
2426 echo "&hl_ipv4_addr=${dottedquad}'>${bond['object_name']}</td><td class='${secondclass}'>${bond['name']}</td><td class='${secondclass}'><strong>";
2427 echo $aat[$bond['type']];
2428 echo "</strong></td></tr>\n";
2429 }
2430 echo "</table><br><br>";
2431 finishPortlet();
2432 }
2433
2434 // FIXME: The returned list is structured differently, than we expect it to be. One of the sides
2435 // must be fixed.
2436 if (count ($address['lblist']))
2437 {
2438 startPortlet ('Virtual services (' . count ($address['lblist']) . ')');
2439 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center' width='100%'>\n";
2440 echo "<tr><th>VS</th><th>name</th></tr>\n";
2441 foreach ($address['lblist'] as $vsinfo)
2442 {
2443 echo "<tr><td class=tdleft><a href='${root}?page=ipv4vs&vs_id=${vsinfo['vs_id']}'>";
2444 echo buildVServiceName ($vsinfo) . "</a></td><td class=tdleft>";
2445 echo $vsinfo['name'] . "</td></tr>\n";
2446 }
2447 echo "</table><br><br>";
2448 finishPortlet();
2449 }
2450
2451 if (count ($address['rslist']))
2452 {
2453 startPortlet ('Real servers (' . count ($address['rslist']) . ')');
2454 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center' width='100%'>\n";
2455 echo "<tr><th>&nbsp;</th><th>port</th><th>RS pool</th></tr>\n";
2456 foreach ($address['rslist'] as $rsinfo)
2457 {
2458 echo "<tr><td>";
2459 if ($rsinfo['inservice'] == 'yes')
2460 printImageHREF ('inservice', 'in service');
2461 else
2462 printImageHREF ('notinservice', 'NOT in service');
2463 echo "</td><td class=tdleft>${rsinfo['rsport']}</td><td class=tdleft><a href='${root}?page=ipv4rsp&pool_id=${rsinfo['rspool_id']}'>";
2464 echo $rsinfo['rspool_name'] . "</a></td></tr>\n";
2465 }
2466 echo "</table><br><br>";
2467 finishPortlet();
2468 }
2469
2470 if (count ($address['outpf']))
2471 {
2472 startPortlet ('departing NAT rules');
2473 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center' width='100%'>\n";
2474 echo "<tr><th>proto</th><th>from</th><th>to</th><th>comment</th></tr>\n";
2475 foreach ($address['outpf'] as $rule)
2476 echo "<tr><td>${rule['proto']}</td><td>${rule['localip']}:${rule['localport']}</td><td>${rule['remoteip']}:${rule['remoteport']}</td><td>${rule['description']}</td></tr>";
2477 echo "</table>";
2478 finishPortlet();
2479 }
2480
2481 if (count ($address['inpf']))
2482 {
2483 startPortlet ('arriving NAT rules');
2484 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center' width='100%'>\n";
2485 echo "<tr><th>proto</th><th>from</th><th>to</th><th>comment</th></tr>\n";
2486 foreach ($address['inpf'] as $rule)
2487 echo "<tr><td>${rule['proto']}</td><td>${rule['localip']}:${rule['localport']}</td><td>${rule['remoteip']}:${rule['remoteport']}</td><td>${rule['description']}</td></tr>";
2488 echo "</table>";
2489 finishPortlet();
2490 }
2491
2492 echo "</td></tr>";
2493 echo "</table>\n";
2494 }
2495
2496 function renderIPv4AddressProperties ($dottedquad)
2497 {
2498 showMessageOrError();
2499 $address = getIPv4Address ($dottedquad);
2500 echo "<center><h1>$dottedquad</h1></center>\n";
2501
2502 startPortlet ('update');
2503 echo "<table border=0 cellpadding=10 cellpadding=1 align='center'>\n";
2504 printOpFormIntro ('editAddress');
2505 echo "<tr><td class='tdright'>Name:</td><td class='tdleft'><input type=text name=name size=20 value='${address['name']}'></tr>";
2506 echo "<td class='tdright'>Reserved:</td><td class='tdleft'><input type=checkbox name=reserved size=20 ";
2507 echo ($address['reserved']=='yes') ? 'checked' : '';
2508 echo "></tr><tr><td colspan=2 class='tdcenter'>";
2509 printImageHREF ('SAVE', 'Save changes', TRUE);
2510 echo "</td></form></tr></table>\n";
2511 finishPortlet();
2512 if (empty ($address['name']) and $address['reserved'] == 'no')
2513 return;
2514
2515 startPortlet ('release');
2516 printOpFormIntro ('editAddress', array ('name' => '', 'reserved' => ''));
2517 echo "<input type=submit value='release'></form>";
2518 finishPortlet();
2519 }
2520
2521 function renderIPv4AddressAllocations ($dottedquad)
2522 {
2523 showMessageOrError();
2524 global $pageno, $tabno, $root, $aat;
2525
2526 $address = getIPv4Address ($dottedquad);
2527 $class = $address['class'];
2528 echo "<center><h1>${dottedquad}</h1></center>\n";
2529 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
2530 echo "<tr><th>&nbsp;</th><th>object</th><th>OS interface</th><th>allocation type</th><th>&nbsp;</th></tr>\n";
2531
2532 if ($address['reserved'] == 'yes')
2533 echo "<tr class='${class}'><td colspan=3>&nbsp;</td><td class=tdleft><strong>RESERVED</strong></td><td>&nbsp;</td></tr>";
2534 foreach ($address['allocs'] as $bond)
2535 {
2536 echo "<tr class='$class'>";
2537 printOpFormIntro ('updIPv4Allocation', array ('object_id' => $bond['object_id']));
2538 echo "<td><a href='${root}process.php?op=delIPv4Allocation&page=${pageno}&tab=${tabno}&ip=${dottedquad}&object_id=${bond['object_id']}'>";
2539 printImageHREF ('delete', 'Unallocate address');
2540 echo "</a></td>";
2541 echo "<td><a href='${root}?page=object&object_id=${bond['object_id']}&hl_ipv4_addr=${dottedquad}'>${bond['object_name']}</td>";
2542 echo "<td><input type='text' name='bond_name' value='${bond['name']}' size=10></td><td>";
2543 printSelect ($aat, 'bond_type', $bond['type']);
2544 echo "</td><td>";
2545 printImageHREF ('save', 'Save changes', TRUE);
2546 echo "</td></form></tr>\n";
2547 }
2548 printOpFormIntro ('addIPv4Allocation');
2549 echo "<td>";
2550 printImageHREF ('add', 'new allocation', TRUE);
2551 echo "</td><td><select name='object_id'>";
2552
2553 foreach (explode (',', getConfigVar ('IPV4_PERFORMERS')) as $type)
2554 foreach (getNarrowObjectList ($type) as $object)
2555 echo "<option value='${object['id']}'>${object['dname']}</option>";
2556
2557 echo "</select></td><td><input type='text' name='bond_name' value='' size=10></td><td>";
2558 printSelect ($aat, 'bond_type');
2559 echo "</td><td>&nbsp;</td></form></tr>";
2560 echo "</table><br><br>";
2561
2562 }
2563
2564 function renderNATv4ForObject ($object_id = 0)
2565 {
2566 global $pageno, $tabno, $root;
2567
2568 $info = getObjectInfo ($object_id);
2569 $forwards = getNATv4ForObject ($object_id);
2570 $alloclist = getObjectIPv4Allocations ($object_id);
2571 showMessageOrError();
2572 echo "<center><h2>locally performed NAT</h2></center>";
2573
2574 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
2575 echo "<tr><th></th><th>Match endpoint</th><th>Translate to</th><th>Target object</th><th>Comment</th><th>&nbsp;</th></tr>\n";
2576
2577 foreach ($forwards['out'] as $pf)
2578 {
2579 $class = 'trerror';
2580 $osif = '';
2581 if (isset ($alloclist [$pf['localip']]))
2582 {
2583 $class = $alloclist [$pf['localip']]['addrinfo']['class'];
2584 $osif = $alloclist [$pf['localip']]['osif'] . ': ';
2585 }
2586
2587 echo "<tr class='$class'>";
2588 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}'>";
2589 printImageHREF ('delete', 'Delete NAT rule');
2590 echo "</a></td>";
2591 echo "<td>${pf['proto']}/${osif}<a href='${root}?page=ipaddress&tab=default&ip=${pf['localip']}'>${pf['localip']}</a>:${pf['localport']}";
2592 if (!empty ($pf['local_addr_name']))
2593 echo ' (' . $pf['local_addr_name'] . ')';
2594 echo "</td>";
2595 echo "<td><a href='${root}?page=ipaddress&tab=default&ip=${pf['remoteip']}'>${pf['remoteip']}</a>:${pf['remoteport']}</td>";
2596
2597 $address = getIPv4Address ($pf['remoteip']);
2598
2599 echo "<td class='description'>";
2600 if (count ($address['allocs']))
2601 foreach ($address['allocs'] as $bond)
2602 echo "<a href='${root}?page=object&tab=default&object_id=${bond['object_id']}'>${bond['object_name']}(${bond['name']})</a> ";
2603 elseif (!empty ($pf['remote_addr_name']))
2604 echo '(' . $pf['remote_addr_name'] . ')';
2605 printOpFormIntro
2606 (
2607 'updNATv4Rule',
2608 array
2609 (
2610 'localip' => $pf['localip'],
2611 'localport' => $pf['localport'],
2612 'remoteip' => $pf['remoteip'],
2613 'remoteport' => $pf['remoteport'],
2614 'proto' => $pf['proto']
2615 )
2616 );
2617 echo "</td><td class='description'>";
2618 echo "<input type='text' name='description' value='${pf['description']}'></td><td>";
2619 printImageHREF ('save', 'Save changes', TRUE);
2620 echo "</td></form></tr>";
2621 }
2622 printOpFormIntro ('addNATv4Rule');
2623 echo "<tr align='center'><td>";
2624 printImageHREF ('add', 'Add new NAT rule', TRUE);
2625 echo '</td><td>';
2626 printSelect (array ('TCP' => 'TCP', 'UDP' => 'UDP'), 'proto');
2627 echo "<select name='localip' tabindex=1>";
2628
2629 foreach ($alloclist as $dottedquad => $alloc)
2630 {
2631 $name = empty ($alloc['addrinfo']['name']) ? '' : (' (' . niftyString ($alloc['addrinfo']['name']) . ')');
2632 $osif = empty ($alloc['osif']) ? '' : ($alloc['osif'] . ': ');
2633 echo "<option value='${dottedquad}'>${osif}${dottedquad}${name}</option>";
2634 }
2635
2636 echo "</select>:<input type='text' name='localport' size='4' tabindex=2></td>";
2637 echo "<td><input type='text' name='remoteip' id='remoteip' size='10' tabindex=3>";
2638 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\");'>";
2639 printImageHREF ('find', 'Find object');
2640 echo "</a>";
2641 echo ":<input type='text' name='remoteport' size='4' tabindex=4></td><td></td>";
2642 echo "<td colspan=1><input type='text' name='description' size='20' tabindex=5></td><td>&nbsp;</td></tr>";
2643 echo "</form>";
2644
2645 echo "</table><br><br>";
2646
2647 echo "<center><h2>arriving NAT connections</h2></center>";
2648 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
2649 echo "<tr><th></th><th>Source</th><th>Source objects</th><th>Target</th><th>Description</th></tr>\n";
2650
2651 foreach ($forwards['in'] as $pf)
2652 {
2653 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}'>";
2654 printImageHREF ('delete', 'Delete NAT rule');
2655 echo "</a></td>";
2656 echo "<td>${pf['proto']}/<a href='${root}?page=ipaddress&tab=default&ip=${pf['localip']}'>${pf['localip']}</a>:${pf['localport']}</td>";
2657 echo "<td class='description'><a href='${root}?page=object&tab=default&object_id=${pf['object_id']}'>${pf['object_name']}</a>";
2658 echo "</td><td><a href='${root}?page=ipaddress&tab=default&ip=${pf['remoteip']}'>${pf['remoteip']}</a>:${pf['remoteport']}</td>";
2659 echo "<td class='description'>${pf['description']}</td></tr>";
2660 }
2661
2662 echo "</table><br><br>";
2663 }
2664
2665 // FIXME: move related code away into ophandler(s)
2666 function renderAddMultipleObjectsForm ()
2667 {
2668 global $root, $pageno, $tabno, $nextorder;
2669
2670 $type_id = array();
2671 $global_type_id = 0;
2672 $name = array();
2673 $asset_no = array();
2674 $keepvalues1 = $keepvalues2 = FALSE;
2675 $log = array();
2676 // Look for current submit.
2677 if (isset ($_REQUEST['got_fast_data']))
2678 {
2679 $taglist = isset ($_REQUEST['taglist']) ? $_REQUEST['taglist'] : array();
2680 $keepvalues1 = TRUE;
2681 $max = getConfigVar ('MASSCOUNT');
2682 for ($i = 0; $i < $max; $i++)
2683 {
2684 if (!isset ($_REQUEST["${i}_object_type_id"]))
2685 {
2686 $log[] = array ('code' => 'error', 'message' => "Submitted form is invalid at line " . $i + 1);
2687 break;
2688 }
2689 assertUIntArg ("${i}_object_type_id", __FUNCTION__, TRUE);
2690 assertStringArg ("${i}_object_name", __FUNCTION__, TRUE);
2691 assertStringArg ("${i}_object_label", __FUNCTION__, TRUE);
2692 assertStringArg ("${i}_object_asset_no", __FUNCTION__, TRUE);
2693 assertStringArg ("${i}_object_barcode", __FUNCTION__, TRUE);
2694 $type_id[$i] = $_REQUEST["${i}_object_type_id"];
2695 // Save user input for possible rendering.
2696 $name[$i] = $_REQUEST["${i}_object_name"];
2697 $label[$i] = $_REQUEST["${i}_object_label"];
2698 $asset_no[$i] = $_REQUEST["${i}_object_asset_no"];
2699 $barcode[$i] = $_REQUEST["${i}_object_barcode"];
2700
2701 // It's better to skip silently, than to print a notice.
2702 if ($type_id[$i] == 0)
2703 continue;
2704 if (commitAddObject ($name[$i], $label[$i], $barcode[$i], $type_id[$i], $asset_no[$i], $taglist) === TRUE)
2705 $log[] = array ('code' => 'success', 'message' => "Added new object '${name[$i]}'");
2706 else
2707 $log[] = array ('code' => 'error', 'message' => __FUNCTION__ . ': commitAddObject() failed');
2708 }
2709 }
2710 elseif (isset ($_REQUEST['got_very_fast_data']))
2711 {
2712 $taglist = isset ($_REQUEST['taglist']) ? $_REQUEST['taglist'] : array();
2713 $keepvalues2 = TRUE;
2714 assertUIntArg ('global_type_id', __FUNCTION__, TRUE);
2715 assertStringArg ('namelist', __FUNCTION__, TRUE);
2716 $global_type_id = $_REQUEST['global_type_id'];
2717 if ($global_type_id == 0)
2718 {
2719 if (!empty ($_REQUEST['namelist']))
2720 $log[] = array ('code' => 'error', 'message' => 'Object type is not selected, check the form below');
2721 else
2722 $log[] = array ('code' => 'error', 'message' => 'Empty form has been ignored. Cheers.');
2723 }
2724 else
2725 {
2726 // The name extractor below was stolen from ophandlers.php:addMultiPorts()
2727 $names1 = explode ('\n', $_REQUEST['namelist']);
2728 $names2 = array();
2729 foreach ($names1 as $line)
2730 {
2731 $parts = explode ('\r', $line);
2732 reset ($parts);
2733 if (empty ($parts[0]))
2734 continue;
2735 else
2736 $names2[] = rtrim ($parts[0]);
2737 }
2738 foreach ($names2 as $cname)
2739 if (commitAddObject ($cname, '', '', $global_type_id, '', $taglist) === TRUE)
2740 $log[] = array ('code' => 'success', 'message' => "Added new object '${cname}'");
2741 else
2742 $log[] = array ('code' => 'error', 'message' => "Could not add '${cname}'");
2743 }
2744 }
2745 printLog ($log);
2746
2747 // Render a form for the next.
2748 $typelist = getObjectTypeList();
2749 $typelist[0] = 'select type...';
2750
2751 startPortlet ('Distinct types, same tags');
2752 $max = getConfigVar ('MASSCOUNT');
2753 echo "<form name=fastform method=post action='${root}?page=${pageno}&tab=${tabno}'>";
2754 echo '<table border=0 align=center>';
2755 echo "<tr><th>Object type</th><th>Common name</th><th>Visible label</th>";
2756 echo "<th>Asset tag</th><th>Barcode</th><th>Tags</th></tr>\n";
2757 // If a user forgot to select object type on input, we keep his
2758 // previous input in the form.
2759 for ($i = 0; $i < $max; $i++)
2760 {
2761 echo '<tr><td>';
2762 // Don't employ DEFAULT_OBJECT_TYPE to avoid creating ghost records for pre-selected empty rows.
2763 printSelect ($typelist, "${i}_object_type_id", 0);
2764 echo '</td>';
2765 echo "<td><input type=text size=30 name=${i}_object_name";
2766 if ($keepvalues1 and isset ($name[$i]) and (!isset ($type_id[$i]) or $type_id[$i] == 0))
2767 echo " value='${name[$i]}'";
2768 echo "></td>";
2769 echo "<td><input type=text size=30 name=${i}_object_label";
2770 if ($keepvalues1 and isset ($label[$i]) and (!isset ($type_id[$i]) or $type_id[$i] == 0))
2771 echo " value='${label[$i]}'";
2772 echo "></td>";
2773 echo "<td><input type=text size=20 name=${i}_object_asset_no";
2774 if ($keepvalues1 and isset ($asset_no[$i]) and (!isset ($type_id[$i]) or $type_id[$i] == 0))
2775 echo " value='${asset_no[$i]}'";
2776 echo "></td>";
2777 echo "<td><input type=text size=10 name=${i}_object_barcode";
2778 if ($keepvalues1 and isset ($barcode[$i]) and (!isset ($type_id[$i]) or $type_id[$i] == 0))
2779 echo " value='${barcode[$i]}'";
2780 echo "></td>";
2781 if ($i == 0)
2782 {
2783 echo "<td valign=top rowspan=${max}>";
2784 renderTagSelect();
2785 echo "</td>\n";
2786 }
2787 echo "</tr>\n";
2788 }
2789 echo "<tr><td class=submit colspan=5><input type=submit name=got_fast_data value='Go!'></td></tr>\n";
2790 echo "</form></table>\n";
2791 finishPortlet();
2792
2793 startPortlet ('Same type, same tags');
2794 echo "<form name=veryfastform method=post action='${root}?page=${pageno}&tab=${tabno}'>";
2795 echo "<table border=0 align=center><tr><th>names</th><th>type</th></tr>";
2796 echo "<tr><td rowspan=3><textarea name=namelist cols=40 rows=25>\n";
2797 if ($keepvalues2 and $global_type_id == 0)
2798 echo $_REQUEST['namelist'];
2799 echo "</textarea></td><td valign=top>";
2800 printSelect ($typelist, "global_type_id", getConfigVar ('DEFAULT_OBJECT_TYPE'));
2801 echo "</td></tr>";
2802 echo "<tr><th>Tags</th></tr>";
2803 echo "<tr><td valign=top>";
2804 renderTagSelect();
2805 echo "</td></tr>";
2806 echo "<tr><td colspan=2><input type=submit name=got_very_fast_data value='Go!'></td></tr></table>\n";
2807 echo "</form>\n";
2808 finishPortlet();
2809 }
2810
2811 function printGreeting ()
2812 {
2813 global $remote_username, $accounts, $root;
2814 $account = $accounts[$remote_username];
2815 $person = empty ($account['user_realname']) ? $account['user_name'] : $account['user_realname'];
2816 echo "Hello, ${person}. This is RackTables " . CODE_VERSION . ". Click <a href='${root}?logout'>here</a> to logout.";
2817 }
2818
2819 function renderSearchResults ()
2820 {
2821 global $remote_username, $root;
2822 $terms = trim ($_REQUEST['q']);
2823 if (empty ($terms))
2824 {
2825 showError ('Search string cannot be empty.', __FUNCTION__);
2826 return;
2827 }
2828 if (!permitted ('objects', 'default'))
2829 {
2830 showError ('You are not authorized for viewing information about objects.', __FUNCTION__);
2831 return;
2832 }
2833 $nhits = 0;
2834 // If we search for L2 address, we can either find one or find none.
2835 if
2836 (
2837 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
2838 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
2839 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
2840 // STP bridge ID: bridge priotity + port MAC address. Cut off first 4 chars and look for MAC address.
2841 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)
2842 )
2843 // Search for L2 address.
2844 {
2845 $terms = str_replace ('.', '', $terms);
2846 $terms = str_replace (':', '', $terms);
2847 $terms = substr ($terms, -12);
2848 $result = searchByl2address ($terms);
2849 if ($result !== NULL)
2850 {
2851 $nhits++;
2852 $lasthit = 'port';
2853 $summary['port'][] = $result;
2854 }
2855 }
2856 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))
2857 // Search for IP address.
2858 {
2859 if (NULL !== getIPv4AddressNetworkId ($terms))
2860 {
2861 $nhits++;
2862 $lasthit = 'ipv4addressbydq';
2863 $summary['ipv4addressbydq'][] = $terms;
2864 }
2865 }
2866 else
2867 // Search for objects, addresses, networks, virtual services and RS pools by their description.
2868 {
2869 $tmp = getObjectSearchResults ($terms);
2870 if (count ($tmp))
2871 {
2872 $nhits += count ($tmp);
2873 $lasthit = 'object';
2874 $summary['object'] = $tmp;
2875 }
2876 $tmp = getIPv4AddressSearchResult ($terms);
2877 if (count ($tmp))
2878 {
2879 $nhits += count ($tmp);
2880 $lasthit = 'ipv4addressbydescr';
2881 $summary['ipv4addressbydescr'] = $tmp;
2882 }
2883 $tmp = getIPv4PrefixSearchResult ($terms);
2884 if (count ($tmp))
2885 {
2886 $nhits += count ($tmp);
2887 $lasthit = 'ipv4network';
2888 $summary['ipv4network'] = $tmp;
2889 }
2890 $tmp = getIPv4RSPoolSearchResult ($terms);
2891 if (count ($tmp))
2892 {
2893 $nhits += count ($tmp);
2894 $lasthit = 'ipv4rspool';
2895 $summary['ipv4rspool'] = $tmp;
2896 }
2897 $tmp = getIPv4VServiceSearchResult ($terms);
2898 if (count ($tmp))
2899 {
2900 $nhits += count ($tmp);
2901 $lasthit = 'ipv4vs';
2902 $summary['ipv4vs'] = $tmp;
2903 }
2904 $tmp = getAccountSearchResult ($terms);
2905 if (count ($tmp))
2906 {
2907 $nhits += count ($tmp);
2908 $lasthit = 'user';
2909 $summary['user'] = $tmp;
2910 }
2911 }
2912 if ($nhits == 0)
2913 echo "<center><h2>Nothing found for '${terms}'</h2></center>";
2914 elseif ($nhits == 1)
2915 {
2916 $record = current ($summary[$lasthit]);
2917 switch ($lasthit)
2918 {
2919 case 'port':
2920 echo "<script language='Javascript'>document.location='${root}?page=object";
2921 echo "&hl_port_id=" . $record['port_id'];
2922 echo "&object_id=" . $record['object_id'] . "';//</script>";
2923 break;
2924 case 'ipv4addressbydq':
2925 $parentnet = getIPv4AddressNetworkId ($record);
2926 if ($parentnet !== NULL)
2927 echo "<script language='Javascript'>document.location='${root}?page=iprange&tab=default&id=${parentnet}&hl_ipv4_addr=${record}';//</script>";
2928 else
2929 echo "<script language='Javascript'>document.location='${root}?page=ipaddress&ip=${record}';//</script>";
2930 break;
2931 case 'ipv4addressbydescr':
2932 $parentnet = getIPv4AddressNetworkId ($record['ip']);
2933 if ($parentnet !== NULL)
2934 echo "<script language='Javascript'>document.location='${root}?page=iprange&tab=default&id=${parentnet}&hl_ipv4_addr=${record['ip']}';//</script>";
2935 else
2936 echo "<script language='Javascript'>document.location='${root}?page=ipaddress&ip=${record['ip']}';//</script>";
2937 break;
2938 case 'ipv4network':
2939 echo "<script language='Javascript'>document.location='${root}?page=iprange";
2940 echo "&id=${record['id']}";
2941 echo "';//</script>";
2942 break;
2943 case 'object':
2944 echo "<script language='Javascript'>document.location='${root}?page=object&object_id=${record['id']}';//</script>";
2945 break;
2946 case 'ipv4rspool':
2947 echo "<script language='Javascript'>document.location='${root}?page=ipv4rsp&pool_id=${record['pool_id']}';//</script>";
2948 break;
2949 case 'ipv4vs':
2950 echo "<script language='Javascript'>document.location='${root}?page=ipv4vs&vs_id=${record['id']}';//</script>";
2951 break;
2952 case 'user':
2953 echo "<script language='Javascript'>document.location='${root}?page=user&user_id=${record['user_id']}';//</script>";
2954 break;
2955 }
2956 return;
2957 }
2958 else
2959 {
2960 global $nextorder;
2961 $order = 'odd';
2962 echo "<center><h2>${nhits} result(s) found for '${terms}'</h2></center>";
2963 foreach ($summary as $where => $what)
2964 switch ($where)
2965 {
2966 case 'object':
2967 startPortlet ("<a href='${root}?page=objects'>Objects</a>");
2968 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
2969 echo '<tr><th>Common name</th><th>Visible label</th><th>Asset tag</th><th>barcode</th></tr>';
2970 foreach ($what as $obj)
2971 {
2972 echo "<tr class=row_${order}><td><a href=\"${root}?page=object&object_id=${obj['id']}\">${obj['dname']}</a></td>";
2973 echo "<td>${obj['label']}</td>";
2974 echo "<td>${obj['asset_no']}</td>";
2975 echo "<td>${obj['barcode']}</td></tr>";
2976 $order = $nextorder[$order];
2977 }
2978 echo '</table>';
2979 finishPortlet();
2980 break;
2981 case 'ipv4network':
2982 startPortlet ("<a href='${root}?page=ipv4space'>IPv4 networks</a>");
2983 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
2984 echo '<tr><th>network</th><th>name/tags</th></tr>';
2985 foreach ($what as $netinfo)
2986 {
2987 echo "<tr class=row_${order} valign=top>";
2988 printIPv4NetInfoTDs ($netinfo);
2989 echo "</tr>\n";
2990 $order = $nextorder[$order];
2991 }
2992 echo '</table>';
2993 finishPortlet();
2994 break;
2995 case 'ipv4addressbydescr':
2996 startPortlet ('IPv4 addresses');
2997 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
2998 // FIXME: address, parent network, routers (if extended view is enabled)
2999 echo '<tr><th>Address</th><th>Descritpion</th></tr>';
3000 foreach ($what as $addr)
3001 {
3002 echo "<tr class=row_${order}><td class=tdleft>";
3003 $parentnet = getIPv4AddressNetworkId ($addr['ip']);
3004 if ($parentnet !== NULL)
3005 echo "<a href='${root}?page=iprange&id=${parentnet}&hl_ipv4_addr=${addr['ip']}'>${addr['ip']}</a></td>";
3006 else
3007 echo "<a href='${root}?page=ipaddress&ip=${addr['ip']}'>${addr['ip']}</a></td>";
3008 echo "<td class=tdleft>${addr['name']}</td></tr>";
3009 $order = $nextorder[$order];
3010 }
3011 echo '</table>';
3012 finishPortlet();
3013 break;
3014 case 'ipv4rspool':
3015 startPortlet ("<a href=&apos