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