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