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