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