r2172 - fix a typo in NAT rules displaying code (pointed out by Piotr Nowacki)
[racktables] / inc / interface.php
... / ...
CommitLineData
1<?php
2/*
3*
4* This file contains frontend functions for RackTables.
5*
6*/
7
8// Interface function's special.
9$nextorder['odd'] = 'even';
10$nextorder['even'] = 'odd';
11
12// address allocation type
13$aat = array
14(
15 'regular' => 'Connected',
16 'virtual' => 'Loopback',
17 'shared' => 'Shared',
18 'router' => 'Router',
19);
20// address allocation code, IPv4 addresses and objects view
21$aac = array
22(
23 'regular' => '',
24 'virtual' => '<strong>L</strong>',
25 'shared' => '<strong>S</strong>',
26 'router' => '<strong>R</strong>',
27);
28// address allocation code, IPv4 networks view
29$aac2 = array
30(
31 'regular' => '',
32 'virtual' => '<strong>L:</strong>',
33 'router' => '<strong>R:</strong>',
34);
35
36// Let's have it here, so extensions can add their own images.
37$image = array();
38$image['error']['path'] = 'pix/error.png';
39$image['error']['width'] = 76;
40$image['error']['height'] = 17;
41$image['logo']['path'] = 'pix/defaultlogo.png';
42$image['logo']['width'] = 210;
43$image['logo']['height'] = 40;
44$image['rackspace']['path'] = 'pix/racks.png';
45$image['rackspace']['width'] = 218;
46$image['rackspace']['height'] = 200;
47$image['objects']['path'] = 'pix/server.png';
48$image['objects']['width'] = 218;
49$image['objects']['height'] = 200;
50$image['ipv4space']['path'] = 'pix/addressspace.png';
51$image['ipv4space']['width'] = 218;
52$image['ipv4space']['height'] = 200;
53$image['ipv4slb']['path'] = 'pix/slb.png';
54$image['ipv4slb']['width'] = 218;
55$image['ipv4slb']['height'] = 200;
56$image['config']['path'] = 'pix/configuration.png';
57$image['config']['width'] = 218;
58$image['config']['height'] = 200;
59$image['reports']['path'] = 'pix/report.png';
60$image['reports']['width'] = 218;
61$image['reports']['height'] = 200;
62$image['useup']['path'] = 'pix/tango-edit-clear.png';
63$image['useup']['width'] = 16;
64$image['useup']['height'] = 16;
65$image['link']['path'] = 'pix/tango-network-wired.png';
66$image['link']['width'] = 16;
67$image['link']['height'] = 16;
68$image['unlink']['path'] = 'pix/tango-edit-clear.png';
69$image['unlink']['width'] = 16;
70$image['unlink']['height'] = 16;
71$image['add']['path'] = 'pix/tango-list-add.png';
72$image['add']['width'] = 16;
73$image['add']['height'] = 16;
74$image['delete']['path'] = 'pix/tango-list-remove.png';
75$image['delete']['width'] = 16;
76$image['delete']['height'] = 16;
77$image['nodelete']['path'] = 'pix/tango-list-remove-shadow.png';
78$image['nodelete']['width'] = 16;
79$image['nodelete']['height'] = 16;
80$image['grant'] = $image['add'];
81$image['revoke'] = $image['delete'];
82$image['inservice']['path'] = 'pix/tango-emblem-system.png';
83$image['inservice']['width'] = 16;
84$image['inservice']['height'] = 16;
85$image['notinservice']['path'] = 'pix/tango-dialog-error.png';
86$image['notinservice']['width'] = 16;
87$image['notinservice']['height'] = 16;
88$image['blockuser'] = $image['inservice'];
89$image['unblockuser'] = $image['notinservice'];
90$image['find']['path'] = 'pix/tango-system-search.png';
91$image['find']['width'] = 16;
92$image['find']['height'] = 16;
93$image['spacer']['path'] = 'pix/pixel.png';
94$image['spacer']['width'] = 16;
95$image['spacer']['height'] = 16;
96$image['next']['path'] = 'pix/tango-go-next.png';
97$image['next']['width'] = 32;
98$image['next']['height'] = 32;
99$image['prev']['path'] = 'pix/tango-go-previous.png';
100$image['prev']['width'] = 32;
101$image['prev']['height'] = 32;
102$image['clear']['path'] = 'pix/tango-edit-clear.png';
103$image['clear']['width'] = 16;
104$image['clear']['height'] = 16;
105$image['CLEAR']['path'] = 'pix/tango-edit-clear-big.png';
106$image['CLEAR']['width'] = 32;
107$image['CLEAR']['height'] = 32;
108$image['save']['path'] = 'pix/tango-document-save.png';
109$image['save']['width'] = 16;
110$image['save']['height'] = 16;
111$image['SAVE']['path'] = 'pix/tango-document-save-big.png';
112$image['SAVE']['width'] = 32;
113$image['SAVE']['height'] = 32;
114$image['create']['path'] = 'pix/tango-document-new.png';
115$image['create']['width'] = 16;
116$image['create']['height'] = 16;
117$image['CREATE']['path'] = 'pix/tango-document-new-big.png';
118$image['CREATE']['width'] = 32;
119$image['CREATE']['height'] = 32;
120$image['DENIED']['path'] = 'pix/tango-dialog-error-big.png';
121$image['DENIED']['width'] = 32;
122$image['DENIED']['height'] = 32;
123
124// This may be populated later onsite, report rendering function will use it.
125// See the $systemreport for structure.
126$localreports = array();
127
128// Main menu.
129function renderIndex ()
130{
131 global $root;
132?>
133<table border=0 cellpadding=0 cellspacing=0 width='100%'>
134 <tr>
135 <td>
136 <div style='text-align: center; margin: 10px; '>
137 <table width='100%' cellspacing=0 cellpadding=30 class=mainmenu border=0>
138 <tr>
139 <td>
140 <h1><a href='<?php echo $root; ?>?page=rackspace'>Rackspace<br>
141 <?php printImageHREF ('rackspace'); ?></a></h1>
142 </td>
143 <td>
144 <h1><a href='<?php echo $root; ?>?page=objects'>Objects<br>
145 <?php printImageHREF ('objects'); ?></a></h1>
146 </td>
147 <td>
148 <h1><a href='<?php echo $root; ?>?page=ipv4space'>IPv4 space<br>
149 <?php printImageHREF ('ipv4space'); ?></a></h1>
150 </td>
151 </tr>
152 </table>
153 <table width='100%' cellspacing=0 cellpadding=30 class=mainmenu border=0>
154 <tr>
155 <td>
156 <h1><a href='<?php echo $root; ?>?page=config'>Configuration<br>
157 <?php printImageHREF ('config'); ?></a></h1>
158 </td>
159 <td>
160 <h1><a href='<?php echo $root; ?>?page=reports'>Reports<br>
161 <?php printImageHREF ('reports'); ?></a></h1>
162 </td>
163 <td>
164 <h1><a href='<?php echo $root; ?>?page=ipv4slb'>IPv4 SLB<br>
165 <?php printImageHREF ('ipv4slb'); ?></a></h1>
166 </td>
167 </tr>
168 </table>
169 </div>
170 </td>
171 </tr>
172</table>
173<?php
174}
175
176function renderRackspace ()
177{
178 $tagfilter = getTagFilter();
179 $tagfilter_str = getTagFilterStr ($tagfilter);
180 echo "<table class=objview border=0 width='100%'><tr><td class=pcleft>";
181 renderTagFilterPortlet ($tagfilter, 'rack');
182 echo '</td><td class=pcright>';
183 echo '<table border=0 cellpadding=10 cellpadding=1>';
184 // generate thumb gallery
185 $rackrowList = getRackspace ($tagfilter);
186 global $root, $nextorder;
187 $rackwidth = getRackImageWidth();
188 $order = 'odd';
189 foreach ($rackrowList as $rackrow)
190 {
191 echo "<tr class=row_${order}><th class=tdleft>";
192 echo "<a href='${root}?page=row&row_id=${rackrow['row_id']}${tagfilter_str}'>";
193 echo "${rackrow['row_name']}</a></th>";
194 $rackList = getRacksForRow ($rackrow['row_id'], $tagfilter);
195 echo "<td><table border=0 cellspacing=5><tr>";
196 foreach ($rackList as $rack)
197 {
198 echo "<td align=center><a href='${root}?page=rack&rack_id=${rack['id']}'>";
199 echo "<img border=0 width=${rackwidth} height=";
200 echo getRackImageHeight ($rack['height']);
201 echo " title='${rack['height']} units'";
202 echo "src='render_image.php?img=minirack&rack_id=${rack['id']}'>";
203 echo "<br>${rack['name']}</a></td>";
204 }
205 echo "</tr></table></tr>\n";
206 $order = $nextorder[$order];
207 }
208 echo "</table>\n";
209 echo "</td></tr></table>\n";
210}
211
212function renderRow ($row_id = 0)
213{
214 if ($row_id == 0)
215 {
216 showError ('Invalid row_id', __FUNCTION__);
217 return;
218 }
219 if (($rowInfo = getRackRowInfo ($row_id)) == NULL)
220 {
221 showError ('getRackRowInfo() failed', __FUNCTION__);
222 return;
223 }
224 $tagfilter = getTagFilter();
225 $rackList = getRacksForRow ($row_id, $tagfilter);
226 // Main layout starts.
227 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
228
229 // Left portlet with row information.
230 echo "<tr><td class=pcleft>";
231 startPortlet ($rowInfo['name']);
232 echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
233 echo "<tr><th width='50%' class=tdright>Racks:</th><td class=tdleft>${rowInfo['count']}</td></tr>\n";
234 echo "<tr><th width='50%' class=tdright>Units:</th><td class=tdleft>${rowInfo['sum']}</td></tr>\n";
235 echo "<tr><th width='50%' class=tdright>%% used:</th><td class=tdleft>";
236 renderProgressBar (getRSUforRackRow ($rackList));
237 echo "</td></tr>\n";
238 echo "</table><br>\n";
239 finishPortlet();
240
241 echo "</td><td class=pcright rowspan=2>";
242
243 global $root, $nextorder;
244 $rackwidth = getRackImageWidth() * getConfigVar ('ROW_SCALE');
245 $order = 'odd';
246 startPortlet ('Racks');
247 echo "<table border=0 cellspacing=5 align='center'><tr>";
248 foreach ($rackList as $rack)
249 {
250 echo "<td align=center class=row_${order}><a href='${root}?page=rack&rack_id=${rack['id']}'>";
251 echo "<img border=0 width=${rackwidth} height=" . (getRackImageHeight ($rack['height']) * getConfigVar ('ROW_SCALE'));
252 echo " title='${rack['height']} units'";
253 echo "src='render_image.php?img=minirack&rack_id=${rack['id']}'>";
254 echo "<br>${rack['name']}</a></td>";
255 $order = $nextorder[$order];
256 }
257 echo "</tr></table>\n";
258 finishPortlet();
259 echo "</td></tr>";
260
261 echo "<tr><td class=pcleft>";
262 renderTagFilterPortlet ($tagfilter, 'rack', 'row_id', $row_id);
263 echo "</td></tr></table>";
264}
265
266function showError ($info = '', $location = 'N/A')
267{
268 global $root;
269 if (preg_match ('/\.php$/', $location))
270 $location = basename ($location);
271 elseif ($location != 'N/A')
272 $location = $location . '()';
273 echo "<div class=msg_error>An error has occured in [${location}]. ";
274 if (empty ($info))
275 echo 'No additional information is available.';
276 else
277 echo "Additional information:<br><p>\n<pre>\n${info}\n</pre></p>";
278 echo "Go back or try starting from <a href='${root}'>index page</a>.<br></div>\n";
279}
280
281// This function renders rack as HTML table.
282function renderRack ($rack_id = 0, $hl_obj_id = 0)
283{
284 if ($rack_id == 0)
285 {
286 showError ('Invalid rack_id', __FUNCTION__);
287 return;
288 }
289 if (($rackData = getRackData ($rack_id)) == NULL)
290 {
291 showError ('getRackData() failed', __FUNCTION__);
292 return;
293 }
294 global $root, $pageno, $tabno;
295 markAllSpans ($rackData);
296 if ($hl_obj_id > 0)
297 highlightObject ($rackData, $hl_obj_id);
298 markupObjectProblems ($rackData);
299 $prev_id = getPrevIDforRack ($rackData['row_id'], $rack_id);
300 $next_id = getNextIDforRack ($rackData['row_id'], $rack_id);
301 echo "<center><table border=0><tr valign=middle>";
302 echo "<td><h2><a href='${root}?page=row&row_id=${rackData['row_id']}'>${rackData['row_name']}</a> :</h2></td>";
303 // FIXME: use 'bypass'?
304 if ($prev_id != NULL)
305 {
306 echo "<td><a href='${root}?page=rack&rack_id=${prev_id}'>";
307 printImageHREF ('prev', 'previous rack');
308 echo "</a></td>";
309 }
310 echo "<td><h2><a href='${root}?page=rack&rack_id=${rackData['id']}'>${rackData['name']}</a></h2></td>";
311 if ($next_id != NULL)
312 {
313 echo "<td><a href='${root}?page=rack&rack_id=${next_id}'>";
314 printImageHREF ('next', 'next rack');
315 echo "</a></td>";
316 }
317 echo "</h2></td></tr></table>\n";
318 if ($rackData['left_is_front'] == 'yes')
319 $markup = array ('left' => 'Front', 'right' => 'Back');
320 else
321 $markup = array ('left' => 'Back', 'right' => 'Front');
322 echo "<table class=rack border=0 cellspacing=0 cellpadding=1>\n";
323 echo "<tr><th width='10%'>&nbsp;</th><th width='20%'>${markup['left']}</th>";
324 echo "<th width='50%'>Interior</th><th width='20%'>${markup['right']}</th></tr>\n";
325 for ($i = $rackData['height']; $i > 0; $i--)
326 {
327 echo '<tr><th>' . ($rackData['bottom_is_unit1'] == 'yes' ? $i : $rackData['height'] - $i + 1) . '</th>';
328 for ($locidx = 0; $locidx < 3; $locidx++)
329 {
330 if (isset ($rackData[$i][$locidx]['skipped']))
331 continue;
332 $state = $rackData[$i][$locidx]['state'];
333 echo "<td class=state_${state}";
334 if (isset ($rackData[$i][$locidx]['hl']))
335 echo $rackData[$i][$locidx]['hl'];
336 if (isset ($rackData[$i][$locidx]['colspan']))
337 echo ' colspan=' . $rackData[$i][$locidx]['colspan'];
338 if (isset ($rackData[$i][$locidx]['rowspan']))
339 echo ' rowspan=' . $rackData[$i][$locidx]['rowspan'];
340 echo ">";
341 switch ($state)
342 {
343 case 'T':
344 $objectData = getObjectInfo ($rackData[$i][$locidx]['object_id']);
345 if (!empty ($objectData['asset_no']))
346 $prefix = "<div title='${objectData['asset_no']}";
347 else
348 $prefix = "<div title='no asset tag";
349 // Don't tell about label, if it matches common name.
350 if ($objectData['name'] != $objectData['label'] and !empty ($objectData['label']))
351 $suffix = ", visible label is \"${objectData['label']}\"'>";
352 else
353 $suffix = "'>";
354 echo $prefix . $suffix;
355 echo "<a href='${root}?page=object&object_id=${objectData['id']}'>${objectData['dname']}</a></div>";
356 break;
357 case 'A':
358 echo '<div title="This rackspace does not exist">&nbsp;</div>';
359 break;
360 case 'F':
361 echo '<div title="Free rackspace">&nbsp;</div>';
362 break;
363 case 'U':
364 echo '<div title="Problematic rackspace, you CAN\'T mount here">&nbsp;</div>';
365 break;
366 default:
367 echo '<div title="No data">&nbsp;</div>';
368 break;
369 }
370 echo '</td>';
371 }
372 echo "</tr>\n";
373 }
374 echo "</table></center>\n";
375}
376
377function renderNewRackForm ($row_id)
378{
379 showMessageOrError();
380
381 startPortlet ('Add one');
382 printOpFormIntro ('addRack', array ('got_data' => 'TRUE'));
383 echo '<table border=0 align=center>';
384 $defh = getConfigVar ('DEFAULT_RACK_HEIGHT');
385 if ($defh == 0)
386 $defh = '';
387 echo "<tr><th class=tdright>Rack name (*):</th><td class=tdleft><input type=text name=rack_name tabindex=1></td>";
388 echo "<td rowspan=4>Assign tags:<br>";
389 renderTagSelect();
390 echo "</td></tr>\n";
391 echo "<tr><th class=tdright>Height in units (*):</th><td class=tdleft><input type=text name=rack_height1 tabindex=2 value='${defh}'></td></tr>\n";
392 echo "<tr><th class=tdright>Comment:</th><td class=tdleft><input type=text name=rack_comment tabindex=3></td></tr>\n";
393 echo "<tr><td class=submit colspan=2>";
394 printImageHREF ('CREATE', 'Add', TRUE);
395 echo "</td></tr></table></form>";
396 finishPortlet();
397
398 startPortlet ('Add many');
399 printOpFormIntro ('addRack', array ('got_mdata' => 'TRUE'));
400 echo '<table border=0 align=center>';
401 $defh = getConfigVar ('DEFAULT_RACK_HEIGHT');
402 if ($defh == 0)
403 $defh = '';
404 echo "<tr><th class=tdright>Height in units (*):</th><td class=tdleft><input type=text name=rack_height2 value='${defh}'></td>";
405 echo "<td rowspan=3 valign=top>Assign tags:<br>";
406 renderTagSelect();
407 echo "</td></tr>\n";
408 echo "<tr><th class=tdright>Rack names (*):</th><td class=tdleft><textarea name=rack_names cols=40 rows=25></textarea></td></tr>\n";
409 echo "<tr><td class=submit colspan=2>";
410 printImageHREF ('CREATE', 'Add', TRUE);
411 echo '</form></table>';
412 finishPortlet();
413}
414
415function renderEditObjectForm ($object_id)
416{
417 showMessageOrError();
418
419 global $pageno, $tabno, $root;
420 $object = getObjectInfo ($object_id);
421 if ($object == NULL)
422 {
423 showError ('getObjectInfo() failed', __FUNCTION__);
424 return;
425 }
426 echo '<table border=0 width=100%><tr>';
427
428 echo '<td class=pcleft>';
429 startPortlet ('Static attributes');
430 printOpFormIntro ('update');
431 echo '<table border=0 align=center>';
432 echo "<tr><th class=tdright>Type:</th><td class=tdleft>";
433 printSelect (getObjectTypeList(), 'object_type_id', $object['objtype_id']);
434 echo "</td></tr>\n";
435 // baseline info
436 echo "<tr><th class=tdright>Common name:</th><td class=tdleft><input type=text name=object_name value='${object['name']}'></td></tr>\n";
437 echo "<tr><th class=tdright>Visible label:</th><td class=tdleft><input type=text name=object_label value='${object['label']}'></td></tr>\n";
438 echo "<tr><th class=tdright>Asset tag:</th><td class=tdleft><input type=text name=object_asset_no value='${object['asset_no']}'></td></tr>\n";
439 echo "<tr><th class=tdright>Barcode:</th><td class=tdleft><input type=text name=object_barcode value='${object['barcode']}'></td></tr>\n";
440 echo "<tr><th class=tdright>Has problems:</th><td class=tdleft><input type=checkbox name=object_has_problems";
441 if ($object['has_problems'] == 'yes')
442 echo ' checked';
443 echo "></td></tr>\n";
444 echo "<tr><td colspan=2><b>Comment:</b><br><textarea name=object_comment rows=10 cols=80>${object['comment']}</textarea></td></tr>";
445 echo "<tr><th class=submit colspan=2>";
446 printImageHREF ('SAVE', 'Save changes', TRUE);
447 echo "</td></tr>\n";
448 echo '</form></table><br>';
449 finishPortlet();
450 echo '</td>';
451
452 // stickers
453 echo '<td class=pcright>';
454 startPortlet ('Optional attributes');
455 $values = getAttrValues ($object_id);
456 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable>\n";
457 echo "<tr><th>&nbsp;</th><th>Attribute</th><th>Value</th><th>&nbsp;</th></tr>\n";
458 printOpFormIntro ('updateStickers');
459 echo '<input type=hidden name=num_attrs value=' . count($values) . ">\n";
460
461 $i = 0;
462 foreach ($values as $record)
463 {
464 echo "<input type=hidden name=${i}_attr_id value=${record['id']}>";
465 echo '<tr><td>';
466 if (!empty ($record['value']))
467 {
468 echo "<a href='${root}process.php?page=${pageno}&tab=${tabno}&op=clearSticker&object_id=${object_id}&attr_id=${record['id']}'>";
469 printImageHREF ('clear', 'Clear value');
470 echo '</a>';
471 }
472 else
473 echo '&nbsp;';
474 echo '</td>';
475 echo "<td class=tdright>${record['name']}:</td><td class=tdleft>";
476 switch ($record['type'])
477 {
478 case 'uint':
479 case 'float':
480 case 'string':
481 echo "<input type=text name=${i}_value value='${record['value']}'>";
482 break;
483 case 'dict':
484 $chapter = readChapter ($record['chapter_name']);
485 $chapter[0] = '-- NOT SET --';
486 printSelect ($chapter, "${i}_value", $record['key']);
487 break;
488 }
489 echo "</td></tr>\n";
490 $i++;
491 }
492 echo "<tr><td colspan=3>";
493 printImageHREF ('SAVE', 'Save changes', TRUE);
494 echo "</td></tr>\n";
495 echo "</form>";
496 echo "</table>\n";
497 finishPortlet();
498 echo '</td>';
499
500 echo '</tr><tr>';
501
502 echo '<td colspan=2>';
503 startPortlet ('history');
504 renderHistory ($pageno, $object_id);
505 finishPortlet();
506 echo '</td>';
507
508 echo '</tr></table>';
509}
510
511// This is a clone of renderEditObjectForm().
512function renderEditRackForm ($rack_id)
513{
514 showMessageOrError();
515 global $pageno;
516 $rack = getRackData ($rack_id);
517 if ($rack == NULL)
518 {
519 showError ('getRackData() failed', __FUNCTION__);
520 return;
521 }
522
523 startPortlet ('Rack attributes');
524 printOpFormIntro ('updateRack');
525 echo '<table border=0 align=center>';
526 echo "<tr><th class=tdright>Rack row:</th><td class=tdleft>";
527 printSelect (readChapter ('RackRow'), 'rack_row_id', $rack['row_id']);
528 echo "</td></tr>\n";
529 echo "<tr><th class=tdright>Name (required):</th><td class=tdleft><input type=text name=rack_name value='${rack['name']}'></td></tr>\n";
530 echo "<tr><th class=tdright>Height (required):</th><td class=tdleft><input type=text name=rack_height value='${rack['height']}'></td></tr>\n";
531 echo "<tr><th class=tdright>Comment:</th><td class=tdleft><input type=text name=rack_comment value='${rack['comment']}'></td></tr>\n";
532 echo "<tr><td class=submit colspan=2>";
533 printImageHREF ('SAVE', 'Save changes', TRUE);
534 echo "</td></tr>\n";
535 echo '</form></table><br>';
536 finishPortlet();
537
538 startPortlet ('History');
539 renderHistory ($pageno, $rack_id);
540 finishPortlet();
541}
542
543// This is a helper for creators and editors.
544function printSelect ($rowList, $select_name, $selected_id = 1)
545{
546 // First collect all data for OPTGROUPs, then ouput it and dump
547 // the rest of records as is.
548 $optgroup = array();
549 $other = array();
550 foreach ($rowList as $dict_key => $dict_value)
551 {
552 if (strpos ($dict_value, '%GSKIP%') !== FALSE)
553 {
554 $tmp = explode ('%GSKIP%', $dict_value, 2);
555 $optgroup[$tmp[0]][$dict_key] = $tmp[1];
556 }
557 elseif (strpos ($dict_value, '%GPASS%') !== FALSE)
558 {
559 $tmp = explode ('%GPASS%', $dict_value, 2);
560 $optgroup[$tmp[0]][$dict_key] = $tmp[1];
561 }
562 else
563 $other[$dict_key] = $dict_value;
564 }
565 echo "<select name=${select_name}>";
566 if (!count ($optgroup))
567 {
568 foreach ($other as $dict_key => $dict_value)
569 {
570 echo "<option value=${dict_key}";
571 if ($dict_key == $selected_id)
572 echo ' selected';
573 echo ">${dict_value}</option>";
574 }
575 }
576 else
577 {
578 foreach ($optgroup as $groupname => $groupdata)
579 {
580 echo "<optgroup label='${groupname}'>";
581 foreach ($groupdata as $dict_key => $dict_value)
582 {
583 echo "<option value=${dict_key}";
584 if ($dict_key == $selected_id)
585 echo ' selected';
586 echo ">${dict_value}</option>";
587 }
588 echo "</optgroup>\n";
589 }
590 if (count ($other))
591 {
592 echo "<optgroup label='other'>\n";
593 foreach ($other as $dict_key => $dict_value)
594 {
595 echo "<option value=${dict_key}";
596 if ($dict_key == $selected_id)
597 echo ' selected';
598 echo ">${dict_value}</option>";
599 }
600 echo "</optgroup>\n";
601 }
602 }
603 echo "</select>";
604}
605
606// used by renderGridForm() and renderRackPage()
607function renderRackInfoPortlet ($rackData)
608{
609 global $root;
610 startPortlet ('summary');
611 echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
612 echo "<tr><th width='50%' class=tdright>Rack row:</th><td class=tdleft>${rackData['row_name']}</td></tr>\n";
613 echo "<tr><th width='50%' class=tdright>Name:</th><td class=tdleft>${rackData['name']}</td></tr>\n";
614 echo "<tr><th width='50%' class=tdright>Height:</th><td class=tdleft>${rackData['height']}</td></tr>\n";
615 echo "<tr><th width='50%' class=tdright>%% used:</th><td class=tdleft>";
616 renderProgressBar (getRSUforRack ($rackData));
617 echo "</td></tr>\n";
618 echo "<tr><th width='50%' class=tdright>Objects:</th><td class=tdleft>";
619 echo count (stuffInRackspace ($rackData));
620 echo "</td></tr>\n";
621 printTagTRs ("${root}?page=rackspace&");
622 if (!empty ($rackData['comment']))
623 echo "<tr><th width='50%' class=tdright>Comment:</th><td class=tdleft>${rackData['comment']}</td></tr>\n";
624 echo '</table>';
625 finishPortlet();
626}
627
628// This is a universal editor of rack design/waste.
629// FIXME: switch to using printOpFormIntro()
630function renderGridForm ($rack_id = 0, $filter, $header, $submit, $state1, $state2)
631{
632 if ($rack_id == 0)
633 {
634 showError ('Invalid rack_id', __FUNCTION__);
635 return;
636 }
637 if (($rackData = getRackData ($rack_id)) == NULL)
638 {
639 showError ('getRackData() failed', __FUNCTION__);
640 return;
641 }
642
643 global $root, $pageno, $tabno;
644 $filter ($rackData);
645 markupObjectProblems ($rackData);
646
647 // Process form submit.
648 if (isset ($_REQUEST['do_update']))
649 {
650 $log[] = processGridForm ($rackData, $state1, $state2);
651 printLog ($log);
652 $rackData = getRackData ($rack_id);
653 $filter ($rackData);
654 markupObjectProblems ($rackData);
655 }
656
657 // Render the result whatever it is.
658 // Main layout.
659 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
660 echo "<tr><td colspan=2 align=center><h1>${rackData['name']}</h1></td></tr>\n";
661
662 // Left column with information portlet.
663 echo "<tr><td class=pcleft height='1%' width='50%'>";
664 renderRackInfoPortlet ($rackData);
665 echo "</td>\n";
666 echo "<td class=pcright>";
667
668 // Grid form.
669 startPortlet ($header);
670 echo "<center>\n";
671 echo "<table class=rack border=0 cellspacing=0 cellpadding=1>\n";
672 echo "<tr><th width='10%'>&nbsp;</th><th width='20%'>Front</th>";
673 echo "<th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n";
674 echo "<form method=post action='${root}?'>\n";
675 echo "<input type=hidden name=page value=${pageno}>\n";
676 echo "<input type=hidden name=tab value=${tabno}>\n";
677 echo "<input type=hidden name=rack_id value=${rack_id}>\n";
678 markupAtomGrid ($rackData, $state2);
679 renderAtomGrid ($rackData);
680 echo "</table></center>\n";
681 echo "<br><input type=submit name=do_update value='${submit}'></form><br><br>\n";
682 finishPortlet();
683 echo "</td></tr></table>\n";
684}
685
686function renderRackDesign ($rack_id)
687{
688 renderGridForm ($rack_id, 'applyRackDesignMask', 'Rack design', 'Set rack design', 'A', 'F');
689}
690
691function renderRackProblems ($rack_id = 0)
692{
693 renderGridForm ($rack_id, 'applyRackProblemMask', 'Rack problems', 'Mark unusable atoms', 'F', 'U');
694}
695
696function startPortlet ($title = '')
697{
698 echo "<div class=portlet><h2>${title}</h2>";
699}
700
701function finishPortlet ()
702{
703 echo "</div>\n";
704}
705
706function printRefsOfType ($refs, $type, $eq)
707{
708 global $root;
709 $gotone=0;
710 foreach ($refs as $ref)
711 {
712 if ($eq($ref['type'], $type))
713 {
714 if ($gotone) echo ', ';
715 echo "<a href='${root}?page=object&object_id=${ref['object_id']}'>";
716 if (!empty ($ref['name']))
717 echo $ref['name'] . '@';
718 echo "${ref['object_name']}</a>";
719 $gotone=1;
720 }
721 }
722}
723
724function renderRackObject ($object_id = 0)
725{
726 global $root, $nextorder, $aac;
727 if ($object_id <= 0)
728 {
729 showError ('Invalid object_id', __FUNCTION__);
730 return;
731 }
732 $info = getObjectInfo ($object_id);
733 if ($info == NULL)
734 {
735 showError ('getObjectInfo() failed', __FUNCTION__);
736 return;
737 }
738 // Main layout starts.
739 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
740 echo "<tr><td colspan=2 align=center><h1>${info['dname']}</h1></td></tr>\n";
741 // left column with uknown number of portlets
742 echo "<tr><td class=pcleft>";
743 startPortlet ('summary');
744 echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
745 if (!empty ($info['name']))
746 echo "<tr><th width='50%' class=tdright>Common name:</th><td class=tdleft>${info['name']}</td></tr>\n";
747 elseif (in_array ($info['objtype_id'], explode (',', getConfigVar ('NAMEFUL_OBJTYPES'))))
748 echo "<tr><td colspan=2 class=msg_error>Common name is missing.</td></tr>\n";
749 echo "<tr><th width='50%' class=tdright>Object type:</th>";
750 echo "<td class=tdleft><a href='${root}?page=objgroup&group_id=${info['objtype_id']}&hl_object_id=${object_id}'>${info['objtype_name']}</a></td></tr>\n";
751 if (!empty ($info['asset_no']))
752 echo "<tr><th width='50%' class=tdright>Asset tag:</th><td class=tdleft>${info['asset_no']}</td></tr>\n";
753 elseif (in_array ($info['objtype_id'], explode (',', getConfigVar ('REQUIRE_ASSET_TAG_FOR'))))
754 echo "<tr><td colspan=2 class=msg_error>Asset tag is missing.</td></tr>\n";
755 if (!empty ($info['label']))
756 echo "<tr><th width='50%' class=tdright>Visible label:</th><td class=tdleft>${info['label']}</td></tr>\n";
757 if (!empty ($info['barcode']))
758 echo "<tr><th width='50%' class=tdright>Barcode:</th><td class=tdleft>${info['barcode']}</td></tr>\n";
759 if ($info['has_problems'] == 'yes')
760 echo "<tr><td colspan=2 class=msg_error>Has problems</td></tr>\n";
761 foreach (getAttrValues ($object_id, TRUE) as $record)
762 if (!empty ($record['value']))
763 echo "<tr><th width='50%' class=opt_attr_th>${record['name']}:</th><td class=tdleft>${record['a_value']}</td></tr>\n";
764 printTagTRs ("${root}?page=objgroup&group_id=${info['objtype_id']}&");
765 echo "</table><br>\n";
766 finishPortlet();
767
768 if (!empty ($info['comment']))
769 {
770 startPortlet ('Comment');
771 echo '<div class=commentblock>' . string_insert_hrefs ($info['comment']) . '</div>';
772 finishPortlet ();
773 }
774
775 $ports = getObjectPortsAndLinks ($object_id);
776 if (count ($ports))
777 {
778 startPortlet ('ports and links');
779 usort($ports, 'sortByName');
780 if ($ports)
781 {
782 $hl_port_id = 0;
783 if (isset ($_REQUEST['hl_port_id']))
784 {
785 assertUIntArg ('hl_port_id', __FUNCTION__);
786 $hl_port_id = $_REQUEST['hl_port_id'];
787 }
788 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
789 echo "<tr><th>Local name</th><th>Visible label</th><th>Port type</th><th>L2 address</th>";
790 echo "<th>Rem. Object</th><th>Rem. port</th></tr>\n";
791 foreach ($ports as $port)
792 {
793 echo '<tr';
794 if ($hl_port_id == $port['id'])
795 echo ' class=port_highlight';
796 echo "><td>${port['name']}</td><td>${port['label']}</td><td>${port['type']}</td>";
797 echo "<td>${port['l2address']}</td>";
798 if ($port['remote_object_id'])
799 {
800 echo "<td><a href='${root}?page=object&object_id=${port['remote_object_id']}&hl_port_id=${port['remote_id']}'>${port['remote_object_name']}</a></td>";
801 echo "<td>${port['remote_name']}</td>";
802 }
803 elseif (!empty ($port['reservation_comment']))
804 {
805 echo "<td><b>Reserved;</b></td>";
806 echo "<td>${port['reservation_comment']}</td>";
807 }
808 else
809 echo '<td>&nbsp;</td><td>&nbsp;</td>';
810 echo "</tr>\n";
811 }
812 echo "</table><br>\n";
813 }
814 finishPortlet();
815 }
816
817 $alloclist = getObjectIPv4Allocations ($object_id);
818 if (count ($alloclist))
819 {
820 startPortlet ('IPv4 addresses');
821 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
822 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
823 echo "<tr><th>OS interface</th><th>IP address</th><th colspan=2>network</th><th>routed by</th><th>peers</th></tr>\n";
824 else
825 echo "<tr><th>OS interface</th><th>IP address</th><th>peers</th></tr>\n";
826 $hl_ipv4_addr = '';
827 if (isset ($_REQUEST['hl_ipv4_addr']))
828 {
829 assertIPv4Arg ('hl_ipv4_addr', __FUNCTION__);
830 $hl_ipv4_addr = $_REQUEST['hl_ipv4_addr'];
831 }
832 foreach ($alloclist as $dottedquad => $alloc)
833 {
834 $address_name = niftyString ($alloc['addrinfo']['name']);
835 $class = $alloc['addrinfo']['class'];
836 $secondclass = ($hl_ipv4_addr == $dottedquad) ? 'tdleft port_highlight' : 'tdleft';
837 $netid = getIPv4AddressNetworkId ($dottedquad);
838 $netinfo = getIPv4NetworkInfo ($netid);
839 echo "<tr class='${class}' valign=top><td class=tdleft>${alloc['osif']}</td><td class='${secondclass}'>";
840 echo "<a href='${root}?page=ipaddress&ip=" . $dottedquad . "&hl_object_id=${object_id}'>${dottedquad}</a>";
841 if (getConfigVar ('EXT_IPV4_VIEW') != 'yes')
842 {
843 if (NULL === $netid)
844 $suffix = '/??';
845 else
846 echo '<small>/' . $netinfo['mask'] . '</small>';
847 }
848 echo '&nbsp;' . $aac[$alloc['type']];
849 if (!empty ($alloc['addrinfo']['name']))
850 echo '(' . niftyString ($alloc['addrinfo']['name']) . ')';
851 echo '</td>';
852 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
853 {
854 if (NULL === $netid)
855 echo '<td colspan=2>?</td>';
856 else
857 printIPv4NetInfoTDs ($netinfo, $secondclass);
858 echo "<td class='${secondclass}'>";
859 // FIXME: These cals are really heavy, replace them with a more appropriate dedicated function.
860 $netdata = getIPv4Network ($netid);
861 $newline = '';
862 foreach (findRouters ($netdata['addrlist']) as $router)
863 {
864 if ($router['id'] == $object_id)
865 continue;
866 echo $newline . $router['addr'] . ", <a href='${root}?page=object&object_id=${router['id']}&hl_ipv4_addr=${router['addr']}'>";
867 echo (empty ($router['iface']) ? '' : $router['iface'] . '@') . $router['dname'] . '</a>';
868 $routertags = loadRackObjectTags ($router['id']);
869 if (count ($routertags))
870 echo '<br><small>' . serializeTags ($routertags, "${root}?page=objects&tab=default&") . '</small>';
871 $newline = '<br>';
872 }
873 echo '</td>';
874 }
875 // peers
876 echo "<td class='${secondclass}'>\n";
877 $prefix = '';
878 if ($alloc['addrinfo']['reserved'] == 'yes')
879 {
880 echo $prefix . '<strong>RESERVED</strong>';
881 $prefix = '; ';
882 }
883 foreach ($alloc['addrinfo']['allocs'] as $allocpeer)
884 {
885 if ($allocpeer['object_id'] == $object_id)
886 continue;
887 echo $prefix . "<a href='${root}?page=object&object_id=${allocpeer['object_id']}'>";
888 if (!empty ($allocpeer['osif']))
889 echo $allocpeer['osif'] . '@';
890 echo $allocpeer['object_name'] . '</a>';
891 $prefix = '; ';
892 }
893 echo "</td></tr>\n";
894 }
895 echo "</table><br>\n";
896 finishPortlet();
897 }
898
899 $forwards = getNATv4ForObject ($object_id);
900 if (count($forwards['in']) or count($forwards['out']))
901 {
902 startPortlet('NATv4');
903
904 if (count($forwards['out']))
905 {
906
907 echo "<h3>locally performed NAT</h3>";
908
909 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
910 echo "<tr><th>Proto</th><th>Match endpoint</th><th>Translate to</th><th>Target object</th><th>Rule comment</th></tr>\n";
911
912 foreach ($forwards['out'] as $pf)
913 {
914 $class = 'trerror';
915 $osif = '';
916 if (isset ($alloclist [$pf['localip']]))
917 {
918 $class = $alloclist [$pf['localip']]['addrinfo']['class'];
919 $osif = $alloclist [$pf['localip']]['osif'] . ': ';
920 }
921 echo "<tr class='$class'>";
922 echo "<td>${pf['proto']}</td><td class=tdleft>${osif}<a href='${root}?page=ipaddress&tab=default&ip=${pf['localip']}'>${pf['localip']}</a>:${pf['localport']}</td>";
923 echo "<td class=tdleft><a href='${root}?page=ipaddress&tab=default&ip=${pf['remoteip']}'>${pf['remoteip']}</a>:${pf['remoteport']}</td>";
924 $address = getIPv4Address ($pf['remoteip']);
925 echo "<td class='description'>";
926 if (count ($address['allocs']))
927 foreach($address['allocs'] as $bond)
928 echo "<a href='${root}?page=object&tab=default&object_id=${bond['object_id']}'>${bond['object_name']}(${bond['name']})</a> ";
929 elseif (!empty ($pf['remote_addr_name']))
930 echo '(' . $pf['remote_addr_name'] . ')';
931 echo "</td><td class='description'>${pf['description']}</td></tr>";
932 }
933 echo "</table><br><br>";
934 }
935 if (count($forwards['in']))
936 {
937 echo "<h3>arriving NAT connections</h3>";
938 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
939 echo "<tr><th>Matched endpoint</th><th>Source object</th><th>Translated to</th><th>Rule comment</th></tr>\n";
940 foreach ($forwards['in'] as $pf)
941 {
942 echo "<tr>";
943 echo "<td>${pf['proto']}/<a href='${root}?page=ipaddress&tab=default&ip=${pf['localip']}'>${pf['localip']}</a>:${pf['localport']}</td>";
944 echo "<td class='description'><a href='${root}?page=object&tab=default&object_id=${pf['object_id']}'>${pf['object_name']}</a>";
945 echo "</td><td><a href='${root}?page=ipaddress&tab=default&ip=${pf['remoteip']}'>${pf['remoteip']}</a>:${pf['remoteport']}</td>";
946 echo "<td class='description'>${pf['description']}</td></tr>";
947 }
948 echo "</table><br><br>";
949 }
950 finishPortlet();
951 }
952
953 $pools = getRSPoolsForObject ($object_id);
954 if (count ($pools))
955 {
956 $order = 'odd';
957 startPortlet ('Real server pools');
958 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable>\n";
959 echo "<tr><th>VS</th><th>RS pool</th><th>RS</th><th>VS config</th><th>RS config</th></tr>\n";
960 foreach ($pools as $vs_id => $info)
961 {
962 echo "<tr valign=top class=row_${order}><td class=tdleft><a href='${root}?page=ipv4vs&vs_id=${vs_id}'>";
963 echo buildVServiceName ($info);
964 echo '</a>';
965 if (!empty ($info['name']))
966 echo "<br>${info['name']}";
967 echo "</td><td class=tdleft><a href='${root}?page=ipv4rsp&pool_id=${info['pool_id']}'>";
968 echo (empty ($info['pool_name']) ? 'ANONYMOUS' : $info['pool_name']);
969 echo '</a></td><td class=tdleft>' . $info['rscount'] . '</td>';
970 echo "<td class=tdleft><pre>${info['vsconfig']}</pre></td>";
971 echo "<td class=tdleft><pre>${info['rsconfig']}</pre></td>";
972 echo "</tr>\n";
973 $order = $nextorder[$order];
974 }
975 echo "</table>\n";
976 finishPortlet();
977 }
978 echo "</td>\n";
979
980 // After left column we have (surprise!) right column with rackspace portlet only.
981 echo "<td class=pcright>";
982 // rackspace portlet
983 startPortlet ('rackspace allocation');
984 // FIXME: now we call getRackData() twice
985 $racks = getResidentRacksData ($object_id);
986 foreach ($racks as $rackData)
987 renderRack ($rackData['id'], $object_id);
988 echo '<br>';
989 finishPortlet();
990 echo "</td></tr>";
991 echo "</table>\n";
992}
993
994function renderRackMultiSelect ($sname, $racks, $selected)
995{
996 // Transform the given flat list into a list of groups, each representing a rack row.
997 $rdata = array();
998 foreach ($racks as $rack)
999 if (!isset ($rdata[$rack['row_name']]))
1000 $rdata[$rack['row_name']] = array ($rack['id'] => $rack['name']);
1001 else
1002 $rdata[$rack['row_name']][$rack['id']] = $rack['name'];
1003 echo "<select name=${sname} multiple size=" . getConfigVar ('MAXSELSIZE') . " onchange='getElementById(\"racks\").submit()'>\n";
1004 foreach ($rdata as $optgroup => $racklist)
1005 {
1006 echo "<optgroup label='${optgroup}'>";
1007 foreach ($racklist as $rack_id => $rack_name)
1008 {
1009 echo "<option value=${rack_id}";
1010 if (!(array_search ($rack_id, $selected) === FALSE))
1011 echo ' selected';
1012 echo">${rack_name}</option>\n";
1013 }
1014 }
1015 echo "</select>\n";
1016}
1017
1018function showMessageOrError ()
1019{
1020 if (isset ($_REQUEST['message']))
1021 echo "<div class=msg_success>${_REQUEST['message']}</div>";
1022 elseif (isset ($_REQUEST['error']))
1023 echo "<div class=msg_error>${_REQUEST['error']}</div>";
1024 elseif (isset ($_REQUEST['log']))
1025 printLog (unserialize (base64_decode ($_REQUEST['log'])));
1026}
1027
1028// This function renders a form for port edition.
1029function renderPortsForObject ($object_id = 0)
1030{
1031 global $root, $pageno, $tabno;
1032 if ($object_id <= 0)
1033 {
1034 showError ('Invalid object_id', __FUNCTION__);
1035 return;
1036 }
1037 showMessageOrError();
1038 startPortlet ('Ports and interfaces');
1039 $ports = getObjectPortsAndLinks ($object_id);
1040 usort($ports, 'sortByName');
1041 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
1042 echo "<tr><th>&nbsp;</th><th>Local name</th><th>Visible label</th><th>Port type</th><th>L2 address</th>";
1043 echo "<th>Rem. object</th><th>Rem. port</th><th>(Un)link or (un)reserve</th><th>&nbsp;</th></tr>\n";
1044 foreach ($ports as $port)
1045 {
1046 printOpFormIntro ('editPort', array ('port_id' => $port['id']));
1047 echo "<tr><td><a href='${root}process.php?op=delPort&page=${pageno}&tab=${tabno}&port_id=${port['id']}&object_id=$object_id&port_name=${port['name']}'>";
1048 printImageHREF ('delete', 'Unlink and Delete this port');
1049 echo "</a></td>\n";
1050 echo "<td><input type=text name=name value='${port['name']}' size=8></td>";
1051 echo "<td><input type=text name=label value='${port['label']}' size=24></td>";
1052 echo "<td>${port['type']}</td>\n";
1053 echo "<td><input type=text name=l2address value='${port['l2address']}'></td>\n";
1054 if ($port['remote_object_id'])
1055 {
1056 echo "<td><a href='${root}?page=object&object_id=${port['remote_object_id']}'>${port['remote_object_name']}</a></td>";
1057 echo "<td>${port['remote_name']}</td>";
1058 echo "<td><a href='${root}process.php?op=unlinkPort&page=${pageno}&tab=${tabno}&port_id=${port['id']}&object_id=$object_id&port_name=";
1059 echo urlencode ($port['name']);
1060 echo "&remote_port_name=${port['remote_name']}&remote_object_name=${port['remote_object_name']}'>";
1061 printImageHREF ('unlink', 'Unlink this port');
1062 echo "</a></td>";
1063 }
1064 elseif (!empty ($port['reservation_comment']))
1065 {
1066 echo "<td><b>Reserved;</b></td>";
1067 echo "<td><input type=text name=reservation_comment value='${port['reservation_comment']}'></td>";
1068 echo "<td><a href='${root}process.php?op=useup&page=${pageno}&tab=${tabno}&port_id=${port['id']}&object_id=${object_id}'>";
1069 printImageHREF ('useup', 'Use up this port');
1070 echo "</a></td>";
1071 }
1072 else
1073 {
1074 echo "<td>&nbsp;</td><td>&nbsp;</td>";
1075 echo "<td>";
1076 echo "<a href='javascript:;' onclick='window.open(\"${root}link_helper.php?port=${port['id']}&type=${port['type_id']}&object_id=$object_id&port_name=";
1077 echo urlencode ($port['name']);
1078 echo "\",\"findlink\",\"height=700, width=400, location=no, menubar=no, resizable=yes, scrollbars=no, status=no, titlebar=no, toolbar=no\");'>";
1079 printImageHREF ('link', 'Link this port');
1080 echo "</a> <input type=text name=reservation_comment>";
1081 echo "</td>\n";
1082 }
1083 echo "<td>";
1084 printImageHREF ('save', 'Save changes', TRUE);
1085 echo "</td></form></tr>\n";
1086 }
1087 printOpFormIntro ('addPort');
1088 echo "<tr><td>";
1089 printImageHREF ('add', '', TRUE, 104);
1090 echo "</td><td><input type=text size=8 name=port_name tabindex=100></td>\n";
1091 echo "<td><input type=text size=24 name=port_label tabindex=101></td>";
1092 echo "<td><select name='port_type_id' tabindex=102>\n";
1093 $types = getPortTypes();
1094 $default_port_type = getConfigVar ('default_port_type');
1095 foreach ($types as $typeid => $typename)
1096 {
1097 echo "<option value='${typeid}'";
1098 if ($typeid == $default_port_type)
1099 echo " selected";
1100 echo ">${typename}</option>\n";
1101 }
1102 echo "</select></td>";
1103 echo "<td><input type=text name=port_l2address tabindex=103></td>\n";
1104 echo "<td colspan=4>&nbsp;</td></tr></form>";
1105 echo "</table><br>\n";
1106 finishPortlet();
1107
1108 startPortlet ('Add/update multiple ports');
1109 printOpFormIntro ('addMultiPorts');
1110 echo 'Format: <select name=format>';
1111 echo '<option value=c3600asy>Cisco 3600 async: sh line | inc TTY</option>';
1112 echo '<option value=fiwg selected>Foundry ServerIron/FastIron WorkGroup/Edge: sh int br</option>';
1113 echo '<option value=fisxii>Foundry FastIron SuperX/II4000: sh int br</option>';
1114 echo '<option value=ssv1>SSV:&lt;interface name&gt; &lt;MAC address&gt;</option>';
1115 echo "</select>";
1116 echo 'Default port type: ';
1117 echo "<select name=port_type>\n";
1118 foreach ($types as $typeid => $typename)
1119 {
1120 echo "<option value='${typeid}'";
1121 if ($typeid == $default_port_type)
1122 echo " selected";
1123 echo ">${typename}</option>\n";
1124 }
1125 echo "</select>";
1126 echo "<input type=submit value='Parse output'><br>\n";
1127 echo "<textarea name=input cols=100 rows=50></textarea><br>\n";
1128 echo '</form>';
1129 finishPortlet();
1130}
1131
1132function renderIPv4ForObject ($object_id = 0)
1133{
1134 global $root, $pageno, $tabno, $aat;
1135 if ($object_id <= 0)
1136 {
1137 showError ('Invalid object_id', __FUNCTION__);
1138 return;
1139 }
1140 showMessageOrError();
1141 startPortlet ('Allocations');
1142 $alloclist = getObjectIPv4Allocations ($object_id);
1143 echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n";
1144 echo "<tr><th>&nbsp;</th><th>OS interface</th><th>IP address</th><th>description</th><th>type</th><th>misc</th><th>&nbsp</th></tr>\n";
1145 foreach ($alloclist as $dottedquad => $alloc)
1146 {
1147 $address_name = niftyString ($alloc['addrinfo']['name']);
1148 $class = $alloc['addrinfo']['class'];
1149 printOpFormIntro ('updIPv4Allocation', array ('ip' => $dottedquad));
1150 echo "<tr class='$class'><td><a href='${root}process.php?op=delIPv4Allocation&page=${pageno}&tab=${tabno}&ip=${dottedquad}&object_id=$object_id'>";
1151 printImageHREF ('delete', 'Delete this IPv4 address');
1152 echo "</a></td>";
1153 echo "<td class=tdleft><input type='text' name='bond_name' value='${alloc['osif']}' size=10></td>";
1154 echo "<td class=tdleft><a href='${root}?page=ipaddress&ip=${dottedquad}'>${dottedquad}</a></td>";
1155 echo "<td class='description'>$address_name</td>\n<td>";
1156 printSelect ($aat, 'bond_type', $alloc['type']);
1157 echo "</td><td>";
1158 $prefix = '';
1159 if ($alloc['addrinfo']['reserved'] == 'yes')
1160 {
1161 echo $prefix . '<strong>RESERVED</strong>';
1162 $prefix = '; ';
1163 }
1164 foreach ($alloc['addrinfo']['allocs'] as $allocpeer)
1165 {
1166 if ($allocpeer['object_id'] == $object_id)
1167 continue;
1168 echo $prefix . "<a href='${root}?page=object&object_id=${allocpeer['object_id']}'>";
1169 if (!empty ($allocpeer['osif']))
1170 echo $allocpeer['osif'] . '@';
1171 echo $allocpeer['object_name'] . '</a>';
1172 $prefix = '; ';
1173 }
1174 echo "</td><td>";
1175 printImageHREF ('save', 'Save changes', TRUE);
1176 echo "</td></form></tr>\n";
1177 }
1178
1179 printOpFormIntro ('addIPv4Allocation');
1180 echo "<tr><td>";
1181 printImageHREF ('add', 'Allocate new address', TRUE, 99);
1182 echo "</td>";
1183 echo "<td class=tdleft><input type='text' size='10' name='bond_name' tabindex=100></td>\n";
1184 echo "<td class=tdleft><input type=text name='ip' tabindex=101></td>\n";
1185 echo "<td>&nbsp;</td><td>";
1186 printSelect ($aat, 'bond_type');
1187 echo "</td><td colspan=2>&nbsp;</td></tr></form></table><br>\n";
1188 finishPortlet();
1189
1190}
1191
1192// Log structure versions:
1193// 1: the whole structure is a list of code-message pairs
1194// 2 and later: there's a "v" field set, which indicates the version
1195// 2: there's a "m" list set to hold message code and optional arguments
1196function printLog ($log)
1197{
1198 switch (TRUE)
1199 {
1200 case !isset ($log['v']):
1201 case $log['v'] == 1:
1202 foreach ($log as $key => $record)
1203 if ($key !== 'v')
1204 echo "<div class=msg_${record['code']}>${record['message']}</div>";
1205 break;
1206 case $log['v'] == 2:
1207 $msginfo = array
1208 (
1209 0 => array ('code' => 'success', 'format' => 'Success: %s'),
1210 1 => array ('code' => 'success', 'format' => '%u new records done, %u already existed'),
1211 2 => array ('code' => 'success', 'format' => 'NATv4 rule was successfully added.'),
1212 3 => array ('code' => 'success', 'format' => 'NATv4 rule was successfully deleted.'),
1213 4 => array ('code' => 'success', 'format' => 'NATv4 rule was successfully updated'),
1214 5 => array ('code' => 'success', 'format' => 'Port %s was added successfully'),
1215 6 => array ('code' => 'success', 'format' => 'Port %s was updated successfully'),
1216 7 => array ('code' => 'success', 'format' => 'Port %s was deleted successfully'),
1217 8 => array ('code' => 'success', 'format' => 'Port %s successfully linked with port %s at object %s'),
1218 9 => array ('code' => 'success', 'format' => 'Port %s was successfully unlinked from %s@%s'),
1219 10 => array ('code' => 'success', 'format' => 'Added %u ports, updated %u ports, encountered %u errors.'),
1220 11 => array ('code' => 'success', 'format' => 'Reservation removed.'),
1221 12 => array ('code' => 'success', 'format' => 'allocation updated'),
1222 13 => array ('code' => 'success', 'format' => 'allocated'),
1223 14 => array ('code' => 'success', 'format' => 'deallocated'),
1224 15 => array ('code' => 'success', 'format' => 'Reset succeeded.'),
1225 16 => array ('code' => 'success', 'format' => 'Update done'),
1226 17 => array ('code' => 'success', 'format' => 'Update(s) succeeded.'),
1227 18 => array ('code' => 'success', 'format' => 'Load balancer was successfully added'),
1228 19 => array ('code' => 'success', 'format' => 'Load balancer was successfully deleted'),
1229 20 => array ('code' => 'success', 'format' => 'Load balancer info was successfully updated'),
1230 21 => array ('code' => 'success', 'format' => 'Generation complete'),
1231 22 => array ('code' => 'success', 'format' => 'Chained %u tags'),
1232 23 => array ('code' => 'success', 'format' => 'IPv4 prefix successfully added'),
1233 24 => array ('code' => 'success', 'format' => 'IPv4 prefix deleted'),
1234 25 => array ('code' => 'success', 'format' => 'IPv4 prefix updated'),
1235 26 => array ('code' => 'success', 'format' => '%u IP address(es) were successfully updated'),
1236 27 => array ('code' => 'success', 'format' => 'IPv4 address updated'),
1237 28 => array ('code' => 'success', 'format' => 'Virtual service was successfully created'),
1238 29 => array ('code' => 'success', 'format' => 'Virtual service was successfully deleted'),
1239 30 => array ('code' => 'success', 'format' => 'Virtual service was successfully updated'),
1240 31 => array ('code' => 'success', 'format' => 'RS pool was successfully created'),
1241 32 => array ('code' => 'success', 'format' => 'RS pool was successfully deleted'),
1242 33 => array ('code' => 'success', 'format' => 'RS pool was successfully updated'),
1243 34 => array ('code' => 'success', 'format' => 'Real server was successfully added'),
1244 35 => array ('code' => 'success', 'format' => 'Real server was successfully deleted'),
1245 36 => array ('code' => 'success', 'format' => 'Real server was successfully updated'),
1246 37 => array ('code' => 'success', 'format' => 'Successfully added %u real servers'),
1247 38 => array ('code' => 'success', 'format' => '%u real server(s) were successfully (de)activated'),
1248 39 => array ('code' => 'success', 'format' => 'User account %s updated.'),
1249 40 => array ('code' => 'success', 'format' => 'User account %s created.'),
1250 41 => array ('code' => 'success', 'format' => 'User account disabled.'),
1251 42 => array ('code' => 'success', 'format' => 'User account enabled.'),
1252 43 => array ('code' => 'success', 'format' => 'Saved successfully.'),
1253 44 => array ('code' => 'success', 'format' => '%s failures and %s successfull changes.'),
1254 45 => array ('code' => 'success', 'format' => "Attribute '%s' created."),
1255 46 => array ('code' => 'success', 'format' => 'Rename successful.'),
1256 47 => array ('code' => 'success', 'format' => 'Attribute was deleted.'),
1257 48 => array ('code' => 'success', 'format' => 'Supplement succeeded.'),
1258 49 => array ('code' => 'success', 'format' => 'Reduction succeeded.'),
1259 50 => array ('code' => 'success', 'format' => 'Reduction succeeded.'),
1260 51 => array ('code' => 'success', 'format' => 'Update succeeded.'),
1261 52 => array ('code' => 'success', 'format' => 'Supplement succeeded.'),
1262 53 => array ('code' => 'success', 'format' => 'Chapter was deleted.'),
1263 54 => array ('code' => 'success', 'format' => 'Chapter was updated.'),
1264 55 => array ('code' => 'success', 'format' => 'Chapter was added.'),
1265 56 => array ('code' => 'success', 'format' => 'Update succeeded.'),
1266 57 => array ('code' => 'success', 'format' => 'Reset complete'),
1267 58 => array ('code' => 'success', 'format' => "Successfully deleted tag ."),
1268 59 => array ('code' => 'success', 'format' => "Created tag '%s'."),
1269 60 => array ('code' => 'success', 'format' => "Updated tag '%s'."),
1270 61 => array ('code' => 'success', 'format' => 'Password changed successfully.'),
1271 62 => array ('code' => 'success', 'format' => 'gw: %s'),
1272 63 => array ('code' => 'success', 'format' => '%u change request(s) have been processed'),
1273 64 => array ('code' => 'success', 'format' => 'Port %s@%s has been assigned to VLAN %u'),
1274 65 => array ('code' => 'success', 'format' => "Added new rack '%s'"),
1275 66 => array ('code' => 'success', 'format' => "File sent Ok via handler '%s'"),
1276 67 => array ('code' => 'success', 'format' => "Tag rolling done, %u objects involved"),
1277 68 => array ('code' => 'success', 'format' => "Updated rack '%s'"),
1278
1279 100 => array ('code' => 'error', 'format' => 'Generic error: %s'),
1280 101 => array ('code' => 'error', 'format' => 'Port name cannot be empty'),
1281 102 => array ('code' => 'error', 'format' => "Error creating user account '%s'"),
1282 103 => array ('code' => 'error', 'format' => 'getHashByID() failed'),
1283 104 => array ('code' => 'error', 'format' => "Error updating user account '%s'"),
1284 105 => array ('code' => 'error', 'format' => 'Error enabling user account.'),
1285 106 => array ('code' => 'error', 'format' => 'Error disabling user account.'),
1286 107 => array ('code' => 'error', 'format' => 'Admin account cannot be disabled'),
1287 108 => array ('code' => 'error', 'format' => '%u failures and %u successfull changes.'),
1288 109 => array ('code' => 'error', 'format' => 'Update failed!'),
1289 110 => array ('code' => 'error', 'format' => 'Supplement failed!'),
1290 111 => array ('code' => 'error', 'format' => 'Reduction failed!'),
1291 112 => array ('code' => 'error', 'format' => 'Error adding chapter.'),
1292 113 => array ('code' => 'error', 'format' => 'Error updating chapter.'),
1293 114 => array ('code' => 'error', 'format' => 'Error deleting chapter.'),
1294 115 => array ('code' => 'error', 'format' => 'Error renaming attribute.'),
1295 116 => array ('code' => 'error', 'format' => 'Error creating attribute.'),
1296 117 => array ('code' => 'error', 'format' => 'Error deleting attribute.'),
1297 118 => array ('code' => 'error', 'format' => 'Supplement failed!'),
1298 119 => array ('code' => 'error', 'format' => 'Reduction failed!'),
1299 120 => array ('code' => 'error', 'format' => 'Reset failed!'),
1300 121 => array ('code' => 'error', 'format' => 'commitUpdateObject() failed'),
1301 122 => array ('code' => 'error', 'format' => 'One or more update(s) failed!'),
1302 123 => array ('code' => 'error', 'format' => 'Cannot process submitted data: unknown format code.'),
1303 124 => array ('code' => 'error', 'format' => 'Error removing reservation!'),
1304 125 => array ('code' => 'error', 'format' => "Update failed with error: '%s'"),
1305 126 => array ('code' => 'error', 'format' => 'addRStoRSPool() failed'),
1306 127 => array ('code' => 'error', 'format' => 'Added %u real servers and encountered %u errors'),
1307 128 => array ('code' => 'error', 'format' => 'commitDeleteRS() failed'),
1308 129 => array ('code' => 'error', 'format' => 'commitDeleteLB() failed'),
1309 130 => array ('code' => 'error', 'format' => 'commitDeleteVS() failed'),
1310 131 => array ('code' => 'error', 'format' => 'invalid format requested'),
1311 132 => array ('code' => 'error', 'format' => 'invalid protocol'),
1312 133 => array ('code' => 'error', 'format' => 'commitUpdateRS() failed'),
1313 134 => array ('code' => 'error', 'format' => 'commitUpdateLB() failed'),
1314 135 => array ('code' => 'error', 'format' => 'commitUpdateVS() failed'),
1315 136 => array ('code' => 'error', 'format' => 'addLBtoRSPool() failed'),
1316 137 => array ('code' => 'error', 'format' => 'addLBtoRSPool() failed'),
1317 138 => array ('code' => 'error', 'format' => 'commitDeleteRSPool() failed'),
1318 139 => array ('code' => 'error', 'format' => 'commitUpdateRSPool() failed'),
1319 140 => array ('code' => 'error', 'format' => 'Encountered %u errors, (de)activated %u real servers'),
1320 141 => array ('code' => 'error', 'format' => 'Encountered %u errors, updated %u IP address(es)'),
1321 142 => array ('code' => 'error', 'format' => 'executeAutoPorts() failed'),
1322 143 => array ('code' => 'error', 'format' => 'Tried chaining %u tags, but experienced %u errors.'),
1323 144 => array ('code' => 'error', 'format' => "Error deleting tag: '%s'"),
1324 145 => array ('code' => 'error', 'format' => "Invalid tag name '%s'"),
1325 146 => array ('code' => 'error', 'format' => "Tag '%s' (or similar name) already exists"),
1326 147 => array ('code' => 'error', 'format' => "Could not create tag '%s' because of error '%s'"),
1327 148 => array ('code' => 'error', 'format' => "Could not update tag '%s' because of error '%s'"),
1328 149 => array ('code' => 'error', 'format' => 'Turing test failed'),
1329 150 => array ('code' => 'error', 'format' => 'Can only change password under DB authentication.'),
1330 151 => array ('code' => 'error', 'format' => 'Old password doesn\'t match.'),
1331 152 => array ('code' => 'error', 'format' => 'New passwords don\'t match.'),
1332 153 => array ('code' => 'error', 'format' => 'Password change failed.'),
1333 154 => array ('code' => 'error', 'format' => "Verification error: %s"),
1334 155 => array ('code' => 'error', 'format' => 'Save failed.'),
1335 156 => array ('code' => 'error', 'format' => 'getSwitchVLANs() failed'),
1336 157 => array ('code' => 'error', 'format' => 'operation not permitted'),
1337 158 => array ('code' => 'error', 'format' => 'Ignoring malformed record #%u in form submit'),
1338 159 => array ('code' => 'error', 'format' => 'Permission denied moving port %s from VLAN%u to VLAN%u'),
1339 160 => array ('code' => 'error', 'format' => 'Invalid arguments'),
1340 161 => array ('code' => 'error', 'format' => 'Endpoint not found. Please either set FQDN attribute or assign an IP address to the object.'),
1341 162 => array ('code' => 'error', 'format' => 'More than one IP address is assigned to this object, please configure FQDN attribute.'),
1342 163 => array ('code' => 'error', 'format' => 'Failed to get any response from queryGateway() or the gateway died'),
1343 164 => array ('code' => 'error', 'format' => 'Gateway failure: %s.'),
1344 165 => array ('code' => 'error', 'format' => 'Gateway failure: malformed reply.'),
1345 166 => array ('code' => 'error', 'format' => 'gw: %s'),
1346 167 => array ('code' => 'error', 'format' => 'Could not find port %s'),
1347 168 => array ('code' => 'error', 'format' => 'Port %s is a trunk'),
1348 169 => array ('code' => 'error', 'format' => 'Failed to configure %s, connector returned code %u'),
1349 170 => array ('code' => 'error', 'format' => 'There is no network for IP address "%s"'),
1350 171 => array ('code' => 'error', 'format' => "Failed creating rack '%s'. Already exists in this row?"),
1351 172 => array ('code' => 'error', 'format' => 'Malformed request'),
1352 173 => array ('code' => 'error', 'format' => "Invalid IPv4 prefix '%s'"),
1353 174 => array ('code' => 'error', 'format' => 'Bad IPv4 address'),
1354 175 => array ('code' => 'error', 'format' => 'Invalid netmask'),
1355 176 => array ('code' => 'error', 'format' => 'This network already exists'),
1356 177 => array ('code' => 'error', 'format' => 'commitUpdateRack() failed'),
1357
1358 200 => array ('code' => 'warning', 'format' => 'generic warning: %s'),
1359 201 => array ('code' => 'warning', 'format' => 'nothing happened...'),
1360 202 => array ('code' => 'warning', 'format' => 'gw: %s'),
1361 203 => array ('code' => 'warning', 'format' => 'Port %s seems to be the first in VLAN %u at this switch.'),
1362 204 => array ('code' => 'warning', 'format' => 'Check uplink/downlink configuration for proper operation.'),
1363 205 => array ('code' => 'warning', 'format' => '%u change request(s) have been ignored'),
1364 );
1365 // Handle the arguments. Is there any better way to do it?
1366 foreach ($log['m'] as $record)
1367 {
1368 if (!isset ($record['c']) or !isset ($msginfo[$record['c']]))
1369 {
1370 echo '<div class=msg_neutral>(this message was lost)</div>';
1371 continue;
1372 }
1373 if (isset ($record['a']))
1374 switch (count ($record['a']))
1375 {
1376 case 1:
1377 $msgtext = sprintf
1378 (
1379 $msginfo[$record['c']]['format'],
1380 $record['a'][0]
1381 );
1382 break;
1383 case 2:
1384 $msgtext = sprintf
1385 (
1386 $msginfo[$record['c']]['format'],
1387 $record['a'][0],
1388 $record['a'][1]
1389 );
1390 break;
1391 case 3:
1392 $msgtext = sprintf
1393 (
1394 $msginfo[$record['c']]['format'],
1395 $record['a'][0],
1396 $record['a'][1],
1397 $record['a'][2]
1398 );
1399 break;
1400 case 4:
1401 default:
1402 $msgtext = sprintf
1403 (
1404 $msginfo[$record['c']]['format'],
1405 $record['a'][0],
1406 $record['a'][1],
1407 $record['a'][2],
1408 $record['a'][3]
1409 );
1410 break;
1411 }
1412 else
1413 $msgtext = $msginfo[$record['c']]['format'];
1414 echo '<div class=msg_' . $msginfo[$record['c']]['code'] . ">${msgtext}</div>";
1415 }
1416 break;
1417 default:
1418 echo '<div class=msg_error>' . __FUNCTION__ . ': internal error</div>';
1419 break;
1420 }
1421}
1422
1423/*
1424The following conditions must be followed:
14251. We can mount onto free atoms only. This means: if any record for an atom
1426already exists in RackSpace, it can't be used for mounting.
14272. We can't unmount from 'W' atoms. Operator should review appropriate comments
1428and either delete them before unmounting or refuse to unmount the object.
1429*/
1430
1431// We extensively use $_REQUEST in the function.
1432// FIXME: move related code into ophandler
1433function renderRackSpaceForObject ($object_id = 0)
1434{
1435 if ($object_id <= 0)
1436 {
1437 showError ('Invalid object_id', __FUNCTION__);
1438 return;
1439 }
1440 $is_submit = isset ($_REQUEST['got_atoms']);
1441 $is_update = isset ($_REQUEST['rackmulti'][0]);
1442 $info = getObjectInfo ($object_id);
1443 if ($info == NULL)
1444 {
1445 showError ('getObjectInfo() failed', __FUNCTION__);
1446 return;
1447 }
1448 // Always process occupied racks plus racks chosen by user. First get racks with
1449 // already allocated rackspace...
1450 $workingRacksData = getResidentRacksData ($object_id);
1451 if ($workingRacksData === NULL)
1452 {
1453 print_r ($workingRacksData);
1454 showError ('getResidentRacksData() failed', __FUNCTION__);
1455 return;
1456 }
1457
1458 // ...and then add those chosen by user (if any).
1459 if ($is_update)
1460 foreach ($_REQUEST['rackmulti'] as $cand_id)
1461 {
1462 if (!isset ($workingRacksData[$cand_id]))
1463 {
1464 $rackData = getRackData ($cand_id);
1465 if ($rackData == NULL)
1466 {
1467 showError ('getRackData() failed', __FUNCTION__);
1468 return NULL;
1469 }
1470 $workingRacksData[$cand_id] = $rackData;
1471 }
1472 }
1473
1474 // Do it only once...
1475 foreach ($workingRacksData as &$rackData)
1476 applyObjectMountMask ($rackData, $object_id);
1477 // Now we workaround an old caveat: http://bugs.php.net/bug.php?id=37410
1478 unset ($rackData);
1479
1480 // Here we process form submit by trying to save all submitted info to database.
1481 if ($is_submit)
1482 {
1483 $oldMolecule = getMoleculeForObject ($object_id);
1484 $worldchanged = FALSE;
1485 $log = array();
1486 foreach ($workingRacksData as $rack_id => $rackData)
1487 {
1488 $logrecord = processGridForm ($rackData, 'F', 'T', $object_id);
1489 $log[] = $logrecord;
1490 if ($logrecord['code'] != 300)
1491 {
1492 $worldchanged = TRUE;
1493 // Reload our working copy after form processing.
1494 $rackData = getRackData ($rack_id);
1495 if ($rackData == NULL)
1496 $log[] = array ('code' => 500, 'message' => 'Working copy update failed in ', __FUNCTION__);
1497 applyObjectMountMask ($rackData, $object_id);
1498 $workingRacksData[$rack_id] = $rackData;
1499 }
1500 }
1501 if ($worldchanged)
1502 {
1503 // Log a record.
1504 $newMolecule = getMoleculeForObject ($object_id);
1505 $oc = count ($oldMolecule);
1506 $nc = count ($newMolecule);
1507 $omid = $oc ? createMolecule ($oldMolecule) : 'NULL';
1508 $nmid = $nc ? createMolecule ($newMolecule) : 'NULL';
1509 global $remote_username;
1510 $comment = empty ($_REQUEST['comment']) ? 'NULL' : "'${_REQUEST['comment']}'";
1511 $query =
1512 "insert into MountOperation(object_id, old_molecule_id, new_molecule_id, user_name, comment) " .
1513 "values (${object_id}, ${omid}, ${nmid}, '${remote_username}', ${comment})";
1514 global $dbxlink;
1515 $result = $dbxlink->query ($query);
1516 if ($result == NULL)
1517 $log[] = array ('code' => 'error', 'message' => 'SQL query failed during history logging.');
1518 else
1519 $log[] = array ('code' => 'success', 'message' => 'History logged.');
1520 }
1521 printLog ($log);
1522 }
1523
1524 // This is the time for rendering.
1525 global $root, $pageno, $tabno;
1526 echo "<form id='racks' action='${root}'>";
1527 echo "<input type=hidden name=page value='${pageno}'>\n";
1528 echo "<input type=hidden name=tab value='${tabno}'>\n";
1529 echo "<input type=hidden name=object_id value='${object_id}'>\n";
1530 // Main layout starts.
1531 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0><tr>";
1532
1533 // Left portlet with rack list.
1534 echo "<td class=pcleft height='1%'>";
1535 startPortlet ('Racks');
1536 $allRacksData = getRacksForRow();
1537 if (count ($allRacksData) <= getConfigVar ('RACK_PRESELECT_THRESHOLD'))
1538 {
1539 foreach (array_keys ($allRacksData) as $rack_id)
1540 {
1541 $rackData = getRackData ($rack_id);
1542 if ($rackData == NULL)
1543 {
1544 showError ('getRackData() failed', __FUNCTION__);
1545 return NULL;
1546 }
1547 $workingRacksData[$rack_id] = $rackData;
1548 }
1549 foreach ($workingRacksData as &$rackData)
1550 applyObjectMountMask ($rackData, $object_id);
1551 unset ($rackData);
1552 }
1553 renderRackMultiSelect ('rackmulti[]', $allRacksData, array_keys ($workingRacksData));
1554 echo "<br>";
1555 echo "<br>";
1556 finishPortlet();
1557 echo "</td>";
1558
1559 // Middle portlet with comment and submit.
1560 echo "<td class=pcleft>";
1561 startPortlet ('Comment');
1562 echo "<textarea name=comment rows=10 cols=40></textarea><br>\n";
1563 echo "<input type=submit value='Save' name=got_atoms>\n";
1564 echo "<br>";
1565 echo "<br>";
1566 finishPortlet();
1567 echo "</td>";
1568
1569 // Right portlet with rendered racks. If this form submit is not final, we have to
1570 // reflect the former state of the grid in current form.
1571 echo "<td class=pcright rowspan=2 height='1%'>";
1572 startPortlet ('Working copy');
1573 echo '<table border=0 cellspacing=10 align=center><tr>';
1574 foreach ($workingRacksData as $rack_id => $rackData)
1575 {
1576 // Order is important here: only original allocation is highlighted.
1577 highlightObject ($rackData, $object_id);
1578 markupAtomGrid ($rackData, 'T');
1579 // If we have a form processed, discard user input and show new database
1580 // contents.
1581 if (!$is_submit and $is_update)
1582 mergeGridFormToRack ($rackData);
1583 echo "<td valign=top>";
1584 echo "<center>\n<h2>${rackData['name']}</h2>\n";
1585 echo "<table class=rack border=0 cellspacing=0 cellpadding=1>\n";
1586 echo "<tr><th width='10%'>&nbsp;</th><th width='20%'>Front</th>";
1587 echo "<th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n";
1588 renderAtomGrid ($rackData);
1589 echo "<tr><th width='10%'>&nbsp;</th><th width='20%'>Front</th>";
1590 echo "<th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n";
1591 echo "</table></center>\n";
1592 echo '</td>';
1593 }
1594 echo "</tr></table>";
1595 finishPortlet();
1596 echo "</td>\n";
1597
1598 echo "</form>\n";
1599 echo "</tr></table>\n";
1600}
1601
1602function renderMolecule ($mdata, $object_id)
1603{
1604 // sort data out
1605 $rackpack = array();
1606 global $loclist;
1607 foreach ($mdata as $rua)
1608 {
1609 $rack_id = $rua['rack_id'];
1610 $unit_no = $rua['unit_no'];
1611 $atom = $rua['atom'];
1612 if (!isset ($rackpack[$rack_id]))
1613 {
1614 $rackData = getRackData ($rack_id);
1615 for ($i = $rackData['height']; $i > 0; $i--)
1616 for ($locidx = 0; $locidx < 3; $locidx++)
1617 $rackData[$i][$locidx]['state'] = 'F';
1618 $rackpack[$rack_id] = $rackData;
1619 }
1620 $rackpack[$rack_id][$unit_no][$loclist[$atom]]['state'] = 'T';
1621 $rackpack[$rack_id][$unit_no][$loclist[$atom]]['object_id'] = $object_id;
1622 }
1623 // now we have some racks to render
1624 foreach ($rackpack as $rackData)
1625 {
1626 markAllSpans ($rackData);
1627 echo "<table class=molecule cellspacing=0>\n";
1628 echo "<caption>${rackData['name']}</caption>\n";
1629 echo "<tr><th width='10%'>&nbsp;</th><th width='20%'>Front</th><th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n";
1630 for ($i = $rackData['height']; $i > 0; $i--)
1631 {
1632 echo "<tr><th>$i</th>";
1633 for ($locidx = 0; $locidx < 3; $locidx++)
1634 {
1635 $state = $rackData[$i][$locidx]['state'];
1636 echo "<td class=state_${state}>&nbsp;</td>\n";
1637 }
1638 echo "</tr>\n";
1639 }
1640 echo "</table>\n";
1641 }
1642}
1643
1644function renderUnmountedObjectsPortlet ()
1645{
1646 startPortlet ('Unmounted objects');
1647 $objs = getUnmountedObjects();
1648 if ($objs === NULL)
1649 {
1650 showError ('getUnmountedObjects() failed', __FUNCTION__);
1651 return;
1652 }
1653 global $root, $nextorder;
1654 $order = 'odd';
1655 echo '<br><br><table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
1656 echo '<tr><th>Common name</th><th>Visible label</th><th>Asset number</th><th>Barcode</th></tr>';
1657 foreach ($objs as $obj)
1658 {
1659 echo "<tr class=row_${order}><td><a href='${root}?page=object&object_id=${obj['id']}'>${obj['dname']}</a></td>";
1660 echo "<td>${obj['label']}</td>";
1661 echo "<td>${obj['asset_no']}</td>";
1662 echo "<td>${obj['barcode']}</td></tr>";
1663 $order = $nextorder[$order];
1664 }
1665 echo "</table><br>\n";
1666 finishPortlet();
1667}
1668
1669function renderProblematicObjectsPortlet ()
1670{
1671 startPortlet ('Problematic objects');
1672 $objs = getProblematicObjects();
1673 if ($objs === NULL)
1674 {
1675 showError ('getProblematicObjects() failed', __FUNCTION__);
1676 return;
1677 }
1678 global $root, $nextorder;
1679 $order = 'odd';
1680 echo '<br><br><table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
1681 echo '<tr><th>Type</th><th>Common name</th></tr>';
1682 foreach ($objs as $obj)
1683 {
1684 echo "<tr class=row_${order}><td>${obj['objtype_name']}</td>";
1685 echo "<td><a href='${root}?page=object&object_id=${obj['id']}'>${obj['dname']}</a></tr>";
1686 $order = $nextorder[$order];
1687 }
1688 echo "</table><br>\n";
1689 finishPortlet();
1690}
1691
1692function renderObjectSpace ()
1693{
1694 global $root, $taglist, $tagtree;
1695 echo "<table border=0 class=objectview>\n";
1696 echo "<tr><td class=pcleft width='50%'>";
1697 startPortlet ('View all by type');
1698 $groupInfo = getObjectGroupInfo();
1699 if ($groupInfo === NULL)
1700 {
1701 showError ('getObjectGroupInfo() failed', __FUNCTION__);
1702 return;
1703 }
1704 if (count ($groupInfo) == 0)
1705 echo "No objects exist in DB";
1706 else
1707 {
1708 echo '<div align=left><ul>';
1709 foreach ($groupInfo as $gi)
1710 echo "<li><a href='${root}?page=objgroup&group_id=${gi['id']}'>${gi['name']}</a> (${gi['count']})</li>";
1711 echo '</ul></div>';
1712 }
1713 finishPortlet();
1714
1715 echo '</td><td class=pcright>';
1716
1717 startPortlet ('View all by tag');
1718 if (count ($taglist) == 0)
1719 echo "No tags exist in DB";
1720 else
1721 renderTagCloud ('object');
1722 finishPortlet();
1723 echo "</td></tr></table>\n";
1724}
1725
1726function renderObjectGroup ()
1727{
1728 global $root, $pageno, $tabno, $nextorder, $taglist, $tagtree;
1729 assertUIntArg ('group_id', __FUNCTION__, TRUE);
1730 $group_id = $_REQUEST['group_id'];
1731 $tagfilter = getTagFilter();
1732 $tagfilter_str = getTagFilterStr ($tagfilter);
1733 echo "<table border=0 class=objectview>\n";
1734 echo "<tr><td class=pcleft width='25%'>";
1735 startPortlet ('change type');
1736 $groupInfo = getObjectGroupInfo();
1737 if ($groupInfo === NULL)
1738 {
1739 showError ('getObjectGroupInfo() failed', __FUNCTION__);
1740 return;
1741 }
1742 if (count ($groupInfo) == 0)
1743 echo "No objects exist in DB";
1744 else
1745 {
1746 echo '<div align=left><ul>';
1747 foreach ($groupInfo as $gi)
1748 {
1749 echo "<li><a href='${root}?page=${pageno}&group_id=${gi['id']}${tagfilter_str}'>";
1750 if ($gi['id'] == $group_id)
1751 echo '<strong>';
1752 echo "${gi['name']}</a>";
1753 if ($gi['id'] == $group_id)
1754 echo '</strong>';
1755 echo " (${gi['count']})";
1756 if ($gi['id'] == $group_id)
1757 echo ' &larr;';
1758 echo "</li>";
1759 }
1760 echo '</ul></div>';
1761 }
1762 finishPortlet();
1763
1764 echo '</td><td class=pcleft>';
1765
1766 startPortlet ('Objects');
1767 $objects = getObjectList ($group_id, $tagfilter, getTFMode());
1768 if ($objects === NULL)
1769 {
1770 showError ('getObjectList() failed', __FUNCTION__);
1771 return;
1772 }
1773 echo '<br><br><table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
1774 echo '<tr><th>Common name</th><th>Visible label</th><th>Asset tag</th><th>Barcode</th><th>Rack</th></tr>';
1775 $order = 'odd';
1776 foreach ($objects as $obj)
1777 {
1778 if (isset ($_REQUEST['hl_object_id']) and $_REQUEST['hl_object_id'] == $obj['id'])
1779 $secondclass = 'tdleft port_highlight';
1780 else
1781 $secondclass = 'tdleft';
1782 echo "<tr class=row_${order}><td class='${secondclass}'><a href='${root}?page=object&object_id=${obj['id']}'>${obj['dname']}</a></td>";
1783 echo "<td class='${secondclass}'>${obj['label']}</td>";
1784 echo "<td class='${secondclass}'>${obj['asset_no']}</td>";
1785 echo "<td class='${secondclass}'>${obj['barcode']}</td>";
1786 if ($obj['rack_id'])
1787 echo "<td class='${secondclass}'><a href='${root}?page=rack&rack_id=${obj['rack_id']}'>${obj['Rack_name']}</a></td>";
1788 else
1789 echo "<td class='${secondclass}'>Unmounted</td>";
1790 echo '</tr>';
1791 $order = $nextorder[$order];
1792 }
1793 echo '</table>';
1794 finishPortlet();
1795
1796 echo "</td><td class=pcright width='25%'>";
1797
1798 renderTagFilterPortlet ($tagfilter, 'object', 'group_id', $group_id);
1799 echo "</td></tr></table>\n";
1800}
1801
1802function renderEmptyPortsSelect ($port_id, $type_id)
1803{
1804 $ports = getEmptyPortsOfType($type_id);
1805 usort($ports, 'sortEmptyPorts');
1806 foreach ($ports as $port)
1807 {
1808 if ($port_id == $port['Port_id'])
1809 continue;
1810 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";
1811 }
1812}
1813
1814function renderAllIPv4Allocations ()
1815{
1816 $addresses = getAllIPv4Allocations();
1817 usort($addresses, 'sortObjectAddressesAndNames');
1818 foreach ($addresses as $address)
1819 {
1820 echo "<option value='${address['ip']}' onclick='getElementById(\"ip\").value=\"${address['ip']}\";'>${address['object_name']} ${address['name']} ${address['ip']}</option>\n";
1821 }
1822}
1823
1824// History viewer for history-enabled simple dictionaries.
1825function renderHistory ($object_type, $object_id)
1826{
1827 switch ($object_type)
1828 {
1829 case 'row':
1830 $query = "select ctime, user_name, name, deleted, comment from RackRowHistory where id = ${object_id} order by ctime";
1831 $header = '<tr><th>change time</th><th>author</th><th>rack row name</th><th>is deleted?</th><th>rack row comment</th></tr>';
1832 $extra = 4;
1833 break;
1834 case 'rack':
1835 $query =
1836 "select ctime, user_name, rh.name, rh.deleted, d.dict_value as name, rh.height, rh.comment " .
1837 "from RackHistory as rh left join Dictionary as d on rh.row_id = d.dict_key " .
1838 "natural join Chapter " .
1839 "where chapter_name = 'RackRow' and rh.id = ${object_id} order by ctime";
1840 $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>';
1841 $extra = 6;
1842 break;
1843 case 'object':
1844 $query =
1845 "select ctime, user_name, name, label, barcode, asset_no, deleted, has_problems, dict_value, comment " .
1846 "from RackObjectHistory inner join Dictionary on objtype_id = dict_key natural join Chapter " .
1847 "where chapter_name = 'RackObjectType' and id=${object_id} order by ctime";
1848 $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>';
1849 $extra = 9;
1850 break;
1851 default:
1852 showError ("Uknown object type '${object_type}'", __FUNCTION__);
1853 return;
1854 }
1855 global $dbxlink;
1856 $result = $dbxlink->query ($query);
1857 if ($result == NULL)
1858 {
1859 showError ('SQL query failed', __FUNCTION__);
1860 return;
1861 }
1862 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
1863 $order = 'odd';
1864 global $nextorder;
1865 echo $header;
1866 while ($row = $result->fetch (PDO::FETCH_NUM))
1867 {
1868 echo "<tr class=row_${order}><td>${row[0]}</td>";
1869 for ($i = 1; $i <= $extra; $i++)
1870 echo "<td>" . $row[$i] . "</td>";
1871 echo "</tr>\n";
1872 $order = $nextorder[$order];
1873 }
1874 echo "</table><br>\n";
1875}
1876
1877function renderRackspaceHistory ()
1878{
1879 global $root, $nextorder, $pageno, $tabno;
1880 $order = 'odd';
1881 $history = getRackspaceHistory();
1882 // Show the last operation by default.
1883 if (isset ($_REQUEST['op_id']))
1884 $op_id = $_REQUEST['op_id'];
1885 elseif (isset ($history[0]['mo_id']))
1886 $op_id = $history[0]['mo_id'];
1887 else $op_id = NULL;
1888
1889 $omid = NULL;
1890 $nmid = NULL;
1891 $object_id = 1;
1892 if ($op_id)
1893 list ($omid, $nmid) = getOperationMolecules ($op_id);
1894
1895 // Main layout starts.
1896 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
1897
1898 // Left top portlet with old allocation.
1899 echo "<tr><td class=pcleft>";
1900 startPortlet ('Old allocation');
1901 if ($omid)
1902 {
1903 $oldMolecule = getMolecule ($omid);
1904 renderMolecule ($oldMolecule, $object_id);
1905 }
1906 else
1907 echo "nothing";
1908 finishPortlet();
1909
1910 echo '</td><td class=pcright>';
1911
1912 // Right top portlet with new allocation
1913 startPortlet ('New allocation');
1914 if ($nmid)
1915 {
1916 $newMolecule = getMolecule ($nmid);
1917 renderMolecule ($newMolecule, $object_id);
1918 }
1919 else
1920 echo "nothing";
1921 finishPortlet();
1922
1923 echo '</td></tr><tr><td colspan=2>';
1924
1925 // Bottom portlet with list
1926
1927 startPortlet ('Rackspace allocation history');
1928 echo "<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>\n";
1929 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";
1930 foreach ($history as $row)
1931 {
1932 if ($row['mo_id'] == $op_id)
1933 $class = 'hl';
1934 else
1935 $class = "row_${order}";
1936 echo "<tr class=${class}><td><a href='${root}?page=${pageno}&tab=${tabno}&op_id=${row['mo_id']}'>${row['ctime']}</a></td>";
1937 echo "<td>${row['user_name']}</td>";
1938 echo "<td>${row['ro_id']}</td><td>${row['objtype_name']}</td><td>${row['name']}</td><td>${row['comment']}</td>\n";
1939 echo "</tr>\n";
1940 $order = $nextorder[$order];
1941 }
1942 echo "</table>\n";
1943 finishPortlet();
1944
1945 echo '</td></tr></table>';
1946
1947}
1948
1949function renderIPv4Space ()
1950{
1951 global $root, $pageno;
1952
1953 echo "<table border=0 class=objectview>\n";
1954 echo "<tr><td class=pcleft>";
1955
1956 $tagfilter = getTagFilter();
1957 $addrspaceList = getAddressspaceList ($tagfilter, getTFMode());
1958 $tagcache = array();
1959 startPortlet ('networks (' . count ($addrspaceList) . ')');
1960 echo "<table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
1961 echo "<tr><th>prefix</th><th>name/tags</th><th>%% used</th>";
1962 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
1963 echo "<th>routed by</th>";
1964 echo "</tr>\n";
1965 foreach ($addrspaceList as $iprange)
1966 {
1967 $netdata = getIPv4Network ($iprange['id']);
1968 $total = ($netdata['ip_bin'] | $netdata['mask_bin_inv']) - ($netdata['ip_bin'] & $netdata['mask_bin']) + 1;
1969 $used = count ($netdata['addrlist']);
1970 echo "<tr valign=top>";
1971 printIPv4NetInfoTDs ($netdata);
1972 echo "<td class=tdcenter>";
1973 renderProgressBar ($used/$total);
1974 echo "<br><small>${used}/${total}</small></td>";
1975 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes')
1976 printRoutersTD (findRouters ($netdata['addrlist']), $tagcache);
1977 echo "</tr>";
1978 }
1979 echo "</table>\n";
1980 finishPortlet();
1981 echo '</td><td class=pcright>';
1982 renderTagFilterPortlet ($tagfilter, 'ipv4net');
1983 echo "</td></tr></table>\n";
1984}
1985
1986function renderIPv4SLB ()
1987{
1988 global $root, $page, $nextorder;
1989
1990 startPortlet ('SLB configuration');
1991 echo "<table border=0 width='100%'><tr>";
1992 foreach (array ('ipv4vslist', 'ipv4rsplist', 'rservers', 'lbs') as $pno)
1993 echo "<td><h3><a href='${root}?page=${pno}'>" . $page[$pno]['title'] . "</a></h3></td>";
1994 echo '</tr></table>';
1995 finishPortlet();
1996
1997 $summary = getSLBSummary();
1998 startPortlet ('SLB tactical overview');
1999 // A single id-keyed array isn't used here to preserve existing
2000 // order of LBs returned by getSLBSummary()
2001 $lblist = array();
2002 $lbdname = array();
2003 foreach ($summary as $vipdata)
2004 foreach (array_keys ($vipdata['lblist']) as $lb_object_id)
2005 if (!in_array ($lb_object_id, $lblist))
2006 {
2007 $oi = getObjectInfo ($lb_object_id);
2008 $lbdname[$lb_object_id] = $oi['dname'];
2009 $lblist[] = $lb_object_id;
2010 }
2011 if (!count ($summary))
2012 echo 'none configured';
2013 else
2014 {
2015 $order = 'odd';
2016 echo "<table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
2017 echo "<tr><th>VS&nbsp;&darr; LB&nbsp;&rarr;</th>";
2018 foreach ($lblist as $lb_object_id)
2019 echo "<th><a href='${root}?page=object&tab=default&object_id=${lb_object_id}'>" . $lbdname[$lb_object_id] . "</a></th>";
2020 echo "</tr>\n";
2021 foreach ($summary as $vsid => $vsdata)
2022 {
2023 echo "<tr class=row_${order}><td class=tdleft><a href='$root?page=ipv4vs&tab=default&vs_id=${vsid}'>";
2024 echo buildVServiceName ($vsdata);
2025 echo '</a>';
2026 if (!empty ($vsdata['name']))
2027 echo "<br>${vsdata['name']}";
2028 echo "</td>";
2029 foreach ($lblist as $lb_object_id)
2030 {
2031 echo '<td class=tdleft>';
2032 if (!isset ($vsdata['lblist'][$lb_object_id]))
2033 echo '&nbsp;';
2034 else
2035 {
2036 echo $vsdata['lblist'][$lb_object_id]['size'];
2037// echo " (<a href='${root}?page=ipv4rsp&pool_id=";
2038// echo $vsdata['lblist'][$lb_object_id]['id'] . "'>";
2039// echo $vsdata['lblist'][$lb_object_id]['name'] . '</a>)';
2040 }
2041 echo '</td>';
2042 }
2043 echo "</tr>\n";
2044 $order = $nextorder[$order];
2045 }
2046 echo "</table>\n";
2047 }
2048 finishPortlet ();
2049}
2050
2051function renderIPv4SpaceEditor ()
2052{
2053 global $root, $pageno, $tabno;
2054 showMessageOrError();
2055
2056 // IPv4 validator
2057?>
2058 <script type="text/javascript">
2059 function init() {
2060 document.add_new_range.range.setAttribute('match', "^\\d\\d?\\d?\\.\\d\\d?\\d?\\.\\d\\d?\\d?\\.\\d\\d?\\d?\\/\\d\\d?$");
2061
2062 Validate.init();
2063 }
2064 window.onload=init;
2065 </script>
2066<?php
2067
2068 startPortlet ("Add new");
2069 echo '<table border=0 cellpadding=10 align=center>';
2070 // This form requires a name, so JavaScript validator can find it.
2071 // No printOpFormIntro() hence
2072 echo "<form method=post name='add_new_range' action='${root}process.php'>\n";
2073 echo "<input type=hidden name=op value=addIPv4Prefix>\n";
2074 echo "<input type=hidden name=page value='${pageno}'>\n";
2075 echo "<input type=hidden name=tab value='${tabno}'>\n";
2076 // tags column
2077 echo '<tr><td rowspan=4><h3>assign tags</h3>';
2078 renderTagSelect();
2079 echo '</td>';
2080 // inputs column
2081 echo "<th class=tdright>prefix</th><td class=tdleft><input type=text name='range' size=18 class='live-validate' tabindex=1></td>";
2082 echo "<tr><th class=tdright>name</th><td class=tdleft><input type=text name='name' size='20' tabindex=2></td></tr>";
2083 echo "<tr><th class=tdright>connected network</th><td class=tdleft><input type=checkbox name='is_bcast' tabindex=3 checked></td></tr>";
2084 echo "<tr><td colspan=2>";
2085 printImageHREF ('CREATE', 'Add a new network', TRUE, 4);
2086 echo '</td></tr>';
2087 echo "</form></table><br><br>\n";
2088 finishPortlet();
2089
2090 $addrspaceList = getAddressspaceList();
2091 if (count ($addrspaceList))
2092 {
2093 startPortlet ('Manage existing (' . count ($addrspaceList) . ')');
2094 echo "<table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n";
2095 echo "<tr><th>&nbsp;</th><th>prefix</th><th>name</th><th>&nbsp;</th></tr>";
2096 foreach ($addrspaceList as $iprange)
2097 {
2098 $netdata = getIPv4Network ($iprange['id']);
2099 $usedips = count ($netdata['addrlist']);
2100 $totalips = ($netdata['ip_bin'] | $netdata['mask_bin_inv']) - ($netdata['ip_bin'] & $netdata['mask_bin']) + 1;
2101 echo "<form method=post action='${root}process.php?page=${pageno}&tab=${tabno}&op=updIPv4Prefix&id=${iprange['id']}'>";
2102 echo '<tr valign=top><td>';
2103 if ($usedips == 0)
2104 {
2105 echo "<a href='${root}process.php?op=delIPv4Prefix&page=${pageno}&tab=${tabno}&id=${iprange['id']}'>";
2106 printImageHREF ('delete', 'Delete this IP range');
2107 echo "</a>";
2108 }
2109 else
2110 printImageHREF ('nodelete', 'There are IP addresses allocated or reserved');
2111 echo "</td>\n<td class=tdleft>${netdata['ip']}/${netdata['mask']}</td>";
2112 echo "<td><input type=text name=name size=40 value='${netdata['name']}'>";
2113 echo "</td><td>";
2114 printImageHREF ('save', 'Save changes', TRUE);
2115 echo "</td></tr></form>\n";
2116 }
2117 echo "</table>";
2118 finishPortlet();
2119 }
2120}
2121
2122function renderIPv4Network ($id)
2123{
2124 global $root, $pageno, $tabno, $aac2;
2125 $netmaskbylen = array
2126 (
2127 32 => '255.255.255.255',
2128 31 => '255.255.255.254',
2129 30 => '255.255.255.252',
2130 29 => '255.255.255.248',
2131 28 => '255.255.255.240',
2132 27 => '255.255.255.224',
2133 26 => '255.255.255.192',
2134 25 => '255.255.255.128',
2135 24 => '255.255.255.0',
2136 23 => '255.255.254.0',
2137 22 => '255.255.252.0',
2138 21 => '255.255.248.0',
2139 20 => '255.255.240.0',
2140 19 => '255.255.224.0',
2141 18 => '255.255.192.0',
2142 17 => '255.255.128.0',
2143 16 => '255.255.0.0',
2144 15 => '255.254.0.0',
2145 14 => '255.252.0.0',
2146 13 => '255.248.0.0',
2147 12 => '255.240.0.0',
2148 11 => '255.224.0.0',
2149 10 => '255.192.0.0',
2150 9 => '255.128.0.0',
2151 8 => '255.0.0.0',
2152 7 => '254.0.0.0',
2153 6 => '252.0.0.0',
2154 5 => '248.0.0.0',
2155 4 => '240.0.0.0',
2156 3 => '224.0.0.0',
2157 2 => '192.0.0.0',
2158 1 => '128.0.0.0'
2159 );
2160 $wildcardbylen = array
2161 (
2162 32 => '0.0.0.0',
2163 31 => '0.0.0.1',
2164 30 => '0.0.0.3',
2165 29 => '0.0.0.7',
2166 28 => '0.0.0.15',
2167 27 => '0.0.0.31',
2168 26 => '0.0.0.63',
2169 25 => '0.0.0.127',
2170 24 => '0.0.0.255',
2171 23 => '0.0.1.255',
2172 22 => '0.0.3.255',
2173 21 => '0.0.7.255',
2174 20 => '0.0.15.255',
2175 19 => '0.0.31.255',
2176 18 => '0.0.63.255',
2177 17 => '0.0.127.255',
2178 16 => '0.0.255.25',
2179 15 => '0.1.255.255',
2180 14 => '0.3.255.255',
2181 13 => '0.7.255.255',
2182 12 => '0.15.255.255',
2183 11 => '0.31.255.255',
2184 10 => '0.63.255.255',
2185 9 => '0.127.255.255',
2186 8 => '0.255.255.255',
2187 7 => '1.255.255.255',
2188 6 => '3.255.255.255',
2189 5 => '7.255.255.255',
2190 4 => '15.255.255.255',
2191 3 => '31.255.255.255',
2192 2 => '63.255.255.255',
2193 1 => '127.255.255.255'
2194 );
2195 $maxperpage = getConfigVar ('IPV4_ADDRS_PER_PAGE');
2196 if (isset($_REQUEST['pg']))
2197 $page = $_REQUEST['pg'];
2198 else
2199 $page=0;
2200
2201 $range = getIPv4Network ($id);
2202 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
2203 echo "<tr><td colspan=2 align=center><h1>${range['ip']}/${range['mask']}</h1><h2>${range['name']}</h2></td></tr>\n";
2204
2205 echo "<tr><td class=pcleft width='50%'>";
2206 startPortlet ('summary');
2207 $total = ($range['ip_bin'] | $range['mask_bin_inv']) - ($range['ip_bin'] & $range['mask_bin']) + 1;
2208 $used = count ($range['addrlist']);
2209 echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
2210
2211 echo "<tr><th width='50%' class=tdright>%% used:</th><td class=tdleft>";
2212 renderProgressBar ($used/$total);
2213 echo "&nbsp;${used}/${total}</td></tr>\n";
2214
2215 echo "<tr><th width='50%' class=tdright>Netmask:</th><td class=tdleft>";
2216 echo $netmaskbylen[$range['mask']];
2217 echo "</td></tr>\n";
2218
2219 echo "<tr><th width='50%' class=tdright>Wildcard bits:</th><td class=tdleft>";
2220 echo $wildcardbylen[$range['mask']];
2221 echo "</td></tr>\n";
2222
2223 $routers = findRouters ($range['addrlist']);
2224 if (getConfigVar ('EXT_IPV4_VIEW') == 'yes' and count ($routers))
2225 {
2226 echo "<tr><th width='50%' class=tdright>Routed by:</th>";
2227 printRoutersTD ($routers);
2228 echo "</tr>\n";
2229 }
2230
2231 printTagTRs ("${root}?page=ipv4space&");
2232 echo "</table><br>\n";
2233 finishPortlet();
2234 echo "</td>\n";
2235
2236 echo "<td class=pcright>";
2237 startPortlet ('details');
2238 $startip = $range['ip_bin'] & $range['mask_bin'];
2239 $endip = $range['ip_bin'] | $range['mask_bin_inv'];
2240 $realstartip = $startip;
2241 $realendip = $endip;
2242 $numpages = 0;
2243 if($endip - $startip > $maxperpage)
2244 {
2245 $numpages = ($endip - $startip)/$maxperpage;
2246 $startip = $startip + $page * $maxperpage;
2247 $endip = $startip + $maxperpage-1;
2248 }
2249 echo "<center>";
2250 if ($numpages)
2251 echo '<h3>' . long2ip ($startip) . ' ~ ' . long2ip ($endip) . '</h3>';
2252 for ($i=0; $i<$numpages; $i++)
2253 {
2254 if ($i == $page)
2255 echo "<b>$i</b> ";
2256 else
2257 echo "<a href='${root}?page=${pageno}&tab=${tabno}&id=$id&pg=$i'>$i</a> ";
2258 }
2259 echo "</center>";
2260
2261 echo "<table class='widetable' border=0 cellspacing=0 cellpadding=5 align='center' width='100%'>\n";
2262 echo "<tr><th>Address</th><th>Name</th><th>Allocation</th></tr>\n";
2263
2264
2265 for ($ip = $startip; $ip <= $endip; $ip++) :
2266 if (isset ($_REQUEST['hl_ipv4_addr']) and ip2long ($_REQUEST['hl_ipv4_addr']) == $ip)
2267 $secondstyle = 'tdleft port_highlight';
2268 else
2269 $secondstyle = 'tdleft';
2270 if (!isset ($range['addrlist'][$ip]))
2271 {
2272 echo "<tr><td class=tdleft><a href='${root}?page=ipaddress&ip=" . long2ip ($ip) . "'>" . long2ip ($ip);
2273 echo "</a></td><td class='${secondstyle}'>&nbsp;</td><td class='${secondstyle}'>&nbsp;</td></tr>\n";
2274 continue;
2275 }
2276 $addr = $range['addrlist'][$ip];
2277 echo "<tr class='${addr['class']}'>";
2278
2279 echo "<td class=tdleft><a href='${root}?page=ipaddress&ip=${addr['ip']}'>${addr['ip']}</a></td>";
2280 echo "<td class='${secondstyle}'>${addr['name']}</td><td class='${secondstyle}'>";
2281 $delim = '';
2282 $prologue = '';
2283 if ( $addr['reserved'] == 'yes')
2284 {
2285 echo "<strong>RESERVED</strong> ";
2286 $delim = '; ';
2287 }
2288 foreach ($range['addrlist'][$ip]['allocs'] as $ref)
2289 {
2290 echo $delim . $aac2[$ref['type']];
2291 echo "<a href='${root}?page=object&object_id=${ref['object_id']}";
2292 echo "&hl_ipv4_addr=${addr['ip']}'>";
2293 echo $ref['name'] . (empty ($ref['name']) ? '' : '@');
2294 echo "${ref['object_name']}</a>";
2295 $delim = '; ';
2296 }
2297 if ($delim != '')
2298 {
2299 $delim = '';
2300 $prologue = '<br>';
2301 }
2302 foreach ($range['addrlist'][$ip]['lblist'] as $ref)
2303 {
2304 echo $prologue;
2305 $prologue = '';
2306 echo "${delim}<a href='${root}?page=object&object_id=${ref['object_id']}'>";
2307 echo "${ref['object_name']}</a>:<a href='${root}?page=ipv4vs&vs_id=${ref['vs_id']}'>";
2308 echo "${ref['vport']}/${ref['proto']}</a>&rarr;";
2309 $delim = '; ';
2310 }
2311 if ($delim != '')
2312 {
2313 $delim = '';
2314 $prologue = '<br>';
2315 }
2316 foreach ($range['addrlist'][$ip]['rslist'] as $ref)
2317 {
2318 echo $prologue;
2319 $prologue = '';
2320 echo "${delim}&rarr;${ref['rsport']}@<a href='${root}?page=ipv4rsp&pool_id=${ref['rspool_id']}'>";
2321 echo "${ref['rspool_name']}</a>";
2322 $delim = '; ';
2323 }
2324 echo "</td></tr>\n";
2325 endfor;
2326 // end of iteration
2327
2328 echo "</table>";
2329 finishPortlet();
2330 echo "</td></tr></table>\n";
2331}
2332
2333function renderIPv4NetworkProperties ($id)
2334{
2335 showMessageOrError();
2336 $netdata = getIPv4NetworkInfo ($id);
2337 echo "<center><h1>${netdata['ip']}/${netdata['mask']}</h1></center>\n";
2338 echo "<table border=0 cellpadding=10 cellpadding=1 align='center'>\n";
2339 printOpFormIntro ('editRange');
2340 echo "<tr><td class='tdright'>Name:</td><td class='tdleft'><input type=text name=name size=20 value='${netdata['name']}'></tr>";
2341 echo "<tr><td colspan=2 class=tdcenter>";
2342 printImageHREF ('SAVE', 'Save changes', TRUE);
2343 echo "</td></form></tr></table>\n";
2344
2345}
2346
2347function renderIPv4Address ($dottedquad)
2348{
2349 global $root, $aat;
2350 $address = getIPv4Address ($dottedquad);
2351 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
2352 echo "<tr><td colspan=2 align=center><h1>${dottedquad}</h1></td></tr>\n";
2353 if (!empty ($address['name']))
2354 echo "<tr><td colspan=2 align=center><h2>${address['name']}</h2></td></tr>\n";
2355
2356 echo "<tr><td class=pcleft>";
2357 startPortlet ('summary');
2358 echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
2359 echo "<tr><th width='50%' class=tdright>Allocations:</th><td class=tdleft>" . count ($address['allocs']) . "</td></tr>\n";
2360 echo "<tr><th width='50%' class=tdright>Originated NAT connections:</th><td class=tdleft>" . count ($address['outpf']) . "</td></tr>\n";
2361 echo "<tr><th width='50%' class=tdright>Arriving NAT connections:</th><td class=tdleft>" . count ($address['inpf']) . "</td></tr>\n";
2362 echo "<tr><th width='50%' class=tdright>SLB virtual services:</th><td class=tdleft>" . count ($address['lblist']) . "</td></tr>\n";
2363 echo "<tr><th width='50%' class=tdright>SLB real servers:</th><td class=tdleft>" . count ($address['rslist']) . "</td></tr>\n";
2364 printTagTRs();
2365 echo "</table><br>\n";
2366 finishPortlet();
2367 echo "</td>\n";
2368
2369 echo "<td class=pcright>";
2370
2371 if (!empty ($address['class']))
2372 {
2373 startPortlet ('allocations');
2374 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center' width='100%'>\n";
2375 echo "<tr><th>object</th><th>OS interface</th><th>allocation type</th></tr>\n";
2376 $class = $address['class'];
2377 // render all allocation records for this address the same way
2378 if ($address['reserved'] == 'yes')
2379 echo "<tr class='${class}'><td colspan=2>&nbsp;</td><td class=tdleft><strong>RESERVED</strong></td></tr>";
2380 foreach ($address['allocs'] as $bond)
2381 {
2382 if (isset ($_REQUEST['hl_object_id']) and $_REQUEST['hl_object_id'] == $bond['object_id'])
2383 $secondclass = 'tdleft port_highlight';
2384 else
2385 $secondclass = 'tdleft';
2386 echo "<tr class='$class'><td class=tdleft><a href='${root}?page=object&object_id=${bond['object_id']}";
2387 echo "&hl_ipv4_addr=${dottedquad}'>${bond['object_name']}</td><td class='${secondclass}'>${bond['name']}</td><td class='${secondclass}'><strong>";
2388 echo $aat[$bond['type']];
2389 echo "</strong></td></tr>\n";
2390 }
2391 echo "</table><br><br>";
2392 finishPortlet();
2393 }
2394
2395 // FIXME: The returned list is structured differently, than we expect it to be. One of the sides
2396 // must be fixed.
2397 if (count ($address['lblist']))
2398 {
2399 startPortlet ('Virtual services (' . count ($address['lblist']) . ')');
2400 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center' width='100%'>\n";
2401 echo "<tr><th>VS</th><th>name</th></tr>\n";
2402 foreach ($address['lblist'] as $vsinfo)
2403 {
2404 echo "<tr><td class=tdleft><a href='${root}?page=ipv4vs&vs_id=${vsinfo['vs_id']}'>";
2405 echo buildVServiceName ($vsinfo) . "</a></td><td class=tdleft>";
2406 echo $vsinfo['name'] . "</td></tr>\n";
2407 }
2408 echo "</table><br><br>";
2409 finishPortlet();
2410 }
2411
2412 if (count ($address['rslist']))
2413 {
2414 startPortlet ('Real servers (' . count ($address['rslist']) . ')');
2415 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center' width='100%'>\n";
2416 echo "<tr><th>&nbsp;</th><th>port</th><th>RS pool</th></tr>\n";
2417 foreach ($address['rslist'] as $rsinfo)
2418 {
2419 echo "<tr><td>";
2420 if ($rsinfo['inservice'] == 'yes')
2421 printImageHREF ('inservice', 'in service');
2422 else
2423 printImageHREF ('notinservice', 'NOT in service');
2424 echo "</td><td class=tdleft>${rsinfo['rsport']}</td><td class=tdleft><a href='${root}?page=ipv4rsp&pool_id=${rsinfo['rspool_id']}'>";
2425 echo $rsinfo['rspool_name'] . "</a></td></tr>\n";
2426 }
2427 echo "</table><br><br>";
2428 finishPortlet();
2429 }
2430
2431 if (count ($address['outpf']))
2432 {
2433 startPortlet ('departing NAT rules');
2434 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center' width='100%'>\n";
2435 echo "<tr><th>proto</th><th>from</th><th>to</th><th>comment</th></tr>\n";
2436 foreach ($address['outpf'] as $rule)
2437 echo "<tr><td>${rule['proto']}</td><td>${rule['localip']}:${rule['localport']}</td><td>${rule['remoteip']}:${rule['remoteport']}</td><td>${rule['description']}</td></tr>";
2438 echo "</table>";
2439 finishPortlet();
2440 }
2441
2442 if (count ($address['inpf']))
2443 {
2444 startPortlet ('arriving NAT rules');
2445 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center' width='100%'>\n";
2446 echo "<tr><th>proto</th><th>from</th><th>to</th><th>comment</th></tr>\n";
2447 foreach ($address['inpf'] as $rule)
2448 echo "<tr><td>${rule['proto']}</td><td>${rule['localip']}:${rule['localport']}</td><td>${rule['remoteip']}:${rule['remoteport']}</td><td>${rule['description']}</td></tr>";
2449 echo "</table>";
2450 finishPortlet();
2451 }
2452
2453 echo "</td></tr>";
2454 echo "</table>\n";
2455}
2456
2457function renderIPv4AddressProperties ($dottedquad)
2458{
2459 showMessageOrError();
2460 $address = getIPv4Address ($dottedquad);
2461 echo "<center><h1>$dottedquad</h1></center>\n";
2462
2463 startPortlet ('update');
2464 echo "<table border=0 cellpadding=10 cellpadding=1 align='center'>\n";
2465 printOpFormIntro ('editAddress');
2466 echo "<tr><td class='tdright'>Name:</td><td class='tdleft'><input type=text name=name size=20 value='${address['name']}'></tr>";
2467 echo "<td class='tdright'>Reserved:</td><td class='tdleft'><input type=checkbox name=reserved size=20 ";
2468 echo ($address['reserved']=='yes') ? 'checked' : '';
2469 echo "></tr><tr><td colspan=2 class='tdcenter'>";
2470 printImageHREF ('SAVE', 'Save changes', TRUE);
2471 echo "</td></form></tr></table>\n";
2472 finishPortlet();
2473 if (empty ($address['name']) and $address['reserved'] == 'no')
2474 return;
2475
2476 startPortlet ('release');
2477 printOpFormIntro ('editAddress', array ('name' => '', 'reserved' => ''));
2478 echo "<input type=submit value='release'></form>";
2479 finishPortlet();
2480}
2481
2482function renderIPv4AddressAllocations ($dottedquad)
2483{
2484 showMessageOrError();
2485 global $pageno, $tabno, $root, $aat;
2486
2487 $address = getIPv4Address ($dottedquad);
2488 $class = $address['class'];
2489 echo "<center><h1>${dottedquad}</h1></center>\n";
2490 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
2491 echo "<tr><th>&nbsp;</th><th>object</th><th>OS interface</th><th>allocation type</th><th>&nbsp;</th></tr>\n";
2492
2493 if ($address['reserved'] == 'yes')
2494 echo "<tr class='${class}'><td colspan=3>&nbsp;</td><td class=tdleft><strong>RESERVED</strong></td><td>&nbsp;</td></tr>";
2495 foreach ($address['allocs'] as $bond)
2496 {
2497 echo "<tr class='$class'>";
2498 printOpFormIntro ('updIPv4Allocation', array ('object_id' => $bond['object_id']));
2499 echo "<td><a href='${root}process.php?op=delIPv4Allocation&page=${pageno}&tab=${tabno}&ip=${dottedquad}&object_id=${bond['object_id']}'>";
2500 printImageHREF ('delete', 'Unallocate address');
2501 echo "</a></td>";
2502 echo "<td><a href='${root}?page=object&object_id=${bond['object_id']}&hl_ipv4_addr=${dottedquad}'>${bond['object_name']}</td>";
2503 echo "<td><input type='text' name='bond_name' value='${bond['name']}' size=10></td><td>";
2504 printSelect ($aat, 'bond_type', $bond['type']);
2505 echo "</td><td>";
2506 printImageHREF ('save', 'Save changes', TRUE);
2507 echo "</td></form></tr>\n";
2508 }
2509 printOpFormIntro ('addIPv4Allocation');
2510 echo "<td>";
2511 printImageHREF ('add', 'new allocation', TRUE);
2512 echo "</td><td><select name='object_id'>";
2513
2514 foreach (explode (',', getConfigVar ('IPV4_PERFORMERS')) as $type)
2515 foreach (getNarrowObjectList ($type) as $object)
2516 echo "<option value='${object['id']}'>${object['dname']}</option>";
2517
2518 echo "</select></td><td><input type='text' name='bond_name' value='' size=10></td><td>";
2519 printSelect ($aat, 'bond_type');
2520 echo "</td><td>&nbsp;</td></form></tr>";
2521 echo "</table><br><br>";
2522
2523}
2524
2525function renderNATv4ForObject ($object_id = 0)
2526{
2527 global $pageno, $tabno, $root;
2528
2529 $info = getObjectInfo ($object_id);
2530 $forwards = getNATv4ForObject ($object_id);
2531 $alloclist = getObjectIPv4Allocations ($object_id);
2532 showMessageOrError();
2533 echo "<center><h2>locally performed NAT</h2></center>";
2534
2535 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
2536 echo "<tr><th></th><th>Match endpoint</th><th>Translate to</th><th>Target object</th><th>Comment</th><th>&nbsp;</th></tr>\n";
2537
2538 foreach ($forwards['out'] as $pf)
2539 {
2540 $class = 'trerror';
2541 $osif = '';
2542 if (isset ($alloclist [$pf['localip']]))
2543 {
2544 $class = $alloclist [$pf['localip']]['addrinfo']['class'];
2545 $osif = $alloclist [$pf['localip']]['osif'] . ': ';
2546 }
2547
2548 echo "<tr class='$class'>";
2549 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}'>";
2550 printImageHREF ('delete', 'Delete NAT rule');
2551 echo "</a></td>";
2552 echo "<td>${pf['proto']}/${osif}<a href='${root}?page=ipaddress&tab=default&ip=${pf['localip']}'>${pf['localip']}</a>:${pf['localport']}";
2553 if (!empty ($pf['local_addr_name']))
2554 echo ' (' . $pf['local_addr_name'] . ')';
2555 echo "</td>";
2556 echo "<td><a href='${root}?page=ipaddress&tab=default&ip=${pf['remoteip']}'>${pf['remoteip']}</a>:${pf['remoteport']}</td>";
2557
2558 $address = getIPv4Address ($pf['remoteip']);
2559
2560 echo "<td class='description'>";
2561 if (count ($address['allocs']))
2562 foreach ($address['allocs'] as $bond)
2563 echo "<a href='${root}?page=object&tab=default&object_id=${bond['object_id']}'>${bond['object_name']}(${bond['name']})</a> ";
2564 elseif (!empty ($pf['remote_addr_name']))
2565 echo '(' . $pf['remote_addr_name'] . ')';
2566 printOpFormIntro
2567 (
2568 'updNATv4Rule',
2569 array
2570 (
2571 'localip' => $pf['localip'],
2572 'localport' => $pf['localport'],
2573 'remoteip' => $pf['remoteip'],
2574 'remoteport' => $pf['remoteport'],
2575 'proto' => $pf['proto']
2576 )
2577 );
2578 echo "</td><td class='description'>";
2579 echo "<input type='text' name='description' value='${pf['description']}'></td><td>";
2580 printImageHREF ('save', 'Save changes', TRUE);
2581 echo "</td></form></tr>";
2582 }
2583 printOpFormIntro ('addNATv4Rule');
2584 echo "<tr align='center'><td>";
2585 printImageHREF ('add', 'Add new NAT rule', TRUE);
2586 echo '</td><td>';
2587 printSelect (array ('TCP' => 'TCP', 'UDP' => 'UDP'), 'proto');
2588 echo "<select name='localip' tabindex=1>";
2589
2590 foreach ($alloclist as $dottedquad => $alloc)
2591 {
2592 $name = empty ($alloc['addrinfo']['name']) ? '' : (' (' . niftyString ($alloc['addrinfo']['name']) . ')');
2593 $osif = empty ($alloc['osif']) ? '' : ($alloc['osif'] . ': ');
2594 echo "<option value='${dottedquad}'>${osif}${dottedquad}${name}</option>";
2595 }
2596
2597 echo "</select>:<input type='text' name='localport' size='4' tabindex=2></td>";
2598 echo "<td><input type='text' name='remoteip' id='remoteip' size='10' tabindex=3>";
2599 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\");'>";
2600 printImageHREF ('find', 'Find object');
2601 echo "</a>";
2602 echo ":<input type='text' name='remoteport' size='4' tabindex=4></td><td></td>";
2603 echo "<td colspan=1><input type='text' name='description' size='20' tabindex=5></td><td>&nbsp;</td></tr>";
2604 echo "</form>";
2605
2606 echo "</table><br><br>";
2607
2608 echo "<center><h2>arriving NAT connections</h2></center>";
2609 echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n";
2610 echo "<tr><th></th><th>Source</th><th>Source objects</th><th>Target</th><th>Description</th></tr>\n";
2611
2612 foreach ($forwards['in'] as $pf)
2613 {
2614 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}'>";
2615 printImageHREF ('delete', 'Delete NAT rule');
2616 echo "</a></td>";
2617 echo "<td>${pf['proto']}/<a href='${root}?page=ipaddress&tab=default&ip=${pf['localip']}'>${pf['localip']}</a>:${pf['localport']}</td>";
2618 echo "<td class='description'><a href='${root}?page=object&tab=default&object_id=${pf['object_id']}'>${pf['object_name']}</a>";
2619 echo "</td><td><a href='${root}?page=ipaddress&tab=default&ip=${pf['remoteip']}'>${pf['remoteip']}</a>:${pf['remoteport']}</td>";
2620 echo "<td class='description'>${pf['description']}</td></tr>";
2621 }
2622
2623 echo "</table><br><br>";
2624}
2625
2626// FIXME: move related code away into ophandler(s)
2627function renderAddMultipleObjectsForm ()
2628{
2629 global $root, $pageno, $tabno, $nextorder;
2630
2631 $type_id = array();
2632 $global_type_id = 0;
2633 $name = array();
2634 $asset_no = array();
2635 $keepvalues1 = $keepvalues2 = FALSE;
2636 $log = array();
2637 // Look for current submit.
2638 if (isset ($_REQUEST['got_fast_data']))
2639 {
2640 $taglist = isset ($_REQUEST['taglist']) ? $_REQUEST['taglist'] : array();
2641 $keepvalues1 = TRUE;
2642 $max = getConfigVar ('MASSCOUNT');
2643 for ($i = 0; $i < $max; $i++)
2644 {
2645 if (!isset ($_REQUEST["${i}_object_type_id"]))
2646 {
2647 $log[] = array ('code' => 'error', 'message' => "Submitted form is invalid at line " . $i + 1);
2648 break;
2649 }
2650 assertUIntArg ("${i}_object_type_id", __FUNCTION__, TRUE);
2651 assertStringArg ("${i}_object_name", __FUNCTION__, TRUE);
2652 assertStringArg ("${i}_object_label", __FUNCTION__, TRUE);
2653 assertStringArg ("${i}_object_asset_no", __FUNCTION__, TRUE);
2654 assertStringArg ("${i}_object_barcode", __FUNCTION__, TRUE);
2655 $type_id[$i] = $_REQUEST["${i}_object_type_id"];
2656 // Save user input for possible rendering.
2657 $name[$i] = $_REQUEST["${i}_object_name"];
2658 $label[$i] = $_REQUEST["${i}_object_label"];
2659 $asset_no[$i] = $_REQUEST["${i}_object_asset_no"];
2660 $barcode[$i] = $_REQUEST["${i}_object_barcode"];
2661
2662 // It's better to skip silently, than to print a notice.
2663 if ($type_id[$i] == 0)
2664 continue;
2665 if (commitAddObject ($name[$i], $label[$i], $barcode[$i], $type_id[$i], $asset_no[$i], $taglist) === TRUE)
2666 $log[] = array ('code' => 'success', 'message' => "Added new object '${name[$i]}'");
2667 else
2668 $log[] = array ('code' => 'error', 'message' => __FUNCTION__ . ': commitAddObject() failed');
2669 }
2670 }
2671 elseif (isset ($_REQUEST['got_very_fast_data']))
2672 {
2673 $taglist = isset ($_REQUEST['taglist']) ? $_REQUEST['taglist'] : array();
2674 $keepvalues2 = TRUE;
2675 assertUIntArg ('global_type_id', __FUNCTION__, TRUE);
2676 assertStringArg ('namelist', __FUNCTION__, TRUE);
2677 $global_type_id = $_REQUEST['global_type_id'];
2678 if ($global_type_id == 0)
2679 {
2680 if (!empty ($_REQUEST['namelist']))
2681 $log[] = array ('code' => 'error', 'message' => 'Object type is not selected, check the form below');
2682 else
2683 $log[] = array ('code' => 'error', 'message' => 'Empty form has been ignored. Cheers.');
2684 }
2685 else
2686 {
2687 // The name extractor below was stolen from ophandlers.php:addMultiPorts()
2688 $names1 = explode ('\n', $_REQUEST['namelist']);
2689 $names2 = array();
2690 foreach ($names1 as $line)
2691 {
2692 $parts = explode ('\r', $line);
2693 reset ($parts);
2694 if (empty ($parts[0]))
2695 continue;
2696 else
2697 $names2[] = rtrim ($parts[0]);
2698 }
2699 foreach ($names2 as $cname)
2700 if (commitAddObject ($cname, '', '', $global_type_id, '', $taglist) === TRUE)
2701 $log[] = array ('code' => 'success', 'message' => "Added new object '${cname}'");
2702 else
2703 $log[] = array ('code' => 'error', 'message' => "Could not add '${cname}'");
2704 }
2705 }
2706 printLog ($log);
2707
2708 // Render a form for the next.
2709 $typelist = getObjectTypeList();
2710 $typelist[0] = 'select type...';
2711
2712 startPortlet ('Distinct types, same tags');
2713 $max = getConfigVar ('MASSCOUNT');
2714 echo "<form name=fastform method=post action='${root}?page=${pageno}&tab=${tabno}'>";
2715 echo '<table border=0 align=center>';
2716 echo "<tr><th>Object type</th><th>Common name</th><th>Visible label</th>";
2717 echo "<th>Asset tag</th><th>Barcode</th><th>Tags</th></tr>\n";
2718 // If a user forgot to select object type on input, we keep his
2719 // previous input in the form.
2720 for ($i = 0; $i < $max; $i++)
2721 {
2722 echo '<tr><td>';
2723 // Don't employ DEFAULT_OBJECT_TYPE to avoid creating ghost records for pre-selected empty rows.
2724 printSelect ($typelist, "${i}_object_type_id", 0);
2725 echo '</td>';
2726 echo "<td><input type=text size=30 name=${i}_object_name";
2727 if ($keepvalues1 and isset ($name[$i]) and (!isset ($type_id[$i]) or $type_id[$i] == 0))
2728 echo " value='${name[$i]}'";
2729 echo "></td>";
2730 echo "<td><input type=text size=30 name=${i}_object_label";
2731 if ($keepvalues1 and isset ($label[$i]) and (!isset ($type_id[$i]) or $type_id[$i] == 0))
2732 echo " value='${label[$i]}'";
2733 echo "></td>";
2734 echo "<td><input type=text size=20 name=${i}_object_asset_no";
2735 if ($keepvalues1 and isset ($asset_no[$i]) and (!isset ($type_id[$i]) or $type_id[$i] == 0))
2736 echo " value='${asset_no[$i]}'";
2737 echo "></td>";
2738 echo "<td><input type=text size=10 name=${i}_object_barcode";
2739 if ($keepvalues1 and isset ($barcode[$i]) and (!isset ($type_id[$i]) or $type_id[$i] == 0))
2740 echo " value='${barcode[$i]}'";
2741 echo "></td>";
2742 if ($i == 0)
2743 {
2744 echo "<td valign=top rowspan=${max}>";
2745 renderTagSelect();
2746 echo "</td>\n";
2747 }
2748 echo "</tr>\n";
2749 }
2750 echo "<tr><td class=submit colspan=5><input type=submit name=got_fast_data value='Go!'></td></tr>\n";
2751 echo "</form></table>\n";
2752 finishPortlet();
2753
2754 startPortlet ('Same type, same tags');
2755 echo "<form name=veryfastform method=post action='${root}?page=${pageno}&tab=${tabno}'>";
2756 echo "<table border=0 align=center><tr><th>names</th><th>type</th></tr>";
2757 echo "<tr><td rowspan=3><textarea name=namelist cols=40 rows=25>\n";
2758 if ($keepvalues2 and $global_type_id == 0)
2759 echo $_REQUEST['namelist'];
2760 echo "</textarea></td><td valign=top>";
2761 printSelect ($typelist, "global_type_id", getConfigVar ('DEFAULT_OBJECT_TYPE'));
2762 echo "</td></tr>";
2763 echo "<tr><th>Tags</th></tr>";
2764 echo "<tr><td valign=top>";
2765 renderTagSelect();
2766 echo "</td></tr>";
2767 echo "<tr><td colspan=2><input type=submit name=got_very_fast_data value='Go!'></td></tr></table>\n";
2768 echo "</form>\n";
2769 finishPortlet();
2770}
2771
2772function printGreeting ()
2773{
2774 global $remote_username, $accounts, $root;
2775 $account = $accounts[$remote_username];
2776 $person = empty ($account['user_realname']) ? $account['user_name'] : $account['user_realname'];
2777 echo "Hello, ${person}. This is RackTables " . CODE_VERSION . ". Click <a href='${root}?logout'>here</a> to logout.";
2778}
2779
2780function renderSearchResults ()
2781{
2782 global $remote_username, $root;
2783 $terms = trim ($_REQUEST['q']);
2784 if (empty ($terms))
2785 {
2786 showError ('Search string cannot be empty.', __FUNCTION__);
2787 return;
2788 }
2789 if (!permitted ('objects', 'default'))
2790 {
2791 showError ('You are not authorized for viewing information about objects.', __FUNCTION__);
2792 return;
2793 }
2794 $nhits = 0;
2795 // If we search for L2 address, we can either find one or find none.
2796 if
2797 (
2798 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
2799 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
2800 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
2801 // STP bridge ID: bridge priotity + port MAC address. Cut off first 4 chars and look for MAC address.
2802 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)
2803 )
2804 // Search for L2 address.
2805 {
2806 $terms = str_replace ('.', '', $terms);
2807 $terms = str_replace (':', '', $terms);
2808 $terms = substr ($terms, -12);
2809 $result = searchByl2address ($terms);
2810 if ($result !== NULL)
2811 {
2812 $nhits++;
2813 $lasthit = 'port';
2814 $summary['port'][] = $result;
2815 }
2816 }
2817 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))
2818 // Search for IP address.
2819 {
2820 if (NULL !== getIPv4AddressNetworkId ($terms))
2821 {
2822 $nhits++;
2823 $lasthit = 'ipv4addressbydq';
2824 $summary['ipv4addressbydq'][] = $terms;
2825 }
2826 }
2827 else
2828 // Search for objects, addresses, networks, virtual services and RS pools by their description.
2829 {
2830 $tmp = getObjectSearchResults ($terms);
2831 if (count ($tmp))
2832 {
2833 $nhits += count ($tmp);
2834 $lasthit = 'object';
2835 $summary['object'] = $tmp;
2836 }
2837 $tmp = getIPv4AddressSearchResult ($terms);
2838 if (count ($tmp))
2839 {
2840 $nhits += count ($tmp);
2841 $lasthit = 'ipv4addressbydescr';
2842 $summary['ipv4addressbydescr'] = $tmp;
2843 }
2844 $tmp = getIPv4PrefixSearchResult ($terms);
2845 if (count ($tmp))
2846 {
2847 $nhits += count ($tmp);
2848 $lasthit = 'ipv4network';
2849 $summary['ipv4network'] = $tmp;
2850 }
2851 $tmp = getIPv4RSPoolSearchResult ($terms);
2852 if (count ($tmp))
2853 {
2854 $nhits += count ($tmp);
2855 $lasthit = 'ipv4rspool';
2856 $summary['ipv4rspool'] = $tmp;
2857 }
2858 $tmp = getIPv4VServiceSearchResult ($terms);
2859 if (count ($tmp))
2860 {
2861 $nhits += count ($tmp);
2862 $lasthit = 'ipv4vs';
2863 $summary['ipv4vs'] = $tmp;
2864 }
2865 $tmp = getAccountSearchResult ($terms);
2866 if (count ($tmp))
2867 {
2868 $nhits += count ($tmp);
2869 $lasthit = 'user';
2870 $summary['user'] = $tmp;
2871 }
2872 }
2873 if ($nhits == 0)
2874 echo "<center><h2>Nothing found for '${terms}'</h2></center>";
2875 elseif ($nhits == 1)
2876 {
2877 $record = current ($summary[$lasthit]);
2878 switch ($lasthit)
2879 {
2880 case 'port':
2881 echo "<script language='Javascript'>document.location='${root}?page=object";
2882 echo "&hl_port_id=" . $record['port_id'];
2883 echo "&object_id=" . $record['object_id'] . "';//</script>";
2884 break;
2885 case 'ipv4addressbydq':
2886 $parentnet = getIPv4AddressNetworkId ($record);
2887 if ($parentnet !== NULL)
2888 echo "<script language='Javascript'>document.location='${root}?page=iprange&tab=default&id=${parentnet}&hl_ipv4_addr=${record}';//</script>";
2889 else
2890 echo "<script language='Javascript'>document.location='${root}?page=ipaddress&ip=${record}';//</script>";
2891 break;
2892 case 'ipv4addressbydescr':
2893 $parentnet = getIPv4AddressNetworkId ($record['ip']);
2894 if ($parentnet !== NULL)
2895 echo "<script language='Javascript'>document.location='${root}?page=iprange&tab=default&id=${parentnet}&hl_ipv4_addr=${record['ip']}';//</script>";
2896 else
2897 echo "<script language='Javascript'>document.location='${root}?page=ipaddress&ip=${record['ip']}';//</script>";
2898 break;
2899 case 'ipv4network':
2900 echo "<script language='Javascript'>document.location='${root}?page=iprange";
2901 echo "&id=${record['id']}";
2902 echo "';//</script>";
2903 break;
2904 case 'object':
2905 echo "<script language='Javascript'>document.location='${root}?page=object&object_id=${record['id']}';//</script>";
2906 break;
2907 case 'ipv4rspool':
2908 echo "<script language='Javascript'>document.location='${root}?page=ipv4rsp&pool_id=${record['pool_id']}';//</script>";
2909 break;
2910 case 'ipv4vs':
2911 echo "<script language='Javascript'>document.location='${root}?page=ipv4vs&vs_id=${record['id']}';//</script>";
2912 break;
2913 case 'user':
2914 echo "<script language='Javascript'>document.location='${root}?page=user&user_id=${record['user_id']}';//</script>";
2915 break;
2916 }
2917 return;
2918 }
2919 else
2920 {
2921 global $nextorder;
2922 $order = 'odd';
2923 echo "<center><h2>${nhits} result(s) found for '${terms}'</h2></center>";
2924 foreach ($summary as $where => $what)
2925 switch ($where)
2926 {
2927 case 'object':
2928 startPortlet ("<a href='${root}?page=objects'>Objects</a>");
2929 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
2930 echo '<tr><th>Common name</th><th>Visible label</th><th>Asset tag</th><th>barcode</th></tr>';
2931 foreach ($what as $obj)
2932 {
2933 echo "<tr class=row_${order}><td><a href=\"${root}?page=object&object_id=${obj['id']}\">${obj['dname']}</a></td>";
2934 echo "<td>${obj['label']}</td>";
2935 echo "<td>${obj['asset_no']}</td>";
2936 echo "<td>${obj['barcode']}</td></tr>";
2937 $order = $nextorder[$order];
2938 }
2939 echo '</table>';
2940 finishPortlet();
2941 break;
2942 case 'ipv4network':
2943 startPortlet ("<a href='${root}?page=ipv4space'>IPv4 networks</a>");
2944 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
2945 echo '<tr><th>network</th><th>name/tags</th></tr>';
2946 foreach ($what as $netinfo)
2947 {
2948 echo "<tr class=row_${order} valign=top>";
2949 printIPv4NetInfoTDs ($netinfo);
2950 echo "</tr>\n";
2951 $order = $nextorder[$order];
2952 }
2953 echo '</table>';
2954 finishPortlet();
2955 break;
2956 case 'ipv4addressbydescr':
2957 startPortlet ('IPv4 addresses');
2958 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
2959 // FIXME: address, parent network, routers (if extended view is enabled)
2960 echo '<tr><th>Address</th><th>Descritpion</th></tr>';
2961 foreach ($what as $addr)
2962 {
2963 echo "<tr class=row_${order}><td class=tdleft>";
2964 $parentnet = getIPv4AddressNetworkId ($addr['ip']);
2965 if ($parentnet !== NULL)
2966 echo "<a href='${root}?page=iprange&id=${parentnet}&hl_ipv4_addr=${addr['ip']}'>${addr['ip']}</a></td>";
2967 else
2968 echo "<a href='${root}?page=ipaddress&ip=${addr['ip']}'>${addr['ip']}</a></td>";
2969 echo "<td class=tdleft>${addr['name']}</td></tr>";
2970 $order = $nextorder[$order];
2971 }
2972 echo '</table>';
2973 finishPortlet();
2974 break;
2975 case 'ipv4rspool':
2976 startPortlet ("<a href='${root}?page=ipv4rsplist'>RS pools</a>");
2977 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
2978 foreach ($what as $rspool)
2979 {
2980 echo "<tr class=row_${order}><td class=tdleft><a href='${root}?page=ipv4rsp&pool_id=${rspool['pool_id']}'>";
2981 echo buildRSPoolName ($rspool);
2982 echo "</a></td></tr>";
2983 $order = $nextorder[$order];
2984 }
2985 echo '</table>';
2986 finishPortlet();
2987 break;
2988 case 'ipv4vs':
2989 startPortlet ("<a href='${root}?page=ipv4vslist'>Virtual services</a>");
2990 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
2991 echo '<tr><th>VS</th><th>Descritpion</th></tr>';
2992 foreach ($what as $vs)
2993 {
2994 echo "<tr class=row_${order}><td class=tdleft><a href='${root}?page=ipv4vs&vs_id=${vs['id']}'>";
2995 echo buildVServiceName ($vs);
2996 echo "</a></td><td class=tdleft>${vs['name']}</td></tr>";
2997 $order = $nextorder[$order];
2998 }
2999 echo '</table>';
3000 finishPortlet();
3001 break;
3002 case 'user':
3003 startPortlet ("<a href='${root}?page=userlist'>Users</a>");
3004 echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>';
3005 echo '<tr><th>username</th><th>realname</th></tr>';
3006 foreach ($what as $item)
3007 {
3008 echo "<tr class=row_${order}><td class=tdleft><a href='${root}?page=user&user_id=${item['user_id']}'>";
3009 echo $item['user_name'];
3010 echo "</a></td><td class=tdleft>${item['user_realname']}</td></tr>";
3011 $order = $nextorder[$order];
3012 }
3013 echo '</table>';
3014 finishPortlet();
3015 break;
3016 }
3017 }
3018}
3019
3020// This function prints a table of checkboxes to aid the user in toggling mount atoms
3021// from one state to another. The first argument is rack data as
3022// produced by getRackData(), the second is the value used for the 'unckecked' state
3023// and the third is the value used for 'checked' state.
3024// Usage contexts:
3025// for mounting an object: printAtomGrid ($data, 'F', 'T')
3026// for changing rack design: printAtomGrid ($data, 'A', 'F')
3027// for adding rack problem: printAtomGrid ($data, 'F', 'U')
3028// for adding object problem: printAtomGrid ($data, 'T', 'W')
3029
3030function renderAtomGrid ($data)
3031{
3032 $rack_id = $data['id'];
3033 for ($unit_no = $data['height']; $unit_no > 0; $unit_no--)
3034 {
3035 echo "<tr><th>${unit_no}</th>";
3036 for ($locidx = 0; $locidx < 3; $locidx++)
3037 {
3038 $state = $data[$unit_no][$locidx]['state'];
3039 echo "<td class=state_${state}";
3040 if (isset ($data[$unit_no][$locidx]['hl']))
3041 echo $data[$unit_no][$locidx]['hl'];
3042 echo ">";
3043 if (!($data[$unit_no][$locidx]['enabled'] === TRUE))
3044 echo '<input type=checkbox disabled>';
3045 else
3046 echo "<input type=checkbox" . $data[$unit_no][$locidx]['checked'] . " name=atom_${rack_id}_${unit_no}_${locidx}>";
3047 echo '</td>';
3048 }
3049 echo "</tr>\n";
3050 }
3051}
3052
3053function renderUserList ()
3054{
3055 global $nextorder, $accounts, $root, $pageno;
3056 echo "<table border=0 class=objectview>\n";
3057 echo "<tr><td class=pcleft>";
3058 startPortlet ('User accounts');
3059 echo "<table class=cooltable border=0 cellpadding=5 cellspacing=0 align=center>\n";
3060 echo "<tr><th class=tdleft>Username</th><th class=tdleft>Real name</th></tr>";
3061 $order = 'odd';
3062 $tagfilter = getTagFilter();
3063 foreach (getUserAccounts ($tagfilter, getTFMode()) as $user)
3064 {
3065 echo "<tr class=row_${order} valign=top><td class=tdleft><a href='${root}?page=user&user_id=${user['user_id']}'>";
3066 echo "${user['user_name']}</a>";
3067 $usertags = loadUserTags ($user['user_id']);
3068 if (count ($usertags))
3069 echo '<br><small>' . serializeTags ($usertags, "${root}?page=${pageno}&tab=default&") . '</small>';
3070 echo "</td><td class=tdleft>${user['user_realname']}</td></li>";
3071 $order = $nextorder[$order];
3072 }
3073 echo '</table>';
3074 finishPortlet();
3075 echo '</td><td class=pcright>';
3076 renderTagFilterPortlet ($tagfilter, 'user');
3077 echo "</td></tr></table>\n";
3078}
3079
3080function renderUserListEditor ()
3081{
3082 global $root, $pageno, $tabno, $accounts;
3083 startPortlet ('User accounts');
3084 showMessageOrError();
3085 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable>\n";
3086 echo "<tr><th>status (click to change)</th><th>Username</th><th>Real name</th><th>Password</th><th>&nbsp;</th></tr>\n";
3087 foreach ($accounts as $account)
3088 {
3089 printOpFormIntro ('updateUser', array ('user_id' => $account['user_id']));
3090 echo "<tr><td>";
3091 if ($account['user_enabled'] == 'yes' && $account['user_id'] != 1)
3092 {
3093 echo "<a href='${root}process.php?op=disableUser&page=${pageno}&tab=${tabno}&user_id=${account['user_id']}'>";
3094 printImageHREF ('blockuser', 'disable account');
3095 echo "</a>\n";
3096 }
3097 if ($account['user_enabled'] == 'no' && $account['user_id'] != 1)
3098 {
3099 echo "<a href='${root}process.php?op=enableUser&page=${pageno}&tab=${tabno}&user_id=${account['user_id']}'>";
3100 printImageHREF ('unblockuser', 'enable account');
3101 echo "</a>\n";
3102 }
3103 // Otherwise skip icon.
3104 echo "</td>";
3105 echo "<td><input type=text name=username value='${account['user_name']}' size=16></td>";
3106 echo "<td><input type=text name=realname value='${account['user_realname']}' size=24></td>";
3107 echo "<td><input type=password name=password value='${account['user_password_hash']}' size=64></td><td>";
3108 printImageHREF ('save', 'Save changes', TRUE);
3109 echo "</td></form></tr>\n";
3110 }
3111 printOpFormIntro ('createUser');
3112 echo "<td>&nbsp;</td><td><input type=text size=16 name=username tabindex=100></td>\n";
3113 echo "<td><input type=text size=24 name=realname tabindex=101></td>";
3114 echo "<td><input type=password size=64 name=password tabindex=102></td><td>";
3115 printImageHREF ('create', 'Add new account', TRUE, 103);
3116 echo "</td></tr></form>";
3117 echo "</table><br>\n";
3118 finishPortlet();
3119}
3120
3121function renderPortMapViewer ()
3122{
3123 renderPortMap (FALSE);
3124}
3125
3126function renderPortMapEditor ()
3127{
3128 renderPortMap (TRUE);
3129}
3130
3131function renderPortMap ($editable = FALSE)
3132{
3133 global $nextorder, $root, $pageno, $tabno;
3134 showMessageOrError();
3135 startPortlet ("Port compatibility map");
3136 $ptlist = getPortTypes();
3137 $pclist = getPortCompat();
3138 $pctable = buildPortCompatMatrixFromList ($ptlist, $pclist);
3139 if ($editable)
3140 printOpFormIntro ('save');
3141 echo "<table class=cooltable border=0 cellpadding=5 cellspacing=0 align=center>\n";
3142 echo "<tr><th class=vert_th>&nbsp;</th>";
3143 foreach ($ptlist as $name2)
3144 echo "<th>to ${name2}</th>";
3145 echo "</tr>";
3146 // Make a copy to have an independent array pointer.
3147 $ptlistY = $ptlist;
3148 $order = 'odd';
3149 foreach ($ptlistY as $type1 => $name1)
3150 {
3151 echo "<tr class=row_${order}><th class=vert_th style='border-bottom: 0px;'>from $name1</th>";
3152 foreach ($ptlist as $type2 => $name2)
3153 {
3154 echo '<td' . ($pctable[$type1][$type2] ? " class=portmap_highlight_$order" : '') . '>';
3155 echo '<input type=checkbox' . ($editable ? " name=atom_${type1}_${type2}" : ' disabled');
3156 echo ($pctable[$type1][$type2] ? ' checked' : '') . '></td>';
3157 }
3158 echo "</tr>\n";
3159 $order = $nextorder[$order];
3160 }
3161 echo '</table><br>';
3162 if ($editable)
3163 {
3164 printImageHREF ('SAVE', 'Save changes', TRUE);
3165 echo "</form>";
3166 }
3167 finishPortlet();
3168}
3169
3170function renderConfigMainpage ()
3171{
3172 global $pageno, $root;
3173 $children = getDirectChildPages ($pageno);
3174 echo '<ul>';
3175 // FIXME: assume all config kids to have static titles at the moment,
3176 // but use some proper abstract function later.
3177 foreach ($children as $cpageno => $child)
3178 echo "<li><a href='${root}?page=${cpageno}'>" . $child['title'] . "</li>\n";
3179 echo '';
3180 echo '</ul>';
3181}
3182
3183function renderRackPage ($rack_id)
3184{
3185 if ($rack_id == 0)
3186 {
3187 showError ('Invalid argument', __FUNCTION__);
3188 return;
3189 }
3190 if (($rackData = getRackData ($rack_id)) == NULL)
3191 {
3192 showError ('getRackData() failed', __FUNCTION__);
3193 return;
3194 }
3195 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0><tr>";
3196
3197 // Left column with information.
3198 echo "<td class=pcleft>";
3199 renderRackInfoPortlet ($rackData);
3200 echo '</td>';
3201
3202 // Right column with rendered rack.
3203 echo '<td>';
3204 startPortlet ('Rack diagram');
3205 renderRack ($rack_id);
3206 finishPortlet();
3207 echo '</td>';
3208
3209 echo '</tr></table>';
3210}
3211
3212function renderDictionary ()
3213{
3214 global $nextorder;
3215 $dict = getDict (TRUE);
3216 echo "<br><table class=cooltable border=0 cellpadding=5 cellspacing=0 align=center>\n";
3217 foreach ($dict as $chapter_no => $chapter)
3218 {
3219 $order = 'odd';
3220 echo "<tr><th>Chapter</th><th>refs</th><th>Word</th></tr>\n";
3221 $wc = count ($chapter['word']);
3222 echo "<tr class=row_${order}><td class=tdleft" . ($wc ? " rowspan = ${wc}" : '');
3223 echo "><div title='number=${chapter_no}'>${chapter['name']} (${wc} records)</div></td>";
3224 if (!$wc)
3225 echo "<td colspan=2>none</td>";
3226 else
3227 {
3228 $chap_start = TRUE;
3229 foreach ($chapter['word'] as $key => $value)
3230 {
3231 if (!$chap_start)
3232 echo "<tr class=row_${order}>";
3233 else
3234 $chap_start = FALSE;
3235 echo '<td>' . ($chapter['refcnt'][$key] ? $chapter['refcnt'][$key] : '&nbsp;') . '</td>';
3236 echo "<td><div title='key=${key}'>${value}</div></td></tr>\n";
3237 $order = $nextorder[$order];
3238 }
3239 }
3240 }
3241 echo "</table>\n<br>";
3242}
3243
3244function renderDictionaryEditor ()
3245{
3246 global $root, $pageno, $tabno, $nextorder;
3247 $dict = getDict();
3248 showMessageOrError();
3249 echo "<br><table class=cooltable border=0 cellpadding=5 cellspacing=0 align=center>\n";
3250 foreach ($dict as $chapter_no => $chapter)
3251 {
3252 $order = 'odd';
3253 echo "<tr><th>Chapter</th><th>&nbsp;</th><th>Word</th><th>&nbsp;</th></tr>\n";
3254 $wc = count ($chapter['word']);
3255 // One extra span for the new record per each chapter block.
3256 echo "<tr class=row_${order}><td class=tdleft" . ($wc ? ' rowspan = ' . ($wc + 1) : '');
3257 echo "><div title='number=${chapter_no}'>${chapter['name']} (${wc} records)</div></td>";
3258 printOpFormIntro ('add', array ('chapter_no' => $chapter['no']));
3259 echo "<td>";
3260 printImageHREF ('add', 'Add new', TRUE);
3261 echo "</td>";
3262 echo "<td class=tdright><input type=text name=dict_value size=32></td>";
3263 echo "<td>&nbsp;</td>";
3264 echo '</tr></form>';
3265 $order = $nextorder[$order];
3266 foreach ($chapter['word'] as $key => $value)
3267 {
3268 printOpFormIntro ('upd', array ('chapter_no' => $chapter['no'], 'dict_key' => $key));
3269 echo "<tr class=row_${order}><td>";
3270 // Prevent deleting words currently used somewhere.
3271 if ($chapter['refcnt'][$key])
3272 printImageHREF ('nodelete', 'referenced ' . $chapter['refcnt'][$key] . ' time(s)');
3273 else
3274 {
3275 echo "<a href='${root}process.php?page=${pageno}&tab=${tabno}&op=del&chapter_no=${chapter['no']}&dict_key=${key}'>";
3276 printImageHREF ('delete', 'Delete word');
3277 echo "</a>";
3278 }
3279 echo '</td>';
3280 echo "<td class=tdright><input type=text name=dict_value size=32 value='${value}'></td><td>";
3281 printImageHREF ('save', 'Save changes', TRUE);
3282 echo "</td></tr></form>\n";
3283 $order = $nextorder[$order];
3284 } // foreach ($chapter['word']
3285 } // foreach ($dict
3286 echo "</table>\n";
3287}
3288
3289// We don't allow to rename/delete a sticky chapter and we don't allow
3290// to delete a non-empty chapter.
3291function renderChaptersEditor ()
3292{
3293 global $root, $pageno, $tabno;
3294 showMessageOrError();
3295 $dict = getDict();
3296 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable>\n";
3297 echo '<tr><th>&nbsp;</th><th>Chapter name</th><th>Words</th><th>&nbsp;</th></tr>';
3298 foreach ($dict as $chapter)
3299 {
3300 $wordcount = count ($chapter['word']);
3301 $sticky = $chapter['sticky'];
3302 printOpFormIntro ('upd', array ('chapter_no' => $chapter['no']));
3303 echo '<tr>';
3304 echo '<td>';
3305 if ($sticky)
3306 printImageHREF ('nodelete', 'system chapter');
3307 elseif ($wordcount > 0)
3308 printImageHREF ('nodelete', 'contains ' . $wordcount . ' word(s)');
3309 else
3310 {
3311 echo "<a href='${root}process.php?page=${pageno}&tab=${tabno}&op=del&chapter_no=${chapter['no']}'>";
3312 printImageHREF ('delete', 'Remove chapter');
3313 echo "</a>";
3314 }
3315 echo '</td>';
3316 echo "<td><input type=text name=chapter_name value='${chapter['name']}'" . ($sticky ? ' disabled' : '') . "></td>";
3317 echo "<td class=tdleft>${wordcount}</td><td>";
3318 if ($sticky)
3319 echo '&nbsp;';
3320 else
3321 printImageHREF ('save', 'Save changes', TRUE);
3322 echo '</td></tr>';
3323 echo '</form>';
3324 }
3325 printOpFormIntro ('add');
3326 echo '<tr><td>';
3327 printImageHREF ('add', 'Add new', TRUE);
3328 echo "</td><td colspan=3><input type=text name=chapter_name></td>";
3329 echo '</tr>';
3330 echo '</form>';
3331 echo "</table>\n";
3332}
3333
3334function renderAttributes ()
3335{
3336 global $nextorder;
3337 $attrMap = getAttrMap();
3338 startPortlet ('Optional attributes');
3339 echo "<table class=cooltable border=0 cellpadding=5 cellspacing=0 align=center>\n";
3340 echo "<tr><th class=tdleft>Attribute name</th><th class=tdleft>Attribute type</th><th class=tdleft>Applies to</th></tr>";
3341 $order = 'odd';
3342 foreach ($attrMap as $attr)
3343 {
3344 echo "<tr class=row_${order}>";
3345 echo "<td class=tdleft>${attr['name']}</td>";
3346 echo "<td class=tdleft>${attr['type']}</td>";
3347 echo '<td class=tdleft>';
3348 if (count ($attr['application']) == 0)
3349 echo '&nbsp;';
3350 else
3351 foreach ($attr['application'] as $app)
3352 if ($attr['type'] == 'dict')
3353 echo "${app['objtype_name']} (values from '${app['chapter_name']}')<br>";
3354 else
3355 echo "${app['objtype_name']}<br>";
3356 echo '</td>';
3357 echo "</tr>\n";
3358 $order = $nextorder[$order];
3359 }
3360 echo "</table><br>\n";
3361 finishPortlet();
3362}
3363
3364function renderEditAttributesForm ()
3365{
3366 global $root, $pageno, $tabno;
3367 $attrMap = getAttrMap();
3368 showMessageOrError();
3369 startPortlet ('Optional attributes');
3370 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable>\n";
3371 echo '<tr><th>&nbsp;</th><th>Name</th><th>Type</th><th>&nbsp;</th></tr>';
3372 foreach ($attrMap as $attr)
3373 {
3374 printOpFormIntro ('upd', array ('attr_id' => $attr['id']));
3375 echo '<tr>';
3376 echo "<td><a href='${root}process.php?page=${pageno}&tab=${tabno}&op=del&attr_id=${attr['id']}'>";
3377 printImageHREF ('delete', 'Remove attribute');
3378 echo '</a></td>';
3379 echo "<td><input type=text name=attr_name value='${attr['name']}'></td>";
3380 echo "<td class=tdleft>${attr['type']}</td><td>";
3381 printImageHREF ('save', 'Save changes', TRUE);
3382 echo '</td></tr>';
3383 echo '</form>';
3384 }
3385 printOpFormIntro ('add');
3386 echo '<tr><td>';
3387 printImageHREF ('add', '', TRUE);
3388 echo "</td><td><input type=text name=attr_name></td>";
3389 echo '<td><select name=attr_type>';
3390 echo '<option value=uint>uint</option>';
3391 echo '<option value=float>float</option>';
3392 echo '<option value=string>string</option>';
3393 echo '<option value=dict>dict</option>';
3394 echo '</select></td>';
3395 echo '</tr>';
3396 echo '</form>';
3397 echo "</table>\n";
3398 finishPortlet();
3399}
3400
3401function renderEditAttrMapForm ()
3402{
3403 global $root, $pageno, $tabno;
3404 $attrMap = getAttrMap();
3405 showMessageOrError();
3406 startPortlet ('Attribute map');
3407 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable>\n";
3408 echo '<tr><th>&nbsp;</th><th>Attribute name</th><th>Object type</th><th>Dictionary chapter</th></tr>';
3409 foreach ($attrMap as $attr)
3410 {
3411 if (count ($attr['application']) == 0)
3412 continue;
3413 foreach ($attr['application'] as $app)
3414 {
3415 echo '<tr>';
3416 echo '<td>';
3417 echo "<a href='${root}process.php?page=${pageno}&tab=${tabno}&op=del&";
3418 echo "attr_id=${attr['id']}&objtype_id=${app['objtype_id']}'>";
3419 printImageHREF ('delete', 'Remove mapping');
3420 echo "</a>";
3421 echo '</td>';
3422 echo "<td>${attr['name']}</td>";
3423 echo "<td>${app['objtype_name']}</td>";
3424 echo "<td>";
3425 if ($attr['type'] == 'dict')
3426 echo "${app['chapter_name']}";
3427 else
3428 echo '&nbsp;';
3429 echo "</td></tr>\n";
3430 }
3431 }
3432 printOpFormIntro ('add');
3433 echo '<tr><td>';
3434 printImageHREF ('add', '', TRUE);
3435 echo "</td><td><select name=attr_id>";
3436 $shortType['uint'] = 'U';
3437 $shortType['float'] = 'F';
3438 $shortType['string'] = 'S';
3439 $shortType['dict'] = 'D';
3440 foreach ($attrMap as $attr)
3441 echo "<option value=${attr['id']}>[" . $shortType[$attr['type']] . "] ${attr['name']}</option>";
3442 echo "</select></td>";
3443 echo '<td>';
3444 printSelect (getObjectTypeList(), 'objtype_id');
3445 echo '</td>';
3446 $dict = getDict();
3447 echo '<td><select name=chapter_no>';
3448 foreach ($dict as $chapter)
3449 if (!$chapter['sticky'])
3450 echo "<option value='${chapter['no']}'>${chapter['name']}</option>";
3451 echo '</select></td>';
3452 echo '</tr>';
3453 echo '</form>';
3454 echo "</table>\n";
3455 finishPortlet();
3456}
3457
3458function printImageHREF ($tag, $title = '', $do_input = FALSE, $tabindex = 0)
3459{
3460 global $root, $image;
3461 if (!isset ($image[$tag]))
3462 $tag = 'error';
3463 $img = $image[$tag];
3464 if ($do_input == TRUE)
3465 echo
3466 "<input type=image name=submit class=icon " .
3467 "src='${root}${img['path']}' " .
3468 "border=0 " .
3469 ($tabindex ? '' : "tabindex=${tabindex}") .
3470 (empty ($title) ? '' : " title='${title}'") . // JT: Add title to input hrefs too
3471 ">";
3472 else
3473 echo
3474 "<img " .
3475 "src='${root}${img['path']}' " .
3476 "width=${img['width']} " .
3477 "height=${img['height']} " .
3478 "border=0 " .
3479 (empty ($title) ? '' : "title='${title}'") .
3480 ">";
3481}
3482
3483// This function returns URL for favourite icon.
3484function getFaviconURL ()
3485{
3486 global $root;
3487 return $root . 'pix/racktables.ico';
3488}
3489
3490// FIXME: stack the report sections somehow, so they can register themselves.
3491function renderSystemReports ()
3492{
3493 $systemreports = array
3494 (
3495 array
3496 (
3497 'title' => 'Dictionary/objects',
3498 'type' => 'counters',
3499 'func' => 'getDictStats'
3500 ),
3501 array
3502 (
3503 'title' => 'IPv4',
3504 'type' => 'counters',
3505 'func' => 'getIPv4Stats'
3506 ),
3507 array
3508 (
3509 'title' => 'Rackspace',
3510 'type' => 'counters',
3511 'func' => 'getRackspaceStats'
3512 ),
3513 array
3514 (
3515 'title' => 'RackCode',
3516 'type' => 'counters',
3517 'func' => 'getRackCodeStats'
3518 ),
3519 array
3520 (
3521 'title' => 'Tags top-50',
3522 'type' => 'custom',
3523 'func' => 'renderTagStats'
3524 ),
3525 );
3526 renderReports ($systemreports);
3527}
3528
3529function renderLocalReports ()
3530{
3531 global $localreports;
3532 renderReports ($localreports);
3533}
3534
3535function renderReports ($what)
3536{
3537 if (!count ($what))
3538 return;
3539 echo "<table align=center>\n";
3540 foreach ($what as $item)
3541 {
3542 echo "<tr><th colspan=2><h3>${item['title']}</h3></th></tr>\n";
3543 switch ($item['type'])
3544 {
3545 case 'counters':
3546 foreach ($item['func'] () as $header => $data)
3547 echo "<tr><td class=tdright>${header}:</td><td class=tdleft>${data}</td></tr>\n";
3548 break;
3549 case 'custom':
3550 echo "<tr><td colspan=2>";
3551 $item['func'] ();
3552 echo "</td></tr>\n";
3553 break;
3554 default:
3555 showError ('Internal data error', __FUNCTION__);
3556 }
3557 echo "<tr><td colspan=2><hr></td></tr>\n";
3558 }
3559 echo "</table>\n";
3560}
3561
3562function dragon ()
3563{
3564 startPortlet ('Here be dragons');
3565?>
3566<div class=dragon><pre><font color="#00ff33">
3567 \||/
3568 | <font color="#ff0000">@</font>___oo
3569 /\ /\ / (__<font color=yellow>,,,,</font>|
3570 ) /^\) ^\/ _)
3571 ) /^\/ _)
3572 ) _ / / _)
3573 /\ )/\/ || | )_)
3574 &lt; &gt; |(<font color=white>,,</font>) )__)
3575 || / \)___)\
3576 | \____( )___) )___
3577 \______(_______<font color=white>;;;</font> __<font color=white>;;;</font>
3578
3579</font></pre></div>
3580<?php
3581 finishPortlet();
3582}
3583
3584function renderUIConfig ()
3585{
3586 global $configCache, $nextorder;
3587 showMessageOrError();
3588 startPortlet ('Current configuration');
3589 echo '<table class=cooltable border=0 cellpadding=5 cellspacing=0 align=center width="50%">';
3590 echo '<tr><th class=tdleft>Option</th><th class=tdleft>Value</th></tr>';
3591 $order = 'odd';
3592 foreach ($configCache as $v)
3593 {
3594 if ($v['is_hidden'] != 'no')
3595 continue;
3596 echo "<tr class=row_${order}>";
3597 echo "<td class=tdright>${v['description']}</td>\n";
3598 echo "<td class=tdleft>${v['varvalue']}</td></tr>";
3599 $order = $nextorder[$order];
3600 }
3601 echo "</table>\n";
3602 finishPortlet();
3603}
3604
3605function renderUIConfigEditForm ()
3606{
3607 global $configCache;
3608 showMessageOrError();
3609 startPortlet ('Current configuration');
3610 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable width='50%'>\n";
3611 echo "<tr><th class=tdleft>Option</th>";
3612 echo "<th class=tdleft>Value</th></tr>";
3613 printOpFormIntro ('upd');
3614
3615 $i = 0;
3616 foreach ($configCache as $v)
3617 {
3618 if ($v['is_hidden'] != 'no')
3619 continue;
3620 echo "<input type=hidden name=${i}_varname value='${v['varname']}'>";
3621 echo "<tr><td class=tdright>${v['description']}</td>";
3622 echo "<td class=tdleft><input type=text name=${i}_varvalue value='${v['varvalue']}' size=24></td>";
3623 echo "</tr>\n";
3624 $i++;
3625 }
3626 echo "<input type=hidden name=num_vars value=${i}>\n";
3627 echo "<tr><td colspan=2>";
3628 printImageHREF ('SAVE', 'Save changes', TRUE);
3629 echo "</td></tr>";
3630 echo "</form>";
3631 finishPortlet();
3632}
3633
3634// This function queries the gateway about current VLAN configuration and
3635// renders a form suitable for submit. Ah, and it does submit processing as well.
3636function renderVLANMembership ($object_id = 0)
3637{
3638 showMessageOrError();
3639 $data = getSwitchVLANs ($object_id);
3640 if ($data === NULL)
3641 {
3642 showError ('getSwitchVLANs() returned NULL', __FUNCTION__);
3643 return;
3644 }
3645 list ($vlanlist, $portlist, $maclist) = $data;
3646
3647 echo '<table border=0 width="100%"><tr><td colspan=3>';
3648
3649 startPortlet ('Current status');
3650 echo "<table class=widetable cellspacing=3 cellpadding=5 align=center width='100%'><tr>";
3651 printOpFormIntro ('setPortVLAN');
3652 $portcount = count ($portlist);
3653 echo "<input type=hidden name=portcount value=" . $portcount . ">\n";
3654 $portno = 0;
3655 $ports_per_row = getConfigVar ('PORTS_PER_ROW');
3656 foreach ($portlist as $port)
3657 {
3658 // Don't let wide forms break our fancy pages.
3659 if ($portno % $ports_per_row == 0)
3660 {
3661 if ($portno > 0)
3662 echo "</tr>\n";
3663 echo "<tr><th>" . ($portno + 1) . "-" . ($portno + $ports_per_row > $portcount ? $portcount : $portno + $ports_per_row) . "</th>";
3664 }
3665 echo '<td class=port_';
3666 if ($port['status'] == 'notconnect')
3667 echo 'notconnect';
3668 elseif ($port['status'] == 'disabled')
3669 echo 'disabled';
3670 elseif ($port['status'] != 'connected')
3671 echo 'unknown';
3672 elseif (!isset ($maclist[$port['portname']]))
3673 echo 'connected_none';
3674 else
3675 {
3676 $maccount = 0;
3677 foreach ($maclist[$port['portname']] as $vlanid => $addrs)
3678 $maccount += count ($addrs);
3679 if ($maccount == 1)
3680 echo 'connected_single';
3681 else
3682 echo 'connected_multi';
3683 }
3684 echo '>' . $port['portname'] . '<br>';
3685 echo "<input type=hidden name=portname_${portno} value=" . $port['portname'] . '>';
3686 if ($port['vlanid'] == 'trunk')
3687 {
3688 echo "<input type=hidden name=vlanid_${portno} value='trunk'>";
3689 echo "<select disabled multiple='multiple' size=1><option>TRUNK</option></select>";
3690 }
3691 elseif ($port['vlanid'] == 'routed')
3692 {
3693 echo "<input type=hidden name=vlanid_${portno} value='routed'>";
3694 echo "<select disabled multiple='multiple' size=1><option>ROUTED</option></select>";
3695 }
3696 else
3697 {
3698 echo "<select name=vlanid_${portno}>";
3699 // A port may belong to a VLAN, which is absent from the VLAN table, this is normal.
3700 // We must be able to render its SELECT properly at least.
3701 $in_table = FALSE;
3702 foreach ($vlanlist as $v => $d)
3703 {
3704 echo "<option value=${v}";
3705 if ($v == $port['vlanid'])
3706 {
3707 echo ' selected';
3708 $in_table = TRUE;
3709 }
3710 echo ">${v}</option>\n";
3711 }
3712 if (!$in_table)
3713 echo "<option value=${port['vlanid']} selected>${port['vlanid']}</option>\n";
3714 echo "</select>";
3715 }
3716 $portno++;
3717 echo "</td>";
3718 }
3719 echo "</tr><tr><td colspan=" . ($ports_per_row + 1) . "><input type=submit value='Save changes'></form></td></tr></table>";
3720 finishPortlet();
3721
3722 echo '</td></tr><tr><td class=pcleft>';
3723 startPortlet ('VLAN table');
3724 echo '<table class=cooltable cellspacing=0 cellpadding=5 align=center width="100%">';
3725 echo "<tr><th>ID</th><th>Description</th></tr>";
3726 $order = 'even';
3727 global $nextorder;
3728 foreach ($vlanlist as $id => $descr)
3729 {
3730 echo "<tr class=row_${order}><td class=tdright>${id}</td><td class=tdleft>${descr}</td></tr>";
3731 $order = $nextorder[$order];
3732 }
3733 echo '</table>';
3734 finishPortlet();
3735
3736 echo '</td><td class=pcright>';
3737
3738 startPortlet ('Color legend');
3739 echo '<table>';
3740 echo "<tr><th>port state</th><th>color code</th></tr>";
3741 echo "<tr><td>not connected</td><td class=port_notconnect>SAMPLE</td></tr>";
3742 echo "<tr><td>disabled</td><td class=port_disabled>SAMPLE</td></tr>";
3743 echo "<tr><td>unknown</td><td class=port_unknown>SAMPLE</td></tr>";
3744 echo "<tr><td>connected with none MAC addresses active</td><td class=port_connected_none>SAMPLE</td></tr>";
3745 echo "<tr><td>connected with 1 MAC addresses active</td><td class=port_connected_single>SAMPLE</td></tr>";
3746 echo "<tr><td>connected with 1+ MAC addresses active</td><td class=port_connected_multi>SAMPLE</td></tr>";
3747 echo '</table>';
3748 finishPortlet();
3749
3750 echo '</td><td class=pcright>';
3751
3752 if (count ($maclist))
3753 {
3754 startPortlet ('MAC address table');
3755 echo '<table border=0 class=cooltable align=center cellspacing=0 cellpadding=5>';
3756 echo "<tr><th>Port</th><th>VLAN ID</th><th>MAC address</th></tr>\n";
3757 $order = 'even';
3758 foreach ($maclist as $portname => $portdata)
3759 foreach ($portdata as $vlanid => $addrgroup)
3760 foreach ($addrgroup as $addr)
3761 {
3762 echo "<tr class=row_${order}><td class=tdleft>$portname</td><td class=tdleft>$vlanid</td>";
3763 echo "<td class=tdleft>$addr</td></tr>\n";
3764 $order = $nextorder[$order];
3765 }
3766 echo '</table>';
3767 finishPortlet();
3768 }
3769
3770 // End of main table.
3771 echo '</td></tr></table>';
3772}
3773
3774function renderSNMPPortFinder ($object_id = 0)
3775{
3776 showMessageOrError();
3777 if ($object_id <= 0)
3778 {
3779 showError ('Invalid argument', __FUNCTION__);
3780 return;
3781 }
3782// FIXME: check if SNMP PHP extension is available!
3783 printOpFormIntro ('querySNMPData');
3784?>
3785<p align=center>
3786This asset has no ports listed, that's why you see this form. If you supply SNMP community,
3787I can try automatic data harvesting on the asset. As soon as at least one port is added,
3788this tab will not be seen any more. Good luck.<br>
3789<input type=text name=community value='public'>
3790<input type=submit name='do_scan' value='Go!'>
3791</form>
3792</p>
3793<?php
3794}
3795
3796function renderUIResetForm()
3797{
3798 printOpFormIntro ('go');
3799 echo "This button will reset user interface configuration to its defaults (except organization name and auth source): ";
3800 echo "<input type=submit value='proceed'>";
3801 echo "</form>";
3802}
3803
3804function renderFirstRowForm ()
3805{
3806 global $root;
3807 echo "<form action='${root}process.php'>\n";
3808 echo "<input type=hidden name=page value=dict>\n";
3809 echo "<input type=hidden name=tab value=edit>\n";
3810 echo "<input type=hidden name=op value=add>\n";
3811 echo "<input type=hidden name=chapter_no value=3>\n";
3812?>
3813<p align=center>
3814Your rackspace seems to be empty, and this form will create your first rack row,
3815just fill in the name. All the subsequent rack rows will have to be added from the
3816Dictionary edit page in Configuration section (you will be redirected right there).
3817<br>
3818<input type=text name=dict_value value='my server room'><br>
3819<?php printImageHREF ('CREATE', 'Add record', TRUE); ?>
3820</form>
3821</p>
3822<?php
3823}
3824
3825function renderLVSConfig ($object_id = 0)
3826{
3827 showMessageOrError();
3828 if ($object_id <= 0)
3829 {
3830 showError ('Invalid argument', __FUNCTION__);
3831 return;
3832 }
3833 echo '<br>';
3834 printOpFormIntro ('submitSLBConfig');
3835 echo "<center><input type=submit value='Submit for activation'></center>";
3836 echo "</form>";
3837 echo '<pre>';
3838 echo buildLVSConfig ($object_id);
3839 echo '</pre>';
3840}
3841
3842function renderVirtualService ($vsid)
3843{
3844 global $root, $nextorder;
3845 if ($vsid <= 0)
3846 {
3847 showError ('Invalid argument', __FUNCTION__);
3848 return;
3849 }
3850 $vsinfo = getVServiceInfo ($vsid);
3851 echo '<table border=0 class=objectview cellspacing=0 cellpadding=0>';
3852 if (!empty ($vsinfo['name']))
3853 echo "<tr><td colspan=2 align=center><h1>${vsinfo['name']}</h1></td></tr>\n";
3854 echo '<tr>';
3855
3856 echo '<td class=pcleft>';
3857 startPortlet ('Frontend');
3858 echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
3859 if (!empty ($vsinfo['name']))
3860 echo "<tr><th width='50%' class=tdright>Name:</th><td class=tdleft>${vsinfo['name']}</td></tr>\n";
3861 echo "<tr><th width='50%' class=tdright>Protocol:</th><td class=tdleft>${vsinfo['proto']}</td></tr>\n";
3862 echo "<tr><th width='50%' class=tdright>Virtual IP address:</th><td class=tdleft><a href='${root}?page=ipaddress&tab=default&ip=${vsinfo['vip']}'>${vsinfo['vip']}</a></td></tr>\n";
3863 echo "<tr><th width='50%' class=tdright>Virtual port:</th><td class=tdleft>${vsinfo['vport']}</td></tr>\n";
3864 printTagTRs ("${root}?page=ipv4vslist&");
3865 if (!empty ($vsinfo['vsconfig']))
3866 {
3867 echo "<tr><th width='50%' class=tdright>VS configuration:</th><td class=tdleft>&nbsp;</td></tr>\n";
3868 echo "<tr><td class=tdleft colspan=2><pre>${vsinfo['vsconfig']}</pre></td></tr>\n";
3869 }
3870 if (!empty ($vsinfo['rsconfig']))
3871 {
3872 echo "<tr><th width='50%' class=tdright>RS configuration:</th><td class=tdleft>&nbsp;</td></tr>\n";
3873 echo "<tr><td class=tdleft colspan=2><pre>${vsinfo['rsconfig']}</pre></td></tr>\n";
3874 }
3875 echo "</table>\n";
3876 finishPortlet ();
3877 echo '</td>';
3878
3879 echo '<td class=pcright>';
3880 startPortlet ('Backend');
3881 echo "<table cellspacing=0 cellpadding=5 align=center border=0>\n";
3882 echo "<tr><th>real server pool</th><th>load balancers</th></tr>\n";
3883 $order = 'odd';
3884 foreach ($vsinfo['rspool'] as $pool_id => $poolInfo)
3885 {
3886 echo "<tr class=row_${order}><td class=tdleft>";
3887 // Pool info
3888 echo '<table width=100%>';
3889 echo "<tr><td colspan=2><a href='${root}?page=ipv4rsp&pool_id=${pool_id}'>";
3890 if (!empty ($poolInfo['name']))
3891 echo $poolInfo['name'];
3892 else
3893 echo 'ANONYMOUS';
3894 echo "</a></td></tr>";
3895 if (!empty ($poolInfo['vsconfig']))
3896 echo "<tr><th>VS config</th><td class=tdleft><pre>${poolInfo['vsconfig']}</pre></td></tr>";
3897 if (!empty ($poolInfo['rsconfig']))
3898 echo "<tr><th>RS config</th><td class=tdleft><pre>${poolInfo['rsconfig']}</pre></td></tr>";
3899 echo '</table>';
3900 echo '</td><td>';
3901 // LB list
3902 if (!count ($poolInfo['lblist']))
3903 echo 'none';
3904 else
3905 {
3906 echo '<table width=100%>';
3907 foreach ($poolInfo['lblist'] as $object_id => $lbInfo)
3908 {
3909 // FIXME: dname should be cached
3910 $oi = getObjectInfo ($object_id);
3911 echo "<tr><td colspan=2><a href='${root}?page=object&object_id=${object_id}'>";
3912 echo $oi['dname'] . '</a></td></tr>';
3913 if (!empty ($lbInfo['vsconfig']))
3914 echo "<tr><th>VS config</th><td class=tdleft><pre>${lbInfo['vsconfig']}</pre></td></tr>";
3915 if (!empty ($lbInfo['rsconfig']))
3916 echo "<tr><th>RS config</th><td class=tdleft><pre>${lbInfo['rsconfig']}</pre></td></tr>";
3917 }
3918 echo '</table>';
3919 }
3920 echo "</td></tr>\n";
3921 $order = $nextorder[$order];
3922 }
3923 echo "</table>\n";
3924 finishPortlet ();
3925 echo '</td>';
3926
3927 echo '</tr><table>';
3928}
3929
3930function renderProgressBar ($percentage = 0)
3931{
3932 global $root;
3933 $done = ((int) ($percentage * 100));
3934 echo "<img width=100 height=10 border=0 title='${done}%' src='${root}render_image.php?img=progressbar&done=${done}'>";
3935}
3936
3937function renderRSPoolServerForm ($pool_id = 0)
3938{
3939 global $root, $pageno, $tabno, $nextorder;
3940 if ($pool_id <= 0)
3941 {
3942 showError ('Invalid pool_id', __FUNCTION__);
3943 return;
3944 }
3945 showMessageOrError();
3946 $poolInfo = getRSPoolInfo ($pool_id);
3947
3948 if (($rsc = count ($poolInfo['rslist'])))
3949 {
3950 startPortlet ("Manage existing (${rsc})");
3951 echo "<table cellspacing=0 cellpadding=5 align=center class=cooltable>\n";
3952 echo "<tr><th>&nbsp;</th><th>Address</th><th>Port</th><th>configuration</th><th>&nbsp;</th></tr>\n";
3953 $order = 'odd';
3954 foreach ($poolInfo['rslist'] as $rsid => $rs)
3955 {
3956 printOpFormIntro ('updRS', array ('rs_id' => $rsid));
3957 echo "<tr valign=top class=row_${order}><td><a href='${root}process.php?page=${pageno}&tab=${tabno}";
3958 echo "&op=delRS&pool_id=${pool_id}&id=${rsid}'>";
3959 printImageHREF ('delete', 'Delete this real server');
3960 echo "</td><td><input type=text name=rsip value='${rs['rsip']}'></td>";
3961 echo "<td><input type=text name=rsport size=5 value='${rs['rsport']}'></td>";
3962 echo "<td><textarea name=rsconfig>${rs['rsconfig']}</textarea></td><td>";
3963 printImageHREF ('save', 'Save changes', TRUE);
3964 echo "</td></tr></form>\n";
3965 $order = $nextorder[$order];
3966 }
3967 echo "</table>\n";
3968 finishPortlet();
3969 }
3970
3971 startPortlet ('Add one');
3972 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable>\n";
3973 echo "<tr><th>in service</th><th>Address</th><th>Port</th><th>&nbsp;</th></tr>\n";
3974 printOpFormIntro ('addRS');
3975 echo "<tr><td>";
3976 if (getConfigVar ('DEFAULT_IPV4_RS_INSERVICE') == 'yes')
3977 printImageHREF ('inservice', 'in service');
3978 else
3979 printImageHREF ('notinservice', 'NOT in service');
3980 echo "</td><td><input type=text name=remoteip id=remoteip tabindex=1> ";
3981 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\");'>";
3982 printImageHREF ('find', 'pick address');
3983 echo "</a></td>";
3984 $default_port = getConfigVar ('DEFAULT_SLB_RS_PORT');
3985 if ($default_port == 0)
3986 $default_port = '';
3987 echo "<td><input type=text name=rsport size=5 value='${default_port}' tabindex=2></td><td>";
3988 printImageHREF ('add', 'Add new', TRUE, 3);
3989 echo "</td></tr><tr><th colspan=4>configuration</th></tr>";
3990 echo "<tr><td colspan=4><textarea name=rsconfig rows=10 cols=80 tabindex=4></textarea></td></tr>";
3991 echo "</form></table>\n";
3992 finishPortlet();
3993
3994 startPortlet ('Add many');
3995 printOpFormIntro ('addMany');
3996 echo "<table border=0 align=center>\n<tr><td>";
3997 if (getConfigVar ('DEFAULT_IPV4_RS_INSERVICE') == 'yes')
3998 printImageHREF ('inservice', 'in service');
3999 else
4000 printImageHREF ('notinservice', 'NOT in service');
4001 echo "</td><td>Format: ";
4002 $formats = array
4003 (
4004 'ipvs_2' => 'ipvsadm -l -n (address and port)',
4005 'ipvs_3' => 'ipvsadm -l -n (address, port and weight)',
4006 'ssv_2' => 'SSV: &lt;IP address&gt; &lt;port&gt;'
4007 );
4008 printSelect ($formats, 'format');
4009 echo "</td><td><input type=submit value=Parse></td></tr>\n";
4010 echo "<tr><td colspan=3><textarea name=rawtext cols=100 rows=50></textarea></td></tr>\n";
4011 echo "</table>\n";
4012 finishPortlet();
4013}
4014
4015function renderRSPoolLBForm ($pool_id = 0)
4016{
4017 global $root, $pageno, $tabno, $nextorder;
4018 showMessageOrError();
4019
4020 $poolInfo = getRSPoolInfo ($pool_id);
4021 $vs_list = array ();
4022 foreach (getVSList() as $vsid => $vsinfo)
4023 $vs_list[$vsid] = buildVServiceName ($vsinfo) . (empty ($vsinfo['name']) ? '' : " (${vsinfo['name']})");
4024
4025 if (count ($poolInfo['lblist']))
4026 {
4027 startPortlet ('Manage existing (' . count ($poolInfo['lblist']) . ')');
4028 echo "<table cellspacing=0 cellpadding=5 align=center class=cooltable>\n";
4029 echo "<tr><th>&nbsp;</th><th>LB</th><th>VS</th><th>VS config</th><th>RS config</th><th>&nbsp;</th></tr>\n";
4030 $order = 'odd';
4031 foreach ($poolInfo['lblist'] as $object_id => $vslist)
4032 foreach ($vslist as $vs_id => $configs)
4033 {
4034 $oi = getObjectInfo ($object_id);
4035 printOpFormIntro ('updLB', array ('vs_id' => $vs_id, 'object_id' => $object_id));
4036 echo "<tr valign=top class=row_${order}><td><a href='${root}process.php?page=${pageno}&tab=${tabno}&op=delLB&pool_id=${pool_id}&object_id=${object_id}&vs_id=${vs_id}'>";
4037 printImageHREF ('delete', 'Unconfigure');
4038 echo "</a></td>";
4039 echo "<td class=tdleft><a href='${root}?page=object&object_id=${object_id}'>${oi['dname']}</a></td>";
4040 echo "<td class=tdleft><a href='${root}?page=ipv4vs&vs_id=${vs_id}'>";
4041 $vsinfo = getVServiceInfo ($vs_id);
4042 echo buildVServiceName ($vsinfo) . '</a>';
4043 if (!empty ($vsinfo['name']))
4044 echo " (${vsinfo['name']})";
4045 echo "</td><td><textarea name=vsconfig>${configs['vsconfig']}</textarea></td>";
4046 echo "<td><textarea name=rsconfig>${configs['rsconfig']}</textarea></td><td>";
4047 printImageHREF ('save', 'Save changes', TRUE);
4048 echo "</td></tr></form>\n";
4049 $order = $nextorder[$order];
4050 }
4051 echo "</table>\n";
4052 finishPortlet();
4053 }
4054
4055 startPortlet ('Add new');
4056 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable>\n";
4057 printOpFormIntro ('addLB');
4058 echo "<tr valign=top><th>LB / VS</th><td class=tdleft><select name='object_id' tabindex=1>";
4059 foreach (explode (',', getConfigVar ('NATV4_PERFORMERS')) as $type)
4060 foreach (getNarrowObjectList ($type) as $object)
4061 echo "<option value='${object['id']}'>${object['dname']}</option>";
4062 echo "</select> ";
4063 printSelect ($vs_list, 'vs_id');
4064 echo "</td><td>";
4065 printImageHREF ('add', 'Configure LB', TRUE, 2);
4066 echo "</td></tr>\n";
4067 echo "<tr><th>VS config</th><td colspan=2><textarea name=vsconfig rows=10 cols=80></textarea></td></tr>";
4068 echo "<tr><th>RS config</th><td colspan=2><textarea name=rsconfig rows=10 cols=80></textarea></td></tr>";
4069 echo "</form></table>\n";
4070 finishPortlet();
4071}
4072
4073function renderVServiceLBForm ($vs_id = 0)
4074{
4075 global $root, $pageno, $tabno, $nextorder;
4076 showMessageOrError();
4077 $vsinfo = getVServiceInfo ($vs_id);
4078
4079 if (count ($vsinfo['rspool']))
4080 {
4081 startPortlet ('Manage existing (' . count ($vsinfo['rspool']) . ')');
4082 echo "<table cellspacing=0 cellpadding=5 align=center class=cooltable>\n";
4083 echo "<tr><th>&nbsp;</th><th>LB</th><th>RS pool</th><th>VS config</th><th>RS config</th><th>&nbsp;</th></tr>\n";
4084 $order = 'odd';
4085 foreach ($vsinfo['rspool'] as $pool_id => $rspinfo)
4086 foreach ($rspinfo['lblist'] as $object_id => $configs)
4087 {
4088 $oi = getObjectInfo ($object_id);
4089 printOpFormIntro ('updLB', array ('pool_id' => $pool_id, 'object_id' => $object_id));
4090 echo "<tr valign=top class=row_${order}><td><a href='${root}process.php?page=${pageno}&tab=${tabno}&op=delLB&pool_id=${pool_id}&object_id=${object_id}&vs_id=${vs_id}'>";
4091 printImageHREF ('delete', 'Unconfigure');
4092 echo "</a></td>";
4093 echo "<td class=tdleft><a href='${root}?page=object&object_id=${object_id}'>${oi['dname']}</a></td>";
4094 echo "<td class=tdleft><a href='${root}?page=ipv4rsp&pool_id=${pool_id}'>${rspinfo['name']}</a></td>";
4095 echo "<td><textarea name=vsconfig>${configs['vsconfig']}</textarea></td>";
4096 echo "<td><textarea name=rsconfig>${configs['rsconfig']}</textarea></td><td>";
4097 printImageHREF ('save', 'Save changes', TRUE);
4098 echo "</td></tr></form>\n";
4099 $order = $nextorder[$order];
4100 }
4101 echo "</table>\n";
4102 finishPortlet();
4103 }
4104
4105 $rsplist = array();
4106 foreach (getRSPoolList() as $pool_id => $poolInfo)
4107 $rsplist[$pool_id] = $poolInfo['name'];
4108 startPortlet ('Add new');
4109 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable>\n";
4110 printOpFormIntro ('addLB');
4111 echo "<tr valign=top><th>LB / RS pool</th><td class=tdleft><select name='object_id' tabindex=1>";
4112 foreach (explode (',', getConfigVar ('NATV4_PERFORMERS')) as $type)
4113 foreach (getNarrowObjectList ($type) as $object)
4114 echo "<option value='${object['id']}'>${object['dname']}</option>";
4115 echo "</select> ";
4116 printSelect ($rsplist, 'pool_id');
4117 echo "</td><td>";
4118 printImageHREF ('add', 'Configure LB', TRUE, 2);
4119 echo "</td></tr>\n";
4120 echo "<tr><th>VS config</th><td colspan=2><textarea name=vsconfig rows=10 cols=80></textarea></td></tr>";
4121 echo "<tr><th>RS config</th><td colspan=2><textarea name=rsconfig rows=10 cols=80></textarea></td></tr>";
4122 echo "</form></table>\n";
4123 finishPortlet();
4124}
4125
4126function renderRSPool ($pool_id = 0)
4127{
4128 global $root;
4129 if ($pool_id <= 0)
4130 {
4131 showError ('Invalid pool_id', __FUNCTION__);
4132 return;
4133 }
4134 $poolInfo = getRSPoolInfo ($pool_id);
4135 if ($poolInfo == NULL)
4136 {
4137 showError ('getRSPoolInfo() returned NULL', __FUNCTION__);
4138 return;
4139 }
4140
4141 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>";
4142 if (!empty ($poolInfo['name']))
4143 echo "<tr><td colspan=2 align=center><h1>{$poolInfo['name']}</h1></td></tr>";
4144 echo "<tr><td class=pcleft>\n";
4145
4146 startPortlet ('Configuration');
4147 echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
4148 if (!empty ($poolInfo['name']))
4149 echo "<tr><th width='50%' class=tdright>Pool name:</th><td class=tdleft>${poolInfo['name']}</td></tr>\n";
4150 echo "<tr><th width='50%' class=tdright>Real servers:</th><td class=tdleft>" . count ($poolInfo['rslist']) . "</td></tr>\n";
4151 echo "<tr><th width='50%' class=tdright>Load balancers:</th><td class=tdleft>" . count ($poolInfo['lblist']) . "</td></tr>\n";
4152 printTagTRs ("${root}?page=ipv4rsplist&");
4153 echo "</table>";
4154 finishPortlet();
4155
4156 startPortlet ('Load balancers (' . count ($poolInfo['lblist']) . ')');
4157 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable>\n";
4158 echo "<tr><th>VS</th><th>LB</th><th>VS config</th><th>RS config</th></tr>";
4159 foreach ($poolInfo['lblist'] as $object_id => $vslist)
4160 foreach ($vslist as $vs_id => $configs)
4161 {
4162 $oi = getObjectInfo ($object_id);
4163 $vi = getVServiceInfo ($vs_id);
4164 echo "<tr valign=top><td class=tdleft><a href='${root}?page=ipv4vs&vs_id=${vs_id}'>";
4165 echo buildVServiceName ($vi);
4166 echo "</a></td><td class=tdleft><a href='${root}?page=object&object_id=${object_id}'>${oi['dname']}</a></td>";
4167 echo "<td class=tdleft><pre>${configs['vsconfig']}</pre></td>";
4168 echo "<td class=tdleft><pre>${configs['rsconfig']}</pre></td></tr>\n";
4169 }
4170 echo "</table>\n";
4171 finishPortlet();
4172
4173 echo "</td><td class=pcright>\n";
4174
4175 startPortlet ('Real servers (' . count ($poolInfo['rslist']) . ')');
4176 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable>\n";
4177 echo "<tr><th>in service</th><th>address</th><th>port</th><th>RS configuration</th></tr>";
4178 foreach ($poolInfo['rslist'] as $rs)
4179 {
4180 echo "<tr valign=top><td align=center>";
4181 if ($rs['inservice'] == 'yes')
4182 printImageHREF ('inservice', 'in service');
4183 else
4184 printImageHREF ('notinservice', 'NOT in service');
4185 echo "</td><td class=tdleft><a href='${root}?page=ipaddress&ip=${rs['rsip']}'>${rs['rsip']}</a></td>";
4186 echo "<td class=tdleft>${rs['rsport']}</td><td class=tdleft><pre>${rs['rsconfig']}</pre></td></tr>\n";
4187 }
4188 echo "</table>\n";
4189 finishPortlet();
4190
4191 echo "</td></tr></table>\n";
4192}
4193
4194function renderVSList ()
4195{
4196 global $root, $pageno, $nextorder;
4197 $tagfilter = getTagFilter();
4198 $vslist = getVSList ($tagfilter, getTFMode());
4199 echo "<table border=0 class=objectview>\n";
4200 echo "<tr><td class=pcleft>";
4201
4202 startPortlet ('Virtual services (' . count ($vslist) . ')');
4203 echo "<table class=widetable border=0 cellpadding=10 cellspacing=0 align=center>\n";
4204 echo "<tr><th>endpoint, name, tags</th><th>VS configuration</th><th>RS configuration</th></tr>";
4205 $order = 'odd';
4206 foreach ($vslist as $vsid => $vsinfo)
4207 {
4208 $vstags = loadIPv4VSTags ($vsid);
4209 echo "<tr align=left valign=top class=row_${order}><td class=tdleft><a href='${root}?page=ipv4vs&vs_id=${vsid}'>" . buildVServiceName ($vsinfo);
4210 echo "</a><br>${vsinfo['name']}";
4211 if (count ($vstags))
4212 {
4213 echo '<br>';
4214 echo serializeTags ($vstags, "${root}?page=${pageno}&tab=default&");
4215 }
4216 echo "</td><td><pre>${vsinfo['vsconfig']}</pre></td>";
4217 echo "<td><pre>${vsinfo['rsconfig']}</pre></td>";
4218 echo "</tr>\n";
4219 $order = $nextorder[$order];
4220 }
4221 echo "</table>";
4222 finishPortlet();
4223 echo '</td><td class=pcright>';
4224 renderTagFilterPortlet ($tagfilter, 'ipv4vs');
4225 echo '</td></tr></table>';
4226}
4227
4228function renderVSListEditForm ()
4229{
4230 global $root, $pageno, $tabno, $nextorder;
4231 showMessageOrError();
4232 $protocols = array ('TCP' => 'TCP', 'UDP' => 'UDP');
4233
4234 startPortlet ('Add new');
4235 printOpFormIntro ('add');
4236 echo "<table class=widetable border=0 cellpadding=10 cellspacing=0 align=center>\n";
4237 echo "<tr><th>&nbsp;</th><th>VIP</th><th>port</th><th>proto</th><th>name</th><th>&nbsp;</th></tr>";
4238 echo "<tr valign=top><td>&nbsp;</td>";
4239 echo "<td><input type=text name=vip tabindex=1></td>";
4240 $default_port = getConfigVar ('DEFAULT_SLB_VS_PORT');
4241 if ($default_port == 0)
4242 $default_port = '';
4243 echo "<td><input type=text name=vport size=5 value='${default_port}' tabindex=2></td><td>";
4244 printSelect ($protocols, 'proto', 'TCP');
4245 echo "</td>";
4246 echo "<td><input type=text name=name tabindex=4></td><td>";
4247 printImageHREF ('CREATE', 'create virtual service', TRUE);
4248 echo "</td></tr><tr><th>VS configuration</th><td colspan=4 class=tdleft><textarea name=vsconfig rows=10 cols=80></textarea></td>\n";
4249 echo "<td rowspan=2><h3>assign tags</h3>";
4250 renderTagSelect();
4251 echo "</td></tr>";
4252 echo "<tr><th>RS configuration</th><td colspan=4 class=tdleft><textarea name=rsconfig rows=10 cols=80></textarea></td></tr>\n";
4253 echo "</table>";
4254 echo "</form>\n";
4255 finishPortlet();
4256
4257 $vslist = getVSList();
4258 if (!count ($vslist))
4259 return;
4260 startPortlet ('Manage existing (' . count ($vslist) . ')');
4261 echo "<table class=cooltable border=0 cellpadding=10 cellspacing=0 align=center>\n";
4262 echo "<tr><th>&nbsp;</th><th>VIP</th><th>port</th><th>proto</th><th>name</th>";
4263 echo "<th>VS configuration</th><th>RS configuration</th><th></th></tr>";
4264 $order = 'odd';
4265 foreach ($vslist as $vsid => $vsinfo)
4266 {
4267 printOpFormIntro ('upd', array ('vs_id' => $vsid));
4268 echo "<tr valign=top class=row_${order}><td>";
4269 if ($vsinfo['poolcount'])
4270 printImageHREF ('nodelete', 'there are ' . $vsinfo['poolcount'] . ' RS pools configured');
4271 else
4272 {
4273 echo "<a href='${root}process.php?page=${pageno}&tab=${tabno}&op=del&vs_id=${vsid}'>";
4274 printImageHREF ('delete', 'delete virtual service');
4275 echo '</a>';
4276 }
4277 echo "</td><td class=tdleft><input type=text name=vip value='${vsinfo['vip']}'></td>";
4278 echo "<td class=tdleft><input type=text name=vport size=5 value='${vsinfo['vport']}'></td>";
4279 echo "<td class=tdleft>";
4280 printSelect ($protocols, 'proto', $vsinfo['proto']);
4281 echo "</td>";
4282 echo "<td class=tdleft><input type=text name=name value='${vsinfo['name']}'></td>";
4283 echo "<td><textarea name=vsconfig>${vsinfo['vsconfig']}</textarea></td>";
4284 echo "<td><textarea name=rsconfig>${vsinfo['rsconfig']}</textarea></td><td>";
4285 printImageHREF ('save', 'save changes', TRUE);
4286 echo "</td></tr></form>\n";
4287 $order = $nextorder[$order];
4288 }
4289 echo "</table>";
4290 finishPortlet();
4291}
4292
4293function renderRSPoolList ()
4294{
4295 global $root, $pageno, $nextorder;
4296 $tagfilter = getTagFilter();
4297 $pool_list = getRSPoolList ($tagfilter, getTFMode());
4298 if ($pool_list === NULL)
4299 {
4300 showError ('getRSPoolList() failed', __FUNCTION__);
4301 return;
4302 }
4303 echo "<table border=0 class=objectview>\n";
4304 echo "<tr><td class=pcleft>";
4305 startPortlet ('RS pools (' . count ($pool_list) . ')');
4306 echo "<table class=widetable border=0 cellpadding=10 cellspacing=0 align=center>\n";
4307 echo "<tr><th>name, refcnt, tags</th><th>VS configuration</th><th>RS configuration</th></tr>";
4308 $order = 'odd';
4309 foreach ($pool_list as $pool_id => $pool_info)
4310 {
4311 $pooltags = loadIPv4RSPoolTags ($pool_id);
4312 echo "<tr valign=top class=row_${order}><td class=tdleft>";
4313 echo "<a href='${root}?page=ipv4rsp&pool_id=${pool_id}'>" . (empty ($pool_info['name']) ? 'ANONYMOUS' : $pool_info['name']) . '</a>';
4314 echo ($pool_info['refcnt'] ? ", ${pool_info['refcnt']}" : '');
4315 if (count ($pooltags))
4316 {
4317 echo '<br>';
4318 echo serializeTags ($pooltags, "${root}?page=${pageno}&tab=default&");
4319 }
4320 echo "</td><td class=tdleft><pre>${pool_info['vsconfig']}</pre></td>";
4321 echo "<td class=tdleft><pre>${pool_info['rsconfig']}</pre></td>";
4322 echo "</tr>\n";
4323 $order = $nextorder[$order];
4324 }
4325 echo "</table>";
4326 finishPortlet ();
4327 echo '</td><td class=pcright>';
4328 renderTagFilterPortlet ($tagfilter, 'ipv4rspool');
4329 echo '</td></tr></table>';
4330}
4331
4332function editRSPools ()
4333{
4334 global $root, $pageno, $tabno, $nextorder;
4335 showMessageOrError();
4336
4337 startPortlet ('Add new');
4338 printOpFormIntro ('add');
4339 echo "<table class=widetable border=0 cellpadding=10 cellspacing=0 align=center>\n";
4340 echo "<tr><th>name</th>";
4341 echo "<td class=tdleft><input type=text name=name tabindex=1></td><td>";
4342 printImageHREF ('CREATE', 'create real server pool', TRUE);
4343 echo "</td></tr><tr><th>VS configuration</th><td><textarea name=vsconfig rows=10 cols=80></textarea></td>";
4344 echo "<td rowspan=2><h3>assign tags</h3>";
4345 renderTagSelect();
4346 echo "</td></tr>";
4347 echo "<tr><th>RS configuration</th><td><textarea name=rsconfig rows=10 cols=80></textarea></td></tr>";
4348 echo "</table></form>";
4349 finishPortlet();
4350
4351 $pool_list = getRSPoolList();
4352 if (!count ($pool_list))
4353 return;
4354 startPortlet ('Manage existing (' . count ($pool_list) . ')');
4355 echo "<table class=cooltable border=0 cellpadding=10 cellspacing=0 align=center>\n";
4356 echo "<tr><th>&nbsp;</th><th>name</th><th>VS configuration</th><th>RS configuration</th><th>&nbsp;</th></tr>";
4357 $order='odd';
4358 foreach ($pool_list as $pool_id => $pool_info)
4359 {
4360 printOpFormIntro ('upd', array ('pool_id' => $pool_id));
4361 echo "<tr valign=top class=row_${order}><td>";
4362 if ($pool_info['refcnt'])
4363 printImageHREF ('nodelete', 'RS pool is used ' . $pool_info['refcnt'] . ' time(s)');
4364 else
4365 {
4366 echo "<a href='${root}process.php?page=${pageno}&tab=${tabno}&op=del&pool_id=${pool_id}'>";
4367 printImageHREF ('delete', 'delete real server pool');
4368 echo '</a>';
4369 }
4370 echo "</td>";
4371 echo "<td class=tdleft><input type=text name=name value='${pool_info['name']}'></td>";
4372 echo "<td><textarea name=vsconfig>${pool_info['vsconfig']}</textarea></td>";
4373 echo "<td><textarea name=rsconfig>${pool_info['rsconfig']}</textarea></td><td>";
4374 printImageHREF ('save', 'save changes', TRUE);
4375 echo "</td></tr></form>\n";
4376 $order = $nextorder[$order];
4377 }
4378 echo "</table>";
4379 finishPortlet();
4380}
4381
4382function renderRealServerList ()
4383{
4384 global $root, $nextorder;
4385 $rslist = getRSList ();
4386 $pool_list = getRSPoolList ();
4387 echo "<table class=widetable border=0 cellpadding=10 cellspacing=0 align=center>\n";
4388 echo "<tr><th>RS pool</th><th>in service</th><th>real IP address</th><th>real port</th><th>RS configuration</th></tr>";
4389 $order = 'even';
4390 $last_pool_id = 0;
4391 foreach ($rslist as $rsinfo)
4392 {
4393 if ($last_pool_id != $rsinfo['rspool_id'])
4394 {
4395 $order = $nextorder[$order];
4396 $last_pool_id = $rsinfo['rspool_id'];
4397 }
4398 echo "<tr valign=top class=row_${order}><td><a href='${root}?page=ipv4rsp&pool_id=${rsinfo['rspool_id']}'>";
4399 echo empty ($pool_list[$rsinfo['rspool_id']]['name']) ? 'ANONYMOUS' : $pool_list[$rsinfo['rspool_id']]['name'];
4400 echo '</a></td><td align=center>';
4401 if ($rsinfo['inservice'] == 'yes')
4402 printImageHREF ('inservice', 'in service');
4403 else
4404 printImageHREF ('notinservice', 'NOT in service');
4405 echo "</td><td><a href='${root}?page=ipaddress&ip=${rsinfo['rsip']}'>${rsinfo['rsip']}</a></td>";
4406 echo "<td>${rsinfo['rsport']}</td>";
4407 echo "<td><pre>${rsinfo['rsconfig']}</pre></td>";
4408 echo "</tr>\n";
4409 }
4410 echo "</table>";
4411}
4412
4413function renderLBList ()
4414{
4415 global $root, $nextorder;
4416 echo "<table class=widetable border=0 cellpadding=10 cellspacing=0 align=center>\n";
4417 echo "<tr><th>Object</th><th>RS pools configured</th></tr>";
4418 $oicache = array();
4419 $order = 'odd';
4420 foreach (getLBList() as $object_id => $poolcount)
4421 {
4422 if (!isset ($oicache[$object_id]))
4423 $oicache[$object_id] = getObjectInfo ($object_id);
4424 echo "<tr valign=top class=row_${order}><td><a href='${root}?page=object&object_id=${object_id}'>";
4425 echo $oicache[$object_id]['dname'] . '</a></td>';
4426 echo "<td>${poolcount}</td></tr>";
4427 $order = $nextorder[$order];
4428 }
4429 echo "</table>";
4430}
4431
4432function renderRSPoolRSInServiceForm ($pool_id = 0)
4433{
4434 if ($pool_id <= 0)
4435 {
4436 showError ('Invalid pool_id', __FUNCTION__);
4437 return;
4438 }
4439 showMessageOrError();
4440 $poolInfo = getRSPoolInfo ($pool_id);
4441 printOpFormIntro ('upd', array ('rscount' => count ($poolInfo['rslist'])));
4442 echo "<table class=widetable border=0 cellpadding=10 cellspacing=0 align=center>\n";
4443 echo "<tr><th>RS address</th><th>RS port</th><th>RS configuration</th><th>in service</th></tr>\n";
4444 $recno = 1;
4445 foreach ($poolInfo['rslist'] as $rs_id => $rsinfo)
4446 {
4447 echo "<input type=hidden name=rsid_${recno} value=${rs_id}>\n";
4448 echo "<tr valign=top><td>${rsinfo['rsip']}</td><td>${rsinfo['rsport']}</td><td><pre>${rsinfo['rsconfig']}</pre></td>";
4449 echo "<td><input type=checkbox tabindex=${recno} name=inservice_${recno}" . ($rsinfo['inservice'] == 'yes' ? ' checked' : '') . "></td>";
4450 echo "</tr>";
4451 $recno++;
4452 }
4453 echo "<tr><td colspan=4 align=center>";
4454 printImageHREF ('SAVE', 'Save changes', TRUE, $recno);
4455 echo "</td></tr></table>\n</form>";
4456}
4457
4458function renderLivePTR ($id = 0)
4459{
4460 if ($id == 0)
4461 {
4462 showError ("Invalid argument", __FUNCTION__);
4463 return;
4464 }
4465 showMessageOrError();
4466 if (isset($_REQUEST['pg']))
4467 $page = $_REQUEST['pg'];
4468 else
4469 $page=0;
4470 global $root, $pageno, $tabno;
4471 $maxperpage = getConfigVar ('IPV4_ADDRS_PER_PAGE');
4472 $range = getIPv4Network ($id);
4473 echo "<center><h1>${range['ip']}/${range['mask']}</h1><h2>${range['name']}</h2></center>\n";
4474
4475 echo "<table class=objview border=0 width='100%'><tr><td class=pcleft>";
4476 startPortlet ('current records');
4477 $startip = $range['ip_bin'] & $range['mask_bin'];
4478 $endip = $range['ip_bin'] | $range['mask_bin_inv'];
4479 $realstartip = $startip;
4480 $realendip = $endip;
4481 $numpages = 0;
4482 if ($endip - $startip > $maxperpage)
4483 {
4484 $numpages = ($endip - $startip) / $maxperpage;
4485 $startip = $startip + $page * $maxperpage;
4486 $endip = $startip + $maxperpage - 1;
4487 }
4488 echo "<center>";
4489 if ($numpages)
4490 echo '<h3>' . long2ip ($startip) . ' ~ ' . long2ip ($endip) . '</h3>';
4491 for ($i=0; $i<$numpages; $i++)
4492 if ($i == $page)
4493 echo "<b>$i</b> ";
4494 else
4495 echo "<a href='${root}?page=${pageno}&tab=${tabno}&id=$id&pg=$i'>$i</a> ";
4496 echo "</center>";
4497
4498 // FIXME: address counter could be calculated incorrectly in some cases
4499 printOpFormIntro ('importPTRData', array ('addrcount' => ($endip - $startip + 1)));
4500
4501 echo "<table class='widetable' border=0 cellspacing=0 cellpadding=5 align='center'>\n";
4502 echo "<tr><th>address</th><th>current name</th><th>DNS data</th><th>import</th></tr>\n";
4503 $idx = 1;
4504 $cnt_match = $cnt_mismatch = $cnt_missing = 0;
4505 for ($ip = $startip; $ip <= $endip; $ip++)
4506 {
4507 // Find the (optional) DB name and the (optional) DNS record, then
4508 // compare values and produce a table row depending on the result.
4509 $addr = isset ($range['addrlist'][$ip]) ? $range['addrlist'][$ip] : array ('name' => '', 'reserved' => 'no');
4510 $straddr = long2ip ($ip);
4511 $ptrname = gethostbyaddr ($straddr);
4512 if ($ptrname == $straddr)
4513 $ptrname = '';
4514 echo "<input type=hidden name=addr_${idx} value=${straddr}>\n";
4515 echo "<input type=hidden name=descr_${idx} value=${ptrname}>\n";
4516 echo "<input type=hidden name=rsvd_${idx} value=${addr['reserved']}>\n";
4517 echo '<tr';
4518 $print_cbox = FALSE;
4519 if ($addr['name'] == $ptrname)
4520 {
4521 if (!empty ($ptrname))
4522 {
4523 echo ' class=trok';
4524 $cnt_match++;
4525 }
4526 }
4527 elseif (empty ($addr['name']) or empty ($ptrname))
4528 {
4529 echo ' class=trwarning';
4530 $print_cbox = TRUE;
4531 $cnt_missing++;
4532 }
4533 else
4534 {
4535 echo ' class=trerror';
4536 $print_cbox = TRUE;
4537 $cnt_mismatch++;
4538 }
4539 echo "><td class='tdleft";
4540 if (!empty ($range['addrlist'][$ip]['class']))
4541 echo ' ' . $range['addrlist'][$ip]['class'];
4542 echo "'><a href='${root}?page=ipaddress&ip=${straddr}'>${straddr}</a></td>";
4543 echo "<td class=tdleft>${addr['name']}</td><td class=tdleft>${ptrname}</td><td>";
4544 if ($print_cbox)
4545 echo "<input type=checkbox name=import_${idx} tabindex=${idx}>";
4546 else
4547 echo '&nbsp;';
4548 echo "</td></tr>\n";
4549 $idx++;
4550 }
4551 echo "<tr><td colspan=4 align=center><input type=submit value='Import selected records'></td></tr>";
4552 echo "</table>";
4553 echo "</form>";
4554 finishPortlet();
4555
4556 echo "</td><td class=pcright>";
4557
4558 startPortlet ('stats');
4559 echo "<table border=0 width='100%' cellspacing=0 cellpadding=2>";
4560 echo "<tr class=trok><th class=tdright>Exact matches:</th><td class=tdleft>${cnt_match}</td></tr>\n";
4561 echo "<tr class=trwarning><th class=tdright>Missing from DB/DNS:</th><td class=tdleft>${cnt_missing}</td></tr>\n";
4562 if ($cnt_mismatch)
4563 echo "<tr class=trerror><th class=tdright>Mismatches:</th><td class=tdleft>${cnt_mismatch}</td></tr>\n";
4564 echo "</table>\n";
4565 finishPortlet();
4566
4567 echo "</td></tr></table>\n";
4568}
4569
4570function renderAutoPortsForm ($object_id = 0)
4571{
4572 if ($object_id <= 0)
4573 {
4574 showError ('Invalid object_id', __FUNCTION__);
4575 return;
4576 }
4577 // If the below call has any data to display, the non-default redirection from the generator
4578 // has failed. Don't ignore the message log anyway.
4579 showMessageOrError();
4580 $info = getObjectInfo ($object_id);
4581 $ptlist = readChapter ('PortType');
4582 echo "<table class='widetable' border=0 cellspacing=0 cellpadding=5 align='center'>\n";
4583 echo "<caption>The following ports can be quickly added:</caption>";
4584 echo "<tr><th>type</th><th>name</th></tr>";
4585 foreach (getAutoPorts ($info['objtype_id']) as $autoport)
4586 echo "<tr><td>" . $ptlist[$autoport['type']] . "</td><td>${autoport['name']}</td></tr>";
4587 printOpFormIntro ('generate');
4588 echo "<tr><td colspan=2 align=center>";
4589 echo "<input type=submit value='Generate'>";
4590 echo "</td></tr>";
4591 echo "</table></form>";
4592}
4593
4594function renderTagRowForViewer ($taginfo, $level = 0)
4595{
4596 echo '<tr><td align=left>';
4597 echo '<div title="id = ' . $taginfo['id'] . '">';
4598 for ($i = 0; $i < $level; $i++)
4599 printImageHREF ('spacer');
4600 echo $taginfo['tag'] . '</div>';
4601 echo "</td></tr>\n";
4602 foreach ($taginfo['kids'] as $kid)
4603 renderTagRowForViewer ($kid, $level + 1);
4604}
4605
4606// FIXME: generated hyperlink must depend on the realm given
4607function renderTagRowForCloud ($taginfo, $realm, $level = 0)
4608{
4609 global $root;
4610 echo '<tr><td align=left>';
4611 for ($i = 0; $i < $level; $i++)
4612 printImageHREF ('spacer');
4613 echo "<a href='${root}?page=objgroup&group_id=0&tagfilter[]=${taginfo['id']}'>";
4614 echo $taginfo['tag'] . '</a>';
4615 if (isset ($taginfo['refcnt'][$realm]))
4616 echo ' (' . $taginfo['refcnt'][$realm] . ')';
4617 echo "</td></tr>\n";
4618 foreach ($taginfo['kids'] as $kid)
4619 renderTagRowForCloud ($kid, $realm, $level + 1);
4620}
4621
4622function renderTagRowForEditor ($taginfo, $level = 0)
4623{
4624 global $root, $pageno, $tabno, $taglist;
4625 echo '<tr><td class=tdleft>';
4626 for ($i = 0; $i < $level; $i++)
4627 printImageHREF ('spacer');
4628 $nrefs = 0;
4629 foreach ($taginfo['refcnt'] as $part)
4630 $nrefs += $part;
4631 if ($nrefs > 0 or count ($taginfo['kids']) > 0)
4632 printImageHREF ('nodelete', "${nrefs} references, " . count ($taginfo['kids']) . ' sub-tags');
4633 else
4634 {
4635 echo "<a href='${root}process.php?page=${pageno}&tab=${tabno}&op=destroyTag&tag_id=${taginfo['id']}'>";
4636 printImageHREF ('delete', 'Delete tag');
4637 echo "</a>";
4638 }
4639 echo "</td>\n<td>";
4640 printOpFormIntro ('updateTag', array ('tag_id' => $taginfo['id']));
4641 echo "<input type=text name=tag_name ";
4642 echo "value='${taginfo['tag']}'></td><td><select name=parent_id>";
4643 echo "<option value=0>-- NONE --</option>\n";
4644 foreach ($taglist as $tlinfo)
4645 {
4646 echo "<option value=${tlinfo['id']}" . ($tlinfo['id'] == $taginfo['parent_id'] ? ' selected' : '');
4647 echo ">${tlinfo['tag']}</option>";
4648 }
4649 echo "</select></td><td>";
4650 printImageHREF ('save', 'Save changes', TRUE);
4651 echo "</form></td></tr>\n";
4652 foreach ($taginfo['kids'] as $kid)
4653 renderTagRowForEditor ($kid, $level + 1);
4654}
4655
4656function renderTagTree ()
4657{
4658 global $tagtree;
4659 echo '<center><table>';
4660 foreach ($tagtree as $taginfo)
4661 {
4662 echo '<tr>';
4663 renderTagRowForViewer ($taginfo);
4664 echo "</tr>\n";
4665 }
4666 echo '</table></center>';
4667}
4668
4669function renderTagCloud ($realm = '')
4670{
4671 global $taglist, $tagtree;
4672 echo '<table>';
4673 foreach (getObjectiveTagTree ($tagtree, $realm) as $taginfo)
4674 {
4675 echo '<tr>';
4676 renderTagRowForCloud ($taginfo, $realm);
4677 echo "</tr>\n";
4678 }
4679 echo '</table>';
4680}
4681
4682function renderTagTreeEditor ()
4683{
4684 global $taglist, $tagtree;
4685 showMessageOrError();
4686 echo "<table class=objview border=0 width='100%'><tr><td class=pcleft>";
4687 startPortlet ('tag tree');
4688 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable>\n";
4689 echo "<tr><th>&nbsp;</th><th>tag</th><th>parent</th><th>&nbsp;</th></tr>\n";
4690 foreach ($tagtree as $taginfo)
4691 renderTagRowForEditor ($taginfo);
4692 printOpFormIntro ('createTag');
4693 echo "<tr><td class=tdleft>";
4694 printImageHREF ('grant', 'Create tag', TRUE, 102);
4695 echo '</td><td><input type=text name=tag_name tabindex=100></td><td><select name=parent_id tabindex=101>';
4696 echo "<option value=0>-- NONE --</option>\n";
4697 foreach ($taglist as $taginfo)
4698 echo "<option value=${taginfo['id']}>${taginfo['tag']}</option>";
4699 echo "</select></td><td>&nbsp;</td></tr>";
4700 echo "</form>\n";
4701 echo '</table>';
4702 finishPortlet();
4703
4704 echo "</td><td><td class=pcright>";
4705
4706 startPortlet ('fallen leaves');
4707 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable>\n";
4708 echo "<tr><th>tag</th><th>parent</th><th>&nbsp;</th></tr>\n";
4709 foreach (getOrphanedTags() as $taginfo)
4710 {
4711 echo '<tr><td>';
4712 printOpFormIntro ('updateTag', array ('tag_id' => $taginfo['id'], 'tag_name' => $taginfo['tag']));
4713 echo "${taginfo['tag']}</td><td><select name=parent_id>";
4714 echo "<option value=0>-- NONE --</option>\n";
4715 foreach ($taglist as $tlinfo)
4716 {
4717 echo "<option value=${tlinfo['id']}" . ($tlinfo['id'] == $taglist[$taginfo['id']]['parent_id'] ? ' selected' : '');
4718 echo ">${tlinfo['tag']}</option>";
4719 }
4720 echo "</select></td><td>";
4721 printImageHREF ('save', 'Save changes', TRUE);
4722 echo "</form></td></tr>\n";
4723 }
4724 echo '</table>';
4725 finishPortlet();
4726 echo "</td></tr></table>";
4727}
4728
4729// Output a sequence of OPTION elements, selecting those, which are present on the
4730// explicit tags list.
4731function renderTagOption ($taginfo, $level = 0)
4732{
4733 global $expl_tags;
4734 $selected = tagOnChain ($taginfo, $expl_tags) ? ' selected' : '';
4735 echo '<option value=' . $taginfo['id'] . "${selected}>";
4736 for ($i = 0; $i < $level; $i++)
4737 echo '-- ';
4738 echo $taginfo['tag'] . "</option>\n";
4739 foreach ($taginfo['kids'] as $kid)
4740 renderTagOption ($kid, $level + 1);
4741}
4742
4743// Idem, but select those, which are shown on the $_REQUEST['tagfiler'] array.
4744// Ignore tag ids, which can't be found on the tree.
4745function renderTagOptionForFilter ($taginfo, $tagfilter, $realm, $level = 0)
4746{
4747 $selected = tagOnIdList ($taginfo, $tagfilter) ?' selected' : '';
4748 echo '<option value=' . $taginfo['id'] . "${selected}>";
4749 for ($i = 0; $i < $level; $i++)
4750 echo '-- ';
4751 echo $taginfo['tag'] . (isset ($taginfo['refcnt'][$realm]) ? ' (' . $taginfo['refcnt'][$realm] . ')' : '') . "</option>\n";
4752 foreach ($taginfo['kids'] as $kid)
4753 renderTagOptionForFilter ($kid, $tagfilter, $realm, $level + 1);
4754}
4755
4756function renderObjectTags ($id)
4757{
4758 renderEntityTagChainEditor ('object', 'object_id', $id);
4759}
4760
4761function renderIPv4PrefixTags ($id)
4762{
4763 renderEntityTagChainEditor ('ipv4net', 'id', $id);
4764}
4765
4766function renderRackTags ($id)
4767{
4768 renderEntityTagChainEditor ('rack', 'rack_id', $id);
4769}
4770
4771function renderIPv4VSTags ($id)
4772{
4773 renderEntityTagChainEditor ('ip4vs', 'vs_id', $id);
4774}
4775
4776function renderIPv4RSPoolTags ($id)
4777{
4778 renderEntityTagChainEditor ('ip4rspool', 'pool_id', $id);
4779}
4780
4781function renderUserTags ($id)
4782{
4783 renderEntityTagChainEditor ('user', 'user_id', $id);
4784}
4785
4786function renderEntityTagChainEditor ($entity_realm = '', $bypass_name, $entity_id = 0)
4787{
4788 global $tagtree, $expl_tags;
4789 if ($entity_realm == '' or $entity_id <= 0)
4790 {
4791 showError ('Invalid or missing arguments', __FUNCTION__);
4792 return;
4793 }
4794 showMessageOrError();
4795 startPortlet ('Tag list');
4796 if (count ($expl_tags))
4797 echo '<h3>(' . serializeTags ($expl_tags) . ')</h3>';
4798 echo '<table border=0 align=center>';
4799 echo '<tr><td colspan=2><h4>hold Ctrl to select more, than one</h4></td></tr>';
4800 printOpFormIntro ('saveTags', array ($bypass_name => $entity_id));
4801 echo '<tr><td colspan=2><select name=taglist[] multiple size=' . getConfigVar ('MAXSELSIZE') . '>';
4802 foreach ($tagtree as $taginfo)
4803 renderTagOption ($taginfo);
4804 echo '</select></td></tr><tr><td>';
4805 printImageHREF ('SAVE', 'Save changes', TRUE);
4806 echo "</form></td><td>";
4807 printOpFormIntro ('saveTags', array ($bypass_name => $entity_id, 'taglist[]' => ''));
4808 printImageHREF ('CLEAR', 'Reset all tags', TRUE);
4809 echo '</form></td></tr></table>';
4810 finishPortlet();
4811}
4812
4813function printTagTRs ($baseurl = '')
4814{
4815 global $expl_tags, $impl_tags, $auto_tags;
4816 if (getConfigVar ('SHOW_EXPLICIT_TAGS') == 'yes' and count ($expl_tags))
4817 {
4818 echo "<tr><th width='50%' class=tag_list_th>Explicit tags:</th><td class=tdleft>";
4819 echo serializeTags ($expl_tags, $baseurl) . "</td></tr>\n";
4820 }
4821 if (getConfigVar ('SHOW_IMPLICIT_TAGS') == 'yes' and count ($impl_tags))
4822 {
4823 echo "<tr><th width='50%' class=tag_list_th>Implicit tags:</th><td class=tdleft>";
4824 echo serializeTags ($impl_tags, $baseurl) . "</td></tr>\n";
4825 }
4826 if (getConfigVar ('SHOW_AUTOMATIC_TAGS') == 'yes' and count ($auto_tags))
4827 {
4828 echo "<tr><th width='50%' class=tag_list_th>Automatic tags:</th><td class=tdleft>";
4829 echo serializeTags ($auto_tags) . "</td></tr>\n";
4830 }
4831}
4832
4833// Detect, filter and return requested tag filter mode: either 'and' or 'or'.
4834function getTFMode ()
4835{
4836 if (isset ($_REQUEST['tfmode']) and $_REQUEST['tfmode'] == 'all')
4837 return 'all';
4838 return 'any';
4839}
4840
4841// Output a portlet with currently selected tags and prepare a form for update.
4842function renderTagFilterPortlet ($tagfilter, $realm, $bypass_name = '', $bypass_value = '')
4843{
4844 global $pageno, $tabno, $taglist, $tagtree;
4845 // Temporary hack, needs to be reviewed later.
4846 $tagfilter = isset ($_REQUEST['tagfilter']) ? $_REQUEST['tagfilter'] : array();
4847 $objectivetags = getObjectiveTagTree ($tagtree, $realm);
4848 startPortlet ('Tag filter');
4849 if (!count ($objectivetags))
4850 {
4851 echo "None defined for current realm.<br>";
4852 return;
4853 }
4854 echo '<table border=0 align=center>';
4855
4856 if (count ($tagfilter))
4857 echo '<h3>(' . serializeTags (buildTagChainFromIds ($tagfilter)) . ')</h3>';
4858 echo "<form method=get>\n";
4859 echo "<input type=hidden name=page value=${pageno}>\n";
4860 echo "<input type=hidden name=tab value=${tabno}>\n";
4861 if ($bypass_name != '')
4862 echo "<input type=hidden name=${bypass_name} value='${bypass_value}'>\n";
4863 echo '<tr><td colspan=2><select name=tagfilter[] multiple>';
4864 foreach ($objectivetags as $taginfo)
4865 renderTagOptionForFilter ($taginfo, complementByKids ($tagfilter), $realm);
4866 echo '</select></td></tr><tr><td>';
4867// $tfmode = getTFMode();
4868// echo '<input type=radio name=tfmode value=all' . ($tfmode == 'all' ? ' checked' : '') . '>all ';
4869// echo '<input type=radio name=tfmode value=any' . ($tfmode == 'any' ? ' checked' : '') . '>any ';
4870 printImageHREF ('save', 'apply', TRUE);
4871 echo "</form></td><td>";
4872
4873 // "reset"
4874 echo "<form method=get>\n";
4875 echo "<input type=hidden name=page value=${pageno}>\n";
4876 echo "<input type=hidden name=tab value=${tabno}>\n";
4877 if ($bypass_name != '')
4878 echo "<input type=hidden name=${bypass_name} value='${bypass_value}'>\n";
4879 printImageHREF ('clear', 'reset', TRUE);
4880 echo '</form></td></tr></table>';
4881 finishPortlet();
4882}
4883
4884// Dump all tags in a single SELECT element.
4885function renderTagSelect ()
4886{
4887 global $taglist, $tagtree;
4888 if (!count ($taglist))
4889 {
4890 echo "No tags defined";
4891 return;
4892 }
4893 echo '<select name=taglist[] multiple>';
4894 foreach ($tagtree as $taginfo)
4895 renderTagOption ($taginfo);
4896 echo '</select><br>';
4897}
4898
4899function renderTagRollerForRow ($row_id)
4900{
4901 $a = rand (1, 20);
4902 $b = rand (1, 20);
4903 $sum = $a + $b;
4904 showMessageOrError();
4905 printOpFormIntro ('rollTags', array ('realsum' => $sum));
4906 echo "<table border=1 align=center>";
4907 echo "<tr><td colspan=2>This special tool allows assigning tags to physical contents (racks <strong>and all contained objects</strong>) of the current ";
4908 echo "rack row.<br>The tag(s) selected below will be ";
4909 echo "appended to already assigned tag(s) of each particular entity. </td></tr>";
4910 echo "<tr><th>Tags</th><td>";
4911 renderTagSelect();
4912 echo "</td></tr>";
4913 echo "<tr><th>Control question: the sum of ${a} and ${b}</th><td><input type=text name=sum></td></tr>";
4914 echo "<tr><td colspan=2 align=center><input type=submit value='Go!'></td></tr>";
4915 echo "</table></form>";
4916}
4917
4918function renderObjectSLB ($object_id)
4919{
4920 global $root, $pageno, $tabno, $nextorder;
4921 showMessageOrError();
4922 $vs_list = $rsplist = array();
4923 foreach (getVSList() as $vsid => $vsinfo)
4924 $vs_list[$vsid] = buildVServiceName ($vsinfo) . (empty ($vsinfo['name']) ? '' : " (${vsinfo['name']})");
4925 foreach (getRSPoolList() as $pool_id => $poolInfo)
4926 $rsplist[$pool_id] = $poolInfo['name'];
4927
4928 startPortlet ('Add new');
4929 echo "<table cellspacing=0 cellpadding=5 align=center class=widetable>\n";
4930 printOpFormIntro ('addLB');
4931 echo "<tr valign=top><th>VS / RS pool</th><td class=tdleft>";
4932 printSelect ($vs_list, 'vs_id');
4933 echo "</td><td>";
4934 printSelect ($rsplist, 'pool_id');
4935 echo "</td><td>";
4936 printImageHREF ('add', 'Configure LB', TRUE, 2);
4937 echo "</td></tr>\n";
4938 echo "<tr><th>VS config</th><td colspan=2><textarea name=vsconfig rows=10 cols=80></textarea></td></tr>";
4939 echo "<tr><th>RS config</th><td colspan=2><textarea name=rsconfig rows=10 cols=80></textarea></td></tr>";
4940 echo "</form></table>\n";
4941 finishPortlet();
4942
4943 $myvslist = getRSPoolsForObject ($object_id);
4944 if (count ($myvslist))
4945 {
4946 startPortlet ('Manage existing (' . count ($myvslist) . ')');
4947 echo "<table cellspacing=0 cellpadding=5 align=center class=cooltable>\n";
4948 echo "<tr><th>&nbsp;</th><th>VS</th><th>RS pool</th><th>VS config</th><th>RS config</th><th>&nbsp;</th></tr>\n";
4949 $order = 'odd';
4950 foreach ($myvslist as $vs_id => $vsinfo)
4951 {
4952 printOpFormIntro ('updLB', array ('vs_id' => $vs_id, 'pool_id' => $vsinfo['pool_id']));
4953 echo "<tr valign=top class=row_${order}><td><a href='${root}process.php?page=${pageno}&tab=${tabno}&op=delLB&pool_id=${vsinfo['pool_id']}&object_id=${object_id}&vs_id=${vs_id}'>";
4954 printImageHREF ('delete', 'Unconfigure');
4955 echo "</a></td>";
4956 echo "</td><td class=tdleft><a href='${root}?page=ipv4vs&vs_id=${vs_id}'>";
4957 echo buildVServiceName ($vsinfo) . "</a>";
4958 if (!empty ($vsinfo['name']))
4959 echo '<br>' . $vsinfo['name'];
4960 echo "</td><td class=tdleft>" . $rsplist[$vsinfo['pool_id']] . "</td>";
4961 echo "<td><textarea name=vsconfig>${vsinfo['vsconfig']}</textarea></td>";
4962 echo "<td><textarea name=rsconfig>${vsinfo['rsconfig']}</textarea></td><td>";
4963 printImageHREF ('save', 'Save changes', TRUE);
4964 echo "</td></tr></form>\n";
4965 $order = $nextorder[$order];
4966 }
4967 echo "</table>\n";
4968 finishPortlet();
4969 }
4970}
4971
4972function renderEditRSPool ($pool_id)
4973{
4974 showMessageOrError();
4975 $poolinfo = getRSPoolInfo ($pool_id);
4976 printOpFormIntro ('updIPv4RSP');
4977 echo '<table border=0 align=center>';
4978 echo "<tr><th class=tdright>name:</th><td class=tdleft><input type=text name=name value='${poolinfo['name']}'></td></tr>\n";
4979 echo "<tr><th class=tdright>VS config:</th><td class=tdleft><textarea name=vsconfig rows=20 cols=80>${poolinfo['vsconfig']}</textarea></td></tr>\n";
4980 echo "<tr><th class=tdright>RS config:</th><td class=tdleft><textarea name=rsconfig rows=20 cols=80>${poolinfo['rsconfig']}</textarea></td></tr>\n";
4981 echo "<tr><th class=submit colspan=2>";
4982 printImageHREF ('SAVE', 'Save changes', TRUE);
4983 echo "</td></tr>\n";
4984 echo "</table></form>\n";
4985}
4986
4987function renderEditVService ($vsid)
4988{
4989 showMessageOrError();
4990 $vsinfo = getVServiceInfo ($vsid);
4991 printOpFormIntro ('updIPv4VS');
4992 echo '<table border=0 align=center>';
4993 echo "<tr><th class=tdright>VIP:</th><td class=tdleft><input type=text name=vip value='${vsinfo['vip']}'></td></tr>\n";
4994 echo "<tr><th class=tdright>port:</th><td class=tdleft><input type=text name=vport value='${vsinfo['vport']}'></td></tr>\n";
4995 echo "<tr><th class=tdright>proto:</th><td class=tdleft>";
4996 printSelect (array ('TCP' => 'TCP', 'UDP' => 'UDP'), 'proto', $vsinfo['proto']);
4997 echo "</td></tr>\n";
4998 echo "<tr><th class=tdright>name:</th><td class=tdleft><input type=text name=name value='${vsinfo['name']}'></td></tr>\n";
4999 echo "<tr><th class=tdright>VS config:</th><td class=tdleft><textarea name=vsconfig rows=20 cols=80>${vsinfo['vsconfig']}</textarea></td></tr>\n";
5000 echo "<tr><th class=tdright>RS config:</th><td class=tdleft><textarea name=rsconfig rows=20 cols=80>${vsinfo['rsconfig']}</textarea></td></tr>\n";
5001 echo "<tr><th class=submit colspan=2>";
5002 printImageHREF ('SAVE', 'Save changes', TRUE);
5003 echo "</td></tr>\n";
5004 echo "</table></form>\n";
5005}
5006
5007function dump ($var)
5008{
5009 echo '<pre>';
5010 print_r ($var);
5011 echo '</pre>';
5012}
5013
5014function renderRackCodeViewer ()
5015{
5016 $text = loadScript ('RackCode');
5017 dump ($text);
5018}
5019
5020function renderRackCodeEditor ()
5021{
5022 $text = loadScript ('RackCode');
5023 showMessageOrError();
5024 printOpFormIntro ('saveRackCode');
5025 echo '<table border=0 align=center>';
5026 echo "<tr><td><textarea rows=40 cols=100 name=rackcode id=RCTA class='codepress rackcode'>";
5027 echo $text . "</textarea></td></tr>\n";
5028 echo "<tr><td align=center>";
5029 echo "<input type='submit' value='Save' onclick='RCTA.toggleEditor();'>";
5030// printImageHREF ('SAVE', 'Save changes', TRUE);
5031 echo "</td></tr>";
5032 echo '</table>';
5033 echo "</form>";
5034}
5035
5036function renderUser ($user_id)
5037{
5038 global $accounts, $expl_tags, $impl_tags;
5039 $username = getUsernameByID ($user_id);
5040 echo '<table border=0 align=center>';
5041 echo "<tr><th class=tdright>Account name:</th><td>${username}</td></tr>";
5042 echo '<tr><th class=tdright>Real name:</th><td>' . $accounts[$username]['user_realname'] . '</td></tr>';
5043 echo '<tr><th class=tdright>Enabled:</th><td>';
5044 // This is weird, some other image titles have to be used.
5045 if ($accounts[$username]['user_enabled'] == 'yes')
5046 printImageHREF ('blockuser', 'enabled');
5047 else
5048 printImageHREF ('unblockuser', 'disabled');
5049 echo '</td></tr>';
5050 // Using printTagTRs() is inappropriate here, because autotags will be filled with current user's
5051 // data, not the viewed one.
5052// printTagTRs ("${root}?page=userlist&");
5053 $baseurl = "${root}?page=userlist&tab=default&";
5054 if (getConfigVar ('SHOW_EXPLICIT_TAGS') == 'yes' and count ($expl_tags))
5055 {
5056 echo "<tr><th width='50%' class=tag_list_th>Explicit tags:</th><td class=tdleft>";
5057 echo serializeTags ($expl_tags, $baseurl) . "</td></tr>\n";
5058 }
5059 if (getConfigVar ('SHOW_IMPLICIT_TAGS') == 'yes' and count ($impl_tags))
5060 {
5061 echo "<tr><th width='50%' class=tag_list_th>Implicit tags:</th><td class=tdleft>";
5062 echo serializeTags ($impl_tags, $baseurl) . "</td></tr>\n";
5063 }
5064 $target_auto_tags = getUserAutoTags ($username);
5065 if (getConfigVar ('SHOW_AUTOMATIC_TAGS') == 'yes' and count ($target_auto_tags))
5066 {
5067 echo "<tr><th width='50%' class=tag_list_th>Automatic tags:</th><td class=tdleft>";
5068 echo serializeTags ($target_auto_tags) . "</td></tr>\n";
5069 }
5070 echo '</table>';
5071}
5072
5073function renderMyPasswordEditor ()
5074{
5075 showMessageOrError();
5076 printOpFormIntro ('changeMyPassword');
5077 echo '<table border=0 align=center>';
5078 echo "<tr><th class=tdright>Current password (*):</th><td><input type=password name=oldpassword tabindex=1></td></tr>";
5079 echo "<tr><th class=tdright>New password (*):</th><td><input type=password name=newpassword1 tabindex=2></td></tr>";
5080 echo "<tr><th class=tdright>New password again (*):</th><td><input type=password name=newpassword2 tabindex=3></td></tr>";
5081 echo "<tr><td colspan=2 align=center><input type=submit value='Change' tabindex=4></td></tr>";
5082 echo '</table></form>';
5083}
5084
5085function renderAccessDenied ()
5086{
5087 echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'."\n";
5088 echo '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">'."\n";
5089 echo "<head><title>RackTables: access denied</title>\n";
5090 echo '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />';
5091 echo "<link rel=stylesheet type='text/css' href=pi.css />\n";
5092 echo "<link rel=icon href='" . getFaviconURL() . "' type='image/x-icon' />";
5093 echo "<link rel=icon href='" . getFaviconURL() . "' type='image/x-icon' />";
5094 echo "</head><body>";
5095 global $user_tags, $auto_tags, $expl_tags, $impl_tags, $pageno, $tabno;
5096 echo "<table border=1 cellspacing=0 cellpadding=3 width='50%' align=center>\n";
5097 echo '<tr><th colspan=2><h3>';
5098 printImageHREF ('DENIED');
5099 echo ' access denied ';
5100 printImageHREF ('DENIED');
5101 echo '</h3></th></tr>';
5102 echo "<tr><th width='50%' class=tag_list_th>Explicit tags:</th><td class=tdleft>";
5103 echo serializeTags ($expl_tags) . "&nbsp;</td></tr>\n";
5104 echo "<tr><th width='50%' class=tag_list_th>Implicit tags:</th><td class=tdleft>";
5105 echo serializeTags ($impl_tags) . "&nbsp;</td></tr>\n";
5106 echo "<tr><th width='50%' class=tag_list_th>Automatic tags:</th><td class=tdleft>";
5107 echo serializeTags ($auto_tags) . "&nbsp;</td></tr>\n";
5108 echo "<tr><th width='50%' class=tag_list_th>This user tags:</th><td class=tdleft>";
5109 echo serializeTags ($user_tags) . "&nbsp;</td></tr>\n";
5110 echo "<tr><th width='50%' class=tag_list_th>Requested page:</th><td class=tdleft>${pageno}</td></tr>\n";
5111 echo "<tr><th width='50%' class=tag_list_th>Requested tab:</th><td class=tdleft>${tabno}</td></tr>\n";
5112 echo "</table>\n";
5113 echo "</body></html>";
5114}
5115
5116function renderMyAccount ()
5117{
5118 global $remote_username, $accounts;
5119 echo "<table border=0 class=objectview cellspacing=0 cellpadding=0 width='50%'>";
5120 echo "<tr><td colspan=2 align=center><h1>${remote_username}</h1></td></tr>\n";
5121 echo "<tr><td colspan=2 align=center><h2>" . $accounts[$remote_username]['user_realname'] . "</h2></td></tr>\n";
5122 echo "</table>";
5123}
5124
5125// Print common operation form prologue, include bypass argument, if
5126// appropriate, and some extra hidden inputs, if requested.
5127function printOpFormIntro ($opname, $extra = array())
5128{
5129 global $root, $pageno, $tabno, $page;
5130 echo "<form method=post action='${root}process.php?page=${pageno}&tab=${tabno}&op=${opname}'>\n";
5131 if (isset ($page[$pageno]['bypass']) and isset ($_REQUEST[$page[$pageno]['bypass']]))
5132 $extra[$page[$pageno]['bypass']] = $_REQUEST[$page[$pageno]['bypass']];
5133 foreach ($extra as $inputname => $inputvalue)
5134 echo "<input type=hidden name=${inputname} value=${inputvalue}>\n";
5135}
5136
5137// This is a two-way formating function:
5138// 1. Replace empty strings with nbsp.
5139// 2. Cut strings, which are too long, and append "cut here" indicator.
5140function niftyString ($string, $maxlen = 30)
5141{
5142 $cutind = '&hellip;'; // length is 1
5143 if (empty ($string))
5144 return '&nbsp;';
5145 if (mb_strlen ($string) > $maxlen)
5146 return mb_substr ($string, 0, $maxlen - 1) . $cutind;
5147 return $string;
5148}
5149
5150// Iterate over what findRouters() returned and output some text suitable for a TD element.
5151// Providing a quasi-static (external) tag cache is advised for calling functions.
5152function printRoutersTD ($rlist, &$tagcache = array())
5153{
5154 global $root;
5155 $delim = '';
5156 $rtrclass = 'tdleft';
5157 foreach ($rlist as $rtr)
5158 {
5159 $tmp = getIPv4Address ($rtr['addr']);
5160 if ($tmp['class'] == 'trerror')
5161 {
5162 $rtrclass = 'tdleft trerror';
5163 break;
5164 }
5165 }
5166 echo "<td class='${rtrclass}'>";
5167 foreach ($rlist as $rtr)
5168 {
5169 echo $delim . $rtr['addr'] . ' ';
5170 echo "<a href='${root}?page=object&object_id=${rtr['id']}&hl_ipv4_addr=${rtr['addr']}'>";
5171 if (!empty ($rtr['iface']))
5172 echo $rtr['iface'] . '@';
5173 echo $rtr['dname'] . '</a>';
5174 if (!isset ($tagcache[$rtr['id']]))
5175 $tagcache[$rtr['id']] = loadRackObjectTags ($rtr['id']);
5176 if (count ($tagcache[$rtr['id']]))
5177 {
5178 echo '<br><small>';
5179 echo serializeTags ($tagcache[$rtr['id']], "${root}?page=objgroup&group_id=0&tab=default&");
5180 echo '</small>';
5181 }
5182 $delim = '<br><hr>';
5183 }