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