Commit | Line | Data |
---|---|---|
b325120a | 1 | <?php |
cddbb9fd DO |
2 | |
3 | # This file is a part of RackTables, a datacenter and server room management | |
4 | # framework. See accompanying file "COPYING" for the full copyright and | |
5 | # licensing information. | |
6 | ||
e673ee24 DO |
7 | /* |
8 | * | |
9 | * This file contains frontend functions for RackTables. | |
10 | * | |
11 | */ | |
12 | ||
e82deb48 | 13 | require_once 'ajax-interface.php'; |
defd92d8 | 14 | require_once 'slb-interface.php'; |
65e557dd | 15 | |
9c0b0016 DO |
16 | // Interface function's special. |
17 | $nextorder['odd'] = 'even'; | |
18 | $nextorder['even'] = 'odd'; | |
19 | ||
52c836b1 DO |
20 | // address allocation type |
21 | $aat = array | |
22 | ( | |
23 | 'regular' => 'Connected', | |
24 | 'virtual' => 'Loopback', | |
25 | 'shared' => 'Shared', | |
26 | 'router' => 'Router', | |
2f96a91a | 27 | 'point2point' => 'Point-to-point', |
52c836b1 | 28 | ); |
beb9e88a | 29 | // address allocation code, IPv4 addresses and objects view |
9d5f6a80 | 30 | $aac_right = array |
52c836b1 DO |
31 | ( |
32 | 'regular' => '', | |
9d5f6a80 AA |
33 | 'virtual' => '<span class="aac-right" title="' . $aat['virtual'] . '">L</span>', |
34 | 'shared' => '<span class="aac-right" title="' . $aat['shared'] . '">S</span>', | |
35 | 'router' => '<span class="aac-right" title="' . $aat['router'] . '">R</span>', | |
2f96a91a | 36 | 'point2point' => '<span class="aac-right" title="' . $aat['point2point'] . '">P</span>', |
52c836b1 | 37 | ); |
beb9e88a | 38 | // address allocation code, IPv4 networks view |
9d5f6a80 | 39 | $aac_left = array |
beb9e88a DO |
40 | ( |
41 | 'regular' => '', | |
9d5f6a80 AA |
42 | 'virtual' => '<span class="aac-left" title="' . $aat['virtual'] . '">L:</span>', |
43 | 'shared' => '<span class="aac-left" title="' . $aat['shared'] . '">S:</span>', | |
44 | 'router' => '<span class="aac-left" title="' . $aat['router'] . '">R:</span>', | |
2f96a91a | 45 | 'point2point' => '<span class="aac-left" title="' . $aat['point2point'] . '">P:</span>', |
beb9e88a | 46 | ); |
52c836b1 | 47 | |
0dabdc53 DO |
48 | $vtdecoder = array |
49 | ( | |
50 | 'ondemand' => '', | |
54b7ced3 DO |
51 | 'compulsory' => 'P', |
52 | # 'alien' => 'NT', | |
0dabdc53 DO |
53 | ); |
54 | ||
55 | $vtoptions = array | |
56 | ( | |
54b7ced3 DO |
57 | 'ondemand' => 'auto', |
58 | 'compulsory' => 'permanent', | |
59 | # 'alien' => 'never touch', | |
0dabdc53 DO |
60 | ); |
61 | ||
e5c4506d DO |
62 | // This may be populated later onsite, report rendering function will use it. |
63 | // See the $systemreport for structure. | |
64 | $localreports = array(); | |
d6adad3e | 65 | |
9db67d95 DO |
66 | $CodePressMap = array |
67 | ( | |
68 | 'sql' => 'sql', | |
69 | 'php' => 'php', | |
cf5da67e | 70 | 'html' => 'htmlmixed', |
9db67d95 DO |
71 | 'css' => 'css', |
72 | 'js' => 'javascript', | |
73 | ); | |
e5c4506d | 74 | |
8d4f7d18 DO |
75 | $attrtypes = array |
76 | ( | |
77 | 'uint' => '[U] unsigned integer', | |
78 | 'float' => '[F] floating point', | |
79 | 'string' => '[S] string', | |
86ff26ae DO |
80 | 'dict' => '[D] dictionary record', |
81 | 'date' => '[T] date' | |
8d4f7d18 DO |
82 | ); |
83 | ||
5eb81cf8 AD |
84 | function showLogoutURL () |
85 | { | |
86 | $https = (isset ($_SERVER['HTTPS']) and $_SERVER['HTTPS'] == 'on') ? 's' : ''; | |
87 | $port = (! in_array ($_SERVER['SERVER_PORT'], array (80, 443))) ? ':' . $_SERVER['SERVER_PORT'] : ''; | |
88 | $pathinfo = pathinfo ($_SERVER['REQUEST_URI']); | |
89 | $dirname = $pathinfo['dirname']; | |
90 | // add a trailing slash if the installation resides in a subdirectory | |
91 | if ($dirname != '/') | |
92 | $dirname .= '/'; | |
93 | printf ('http%s://logout@%s%s?logout', $https, $_SERVER['SERVER_NAME'], $dirname); | |
94 | } | |
95 | ||
a1d72d2e AA |
96 | $quick_links = NULL; // you can override this in your local.php, but first initialize it with getConfiguredQuickLinks() |
97 | ||
98 | function renderQuickLinks() | |
99 | { | |
100 | global $quick_links; | |
101 | if (! isset ($quick_links)) | |
102 | $quick_links = getConfiguredQuickLinks(); | |
103 | echo '<ul class="qlinks">'; | |
104 | foreach ($quick_links as $link) | |
105 | echo '<li><a href="' . $link['href'] . '">' . str_replace (' ', ' ', $link['title']) . '</a></li>'; | |
106 | echo '</ul>'; | |
107 | } | |
108 | ||
f97df464 DO |
109 | function renderInterfaceHTML ($pageno, $tabno, $payload) |
110 | { | |
111 | ?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | |
112 | <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | |
113 | <head><title><?php echo getTitle ($pageno); ?></title> | |
114 | <?php printPageHeaders(); ?> | |
115 | </head> | |
116 | <body> | |
b2937330 AA |
117 | <div class="maintable"> |
118 | <div class="mainheader"> | |
5eb81cf8 | 119 | <div style="float: right" class=greeting><a href='index.php?page=myaccount&tab=default'><?php global $remote_displayname; echo $remote_displayname ?></a> [ <a href='<?php showLogoutURL(); ?>'>logout</a> ]</div> |
a1d72d2e | 120 | <?php echo getConfigVar ('enterprise') ?> RackTables <a href="http://racktables.org" title="Visit RackTables site"><?php echo CODE_VERSION ?></a><?php renderQuickLinks() ?> |
b2937330 | 121 | </div> |
d688a63f | 122 | <div class="menubar"><?php showPathAndSearch ($pageno, $tabno); ?></div> |
b2937330 AA |
123 | <div class="tabbar"><?php showTabs ($pageno, $tabno); ?></div> |
124 | <div class="msgbar"><?php showMessageOrError(); ?></div> | |
125 | <div class="pagebar"><?php echo $payload; ?></div> | |
126 | </div> | |
f97df464 DO |
127 | </body> |
128 | </html> | |
129 | <?php | |
130 | } | |
131 | ||
e673ee24 | 132 | // Main menu. |
f2168c4b DO |
133 | function renderIndexItem ($ypageno) |
134 | { | |
135 | echo (! permitted ($ypageno)) ? " <td> </td>\n" : | |
136 | " <td>\n" . | |
137 | " <h1><a href='" . makeHref (array ('page' => $ypageno)) . "'>" . | |
138 | getPageName ($ypageno) . "<br>\n" . getImageHREF ($ypageno) . | |
139 | "</a></h1>\n" . | |
140 | " </td>\n"; | |
4b680876 DO |
141 | } |
142 | ||
e673ee24 DO |
143 | function renderIndex () |
144 | { | |
67c5c049 | 145 | global $indexlayout; |
e673ee24 DO |
146 | ?> |
147 | <table border=0 cellpadding=0 cellspacing=0 width='100%'> | |
148 | <tr> | |
149 | <td> | |
150 | <div style='text-align: center; margin: 10px; '> | |
a544d2c4 | 151 | <table width='100%' cellspacing=0 cellpadding=20 class=mainmenu border=0> |
4b680876 | 152 | <?php |
67c5c049 DO |
153 | foreach ($indexlayout as $row) |
154 | { | |
155 | echo '<tr>'; | |
156 | foreach ($row as $column) | |
157 | if ($column === NULL) | |
158 | echo '<td> </td>'; | |
159 | else | |
160 | renderIndexItem ($column); | |
161 | echo '</tr>'; | |
162 | } | |
163 | ?> | |
e673ee24 DO |
164 | </table> |
165 | </div> | |
166 | </td> | |
167 | </tr> | |
168 | </table> | |
b325120a | 169 | <?php |
e673ee24 DO |
170 | } |
171 | ||
f3505b35 AA |
172 | function getRenderedAlloc ($object_id, $alloc) |
173 | { | |
174 | $ret = array | |
175 | ( | |
176 | 'tr_class' => '', | |
40c9fc94 | 177 | 'td_name_suffix' => '', |
f3505b35 AA |
178 | 'td_ip' => '', |
179 | 'td_network' => '', | |
180 | 'td_routed_by' => '', | |
181 | 'td_peers' => '', | |
182 | ); | |
183 | $dottedquad = $alloc['addrinfo']['ip']; | |
4318ced5 | 184 | $ip_bin = $alloc['addrinfo']['ip_bin']; |
f3505b35 | 185 | |
4318ced5 AA |
186 | $hl_ip_bin = NULL; |
187 | if (isset ($_REQUEST['hl_ip'])) | |
f3505b35 | 188 | { |
4318ced5 AA |
189 | $hl_ip_bin = ip_parse ($_REQUEST['hl_ip']); |
190 | addAutoScrollScript ("ip-" . $_REQUEST['hl_ip']); | |
f3505b35 AA |
191 | } |
192 | ||
193 | $ret['tr_class'] = $alloc['addrinfo']['class']; | |
4318ced5 | 194 | if ($hl_ip_bin === $ip_bin) |
5c717ce5 | 195 | $ret['tr_class'] .= ' highlight'; |
dec748f6 | 196 | |
68c91b9c AA |
197 | // render IP change history |
198 | $ip_title = ''; | |
199 | $ip_class = ''; | |
200 | if (isset ($alloc['addrinfo']['last_log'])) | |
201 | { | |
202 | $log = $alloc['addrinfo']['last_log']; | |
203 | $ip_title = "title='" . | |
204 | htmlspecialchars | |
205 | ( | |
206 | $log['user'] . ', ' . formatAge ($log['time']), | |
207 | ENT_QUOTES | |
208 | ) . "'"; | |
209 | $ip_class = 'hover-history underline'; | |
210 | } | |
211 | ||
f3505b35 | 212 | // render IP address td |
9d5f6a80 | 213 | global $aac_right; |
4318ced5 AA |
214 | $netinfo = spotNetworkByIP ($ip_bin); |
215 | $ret['td_ip'] = "<td class='tdleft'>"; | |
216 | if (isset ($netinfo)) | |
217 | { | |
218 | $title = $dottedquad; | |
219 | if (getConfigVar ('EXT_IPV4_VIEW') != 'yes') | |
220 | $title .= '/' . $netinfo['mask']; | |
68c91b9c | 221 | $ret['td_ip'] .= "<a name='ip-$dottedquad' class='$ip_class' $ip_title href='" . |
f3505b35 AA |
222 | makeHref ( |
223 | array | |
224 | ( | |
4318ced5 | 225 | 'page' => 'ipaddress', |
f3505b35 AA |
226 | 'hl_object_id' => $object_id, |
227 | 'ip' => $dottedquad, | |
228 | ) | |
4318ced5 AA |
229 | ) . "'>$title</a>"; |
230 | } | |
f3505b35 | 231 | else |
68c91b9c | 232 | $ret['td_ip'] .= "<span class='$ip_class' $ip_title>$dottedquad</span>"; |
9d5f6a80 | 233 | $ret['td_ip'] .= $aac_right[$alloc['type']]; |
f3505b35 | 234 | if (strlen ($alloc['addrinfo']['name'])) |
a0bdf6dc | 235 | $ret['td_ip'] .= ' (' . stringForLabel ($alloc['addrinfo']['name']) . ')'; |
f3505b35 AA |
236 | $ret['td_ip'] .= '</td>'; |
237 | ||
238 | // render network and routed_by tds | |
4318ced5 AA |
239 | $td_class = 'tdleft'; |
240 | if (! isset ($netinfo)) | |
f3505b35 AA |
241 | { |
242 | $ret['td_network'] = "<td class='$td_class sparenetwork'>N/A</td>"; | |
243 | $ret['td_routed_by'] = $ret['td_network']; | |
244 | } | |
245 | else | |
246 | { | |
247 | $ret['td_network'] = "<td class='$td_class'>" . | |
248 | getOutputOf ('renderCell', $netinfo) . '</td>'; | |
249 | ||
98350e52 AA |
250 | // render "routed by" td |
251 | if ($display_routers = (getConfigVar ('IPV4_TREE_RTR_AS_CELL') == 'none')) | |
9d5f6a80 | 252 | $ret['td_routed_by'] = '<td> </td>'; |
f3505b35 | 253 | else |
98350e52 | 254 | { |
98350e52 | 255 | $other_routers = array(); |
6063fab7 | 256 | foreach (findNetRouters ($netinfo) as $router) |
98350e52 AA |
257 | if ($router['id'] != $object_id) |
258 | $other_routers[] = $router; | |
259 | if (count ($other_routers)) | |
260 | $ret['td_routed_by'] = getOutputOf ('printRoutersTD', $other_routers, $display_routers); | |
261 | else | |
262 | $ret['td_routed_by'] = "<td class='$td_class'> </td>"; | |
263 | } | |
f3505b35 | 264 | } |
dec748f6 | 265 | |
f3505b35 AA |
266 | // render peers td |
267 | $ret['td_peers'] = "<td class='$td_class'>"; | |
268 | $prefix = ''; | |
e749a34f | 269 | $separator = '; '; |
f3505b35 AA |
270 | if ($alloc['addrinfo']['reserved'] == 'yes') |
271 | { | |
272 | $ret['td_peers'] .= $prefix . '<strong>RESERVED</strong>'; | |
e749a34f | 273 | $prefix = $separator; |
f3505b35 AA |
274 | } |
275 | foreach ($alloc['addrinfo']['allocs'] as $allocpeer) | |
2f96a91a AA |
276 | if ($allocpeer['object_id'] != $object_id) |
277 | { | |
278 | $ret['td_peers'] .= $prefix . makeIPAllocLink ($ip_bin, $allocpeer); | |
279 | $prefix = $separator; | |
280 | } | |
281 | elseif ($allocpeer['type'] == 'point2point' && isset ($netinfo)) | |
282 | { | |
283 | // show PtP peers in the IP network | |
6063fab7 AA |
284 | $addrlist = isset ($netinfo['own_addrlist']) ? $netinfo['own_addrlist'] : getIPAddrList ($netinfo, IPSCAN_DO_ALLOCS); |
285 | foreach (getPtPNeighbors ($ip_bin, $addrlist) as $p_ip_bin => $p_alloc_list) | |
2f96a91a AA |
286 | foreach ($p_alloc_list as $p_alloc) |
287 | { | |
288 | $ret['td_peers'] .= $prefix . '↔ ' . makeIPAllocLink ($p_ip_bin, $p_alloc); | |
289 | $prefix = $separator; | |
290 | } | |
291 | } | |
292 | ||
f3505b35 AA |
293 | $ret['td_peers'] .= '</td>'; |
294 | ||
295 | return $ret; | |
296 | } | |
297 | ||
e1add254 AD |
298 | function renderLocationFilterPortlet () |
299 | { | |
e1add254 | 300 | // Recursive function used to build the location tree |
2056822d | 301 | function renderLocationCheckbox ($subtree, $level = 0) |
e1add254 AD |
302 | { |
303 | $self = __FUNCTION__; | |
e1add254 | 304 | |
2056822d | 305 | foreach ($subtree as $location_id => $location) |
e1add254 | 306 | { |
9f68b666 | 307 | echo "<div class=tagbox style='text-align:left; padding-left:" . ($level * 16) . "px;'>"; |
950dfa1f | 308 | $checked = (! isset ($_SESSION['locationFilter']) || in_array ($location['id'], $_SESSION['locationFilter'])) ? 'checked' : ''; |
9c88bba9 | 309 | echo "<label><input type=checkbox name='location_id[]' class=${level} value='${location['id']}'${checked} onClick=checkAll(this)>${location['name']}"; |
9f68b666 | 310 | echo '</label>'; |
2056822d | 311 | if ($location['kidc']) |
9f68b666 AD |
312 | { |
313 | echo "<a id='lfa" . $location['id'] . "' onclick=\"expand('${location['id']}')\" href\"#\" > - </a>"; | |
314 | echo "<div id='lfd" . $location['id'] . "'>"; | |
2056822d | 315 | $self ($location['kids'], $level + 1); |
9f68b666 AD |
316 | echo '</div>'; |
317 | } | |
318 | echo '</div>'; | |
e1add254 AD |
319 | } |
320 | } | |
321 | ||
9c88bba9 AD |
322 | addJS(<<<END |
323 | function checkAll(bx) { | |
324 | for (var tbls=document.getElementsByTagName("table"), i=tbls.length; i--;) | |
4e9e1b7a | 325 | if (tbls[i].id == "locationFilter") { |
9c88bba9 AD |
326 | var bxs=tbls[i].getElementsByTagName("input"); |
327 | var in_tree = false; | |
9f68b666 | 328 | for (var j=0; j<bxs.length; j++) { |
9c88bba9 AD |
329 | if(in_tree == false && bxs[j].value == bx.value) |
330 | in_tree = true; | |
331 | else if(parseInt(bxs[j].className) <= parseInt(bx.className)) | |
332 | in_tree = false; | |
333 | if (bxs[j].type=="checkbox" && in_tree == true) | |
334 | bxs[j].checked = bx.checked; | |
335 | } | |
336 | } | |
337 | } | |
9f68b666 AD |
338 | |
339 | function collapseAll(bx) { | |
340 | for (var tbls=document.getElementsByTagName("table"), i=tbls.length; i--;) | |
341 | if (tbls[i].id == "locationFilter") { | |
342 | var bxs=tbls[i].getElementsByTagName("div"); | |
343 | //loop through divs to hide unchecked | |
344 | for (var j=0; j<bxs.length; j++) { | |
345 | var is_checked = -1; | |
346 | var in_div=bxs[j].getElementsByTagName("input"); | |
347 | //loop through input to find if any is checked | |
348 | for (var k=0; k<in_div.length; k++) { | |
349 | if(in_div[k].type="checkbox") { | |
350 | if (in_div[k].checked == true) { | |
351 | is_checked = true; | |
352 | break; | |
353 | } | |
354 | else | |
355 | is_checked = false; | |
356 | } | |
357 | } | |
358 | // nothing selected and element id is lfd, collapse it | |
359 | if (is_checked == false && !bxs[j].id.indexOf("lfd")) | |
360 | expand(bxs[j].id.substr(3)); | |
361 | } | |
362 | } | |
363 | } | |
364 | ||
365 | function expand(id) { | |
366 | var divid = document.getElementById("lfd" + id); | |
367 | var iconid = document.getElementById("lfa" + id); | |
368 | if (divid.style.display == 'none') { | |
369 | divid.style.display = 'block'; | |
370 | iconid.innerHTML = ' - '; | |
371 | } else { | |
372 | divid.style.display = 'none'; | |
373 | iconid.innerHTML = ' + '; | |
374 | } | |
375 | } | |
9c88bba9 AD |
376 | END |
377 | ,TRUE); | |
e1add254 AD |
378 | startPortlet ('Location filter'); |
379 | echo <<<END | |
9c88bba9 | 380 | <table border=0 align=center cellspacing=0 class="tagtree" id="locationFilter"> |
6b816bde | 381 | <form method=post> |
e1add254 AD |
382 | <input type=hidden name=page value=rackspace> |
383 | <input type=hidden name=tab value=default> | |
384 | <input type=hidden name=changeLocationFilter value=true> | |
385 | END; | |
2056822d AA |
386 | |
387 | $locationlist = listCells ('location'); | |
e1add254 AD |
388 | if (count ($locationlist)) |
389 | { | |
9c88bba9 AD |
390 | echo "<tr><td class=tagbox style='padding-left: 0px'><label>"; |
391 | echo "<input type=checkbox name='location' onClick=checkAll(this)> Toggle all"; | |
1341dc93 | 392 | echo "<img src=?module=chrome&uri=pix/1x1t.gif onLoad=collapseAll(this)>"; // dirty hack to collapse all when page is displayed |
9c88bba9 | 393 | echo "</label></td></tr>\n"; |
9f68b666 | 394 | echo "<tr><td class=tagbox><hr>\n"; |
d6409c53 | 395 | renderLocationCheckbox (treeFromList (addTraceToNodes ($locationlist))); |
9f68b666 AD |
396 | echo "<hr></td></tr>\n"; |
397 | echo '<tr><td>'; | |
e1add254 AD |
398 | printImageHREF ('setfilter', 'set filter', TRUE); |
399 | echo "</td></tr>\n"; | |
400 | } | |
401 | else | |
402 | { | |
403 | echo "<tr><td class='tagbox sparenetwork'>(no locations exist)</td></tr>\n"; | |
404 | echo "<tr><td>"; | |
405 | printImageHREF ('setfilter gray'); | |
406 | echo "</td></tr>\n"; | |
407 | } | |
408 | ||
409 | echo "</form></table>\n"; | |
410 | finishPortlet (); | |
411 | } | |
412 | ||
d9bad31a AD |
413 | function rackspaceCmp ($a, $b) |
414 | { | |
415 | $ret = strnatcasecmp ($a['location_tree'], $b['location_tree']); | |
416 | if (!$ret) | |
417 | $ret = strnatcasecmp ($a['row_name'], $b['row_name']); | |
418 | return $ret; | |
419 | } | |
420 | ||
e10d9597 DO |
421 | function getRackThumbLink ($rack, $scale = 1) |
422 | { | |
423 | if (! is_int ($scale) || $scale <= 0) | |
424 | throw new InvalidArgException ('scale', $scale, 'must be a natural number'); | |
425 | $width = getRackImageWidth() * $scale; | |
426 | $height = getRackImageHeight ($rack['height']) * $scale; | |
427 | $title = "${rack['height']} units"; | |
428 | $src = '?module=image' . | |
429 | ($scale == 1 ? '&img=minirack' : "&img=midirack&scale=${scale}") . | |
430 | "&rack_id=${rack['id']}"; | |
431 | $img = "<img border=0 width=${width} height=${height} title='${title}' src='${src}'>"; | |
168c2acb | 432 | return mkA ($img, 'rack', $rack['id']); |
e10d9597 DO |
433 | } |
434 | ||
e673ee24 DO |
435 | function renderRackspace () |
436 | { | |
e1add254 | 437 | // Handle the location filter |
0a00b344 | 438 | startSession(); |
e1add254 AD |
439 | if (isset ($_REQUEST['changeLocationFilter'])) |
440 | unset ($_SESSION['locationFilter']); | |
441 | if (isset ($_REQUEST['location_id'])) | |
442 | $_SESSION['locationFilter'] = $_REQUEST['location_id']; | |
5d6352df | 443 | session_commit(); |
e1add254 | 444 | |
950dfa1f AA |
445 | echo "<table class=objview border=0 width='100%'><tr><td class=pcleft>"; |
446 | ||
95857b5c | 447 | $found_racks = array(); |
a8efc03e | 448 | $cellfilter = getCellFilter(); |
950dfa1f | 449 | if (! ($cellfilter['is_empty'] && !isset ($_SESSION['locationFilter']) && renderEmptyResults ($cellfilter, 'racks', getEntitiesCount ('rack')))) |
e1add254 | 450 | { |
950dfa1f AA |
451 | $rows = array(); |
452 | $rackCount = 0; | |
524f8a7b | 453 | foreach (listCells ('row') as $row_id => $rowInfo) |
950dfa1f | 454 | { |
2b16c179 | 455 | $rackList = applyCellFilter ('rack', $cellfilter, $row_id); |
950dfa1f | 456 | $found_racks = array_merge ($found_racks, $rackList); |
d9bad31a AD |
457 | $location_id = $rowInfo['location_id']; |
458 | $locationIdx = 0; | |
459 | // contains location names in the form of 'grandparent parent child', used for sorting | |
460 | $locationTree = ''; | |
461 | // contains location names as well as links | |
462 | $hrefLocationTree = ''; | |
463 | while ($location_id) | |
464 | { | |
465 | if ($locationIdx == 20) | |
466 | { | |
467 | showWarning ("Warning: There is likely a circular reference in the location tree. Investigate location ${location_id}."); | |
468 | break; | |
469 | } | |
470 | $parentLocation = spotEntity ('location', $location_id); | |
471 | $locationTree = sprintf ('%s %s', $parentLocation['name'], $locationTree); | |
472 | $hrefLocationTree = "» <a href='" . | |
473 | makeHref(array('page'=>'location', 'location_id'=>$parentLocation['id'])) . | |
474 | "${cellfilter['urlextra']}'>${parentLocation['name']}</a> " . | |
475 | $hrefLocationTree; | |
476 | $location_id = $parentLocation['parent_id']; | |
477 | $locationIdx++; | |
478 | } | |
479 | $hrefLocationTree = substr ($hrefLocationTree, 8); | |
950dfa1f AA |
480 | $rows[] = array ( |
481 | 'location_id' => $rowInfo['location_id'], | |
d9bad31a AD |
482 | 'location_tree' => $locationTree, |
483 | 'href_location_tree' => $hrefLocationTree, | |
950dfa1f AA |
484 | 'row_id' => $row_id, |
485 | 'row_name' => $rowInfo['name'], | |
486 | 'racks' => $rackList | |
487 | ); | |
488 | $rackCount += count($rackList); | |
489 | } | |
1ebbf889 | 490 | |
d9bad31a AD |
491 | // sort by location, then by row |
492 | usort ($rows, 'rackspaceCmp'); | |
493 | ||
950dfa1f | 494 | if (! renderEmptyResults($cellfilter, 'racks', $rackCount)) |
1ebbf889 | 495 | { |
950dfa1f AA |
496 | // generate thumb gallery |
497 | global $nextorder; | |
950dfa1f AA |
498 | // Zero value effectively disables the limit. |
499 | $maxPerRow = getConfigVar ('RACKS_PER_ROW'); | |
500 | $order = 'odd'; | |
18733c4a AD |
501 | if (! count ($rows)) |
502 | echo "<h2>No rows found</h2>\n"; | |
503 | else | |
e1add254 | 504 | { |
950dfa1f AA |
505 | echo '<table border=0 cellpadding=10 class=cooltable>'; |
506 | echo '<tr><th class=tdleft>Location</th><th class=tdleft>Row</th><th class=tdleft>Racks</th></tr>'; | |
507 | foreach ($rows as $row) | |
c08915c7 | 508 | { |
950dfa1f AA |
509 | $rackList = $row['racks']; |
510 | ||
511 | if ( | |
512 | $location_id != '' and isset ($_SESSION['locationFilter']) and !in_array ($location_id, $_SESSION['locationFilter']) or | |
513 | empty ($rackList) and ! $cellfilter['is_empty'] | |
514 | ) | |
515 | continue; | |
516 | $rackListIdx = 0; | |
d9bad31a AD |
517 | echo "<tr class=row_${order}><th class=tdleft>${row['href_location_tree']}</th>"; |
518 | echo "<th class=tdleft><a href='".makeHref(array('page'=>'row', 'row_id'=>$row['row_id']))."${cellfilter['urlextra']}'>${row['row_name']}</a></th>"; | |
950dfa1f | 519 | echo "<th class=tdleft><table border=0 cellspacing=5><tr>"; |
18733c4a AD |
520 | if (! count ($rackList)) |
521 | echo '<td>(empty row)</td>'; | |
950dfa1f AA |
522 | else |
523 | foreach ($rackList as $rack) | |
e1add254 | 524 | { |
950dfa1f AA |
525 | if ($rackListIdx > 0 and $maxPerRow > 0 and $rackListIdx % $maxPerRow == 0) |
526 | { | |
527 | echo '</tr></table></th></tr>'; | |
d9bad31a | 528 | echo "<tr class=row_${order}><th class=tdleft></th><th class=tdleft>${row['row_name']} (continued)"; |
950dfa1f AA |
529 | echo "</th><th class=tdleft><table border=0 cellspacing=5><tr>"; |
530 | } | |
168c2acb DO |
531 | echo '<td align=center valign=bottom>' . getRackThumbLink ($rack); |
532 | echo '<br>' . mkA (stringForLabel ($rack['name']), 'rack', $rack['id']) . '</td>'; | |
950dfa1f | 533 | $rackListIdx++; |
e1add254 | 534 | } |
950dfa1f AA |
535 | $order = $nextorder[$order]; |
536 | echo "</tr></table></th></tr>\n"; | |
537 | } | |
538 | echo "</table>\n"; | |
e1add254 | 539 | } |
1ebbf889 | 540 | } |
e673ee24 | 541 | } |
14ad4f4a DO |
542 | echo '</td><td class=pcright width="25%">'; |
543 | renderCellFilterPortlet ($cellfilter, 'rack', $found_racks); | |
e1add254 AD |
544 | echo "<br>\n"; |
545 | renderLocationFilterPortlet (); | |
489a7502 | 546 | echo "</td></tr></table>\n"; |
e673ee24 DO |
547 | } |
548 | ||
2056822d | 549 | function renderLocationRowForEditor ($subtree, $level = 0) |
e1add254 AD |
550 | { |
551 | $self = __FUNCTION__; | |
2056822d AA |
552 | foreach ($subtree as $locationinfo) |
553 | { | |
554 | echo "<tr><td align=left style='padding-left: " . ($locationinfo['kidc'] ? $level : ($level + 1) * 16) . "px;'>"; | |
555 | if ($locationinfo['kidc']) | |
556 | printImageHREF ('node-expanded-static'); | |
557 | if ($locationinfo['refcnt'] > 0 || $locationinfo['kidc'] > 0) | |
558 | printImageHREF ('nodestroy'); | |
559 | else | |
10f5133a | 560 | echo getOpLink (array ('op' => 'deleteLocation', 'location_id' => $locationinfo['id']), '', 'destroy', 'Delete location'); |
2056822d AA |
561 | echo '</td><td class=tdleft>'; |
562 | printOpFormIntro ('updateLocation', array ('location_id' => $locationinfo['id'])); | |
563 | $parent = isset ($locationinfo['parent_id']) ? $locationinfo['parent_id'] : 0; | |
564 | echo getSelect | |
565 | ( | |
566 | array ( $parent => $parent ? htmlspecialchars ($locationinfo['parent_name']) : '-- NONE --'), | |
567 | array ('name' => 'parent_id', 'id' => 'locationid_' . $locationinfo['id'], 'class' => 'locationlist-popup'), | |
568 | $parent, | |
569 | FALSE | |
570 | ); | |
571 | echo "</td><td class=tdleft>"; | |
572 | echo "<input type=text size=48 name=name value='${locationinfo['name']}'>"; | |
573 | echo '</td><td>' . getImageHREF ('save', 'Save changes', TRUE) . "</form></td></tr>\n"; | |
574 | if ($locationinfo['kidc']) | |
575 | $self ($locationinfo['kids'], $level + 1); | |
576 | } | |
e1add254 AD |
577 | } |
578 | ||
82fa45a9 | 579 | function renderLocationSelectTree ($select_name, $selected_id = NULL) |
eda41675 | 580 | { |
82fa45a9 | 581 | echo "<select name='${select_name}'>"; |
eda41675 | 582 | echo '<option value=0>-- NONE --</option>'; |
359ea9f9 | 583 | $locationlist = listCells ('location'); |
d6409c53 | 584 | foreach (treeFromList (addTraceToNodes ($locationlist)) as $location) |
eda41675 AD |
585 | { |
586 | echo "<option value=${location['id']} style='font-weight: bold' "; | |
587 | if ($location['id'] == $selected_id ) | |
588 | echo ' selected'; | |
589 | echo ">${location['name']}</option>"; | |
e3648fa6 | 590 | printLocationChildrenSelectOptions ($location, $selected_id); |
eda41675 AD |
591 | } |
592 | echo '</select>'; | |
593 | } | |
594 | ||
e1add254 AD |
595 | function renderRackspaceLocationEditor () |
596 | { | |
b090b2da RQ |
597 | $js = <<<JSTXT |
598 | function locationeditor_showselectbox(e) { | |
599 | $(this).load('index.php', {module: 'ajax', ac: 'get-location-select', locationid: this.id}); | |
600 | $(this).unbind('mousedown', locationeditor_showselectbox); | |
601 | } | |
602 | $(document).ready(function () { | |
603 | $('select.locationlist-popup').bind('mousedown', locationeditor_showselectbox); | |
604 | }); | |
605 | JSTXT; | |
606 | ||
607 | addJS($js, TRUE ); | |
e1add254 AD |
608 | function printNewItemTR () |
609 | { | |
e1add254 | 610 | printOpFormIntro ('addLocation'); |
eda41675 | 611 | echo '<tr><td>'; |
e1add254 | 612 | printImageHREF ('create', 'Add new location', TRUE); |
82fa45a9 DO |
613 | echo '</td><td>'; |
614 | renderLocationSelectTree ('parent_id'); | |
04c61e7e AB |
615 | echo '</td><td><input type=text size=48 name=name></td><td>'; |
616 | printImageHREF ('create', 'Add new location', TRUE); | |
e1add254 AD |
617 | echo "</td></tr></form>\n"; |
618 | } | |
e1add254 AD |
619 | |
620 | startPortlet ('Locations'); | |
621 | echo "<table border=0 cellspacing=0 cellpadding=5 align=center class=widetable>\n"; | |
622 | echo "<tr><th> </th><th>Parent</th><th>Name</th><th> </th></tr>\n"; | |
623 | if (getConfigVar ('ADDNEW_AT_TOP') == 'yes') | |
624 | printNewItemTR(); | |
2056822d | 625 | |
1e0f13f3 | 626 | $locations = listCells ('location'); |
d6409c53 | 627 | renderLocationRowForEditor (treeFromList (addTraceToNodes ($locations))); |
2056822d | 628 | |
e1add254 AD |
629 | if (getConfigVar ('ADDNEW_AT_TOP') != 'yes') |
630 | printNewItemTR(); | |
631 | echo "</table><br>\n"; | |
632 | finishPortlet(); | |
633 | } | |
634 | ||
345fd640 AD |
635 | function renderRackspaceRowEditor () |
636 | { | |
eda41675 | 637 | function printNewItemTR () |
345fd640 AD |
638 | { |
639 | printOpFormIntro ('addRow'); | |
eda41675 | 640 | echo '<tr><td>'; |
7be51fea | 641 | printImageHREF ('create', 'Add new row', TRUE); |
04eee8d2 VS |
642 | echo '</td><td> '; |
643 | echo '</td><td> '; | |
82fa45a9 DO |
644 | echo '</td><td>'; |
645 | renderLocationSelectTree ('location_id'); | |
04c61e7e AB |
646 | echo '</td><td><input type=text name=name></td><td>'; |
647 | printImageHREF ('create', 'Add new row', TRUE); | |
eda41675 | 648 | echo '</td></tr></form>'; |
345fd640 | 649 | } |
d732e47e | 650 | startPortlet ('Rows'); |
345fd640 | 651 | echo "<table border=0 cellspacing=0 cellpadding=5 align=center class=widetable>\n"; |
04eee8d2 | 652 | echo "<tr><th> </th><th># Racks</th><th># Devices</th><th>Location</th><th>Name</th><th> </th><th>Row link</th></tr>\n"; |
345fd640 | 653 | if (getConfigVar ('ADDNEW_AT_TOP') == 'yes') |
eda41675 | 654 | printNewItemTR (); |
524f8a7b | 655 | foreach (listCells ('row') as $row_id => $rowInfo) |
345fd640 | 656 | { |
eda41675 | 657 | echo '<tr><td>'; |
04eee8d2 VS |
658 | $rc = $rowInfo['rackc']; |
659 | $delete_racks_str = $rc ? " and $rc rack(s)" : ''; | |
660 | echo getOpLink (array ('op'=>'deleteRow', 'row_id'=>$row_id), '', 'destroy', 'Delete row'.$delete_racks_str, 'need-confirmation'); | |
c40666f5 | 661 | printOpFormIntro ('updateRow', array ('row_id' => $row_id)); |
eda41675 | 662 | echo '</td><td>'; |
04eee8d2 VS |
663 | echo $rc; |
664 | echo '</td><td>'; | |
665 | echo getRowMountsCount ($row_id); | |
666 | echo '</td><td>'; | |
82fa45a9 | 667 | renderLocationSelectTree ('location_id', $rowInfo['location_id']); |
04c61e7e | 668 | echo "</td><td><input type=text name=name value='${rowInfo['name']}'></td><td>"; |
7be51fea | 669 | printImageHREF ('save', 'Save changes', TRUE); |
524f8a7b AA |
670 | echo "</form></td>"; |
671 | echo "<td>" . mkCellA ($rowInfo) . "</td>"; | |
672 | echo "</tr>\n"; | |
345fd640 AD |
673 | } |
674 | if (getConfigVar ('ADDNEW_AT_TOP') != 'yes') | |
eda41675 | 675 | printNewItemTR (); |
345fd640 AD |
676 | echo "</table><br>\n"; |
677 | finishPortlet(); | |
678 | } | |
679 | ||
9da8ee26 | 680 | function renderRow() |
e673ee24 | 681 | { |
9da8ee26 | 682 | $row_id = getBypassValue(); |
e16b666c | 683 | $rowInfo = getRowInfo ($row_id); |
a8efc03e | 684 | $cellfilter = getCellFilter(); |
2b16c179 | 685 | $rackList = applyCellFilter ('rack', $cellfilter, $row_id); |
138655f5 AD |
686 | |
687 | $summary = array (); | |
688 | $summary['Name'] = $rowInfo['name']; | |
689 | if ($rowInfo['location_id']) | |
690 | $summary['Location'] = mkA ($rowInfo['location'], 'location', $rowInfo['location_id']); | |
691 | $summary['Racks'] = $rowInfo['count']; | |
692 | $summary['Units'] = $rowInfo['sum']; | |
693 | $summary['% used'] = getProgressBar (getRSUforRow ($rackList)); | |
249c78b2 | 694 | foreach (getAttrValuesSorted ($row_id) as $record) |
138655f5 AD |
695 | if |
696 | ( | |
697 | $record['value'] != '' and | |
698 | permitted (NULL, NULL, NULL, array (array ('tag' => '$attr_' . $record['id']))) | |
699 | ) | |
700 | $summary['{sticker}' . $record['name']] = formatAttributeValue ($record); | |
701 | ||
e673ee24 DO |
702 | // Main layout starts. |
703 | echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>"; | |
704 | ||
705 | // Left portlet with row information. | |
706 | echo "<tr><td class=pcleft>"; | |
138655f5 | 707 | renderEntitySummary ($rowInfo, 'Summary', $summary); |
7f297114 | 708 | renderCellFilterPortlet ($cellfilter, 'rack', $rackList, array ('row_id' => $row_id)); |
6ccfd4bd | 709 | renderFilesPortlet ('row',$row_id); |
48325652 | 710 | echo "</td><td class=pcright>"; |
e673ee24 | 711 | |
4fbb5a00 | 712 | global $nextorder; |
f5883ec1 DO |
713 | // Maximum number of racks per row is proportionally less, but at least 1. |
714 | $maxPerRow = max (floor (getConfigVar ('RACKS_PER_ROW') / getConfigVar ('ROW_SCALE')), 1); | |
715 | $rackListIdx = 0; | |
e673ee24 DO |
716 | $order = 'odd'; |
717 | startPortlet ('Racks'); | |
718 | echo "<table border=0 cellspacing=5 align='center'><tr>"; | |
64b95774 | 719 | foreach ($rackList as $rack) |
e673ee24 | 720 | { |
f5883ec1 DO |
721 | if ($rackListIdx % $maxPerRow == 0) |
722 | { | |
723 | if ($rackListIdx > 0) | |
724 | echo '</tr>'; | |
725 | echo '<tr>'; | |
726 | } | |
9b8174d7 | 727 | $class = ($rack['has_problems'] == 'yes') ? 'error' : $order; |
168c2acb DO |
728 | echo "<td align=center valign=bottom class=row_${class}>" . |
729 | getRackThumbLink ($rack, getConfigVar ('ROW_SCALE')) . | |
730 | '<br>' . mkA (stringForLabel ($rack['name']), 'rack', $rack['id']) . '</td>'; | |
e673ee24 | 731 | $order = $nextorder[$order]; |
f5883ec1 | 732 | $rackListIdx++; |
e673ee24 DO |
733 | } |
734 | echo "</tr></table>\n"; | |
735 | finishPortlet(); | |
e673ee24 DO |
736 | echo "</td></tr></table>"; |
737 | } | |
738 | ||
9da8ee26 | 739 | function renderEditRowForm() |
138655f5 | 740 | { |
9da8ee26 | 741 | $row_id = getBypassValue(); |
138655f5 AD |
742 | $row = getRowInfo ($row_id); |
743 | ||
744 | startPortlet ('Attributes'); | |
745 | printOpFormIntro ('updateRow'); | |
746 | echo '<table border=0 align=center>'; | |
747 | echo '<tr><td> </td><th class=tdright>Location:</th><td class=tdleft>'; | |
748 | $locations = array (); | |
749 | $locations[0] = '-- NOT SET --'; | |
750 | foreach (listCells ('location') as $id => $locationInfo) | |
751 | $locations[$id] = $locationInfo['name']; | |
752 | natcasesort ($locations); | |
753 | printSelect ($locations, array ('name' => 'location_id'), $row['location_id']); | |
754 | echo "</td></tr>\n"; | |
755 | echo "<tr><td> </td><th class=tdright>Name (required):</th><td class=tdleft><input type=text name=name value='${row['name']}'></td></tr>\n"; | |
756 | ||
757 | // optional attributes | |
249c78b2 | 758 | $values = getAttrValuesSorted ($row_id); |
138655f5 AD |
759 | $num_attrs = count ($values); |
760 | echo "<input type=hidden name=num_attrs value=${num_attrs}>\n"; | |
761 | $i = 0; | |
762 | foreach ($values as $record) | |
763 | { | |
764 | echo "<input type=hidden name=${i}_attr_id value=${record['id']}>"; | |
765 | echo '<tr><td>'; | |
766 | if (strlen ($record['value'])) | |
767 | echo getOpLink (array('op'=>'clearSticker', 'attr_id'=>$record['id']), '', 'clear', 'Clear value', 'need-confirmation'); | |
768 | else | |
769 | echo ' '; | |
770 | echo '</td>'; | |
771 | echo "<th class=sticker>${record['name']}:</th><td class=tdleft>"; | |
772 | switch ($record['type']) | |
773 | { | |
774 | case 'uint': | |
775 | case 'float': | |
776 | case 'string': | |
777 | echo "<input type=text name=${i}_value value='${record['value']}'>"; | |
778 | break; | |
779 | case 'dict': | |
780 | $chapter = readChapter ($record['chapter_id'], 'o'); | |
781 | $chapter[0] = '-- NOT SET --'; | |
782 | $chapter = cookOptgroups ($chapter, 1562, $record['key']); | |
783 | printNiftySelect ($chapter, array ('name' => "${i}_value"), $record['key']); | |
784 | break; | |
785 | } | |
786 | echo "</td></tr>\n"; | |
787 | $i++; | |
788 | } | |
789 | if ($row['count'] == 0) | |
790 | { | |
791 | echo '<tr><td> </td><th class=tdright>Actions:</th><td class=tdleft>'; | |
792 | echo getOpLink (array ('op'=>'deleteRow'), '', 'destroy', 'Delete row', 'need-confirmation'); | |
793 | echo " </td></tr>\n"; | |
794 | } | |
795 | echo "<tr><td class=submit colspan=3>"; | |
796 | printImageHREF ('SAVE', 'Save changes', TRUE); | |
797 | echo "</td></tr>\n"; | |
798 | echo '</form></table><br>'; | |
799 | finishPortlet(); | |
800 | ||
801 | startPortlet ('History'); | |
802 | renderObjectHistory ($row_id); | |
803 | finishPortlet(); | |
804 | } | |
805 | ||
0a7feebb | 806 | // Used by renderRack() |
84feb87b | 807 | function printObjectDetailsForRenderRack ($object_id, $hl_obj_id = 0) |
0a7feebb AD |
808 | { |
809 | $objectData = spotEntity ('object', $object_id); | |
810 | if (strlen ($objectData['asset_no'])) | |
811 | $prefix = "<div title='${objectData['asset_no']}"; | |
812 | else | |
813 | $prefix = "<div title='no asset tag"; | |
814 | // Don't tell about label, if it matches common name. | |
815 | $body = ''; | |
816 | if ($objectData['name'] != $objectData['label'] and strlen ($objectData['label'])) | |
817 | $body = ", visible label is \"${objectData['label']}\""; | |
818 | // Display list of child objects, if any | |
c17a36f0 | 819 | $objectChildren = getChildren ($objectData, 'object'); |
5a7bf292 | 820 | $slotRows = $slotCols = $slotInfo = $slotData = $slotTitle = $slotClass = array (); |
0a7feebb AD |
821 | if (count($objectChildren) > 0) |
822 | { | |
c17a36f0 | 823 | foreach ($objectChildren as $childData) |
84feb87b | 824 | { |
c17a36f0 AA |
825 | $childNames[] = $childData['name']; |
826 | $attrData = getAttrValues ($childData['id']); | |
be28528c M |
827 | $numRows = $numCols = 1; |
828 | if (isset ($attrData[2])) // HW type | |
829 | { | |
830 | extractLayout ($attrData[2]); | |
831 | if (isset ($attrData[2]['rows'])) | |
832 | { | |
833 | $numRows = $attrData[2]['rows']; | |
834 | $numCols = $attrData[2]['cols']; | |
835 | } | |
836 | } | |
05abd358 | 837 | if (isset ($attrData['28'])) // slot number |
84feb87b AD |
838 | { |
839 | $slot = $attrData['28']['value']; | |
be28528c M |
840 | if (preg_match ('/\d+/', $slot, $matches)) |
841 | $slot = $matches[0]; | |
842 | $slotRows[$slot] = $numRows; | |
843 | $slotCols[$slot] = $numCols; | |
c17a36f0 AA |
844 | $slotInfo[$slot] = $childData['dname']; |
845 | $slotData[$slot] = $childData['id']; | |
84feb87b AD |
846 | if (strlen ($childData['asset_no'])) |
847 | $slotTitle[$slot] = "<div title='${childData['asset_no']}"; | |
848 | else | |
849 | $slotTitle[$slot] = "<div title='no asset tag"; | |
c17a36f0 | 850 | if (strlen ($childData['label']) and $childData['label'] != $childData['dname']) |
84feb87b AD |
851 | $slotTitle[$slot] .= ", visible label is \"${childData['label']}\""; |
852 | $slotTitle[$slot] .= "'>"; | |
5a7bf292 M |
853 | $slotClass[$slot] = 'state_T'; |
854 | if ($childData['has_problems'] == 'yes') | |
855 | $slotClass[$slot] = 'state_Tw'; | |
c17a36f0 | 856 | if ($childData['id'] == $hl_obj_id) |
5a7bf292 | 857 | $slotClass[$slot] = 'state_Th'; |
84feb87b AD |
858 | } |
859 | } | |
0a7feebb AD |
860 | natsort($childNames); |
861 | $suffix = sprintf(", contains %s'>", implode(', ', $childNames)); | |
862 | } | |
863 | else | |
864 | $suffix = "'>"; | |
ad3e5e7e | 865 | echo "${prefix}${body}${suffix}" . mkA ($objectData['dname'], 'object', $objectData['id']) . '</div>'; |
84feb87b AD |
866 | if (in_array ($objectData['objtype_id'], array (1502,1503))) // server chassis, network chassis |
867 | { | |
868 | $objAttr = getAttrValues ($objectData['id']); | |
869 | if (isset ($objAttr[2])) // HW type | |
870 | { | |
871 | extractLayout ($objAttr[2]); | |
872 | if (isset ($objAttr[2]['rows'])) | |
873 | { | |
874 | $rows = $objAttr[2]['rows']; | |
875 | $cols = $objAttr[2]['cols']; | |
876 | $layout = $objAttr[2]['layout']; | |
877 | echo "<table width='100%' border='1'>"; | |
878 | for ($r = 0; $r < $rows; $r++) | |
879 | { | |
880 | echo '<tr>'; | |
881 | for ($c = 0; $c < $cols; $c++) | |
882 | { | |
883 | $s = ($r * $cols) + $c + 1; | |
884 | if (isset ($slotData[$s])) | |
885 | { | |
be28528c | 886 | if ($slotData[$s] >= 0) |
84feb87b | 887 | { |
be28528c M |
888 | for ($lr = 0; $lr < $slotRows[$s]; $lr++) |
889 | for ($lc = 0; $lc < $slotCols[$s]; $lc++) | |
890 | { | |
891 | $skip = ($lr * $cols) + $lc; | |
892 | if ($skip > 0) | |
893 | $slotData[$s + $skip] = -1; | |
894 | } | |
895 | echo '<td'; | |
896 | if ($slotRows[$s] > 1) | |
897 | echo " rowspan=$slotRows[$s]"; | |
898 | if ($slotCols[$s] > 1) | |
899 | echo " colspan=$slotCols[$s]"; | |
5a7bf292 | 900 | echo " class='${slotClass[$s]}'>${slotTitle[$s]}"; |
be28528c M |
901 | if ($layout == 'V') |
902 | { | |
903 | $tmp = substr ($slotInfo[$s], 0, 1); | |
904 | foreach (str_split (substr ($slotInfo[$s], 1)) as $letter) | |
905 | $tmp .= '<br>' . $letter; | |
906 | $slotInfo[$s] = $tmp; | |
907 | } | |
908 | echo mkA ($slotInfo[$s], 'object', $slotData[$s]); | |
909 | echo '</div></td>'; | |
84feb87b | 910 | } |
84feb87b AD |
911 | } |
912 | else | |
913 | echo "<td class='state_F'><div title=\"Free slot\"> </div></td>"; | |
914 | } | |
915 | echo '</tr>'; | |
916 | } | |
917 | echo '</table>'; | |
918 | } | |
919 | } | |
920 | } | |
0a7feebb AD |
921 | } |
922 | ||
e673ee24 | 923 | // This function renders rack as HTML table. |
7e1db771 | 924 | function renderRack ($rack_id, $hl_obj_id = 0) |
e673ee24 | 925 | { |
61a1d996 DO |
926 | $rackData = spotEntity ('rack', $rack_id); |
927 | amplifyCell ($rackData); | |
e673ee24 DO |
928 | markAllSpans ($rackData); |
929 | if ($hl_obj_id > 0) | |
930 | highlightObject ($rackData, $hl_obj_id); | |
736acd8d | 931 | $neighbors = getRackNeighbors ($rackData['row_id'], $rack_id); |
eda8b3ce DO |
932 | $prev_id = $neighbors['prev']; |
933 | $next_id = $neighbors['next']; | |
d48d8820 | 934 | echo "<center><table border=0><tr valign=middle>"; |
ad3e5e7e | 935 | echo '<td><h2>' . mkA ($rackData['row_name'], 'row', $rackData['row_id']) . ' :</h2></td>'; |
e673ee24 | 936 | if ($prev_id != NULL) |
ad3e5e7e DO |
937 | echo '<td>' . mkA (getImageHREF ('prev', 'previous rack'), 'rack', $prev_id) . '</td>'; |
938 | echo '<td><h2>' . mkA ($rackData['name'], 'rack', $rackData['id']) . '</h2></td>'; | |
e673ee24 | 939 | if ($next_id != NULL) |
ad3e5e7e | 940 | echo '<td>' . mkA (getImageHREF ('next', 'next rack'), 'rack', $next_id) . '</td>'; |
d48d8820 | 941 | echo "</h2></td></tr></table>\n"; |
e673ee24 | 942 | echo "<table class=rack border=0 cellspacing=0 cellpadding=1>\n"; |
d08147d6 DO |
943 | echo "<tr><th width='10%'> </th><th width='20%'>Front</th>"; |
944 | echo "<th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n"; | |
e673ee24 DO |
945 | for ($i = $rackData['height']; $i > 0; $i--) |
946 | { | |
4dcd770e | 947 | echo "<tr><th>" . inverseRackUnit ($i, $rackData) . "</th>"; |
e673ee24 DO |
948 | for ($locidx = 0; $locidx < 3; $locidx++) |
949 | { | |
950 | if (isset ($rackData[$i][$locidx]['skipped'])) | |
951 | continue; | |
952 | $state = $rackData[$i][$locidx]['state']; | |
65e557dd | 953 | echo "<td class='atom state_${state}"; |
e673ee24 DO |
954 | if (isset ($rackData[$i][$locidx]['hl'])) |
955 | echo $rackData[$i][$locidx]['hl']; | |
65e557dd | 956 | echo "'"; |
e673ee24 DO |
957 | if (isset ($rackData[$i][$locidx]['colspan'])) |
958 | echo ' colspan=' . $rackData[$i][$locidx]['colspan']; | |
959 | if (isset ($rackData[$i][$locidx]['rowspan'])) | |
960 | echo ' rowspan=' . $rackData[$i][$locidx]['rowspan']; | |
961 | echo ">"; | |
962 | switch ($state) | |
963 | { | |
964 | case 'T': | |
84feb87b | 965 | printObjectDetailsForRenderRack ($rackData[$i][$locidx]['object_id'], $hl_obj_id); |
e673ee24 DO |
966 | break; |
967 | case 'A': | |
968 | echo '<div title="This rackspace does not exist"> </div>'; | |
969 | break; | |
970 | case 'F': | |
971 | echo '<div title="Free rackspace"> </div>'; | |
972 | break; | |
973 | case 'U': | |
974 | echo '<div title="Problematic rackspace, you CAN\'T mount here"> </div>'; | |
975 | break; | |
976 | default: | |
977 | echo '<div title="No data"> </div>'; | |
978 | break; | |
979 | } | |
980 | echo '</td>'; | |
981 | } | |
982 | echo "</tr>\n"; | |
983 | } | |
0a7feebb AD |
984 | echo "</table>\n"; |
985 | // Get a list of all of objects Zero-U mounted to this rack | |
c17a36f0 AA |
986 | $zeroUObjects = getChildren ($rackData, 'object'); |
987 | uasort ($zeroUObjects, 'compare_name'); | |
a20a4e3c DO |
988 | if (count ($zeroUObjects) > 0) |
989 | { | |
0a7feebb AD |
990 | echo "<br><table width='75%' class=rack border=0 cellspacing=0 cellpadding=1>\n"; |
991 | echo "<tr><th>Zero-U:</th></tr>\n"; | |
992 | foreach ($zeroUObjects as $zeroUObject) | |
993 | { | |
c17a36f0 | 994 | $state = ($zeroUObject['id'] == $hl_obj_id) ? 'Th' : 'T'; |
a2037cdd DO |
995 | if ($zeroUObject['has_problems'] == 'yes') |
996 | $state .= 'w'; | |
0a7feebb | 997 | echo "<tr><td class='atom state_${state}'>"; |
c17a36f0 | 998 | printObjectDetailsForRenderRack($zeroUObject['id']); |
0a7feebb AD |
999 | echo "</td></tr>\n"; |
1000 | } | |
1001 | echo "</table>\n"; | |
1002 | } | |
1003 | echo "</center>\n"; | |
e673ee24 DO |
1004 | } |
1005 | ||
9da8ee26 | 1006 | function renderRackSortForm() |
42504426 | 1007 | { |
9da8ee26 | 1008 | $row_id = getBypassValue(); |
b090b2da RQ |
1009 | includeJQueryUI (false); |
1010 | $js = <<<JSTXT | |
1011 | $(document).ready( | |
1012 | function () { | |
1013 | $("#sortRacks").sortable({ | |
1014 | update : function () { | |
1015 | serial = $('#sortRacks').sortable('serialize'); | |
1016 | $.ajax({ | |
824886b2 | 1017 | url: 'index.php?module=ajax&ac=upd-rack-sort-order&row_id=${row_id}', |
b090b2da RQ |
1018 | type: 'post', |
1019 | data: serial, | |
1020 | }); | |
1021 | } | |
1022 | }); | |
1023 | } | |
42504426 | 1024 | ); |
b090b2da RQ |
1025 | JSTXT; |
1026 | addJS($js, true); | |
42504426 AD |
1027 | |
1028 | startPortlet ('Racks'); | |
1029 | echo "<table border=0 cellspacing=0 cellpadding=5 align=center class=widetable>\n"; | |
1030 | echo "<tr><th>Drag to change order</th></tr>\n"; | |
1031 | echo "<tr><td><ul class='uflist' id='sortRacks'>\n"; | |
1032 | foreach (getRacks($row_id) as $rack_id => $rackInfo) | |
1033 | echo "<li id=racks_${rack_id}>${rackInfo['name']}</li>\n"; | |
1034 | echo "</ul></td></tr></table>\n"; | |
1035 | finishPortlet(); | |
1036 | } | |
1037 | ||
9da8ee26 | 1038 | function renderNewRackForm() |
e673ee24 | 1039 | { |
9b8174d7 AD |
1040 | $default_height = getConfigVar ('DEFAULT_RACK_HEIGHT'); |
1041 | if ($default_height == 0) | |
1042 | $default_height = ''; | |
50b4ba85 | 1043 | startPortlet ('Add one'); |
f19c75d6 | 1044 | printOpFormIntro ('addRack', array ('got_data' => 'TRUE')); |
e673ee24 | 1045 | echo '<table border=0 align=center>'; |
04c61e7e AB |
1046 | echo "<tr><th class=tdright>Name (required):</th><td class=tdleft><input type=text name=name></td>"; |
1047 | echo "<tr><th class=tdright>Height in units (required):</th><td class=tdleft><input type=text name=height1 value='${default_height}'></td></tr>\n"; | |
1048 | echo "<tr><th class=tdright>Asset tag:</th><td class=tdleft><input type=text name=asset_no></td></tr>\n"; | |
1049 | echo "<tr><th class=tdright>Tags:</td><td class=tdleft>"; | |
e7b84015 | 1050 | printTagsPicker (); |
72d52730 | 1051 | echo "</td></tr>\n"; |
f19c75d6 DO |
1052 | echo "<tr><td class=submit colspan=2>"; |
1053 | printImageHREF ('CREATE', 'Add', TRUE); | |
1054 | echo "</td></tr></table></form>"; | |
406b54bd | 1055 | finishPortlet(); |
406b54bd | 1056 | |
50b4ba85 | 1057 | startPortlet ('Add many'); |
f19c75d6 | 1058 | printOpFormIntro ('addRack', array ('got_mdata' => 'TRUE')); |
50b4ba85 | 1059 | echo '<table border=0 align=center>'; |
9b8174d7 | 1060 | echo "<tr><th class=tdright>Height in units (*):</th><td class=tdleft><input type=text name=height2 value='${default_height}'></td>"; |
04c61e7e | 1061 | echo "<tr><th class=tdright>Assign tags:</td><td class=tdleft>"; |
e7b84015 | 1062 | printTagsPicker (); |
72d52730 | 1063 | echo "</td></tr>\n"; |
9b8174d7 | 1064 | echo "<tr><th class=tdright>Rack names (required):</th><td class=tdleft><textarea name=names cols=40 rows=25></textarea></td></tr>\n"; |
f19c75d6 DO |
1065 | echo "<tr><td class=submit colspan=2>"; |
1066 | printImageHREF ('CREATE', 'Add', TRUE); | |
e673ee24 DO |
1067 | echo '</form></table>'; |
1068 | finishPortlet(); | |
1069 | } | |
1070 | ||
3825c4db | 1071 | function renderEditObjectForm() |
e673ee24 | 1072 | { |
42422859 | 1073 | global $pageno; |
3825c4db | 1074 | $object_id = getBypassValue(); |
fb6e2f57 | 1075 | $object = spotEntity ('object', $object_id); |
cdd3efe9 | 1076 | startPortlet (); |
43fb6eaf | 1077 | printOpFormIntro ('update'); |
cdd3efe9 AD |
1078 | |
1079 | // static attributes | |
e10f583a DO |
1080 | echo '<table border=0 cellspacing=0 cellpadding=3 align=center>'; |
1081 | echo "<tr><td> </td><th colspan=2><h2>Attributes</h2></th></tr>"; | |
3825c4db DO |
1082 | echo '<tr><td> </td><th class=tdright>Type:</th><td class=tdleft>'; |
1083 | printSelect (getObjectTypeChangeOptions ($object['id']), array ('name' => 'object_type_id'), $object['objtype_id']); | |
1084 | echo '</td></tr>'; | |
22bb04da | 1085 | // baseline info |
e10f583a | 1086 | echo "<tr><td> </td><th class=tdright>Common name:</th><td class=tdleft><input type=text name=object_name value='${object['name']}'></td></tr>\n"; |
42422859 AD |
1087 | echo "<tr><td> </td><th class=tdright>Visible label:</th><td class=tdleft><input type=text name=object_label value='${object['label']}'></td></tr>\n"; |
1088 | echo "<tr><td> </td><th class=tdright>Asset tag:</th><td class=tdleft><input type=text name=object_asset_no value='${object['asset_no']}'></td></tr>\n"; | |
e7b84015 AB |
1089 | echo "<tr><td> </td><th class=tdright>Tags:</th><td class=tdleft>"; |
1090 | printTagsPicker (); | |
1091 | echo "</td></tr>\n"; | |
0682218d | 1092 | // parent selection |
9b8174d7 | 1093 | if (objectTypeMayHaveParent ($object['objtype_id'])) |
0682218d | 1094 | { |
9563f56f | 1095 | $parents = getParents ($object, 'object'); |
af8916e9 AD |
1096 | // lookup the human-readable object type, sort by it |
1097 | foreach ($parents as $parent_id => $parent) | |
1098 | $parents[$parent_id]['object_type'] = decodeObjectType ($parent['objtype_id']); | |
1099 | $grouped_parents = groupBy ($parents, 'object_type'); | |
1100 | ksort ($grouped_parents); | |
1101 | foreach ($grouped_parents as $parents_group) | |
0682218d | 1102 | { |
9563f56f | 1103 | uasort ($parents_group, 'compare_name'); |
af8916e9 | 1104 | $label = $parents_group[key ($parents_group)]['object_type'] . (count($parents_group) > 1 ? ' containers:' : ' container:'); |
9563f56f | 1105 | foreach ($parents_group as $link_id => $parent_cell) |
8526b4cc | 1106 | { |
8526b4cc J |
1107 | echo "<tr><td> </td>"; |
1108 | echo "<th class=tdright>${label}</th><td class=tdleft>"; | |
9563f56f | 1109 | echo mkCellA ($parent_cell); |
8526b4cc J |
1110 | echo " "; |
1111 | echo getOpLink (array('op'=>'unlinkObjects', 'link_id'=>$link_id), '', 'cut', 'Unlink container'); | |
1112 | echo "</td></tr>\n"; | |
1113 | $label = ' '; | |
1114 | } | |
0682218d AD |
1115 | } |
1116 | echo "<tr><td> </td>"; | |
1117 | echo "<th class=tdright>Select container:</th><td class=tdleft>"; | |
5d4ca0f3 | 1118 | echo getPopupLink ('objlist', array(), 'findlink', 'attach', 'Select a container'); |
de55c069 | 1119 | echo "</td></tr>\n"; |
0682218d | 1120 | } |
cdd3efe9 | 1121 | // optional attributes |
a2a7f6f6 | 1122 | $i = 0; |
249c78b2 | 1123 | $values = getAttrValuesSorted ($object_id); |
2b98d5a2 | 1124 | if (count($values) > 0) |
e673ee24 | 1125 | { |
2b98d5a2 | 1126 | foreach ($values as $record) |
e673ee24 | 1127 | { |
990fce2a AA |
1128 | if (! permitted (NULL, NULL, NULL, array ( |
1129 | array ('tag' => '$attr_' . $record['id']), | |
1130 | array ('tag' => '$any_op'), | |
1131 | ))) | |
1132 | continue; | |
2b98d5a2 AD |
1133 | echo "<input type=hidden name=${i}_attr_id value=${record['id']}>"; |
1134 | echo '<tr><td>'; | |
59a83bd8 | 1135 | if (strlen ($record['value'])) |
10f5133a | 1136 | echo getOpLink (array('op'=>'clearSticker', 'attr_id'=>$record['id']), '', 'clear', 'Clear value', 'need-confirmation'); |
2b98d5a2 AD |
1137 | else |
1138 | echo ' '; | |
1139 | echo '</td>'; | |
edb59cb5 DO |
1140 | echo "<th class=sticker>${record['name']}"; |
1141 | if ($record['type'] == 'date') | |
1142 | echo ' (' . datetimeFormatHint (getConfigVar ('DATETIME_FORMAT')) . ')'; | |
1143 | echo ':</th><td class=tdleft>'; | |
2b98d5a2 AD |
1144 | switch ($record['type']) |
1145 | { | |
1146 | case 'uint': | |
1147 | case 'float': | |
1148 | case 'string': | |
1149 | echo "<input type=text name=${i}_value value='${record['value']}'>"; | |
1150 | break; | |
1151 | case 'dict': | |
7fa7047a | 1152 | $chapter = readChapter ($record['chapter_id'], 'o'); |
2b98d5a2 | 1153 | $chapter[0] = '-- NOT SET --'; |
f3d274bf | 1154 | $chapter = cookOptgroups ($chapter, $object['objtype_id'], $record['key']); |
cd3775e9 | 1155 | printNiftySelect ($chapter, array ('name' => "${i}_value"), $record['key']); |
2b98d5a2 | 1156 | break; |
86ff26ae | 1157 | case 'date': |
2a943f85 | 1158 | $date_value = $record['value'] ? datetimestrFromTimestamp ($record['value']) : ''; |
86ff26ae DO |
1159 | echo "<input type=text name=${i}_value value='${date_value}'>"; |
1160 | break; | |
2b98d5a2 AD |
1161 | } |
1162 | echo "</td></tr>\n"; | |
1163 | $i++; | |
e673ee24 | 1164 | } |
e673ee24 | 1165 | } |
a2a7f6f6 | 1166 | echo '<input type=hidden name=num_attrs value=' . $i . ">\n"; |
e10f583a DO |
1167 | echo "<tr><td> </td><th class=tdright>Has problems:</th><td class=tdleft><input type=checkbox name=object_has_problems"; |
1168 | if ($object['has_problems'] == 'yes') | |
1169 | echo ' checked'; | |
1170 | echo "></td></tr>\n"; | |
dec748f6 | 1171 | echo "<tr><td> </td><th class=tdright>Actions:</th><td class=tdleft>"; |
10f5133a | 1172 | echo getOpLink (array ('op'=>'deleteObject', 'page'=>'depot', 'tab'=>'addmore', 'object_id'=>$object_id), '' ,'destroy', 'Delete object', 'need-confirmation'); |
abd1e9ac | 1173 | echo " "; |
10f5133a | 1174 | echo getOpLink (array ('op'=>'resetObject'), '' ,'clear', 'Reset (cleanup) object', 'need-confirmation'); |
abd1e9ac | 1175 | echo "</td></tr>\n"; |
e10f583a | 1176 | echo "<tr><td colspan=3><b>Comment:</b><br><textarea name=object_comment rows=10 cols=80>${object['comment']}</textarea></td></tr>"; |
cdd3efe9 | 1177 | |
e10f583a | 1178 | echo "<tr><th class=submit colspan=3>"; |
5bbbeaa2 | 1179 | printImageHREF ('SAVE', 'Save changes', TRUE); |
cdd3efe9 | 1180 | echo "</form></th></tr></table>\n"; |
e673ee24 | 1181 | finishPortlet(); |
e673ee24 | 1182 | |
cdd3efe9 | 1183 | echo '<table border=0 width=100%><tr><td>'; |
e673ee24 | 1184 | startPortlet ('history'); |
9b8174d7 | 1185 | renderObjectHistory ($object_id); |
e673ee24 | 1186 | finishPortlet(); |
cdd3efe9 | 1187 | echo '</td></tr></table>'; |
e673ee24 DO |
1188 | } |
1189 | ||
9da8ee26 | 1190 | function renderEditRackForm() |
e673ee24 | 1191 | { |
0c2b7c4a | 1192 | global $pageno; |
9da8ee26 | 1193 | $rack_id = getBypassValue(); |
61a1d996 DO |
1194 | $rack = spotEntity ('rack', $rack_id); |
1195 | amplifyCell ($rack); | |
e673ee24 | 1196 | |
9b8174d7 | 1197 | startPortlet ('Attributes'); |
7056988c | 1198 | printOpFormIntro ('updateRack'); |
e673ee24 | 1199 | echo '<table border=0 align=center>'; |
9b8174d7 | 1200 | echo "<tr><td> </td><th class=tdright>Rack row:</th><td class=tdleft>"; |
524f8a7b | 1201 | foreach (listCells ('row') as $row_id => $rowInfo) |
64a973a7 AD |
1202 | { |
1203 | $trail = getLocationTrail ($rowInfo['location_id'], FALSE); | |
1204 | $rows[$row_id] = empty ($trail) ? $rowInfo['name'] : $rowInfo['name'] . ' [' . $trail . ']'; | |
1205 | } | |
1206 | natcasesort ($rows); | |
e1add254 | 1207 | printSelect ($rows, array ('name' => 'row_id'), $rack['row_id']); |
e673ee24 | 1208 | echo "</td></tr>\n"; |
9b8174d7 AD |
1209 | echo "<tr><td> </td><th class=tdright>Name (required):</th><td class=tdleft><input type=text name=name value='${rack['name']}'></td></tr>\n"; |
1210 | echo "<tr><td> </td><th class=tdright>Height (required):</th><td class=tdleft><input type=text name=height value='${rack['height']}'></td></tr>\n"; | |
9b8174d7 | 1211 | echo "<tr><td> </td><th class=tdright>Asset tag:</th><td class=tdleft><input type=text name=asset_no value='${rack['asset_no']}'></td></tr>\n"; |
e7b84015 AB |
1212 | echo "<tr><td> </td><th class=tdright>Tags:</th><td class=tdleft>"; |
1213 | printTagsPicker (); | |
1214 | echo "</td></tr>\n"; | |
9b8174d7 | 1215 | // optional attributes |
249c78b2 | 1216 | $values = getAttrValuesSorted ($rack_id); |
9b8174d7 | 1217 | $num_attrs = count($values); |
42504426 | 1218 | $num_attrs = $num_attrs-2; // subtract for the 'height' and 'sort_order' attributes |
9b8174d7 AD |
1219 | echo "<input type=hidden name=num_attrs value=${num_attrs}>\n"; |
1220 | $i = 0; | |
1221 | foreach ($values as $record) | |
1222 | { | |
1223 | // Skip the 'height' attribute as it's already displayed as a required field | |
42504426 AD |
1224 | // Also skip the 'sort_order' attribute |
1225 | if ($record['id'] == 27 or $record['id'] == 29) | |
9b8174d7 AD |
1226 | continue; |
1227 | echo "<input type=hidden name=${i}_attr_id value=${record['id']}>"; | |
1228 | echo '<tr><td>'; | |
1229 | if (strlen ($record['value'])) | |
10f5133a | 1230 | echo getOpLink (array('op'=>'clearSticker', 'attr_id'=>$record['id']), '', 'clear', 'Clear value', 'need-confirmation'); |
9b8174d7 AD |
1231 | else |
1232 | echo ' '; | |
1233 | echo '</td>'; | |
1234 | echo "<th class=sticker>${record['name']}:</th><td class=tdleft>"; | |
1235 | switch ($record['type']) | |
1236 | { | |
1237 | case 'uint': | |
1238 | case 'float': | |
1239 | case 'string': | |
1240 | echo "<input type=text name=${i}_value value='${record['value']}'>"; | |
1241 | break; | |
1242 | case 'dict': | |
1243 | $chapter = readChapter ($record['chapter_id'], 'o'); | |
1244 | $chapter[0] = '-- NOT SET --'; | |
1245 | $chapter = cookOptgroups ($chapter, 1560, $record['key']); | |
1246 | printNiftySelect ($chapter, array ('name' => "${i}_value"), $record['key']); | |
1247 | break; | |
1248 | } | |
1249 | echo "</td></tr>\n"; | |
1250 | $i++; | |
1251 | } | |
1252 | echo "<tr><td> </td><th class=tdright>Has problems:</th><td class=tdleft><input type=checkbox name=has_problems"; | |
1253 | if ($rack['has_problems'] == 'yes') | |
1254 | echo ' checked'; | |
1255 | echo "></td></tr>\n"; | |
04eee8d2 | 1256 | echo "<tr><td> </td><th class=tdright>Actions:</th><td class=tdleft>"; |
c495997f | 1257 | if ($rack['isDeletable']) |
c8187437 | 1258 | { |
10f5133a | 1259 | echo getOpLink (array ('op'=>'deleteRack'), '', 'destroy', 'Delete rack', 'need-confirmation'); |
04eee8d2 | 1260 | echo " "; |
c8187437 | 1261 | } |
04eee8d2 VS |
1262 | else |
1263 | { | |
1264 | echo getOpLink (array ('op'=>'cleanRack'), '' ,'clear', 'Reset (cleanup) rack mounts', 'need-confirmation'); | |
1265 | echo " "; | |
1266 | } | |
1267 | echo "</td></tr>\n"; | |
9b8174d7 AD |
1268 | echo "<tr><td colspan=3><b>Comment:</b><br><textarea name=comment rows=10 cols=80>${rack['comment']}</textarea></td></tr>"; |
1269 | echo "<tr><td class=submit colspan=3>"; | |
7056988c DO |
1270 | printImageHREF ('SAVE', 'Save changes', TRUE); |
1271 | echo "</td></tr>\n"; | |
e673ee24 DO |
1272 | echo '</form></table><br>'; |
1273 | finishPortlet(); | |
dec748f6 | 1274 | |
e673ee24 | 1275 | startPortlet ('History'); |
9b8174d7 | 1276 | renderObjectHistory ($rack_id); |
e673ee24 DO |
1277 | finishPortlet(); |
1278 | } | |
1279 | ||
6b9bdb08 AA |
1280 | // populates the $summary array with the sum of power attributes of the objects mounted into the rack |
1281 | function populateRackPower ($rackData, &$summary) | |
1282 | { | |
1283 | $power_attrs = array( | |
1284 | 7, // 'float','max. current, Ampers' | |
1285 | 13, // 'float','max power, Watts' | |
1286 | ); | |
1287 | $sum = array(); | |
1288 | if (! isset ($rackData['mountedObjects'])) | |
1289 | amplifyCell ($rackData); | |
1290 | foreach ($rackData['mountedObjects'] as $object_id) | |
1291 | { | |
1292 | $attrs = getAttrValues ($object_id); | |
1293 | foreach ($power_attrs as $attr_id) | |
1294 | if (isset ($attrs[$attr_id]) && $attrs[$attr_id]['type'] == 'float') | |
1295 | { | |
1296 | if (! isset ($sum[$attr_id])) | |
1297 | { | |
1298 | $sum[$attr_id]['sum'] = 0.0; | |
1299 | $sum[$attr_id]['name'] = $attrs[$attr_id]['name']; | |
1300 | } | |
1301 | $sum[$attr_id]['sum'] += $attrs[$attr_id]['value']; | |
1302 | } | |
1303 | } | |
1304 | foreach ($sum as $attr) | |
1305 | if ($attr['sum'] > 0.0) | |
1306 | $summary[$attr['name']] = $attr['sum']; | |
1307 | } | |
1308 | ||
254673dd DO |
1309 | // used by renderGridForm() and renderRackPage() |
1310 | function renderRackInfoPortlet ($rackData) | |
1311 | { | |
646272be | 1312 | $summary = array(); |
67cfe546 | 1313 | $summary['Rack row'] = mkA ($rackData['row_name'], 'row', $rackData['row_id']); |
646272be AA |
1314 | $summary['Name'] = $rackData['name']; |
1315 | $summary['Height'] = $rackData['height']; | |
9b8174d7 | 1316 | if (strlen ($rackData['asset_no'])) |
646272be | 1317 | $summary['Asset tag'] = $rackData['asset_no']; |
9b8174d7 | 1318 | if ($rackData['has_problems'] == 'yes') |
646272be | 1319 | $summary[] = array ('<tr><td colspan=2 class=msg_error>Has problems</td></tr>'); |
6b9bdb08 | 1320 | populateRackPower ($rackData, $summary); |
42504426 AD |
1321 | // Display populated attributes, but skip 'height' since it's already displayed above |
1322 | // and skip 'sort_order' because it's modified using AJAX | |
249c78b2 | 1323 | foreach (getAttrValuesSorted ($rackData['id']) as $record) |
42504426 | 1324 | if ($record['id'] != 27 && $record['id'] != 29 && strlen ($record['value'])) |
646272be AA |
1325 | $summary['{sticker}' . $record['name']] = formatAttributeValue ($record); |
1326 | $summary['% used'] = getProgressBar (getRSUforRack ($rackData)); | |
1327 | $summary['Objects'] = count ($rackData['mountedObjects']); | |
1328 | $summary['tags'] = ''; | |
646272be | 1329 | renderEntitySummary ($rackData, 'summary', $summary); |
0602fc27 DO |
1330 | if ($rackData['comment'] != '') |
1331 | { | |
1332 | startPortlet ('Comment'); | |
1333 | echo '<div class=commentblock>' . string_insert_hrefs ($rackData['comment']) . '</div>'; | |
1334 | finishPortlet (); | |
1335 | } | |
254673dd DO |
1336 | } |
1337 | ||
e673ee24 | 1338 | // This is a universal editor of rack design/waste. |
7056988c | 1339 | // FIXME: switch to using printOpFormIntro() |
7e1db771 | 1340 | function renderGridForm ($rack_id, $filter, $header, $submit, $state1, $state2) |
e673ee24 | 1341 | { |
61a1d996 DO |
1342 | $rackData = spotEntity ('rack', $rack_id); |
1343 | amplifyCell ($rackData); | |
254673dd | 1344 | $filter ($rackData); |
e673ee24 | 1345 | |
e673ee24 DO |
1346 | // Render the result whatever it is. |
1347 | // Main layout. | |
1348 | echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>"; | |
1349 | echo "<tr><td colspan=2 align=center><h1>${rackData['name']}</h1></td></tr>\n"; | |
1350 | ||
1351 | // Left column with information portlet. | |
1352 | echo "<tr><td class=pcleft height='1%' width='50%'>"; | |
254673dd | 1353 | renderRackInfoPortlet ($rackData); |
e673ee24 | 1354 | echo "</td>\n"; |
bb09cca0 | 1355 | echo "<td class=pcright>"; |
e673ee24 DO |
1356 | |
1357 | // Grid form. | |
c26d97b6 | 1358 | $is_ro = !rackModificationPermitted ($rackData, 'updateRack'); |
e673ee24 | 1359 | startPortlet ($header); |
65e557dd | 1360 | addJS ('js/racktables.js'); |
e673ee24 | 1361 | echo "<center>\n"; |
c26d97b6 VS |
1362 | $read_only_text = $is_ro ? '(read-only)' : ' '; |
1363 | echo "<p style='color: red; margin-top:0px'>${read_only_text}</p>\n"; | |
e673ee24 | 1364 | echo "<table class=rack border=0 cellspacing=0 cellpadding=1>\n"; |
57c69e9c | 1365 | echo "<tr><th width='10%'> </th>"; |
bd0bfb76 AD |
1366 | echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '0', ${rackData['height']})\">Front</a></th>"; |
1367 | echo "<th width='50%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '1', ${rackData['height']})\">Interior</a></th>"; | |
1368 | echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '2', ${rackData['height']})\">Back</a></th></tr>\n"; | |
4fbb5a00 | 1369 | printOpFormIntro ('updateRack'); |
e673ee24 | 1370 | markupAtomGrid ($rackData, $state2); |
c26d97b6 | 1371 | renderAtomGrid ($rackData, $is_ro); |
e673ee24 DO |
1372 | echo "</table></center>\n"; |
1373 | echo "<br><input type=submit name=do_update value='${submit}'></form><br><br>\n"; | |
1374 | finishPortlet(); | |
bb09cca0 | 1375 | echo "</td></tr></table>\n"; |
e673ee24 DO |
1376 | } |
1377 | ||
1378 | function renderRackDesign ($rack_id) | |
1379 | { | |
bb09cca0 | 1380 | renderGridForm ($rack_id, 'applyRackDesignMask', 'Rack design', 'Set rack design', 'A', 'F'); |
e673ee24 DO |
1381 | } |
1382 | ||
7e1db771 | 1383 | function renderRackProblems ($rack_id) |
e673ee24 | 1384 | { |
bb09cca0 | 1385 | renderGridForm ($rack_id, 'applyRackProblemMask', 'Rack problems', 'Mark unusable atoms', 'F', 'U'); |
e673ee24 DO |
1386 | } |
1387 | ||
40c9fc94 AA |
1388 | function renderObjectPortRow ($port, $is_highlighted) |
1389 | { | |
8579b51b AA |
1390 | // highlight port name with yellow if it's name is not canonical |
1391 | $canon_pn = shortenPortName ($port['name'], $port['object_id']); | |
1392 | $name_class = $canon_pn == $port['name'] ? '' : 'trwarning'; | |
1393 | ||
90bf1755 DO |
1394 | echo '<tr'; |
1395 | if ($is_highlighted) | |
1396 | echo ' class=highlight'; | |
40c9fc94 | 1397 | $a_class = isEthernetPort ($port) ? 'port-menu' : ''; |
8579b51b | 1398 | echo "><td class='tdleft $name_class' NOWRAP><a name='port-${port['id']}' class='interactive-portname nolink $a_class'>${port['name']}</a></td>"; |
40c9fc94 AA |
1399 | echo "<td class=tdleft>${port['label']}</td>"; |
1400 | echo "<td class=tdleft>" . formatPortIIFOIF ($port) . "</td><td class=tdleft><tt>${port['l2address']}</tt></td>"; | |
0b09238d | 1401 | if ($port['remote_object_id']) |
90bf1755 | 1402 | { |
0b09238d DO |
1403 | echo "<td class=tdleft>" . |
1404 | formatPortLink ($port['remote_object_id'], $port['remote_object_name'], $port['remote_id'], NULL) . | |
1405 | "</td>"; | |
1406 | echo "<td class=tdleft>" . formatLoggedSpan ($port['last_log'], $port['remote_name'], 'underline') . "</td>"; | |
1407 | $editable = permitted ('object', 'ports', 'editPort') | |
1408 | ? 'editable' | |
1409 | : ''; | |
1410 | echo "<td class=tdleft><span class='rsvtext $editable id-${port['id']} op-upd-reservation-cable'>${port['cableid']}</span></td>"; | |
40c9fc94 | 1411 | } |
90bf1755 DO |
1412 | else |
1413 | echo implode ('', formatPortReservation ($port)) . '<td></td>'; | |
0b09238d | 1414 | echo "</tr>"; |
40c9fc94 AA |
1415 | } |
1416 | ||
9da8ee26 | 1417 | function renderObject() |
e673ee24 | 1418 | { |
8dc2a6c8 | 1419 | global $nextorder, $virtual_obj_types; |
9da8ee26 | 1420 | $object_id = getBypassValue(); |
fb6e2f57 | 1421 | $info = spotEntity ('object', $object_id); |
94fe6370 | 1422 | amplifyCell ($info); |
e673ee24 DO |
1423 | // Main layout starts. |
1424 | echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>"; | |
1425 | echo "<tr><td colspan=2 align=center><h1>${info['dname']}</h1></td></tr>\n"; | |
1426 | // left column with uknown number of portlets | |
1427 | echo "<tr><td class=pcleft>"; | |
646272be AA |
1428 | |
1429 | // display summary portlet | |
1430 | $summary = array(); | |
59a83bd8 | 1431 | if (strlen ($info['name'])) |
646272be | 1432 | $summary['Common name'] = $info['name']; |
94fe6370 | 1433 | elseif (considerConfiguredConstraint ($info, 'NAMEWARN_LISTSRC')) |
646272be AA |
1434 | $summary[] = array ('<tr><td colspan=2 class=msg_error>Common name is missing.</td></tr>'); |
1435 | $summary['Object type'] = '<a href="' . makeHref (array ( | |
341fd895 DO |
1436 | 'page' => 'depot', |
1437 | 'tab' => 'default', | |
1438 | 'cfe' => '{$typeid_' . $info['objtype_id'] . '}' | |
eb11ba46 | 1439 | )) . '">' . decodeObjectType ($info['objtype_id']) . '</a>'; |
9b8174d7 | 1440 | if (strlen ($info['label'])) |
646272be | 1441 | $summary['Visible label'] = $info['label']; |
59a83bd8 | 1442 | if (strlen ($info['asset_no'])) |
646272be | 1443 | $summary['Asset tag'] = $info['asset_no']; |
d4e8ddeb | 1444 | elseif (considerConfiguredConstraint ($info, 'ASSETWARN_LISTSRC')) |
646272be | 1445 | $summary[] = array ('<tr><td colspan=2 class=msg_error>Asset tag is missing.</td></tr>'); |
9563f56f | 1446 | $parents = getParents ($info, 'object'); |
af8916e9 AD |
1447 | // lookup the human-readable object type, sort by it |
1448 | foreach ($parents as $parent_id => $parent) | |
1449 | $parents[$parent_id]['object_type'] = decodeObjectType ($parent['objtype_id']); | |
1450 | $grouped_parents = groupBy ($parents, 'object_type'); | |
1451 | ksort ($grouped_parents); | |
1452 | foreach ($grouped_parents as $parents_group) | |
0682218d | 1453 | { |
9563f56f | 1454 | uasort ($parents_group, 'compare_name'); |
af8916e9 | 1455 | $label = $parents_group[key ($parents_group)]['object_type'] . (count($parents_group) > 1 ? ' containers' : ' container'); |
9563f56f AA |
1456 | $fmt_parents = array(); |
1457 | foreach ($parents_group as $parent) | |
1458 | $fmt_parents[] = mkCellA ($parent); | |
af8916e9 | 1459 | $summary[$label] = implode ('<br>', $fmt_parents); |
0682218d | 1460 | } |
9563f56f AA |
1461 | $children = getChildren ($info, 'object'); |
1462 | foreach (groupBy ($children, 'objtype_id') as $objtype_id => $children_group) | |
42fb3aa2 | 1463 | { |
9563f56f AA |
1464 | uasort ($children_group, 'compare_name'); |
1465 | $fmt_children = array(); | |
1466 | foreach ($children_group as $child) | |
1467 | $fmt_children[] = mkCellA ($child); | |
1468 | $summary["Contains " . strtolower(decodeObjectType ($objtype_id))] = implode ('<br>', $fmt_children); | |
42fb3aa2 | 1469 | } |
e673ee24 | 1470 | if ($info['has_problems'] == 'yes') |
646272be | 1471 | $summary[] = array ('<tr><td colspan=2 class=msg_error>Has problems</td></tr>'); |
249c78b2 | 1472 | foreach (getAttrValuesSorted ($object_id) as $record) |
4969aa31 DO |
1473 | if |
1474 | ( | |
dec748f6 | 1475 | strlen ($record['value']) and |
4969aa31 DO |
1476 | permitted (NULL, NULL, NULL, array (array ('tag' => '$attr_' . $record['id']))) |
1477 | ) | |
646272be | 1478 | $summary['{sticker}' . $record['name']] = formatAttributeValue ($record); |
a2c597ea AA |
1479 | $summary[] = array (getOutputOf ('printTagTRs', |
1480 | $info, | |
1481 | makeHref | |
1482 | ( | |
1483 | array | |
1484 | ( | |
1485 | 'page'=>'depot', | |
1486 | 'tab'=>'default', | |
1487 | 'andor' => 'and', | |
1488 | 'cfe' => '{$typeid_' . $info['objtype_id'] . '}', | |
1489 | ) | |
1490 | )."&" | |
1491 | )); | |
0b09238d | 1492 | renderEntitySummary ($info, 'summary', $summary); |
e673ee24 | 1493 | |
59a83bd8 | 1494 | if (strlen ($info['comment'])) |
e673ee24 DO |
1495 | { |
1496 | startPortlet ('Comment'); | |
6cc5d6cd | 1497 | echo '<div class=commentblock>' . string_insert_hrefs ($info['comment']) . '</div>'; |
e673ee24 DO |
1498 | finishPortlet (); |
1499 | } | |
1500 | ||
b5700329 AA |
1501 | $logrecords = getLogRecordsForObject ($_REQUEST['object_id']); |
1502 | if (count ($logrecords)) | |
9a90adc4 DO |
1503 | { |
1504 | startPortlet ('log records'); | |
1505 | echo "<table cellspacing=0 cellpadding=5 align=center class=widetable width='100%'>"; | |
1506 | $order = 'odd'; | |
b5700329 | 1507 | foreach ($logrecords as $row) |
9a90adc4 DO |
1508 | { |
1509 | echo "<tr class=row_${order} valign=top>"; | |
1510 | echo '<td class=tdleft>' . $row['date'] . '<br>' . $row['user'] . '</td>'; | |
0b8d8309 | 1511 | echo '<td class="logentry">' . string_insert_hrefs (htmlspecialchars ($row['content'], ENT_NOQUOTES)) . '</td>'; |
9a90adc4 DO |
1512 | echo '</tr>'; |
1513 | $order = $nextorder[$order]; | |
1514 | } | |
1515 | echo '</table>'; | |
1516 | finishPortlet(); | |
1517 | } | |
1518 | ||
65e557dd | 1519 | switchportInfoJS ($object_id); // load JS code to make portnames interactive |
e1ae3fb4 AD |
1520 | renderFilesPortlet ('object', $object_id); |
1521 | ||
9f75e165 | 1522 | if (count ($info['ports'])) |
e673ee24 | 1523 | { |
0b09238d | 1524 | startPortlet ('ports and links'); |
9f75e165 DO |
1525 | $hl_port_id = 0; |
1526 | if (isset ($_REQUEST['hl_port_id'])) | |
e673ee24 | 1527 | { |
0cc24e9a | 1528 | assertUIntArg ('hl_port_id'); |
9f75e165 | 1529 | $hl_port_id = $_REQUEST['hl_port_id']; |
65e557dd | 1530 | addAutoScrollScript ("port-$hl_port_id"); |
9f75e165 | 1531 | } |
0b09238d | 1532 | echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>"; |
9f75e165 | 1533 | echo '<tr><th class=tdleft>Local name</th><th class=tdleft>Visible label</th>'; |
0d59a51c | 1534 | echo '<th class=tdleft>Interface</th><th class=tdleft>L2 address</th>'; |
0c7c9f8b | 1535 | echo '<th class=tdcenter colspan=2>Remote object and port</th>'; |
0b09238d | 1536 | echo '<th class=tdleft>Cable ID</th></tr>'; |
9f75e165 | 1537 | foreach ($info['ports'] as $port) |
40c9fc94 | 1538 | callHook ('renderObjectPortRow', $port, ($hl_port_id == $port['id'])); |
fd5edda8 | 1539 | if (permitted (NULL, 'ports', 'set_reserve_comment')) |
a8dc2982 | 1540 | addJS ('js/inplace-edit.js'); |
9f75e165 | 1541 | echo "</table><br>"; |
e673ee24 DO |
1542 | finishPortlet(); |
1543 | } | |
85970da2 | 1544 | |
21ee3351 | 1545 | if (count ($info['ipv4']) + count ($info['ipv6'])) |
e673ee24 | 1546 | { |
21ee3351 | 1547 | startPortlet ('IP addresses'); |
e673ee24 | 1548 | echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n"; |
f0ed1181 | 1549 | if (getConfigVar ('EXT_IPV4_VIEW') == 'yes') |
9d5f6a80 | 1550 | echo "<tr class=tdleft><th>OS interface</th><th>IP address</th><th>network</th><th>routed by</th><th>peers</th></tr>\n"; |
83fdf85f | 1551 | else |
9d5f6a80 | 1552 | echo "<tr class=tdleft><th>OS interface</th><th>IP address</th><th>peers</th></tr>\n"; |
21ee3351 AA |
1553 | |
1554 | // group IP allocations by interface name instead of address family | |
1555 | $allocs_by_iface = array(); | |
1556 | foreach (array ('ipv4', 'ipv6') as $ip_v) | |
4318ced5 AA |
1557 | foreach ($info[$ip_v] as $ip_bin => $alloc) |
1558 | $allocs_by_iface[$alloc['osif']][$ip_bin] = $alloc; | |
dec748f6 | 1559 | |
21ee3351 AA |
1560 | // sort allocs array by portnames |
1561 | foreach (sortPortList ($allocs_by_iface) as $iface_name => $alloclist) | |
1562 | { | |
1563 | $is_first_row = TRUE; | |
f3505b35 | 1564 | foreach ($alloclist as $alloc) |
b90c3907 | 1565 | { |
40c9fc94 | 1566 | $rendered_alloc = callHook ('getRenderedAlloc', $object_id, $alloc); |
f3505b35 | 1567 | echo "<tr class='${rendered_alloc['tr_class']}' valign=top>"; |
21ee3351 | 1568 | |
f3505b35 | 1569 | // display iface name, same values are grouped into single cell |
21ee3351 AA |
1570 | if ($is_first_row) |
1571 | { | |
1572 | $rowspan = count ($alloclist) > 1 ? 'rowspan="' . count ($alloclist) . '"' : ''; | |
40c9fc94 | 1573 | echo "<td class=tdleft $rowspan>" . $iface_name . $rendered_alloc['td_name_suffix'] . "</td>"; |
21ee3351 AA |
1574 | $is_first_row = FALSE; |
1575 | } | |
f3505b35 | 1576 | echo $rendered_alloc['td_ip']; |
21ee3351 | 1577 | if (getConfigVar ('EXT_IPV4_VIEW') == 'yes') |
83fdf85f | 1578 | { |
f3505b35 AA |
1579 | echo $rendered_alloc['td_network']; |
1580 | echo $rendered_alloc['td_routed_by']; | |
21ee3351 | 1581 | } |
f3505b35 AA |
1582 | echo $rendered_alloc['td_peers']; |
1583 | ||
1584 | echo "</tr>\n"; | |
b90c3907 | 1585 | } |
e673ee24 DO |
1586 | } |
1587 | echo "</table><br>\n"; | |
1588 | finishPortlet(); | |
1589 | } | |
1590 | ||
94fe6370 | 1591 | $forwards = $info['nat4']; |
e673ee24 DO |
1592 | if (count($forwards['in']) or count($forwards['out'])) |
1593 | { | |
f28fbe8b | 1594 | startPortlet('NATv4'); |
e673ee24 DO |
1595 | |
1596 | if (count($forwards['out'])) | |
1597 | { | |
1598 | ||
f28fbe8b | 1599 | echo "<h3>locally performed NAT</h3>"; |
e673ee24 | 1600 | |
105a3bc8 | 1601 | echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n"; |
f28fbe8b | 1602 | echo "<tr><th>Proto</th><th>Match endpoint</th><th>Translate to</th><th>Target object</th><th>Rule comment</th></tr>\n"; |
e673ee24 DO |
1603 | |
1604 | foreach ($forwards['out'] as $pf) | |
1605 | { | |
2c817354 DO |
1606 | $class = 'trerror'; |
1607 | $osif = ''; | |
6a3c2dc5 AA |
1608 | $localip_bin = ip_parse ($pf['localip']); |
1609 | if (array_key_exists ($localip_bin, $info['ipv4'])) | |
2c817354 | 1610 | { |
6a3c2dc5 AA |
1611 | $class = $info['ipv4'][$localip_bin]['addrinfo']['class']; |
1612 | $osif = $info['ipv4'][$localip_bin]['osif'] . ': '; | |
2c817354 | 1613 | } |
e673ee24 | 1614 | echo "<tr class='$class'>"; |
7419401e AA |
1615 | echo "<td>${pf['proto']}</td><td class=tdleft>${osif}" . getRenderedIPPortPair ($pf['localip'], $pf['localport']) . "</td>"; |
1616 | echo "<td class=tdleft>" . getRenderedIPPortPair ($pf['remoteip'], $pf['remoteport']) . "</td>"; | |
4318ced5 | 1617 | $address = getIPAddress (ip4_parse ($pf['remoteip'])); |
e673ee24 | 1618 | echo "<td class='description'>"; |
53ef3908 DO |
1619 | if (count ($address['allocs'])) |
1620 | foreach($address['allocs'] as $bond) | |
ad3e5e7e | 1621 | echo mkA ("${bond['object_name']}(${bond['name']})", 'object', $bond['object_id']) . ' '; |
59a83bd8 | 1622 | elseif (strlen ($pf['remote_addr_name'])) |
f28fbe8b | 1623 | echo '(' . $pf['remote_addr_name'] . ')'; |
53ef3908 | 1624 | echo "</td><td class='description'>${pf['description']}</td></tr>"; |
e673ee24 DO |
1625 | } |
1626 | echo "</table><br><br>"; | |
1627 | } | |
1628 | if (count($forwards['in'])) | |
1629 | { | |
f28fbe8b | 1630 | echo "<h3>arriving NAT connections</h3>"; |
105a3bc8 | 1631 | echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n"; |
f28fbe8b | 1632 | echo "<tr><th>Matched endpoint</th><th>Source object</th><th>Translated to</th><th>Rule comment</th></tr>\n"; |
e673ee24 DO |
1633 | foreach ($forwards['in'] as $pf) |
1634 | { | |
1635 | echo "<tr>"; | |
7419401e | 1636 | echo "<td>${pf['proto']}/" . getRenderedIPPortPair ($pf['localip'], $pf['localport']) . "</td>"; |
ad3e5e7e | 1637 | echo '<td class="description">' . mkA ($pf['object_name'], 'object', $pf['object_id']); |
7419401e | 1638 | echo "</td><td>" . getRenderedIPPortPair ($pf['remoteip'], $pf['remoteport']) . "</td>"; |
e673ee24 DO |
1639 | echo "<td class='description'>${pf['description']}</td></tr>"; |
1640 | } | |
e673ee24 DO |
1641 | echo "</table><br><br>"; |
1642 | } | |
1643 | finishPortlet(); | |
1644 | } | |
1645 | ||
eacc0983 | 1646 | renderSLBTriplets2 ($info); |
defd92d8 | 1647 | renderSLBTriplets ($info); |
e673ee24 DO |
1648 | echo "</td>\n"; |
1649 | ||
7056988c | 1650 | // After left column we have (surprise!) right column with rackspace portlet only. |
e673ee24 | 1651 | echo "<td class=pcright>"; |
8dc2a6c8 | 1652 | if (!in_array($info['objtype_id'], $virtual_obj_types)) |
0682218d AD |
1653 | { |
1654 | // rackspace portlet | |
1655 | startPortlet ('rackspace allocation'); | |
1656 | foreach (getResidentRacksData ($object_id, FALSE) as $rack_id) | |
1657 | renderRack ($rack_id, $object_id); | |
1658 | echo '<br>'; | |
1659 | finishPortlet(); | |
1660 | } | |
e673ee24 DO |
1661 | echo "</td></tr>"; |
1662 | echo "</table>\n"; | |
1663 | } | |
1664 | ||
1665 | function renderRackMultiSelect ($sname, $racks, $selected) | |
1666 | { | |
04571888 DO |
1667 | // Transform the given flat list into a list of groups, each representing a rack row. |
1668 | $rdata = array(); | |
e673ee24 | 1669 | foreach ($racks as $rack) |
d016010a | 1670 | { |
7b6ae79a AD |
1671 | $trail = getLocationTrail ($rack['location_id'], FALSE); |
1672 | if(!empty ($trail)) | |
1673 | $row_name = $trail . ' : ' . $rack['row_name']; | |
1674 | else | |
1675 | $row_name = $rack['row_name']; | |
d016010a AD |
1676 | $rdata[$row_name][$rack['id']] = $rack['name']; |
1677 | } | |
4fbb5a00 | 1678 | echo "<select name=${sname} multiple size=" . getConfigVar ('MAXSELSIZE') . " onchange='getElementsByName(\"updateObjectAllocation\")[0].submit()'>\n"; |
acfc0d89 AA |
1679 | $row_names = array_keys ($rdata); |
1680 | natsort ($row_names); | |
1681 | foreach ($row_names as $optgroup) | |
e673ee24 | 1682 | { |
04571888 | 1683 | echo "<optgroup label='${optgroup}'>"; |
acfc0d89 | 1684 | foreach ($rdata[$optgroup] as $rack_id => $rack_name) |
04571888 DO |
1685 | { |
1686 | echo "<option value=${rack_id}"; | |
1687 | if (!(array_search ($rack_id, $selected) === FALSE)) | |
1688 | echo ' selected'; | |
1689 | echo">${rack_name}</option>\n"; | |
1690 | } | |
e673ee24 DO |
1691 | } |
1692 | echo "</select>\n"; | |
1693 | } | |
1694 | ||
e673ee24 | 1695 | // This function renders a form for port edition. |
9da8ee26 | 1696 | function renderPortsForObject() |
e673ee24 | 1697 | { |
3153a326 DO |
1698 | $prefs = getPortListPrefs(); |
1699 | function printNewItemTR ($prefs) | |
39b4abd0 DO |
1700 | { |
1701 | printOpFormIntro ('addPort'); | |
1702 | echo "<tr><td>"; | |
f5ff50f5 | 1703 | printImageHREF ('add', 'add a port', TRUE); |
7b30e187 | 1704 | echo "</td><td class='tdleft'><input type=text size=16 name=port_name></td>\n"; |
04c61e7e | 1705 | echo "<td><input type=text name=port_label></td><td>"; |
759b21d2 | 1706 | printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type_id'), $prefs['selected']); |
04c61e7e | 1707 | echo "<td><input type=text name=port_l2address size=18 maxlength=24></td>\n"; |
318c48a8 | 1708 | echo "<td colspan=4> </td><td>"; |
04c61e7e | 1709 | printImageHREF ('add', 'add a port', TRUE); |
9318d2ef | 1710 | echo "</td></tr></form>"; |
39b4abd0 | 1711 | } |
a1fc539a | 1712 | if (getConfigVar('ENABLE_MULTIPORT_FORM') == 'yes' || getConfigVar('ENABLE_BULKPORT_FORM') == 'yes' ) |
f44fdef9 DO |
1713 | startPortlet ('Ports and interfaces'); |
1714 | else | |
1715 | echo '<br>'; | |
9da8ee26 | 1716 | $object = spotEntity ('object', getBypassValue()); |
9f75e165 | 1717 | amplifyCell ($object); |
a1fc539a RF |
1718 | if (getConfigVar ('ADDNEW_AT_TOP') == 'yes' && getConfigVar('ENABLE_BULKPORT_FORM') == 'yes'){ |
1719 | echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n"; | |
1720 | echo "<tr><th> </th><th class=tdleft>Local name</th><th class=tdleft>Visible label</th><th class=tdleft>Interface</th><th class=tdleft>Start Number</th>"; | |
1721 | echo "<th class=tdleft>Count</th><th> </th></tr>\n"; | |
1722 | printOpFormIntro ('addBulkPorts'); | |
1723 | echo "<tr><td>"; | |
1724 | printImageHREF ('add', 'add ports', TRUE); | |
04c61e7e AB |
1725 | echo "</td><td><input type=text size=8 name=port_name></td>\n"; |
1726 | echo "<td><input type=text name=port_label></td><td>"; | |
759b21d2 | 1727 | printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type_id'), $prefs['selected']); |
04c61e7e AB |
1728 | echo "<td><input type=text name=port_numbering_start size=3 maxlength=3></td>\n"; |
1729 | echo "<td><input type=text name=port_numbering_count size=3 maxlength=3></td>\n"; | |
0b09238d | 1730 | echo "<td> </td><td>"; |
04c61e7e | 1731 | printImageHREF ('add', 'add ports', TRUE); |
a1fc539a RF |
1732 | echo "</td></tr></form>"; |
1733 | echo "</table><br>\n"; | |
1734 | } | |
dec748f6 | 1735 | |
0b09238d | 1736 | echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n"; |
0d59a51c | 1737 | echo "<tr><th> </th><th class=tdleft>Local name</th><th class=tdleft>Visible label</th><th class=tdleft>Interface</th><th class=tdleft>L2 address</th>"; |
0b09238d | 1738 | echo "<th class=tdcenter colspan=2>Remote object and port</th><th>Cable ID</th><th class=tdcenter>(Un)link or (un)reserve</th><th> </th></tr>\n"; |
39b4abd0 | 1739 | if (getConfigVar ('ADDNEW_AT_TOP') == 'yes') |
3153a326 | 1740 | printNewItemTR ($prefs); |
45ff9012 | 1741 | |
0b09238d DO |
1742 | // clear ports link |
1743 | echo getOpLink (array ('op'=>'deleteAll'), 'Clear port list', 'clear', '', 'need-confirmation'); | |
1744 | ||
8579b51b AA |
1745 | // rename ports link |
1746 | $n_ports_to_rename = 0; | |
1747 | foreach ($object['ports'] as $port) | |
1748 | if ($port['name'] != shortenPortName ($port['name'], $object['id'])) | |
1749 | $n_ports_to_rename++; | |
1750 | if ($n_ports_to_rename) | |
1751 | echo '<p>' . getOpLink (array ('op'=>'renameAll'), "Auto-rename $n_ports_to_rename ports", 'recalc', 'Use RackTables naming convention for this device type') . '</p>'; | |
1752 | ||
00276508 AA |
1753 | if (isset ($_REQUEST['hl_port_id'])) |
1754 | { | |
1755 | assertUIntArg ('hl_port_id'); | |
1756 | $hl_port_id = intval ($_REQUEST['hl_port_id']); | |
65e557dd | 1757 | addAutoScrollScript ("port-$hl_port_id"); |
00276508 | 1758 | } |
9da8ee26 | 1759 | switchportInfoJS ($object['id']); // load JS code to make portnames interactive |
9f75e165 | 1760 | foreach ($object['ports'] as $port) |
e673ee24 | 1761 | { |
8579b51b AA |
1762 | // highlight port name with yellow if it's name is not canonical |
1763 | $canon_pn = shortenPortName ($port['name'], $port['object_id']); | |
1764 | $name_class = $canon_pn == $port['name'] ? '' : 'trwarning'; | |
1765 | ||
5c717ce5 | 1766 | $tr_class = isset ($hl_port_id) && $hl_port_id == $port['id'] ? 'class="highlight"' : ''; |
7056988c | 1767 | printOpFormIntro ('editPort', array ('port_id' => $port['id'])); |
d0d40671 | 1768 | echo "<tr $tr_class><td><a name='port-${port['id']}' href='".makeHrefProcess(array('op'=>'delPort', 'port_id'=>$port['id']))."'>"; |
e673ee24 DO |
1769 | printImageHREF ('delete', 'Unlink and Delete this port'); |
1770 | echo "</a></td>\n"; | |
65e557dd | 1771 | $a_class = isEthernetPort ($port) ? 'port-menu' : ''; |
7b30e187 | 1772 | echo "<td class='tdleft $name_class' NOWRAP><input type=text name=name class='interactive-portname $a_class' value='${port['name']}' size=16></td>"; |
cd3775e9 | 1773 | echo "<td><input type=text name=label value='${port['label']}'></td>"; |
8e021b86 AA |
1774 | echo '<td>'; |
1775 | if ($port['iif_id'] != 1) | |
1776 | echo '<label>' . $port['iif_name'] . ' '; | |
4f968fa8 | 1777 | $port_type_opts = array(); |
78b59ab3 | 1778 | if (! $port['linked']) |
759b21d2 | 1779 | $port_type_opts = getUnlinkedPortTypeOptions ($port['iif_id']); |
78b59ab3 | 1780 | else |
4f968fa8 AA |
1781 | foreach (getExistingPortTypeOptions ($port) as $oif_id => $opt_str) |
1782 | $port_type_opts[$port['iif_name']][$port['iif_id'] . '-' . $oif_id] = $opt_str; | |
4f968fa8 | 1783 | printNiftySelect ($port_type_opts, array ('name' => 'port_type_id'), $port['iif_id'] . '-' . $port['oif_id']); |
8e021b86 AA |
1784 | if ($port['iif_id'] != 1) |
1785 | echo '</label>'; | |
1786 | echo '</td>'; | |
1787 | ||
cd3775e9 DO |
1788 | // 18 is enough to fit 6-byte MAC address in its longest form, |
1789 | // while 24 should be Ok for WWN | |
1790 | echo "<td><input type=text name=l2address value='${port['l2address']}' size=18 maxlength=24></td>\n"; | |
0b09238d | 1791 | if ($port['remote_object_id']) |
90bf1755 | 1792 | { |
0b09238d DO |
1793 | echo "<td>" . |
1794 | formatLoggedSpan ($port['last_log'], formatPortLink ($port['remote_object_id'], $port['remote_object_name'], $port['remote_id'], NULL)) . | |
1795 | "</td>"; | |
1796 | echo "<td> " . formatLoggedSpan ($port['last_log'], $port['remote_name'], 'underline') . | |
1797 | "<input type=hidden name=reservation_comment value=''></td>"; | |
1798 | echo "<td><input type=text name=cable value='${port['cableid']}'></td>"; | |
1799 | echo "<td class=tdcenter>"; | |
1800 | echo getOpLink (array('op'=>'unlinkPort', 'port_id'=>$port['id'], ), '', 'cut', 'Unlink this port'); | |
1801 | echo "</td>"; | |
e673ee24 | 1802 | } |
59a83bd8 | 1803 | elseif (strlen ($port['reservation_comment'])) |
e673ee24 | 1804 | { |
0b09238d | 1805 | echo "<td>" . formatLoggedSpan ($port['last_log'], 'Reserved:', 'strong underline') . "</td>"; |
e673ee24 | 1806 | echo "<td><input type=text name=reservation_comment value='${port['reservation_comment']}'></td>"; |
318c48a8 | 1807 | echo "<td></td>"; |
10f5133a AA |
1808 | echo "<td class=tdcenter>"; |
1809 | echo getOpLink (array('op'=>'useup', 'port_id'=>$port['id']), '', 'clear', 'Use up this port'); | |
1810 | echo "</td>"; | |
e673ee24 DO |
1811 | } |
1812 | else | |
1813 | { | |
6b1ca530 | 1814 | $in_rack = getConfigVar ('NEAREST_RACKS_CHECKBOX'); |
de55c069 AA |
1815 | echo "<td> </td><td> </td><td> </td><td class=tdcenter>"; |
1816 | echo getPopupLink ('portlist', array ('port' => $port['id'], 'in_rack' => ($in_rack == "yes" ? "on" : "")), 'findlink', 'plug', '', 'Link this port'); | |
0b09238d | 1817 | echo " <input type=text name=reservation_comment></td>\n"; |
90bf1755 | 1818 | } |
0b09238d DO |
1819 | echo "<td>"; |
1820 | printImageHREF ('save', 'Save changes', TRUE); | |
1821 | echo "</td></form></tr>\n"; | |
e673ee24 | 1822 | } |
39b4abd0 | 1823 | if (getConfigVar ('ADDNEW_AT_TOP') != 'yes') |
3153a326 | 1824 | printNewItemTR ($prefs); |
e673ee24 | 1825 | echo "</table><br>\n"; |
a1fc539a RF |
1826 | if (getConfigVar ('ADDNEW_AT_TOP') != 'yes' && getConfigVar('ENABLE_BULKPORT_FORM') == 'yes'){ |
1827 | echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n"; | |
1828 | echo "<tr><th> </th><th class=tdleft>Local name</th><th class=tdleft>Visible label</th><th class=tdleft>Interface</th><th class=tdleft>Start Number</th>"; | |
1829 | echo "<th class=tdleft>Count</th><th> </th></tr>\n"; | |
dec748f6 | 1830 | printOpFormIntro ('addBulkPorts'); |
a1fc539a RF |
1831 | echo "<tr><td>"; |
1832 | printImageHREF ('add', 'add ports', TRUE); | |
04c61e7e AB |
1833 | echo "</td><td><input type=text size=8 name=port_name></td>\n"; |
1834 | echo "<td><input type=text name=port_label></td><td>"; | |
759b21d2 | 1835 | printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type_id'), $prefs['selected']); |
04c61e7e AB |
1836 | echo "<td><input type=text name=port_numbering_start size=3 maxlength=3></td>\n"; |
1837 | echo "<td><input type=text name=port_numbering_count size=3 maxlength=3></td>\n"; | |
a1fc539a | 1838 | echo "<td> </td><td>"; |
04c61e7e | 1839 | printImageHREF ('add', 'add ports', TRUE); |
a1fc539a RF |
1840 | echo "</td></tr></form>"; |
1841 | echo "</table><br>\n"; | |
1842 | } | |
90bf1755 DO |
1843 | if (getConfigVar('ENABLE_MULTIPORT_FORM') == 'yes') |
1844 | finishPortlet(); | |
f44fdef9 DO |
1845 | if (getConfigVar('ENABLE_MULTIPORT_FORM') != 'yes') |
1846 | return; | |
e673ee24 DO |
1847 | |
1848 | startPortlet ('Add/update multiple ports'); | |
7056988c | 1849 | printOpFormIntro ('addMultiPorts'); |
8331b4e4 DO |
1850 | $formats = array |
1851 | ( | |
1852 | 'c3600asy' => 'Cisco 3600 async: sh line | inc TTY', | |
1853 | 'fiwg' => 'Foundry ServerIron/FastIron WorkGroup/Edge: sh int br', | |
1854 | 'fisxii' => 'Foundry FastIron SuperX/II4000: sh int br', | |
1855 | 'ssv1' => 'SSV:<interface name> [<MAC address>]', | |
1856 | ); | |
1857 | echo 'Format: ' . getSelect ($formats, array ('name' => 'format'), 'ssv1'); | |
e673ee24 | 1858 | echo 'Default port type: '; |
759b21d2 | 1859 | printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type'), $prefs['selected']); |
04c61e7e AB |
1860 | echo "<input type=submit value='Parse output'><br>\n"; |
1861 | echo "<textarea name=input cols=100 rows=50></textarea><br>\n"; | |
e673ee24 DO |
1862 | echo '</form>'; |
1863 | finishPortlet(); | |
1864 | } | |
1865 | ||
9da8ee26 | 1866 | function renderIPForObject() |
e673ee24 | 1867 | { |
4318ced5 | 1868 | function printNewItemTR ($default_type) |
21ee3351 AA |
1869 | { |
1870 | global $aat; | |
4318ced5 AA |
1871 | printOpFormIntro ('add'); |
1872 | echo "<tr><td>"; // left btn | |
dec748f6 | 1873 | printImageHREF ('add', 'allocate', TRUE); |
21ee3351 | 1874 | echo "</td>"; |
04c61e7e AB |
1875 | echo "<td class=tdleft><input type='text' size='10' name='bond_name'></td>\n"; // if-name |
1876 | echo "<td class=tdleft><input type=text name='ip'></td>\n"; // IP | |
4318ced5 AA |
1877 | if (getConfigVar ('EXT_IPV4_VIEW') == 'yes') |
1878 | echo "<td colspan=2> </td>"; // network, routed by | |
1879 | echo '<td>'; | |
04c61e7e | 1880 | printSelect ($aat, array ('name' => 'bond_type'), $default_type); // type |
4318ced5 | 1881 | echo "</td><td> </td><td>"; // misc |
04c61e7e | 1882 | printImageHREF ('add', 'allocate', TRUE); // right btn |
21ee3351 AA |
1883 | echo "</td></tr></form>"; |
1884 | } | |
21ee3351 AA |
1885 | global $aat; |
1886 | startPortlet ('Allocations'); | |
4318ced5 AA |
1887 | echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'><tr>\n"; |
1888 | echo '<th> </th>'; | |
1889 | echo '<th>OS interface</th>'; | |
1890 | echo '<th>IP address</th>'; | |
21ee3351 | 1891 | if (getConfigVar ('EXT_IPV4_VIEW') == 'yes') |
4318ced5 AA |
1892 | { |
1893 | echo '<th>network</th>'; | |
1894 | echo '<th>routed by</th>'; | |
1895 | } | |
1896 | echo '<th>type</th>'; | |
1897 | echo '<th>misc</th>'; | |
b1b07891 | 1898 | echo '<th> </th>'; |
4318ced5 | 1899 | echo '</tr>'; |
21ee3351 | 1900 | |
710ead7e AA |
1901 | $alloc_list = ''; // most of the output is stored here |
1902 | $used_alloc_types = array(); | |
9da8ee26 | 1903 | $object_id = getBypassValue(); |
4318ced5 | 1904 | foreach (getObjectIPAllocations ($object_id) as $alloc) |
21ee3351 | 1905 | { |
710ead7e AA |
1906 | if (! isset ($used_alloc_types[$alloc['type']])) |
1907 | $used_alloc_types[$alloc['type']] = 0; | |
1908 | $used_alloc_types[$alloc['type']]++; | |
1909 | ||
40c9fc94 | 1910 | $rendered_alloc = callHook ('getRenderedAlloc', $object_id, $alloc); |
4318ced5 | 1911 | $alloc_list .= getOutputOf ('printOpFormIntro', 'upd', array ('ip' => $alloc['addrinfo']['ip'])); |
710ead7e | 1912 | $alloc_list .= "<tr class='${rendered_alloc['tr_class']}' valign=top>"; |
f3505b35 | 1913 | |
10f5133a | 1914 | $alloc_list .= "<td>" . getOpLink (array ('op' => 'del', 'ip' => $alloc['addrinfo']['ip']), '', 'delete', 'Delete this IP address') . "</td>"; |
40c9fc94 | 1915 | $alloc_list .= "<td class=tdleft><input type='text' name='bond_name' value='${alloc['osif']}' size=10>" . $rendered_alloc['td_name_suffix'] . "</td>"; |
710ead7e | 1916 | $alloc_list .= $rendered_alloc['td_ip']; |
21ee3351 AA |
1917 | if (getConfigVar ('EXT_IPV4_VIEW') == 'yes') |
1918 | { | |
710ead7e AA |
1919 | $alloc_list .= $rendered_alloc['td_network']; |
1920 | $alloc_list .= $rendered_alloc['td_routed_by']; | |
21ee3351 | 1921 | } |
710ead7e AA |
1922 | $alloc_list .= '<td>' . getSelect ($aat, array ('name' => 'bond_type'), $alloc['type']) . "</td>"; |
1923 | $alloc_list .= $rendered_alloc['td_peers']; | |
1924 | $alloc_list .= "<td>" .getImageHREF ('save', 'Save changes', TRUE) . "</td>"; | |
f3505b35 | 1925 | |
710ead7e | 1926 | $alloc_list .= "</form></tr>\n"; |
21ee3351 | 1927 | } |
710ead7e | 1928 | asort ($used_alloc_types, SORT_NUMERIC); |
a0a5ce54 | 1929 | $most_popular_type = empty ($used_alloc_types) ? 'regular' : array_last (array_keys ($used_alloc_types)); |
710ead7e AA |
1930 | |
1931 | if ($list_on_top = (getConfigVar ('ADDNEW_AT_TOP') != 'yes')) | |
1932 | echo $alloc_list; | |
4318ced5 | 1933 | printNewItemTR ($most_popular_type); |
710ead7e AA |
1934 | if (! $list_on_top) |
1935 | echo $alloc_list; | |
21ee3351 AA |
1936 | |
1937 | echo "</table><br>\n"; | |
1938 | finishPortlet(); | |
f3505b35 AA |
1939 | } |
1940 | ||
08408472 AA |
1941 | // This function is deprecated. Do not rely on its internals, |
1942 | // it will probably be removed in the next major relese. | |
1943 | // Use new showError, showWarning, showSuccess functions. | |
dec748f6 | 1944 | // Log array is stored in global $log_messages. Its format is simple: plain ordered array |
8ab645cf | 1945 | // with values having keys 'c' (both message code and severity) and 'a' (sprintf arguments array) |
1cb6adf5 | 1946 | function showMessageOrError () |
e673ee24 | 1947 | { |
a2b16202 AA |
1948 | global $log_messages; |
1949 | ||
0a00b344 | 1950 | startSession(); |
a2b16202 AA |
1951 | if (isset ($_SESSION['log'])) |
1952 | { | |
1953 | $log_messages = array_merge ($_SESSION['log'], $log_messages); | |
1954 | unset ($_SESSION['log']); | |
1955 | } | |
1956 | session_commit(); | |
1957 | ||
1958 | if (empty ($log_messages)) | |
1cb6adf5 | 1959 | return; |
8ab645cf AA |
1960 | $msginfo = array |
1961 | ( | |
dec748f6 | 1962 | // records 0~99 with success messages |
8ab645cf AA |
1963 | 0 => array ('code' => 'success', 'format' => '%s'), |
1964 | 5 => array ('code' => 'success', 'format' => 'added record "%s" successfully'), | |
1965 | 6 => array ('code' => 'success', 'format' => 'updated record "%s" successfully'), | |
1966 | 7 => array ('code' => 'success', 'format' => 'deleted record "%s" successfully'), | |
1967 | 8 => array ('code' => 'success', 'format' => 'Port %s successfully linked with %s'), | |
1968 | 10 => array ('code' => 'success', 'format' => 'Added %u ports, updated %u ports, encountered %u errors.'), | |
1969 | 21 => array ('code' => 'success', 'format' => 'Generation complete'), | |
1970 | 26 => array ('code' => 'success', 'format' => 'updated %u records successfully'), | |
1971 | 37 => array ('code' => 'success', 'format' => 'added %u records successfully'), | |
1972 | 38 => array ('code' => 'success', 'format' => 'removed %u records successfully'), | |
8ab645cf AA |
1973 | 43 => array ('code' => 'success', 'format' => 'Saved successfully.'), |
1974 | 44 => array ('code' => 'success', 'format' => '%s failures and %s successfull changes.'), | |
1975 | 48 => array ('code' => 'success', 'format' => 'added a record successfully'), | |
1976 | 49 => array ('code' => 'success', 'format' => 'deleted a record successfully'), | |
1977 | 51 => array ('code' => 'success', 'format' => 'updated a record successfully'), | |
1978 | 57 => array ('code' => 'success', 'format' => 'Reset complete'), | |
04eee8d2 | 1979 | 58 => array ('code' => 'success', 'format' => '%u device(s) unmounted successfully'), |
8ab645cf | 1980 | 63 => array ('code' => 'success', 'format' => '%u change request(s) have been processed'), |
8ab645cf AA |
1981 | 67 => array ('code' => 'success', 'format' => "Tag rolling done, %u objects involved"), |
1982 | 71 => array ('code' => 'success', 'format' => 'File "%s" was linked successfully'), | |
1983 | 72 => array ('code' => 'success', 'format' => 'File was unlinked successfully'), | |
8ab645cf AA |
1984 | 82 => array ('code' => 'success', 'format' => "Bulk port creation was successful. %u ports created, %u failed"), |
1985 | 87 => array ('code' => 'success', 'format' => '802.1Q recalculate: %d ports changed on %d switches'), | |
8628ae44 | 1986 | // records 100~199 with fatal error messages |
8ab645cf AA |
1987 | 100 => array ('code' => 'error', 'format' => '%s'), |
1988 | 109 => array ('code' => 'error', 'format' => 'failed updating a record'), | |
8ab645cf AA |
1989 | 131 => array ('code' => 'error', 'format' => 'invalid format requested'), |
1990 | 141 => array ('code' => 'error', 'format' => 'Encountered %u errors, updated %u record(s)'), | |
1991 | 149 => array ('code' => 'error', 'format' => 'Turing test failed'), | |
1992 | 150 => array ('code' => 'error', 'format' => 'Can only change password under DB authentication.'), | |
1993 | 151 => array ('code' => 'error', 'format' => 'Old password doesn\'t match.'), | |
1994 | 152 => array ('code' => 'error', 'format' => 'New passwords don\'t match.'), | |
1995 | 154 => array ('code' => 'error', 'format' => "Verification error: %s"), | |
1996 | 155 => array ('code' => 'error', 'format' => 'Save failed.'), | |
1997 | 159 => array ('code' => 'error', 'format' => 'Permission denied moving port %s from VLAN%u to VLAN%u'), | |
1998 | 161 => array ('code' => 'error', 'format' => 'Endpoint not found. Please either set FQDN attribute or assign an IP address to the object.'), | |
1999 | 162 => array ('code' => 'error', 'format' => 'More than one IP address is assigned to this object, please configure FQDN attribute.'), | |
8ab645cf AA |
2000 | 170 => array ('code' => 'error', 'format' => 'There is no network for IP address "%s"'), |
2001 | 172 => array ('code' => 'error', 'format' => 'Malformed request'), | |
2002 | 179 => array ('code' => 'error', 'format' => 'Expired form has been declined.'), | |
2003 | 188 => array ('code' => 'error', 'format' => "Fatal SNMP failure"), | |
2004 | 189 => array ('code' => 'error', 'format' => "Unknown OID '%s'"), | |
2005 | 191 => array ('code' => 'error', 'format' => "deploy was blocked due to conflicting configuration versions"), | |
f0ff4930 | 2006 | |
8628ae44 | 2007 | // records 200~299 with warnings |
8ab645cf AA |
2008 | 200 => array ('code' => 'warning', 'format' => '%s'), |
2009 | 201 => array ('code' => 'warning', 'format' => 'nothing happened...'), | |
e1add254 | 2010 | 206 => array ('code' => 'warning', 'format' => '%s is not empty'), |
7587edca | 2011 | 207 => array ('code' => 'warning', 'format' => 'File upload failed, error: %s'), |
57777e4a | 2012 | |
24d3182a | 2013 | // records 300~399 with notices |
8ab645cf | 2014 | 300 => array ('code' => 'neutral', 'format' => '%s'), |
24d3182a | 2015 | |
8ab645cf AA |
2016 | ); |
2017 | // Handle the arguments. Is there any better way to do it? | |
a2b16202 | 2018 | foreach ($log_messages as $record) |
8ab645cf AA |
2019 | { |
2020 | if (!isset ($record['c']) or !isset ($msginfo[$record['c']])) | |
2021 | { | |
41152018 AA |
2022 | $prefix = isset ($record['c']) ? $record['c'] . ': ' : ''; |
2023 | echo "<div class=msg_neutral>(${prefix}this message was lost)</div>"; | |
8ab645cf AA |
2024 | continue; |
2025 | } | |
2026 | if (isset ($record['a'])) | |
2027 | switch (count ($record['a'])) | |
baf37d01 | 2028 | { |
8ab645cf AA |
2029 | case 1: |
2030 | $msgtext = sprintf | |
2031 | ( | |
2032 | $msginfo[$record['c']]['format'], | |
2033 | $record['a'][0] | |
2034 | ); | |
2035 | break; | |
2036 | case 2: | |
2037 | $msgtext = sprintf | |
2038 | ( | |
2039 | $msginfo[$record['c']]['format'], | |
2040 | $record['a'][0], | |
2041 | $record['a'][1] | |
2042 | ); | |
2043 | break; | |
2044 | case 3: | |
2045 | $msgtext = sprintf | |
2046 | ( | |
2047 | $msginfo[$record['c']]['format'], | |
2048 | $record['a'][0], | |
2049 | $record['a'][1], | |
2050 | $record['a'][2] | |
2051 | ); | |
2052 | break; | |
2053 | case 4: | |
2054 | default: | |
2055 | $msgtext = sprintf | |
2056 | ( | |
2057 | $msginfo[$record['c']]['format'], | |
2058 | $record['a'][0], | |
2059 | $record['a'][1], | |
2060 | $record['a'][2], | |
2061 | $record['a'][3] | |
2062 | ); | |
2063 | break; | |
baf37d01 | 2064 | } |
8ab645cf AA |
2065 | else |
2066 | $msgtext = $msginfo[$record['c']]['format']; | |
2067 | echo '<div class=msg_' . $msginfo[$record['c']]['code'] . ">${msgtext}</div>"; | |
baf37d01 | 2068 | } |
a2b16202 | 2069 | $log_messages = array(); |
e673ee24 DO |
2070 | } |
2071 | ||
65e557dd | 2072 | // renders two tables: port link status and learned MAC list |
9da8ee26 | 2073 | function renderPortsInfo() |
65e557dd | 2074 | { |
9da8ee26 | 2075 | $object_id = getBypassValue(); |
2d33a804 | 2076 | $breed = detectDeviceBreed ($object_id); |
03522bd8 AA |
2077 | try |
2078 | { | |
2079 | if (permitted (NULL, NULL, 'get_link_status')) | |
2d33a804 | 2080 | { |
2081 | if (validBreedFunction ($breed, 'getportstatus')) | |
2082 | $linkStatus = queryDevice ($object_id, 'getportstatus'); | |
2083 | } | |
03522bd8 AA |
2084 | else |
2085 | showWarning ("You don't have permission to view ports link status"); | |
2086 | ||
2087 | if (permitted (NULL, NULL, 'get_mac_list')) | |
2d33a804 | 2088 | { |
2089 | if (validBreedFunction ($breed, 'getmaclist')) | |
2090 | $macList = sortPortList (queryDevice ($object_id, 'getmaclist')); | |
2091 | } | |
03522bd8 AA |
2092 | else |
2093 | showWarning ("You don't have permission to view learned MAC list"); | |
2094 | } | |
2095 | catch (RTGatewayError $e) | |
2096 | { | |
2097 | showError ($e->getMessage()); | |
2098 | return; | |
2099 | } | |
2100 | ||
65e557dd AA |
2101 | global $nextorder; |
2102 | echo "<table width='100%'><tr>"; | |
03522bd8 | 2103 | if (! empty ($linkStatus)) |
65e557dd | 2104 | { |
03522bd8 AA |
2105 | echo "<td valign='top' width='50%'>"; |
2106 | startPortlet('Link status'); | |
2107 | echo "<table width='80%' class='widetable' cellspacing=0 cellpadding='5px' align='center'><tr><th>Port<th><th>Link status<th>Link info</tr>"; | |
2108 | $order = 'even'; | |
2109 | foreach ($linkStatus as $pn => $link) | |
65e557dd | 2110 | { |
03522bd8 | 2111 | switch ($link['status']) |
65e557dd | 2112 | { |
03522bd8 AA |
2113 | case 'up': |
2114 | $img_filename = 'link-up.png'; | |
2115 | break; | |
2116 | case 'down': | |
2117 | $img_filename = 'link-down.png'; | |
2118 | break; | |
2119 | case 'disabled': | |
2120 | $img_filename = 'link-disabled.png'; | |
2121 | break; | |
2122 | default: | |
2123 | $img_filename = '1x1t.gif'; | |
2124 | } | |
9f78501e | 2125 | |
03522bd8 AA |
2126 | echo "<tr class='row_$order'>"; |
2127 | $order = $nextorder[$order]; | |
2128 | echo '<td>' . $pn; | |
2129 | echo '<td>' . '<img width=16 height=16 src="?module=chrome&uri=pix/' . $img_filename . '">'; | |
2130 | echo '<td>' . $link['status']; | |
2131 | $info = ''; | |
2132 | if (isset ($link['speed'])) | |
2133 | $info .= $link['speed']; | |
2134 | if (isset ($link['duplex'])) | |
2135 | { | |
2136 | if (! empty ($info)) | |
2137 | $info .= ', '; | |
2138 | $info .= $link['duplex']; | |
65e557dd | 2139 | } |
03522bd8 AA |
2140 | echo '<td>' . $info; |
2141 | echo '</tr>'; | |
65e557dd | 2142 | } |
03522bd8 AA |
2143 | echo "</table></td>"; |
2144 | finishPortlet(); | |
65e557dd AA |
2145 | } |
2146 | ||
65e557dd AA |
2147 | if (! empty ($macList)) |
2148 | { | |
2149 | echo "<td valign='top' width='50%'>"; | |
2150 | $rendered_macs = ''; | |
2151 | $mac_count = 0; | |
2152 | $rendered_macs .= "<table width='80%' class='widetable' cellspacing=0 cellpadding='5px' align='center'><tr><th>MAC<th>Vlan<th>Port</tr>"; | |
2153 | $order = 'even'; | |
2154 | foreach ($macList as $pn => $list) | |
2155 | { | |
2156 | $order = $nextorder[$order]; | |
2157 | foreach ($list as $item) | |
2158 | { | |
2159 | ++$mac_count; | |
2160 | $rendered_macs .= "<tr class='row_$order'>"; | |
2161 | $rendered_macs .= '<td style="font-family: monospace">' . $item['mac']; | |
2162 | $rendered_macs .= '<td>' . $item['vid']; | |
2163 | $rendered_macs .= '<td>' . $pn; | |
2164 | $rendered_macs .= '</tr>'; | |
2165 | } | |
2166 | } | |
2167 | $rendered_macs .= "</table></td>"; | |
dec748f6 | 2168 | |
65e557dd AA |
2169 | startPortlet("Learned MACs ($mac_count)"); |
2170 | echo $rendered_macs; | |
2171 | finishPortlet(); | |
2172 | } | |
2173 | ||
2174 | echo "</td></tr></table>"; | |
2175 | } | |
2176 | ||
e673ee24 | 2177 | /* |
51c18782 | 2178 | The following conditions must be met: |
e673ee24 DO |
2179 | 1. We can mount onto free atoms only. This means: if any record for an atom |
2180 | already exists in RackSpace, it can't be used for mounting. | |
2181 | 2. We can't unmount from 'W' atoms. Operator should review appropriate comments | |
2182 | and either delete them before unmounting or refuse to unmount the object. | |
2183 | */ | |
9da8ee26 | 2184 | function renderRackSpaceForObject() |
e673ee24 | 2185 | { |
9da8ee26 | 2186 | $object_id = getBypassValue(); |
e673ee24 DO |
2187 | // Always process occupied racks plus racks chosen by user. First get racks with |
2188 | // already allocated rackspace... | |
51c18782 | 2189 | $workingRacksData = getResidentRacksData ($object_id); |
e673ee24 | 2190 | // ...and then add those chosen by user (if any). |
2135fd83 | 2191 | if (isset($_REQUEST['rackmulti'])) |
e673ee24 | 2192 | foreach ($_REQUEST['rackmulti'] as $cand_id) |
e673ee24 DO |
2193 | if (!isset ($workingRacksData[$cand_id])) |
2194 | { | |
0cc24e9a | 2195 | $rackData = spotEntity ('rack', $cand_id); |
61a1d996 | 2196 | amplifyCell ($rackData); |
e673ee24 DO |
2197 | $workingRacksData[$cand_id] = $rackData; |
2198 | } | |
51690ad4 | 2199 | |
c17a36f0 AA |
2200 | // Get a list of rack ids that are parents of this object. |
2201 | $object = spotEntity ('object', $object_id); | |
2202 | $parentRacks = reduceSubarraysToColumn (getParents ($object, 'rack'), 'id'); | |
0a7feebb | 2203 | |
e673ee24 DO |
2204 | // Main layout starts. |
2205 | echo "<table border=0 class=objectview cellspacing=0 cellpadding=0><tr>"; | |
2206 | ||
2207 | // Left portlet with rack list. | |
2208 | echo "<td class=pcleft height='1%'>"; | |
2209 | startPortlet ('Racks'); | |
a8efc03e | 2210 | $allRacksData = listCells ('rack'); |
6d42599c AA |
2211 | |
2212 | // filter rack list to match only racks having common tags with the object (reducing $allRacksData) | |
2213 | if (! isset ($_REQUEST['show_all_racks']) and getConfigVar ('FILTER_RACKLIST_BY_TAGS') == 'yes') | |
2214 | { | |
2215 | $matching_racks = array(); | |
6d42599c AA |
2216 | $matched_tags = array(); |
2217 | foreach ($allRacksData as $rack) | |
01205bb6 | 2218 | { |
b51c1007 | 2219 | $tag_chain = array_merge ($rack['etags'], $rack['itags']); |
6d42599c | 2220 | foreach ($object['etags'] as $tag) |
01205bb6 | 2221 | if (tagOnChain ($tag, $tag_chain)) |
6d42599c AA |
2222 | { |
2223 | $matching_racks[$rack['id']] = $rack; | |
2224 | $matched_tags[$tag['id']] = $tag; | |
2225 | break; | |
2226 | } | |
01205bb6 | 2227 | } |
6d42599c AA |
2228 | // add current object's racks even if they dont match filter |
2229 | foreach ($workingRacksData as $rack_id => $rack) | |
2230 | if (! isset ($matching_racks[$rack_id])) | |
2231 | $matching_racks[$rack_id] = $rack; | |
2232 | // if matching racks found, and rack list is reduced, show 'show all' link | |
2233 | if (count ($matching_racks) and count ($matching_racks) != count ($allRacksData)) | |
2234 | { | |
2235 | $filter_text = ''; | |
2236 | foreach ($matched_tags as $tag) | |
2237 | $filter_text .= (empty ($filter_text) ? '' : ' or ') . '{' . $tag['tag'] . '}'; | |
2238 | $href_show_all = trim($_SERVER['REQUEST_URI'], '&'); | |
2239 | $href_show_all .= htmlspecialchars('&show_all_racks=1'); | |
2240 | echo "(filtered by <span class='filter-text'>$filter_text</span>, <a href='$href_show_all'>show all</a>)<p>"; | |
2241 | $allRacksData = $matching_racks; | |
2242 | } | |
2243 | } | |
2244 | ||
4b8d413e | 2245 | if (count ($allRacksData) <= getConfigVar ('RACK_PRESELECT_THRESHOLD')) |
61a1d996 | 2246 | foreach ($allRacksData as $rack) |
51c18782 DO |
2247 | if (!array_key_exists ($rack['id'], $workingRacksData)) |
2248 | { | |
2249 | amplifyCell ($rack); | |
2250 | $workingRacksData[$rack['id']] = $rack; | |
2251 | } | |
2252 | foreach (array_keys ($workingRacksData) as $rackId) | |
2253 | applyObjectMountMask ($workingRacksData[$rackId], $object_id); | |
2254 | printOpFormIntro ('updateObjectAllocation'); | |
4b8d413e | 2255 | renderRackMultiSelect ('rackmulti[]', $allRacksData, array_keys ($workingRacksData)); |
51c18782 | 2256 | echo "<br><br>"; |
e673ee24 DO |
2257 | finishPortlet(); |
2258 | echo "</td>"; | |
2259 | ||
2260 | // Middle portlet with comment and submit. | |
2261 | echo "<td class=pcleft>"; | |
5c8bf2ba | 2262 | startPortlet ('Comment (for Rackspace History)'); |
e673ee24 DO |
2263 | echo "<textarea name=comment rows=10 cols=40></textarea><br>\n"; |
2264 | echo "<input type=submit value='Save' name=got_atoms>\n"; | |
51c18782 | 2265 | echo "<br><br>"; |
e673ee24 DO |
2266 | finishPortlet(); |
2267 | echo "</td>"; | |
2268 | ||
2269 | // Right portlet with rendered racks. If this form submit is not final, we have to | |
2270 | // reflect the former state of the grid in current form. | |
2271 | echo "<td class=pcright rowspan=2 height='1%'>"; | |
2272 | startPortlet ('Working copy'); | |
e8b94513 | 2273 | includeJQueryUI (false); |
65e557dd | 2274 | addJS ('js/racktables.js'); |
c82023ad | 2275 | addJS ('js/bulkselector.js'); |
e673ee24 DO |
2276 | echo '<table border=0 cellspacing=10 align=center><tr>'; |
2277 | foreach ($workingRacksData as $rack_id => $rackData) | |
2278 | { | |
c26d97b6 | 2279 | $is_ro = !rackModificationPermitted ($rackData, 'updateObjectAllocation'); |
e673ee24 DO |
2280 | // Order is important here: only original allocation is highlighted. |
2281 | highlightObject ($rackData, $object_id); | |
2282 | markupAtomGrid ($rackData, 'T'); | |
2283 | // If we have a form processed, discard user input and show new database | |
2284 | // contents. | |
c26d97b6 | 2285 | if (!$is_ro && isset ($_REQUEST['rackmulti'][0])) // is an update |
e673ee24 DO |
2286 | mergeGridFormToRack ($rackData); |
2287 | echo "<td valign=top>"; | |
c26d97b6 VS |
2288 | echo "<center>\n<h2 style='margin:0px'>${rackData['name']}</h2>\n"; |
2289 | $read_only_text = $is_ro ? '(read-only)' : ' '; | |
2290 | echo "<p style='color: red; margin-top:0px'>${read_only_text}</p>\n"; | |
e8b94513 | 2291 | echo "<table class=rack id=selectableRack border=0 cellspacing=0 cellpadding=1>\n"; |
57c69e9c | 2292 | echo "<tr><th width='10%'> </th>"; |
bd0bfb76 AD |
2293 | echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '0', ${rackData['height']})\">Front</a></th>"; |
2294 | echo "<th width='50%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '1', ${rackData['height']})\">Interior</a></th>"; | |
2295 | echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '2', ${rackData['height']})\">Back</a></th></tr>\n"; | |
c26d97b6 | 2296 | renderAtomGrid ($rackData, $is_ro); |
57c69e9c | 2297 | echo "<tr><th width='10%'> </th>"; |
bd0bfb76 AD |
2298 | echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '0', ${rackData['height']})\">Front</a></th>"; |
2299 | echo "<th width='50%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '1', ${rackData['height']})\">Interior</a></th>"; | |
2300 | echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '2', ${rackData['height']})\">Back</a></th></tr>\n"; | |
0a7feebb AD |
2301 | echo "</table>\n<br>\n"; |
2302 | // Determine zero-u checkbox status. | |
2303 | // If form has been submitted, use form data, otherwise use DB data. | |
c26d97b6 | 2304 | if (!$is_ro && isset($_REQUEST['op'])) |
0a7feebb AD |
2305 | $checked = isset($_REQUEST['zerou_'.$rack_id]) ? 'checked' : ''; |
2306 | else | |
2307 | $checked = in_array($rack_id, $parentRacks) ? 'checked' : ''; | |
c26d97b6 VS |
2308 | $disabled_text = $is_ro ? ' disabled' : ''; |
2309 | echo "<label for=zerou_${rack_id}>Zero-U:</label> <input type=checkbox ${checked} name=zerou_${rack_id} id=zerou_${rack_id}${disabled_text}>\n<br><br>\n"; | |
bd0bfb76 | 2310 | echo "<input type='button' onclick='uncheckAll();' value='Uncheck all'>\n"; |
0a7feebb | 2311 | echo '</center></td>'; |
e673ee24 DO |
2312 | } |
2313 | echo "</tr></table>"; | |
2314 | finishPortlet(); | |
2315 | echo "</td>\n"; | |
2316 | ||
2317 | echo "</form>\n"; | |
2318 | echo "</tr></table>\n"; | |
2319 | } | |
2320 | ||
2321 | function renderMolecule ($mdata, $object_id) | |
2322 | { | |
2323 | // sort data out | |
2324 | $rackpack = array(); | |
2325 | global $loclist; | |
64b95774 | 2326 | foreach ($mdata as $rua) |
e673ee24 DO |
2327 | { |
2328 | $rack_id = $rua['rack_id']; | |
2329 | $unit_no = $rua['unit_no']; | |
2330 | $atom = $rua['atom']; | |
2331 | if (!isset ($rackpack[$rack_id])) | |
2332 | { | |
61a1d996 DO |
2333 | $rackData = spotEntity ('rack', $rack_id); |
2334 | amplifyCell ($rackData); | |
e673ee24 DO |
2335 | for ($i = $rackData['height']; $i > 0; $i--) |
2336 | for ($locidx = 0; $locidx < 3; $locidx++) | |
2337 | $rackData[$i][$locidx]['state'] = 'F'; | |
2338 | $rackpack[$rack_id] = $rackData; | |
2339 | } | |
2340 | $rackpack[$rack_id][$unit_no][$loclist[$atom]]['state'] = 'T'; | |
2341 | $rackpack[$rack_id][$unit_no][$loclist[$atom]]['object_id'] = $object_id; | |
2342 | } | |
2343 | // now we have some racks to render | |
64b95774 | 2344 | foreach ($rackpack as $rackData) |
e673ee24 DO |
2345 | { |
2346 | markAllSpans ($rackData); | |
2347 | echo "<table class=molecule cellspacing=0>\n"; | |
2348 | echo "<caption>${rackData['name']}</caption>\n"; | |
2349 | echo "<tr><th width='10%'> </th><th width='20%'>Front</th><th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n"; | |
2350 | for ($i = $rackData['height']; $i > 0; $i--) | |
2351 | { | |
4dcd770e | 2352 | echo "<tr><th>" . inverseRackUnit ($i, $rackData) . "</th>"; |
e673ee24 DO |
2353 | for ($locidx = 0; $locidx < 3; $locidx++) |
2354 | { | |
2355 | $state = $rackData[$i][$locidx]['state']; | |
65e557dd | 2356 | echo "<td class='atom state_${state}'> </td>\n"; |
e673ee24 DO |
2357 | } |
2358 | echo "</tr>\n"; | |
2359 | } | |
2360 | echo "</table>\n"; | |
2361 | } | |
2362 | } | |
2363 | ||
23cdc7e9 | 2364 | function renderDepot () |
e673ee24 | 2365 | { |
23cdc7e9 | 2366 | global $pageno, $nextorder; |
23cdc7e9 | 2367 | $cellfilter = getCellFilter(); |
950dfa1f AA |
2368 | $objects = array(); |
2369 | $objects_count = getEntitiesCount ('object'); | |
db8255ac | 2370 | $showobjecttype = (getConfigVar ('SHOW_OBJECTTYPE') == 'yes'); |
23cdc7e9 DO |
2371 | |
2372 | echo "<table border=0 class=objectview>\n"; | |
2373 | echo "<tr><td class=pcleft>"; | |
2374 | ||
950dfa1f AA |
2375 | if ($objects_count == 0) |
2376 | echo '<h2>No objects exist</h2>'; | |
2377 | // 1st attempt: do not fetch all objects if cellfilter is empty and rendering empty result is enabled | |
2378 | elseif (! ($cellfilter['is_empty'] && renderEmptyResults ($cellfilter, 'objects', $objects_count))) | |
e673ee24 | 2379 | { |
2b16c179 | 2380 | $objects = applyCellFilter ('object', $cellfilter); |
20506de3 | 2381 | // 2nd attempt: do not render all fetched objects if rendering empty result is enabled |
950dfa1f | 2382 | if (! renderEmptyResults ($cellfilter, 'objects', count($objects))) |
1ebbf889 | 2383 | { |
4899096d AD |
2384 | startPortlet ('Objects (' . count ($objects) . ')'); |
2385 | echo '<br><br><table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>'; | |
db8255ac J |
2386 | echo '<tr><th>Common name</th>'; |
2387 | if ($showobjecttype) | |
2388 | echo '<th>Type</th>'; | |
2389 | echo '<th>Visible label</th><th>Asset tag</th><th>Row/Rack or Container</th></tr>'; | |
4899096d | 2390 | $order = 'odd'; |
3f8a25d6 DO |
2391 | # gather IDs of all objects and fetch rackspace info in one pass |
2392 | $idlist = array(); | |
2393 | foreach ($objects as $obj) | |
2394 | $idlist[] = $obj['id']; | |
2395 | $mountinfo = getMountInfo ($idlist); | |
cae81598 | 2396 | $containerinfo = getContainerInfo ($idlist); |
4899096d AD |
2397 | foreach ($objects as $obj) |
2398 | { | |
ec788aba AD |
2399 | $problem = ($obj['has_problems'] == 'yes') ? 'has_problems' : ''; |
2400 | echo "<tr class='row_${order} tdleft ${problem}' valign=top><td>" . mkA ("<strong>${obj['dname']}</strong>", 'object', $obj['id']); | |
4899096d AD |
2401 | if (count ($obj['etags'])) |
2402 | echo '<br><small>' . serializeTags ($obj['etags'], makeHref(array('page'=>$pageno, 'tab'=>'default')) . '&') . '</small>'; | |
db8255ac J |
2403 | echo '</td>'; |
2404 | if ($showobjecttype) | |
9563f56f | 2405 | echo "<td>" . decodeObjectType ($obj['objtype_id']) . "</td>"; |
8526b4cc | 2406 | echo "<td>${obj['label']}</td>"; |
4318ced5 | 2407 | echo "<td>${obj['asset_no']}</td>"; |
3f8a25d6 | 2408 | $places = array(); |
cae81598 AD |
2409 | if (array_key_exists ($obj['id'], $containerinfo)) |
2410 | foreach ($containerinfo[$obj['id']] as $ci) | |
20506de3 | 2411 | $places[] = mkA ($ci['container_dname'], 'object', $ci['container_id']); |
cae81598 | 2412 | if (array_key_exists ($obj['id'], $mountinfo)) |
3f8a25d6 DO |
2413 | foreach ($mountinfo[$obj['id']] as $mi) |
2414 | $places[] = mkA ($mi['row_name'], 'row', $mi['row_id']) . '/' . mkA ($mi['rack_name'], 'rack', $mi['rack_id']); | |
cae81598 AD |
2415 | if (! count ($places)) |
2416 | $places[] = 'Unmounted'; | |
4318ced5 | 2417 | echo "<td>" . implode (', ', $places) . '</td>'; |
4899096d AD |
2418 | echo '</tr>'; |
2419 | $order = $nextorder[$order]; | |
2420 | } | |
2421 | echo '</table>'; | |
2422 | finishPortlet(); | |
1ebbf889 | 2423 | } |
e673ee24 | 2424 | } |
23cdc7e9 DO |
2425 | |
2426 | echo "</td><td class=pcright width='25%'>"; | |
2427 | ||
95857b5c | 2428 | renderCellFilterPortlet ($cellfilter, 'object', $objects); |
23cdc7e9 | 2429 | echo "</td></tr></table>\n"; |
e673ee24 DO |
2430 | } |
2431 | ||
1ebbf889 AA |
2432 | // This function returns TRUE if the result set is too big to be rendered, and no filter is set. |
2433 | // In this case it renders the describing message instead. | |
2434 | function renderEmptyResults($cellfilter, $entities_name, $count = NULL) | |
2435 | { | |
2436 | if (!$cellfilter['is_empty']) | |
2437 | return FALSE; | |
2438 | if (isset ($_REQUEST['show_all_objects'])) | |
2439 | return FALSE; | |
2440 | $max = intval(getConfigVar('MAX_UNFILTERED_ENTITIES')); | |
2441 | if (0 == $max || $count <= $max) | |
2442 | return FALSE; | |
2443 | ||
2444 | $href_show_all = trim($_SERVER['REQUEST_URI'], '&'); | |
2445 | $href_show_all .= htmlspecialchars('&show_all_objects=1'); | |
2446 | $suffix = isset ($count) ? " ($count)" : ''; | |
2447 | echo <<<END | |
2448 | <p>Please set a filter to display the corresponging $entities_name. | |
2449 | <br><a href="$href_show_all">Show all $entities_name$suffix</a> | |
2450 | END; | |
2451 | return TRUE; | |
2452 | } | |
2453 | ||
e673ee24 | 2454 | // History viewer for history-enabled simple dictionaries. |
9b8174d7 | 2455 | function renderObjectHistory ($object_id) |
e673ee24 | 2456 | { |
e673ee24 DO |
2457 | $order = 'odd'; |
2458 | global $nextorder; | |
9b8174d7 AD |
2459 | echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>'; |
2460 | echo '<tr><th>change time</th><th>author</th><th>name</th><th>visible label</th><th>asset no</th><th>has problems?</th><th>comment</th></tr>'; | |
2461 | $result = usePreparedSelectBlade | |
2462 | ( | |
2463 | 'SELECT ctime, user_name, name, label, asset_no, has_problems, comment FROM ObjectHistory WHERE id=? ORDER BY ctime', | |
2464 | array ($object_id) | |
2465 | ); | |
e673ee24 DO |
2466 | while ($row = $result->fetch (PDO::FETCH_NUM)) |
2467 | { | |
2468 | echo "<tr class=row_${order}><td>${row[0]}</td>"; | |
9b8174d7 | 2469 | for ($i = 1; $i <= 6; $i++) |
e673ee24 DO |
2470 | echo "<td>" . $row[$i] . "</td>"; |
2471 | echo "</tr>\n"; | |
2472 | $order = $nextorder[$order]; | |
2473 | } | |
2474 | echo "</table><br>\n"; | |
2475 | } | |
2476 | ||
2477 | function renderRackspaceHistory () | |
2478 | { | |
4fbb5a00 | 2479 | global $nextorder, $pageno, $tabno; |
e673ee24 DO |
2480 | $order = 'odd'; |
2481 | $history = getRackspaceHistory(); | |
2482 | // Show the last operation by default. | |
2483 | if (isset ($_REQUEST['op_id'])) | |
2484 | $op_id = $_REQUEST['op_id']; | |
2485 | elseif (isset ($history[0]['mo_id'])) | |
2486 | $op_id = $history[0]['mo_id']; | |
2487 | else $op_id = NULL; | |
dec748f6 | 2488 | |
e673ee24 DO |
2489 | $omid = NULL; |
2490 | $nmid = NULL; | |
2491 | $object_id = 1; | |
2492 | if ($op_id) | |
2493 | list ($omid, $nmid) = getOperationMolecules ($op_id); | |
2494 | ||
2495 | // Main layout starts. | |
2496 | echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>"; | |
2497 | ||
2498 | // Left top portlet with old allocation. | |
2499 | echo "<tr><td class=pcleft>"; | |
2500 | startPortlet ('Old allocation'); | |
2501 | if ($omid) | |
2502 | { | |
2503 | $oldMolecule = getMolecule ($omid); | |
2504 | renderMolecule ($oldMolecule, $object_id); | |
2505 | } | |
2506 | else | |
2507 | echo "nothing"; | |
2508 | finishPortlet(); | |
2509 | ||
2510 | echo '</td><td class=pcright>'; | |
2511 | ||
2512 | // Right top portlet with new allocation | |
2513 | startPortlet ('New allocation'); | |
2514 | if ($nmid) | |
2515 | { | |
2516 | $newMolecule = getMolecule ($nmid); | |
2517 | renderMolecule ($newMolecule, $object_id); | |
2518 | } | |
2519 | else | |
2520 | echo "nothing"; | |
2521 | finishPortlet(); | |
737a3f72 | 2522 | |
e673ee24 | 2523 | echo '</td></tr><tr><td colspan=2>'; |
737a3f72 | 2524 | |
e673ee24 DO |
2525 | // Bottom portlet with list |
2526 | ||
2527 | startPortlet ('Rackspace allocation history'); | |
2528 | echo "<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>\n"; | |
7fa7047a | 2529 | echo "<tr><th>timestamp</th><th>author</th><th>object</th><th>comment</th></tr>\n"; |
e673ee24 DO |
2530 | foreach ($history as $row) |
2531 | { | |
2532 | if ($row['mo_id'] == $op_id) | |
2533 | $class = 'hl'; | |
2534 | else | |
2535 | $class = "row_${order}"; | |
4fbb5a00 | 2536 | echo "<tr class=${class}><td><a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'op_id'=>$row['mo_id']))."'>${row['ctime']}</a></td>"; |
7fa7047a DO |
2537 | echo "<td>${row['user_name']}</td><td>"; |
2538 | renderCell (spotEntity ('object', $row['ro_id'])); | |
a0bdf6dc | 2539 | echo '</td><td>' . stringForTD ($row['comment'], 0) . '</td></tr>'; |
e673ee24 DO |
2540 | $order = $nextorder[$order]; |
2541 | } | |
2542 | echo "</table>\n"; | |
2543 | finishPortlet(); | |
737a3f72 | 2544 | |
e673ee24 | 2545 | echo '</td></tr></table>'; |
e673ee24 DO |
2546 | } |
2547 | ||
4318ced5 | 2548 | function renderIPSpaceRecords ($tree, $baseurl, $target = 0, $level = 1) |
d65353ad DO |
2549 | { |
2550 | $self = __FUNCTION__; | |
4318ced5 | 2551 | $knight = (getConfigVar ('IPV4_ENABLE_KNIGHT') == 'yes'); |
00276508 AA |
2552 | |
2553 | // scroll page to the highlighted item | |
2554 | if ($target && isset ($_REQUEST['hl_net'])) | |
65e557dd | 2555 | addAutoScrollScript ("net-$target"); |
00276508 | 2556 | |
d65353ad DO |
2557 | foreach ($tree as $item) |
2558 | { | |
6063fab7 | 2559 | $display_routers = (getConfigVar ('IPV4_TREE_RTR_AS_CELL') != 'none'); |
4318ced5 | 2560 | |
0137d53c DO |
2561 | if (isset ($item['id'])) |
2562 | { | |
1f54e1ba | 2563 | $decor = array ('indent' => $level); |
fec0c8da | 2564 | if ($item['symbol'] == 'node-collapsed') |
4318ced5 | 2565 | $decor['symbolurl'] = "${baseurl}&eid=${item['id']}&hl_net=1"; |
fec0c8da | 2566 | elseif ($item['symbol'] == 'node-expanded') |
4318ced5 AA |
2567 | $decor['symbolurl'] = $baseurl . ($item['parent_id'] ? "&eid=${item['parent_id']}&hl_net=1" : ''); |
2568 | $tr_class = ''; | |
21ee3351 | 2569 | if ($target == $item['id'] && isset ($_REQUEST['hl_net'])) |
64347dcf | 2570 | { |
5c717ce5 | 2571 | $decor['tdclass'] = ' highlight'; |
4318ced5 | 2572 | $tr_class = $decor['tdclass']; |
64347dcf | 2573 | } |
4318ced5 AA |
2574 | echo "<tr valign=top class=\"$tr_class\">"; |
2575 | printIPNetInfoTDs ($item, $decor); | |
2576 | ||
2577 | // capacity and usage | |
2578 | echo "<td class=tdcenter>"; | |
2579 | echo getRenderedIPNetCapacity ($item); | |
64347dcf | 2580 | echo "</td>"; |
4318ced5 AA |
2581 | |
2582 | if ($display_routers) | |
6063fab7 | 2583 | printRoutersTD (findNetRouters ($item), getConfigVar ('IPV4_TREE_RTR_AS_CELL')); |
0137d53c | 2584 | echo "</tr>"; |
fec0c8da | 2585 | if ($item['symbol'] == 'node-expanded' or $item['symbol'] == 'node-expanded-static') |
4318ced5 | 2586 | $self ($item['kids'], $baseurl, $target, $level + 1); |
0137d53c | 2587 | } |
26fc6e7c | 2588 | elseif (getConfigVar ('IPV4_TREE_SHOW_UNALLOCATED') == 'yes') |
0137d53c | 2589 | { |
4318ced5 | 2590 | // non-allocated (spare) IP range |
0137d53c | 2591 | echo "<tr valign=top>"; |
21ee3351 | 2592 | printIPNetInfoTDs ($item, array ('indent' => $level, 'knight' => $knight, 'tdclass' => 'sparenetwork')); |
00276508 | 2593 | |
4318ced5 | 2594 | // capacity and usage |
21ee3351 | 2595 | echo "<td class=tdcenter>"; |
4318ced5 | 2596 | echo getRenderedIPNetCapacity ($item); |
21ee3351 | 2597 | echo "</td>"; |
4318ced5 AA |
2598 | if ($display_routers) |
2599 | echo "<td></td>"; | |
21ee3351 | 2600 | echo "</tr>"; |
21ee3351 | 2601 | } |
21ee3351 AA |
2602 | } |
2603 | } | |
2604 | ||
4318ced5 | 2605 | function renderIPSpace() |
e673ee24 | 2606 | { |
4fbb5a00 | 2607 | global $pageno, $tabno; |
4318ced5 | 2608 | $realm = ($pageno == 'ipv4space' ? 'ipv4net' : 'ipv6net'); |
31c941ec | 2609 | $cellfilter = getCellFilter(); |
21ee3351 | 2610 | |
b99b4167 AA |
2611 | // expand request can take either natural values or "ALL". Zero means no expanding. |
2612 | $eid = isset ($_REQUEST['eid']) ? $_REQUEST['eid'] : 0; | |
2613 | ||
21ee3351 AA |
2614 | echo "<table border=0 class=objectview>\n"; |
2615 | echo "<tr><td class=pcleft>"; | |
950dfa1f AA |
2616 | |
2617 | $netlist = array(); | |
b99b4167 | 2618 | if (! ($cellfilter['is_empty'] && ! $eid && renderEmptyResults($cellfilter, 'IP nets', getEntitiesCount ($realm)))) |
21ee3351 | 2619 | { |
950dfa1f AA |
2620 | $top = NULL; |
2621 | foreach (listCells ($realm) as $net) | |
21ee3351 | 2622 | { |
950dfa1f AA |
2623 | if (isset ($top) and IPNetContains ($top, $net)) |
2624 | ; | |
2625 | elseif (! count ($cellfilter['expression']) or judgeCell ($net, $cellfilter['expression'])) | |
2626 | $top = $net; | |
2627 | else | |
2628 | continue; | |
2629 | $netlist[$net['id']] = $net; | |
2630 | } | |
2631 | $netcount = count ($netlist); | |
950dfa1f AA |
2632 | $tree = prepareIPTree ($netlist, $eid); |
2633 | ||
2634 | if (! renderEmptyResults($cellfilter, 'IP nets', count($tree))) | |
2635 | { | |
2636 | startPortlet ("networks (${netcount})"); | |
2637 | echo '<h4>'; | |
2638 | $all = "<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'eid'=>'ALL')) . | |
2639 | $cellfilter['urlextra'] . "'>expand all</a>"; | |
2640 | $none = "<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'eid'=>'NONE')) . | |
2641 | $cellfilter['urlextra'] . "'>collapse all</a>"; | |
2642 | $auto = "<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno)) . | |
2643 | $cellfilter['urlextra'] . "'>auto-collapse</a>"; | |
2644 | ||
2645 | if ($eid === 0) | |
2646 | echo 'auto-collapsing at threshold ' . getConfigVar ('TREE_THRESHOLD') . " ($all / $none)"; | |
2647 | elseif ($eid === 'ALL') | |
2648 | echo "expanding all ($auto / $none)"; | |
2649 | elseif ($eid === 'NONE') | |
2650 | echo "collapsing all ($all / $auto)"; | |
2651 | else | |
2652 | { | |
a0f0c0c7 AA |
2653 | try |
2654 | { | |
2655 | $netinfo = spotEntity ($realm, $eid); | |
2656 | echo "expanding ${netinfo['ip']}/${netinfo['mask']} ($auto / $all / $none)"; | |
2657 | } | |
2658 | catch (EntityNotFoundException $e) | |
2659 | { | |
2660 | // ignore invalid eid error | |
2661 | } | |
950dfa1f AA |
2662 | } |
2663 | echo "</h4><table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n"; | |
2664 | echo "<tr><th>prefix</th><th>name/tags</th><th>capacity</th>"; | |
2665 | if (getConfigVar ('IPV4_TREE_RTR_AS_CELL') != 'none') | |
2666 | echo "<th>routed by</th>"; | |
2667 | echo "</tr>\n"; | |
2668 | $baseurl = makeHref(array('page'=>$pageno, 'tab'=>$tabno)) . $cellfilter['urlextra']; | |
2669 | renderIPSpaceRecords ($tree, $baseurl, $eid); | |
2670 | echo "</table>\n"; | |
2671 | finishPortlet(); | |
21ee3351 | 2672 | } |
21ee3351 AA |
2673 | } |
2674 | ||
2675 | echo '</td><td class=pcright>'; | |
950dfa1f | 2676 | renderCellFilterPortlet ($cellfilter, $realm, $netlist); |
21ee3351 AA |
2677 | echo "</td></tr></table>\n"; |
2678 | } | |
2679 | ||
4318ced5 | 2680 | function renderIPSpaceEditor() |
21ee3351 | 2681 | { |
4318ced5 AA |
2682 | global $pageno; |
2683 | $realm = ($pageno == 'ipv4space' ? 'ipv4net' : 'ipv6net'); | |
2684 | $net_page = $realm; // 'ipv4net', 'ipv6net' | |
2685 | $addrspaceList = listCells ($realm); | |
93a49e5b AA |
2686 | startPortlet ('Manage existing (' . count ($addrspaceList) . ')'); |
2687 | if (count ($addrspaceList)) | |
21ee3351 | 2688 | { |
21ee3351 AA |
2689 | echo "<table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n"; |
2690 | echo "<tr><th> </th><th>prefix</th><th>name</th><th>capacity</th></tr>"; | |
21ee3351 AA |
2691 | foreach ($addrspaceList as $netinfo) |
2692 | { | |
21ee3351 | 2693 | echo "<tr valign=top><td>"; |
93a49e5b | 2694 | if (! isIPNetworkEmpty ($netinfo)) |
21ee3351 AA |
2695 | printImageHREF ('nodestroy', 'There are ' . count ($netinfo['addrlist']) . ' allocations inside'); |
2696 | else | |
93a49e5b | 2697 | echo getOpLink (array ('op' => 'del', 'id' => $netinfo['id']), '', 'destroy', 'Delete this prefix'); |
ad3e5e7e | 2698 | echo '</td><td class=tdleft>' . mkA ("${netinfo['ip']}/${netinfo['mask']}", $net_page, $netinfo['id']) . '</td>'; |
a0bdf6dc | 2699 | echo '<td class=tdleft>' . stringForTD ($netinfo['name']); |
1f54e1ba DO |
2700 | if (count ($netinfo['etags'])) |
2701 | echo '<br><small>' . serializeTags ($netinfo['etags']) . '</small>'; | |
2702 | echo '</td><td>'; | |
4318ced5 | 2703 | echo getRenderedIPNetCapacity ($netinfo); |
b1e39212 | 2704 | echo '</tr>'; |
e673ee24 | 2705 | } |
04d619d0 DO |
2706 | echo "</table>"; |
2707 | finishPortlet(); | |
e673ee24 | 2708 | } |
93a49e5b AA |
2709 | } |
2710 | ||
2711 | function renderIPNewNetForm () | |
2712 | { | |
2713 | global $pageno; | |
2714 | if ($pageno == 'ipv6space') | |
2715 | { | |
2716 | $realm = 'ipv6net'; | |
3495ec6e | 2717 | $regexp = '^[a-fA-F0-9:]*:[a-fA-F0-9:\.]*/\d{1,3}$'; |
93a49e5b AA |
2718 | } |
2719 | else | |
2720 | { | |
2721 | $realm = 'ipv4net'; | |
3495ec6e | 2722 | $regexp = '^(\d{1,3}\.){3}\d{1,3}/\d{1,2}$'; |
93a49e5b AA |
2723 | } |
2724 | ||
2725 | // IP prefix validator | |
10f5133a | 2726 | addJS ('js/live_validation.js'); |
93a49e5b | 2727 | $regexp = addslashes ($regexp); |
10f5133a | 2728 | addJS (<<<END |
93a49e5b | 2729 | $(document).ready(function () { |
b895e6b4 | 2730 | $('form#add input[name="range"]').attr('match', '$regexp'); |
93a49e5b AA |
2731 | Validate.init(); |
2732 | }); | |
2733 | END | |
2734 | , TRUE); | |
dec748f6 | 2735 | |
93a49e5b | 2736 | startPortlet ('Add new'); |
10f5133a | 2737 | printOpFormIntro ('add'); |
e7b84015 AB |
2738 | echo '<table border=0 cellpadding=5 cellspacing=0 align=center>'; |
2739 | ||
93a49e5b AA |
2740 | // inputs column |
2741 | $prefix_value = empty ($_REQUEST['set-prefix']) ? '' : $_REQUEST['set-prefix']; | |
04c61e7e | 2742 | echo "<th class=tdright>Prefix:</th><td class=tdleft><input type=text name='range' size=36 class='live-validate' value='${prefix_value}'></td>"; |
e7b84015 | 2743 | echo '<tr><th class=tdright>VLAN:</th><td class=tdleft>'; |
04c61e7e AB |
2744 | echo getOptionTree ('vlan_ck', getAllVLANOptions(), array ('select_class' => 'vertical')) . '</td></tr>'; |
2745 | echo "<tr><th class=tdright>Name:</th><td class=tdleft><input type=text name='name' size='20'></td></tr>"; | |
e7b84015 AB |
2746 | echo '<tr><th class=tdright>Tags:</th><td class="tdleft">'; |
2747 | printTagsPicker (); | |
2748 | echo '</td></tr>'; | |
04c61e7e | 2749 | echo '<tr><td class=tdright><input type=checkbox name="is_connected"></td><th class=tdleft>reserve subnet-router anycast address</th></tr>'; |
93a49e5b | 2750 | echo "<tr><td colspan=2>"; |
04c61e7e | 2751 | printImageHREF ('CREATE', 'Add a new network', TRUE); |
93a49e5b | 2752 | echo '</td></tr>'; |
e7b84015 | 2753 | echo "</table></form><br><br>\n"; |
93a49e5b | 2754 | finishPortlet(); |
e673ee24 DO |
2755 | } |
2756 | ||
4318ced5 | 2757 | function getRenderedIPNetBacktrace ($range) |
e673ee24 | 2758 | { |
4318ced5 AA |
2759 | if (getConfigVar ('EXT_IPV4_VIEW') != 'yes') |
2760 | return array(); | |
e673ee24 | 2761 | |
4318ced5 AA |
2762 | $v = ($range['realm'] == 'ipv4net') ? 4 : 6; |
2763 | $space = "ipv${v}space"; // ipv4space, ipv6space | |
2764 | $tag = "\$ip${v}netid_"; // $ip4netid_, $ip6netid_ | |
dec748f6 | 2765 | |
4318ced5 AA |
2766 | $ret = array(); |
2767 | // Build a backtrace from all parent networks. | |
2768 | $clen = $range['mask']; | |
2769 | $backtrace = array(); | |
2770 | $backtrace['→'] = $range; | |
2771 | $key = ''; | |
2772 | while (NULL !== ($upperid = getIPAddressNetworkId ($range['ip_bin'], $clen))) | |
2773 | { | |
2774 | $upperinfo = spotEntity ($range['realm'], $upperid); | |
2775 | $clen = $upperinfo['mask']; | |
2776 | $key .= '↑'; | |
2777 | $backtrace[$key] = $upperinfo; | |
2778 | } | |
2779 | foreach (array_reverse ($backtrace) as $arrow => $ainfo) | |
2780 | { | |
2781 | $link = '<a href="' . makeHref (array ( | |
2782 | 'page' => $space, | |
2783 | 'tab' => 'default', | |
2784 | 'clear-cf' => '', | |
2785 | 'cfe' => '{' . $tag . $ainfo['id'] . '}', | |
2786 | 'hl_net' => 1, | |
2787 | 'eid' => $range['id'], | |
2788 | )) . '" title="View IP tree with this net as root">' . $arrow . '</a>'; | |
2789 | $ret[] = array ($link, getOutputOf ('renderCell', $ainfo)); | |
2790 | } | |
2791 | return $ret; | |
2792 | } | |
2793 | ||
9da8ee26 | 2794 | function renderIPNetwork() |
4318ced5 AA |
2795 | { |
2796 | global $pageno; | |
2797 | $realm = $pageno; // 'ipv4net', 'ipv6net' | |
9da8ee26 | 2798 | $range = spotEntity ($realm, getBypassValue()); |
4318ced5 | 2799 | loadIPAddrList ($range); |
2034d968 | 2800 | echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>"; |
99ab184f DO |
2801 | echo "<tr><td colspan=2 align=center><h1>${range['ip']}/${range['mask']}</h1><h2>"; |
2802 | echo htmlspecialchars ($range['name'], ENT_QUOTES, 'UTF-8') . "</h2></td></tr>\n"; | |
2034d968 DO |
2803 | |
2804 | echo "<tr><td class=pcleft width='50%'>"; | |
646272be AA |
2805 | |
2806 | // render summary portlet | |
2807 | $summary = array(); | |
4318ced5 | 2808 | $summary['%% used'] = getRenderedIPNetCapacity ($range); |
2b6b0038 | 2809 | $summary = getRenderedIPNetBacktrace ($range) + $summary; |
4318ced5 | 2810 | if ($realm == 'ipv4net') |
001e61fa | 2811 | { |
4318ced5 AA |
2812 | $summary[] = array ('Netmask:', ip4_format ($range['mask_bin'])); |
2813 | $summary[] = array ('Netmask:', "0x" . strtoupper (implode ('', unpack ('H*', $range['mask_bin'])))); | |
2814 | $summary['Wildcard bits'] = ip4_format ( ~ $range['mask_bin']); | |
001e61fa | 2815 | } |
dec748f6 | 2816 | |
11e3af31 DO |
2817 | $reuse_domain = considerConfiguredConstraint ($range, '8021Q_MULTILINK_LISTSRC'); |
2818 | $domainclass = array(); | |
2819 | foreach (array_count_values (reduceSubarraysToColumn ($range['8021q'], 'domain_id')) as $domain_id => $vlan_count) | |
2820 | $domainclass[$domain_id] = $vlan_count == 1 ? '' : ($reuse_domain ? '{trwarning}' : '{trerror}'); | |
a5f9d1ca | 2821 | foreach ($range['8021q'] as $item) |
3f642516 | 2822 | $summary[] = array ($domainclass[$item['domain_id']] . 'VLAN:', formatVLANAsHyperlink (getVlanRow ($item['domain_id'] . '-' . $item['vlan_id']))); |
6063fab7 | 2823 | if (getConfigVar ('EXT_IPV4_VIEW') == 'yes' and count ($routers = findNetRouters ($range))) |
04d619d0 | 2824 | { |
646272be AA |
2825 | $summary['Routed by'] = ''; |
2826 | foreach ($routers as $rtr) | |
4318ced5 | 2827 | $summary['Routed by'] .= getOutputOf ('renderRouterCell', $rtr['ip_bin'], $rtr['iface'], spotEntity ('object', $rtr['id'])); |
04d619d0 | 2828 | } |
646272be AA |
2829 | $summary['tags'] = ''; |
2830 | renderEntitySummary ($range, 'summary', $summary); | |
e1ae3fb4 | 2831 | |
99ab184f DO |
2832 | if (strlen ($range['comment'])) |
2833 | { | |
2834 | startPortlet ('Comment'); | |
2835 | echo '<div class=commentblock>' . string_insert_hrefs (htmlspecialchars ($range['comment'], ENT_QUOTES, 'UTF-8')) . '</div>'; | |
2836 | finishPortlet (); | |
2837 | } | |
2838 | ||
9da8ee26 | 2839 | renderFilesPortlet ($realm, $range['id']); |
2034d968 | 2840 | echo "</td>\n"; |
e673ee24 | 2841 | |
2034d968 DO |
2842 | echo "<td class=pcright>"; |
2843 | startPortlet ('details'); | |
4318ced5 AA |
2844 | renderIPNetworkAddresses ($range); |
2845 | finishPortlet(); | |
2846 | echo "</td></tr></table>\n"; | |
2847 | } | |
e673ee24 | 2848 | |
4318ced5 AA |
2849 | // Used solely by renderSeparator |
2850 | function renderEmptyIPv6 ($ip_bin, $hl_ip) | |
2851 | { | |
2852 | $class = 'tdleft'; | |
2853 | if ($ip_bin === $hl_ip) | |
5c717ce5 | 2854 | $class .= ' highlight'; |
4318ced5 | 2855 | $fmt = ip6_format ($ip_bin); |
235124a6 | 2856 | echo "<tr class='$class'><td><a name='ip-$fmt' href='" . makeHref (array ('page' => 'ipaddress', 'ip' => $fmt)) . "'>" . $fmt; |
0b8d8309 AA |
2857 | $editable = permitted ('ipaddress', 'properties', 'editAddress') |
2858 | ? 'editable' | |
2859 | : ''; | |
cc2fa820 AD |
2860 | echo "</a></td><td><span class='rsvtext $editable id-$fmt op-upd-ip-name'></span></td>"; |
2861 | echo "<td><span class='rsvtext $editable id-$fmt op-upd-ip-comment'></span></td><td> </td></tr>\n"; | |
4318ced5 AA |
2862 | } |
2863 | ||
2864 | // Renders empty table line to shrink empty IPv6 address ranges. | |
2865 | // If the range consists of single address, renders the address instead of empty line. | |
2866 | // Renders address $hl_ip inside the range. | |
2867 | // Used solely by renderIPv6NetworkAddresses | |
2868 | function renderSeparator ($first, $last, $hl_ip) | |
2869 | { | |
2870 | $self = __FUNCTION__; | |
2871 | if (strcmp ($first, $last) > 0) | |
2872 | return; | |
2873 | if ($first == $last) | |
2874 | renderEmptyIPv6 ($first, $hl_ip); | |
2875 | elseif (isset ($hl_ip) && strcmp ($hl_ip, $first) >= 0 && strcmp ($hl_ip, $last) <= 0) | |
2876 | { // $hl_ip is inside the range $first - $last | |
2877 | $self ($first, ip_prev ($hl_ip), $hl_ip); | |
2878 | renderEmptyIPv6 ($hl_ip, $hl_ip); | |
2879 | $self (ip_next ($hl_ip), $last, $hl_ip); | |
2880 | } | |
2881 | else | |
cc2fa820 | 2882 | echo "<tr><td colspan=4 class=tdleft></td></tr>\n"; |
4318ced5 AA |
2883 | } |
2884 | ||
75e7c0c6 | 2885 | // calculates page number that contains given $ip (used by renderIPv6NetworkAddresses) |
4318ced5 AA |
2886 | function getPageNumOfIPv6 ($list, $ip_bin, $maxperpage) |
2887 | { | |
2888 | if (intval ($maxperpage) <= 0 || count ($list) <= $maxperpage) | |
2889 | return 0; | |
2890 | $keys = array_keys ($list); | |
2891 | for ($i = 1; $i <= count ($keys); $i++) | |
2892 | if (strcmp ($keys[$i-1], $ip_bin) >= 0) | |
2893 | return intval ($i / $maxperpage); | |
2894 | return intval (count ($list) / $maxperpage); | |
2895 | } | |
2896 | ||
2897 | function renderIPNetworkAddresses ($range) | |
2898 | { | |
2899 | switch (strlen ($range['ip_bin'])) | |
2900 | { | |
2901 | case 4: return renderIPv4NetworkAddresses ($range); | |
2902 | case 16: return renderIPv6NetworkAddresses ($range); | |
2903 | default: throw new InvalidArgException ("range['ip_bin']", $range['ip_bin']); | |
2904 | } | |
2905 | } | |
2906 | ||
247acd67 KZ |
2907 | function renderIPv4NetworkPageLink ($rangeid, $page, $title) |
2908 | { | |
2909 | global $pageno, $tabno; | |
2910 | return "<a href='".makeHref (array ('page' => $pageno, 'tab' => $tabno, 'id' => $rangeid, 'pg' => $page)) . "' title='".$title."'>".$page."</a> "; | |
2911 | } | |
2912 | ||
2913 | function renderIPv4NetworkPagination ($range, $page, $numpages) | |
2914 | { | |
2915 | $rendered_pager = ''; | |
2916 | $startip = ip4_bin2int ($range['ip_bin']); | |
2917 | $endip = ip4_bin2int (ip_last ($range)); | |
2918 | $rangeid = $range['id']; | |
2919 | // Should make this configurable perhaps | |
2920 | // How many pages before/after current page to show | |
2921 | $prepostpagecount = 8; | |
2922 | // Minimum pages where pagination does not happen | |
2923 | $paginationat = 16; // 16 pages is a /20, 32 is a /19 | |
2924 | $maxperpage = getConfigVar ('IPV4_ADDRS_PER_PAGE'); | |
2925 | if ($numpages <= $paginationat) | |
2926 | { | |
2927 | // create original pagination | |
2928 | for ($i = 0; $i < $numpages; $i++) | |
2929 | if ($i == $page) | |
2930 | $rendered_pager .= "<b>".$i."</b> "; | |
2931 | else | |
2932 | $rendered_pager .= renderIPv4NetworkPageLink($rangeid, $i, ip4_format(ip4_int2bin($startip + $i * $maxperpage))); | |
2933 | } | |
2934 | else // number of pages > page range, create ranged pagination | |
2935 | { | |
2936 | // page is within first subset | |
2937 | if ($page - $prepostpagecount <= 1) | |
2938 | { | |
2939 | for ($i = 0; $i < $page; $i++) | |
2940 | $rendered_pager .= renderIPv4NetworkPageLink($rangeid, $i, ip4_format(ip4_int2bin($startip + $i * $maxperpage))); | |
2941 | } | |
2942 | // render 0 ... [page - prepostpagecount] [page - prepostpagecount + 1] ... [page - 1] | |
2943 | else | |
2944 | { | |
2945 | $rendered_pager .= renderIPv4NetworkPageLink($rangeid, 0, ip4_format(ip4_int2bin($startip))); | |
2946 | $rendered_pager .= "... "; | |
2947 | for ($i = $page - $prepostpagecount; $i < $page; $i++) | |
2948 | $rendered_pager .= renderIPv4NetworkPageLink($rangeid, $i, ip4_format(ip4_int2bin($startip + $i * $maxperpage))); | |
2949 | } | |
2950 | // render current page | |
2951 | $rendered_pager .= "<b>".$page."</b> "; | |
2952 | // page is within last subset | |
2953 | if ($page + $prepostpagecount >= $numpages-2) | |
2954 | { | |
2955 | for ($i = $page+1; $i < $numpages; $i++) | |
2956 | $rendered_pager .= renderIPv4NetworkPageLink($rangeid, $i, ip4_format(ip4_int2bin($startip + $i * $maxperpage))); | |
2957 | } | |
2958 | // render [page + 1] [page + 2] ... [page + postpagecount] ... [end page] | |
2959 | else | |
2960 | { | |
2961 | for ($i = $page+1; $i <= $page+$prepostpagecount; $i++) | |
2962 | $rendered_pager .= renderIPv4NetworkPageLink($rangeid, $i, ip4_format(ip4_int2bin($startip + $i * $maxperpage))); | |
2963 | $rendered_pager .= "... "; | |
2964 | $rendered_pager .= renderIPv4NetworkPageLink($rangeid, ($numpages-1), ip4_format(ip4_int2bin($endip))); | |
2965 | } | |
2966 | } | |
2967 | return $rendered_pager; | |
2968 | } | |
2969 | ||
4318ced5 AA |
2970 | function renderIPv4NetworkAddresses ($range) |
2971 | { | |
9d5f6a80 | 2972 | global $pageno, $tabno, $aac_left; |
4318ced5 AA |
2973 | $startip = ip4_bin2int ($range['ip_bin']); |
2974 | $endip = ip4_bin2int (ip_last ($range)); | |
2975 | ||
2976 | if (isset ($_REQUEST['hl_ip'])) | |
00276508 | 2977 | { |
4318ced5 AA |
2978 | $hl_ip = ip4_bin2int (ip4_parse ($_REQUEST['hl_ip'])); |
2979 | addAutoScrollScript ('ip-' . $_REQUEST['hl_ip']); // scroll page to highlighted ip | |
00276508 AA |
2980 | } |
2981 | ||
79b57b18 AA |
2982 | // pager |
2983 | $maxperpage = getConfigVar ('IPV4_ADDRS_PER_PAGE'); | |
2984 | $address_count = $endip - $startip + 1; | |
2985 | $page = 0; | |
446c25c3 | 2986 | $rendered_pager = ''; |
79b57b18 AA |
2987 | if ($address_count > $maxperpage && $maxperpage > 0) |
2988 | { | |
2989 | $page = isset ($_REQUEST['pg']) ? $_REQUEST['pg'] : (isset ($hl_ip) ? intval (($hl_ip - $startip) / $maxperpage) : 0); | |
2990 | if ($numpages = ceil ($address_count / $maxperpage)) | |
2991 | { | |
4318ced5 | 2992 | echo '<h3>' . ip4_format (ip4_int2bin ($startip)) . ' ~ ' . ip4_format (ip4_int2bin ($endip)) . '</h3>'; |
247acd67 | 2993 | $rendered_pager = renderIPv4NetworkPagination ($range, $page, $numpages); |
79b57b18 AA |
2994 | } |
2995 | $startip = $startip + $page * $maxperpage; | |
2996 | $endip = min ($startip + $maxperpage - 1, $endip); | |
2997 | } | |
2998 | ||
446c25c3 | 2999 | echo $rendered_pager; |
beb9e88a | 3000 | echo "<table class='widetable' border=0 cellspacing=0 cellpadding=5 align='center' width='100%'>\n"; |
cc2fa820 | 3001 | echo "<tr><th>Address</th><th>Name</th><th>Comment</th><th>Allocation</th></tr>\n"; |
e673ee24 | 3002 | |
4318ced5 AA |
3003 | markupIPAddrList ($range['addrlist']); |
3004 | for ($ip = $startip; $ip <= $endip; $ip++) | |
3005 | { | |
3006 | $ip_bin = ip4_int2bin ($ip); | |
3007 | $dottedquad = ip4_format ($ip_bin); | |
5c717ce5 | 3008 | $tr_class = (isset ($hl_ip) && $hl_ip == $ip ? 'highlight' : ''); |
0cd7c0f6 AA |
3009 | if (isset ($range['addrlist'][$ip_bin])) |
3010 | $addr = $range['addrlist'][$ip_bin]; | |
3011 | else | |
e673ee24 | 3012 | { |
235124a6 | 3013 | echo "<tr class='tdleft $tr_class'><td class=tdleft><a name='ip-$dottedquad' href='" . makeHref(array('page'=>'ipaddress', 'ip' => $dottedquad)) . "'>$dottedquad</a></td>"; |
0b8d8309 AA |
3014 | $editable = permitted ('ipaddress', 'properties', 'editAddress') |
3015 | ? 'editable' | |
3016 | : ''; | |
cc2fa820 AD |
3017 | echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-name'></span></td>"; |
3018 | echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-comment'></span></td><td></td></tr>\n"; | |
b2035dca DO |
3019 | continue; |
3020 | } | |
68c91b9c AA |
3021 | // render IP change history |
3022 | $title = ''; | |
3023 | $history_class = ''; | |
3024 | if (isset ($addr['last_log'])) | |
3025 | { | |
3026 | $title = ' title="' . htmlspecialchars ($addr['last_log']['user'] . ', ' . formatAge ($addr['last_log']['time']) , ENT_QUOTES) . '"'; | |
3027 | $history_class = 'hover-history underline'; | |
3028 | } | |
4318ced5 AA |
3029 | $tr_class .= ' ' . $addr['class']; |
3030 | echo "<tr class='tdleft $tr_class'>"; | |
235124a6 | 3031 | echo "<td><a class='$history_class' $title name='ip-$dottedquad' href='".makeHref(array('page'=>'ipaddress', 'ip'=>$addr['ip']))."'>${addr['ip']}</a></td>"; |
0b8d8309 | 3032 | $editable = |
cc2fa820 | 3033 | (empty ($addr['allocs']) || !empty ($addr['name']) || !empty ($addr['comment'])) |
0b8d8309 AA |
3034 | && permitted ('ipaddress', 'properties', 'editAddress') |
3035 | ? 'editable' | |
3036 | : ''; | |
cc2fa820 AD |
3037 | echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-name'>${addr['name']}</span></td>"; |
3038 | echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-comment'>${addr['comment']}</span></td>"; | |
0b8d8309 | 3039 | echo "<td>"; |
b2035dca | 3040 | $delim = ''; |
b2035dca DO |
3041 | if ( $addr['reserved'] == 'yes') |
3042 | { | |
2d318652 | 3043 | echo "<strong>RESERVED</strong> "; |
b2035dca DO |
3044 | $delim = '; '; |
3045 | } | |
212b565a | 3046 | foreach ($addr['allocs'] as $ref) |
b2035dca | 3047 | { |
9d5f6a80 | 3048 | echo $delim . $aac_left[$ref['type']]; |
e749a34f | 3049 | echo makeIPAllocLink ($ip_bin, $ref, TRUE); |
b2035dca DO |
3050 | $delim = '; '; |
3051 | } | |
3052 | if ($delim != '') | |
e0d6e38e | 3053 | $delim = '<br>'; |
212b565a AA |
3054 | foreach ($addr['vslist'] as $vs_id) |
3055 | { | |
3056 | $vs = spotEntity ('ipv4vs', $vs_id); | |
ad3e5e7e | 3057 | echo $delim . mkA ("${vs['name']}:${vs['vport']}/${vs['proto']}", 'ipv4vs', $vs['id']) . '→'; |
212b565a AA |
3058 | $delim = '<br>'; |
3059 | } | |
eacc0983 AA |
3060 | foreach ($addr['vsglist'] as $vs_id) |
3061 | { | |
3062 | $vs = spotEntity ('ipvs', $vs_id); | |
3063 | echo $delim . mkA ($vs['name'], 'ipvs', $vs['id']) . '→'; | |
3064 | $delim = '<br>'; | |
3065 | } | |
212b565a AA |
3066 | foreach ($addr['rsplist'] as $rsp_id) |
3067 | { | |
3068 | $rsp = spotEntity ('ipv4rspool', $rsp_id); | |
ad3e5e7e | 3069 | echo "${delim}→" . mkA ($rsp['name'], 'ipv4rspool', $rsp['id']); |
212b565a AA |
3070 | $delim = '<br>'; |
3071 | } | |
b2035dca | 3072 | echo "</td></tr>\n"; |
4318ced5 | 3073 | } |
2727c7df | 3074 | // end of iteration |
a8dc2982 AA |
3075 | if (permitted (NULL, NULL, 'set_reserve_comment')) |
3076 | addJS ('js/inplace-edit.js'); | |
e673ee24 DO |
3077 | |
3078 | echo "</table>"; | |
446c25c3 AA |
3079 | if (! empty ($rendered_pager)) |
3080 | echo '<p>' . $rendered_pager . '</p>'; | |
21ee3351 AA |
3081 | } |
3082 | ||
3083 | function renderIPv6NetworkAddresses ($netinfo) | |
3084 | { | |
9d5f6a80 | 3085 | global $pageno, $tabno, $aac_left; |
21ee3351 | 3086 | echo "<table class='widetable' border=0 cellspacing=0 cellpadding=5 align='center' width='100%'>\n"; |
cc2fa820 | 3087 | echo "<tr><th>Address</th><th>Name</th><th>Comment</th><th>Allocation</th></tr>\n"; |
21ee3351 | 3088 | |
4318ced5 AA |
3089 | $hl_ip = NULL; |
3090 | if (isset ($_REQUEST['hl_ip'])) | |
3091 | { | |
3092 | $hl_ip = ip6_parse ($_REQUEST['hl_ip']); | |
3093 | addAutoScrollScript ('ip-' . ip6_format ($hl_ip)); | |
3094 | } | |
21ee3351 | 3095 | |
21ee3351 AA |
3096 | $addresses = $netinfo['addrlist']; |
3097 | ksort ($addresses); | |
4318ced5 | 3098 | markupIPAddrList ($addresses); |
21ee3351 AA |
3099 | |
3100 | // pager | |
3101 | $maxperpage = getConfigVar ('IPV4_ADDRS_PER_PAGE'); | |
3102 | if (count ($addresses) > $maxperpage && $maxperpage > 0) | |
3103 | { | |
3104 | $page = isset ($_REQUEST['pg']) ? $_REQUEST['pg'] : (isset ($hl_ip) ? getPageNumOfIPv6 ($addresses, $hl_ip, $maxperpage) : 0); | |
3105 | $numpages = ceil (count ($addresses) / $maxperpage); | |
3106 | echo "<center><h3>$numpages pages:</h3>"; | |
3107 | for ($i=0; $i<$numpages; $i++) | |
3108 | { | |
3109 | if ($i == $page) | |
3110 | echo "<b>$i</b> "; | |
3111 | else | |
3112 | echo "<a href='" . makeHref (array ('page' => $pageno, 'tab' => $tabno, 'id' => $netinfo['id'], 'pg' => $i)) . "'>$i</a> "; | |
3113 | } | |
3114 | echo "</center>"; | |
3115 | } | |
3116 | ||
3117 | $i = 0; | |
dec748f6 | 3118 | $interruped = FALSE; |
4318ced5 AA |
3119 | $prev_ip = ip_prev ($netinfo['ip_bin']); |
3120 | foreach ($addresses as $ip_bin => $addr) | |
21ee3351 AA |
3121 | { |
3122 | if (isset ($page)) | |
3123 | { | |
3124 | ++$i; | |
3125 | if ($i <= $maxperpage * $page) | |
3126 | continue; | |
3127 | elseif ($i > $maxperpage * ($page + 1)) | |
3128 | { | |
3129 | $interruped = TRUE; | |
3130 | break; | |
3131 | } | |
3132 | } | |
3133 | ||
4318ced5 AA |
3134 | if ($ip_bin != ip_next ($prev_ip)) |
3135 | renderSeparator (ip_next ($prev_ip), ip_prev ($ip_bin), $hl_ip); | |
3136 | $prev_ip = $ip_bin; | |
3137 | ||
3138 | // render IP change history | |
3139 | $title = ''; | |
3140 | $history_class = ''; | |
3141 | if (isset ($addr['last_log'])) | |
3142 | { | |
3143 | $title = ' title="' . htmlspecialchars ($addr['last_log']['user'] . ', ' . formatAge ($addr['last_log']['time']) , ENT_QUOTES) . '"'; | |
3144 | $history_class = 'hover-history underline'; | |
3145 | } | |
3146 | ||
5c717ce5 | 3147 | $tr_class = $addr['class'] . ' tdleft' . ($hl_ip === $ip_bin ? ' highlight' : ''); |
4318ced5 | 3148 | echo "<tr class='$tr_class'>"; |
235124a6 | 3149 | echo "<td><a class='$history_class' $title name='ip-${addr['ip']}' href='" . makeHref (array ('page' => 'ipaddress', 'ip' => $addr['ip'])) . "'>${addr['ip']}</a></td>"; |
0b8d8309 AA |
3150 | $editable = |
3151 | (empty ($addr['allocs']) || !empty ($addr['name']) | |
3152 | && permitted ('ipaddress', 'properties', 'editAddress') | |
3153 | ? 'editable' | |
3154 | : ''); | |
cc2fa820 AD |
3155 | echo "<td><span class='rsvtext $editable id-${addr['ip']} op-upd-ip-name'>${addr['name']}</span></td>"; |
3156 | echo "<td><span class='rsvtext $editable id-${addr['ip']} op-upd-ip-comment'>${addr['comment']}</span></td><td>"; | |
21ee3351 | 3157 | $delim = ''; |
21ee3351 AA |
3158 | if ( $addr['reserved'] == 'yes') |
3159 | { | |
3160 | echo "<strong>RESERVED</strong> "; | |
3161 | $delim = '; '; | |
3162 | } | |
3163 | foreach ($addr['allocs'] as $ref) | |
3164 | { | |
9d5f6a80 | 3165 | echo $delim . $aac_left[$ref['type']]; |
e749a34f | 3166 | echo makeIPAllocLink ($ip_bin, $ref, TRUE); |
21ee3351 AA |
3167 | $delim = '; '; |
3168 | } | |
3169 | if ($delim != '') | |