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 | { | |
55eefced | 86 | $https = (isset ($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 's' : ''; |
5eb81cf8 AD |
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"> | |
832fdbb9 | 119 | <div style="float: right" class=greeting><?php global $remote_displayname; echo mkA ($remote_displayname, 'myaccount', NULL, 'default'); ?> [ <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']]; |
33973968 | 234 | if ($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 | ||
150effa7 | 421 | function getRackThumbLink ($rack, $scale = 1, $object_id = NULL) |
e10d9597 DO |
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' . | |
150effa7 DO |
429 | ($scale == 1 && $object_id === NULL ? '&img=minirack' : "&img=midirack&scale=${scale}") . |
430 | "&rack_id=${rack['id']}" . | |
431 | ($object_id === NULL ? '' : "&object_id=${object_id}"); | |
e10d9597 | 432 | $img = "<img border=0 width=${width} height=${height} title='${title}' src='${src}'>"; |
168c2acb | 433 | return mkA ($img, 'rack', $rack['id']); |
e10d9597 DO |
434 | } |
435 | ||
e673ee24 DO |
436 | function renderRackspace () |
437 | { | |
e1add254 | 438 | // Handle the location filter |
0a00b344 | 439 | startSession(); |
e1add254 AD |
440 | if (isset ($_REQUEST['changeLocationFilter'])) |
441 | unset ($_SESSION['locationFilter']); | |
442 | if (isset ($_REQUEST['location_id'])) | |
443 | $_SESSION['locationFilter'] = $_REQUEST['location_id']; | |
5d6352df | 444 | session_commit(); |
e1add254 | 445 | |
950dfa1f AA |
446 | echo "<table class=objview border=0 width='100%'><tr><td class=pcleft>"; |
447 | ||
95857b5c | 448 | $found_racks = array(); |
a8efc03e | 449 | $cellfilter = getCellFilter(); |
950dfa1f | 450 | if (! ($cellfilter['is_empty'] && !isset ($_SESSION['locationFilter']) && renderEmptyResults ($cellfilter, 'racks', getEntitiesCount ('rack')))) |
e1add254 | 451 | { |
950dfa1f AA |
452 | $rows = array(); |
453 | $rackCount = 0; | |
524f8a7b | 454 | foreach (listCells ('row') as $row_id => $rowInfo) |
950dfa1f | 455 | { |
2b16c179 | 456 | $rackList = applyCellFilter ('rack', $cellfilter, $row_id); |
950dfa1f | 457 | $found_racks = array_merge ($found_racks, $rackList); |
d9bad31a AD |
458 | $location_id = $rowInfo['location_id']; |
459 | $locationIdx = 0; | |
460 | // contains location names in the form of 'grandparent parent child', used for sorting | |
461 | $locationTree = ''; | |
462 | // contains location names as well as links | |
463 | $hrefLocationTree = ''; | |
464 | while ($location_id) | |
465 | { | |
466 | if ($locationIdx == 20) | |
467 | { | |
468 | showWarning ("Warning: There is likely a circular reference in the location tree. Investigate location ${location_id}."); | |
469 | break; | |
470 | } | |
471 | $parentLocation = spotEntity ('location', $location_id); | |
472 | $locationTree = sprintf ('%s %s', $parentLocation['name'], $locationTree); | |
473 | $hrefLocationTree = "» <a href='" . | |
474 | makeHref(array('page'=>'location', 'location_id'=>$parentLocation['id'])) . | |
475 | "${cellfilter['urlextra']}'>${parentLocation['name']}</a> " . | |
476 | $hrefLocationTree; | |
477 | $location_id = $parentLocation['parent_id']; | |
478 | $locationIdx++; | |
479 | } | |
480 | $hrefLocationTree = substr ($hrefLocationTree, 8); | |
950dfa1f AA |
481 | $rows[] = array ( |
482 | 'location_id' => $rowInfo['location_id'], | |
d9bad31a AD |
483 | 'location_tree' => $locationTree, |
484 | 'href_location_tree' => $hrefLocationTree, | |
950dfa1f AA |
485 | 'row_id' => $row_id, |
486 | 'row_name' => $rowInfo['name'], | |
487 | 'racks' => $rackList | |
488 | ); | |
489 | $rackCount += count($rackList); | |
490 | } | |
1ebbf889 | 491 | |
d9bad31a AD |
492 | // sort by location, then by row |
493 | usort ($rows, 'rackspaceCmp'); | |
494 | ||
950dfa1f | 495 | if (! renderEmptyResults($cellfilter, 'racks', $rackCount)) |
1ebbf889 | 496 | { |
950dfa1f AA |
497 | // generate thumb gallery |
498 | global $nextorder; | |
950dfa1f AA |
499 | // Zero value effectively disables the limit. |
500 | $maxPerRow = getConfigVar ('RACKS_PER_ROW'); | |
501 | $order = 'odd'; | |
18733c4a AD |
502 | if (! count ($rows)) |
503 | echo "<h2>No rows found</h2>\n"; | |
504 | else | |
e1add254 | 505 | { |
950dfa1f AA |
506 | echo '<table border=0 cellpadding=10 class=cooltable>'; |
507 | echo '<tr><th class=tdleft>Location</th><th class=tdleft>Row</th><th class=tdleft>Racks</th></tr>'; | |
508 | foreach ($rows as $row) | |
c08915c7 | 509 | { |
950dfa1f AA |
510 | $rackList = $row['racks']; |
511 | ||
512 | if ( | |
55eefced DO |
513 | $location_id != '' && isset ($_SESSION['locationFilter']) && ! in_array ($location_id, $_SESSION['locationFilter']) || |
514 | empty ($rackList) && ! $cellfilter['is_empty'] | |
950dfa1f AA |
515 | ) |
516 | continue; | |
517 | $rackListIdx = 0; | |
d9bad31a AD |
518 | echo "<tr class=row_${order}><th class=tdleft>${row['href_location_tree']}</th>"; |
519 | echo "<th class=tdleft><a href='".makeHref(array('page'=>'row', 'row_id'=>$row['row_id']))."${cellfilter['urlextra']}'>${row['row_name']}</a></th>"; | |
950dfa1f | 520 | echo "<th class=tdleft><table border=0 cellspacing=5><tr>"; |
18733c4a AD |
521 | if (! count ($rackList)) |
522 | echo '<td>(empty row)</td>'; | |
950dfa1f AA |
523 | else |
524 | foreach ($rackList as $rack) | |
e1add254 | 525 | { |
55eefced | 526 | if ($rackListIdx > 0 && $maxPerRow > 0 && $rackListIdx % $maxPerRow == 0) |
950dfa1f AA |
527 | { |
528 | echo '</tr></table></th></tr>'; | |
d9bad31a | 529 | echo "<tr class=row_${order}><th class=tdleft></th><th class=tdleft>${row['row_name']} (continued)"; |
950dfa1f AA |
530 | echo "</th><th class=tdleft><table border=0 cellspacing=5><tr>"; |
531 | } | |
168c2acb DO |
532 | echo '<td align=center valign=bottom>' . getRackThumbLink ($rack); |
533 | echo '<br>' . mkA (stringForLabel ($rack['name']), 'rack', $rack['id']) . '</td>'; | |
950dfa1f | 534 | $rackListIdx++; |
e1add254 | 535 | } |
950dfa1f AA |
536 | $order = $nextorder[$order]; |
537 | echo "</tr></table></th></tr>\n"; | |
538 | } | |
539 | echo "</table>\n"; | |
e1add254 | 540 | } |
1ebbf889 | 541 | } |
e673ee24 | 542 | } |
14ad4f4a DO |
543 | echo '</td><td class=pcright width="25%">'; |
544 | renderCellFilterPortlet ($cellfilter, 'rack', $found_racks); | |
e1add254 AD |
545 | echo "<br>\n"; |
546 | renderLocationFilterPortlet (); | |
489a7502 | 547 | echo "</td></tr></table>\n"; |
e673ee24 DO |
548 | } |
549 | ||
2056822d | 550 | function renderLocationRowForEditor ($subtree, $level = 0) |
e1add254 AD |
551 | { |
552 | $self = __FUNCTION__; | |
2056822d AA |
553 | foreach ($subtree as $locationinfo) |
554 | { | |
555 | echo "<tr><td align=left style='padding-left: " . ($locationinfo['kidc'] ? $level : ($level + 1) * 16) . "px;'>"; | |
556 | if ($locationinfo['kidc']) | |
557 | printImageHREF ('node-expanded-static'); | |
558 | if ($locationinfo['refcnt'] > 0 || $locationinfo['kidc'] > 0) | |
559 | printImageHREF ('nodestroy'); | |
560 | else | |
10f5133a | 561 | echo getOpLink (array ('op' => 'deleteLocation', 'location_id' => $locationinfo['id']), '', 'destroy', 'Delete location'); |
2056822d AA |
562 | echo '</td><td class=tdleft>'; |
563 | printOpFormIntro ('updateLocation', array ('location_id' => $locationinfo['id'])); | |
564 | $parent = isset ($locationinfo['parent_id']) ? $locationinfo['parent_id'] : 0; | |
565 | echo getSelect | |
566 | ( | |
567 | array ( $parent => $parent ? htmlspecialchars ($locationinfo['parent_name']) : '-- NONE --'), | |
568 | array ('name' => 'parent_id', 'id' => 'locationid_' . $locationinfo['id'], 'class' => 'locationlist-popup'), | |
569 | $parent, | |
570 | FALSE | |
571 | ); | |
572 | echo "</td><td class=tdleft>"; | |
573 | echo "<input type=text size=48 name=name value='${locationinfo['name']}'>"; | |
574 | echo '</td><td>' . getImageHREF ('save', 'Save changes', TRUE) . "</form></td></tr>\n"; | |
575 | if ($locationinfo['kidc']) | |
576 | $self ($locationinfo['kids'], $level + 1); | |
577 | } | |
e1add254 AD |
578 | } |
579 | ||
82fa45a9 | 580 | function renderLocationSelectTree ($select_name, $selected_id = NULL) |
eda41675 | 581 | { |
82fa45a9 | 582 | echo "<select name='${select_name}'>"; |
eda41675 | 583 | echo '<option value=0>-- NONE --</option>'; |
359ea9f9 | 584 | $locationlist = listCells ('location'); |
d6409c53 | 585 | foreach (treeFromList (addTraceToNodes ($locationlist)) as $location) |
eda41675 AD |
586 | { |
587 | echo "<option value=${location['id']} style='font-weight: bold' "; | |
588 | if ($location['id'] == $selected_id ) | |
589 | echo ' selected'; | |
590 | echo ">${location['name']}</option>"; | |
e3648fa6 | 591 | printLocationChildrenSelectOptions ($location, $selected_id); |
eda41675 AD |
592 | } |
593 | echo '</select>'; | |
594 | } | |
595 | ||
e1add254 AD |
596 | function renderRackspaceLocationEditor () |
597 | { | |
b090b2da RQ |
598 | $js = <<<JSTXT |
599 | function locationeditor_showselectbox(e) { | |
600 | $(this).load('index.php', {module: 'ajax', ac: 'get-location-select', locationid: this.id}); | |
601 | $(this).unbind('mousedown', locationeditor_showselectbox); | |
602 | } | |
603 | $(document).ready(function () { | |
604 | $('select.locationlist-popup').bind('mousedown', locationeditor_showselectbox); | |
605 | }); | |
606 | JSTXT; | |
607 | ||
608 | addJS($js, TRUE ); | |
e1add254 AD |
609 | function printNewItemTR () |
610 | { | |
e1add254 | 611 | printOpFormIntro ('addLocation'); |
eda41675 | 612 | echo '<tr><td>'; |
e1add254 | 613 | printImageHREF ('create', 'Add new location', TRUE); |
82fa45a9 DO |
614 | echo '</td><td>'; |
615 | renderLocationSelectTree ('parent_id'); | |
04c61e7e AB |
616 | echo '</td><td><input type=text size=48 name=name></td><td>'; |
617 | printImageHREF ('create', 'Add new location', TRUE); | |
e1add254 AD |
618 | echo "</td></tr></form>\n"; |
619 | } | |
e1add254 AD |
620 | |
621 | startPortlet ('Locations'); | |
622 | echo "<table border=0 cellspacing=0 cellpadding=5 align=center class=widetable>\n"; | |
623 | echo "<tr><th> </th><th>Parent</th><th>Name</th><th> </th></tr>\n"; | |
624 | if (getConfigVar ('ADDNEW_AT_TOP') == 'yes') | |
625 | printNewItemTR(); | |
2056822d | 626 | |
1e0f13f3 | 627 | $locations = listCells ('location'); |
d6409c53 | 628 | renderLocationRowForEditor (treeFromList (addTraceToNodes ($locations))); |
2056822d | 629 | |
e1add254 AD |
630 | if (getConfigVar ('ADDNEW_AT_TOP') != 'yes') |
631 | printNewItemTR(); | |
632 | echo "</table><br>\n"; | |
633 | finishPortlet(); | |
634 | } | |
635 | ||
345fd640 AD |
636 | function renderRackspaceRowEditor () |
637 | { | |
eda41675 | 638 | function printNewItemTR () |
345fd640 AD |
639 | { |
640 | printOpFormIntro ('addRow'); | |
eda41675 | 641 | echo '<tr><td>'; |
7be51fea | 642 | printImageHREF ('create', 'Add new row', TRUE); |
04eee8d2 VS |
643 | echo '</td><td> '; |
644 | echo '</td><td> '; | |
82fa45a9 DO |
645 | echo '</td><td>'; |
646 | renderLocationSelectTree ('location_id'); | |
04c61e7e AB |
647 | echo '</td><td><input type=text name=name></td><td>'; |
648 | printImageHREF ('create', 'Add new row', TRUE); | |
aca7e169 | 649 | echo '</td><td> '; |
eda41675 | 650 | echo '</td></tr></form>'; |
345fd640 | 651 | } |
d732e47e | 652 | startPortlet ('Rows'); |
345fd640 | 653 | echo "<table border=0 cellspacing=0 cellpadding=5 align=center class=widetable>\n"; |
04eee8d2 | 654 | 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 | 655 | if (getConfigVar ('ADDNEW_AT_TOP') == 'yes') |
eda41675 | 656 | printNewItemTR (); |
524f8a7b | 657 | foreach (listCells ('row') as $row_id => $rowInfo) |
345fd640 | 658 | { |
eda41675 | 659 | echo '<tr><td>'; |
04eee8d2 VS |
660 | $rc = $rowInfo['rackc']; |
661 | $delete_racks_str = $rc ? " and $rc rack(s)" : ''; | |
662 | echo getOpLink (array ('op'=>'deleteRow', 'row_id'=>$row_id), '', 'destroy', 'Delete row'.$delete_racks_str, 'need-confirmation'); | |
c40666f5 | 663 | printOpFormIntro ('updateRow', array ('row_id' => $row_id)); |
eda41675 | 664 | echo '</td><td>'; |
04eee8d2 VS |
665 | echo $rc; |
666 | echo '</td><td>'; | |
667 | echo getRowMountsCount ($row_id); | |
668 | echo '</td><td>'; | |
82fa45a9 | 669 | renderLocationSelectTree ('location_id', $rowInfo['location_id']); |
04c61e7e | 670 | echo "</td><td><input type=text name=name value='${rowInfo['name']}'></td><td>"; |
7be51fea | 671 | printImageHREF ('save', 'Save changes', TRUE); |
524f8a7b AA |
672 | echo "</form></td>"; |
673 | echo "<td>" . mkCellA ($rowInfo) . "</td>"; | |
674 | echo "</tr>\n"; | |
345fd640 AD |
675 | } |
676 | if (getConfigVar ('ADDNEW_AT_TOP') != 'yes') | |
eda41675 | 677 | printNewItemTR (); |
345fd640 AD |
678 | echo "</table><br>\n"; |
679 | finishPortlet(); | |
680 | } | |
681 | ||
d10401bf | 682 | function renderRow ($row_id) |
e673ee24 | 683 | { |
e16b666c | 684 | $rowInfo = getRowInfo ($row_id); |
a8efc03e | 685 | $cellfilter = getCellFilter(); |
2b16c179 | 686 | $rackList = applyCellFilter ('rack', $cellfilter, $row_id); |
138655f5 AD |
687 | |
688 | $summary = array (); | |
689 | $summary['Name'] = $rowInfo['name']; | |
690 | if ($rowInfo['location_id']) | |
691 | $summary['Location'] = mkA ($rowInfo['location'], 'location', $rowInfo['location_id']); | |
692 | $summary['Racks'] = $rowInfo['count']; | |
693 | $summary['Units'] = $rowInfo['sum']; | |
694 | $summary['% used'] = getProgressBar (getRSUforRow ($rackList)); | |
249c78b2 | 695 | foreach (getAttrValuesSorted ($row_id) as $record) |
138655f5 AD |
696 | if |
697 | ( | |
55eefced | 698 | $record['value'] != '' && |
138655f5 AD |
699 | permitted (NULL, NULL, NULL, array (array ('tag' => '$attr_' . $record['id']))) |
700 | ) | |
701 | $summary['{sticker}' . $record['name']] = formatAttributeValue ($record); | |
702 | ||
e673ee24 DO |
703 | // Main layout starts. |
704 | echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>"; | |
705 | ||
706 | // Left portlet with row information. | |
707 | echo "<tr><td class=pcleft>"; | |
138655f5 | 708 | renderEntitySummary ($rowInfo, 'Summary', $summary); |
7f297114 | 709 | renderCellFilterPortlet ($cellfilter, 'rack', $rackList, array ('row_id' => $row_id)); |
6ccfd4bd | 710 | renderFilesPortlet ('row',$row_id); |
48325652 | 711 | echo "</td><td class=pcright>"; |
e673ee24 | 712 | |
4fbb5a00 | 713 | global $nextorder; |
f5883ec1 DO |
714 | // Maximum number of racks per row is proportionally less, but at least 1. |
715 | $maxPerRow = max (floor (getConfigVar ('RACKS_PER_ROW') / getConfigVar ('ROW_SCALE')), 1); | |
716 | $rackListIdx = 0; | |
e673ee24 DO |
717 | $order = 'odd'; |
718 | startPortlet ('Racks'); | |
719 | echo "<table border=0 cellspacing=5 align='center'><tr>"; | |
64b95774 | 720 | foreach ($rackList as $rack) |
e673ee24 | 721 | { |
f5883ec1 DO |
722 | if ($rackListIdx % $maxPerRow == 0) |
723 | { | |
724 | if ($rackListIdx > 0) | |
725 | echo '</tr>'; | |
726 | echo '<tr>'; | |
727 | } | |
9b8174d7 | 728 | $class = ($rack['has_problems'] == 'yes') ? 'error' : $order; |
168c2acb DO |
729 | echo "<td align=center valign=bottom class=row_${class}>" . |
730 | getRackThumbLink ($rack, getConfigVar ('ROW_SCALE')) . | |
731 | '<br>' . mkA (stringForLabel ($rack['name']), 'rack', $rack['id']) . '</td>'; | |
e673ee24 | 732 | $order = $nextorder[$order]; |
f5883ec1 | 733 | $rackListIdx++; |
e673ee24 DO |
734 | } |
735 | echo "</tr></table>\n"; | |
736 | finishPortlet(); | |
e673ee24 DO |
737 | echo "</td></tr></table>"; |
738 | } | |
739 | ||
d10401bf | 740 | function renderEditRowForm ($row_id) |
138655f5 AD |
741 | { |
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>'; | |
33973968 | 766 | if ($record['value'] != '') |
138655f5 AD |
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); | |
33973968 | 810 | if ($objectData['asset_no'] != '') |
0a7feebb AD |
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 = ''; | |
55eefced | 816 | if ($objectData['name'] != $objectData['label'] && $objectData['label'] != '') |
0a7feebb AD |
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']; | |
33973968 | 846 | if ($childData['asset_no'] != '') |
84feb87b AD |
847 | $slotTitle[$slot] = "<div title='${childData['asset_no']}"; |
848 | else | |
849 | $slotTitle[$slot] = "<div title='no asset tag"; | |
55eefced | 850 | if ($childData['label'] != '' && $childData['label'] != $childData['dname']) |
84feb87b AD |
851 | $slotTitle[$slot] .= ", visible label is \"${childData['label']}\""; |
852 | $slotTitle[$slot] .= "'>"; | |
5a7bf292 | 853 | $slotClass[$slot] = 'state_T'; |
c17a36f0 | 854 | if ($childData['id'] == $hl_obj_id) |
0cdfc55c DO |
855 | $slotClass[$slot] .= 'h'; |
856 | if ($childData['has_problems'] == 'yes') | |
857 | $slotClass[$slot] .= 'w'; | |
84feb87b AD |
858 | } |
859 | } | |
0a7feebb AD |
860 | natsort($childNames); |
861 | $suffix = sprintf(", contains %s'>", implode(', ', $childNames)); | |
862 | } | |
863 | else | |
864 | $suffix = "'>"; | |
6d8424f8 | 865 | echo "${prefix}${body}${suffix}" . mkCellA ($objectData) . '</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 | { | |
3e393bcc AY |
903 | $tmp = mb_substr($slotInfo[$s], 0, 1); |
904 | for($i = 1; $i < mb_strlen($slotInfo[$s]); $i++) | |
905 | { | |
906 | $tmp .= '<br>' . mb_substr($slotInfo[$s], $i, 1); | |
907 | } | |
be28528c M |
908 | $slotInfo[$s] = $tmp; |
909 | } | |
910 | echo mkA ($slotInfo[$s], 'object', $slotData[$s]); | |
911 | echo '</div></td>'; | |
84feb87b | 912 | } |
84feb87b AD |
913 | } |
914 | else | |
915 | echo "<td class='state_F'><div title=\"Free slot\"> </div></td>"; | |
916 | } | |
917 | echo '</tr>'; | |
918 | } | |
919 | echo '</table>'; | |
920 | } | |
921 | } | |
922 | } | |
0a7feebb AD |
923 | } |
924 | ||
e673ee24 | 925 | // This function renders rack as HTML table. |
7e1db771 | 926 | function renderRack ($rack_id, $hl_obj_id = 0) |
e673ee24 | 927 | { |
61a1d996 DO |
928 | $rackData = spotEntity ('rack', $rack_id); |
929 | amplifyCell ($rackData); | |
e673ee24 DO |
930 | markAllSpans ($rackData); |
931 | if ($hl_obj_id > 0) | |
932 | highlightObject ($rackData, $hl_obj_id); | |
736acd8d | 933 | $neighbors = getRackNeighbors ($rackData['row_id'], $rack_id); |
eda8b3ce DO |
934 | $prev_id = $neighbors['prev']; |
935 | $next_id = $neighbors['next']; | |
d48d8820 | 936 | echo "<center><table border=0><tr valign=middle>"; |
ad3e5e7e | 937 | echo '<td><h2>' . mkA ($rackData['row_name'], 'row', $rackData['row_id']) . ' :</h2></td>'; |
e673ee24 | 938 | if ($prev_id != NULL) |
ad3e5e7e DO |
939 | echo '<td>' . mkA (getImageHREF ('prev', 'previous rack'), 'rack', $prev_id) . '</td>'; |
940 | echo '<td><h2>' . mkA ($rackData['name'], 'rack', $rackData['id']) . '</h2></td>'; | |
e673ee24 | 941 | if ($next_id != NULL) |
ad3e5e7e | 942 | echo '<td>' . mkA (getImageHREF ('next', 'next rack'), 'rack', $next_id) . '</td>'; |
d48d8820 | 943 | echo "</h2></td></tr></table>\n"; |
e673ee24 | 944 | echo "<table class=rack border=0 cellspacing=0 cellpadding=1>\n"; |
d08147d6 DO |
945 | echo "<tr><th width='10%'> </th><th width='20%'>Front</th>"; |
946 | echo "<th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n"; | |
e673ee24 DO |
947 | for ($i = $rackData['height']; $i > 0; $i--) |
948 | { | |
4dcd770e | 949 | echo "<tr><th>" . inverseRackUnit ($i, $rackData) . "</th>"; |
e673ee24 DO |
950 | for ($locidx = 0; $locidx < 3; $locidx++) |
951 | { | |
952 | if (isset ($rackData[$i][$locidx]['skipped'])) | |
953 | continue; | |
954 | $state = $rackData[$i][$locidx]['state']; | |
65e557dd | 955 | echo "<td class='atom state_${state}"; |
e673ee24 DO |
956 | if (isset ($rackData[$i][$locidx]['hl'])) |
957 | echo $rackData[$i][$locidx]['hl']; | |
65e557dd | 958 | echo "'"; |
e673ee24 DO |
959 | if (isset ($rackData[$i][$locidx]['colspan'])) |
960 | echo ' colspan=' . $rackData[$i][$locidx]['colspan']; | |
961 | if (isset ($rackData[$i][$locidx]['rowspan'])) | |
962 | echo ' rowspan=' . $rackData[$i][$locidx]['rowspan']; | |
963 | echo ">"; | |
964 | switch ($state) | |
965 | { | |
966 | case 'T': | |
84feb87b | 967 | printObjectDetailsForRenderRack ($rackData[$i][$locidx]['object_id'], $hl_obj_id); |
e673ee24 DO |
968 | break; |
969 | case 'A': | |
970 | echo '<div title="This rackspace does not exist"> </div>'; | |
971 | break; | |
972 | case 'F': | |
973 | echo '<div title="Free rackspace"> </div>'; | |
974 | break; | |
975 | case 'U': | |
976 | echo '<div title="Problematic rackspace, you CAN\'T mount here"> </div>'; | |
977 | break; | |
978 | default: | |
979 | echo '<div title="No data"> </div>'; | |
980 | break; | |
981 | } | |
982 | echo '</td>'; | |
983 | } | |
984 | echo "</tr>\n"; | |
985 | } | |
0a7feebb AD |
986 | echo "</table>\n"; |
987 | // Get a list of all of objects Zero-U mounted to this rack | |
c17a36f0 AA |
988 | $zeroUObjects = getChildren ($rackData, 'object'); |
989 | uasort ($zeroUObjects, 'compare_name'); | |
a20a4e3c DO |
990 | if (count ($zeroUObjects) > 0) |
991 | { | |
0a7feebb AD |
992 | echo "<br><table width='75%' class=rack border=0 cellspacing=0 cellpadding=1>\n"; |
993 | echo "<tr><th>Zero-U:</th></tr>\n"; | |
994 | foreach ($zeroUObjects as $zeroUObject) | |
995 | { | |
c17a36f0 | 996 | $state = ($zeroUObject['id'] == $hl_obj_id) ? 'Th' : 'T'; |
a2037cdd DO |
997 | if ($zeroUObject['has_problems'] == 'yes') |
998 | $state .= 'w'; | |
0a7feebb | 999 | echo "<tr><td class='atom state_${state}'>"; |
c17a36f0 | 1000 | printObjectDetailsForRenderRack($zeroUObject['id']); |
0a7feebb AD |
1001 | echo "</td></tr>\n"; |
1002 | } | |
1003 | echo "</table>\n"; | |
1004 | } | |
1005 | echo "</center>\n"; | |
e673ee24 DO |
1006 | } |
1007 | ||
d10401bf | 1008 | function renderRackSortForm ($row_id) |
42504426 | 1009 | { |
b090b2da RQ |
1010 | includeJQueryUI (false); |
1011 | $js = <<<JSTXT | |
1012 | $(document).ready( | |
1013 | function () { | |
1014 | $("#sortRacks").sortable({ | |
1015 | update : function () { | |
1016 | serial = $('#sortRacks').sortable('serialize'); | |
1017 | $.ajax({ | |
824886b2 | 1018 | url: 'index.php?module=ajax&ac=upd-rack-sort-order&row_id=${row_id}', |
b090b2da RQ |
1019 | type: 'post', |
1020 | data: serial, | |
1021 | }); | |
1022 | } | |
1023 | }); | |
1024 | } | |
42504426 | 1025 | ); |
b090b2da RQ |
1026 | JSTXT; |
1027 | addJS($js, true); | |
42504426 AD |
1028 | |
1029 | startPortlet ('Racks'); | |
1030 | echo "<table border=0 cellspacing=0 cellpadding=5 align=center class=widetable>\n"; | |
1031 | echo "<tr><th>Drag to change order</th></tr>\n"; | |
1032 | echo "<tr><td><ul class='uflist' id='sortRacks'>\n"; | |
1033 | foreach (getRacks($row_id) as $rack_id => $rackInfo) | |
1034 | echo "<li id=racks_${rack_id}>${rackInfo['name']}</li>\n"; | |
1035 | echo "</ul></td></tr></table>\n"; | |
1036 | finishPortlet(); | |
1037 | } | |
1038 | ||
78ba6f56 | 1039 | function renderNewRackForm() |
e673ee24 | 1040 | { |
9b8174d7 AD |
1041 | $default_height = getConfigVar ('DEFAULT_RACK_HEIGHT'); |
1042 | if ($default_height == 0) | |
1043 | $default_height = ''; | |
50b4ba85 | 1044 | startPortlet ('Add one'); |
6b552311 | 1045 | printOpFormIntro ('addRack', array ('mode' => 'one')); |
e673ee24 | 1046 | echo '<table border=0 align=center>'; |
04c61e7e AB |
1047 | echo "<tr><th class=tdright>Name (required):</th><td class=tdleft><input type=text name=name></td>"; |
1048 | echo "<tr><th class=tdright>Height in units (required):</th><td class=tdleft><input type=text name=height1 value='${default_height}'></td></tr>\n"; | |
1049 | echo "<tr><th class=tdright>Asset tag:</th><td class=tdleft><input type=text name=asset_no></td></tr>\n"; | |
1050 | echo "<tr><th class=tdright>Tags:</td><td class=tdleft>"; | |
e7b84015 | 1051 | printTagsPicker (); |
72d52730 | 1052 | echo "</td></tr>\n"; |
f19c75d6 DO |
1053 | echo "<tr><td class=submit colspan=2>"; |
1054 | printImageHREF ('CREATE', 'Add', TRUE); | |
1055 | echo "</td></tr></table></form>"; | |
406b54bd | 1056 | finishPortlet(); |
406b54bd | 1057 | |
50b4ba85 | 1058 | startPortlet ('Add many'); |
6b552311 | 1059 | printOpFormIntro ('addRack', array ('mode' => 'many')); |
50b4ba85 | 1060 | echo '<table border=0 align=center>'; |
9b8174d7 | 1061 | echo "<tr><th class=tdright>Height in units (*):</th><td class=tdleft><input type=text name=height2 value='${default_height}'></td>"; |
04c61e7e | 1062 | echo "<tr><th class=tdright>Assign tags:</td><td class=tdleft>"; |
e7b84015 | 1063 | printTagsPicker (); |
72d52730 | 1064 | echo "</td></tr>\n"; |
9b8174d7 | 1065 | 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 |
1066 | echo "<tr><td class=submit colspan=2>"; |
1067 | printImageHREF ('CREATE', 'Add', TRUE); | |
e673ee24 DO |
1068 | echo '</form></table>'; |
1069 | finishPortlet(); | |
1070 | } | |
1071 | ||
3825c4db | 1072 | function renderEditObjectForm() |
e673ee24 | 1073 | { |
42422859 | 1074 | global $pageno; |
3825c4db | 1075 | $object_id = getBypassValue(); |
fb6e2f57 | 1076 | $object = spotEntity ('object', $object_id); |
cdd3efe9 | 1077 | startPortlet (); |
43fb6eaf | 1078 | printOpFormIntro ('update'); |
cdd3efe9 AD |
1079 | |
1080 | // static attributes | |
e10f583a DO |
1081 | echo '<table border=0 cellspacing=0 cellpadding=3 align=center>'; |
1082 | echo "<tr><td> </td><th colspan=2><h2>Attributes</h2></th></tr>"; | |
3825c4db DO |
1083 | echo '<tr><td> </td><th class=tdright>Type:</th><td class=tdleft>'; |
1084 | printSelect (getObjectTypeChangeOptions ($object['id']), array ('name' => 'object_type_id'), $object['objtype_id']); | |
1085 | echo '</td></tr>'; | |
22bb04da | 1086 | // baseline info |
e10f583a | 1087 | 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 |
1088 | 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"; |
1089 | 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 |
1090 | echo "<tr><td> </td><th class=tdright>Tags:</th><td class=tdleft>"; |
1091 | printTagsPicker (); | |
1092 | echo "</td></tr>\n"; | |
0682218d | 1093 | // parent selection |
9b8174d7 | 1094 | if (objectTypeMayHaveParent ($object['objtype_id'])) |
0682218d | 1095 | { |
9563f56f | 1096 | $parents = getParents ($object, 'object'); |
af8916e9 AD |
1097 | // lookup the human-readable object type, sort by it |
1098 | foreach ($parents as $parent_id => $parent) | |
1099 | $parents[$parent_id]['object_type'] = decodeObjectType ($parent['objtype_id']); | |
1100 | $grouped_parents = groupBy ($parents, 'object_type'); | |
1101 | ksort ($grouped_parents); | |
1102 | foreach ($grouped_parents as $parents_group) | |
0682218d | 1103 | { |
9563f56f | 1104 | uasort ($parents_group, 'compare_name'); |
af8916e9 | 1105 | $label = $parents_group[key ($parents_group)]['object_type'] . (count($parents_group) > 1 ? ' containers:' : ' container:'); |
9563f56f | 1106 | foreach ($parents_group as $link_id => $parent_cell) |
8526b4cc | 1107 | { |
8526b4cc J |
1108 | echo "<tr><td> </td>"; |
1109 | echo "<th class=tdright>${label}</th><td class=tdleft>"; | |
9563f56f | 1110 | echo mkCellA ($parent_cell); |
8526b4cc J |
1111 | echo " "; |
1112 | echo getOpLink (array('op'=>'unlinkObjects', 'link_id'=>$link_id), '', 'cut', 'Unlink container'); | |
1113 | echo "</td></tr>\n"; | |
1114 | $label = ' '; | |
1115 | } | |
0682218d AD |
1116 | } |
1117 | echo "<tr><td> </td>"; | |
1118 | echo "<th class=tdright>Select container:</th><td class=tdleft>"; | |
5d4ca0f3 | 1119 | echo getPopupLink ('objlist', array(), 'findlink', 'attach', 'Select a container'); |
de55c069 | 1120 | echo "</td></tr>\n"; |
0682218d | 1121 | } |
cdd3efe9 | 1122 | // optional attributes |
a2a7f6f6 | 1123 | $i = 0; |
249c78b2 | 1124 | $values = getAttrValuesSorted ($object_id); |
2b98d5a2 | 1125 | if (count($values) > 0) |
e673ee24 | 1126 | { |
2b98d5a2 | 1127 | foreach ($values as $record) |
e673ee24 | 1128 | { |
990fce2a AA |
1129 | if (! permitted (NULL, NULL, NULL, array ( |
1130 | array ('tag' => '$attr_' . $record['id']), | |
1131 | array ('tag' => '$any_op'), | |
1132 | ))) | |
1133 | continue; | |
2b98d5a2 AD |
1134 | echo "<input type=hidden name=${i}_attr_id value=${record['id']}>"; |
1135 | echo '<tr><td>'; | |
33973968 | 1136 | if ($record['value'] != '') |
10f5133a | 1137 | echo getOpLink (array('op'=>'clearSticker', 'attr_id'=>$record['id']), '', 'clear', 'Clear value', 'need-confirmation'); |
2b98d5a2 AD |
1138 | else |
1139 | echo ' '; | |
1140 | echo '</td>'; | |
edb59cb5 DO |
1141 | echo "<th class=sticker>${record['name']}"; |
1142 | if ($record['type'] == 'date') | |
1143 | echo ' (' . datetimeFormatHint (getConfigVar ('DATETIME_FORMAT')) . ')'; | |
1144 | echo ':</th><td class=tdleft>'; | |
2b98d5a2 AD |
1145 | switch ($record['type']) |
1146 | { | |
1147 | case 'uint': | |
1148 | case 'float': | |
1149 | case 'string': | |
1150 | echo "<input type=text name=${i}_value value='${record['value']}'>"; | |
1151 | break; | |
1152 | case 'dict': | |
7fa7047a | 1153 | $chapter = readChapter ($record['chapter_id'], 'o'); |
2b98d5a2 | 1154 | $chapter[0] = '-- NOT SET --'; |
f3d274bf | 1155 | $chapter = cookOptgroups ($chapter, $object['objtype_id'], $record['key']); |
cd3775e9 | 1156 | printNiftySelect ($chapter, array ('name' => "${i}_value"), $record['key']); |
2b98d5a2 | 1157 | break; |
86ff26ae | 1158 | case 'date': |
2a943f85 | 1159 | $date_value = $record['value'] ? datetimestrFromTimestamp ($record['value']) : ''; |
86ff26ae DO |
1160 | echo "<input type=text name=${i}_value value='${date_value}'>"; |
1161 | break; | |
2b98d5a2 AD |
1162 | } |
1163 | echo "</td></tr>\n"; | |
1164 | $i++; | |
e673ee24 | 1165 | } |
e673ee24 | 1166 | } |
a2a7f6f6 | 1167 | echo '<input type=hidden name=num_attrs value=' . $i . ">\n"; |
e10f583a DO |
1168 | echo "<tr><td> </td><th class=tdright>Has problems:</th><td class=tdleft><input type=checkbox name=object_has_problems"; |
1169 | if ($object['has_problems'] == 'yes') | |
1170 | echo ' checked'; | |
1171 | echo "></td></tr>\n"; | |
dec748f6 | 1172 | echo "<tr><td> </td><th class=tdright>Actions:</th><td class=tdleft>"; |
10f5133a | 1173 | echo getOpLink (array ('op'=>'deleteObject', 'page'=>'depot', 'tab'=>'addmore', 'object_id'=>$object_id), '' ,'destroy', 'Delete object', 'need-confirmation'); |
abd1e9ac | 1174 | echo " "; |
10f5133a | 1175 | echo getOpLink (array ('op'=>'resetObject'), '' ,'clear', 'Reset (cleanup) object', 'need-confirmation'); |
abd1e9ac | 1176 | echo "</td></tr>\n"; |
e10f583a | 1177 | echo "<tr><td colspan=3><b>Comment:</b><br><textarea name=object_comment rows=10 cols=80>${object['comment']}</textarea></td></tr>"; |
cdd3efe9 | 1178 | |
e10f583a | 1179 | echo "<tr><th class=submit colspan=3>"; |
5bbbeaa2 | 1180 | printImageHREF ('SAVE', 'Save changes', TRUE); |
cdd3efe9 | 1181 | echo "</form></th></tr></table>\n"; |
e673ee24 | 1182 | finishPortlet(); |
e673ee24 | 1183 | |
cdd3efe9 | 1184 | echo '<table border=0 width=100%><tr><td>'; |
e673ee24 | 1185 | startPortlet ('history'); |
9b8174d7 | 1186 | renderObjectHistory ($object_id); |
e673ee24 | 1187 | finishPortlet(); |
cdd3efe9 | 1188 | echo '</td></tr></table>'; |
e673ee24 DO |
1189 | } |
1190 | ||
d10401bf | 1191 | function renderEditRackForm ($rack_id) |
e673ee24 | 1192 | { |
0c2b7c4a | 1193 | global $pageno; |
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 | 1224 | // Also skip the 'sort_order' attribute |
55eefced | 1225 | if ($record['id'] == 27 || $record['id'] == 29) |
9b8174d7 AD |
1226 | continue; |
1227 | echo "<input type=hidden name=${i}_attr_id value=${record['id']}>"; | |
1228 | echo '<tr><td>'; | |
33973968 | 1229 | if ($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']; | |
33973968 | 1316 | if ($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) |
33973968 | 1324 | if ($record['id'] != 27 && $record['id'] != 29 && $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 | ||
d10401bf | 1417 | function renderObject ($object_id) |
e673ee24 | 1418 | { |
8dc2a6c8 | 1419 | global $nextorder, $virtual_obj_types; |
fb6e2f57 | 1420 | $info = spotEntity ('object', $object_id); |
94fe6370 | 1421 | amplifyCell ($info); |
e673ee24 DO |
1422 | // Main layout starts. |
1423 | echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>"; | |
1424 | echo "<tr><td colspan=2 align=center><h1>${info['dname']}</h1></td></tr>\n"; | |
1425 | // left column with uknown number of portlets | |
1426 | echo "<tr><td class=pcleft>"; | |
646272be AA |
1427 | |
1428 | // display summary portlet | |
1429 | $summary = array(); | |
33973968 | 1430 | if ($info['name'] != '') |
646272be | 1431 | $summary['Common name'] = $info['name']; |
94fe6370 | 1432 | elseif (considerConfiguredConstraint ($info, 'NAMEWARN_LISTSRC')) |
646272be AA |
1433 | $summary[] = array ('<tr><td colspan=2 class=msg_error>Common name is missing.</td></tr>'); |
1434 | $summary['Object type'] = '<a href="' . makeHref (array ( | |
341fd895 DO |
1435 | 'page' => 'depot', |
1436 | 'tab' => 'default', | |
1437 | 'cfe' => '{$typeid_' . $info['objtype_id'] . '}' | |
eb11ba46 | 1438 | )) . '">' . decodeObjectType ($info['objtype_id']) . '</a>'; |
33973968 | 1439 | if ($info['label'] != '') |
646272be | 1440 | $summary['Visible label'] = $info['label']; |
33973968 | 1441 | if ($info['asset_no'] != '') |
646272be | 1442 | $summary['Asset tag'] = $info['asset_no']; |
d4e8ddeb | 1443 | elseif (considerConfiguredConstraint ($info, 'ASSETWARN_LISTSRC')) |
646272be | 1444 | $summary[] = array ('<tr><td colspan=2 class=msg_error>Asset tag is missing.</td></tr>'); |
9563f56f | 1445 | $parents = getParents ($info, 'object'); |
af8916e9 AD |
1446 | // lookup the human-readable object type, sort by it |
1447 | foreach ($parents as $parent_id => $parent) | |
1448 | $parents[$parent_id]['object_type'] = decodeObjectType ($parent['objtype_id']); | |
1449 | $grouped_parents = groupBy ($parents, 'object_type'); | |
1450 | ksort ($grouped_parents); | |
1451 | foreach ($grouped_parents as $parents_group) | |
0682218d | 1452 | { |
9563f56f | 1453 | uasort ($parents_group, 'compare_name'); |
af8916e9 | 1454 | $label = $parents_group[key ($parents_group)]['object_type'] . (count($parents_group) > 1 ? ' containers' : ' container'); |
9563f56f AA |
1455 | $fmt_parents = array(); |
1456 | foreach ($parents_group as $parent) | |
1457 | $fmt_parents[] = mkCellA ($parent); | |
af8916e9 | 1458 | $summary[$label] = implode ('<br>', $fmt_parents); |
0682218d | 1459 | } |
9563f56f AA |
1460 | $children = getChildren ($info, 'object'); |
1461 | foreach (groupBy ($children, 'objtype_id') as $objtype_id => $children_group) | |
42fb3aa2 | 1462 | { |
9563f56f AA |
1463 | uasort ($children_group, 'compare_name'); |
1464 | $fmt_children = array(); | |
1465 | foreach ($children_group as $child) | |
1466 | $fmt_children[] = mkCellA ($child); | |
1467 | $summary["Contains " . strtolower(decodeObjectType ($objtype_id))] = implode ('<br>', $fmt_children); | |
42fb3aa2 | 1468 | } |
e673ee24 | 1469 | if ($info['has_problems'] == 'yes') |
646272be | 1470 | $summary[] = array ('<tr><td colspan=2 class=msg_error>Has problems</td></tr>'); |
249c78b2 | 1471 | foreach (getAttrValuesSorted ($object_id) as $record) |
4969aa31 DO |
1472 | if |
1473 | ( | |
55eefced | 1474 | $record['value'] != '' && |
4969aa31 DO |
1475 | permitted (NULL, NULL, NULL, array (array ('tag' => '$attr_' . $record['id']))) |
1476 | ) | |
646272be | 1477 | $summary['{sticker}' . $record['name']] = formatAttributeValue ($record); |
a2c597ea AA |
1478 | $summary[] = array (getOutputOf ('printTagTRs', |
1479 | $info, | |
1480 | makeHref | |
1481 | ( | |
1482 | array | |
1483 | ( | |
1484 | 'page'=>'depot', | |
1485 | 'tab'=>'default', | |
1486 | 'andor' => 'and', | |
1487 | 'cfe' => '{$typeid_' . $info['objtype_id'] . '}', | |
1488 | ) | |
1489 | )."&" | |
1490 | )); | |
0b09238d | 1491 | renderEntitySummary ($info, 'summary', $summary); |
e673ee24 | 1492 | |
33973968 | 1493 | if ($info['comment'] != '') |
e673ee24 DO |
1494 | { |
1495 | startPortlet ('Comment'); | |
6cc5d6cd | 1496 | echo '<div class=commentblock>' . string_insert_hrefs ($info['comment']) . '</div>'; |
e673ee24 DO |
1497 | finishPortlet (); |
1498 | } | |
1499 | ||
b5700329 AA |
1500 | $logrecords = getLogRecordsForObject ($_REQUEST['object_id']); |
1501 | if (count ($logrecords)) | |
9a90adc4 DO |
1502 | { |
1503 | startPortlet ('log records'); | |
1504 | echo "<table cellspacing=0 cellpadding=5 align=center class=widetable width='100%'>"; | |
1505 | $order = 'odd'; | |
b5700329 | 1506 | foreach ($logrecords as $row) |
9a90adc4 DO |
1507 | { |
1508 | echo "<tr class=row_${order} valign=top>"; | |
1509 | echo '<td class=tdleft>' . $row['date'] . '<br>' . $row['user'] . '</td>'; | |
0b8d8309 | 1510 | echo '<td class="logentry">' . string_insert_hrefs (htmlspecialchars ($row['content'], ENT_NOQUOTES)) . '</td>'; |
9a90adc4 DO |
1511 | echo '</tr>'; |
1512 | $order = $nextorder[$order]; | |
1513 | } | |
1514 | echo '</table>'; | |
1515 | finishPortlet(); | |
1516 | } | |
1517 | ||
65e557dd | 1518 | switchportInfoJS ($object_id); // load JS code to make portnames interactive |
e1ae3fb4 AD |
1519 | renderFilesPortlet ('object', $object_id); |
1520 | ||
9f75e165 | 1521 | if (count ($info['ports'])) |
e673ee24 | 1522 | { |
0b09238d | 1523 | startPortlet ('ports and links'); |
9f75e165 DO |
1524 | $hl_port_id = 0; |
1525 | if (isset ($_REQUEST['hl_port_id'])) | |
e673ee24 | 1526 | { |
0cc24e9a | 1527 | assertUIntArg ('hl_port_id'); |
9f75e165 | 1528 | $hl_port_id = $_REQUEST['hl_port_id']; |
65e557dd | 1529 | addAutoScrollScript ("port-$hl_port_id"); |
9f75e165 | 1530 | } |
0b09238d | 1531 | echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>"; |
9f75e165 | 1532 | echo '<tr><th class=tdleft>Local name</th><th class=tdleft>Visible label</th>'; |
0d59a51c | 1533 | echo '<th class=tdleft>Interface</th><th class=tdleft>L2 address</th>'; |
0c7c9f8b | 1534 | echo '<th class=tdcenter colspan=2>Remote object and port</th>'; |
0b09238d | 1535 | echo '<th class=tdleft>Cable ID</th></tr>'; |
9f75e165 | 1536 | foreach ($info['ports'] as $port) |
40c9fc94 | 1537 | callHook ('renderObjectPortRow', $port, ($hl_port_id == $port['id'])); |
fd5edda8 | 1538 | if (permitted (NULL, 'ports', 'set_reserve_comment')) |
a8dc2982 | 1539 | addJS ('js/inplace-edit.js'); |
9f75e165 | 1540 | echo "</table><br>"; |
e673ee24 DO |
1541 | finishPortlet(); |
1542 | } | |
85970da2 | 1543 | |
21ee3351 | 1544 | if (count ($info['ipv4']) + count ($info['ipv6'])) |
e673ee24 | 1545 | { |
21ee3351 | 1546 | startPortlet ('IP addresses'); |
e673ee24 | 1547 | echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n"; |
f0ed1181 | 1548 | if (getConfigVar ('EXT_IPV4_VIEW') == 'yes') |
9d5f6a80 | 1549 | 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 | 1550 | else |
9d5f6a80 | 1551 | echo "<tr class=tdleft><th>OS interface</th><th>IP address</th><th>peers</th></tr>\n"; |
21ee3351 AA |
1552 | |
1553 | // group IP allocations by interface name instead of address family | |
1554 | $allocs_by_iface = array(); | |
1555 | foreach (array ('ipv4', 'ipv6') as $ip_v) | |
4318ced5 AA |
1556 | foreach ($info[$ip_v] as $ip_bin => $alloc) |
1557 | $allocs_by_iface[$alloc['osif']][$ip_bin] = $alloc; | |
dec748f6 | 1558 | |
21ee3351 AA |
1559 | // sort allocs array by portnames |
1560 | foreach (sortPortList ($allocs_by_iface) as $iface_name => $alloclist) | |
1561 | { | |
1562 | $is_first_row = TRUE; | |
f3505b35 | 1563 | foreach ($alloclist as $alloc) |
b90c3907 | 1564 | { |
40c9fc94 | 1565 | $rendered_alloc = callHook ('getRenderedAlloc', $object_id, $alloc); |
f3505b35 | 1566 | echo "<tr class='${rendered_alloc['tr_class']}' valign=top>"; |
21ee3351 | 1567 | |
f3505b35 | 1568 | // display iface name, same values are grouped into single cell |
21ee3351 AA |
1569 | if ($is_first_row) |
1570 | { | |
1571 | $rowspan = count ($alloclist) > 1 ? 'rowspan="' . count ($alloclist) . '"' : ''; | |
40c9fc94 | 1572 | echo "<td class=tdleft $rowspan>" . $iface_name . $rendered_alloc['td_name_suffix'] . "</td>"; |
21ee3351 AA |
1573 | $is_first_row = FALSE; |
1574 | } | |
f3505b35 | 1575 | echo $rendered_alloc['td_ip']; |
21ee3351 | 1576 | if (getConfigVar ('EXT_IPV4_VIEW') == 'yes') |
83fdf85f | 1577 | { |
f3505b35 AA |
1578 | echo $rendered_alloc['td_network']; |
1579 | echo $rendered_alloc['td_routed_by']; | |
21ee3351 | 1580 | } |
f3505b35 AA |
1581 | echo $rendered_alloc['td_peers']; |
1582 | ||
1583 | echo "</tr>\n"; | |
b90c3907 | 1584 | } |
e673ee24 DO |
1585 | } |
1586 | echo "</table><br>\n"; | |
1587 | finishPortlet(); | |
1588 | } | |
1589 | ||
94fe6370 | 1590 | $forwards = $info['nat4']; |
55eefced | 1591 | if (count ($forwards['in']) || count ($forwards['out'])) |
e673ee24 | 1592 | { |
f28fbe8b | 1593 | startPortlet('NATv4'); |
e673ee24 DO |
1594 | |
1595 | if (count($forwards['out'])) | |
1596 | { | |
1597 | ||
f28fbe8b | 1598 | echo "<h3>locally performed NAT</h3>"; |
e673ee24 | 1599 | |
105a3bc8 | 1600 | echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n"; |
f28fbe8b | 1601 | 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 |
1602 | |
1603 | foreach ($forwards['out'] as $pf) | |
1604 | { | |
2c817354 DO |
1605 | $class = 'trerror'; |
1606 | $osif = ''; | |
6a3c2dc5 AA |
1607 | $localip_bin = ip_parse ($pf['localip']); |
1608 | if (array_key_exists ($localip_bin, $info['ipv4'])) | |
2c817354 | 1609 | { |
6a3c2dc5 AA |
1610 | $class = $info['ipv4'][$localip_bin]['addrinfo']['class']; |
1611 | $osif = $info['ipv4'][$localip_bin]['osif'] . ': '; | |
2c817354 | 1612 | } |
e673ee24 | 1613 | echo "<tr class='$class'>"; |
7419401e AA |
1614 | echo "<td>${pf['proto']}</td><td class=tdleft>${osif}" . getRenderedIPPortPair ($pf['localip'], $pf['localport']) . "</td>"; |
1615 | echo "<td class=tdleft>" . getRenderedIPPortPair ($pf['remoteip'], $pf['remoteport']) . "</td>"; | |
4318ced5 | 1616 | $address = getIPAddress (ip4_parse ($pf['remoteip'])); |
e673ee24 | 1617 | echo "<td class='description'>"; |
53ef3908 DO |
1618 | if (count ($address['allocs'])) |
1619 | foreach($address['allocs'] as $bond) | |
ad3e5e7e | 1620 | echo mkA ("${bond['object_name']}(${bond['name']})", 'object', $bond['object_id']) . ' '; |
33973968 | 1621 | elseif ($pf['remote_addr_name'] != '') |
f28fbe8b | 1622 | echo '(' . $pf['remote_addr_name'] . ')'; |
53ef3908 | 1623 | echo "</td><td class='description'>${pf['description']}</td></tr>"; |
e673ee24 DO |
1624 | } |
1625 | echo "</table><br><br>"; | |
1626 | } | |
1627 | if (count($forwards['in'])) | |
1628 | { | |
f28fbe8b | 1629 | echo "<h3>arriving NAT connections</h3>"; |
105a3bc8 | 1630 | echo "<table class='widetable' cellpadding=5 cellspacing=0 border=0 align='center'>\n"; |
f28fbe8b | 1631 | echo "<tr><th>Matched endpoint</th><th>Source object</th><th>Translated to</th><th>Rule comment</th></tr>\n"; |
e673ee24 DO |
1632 | foreach ($forwards['in'] as $pf) |
1633 | { | |
1634 | echo "<tr>"; | |
7419401e | 1635 | echo "<td>${pf['proto']}/" . getRenderedIPPortPair ($pf['localip'], $pf['localport']) . "</td>"; |
ad3e5e7e | 1636 | echo '<td class="description">' . mkA ($pf['object_name'], 'object', $pf['object_id']); |
7419401e | 1637 | echo "</td><td>" . getRenderedIPPortPair ($pf['remoteip'], $pf['remoteport']) . "</td>"; |
e673ee24 DO |
1638 | echo "<td class='description'>${pf['description']}</td></tr>"; |
1639 | } | |
e673ee24 DO |
1640 | echo "</table><br><br>"; |
1641 | } | |
1642 | finishPortlet(); | |
1643 | } | |
1644 | ||
eacc0983 | 1645 | renderSLBTriplets2 ($info); |
defd92d8 | 1646 | renderSLBTriplets ($info); |
e673ee24 DO |
1647 | echo "</td>\n"; |
1648 | ||
7056988c | 1649 | // After left column we have (surprise!) right column with rackspace portlet only. |
e673ee24 | 1650 | echo "<td class=pcright>"; |
8dc2a6c8 | 1651 | if (!in_array($info['objtype_id'], $virtual_obj_types)) |
0682218d AD |
1652 | { |
1653 | // rackspace portlet | |
1654 | startPortlet ('rackspace allocation'); | |
1655 | foreach (getResidentRacksData ($object_id, FALSE) as $rack_id) | |
1656 | renderRack ($rack_id, $object_id); | |
1657 | echo '<br>'; | |
1658 | finishPortlet(); | |
1659 | } | |
e673ee24 DO |
1660 | echo "</td></tr>"; |
1661 | echo "</table>\n"; | |
1662 | } | |
1663 | ||
1664 | function renderRackMultiSelect ($sname, $racks, $selected) | |
1665 | { | |
04571888 DO |
1666 | // Transform the given flat list into a list of groups, each representing a rack row. |
1667 | $rdata = array(); | |
e673ee24 | 1668 | foreach ($racks as $rack) |
d016010a | 1669 | { |
b956dd24 | 1670 | if ('' != $trail = getLocationTrail ($rack['location_id'], FALSE)) |
7b6ae79a AD |
1671 | $row_name = $trail . ' : ' . $rack['row_name']; |
1672 | else | |
1673 | $row_name = $rack['row_name']; | |
d016010a AD |
1674 | $rdata[$row_name][$rack['id']] = $rack['name']; |
1675 | } | |
4fbb5a00 | 1676 | echo "<select name=${sname} multiple size=" . getConfigVar ('MAXSELSIZE') . " onchange='getElementsByName(\"updateObjectAllocation\")[0].submit()'>\n"; |
acfc0d89 AA |
1677 | $row_names = array_keys ($rdata); |
1678 | natsort ($row_names); | |
1679 | foreach ($row_names as $optgroup) | |
e673ee24 | 1680 | { |
04571888 | 1681 | echo "<optgroup label='${optgroup}'>"; |
acfc0d89 | 1682 | foreach ($rdata[$optgroup] as $rack_id => $rack_name) |
04571888 DO |
1683 | { |
1684 | echo "<option value=${rack_id}"; | |
1685 | if (!(array_search ($rack_id, $selected) === FALSE)) | |
1686 | echo ' selected'; | |
1687 | echo">${rack_name}</option>\n"; | |
1688 | } | |
e673ee24 DO |
1689 | } |
1690 | echo "</select>\n"; | |
1691 | } | |
1692 | ||
e673ee24 | 1693 | // This function renders a form for port edition. |
d10401bf | 1694 | function renderPortsForObject ($object_id) |
e673ee24 | 1695 | { |
3153a326 DO |
1696 | $prefs = getPortListPrefs(); |
1697 | function printNewItemTR ($prefs) | |
39b4abd0 DO |
1698 | { |
1699 | printOpFormIntro ('addPort'); | |
1700 | echo "<tr><td>"; | |
f5ff50f5 | 1701 | printImageHREF ('add', 'add a port', TRUE); |
7b30e187 | 1702 | echo "</td><td class='tdleft'><input type=text size=16 name=port_name></td>\n"; |
04c61e7e | 1703 | echo "<td><input type=text name=port_label></td><td>"; |
759b21d2 | 1704 | printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type_id'), $prefs['selected']); |
04c61e7e | 1705 | echo "<td><input type=text name=port_l2address size=18 maxlength=24></td>\n"; |
318c48a8 | 1706 | echo "<td colspan=4> </td><td>"; |
04c61e7e | 1707 | printImageHREF ('add', 'add a port', TRUE); |
9318d2ef | 1708 | echo "</td></tr></form>"; |
39b4abd0 | 1709 | } |
a1fc539a | 1710 | if (getConfigVar('ENABLE_MULTIPORT_FORM') == 'yes' || getConfigVar('ENABLE_BULKPORT_FORM') == 'yes' ) |
f44fdef9 DO |
1711 | startPortlet ('Ports and interfaces'); |
1712 | else | |
1713 | echo '<br>'; | |
d10401bf | 1714 | $object = spotEntity ('object', $object_id); |
9f75e165 | 1715 | amplifyCell ($object); |
a1fc539a RF |
1716 | if (getConfigVar ('ADDNEW_AT_TOP') == 'yes' && getConfigVar('ENABLE_BULKPORT_FORM') == 'yes'){ |
1717 | echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n"; | |
1718 | 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>"; | |
1719 | echo "<th class=tdleft>Count</th><th> </th></tr>\n"; | |
1720 | printOpFormIntro ('addBulkPorts'); | |
1721 | echo "<tr><td>"; | |
1722 | printImageHREF ('add', 'add ports', TRUE); | |
04c61e7e AB |
1723 | echo "</td><td><input type=text size=8 name=port_name></td>\n"; |
1724 | echo "<td><input type=text name=port_label></td><td>"; | |
759b21d2 | 1725 | printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type_id'), $prefs['selected']); |
04c61e7e AB |
1726 | echo "<td><input type=text name=port_numbering_start size=3 maxlength=3></td>\n"; |
1727 | echo "<td><input type=text name=port_numbering_count size=3 maxlength=3></td>\n"; | |
0b09238d | 1728 | echo "<td> </td><td>"; |
04c61e7e | 1729 | printImageHREF ('add', 'add ports', TRUE); |
a1fc539a RF |
1730 | echo "</td></tr></form>"; |
1731 | echo "</table><br>\n"; | |
1732 | } | |
dec748f6 | 1733 | |
0b09238d | 1734 | echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n"; |
0d59a51c | 1735 | 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 | 1736 | 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 | 1737 | if (getConfigVar ('ADDNEW_AT_TOP') == 'yes') |
3153a326 | 1738 | printNewItemTR ($prefs); |
45ff9012 | 1739 | |
0b09238d DO |
1740 | // clear ports link |
1741 | echo getOpLink (array ('op'=>'deleteAll'), 'Clear port list', 'clear', '', 'need-confirmation'); | |
1742 | ||
8579b51b AA |
1743 | // rename ports link |
1744 | $n_ports_to_rename = 0; | |
1745 | foreach ($object['ports'] as $port) | |
1746 | if ($port['name'] != shortenPortName ($port['name'], $object['id'])) | |
1747 | $n_ports_to_rename++; | |
1748 | if ($n_ports_to_rename) | |
bd2dcd32 | 1749 | echo '<p>' . getOpLink (array ('op'=>'renameAll'), "Auto-rename $n_ports_to_rename port(s)", 'recalc', 'Use RackTables naming convention for this device type') . '</p>'; |
8579b51b | 1750 | |
00276508 AA |
1751 | if (isset ($_REQUEST['hl_port_id'])) |
1752 | { | |
1753 | assertUIntArg ('hl_port_id'); | |
1754 | $hl_port_id = intval ($_REQUEST['hl_port_id']); | |
65e557dd | 1755 | addAutoScrollScript ("port-$hl_port_id"); |
00276508 | 1756 | } |
d10401bf | 1757 | switchportInfoJS ($object_id); // load JS code to make portnames interactive |
9f75e165 | 1758 | foreach ($object['ports'] as $port) |
e673ee24 | 1759 | { |
8579b51b AA |
1760 | // highlight port name with yellow if it's name is not canonical |
1761 | $canon_pn = shortenPortName ($port['name'], $port['object_id']); | |
1762 | $name_class = $canon_pn == $port['name'] ? '' : 'trwarning'; | |
1763 | ||
5c717ce5 | 1764 | $tr_class = isset ($hl_port_id) && $hl_port_id == $port['id'] ? 'class="highlight"' : ''; |
7056988c | 1765 | printOpFormIntro ('editPort', array ('port_id' => $port['id'])); |
d0d40671 | 1766 | echo "<tr $tr_class><td><a name='port-${port['id']}' href='".makeHrefProcess(array('op'=>'delPort', 'port_id'=>$port['id']))."'>"; |
e673ee24 DO |
1767 | printImageHREF ('delete', 'Unlink and Delete this port'); |
1768 | echo "</a></td>\n"; | |
65e557dd | 1769 | $a_class = isEthernetPort ($port) ? 'port-menu' : ''; |
7b30e187 | 1770 | echo "<td class='tdleft $name_class' NOWRAP><input type=text name=name class='interactive-portname $a_class' value='${port['name']}' size=16></td>"; |
cd3775e9 | 1771 | echo "<td><input type=text name=label value='${port['label']}'></td>"; |
8e021b86 AA |
1772 | echo '<td>'; |
1773 | if ($port['iif_id'] != 1) | |
1774 | echo '<label>' . $port['iif_name'] . ' '; | |
4f968fa8 | 1775 | $port_type_opts = array(); |
78b59ab3 | 1776 | if (! $port['linked']) |
759b21d2 | 1777 | $port_type_opts = getUnlinkedPortTypeOptions ($port['iif_id']); |
78b59ab3 | 1778 | else |
4f968fa8 AA |
1779 | foreach (getExistingPortTypeOptions ($port) as $oif_id => $opt_str) |
1780 | $port_type_opts[$port['iif_name']][$port['iif_id'] . '-' . $oif_id] = $opt_str; | |
4f968fa8 | 1781 | printNiftySelect ($port_type_opts, array ('name' => 'port_type_id'), $port['iif_id'] . '-' . $port['oif_id']); |
8e021b86 AA |
1782 | if ($port['iif_id'] != 1) |
1783 | echo '</label>'; | |
1784 | echo '</td>'; | |
1785 | ||
cd3775e9 DO |
1786 | // 18 is enough to fit 6-byte MAC address in its longest form, |
1787 | // while 24 should be Ok for WWN | |
1788 | echo "<td><input type=text name=l2address value='${port['l2address']}' size=18 maxlength=24></td>\n"; | |
0b09238d | 1789 | if ($port['remote_object_id']) |
90bf1755 | 1790 | { |
0b09238d DO |
1791 | echo "<td>" . |
1792 | formatLoggedSpan ($port['last_log'], formatPortLink ($port['remote_object_id'], $port['remote_object_name'], $port['remote_id'], NULL)) . | |
1793 | "</td>"; | |
1794 | echo "<td> " . formatLoggedSpan ($port['last_log'], $port['remote_name'], 'underline') . | |
1795 | "<input type=hidden name=reservation_comment value=''></td>"; | |
1796 | echo "<td><input type=text name=cable value='${port['cableid']}'></td>"; | |
1797 | echo "<td class=tdcenter>"; | |
1798 | echo getOpLink (array('op'=>'unlinkPort', 'port_id'=>$port['id'], ), '', 'cut', 'Unlink this port'); | |
1799 | echo "</td>"; | |
e673ee24 | 1800 | } |
33973968 | 1801 | elseif ($port['reservation_comment'] != '') |
e673ee24 | 1802 | { |
0b09238d | 1803 | echo "<td>" . formatLoggedSpan ($port['last_log'], 'Reserved:', 'strong underline') . "</td>"; |
e673ee24 | 1804 | echo "<td><input type=text name=reservation_comment value='${port['reservation_comment']}'></td>"; |
318c48a8 | 1805 | echo "<td></td>"; |
10f5133a AA |
1806 | echo "<td class=tdcenter>"; |
1807 | echo getOpLink (array('op'=>'useup', 'port_id'=>$port['id']), '', 'clear', 'Use up this port'); | |
1808 | echo "</td>"; | |
e673ee24 DO |
1809 | } |
1810 | else | |
1811 | { | |
6b1ca530 | 1812 | $in_rack = getConfigVar ('NEAREST_RACKS_CHECKBOX'); |
de55c069 AA |
1813 | echo "<td> </td><td> </td><td> </td><td class=tdcenter>"; |
1814 | echo getPopupLink ('portlist', array ('port' => $port['id'], 'in_rack' => ($in_rack == "yes" ? "on" : "")), 'findlink', 'plug', '', 'Link this port'); | |
0b09238d | 1815 | echo " <input type=text name=reservation_comment></td>\n"; |
90bf1755 | 1816 | } |
0b09238d DO |
1817 | echo "<td>"; |
1818 | printImageHREF ('save', 'Save changes', TRUE); | |
1819 | echo "</td></form></tr>\n"; | |
e673ee24 | 1820 | } |
39b4abd0 | 1821 | if (getConfigVar ('ADDNEW_AT_TOP') != 'yes') |
3153a326 | 1822 | printNewItemTR ($prefs); |
e673ee24 | 1823 | echo "</table><br>\n"; |
a1fc539a RF |
1824 | if (getConfigVar ('ADDNEW_AT_TOP') != 'yes' && getConfigVar('ENABLE_BULKPORT_FORM') == 'yes'){ |
1825 | echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'>\n"; | |
1826 | 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>"; | |
1827 | echo "<th class=tdleft>Count</th><th> </th></tr>\n"; | |
dec748f6 | 1828 | printOpFormIntro ('addBulkPorts'); |
a1fc539a RF |
1829 | echo "<tr><td>"; |
1830 | printImageHREF ('add', 'add ports', TRUE); | |
04c61e7e AB |
1831 | echo "</td><td><input type=text size=8 name=port_name></td>\n"; |
1832 | echo "<td><input type=text name=port_label></td><td>"; | |
759b21d2 | 1833 | printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type_id'), $prefs['selected']); |
04c61e7e AB |
1834 | echo "<td><input type=text name=port_numbering_start size=3 maxlength=3></td>\n"; |
1835 | echo "<td><input type=text name=port_numbering_count size=3 maxlength=3></td>\n"; | |
a1fc539a | 1836 | echo "<td> </td><td>"; |
04c61e7e | 1837 | printImageHREF ('add', 'add ports', TRUE); |
a1fc539a RF |
1838 | echo "</td></tr></form>"; |
1839 | echo "</table><br>\n"; | |
1840 | } | |
90bf1755 DO |
1841 | if (getConfigVar('ENABLE_MULTIPORT_FORM') == 'yes') |
1842 | finishPortlet(); | |
f44fdef9 DO |
1843 | if (getConfigVar('ENABLE_MULTIPORT_FORM') != 'yes') |
1844 | return; | |
e673ee24 DO |
1845 | |
1846 | startPortlet ('Add/update multiple ports'); | |
7056988c | 1847 | printOpFormIntro ('addMultiPorts'); |
8331b4e4 DO |
1848 | $formats = array |
1849 | ( | |
1850 | 'c3600asy' => 'Cisco 3600 async: sh line | inc TTY', | |
1851 | 'fiwg' => 'Foundry ServerIron/FastIron WorkGroup/Edge: sh int br', | |
1852 | 'fisxii' => 'Foundry FastIron SuperX/II4000: sh int br', | |
d842dbbc | 1853 | 'ssv1' => 'SSV:<interface name> [<MAC address>]', |
8331b4e4 DO |
1854 | ); |
1855 | echo 'Format: ' . getSelect ($formats, array ('name' => 'format'), 'ssv1'); | |
e673ee24 | 1856 | echo 'Default port type: '; |
759b21d2 | 1857 | printNiftySelect (getNewPortTypeOptions(), array ('name' => 'port_type'), $prefs['selected']); |
04c61e7e AB |
1858 | echo "<input type=submit value='Parse output'><br>\n"; |
1859 | echo "<textarea name=input cols=100 rows=50></textarea><br>\n"; | |
e673ee24 DO |
1860 | echo '</form>'; |
1861 | finishPortlet(); | |
1862 | } | |
1863 | ||
d10401bf | 1864 | function renderIPForObject ($object_id) |
e673ee24 | 1865 | { |
4318ced5 | 1866 | function printNewItemTR ($default_type) |
21ee3351 AA |
1867 | { |
1868 | global $aat; | |
4318ced5 AA |
1869 | printOpFormIntro ('add'); |
1870 | echo "<tr><td>"; // left btn | |
dec748f6 | 1871 | printImageHREF ('add', 'allocate', TRUE); |
21ee3351 | 1872 | echo "</td>"; |
04c61e7e AB |
1873 | echo "<td class=tdleft><input type='text' size='10' name='bond_name'></td>\n"; // if-name |
1874 | echo "<td class=tdleft><input type=text name='ip'></td>\n"; // IP | |
4318ced5 AA |
1875 | if (getConfigVar ('EXT_IPV4_VIEW') == 'yes') |
1876 | echo "<td colspan=2> </td>"; // network, routed by | |
1877 | echo '<td>'; | |
04c61e7e | 1878 | printSelect ($aat, array ('name' => 'bond_type'), $default_type); // type |
4318ced5 | 1879 | echo "</td><td> </td><td>"; // misc |
04c61e7e | 1880 | printImageHREF ('add', 'allocate', TRUE); // right btn |
21ee3351 AA |
1881 | echo "</td></tr></form>"; |
1882 | } | |
21ee3351 AA |
1883 | global $aat; |
1884 | startPortlet ('Allocations'); | |
4318ced5 AA |
1885 | echo "<table cellspacing=0 cellpadding='5' align='center' class='widetable'><tr>\n"; |
1886 | echo '<th> </th>'; | |
1887 | echo '<th>OS interface</th>'; | |
1888 | echo '<th>IP address</th>'; | |
21ee3351 | 1889 | if (getConfigVar ('EXT_IPV4_VIEW') == 'yes') |
4318ced5 AA |
1890 | { |
1891 | echo '<th>network</th>'; | |
1892 | echo '<th>routed by</th>'; | |
1893 | } | |
1894 | echo '<th>type</th>'; | |
1895 | echo '<th>misc</th>'; | |
b1b07891 | 1896 | echo '<th> </th>'; |
4318ced5 | 1897 | echo '</tr>'; |
21ee3351 | 1898 | |
710ead7e AA |
1899 | $alloc_list = ''; // most of the output is stored here |
1900 | $used_alloc_types = array(); | |
4318ced5 | 1901 | foreach (getObjectIPAllocations ($object_id) as $alloc) |
21ee3351 | 1902 | { |
710ead7e AA |
1903 | if (! isset ($used_alloc_types[$alloc['type']])) |
1904 | $used_alloc_types[$alloc['type']] = 0; | |
1905 | $used_alloc_types[$alloc['type']]++; | |
1906 | ||
40c9fc94 | 1907 | $rendered_alloc = callHook ('getRenderedAlloc', $object_id, $alloc); |
4318ced5 | 1908 | $alloc_list .= getOutputOf ('printOpFormIntro', 'upd', array ('ip' => $alloc['addrinfo']['ip'])); |
710ead7e | 1909 | $alloc_list .= "<tr class='${rendered_alloc['tr_class']}' valign=top>"; |
f3505b35 | 1910 | |
10f5133a | 1911 | $alloc_list .= "<td>" . getOpLink (array ('op' => 'del', 'ip' => $alloc['addrinfo']['ip']), '', 'delete', 'Delete this IP address') . "</td>"; |
40c9fc94 | 1912 | $alloc_list .= "<td class=tdleft><input type='text' name='bond_name' value='${alloc['osif']}' size=10>" . $rendered_alloc['td_name_suffix'] . "</td>"; |
710ead7e | 1913 | $alloc_list .= $rendered_alloc['td_ip']; |
21ee3351 AA |
1914 | if (getConfigVar ('EXT_IPV4_VIEW') == 'yes') |
1915 | { | |
710ead7e AA |
1916 | $alloc_list .= $rendered_alloc['td_network']; |
1917 | $alloc_list .= $rendered_alloc['td_routed_by']; | |
21ee3351 | 1918 | } |
710ead7e AA |
1919 | $alloc_list .= '<td>' . getSelect ($aat, array ('name' => 'bond_type'), $alloc['type']) . "</td>"; |
1920 | $alloc_list .= $rendered_alloc['td_peers']; | |
1921 | $alloc_list .= "<td>" .getImageHREF ('save', 'Save changes', TRUE) . "</td>"; | |
f3505b35 | 1922 | |
710ead7e | 1923 | $alloc_list .= "</form></tr>\n"; |
21ee3351 | 1924 | } |
710ead7e | 1925 | asort ($used_alloc_types, SORT_NUMERIC); |
589c027b | 1926 | $most_popular_type = ! count ($used_alloc_types) ? 'regular' : array_last (array_keys ($used_alloc_types)); |
710ead7e AA |
1927 | |
1928 | if ($list_on_top = (getConfigVar ('ADDNEW_AT_TOP') != 'yes')) | |
1929 | echo $alloc_list; | |
4318ced5 | 1930 | printNewItemTR ($most_popular_type); |
710ead7e AA |
1931 | if (! $list_on_top) |
1932 | echo $alloc_list; | |
21ee3351 AA |
1933 | |
1934 | echo "</table><br>\n"; | |
1935 | finishPortlet(); | |
f3505b35 AA |
1936 | } |
1937 | ||
08408472 AA |
1938 | // This function is deprecated. Do not rely on its internals, |
1939 | // it will probably be removed in the next major relese. | |
1940 | // Use new showError, showWarning, showSuccess functions. | |
dec748f6 | 1941 | // Log array is stored in global $log_messages. Its format is simple: plain ordered array |
8ab645cf | 1942 | // with values having keys 'c' (both message code and severity) and 'a' (sprintf arguments array) |
1cb6adf5 | 1943 | function showMessageOrError () |
e673ee24 | 1944 | { |
a2b16202 AA |
1945 | global $log_messages; |
1946 | ||
0a00b344 | 1947 | startSession(); |
a2b16202 AA |
1948 | if (isset ($_SESSION['log'])) |
1949 | { | |
1950 | $log_messages = array_merge ($_SESSION['log'], $log_messages); | |
1951 | unset ($_SESSION['log']); | |
1952 | } | |
1953 | session_commit(); | |
1954 | ||
1955 | if (empty ($log_messages)) | |
1cb6adf5 | 1956 | return; |
8ab645cf AA |
1957 | $msginfo = array |
1958 | ( | |
dec748f6 | 1959 | // records 0~99 with success messages |
8ab645cf AA |
1960 | 0 => array ('code' => 'success', 'format' => '%s'), |
1961 | 5 => array ('code' => 'success', 'format' => 'added record "%s" successfully'), | |
1962 | 6 => array ('code' => 'success', 'format' => 'updated record "%s" successfully'), | |
1963 | 7 => array ('code' => 'success', 'format' => 'deleted record "%s" successfully'), | |
1964 | 8 => array ('code' => 'success', 'format' => 'Port %s successfully linked with %s'), | |
493e13dd | 1965 | 10 => array ('code' => 'success', 'format' => 'Added %u port(s), updated %u port(s), encountered %u error(s).'), |
8ab645cf | 1966 | 21 => array ('code' => 'success', 'format' => 'Generation complete'), |
493e13dd DO |
1967 | 26 => array ('code' => 'success', 'format' => 'updated %u record(s) successfully'), |
1968 | 37 => array ('code' => 'success', 'format' => 'added %u record(s) successfully'), | |
1969 | 38 => array ('code' => 'success', 'format' => 'removed %u record(s) successfully'), | |
8ab645cf | 1970 | 43 => array ('code' => 'success', 'format' => 'Saved successfully.'), |
493e13dd | 1971 | 44 => array ('code' => 'success', 'format' => '%s failure(s) and %s successfull change(s).'), |
8ab645cf AA |
1972 | 48 => array ('code' => 'success', 'format' => 'added a record successfully'), |
1973 | 49 => array ('code' => 'success', 'format' => 'deleted a record successfully'), | |
1974 | 51 => array ('code' => 'success', 'format' => 'updated a record successfully'), | |
1975 | 57 => array ('code' => 'success', 'format' => 'Reset complete'), | |
04eee8d2 | 1976 | 58 => array ('code' => 'success', 'format' => '%u device(s) unmounted successfully'), |
8ab645cf | 1977 | 63 => array ('code' => 'success', 'format' => '%u change request(s) have been processed'), |
493e13dd | 1978 | 67 => array ('code' => 'success', 'format' => "Tag rolling done, %u object(s) involved"), |
8ab645cf AA |
1979 | 71 => array ('code' => 'success', 'format' => 'File "%s" was linked successfully'), |
1980 | 72 => array ('code' => 'success', 'format' => 'File was unlinked successfully'), | |
493e13dd DO |
1981 | 82 => array ('code' => 'success', 'format' => "Bulk port creation was successful. %u port(s) created, %u failed"), |
1982 | 87 => array ('code' => 'success', 'format' => '802.1Q recalculate: %d port(s) changed on %d switch(es)'), | |
8628ae44 | 1983 | // records 100~199 with fatal error messages |
8ab645cf AA |
1984 | 100 => array ('code' => 'error', 'format' => '%s'), |
1985 | 109 => array ('code' => 'error', 'format' => 'failed updating a record'), | |
8ab645cf | 1986 | 131 => array ('code' => 'error', 'format' => 'invalid format requested'), |
493e13dd | 1987 | 141 => array ('code' => 'error', 'format' => 'Encountered %u error(s), updated %u record(s)'), |
8ab645cf AA |
1988 | 149 => array ('code' => 'error', 'format' => 'Turing test failed'), |
1989 | 150 => array ('code' => 'error', 'format' => 'Can only change password under DB authentication.'), | |
1990 | 151 => array ('code' => 'error', 'format' => 'Old password doesn\'t match.'), | |
1991 | 152 => array ('code' => 'error', 'format' => 'New passwords don\'t match.'), | |
1992 | 154 => array ('code' => 'error', 'format' => "Verification error: %s"), | |
1993 | 155 => array ('code' => 'error', 'format' => 'Save failed.'), | |
1994 | 159 => array ('code' => 'error', 'format' => 'Permission denied moving port %s from VLAN%u to VLAN%u'), | |
1995 | 161 => array ('code' => 'error', 'format' => 'Endpoint not found. Please either set FQDN attribute or assign an IP address to the object.'), | |
1996 | 162 => array ('code' => 'error', 'format' => 'More than one IP address is assigned to this object, please configure FQDN attribute.'), | |
8ab645cf AA |
1997 | 170 => array ('code' => 'error', 'format' => 'There is no network for IP address "%s"'), |
1998 | 172 => array ('code' => 'error', 'format' => 'Malformed request'), | |
1999 | 179 => array ('code' => 'error', 'format' => 'Expired form has been declined.'), | |
2000 | 188 => array ('code' => 'error', 'format' => "Fatal SNMP failure"), | |
2001 | 189 => array ('code' => 'error', 'format' => "Unknown OID '%s'"), | |
2002 | 191 => array ('code' => 'error', 'format' => "deploy was blocked due to conflicting configuration versions"), | |
f0ff4930 | 2003 | |
8628ae44 | 2004 | // records 200~299 with warnings |
8ab645cf AA |
2005 | 200 => array ('code' => 'warning', 'format' => '%s'), |
2006 | 201 => array ('code' => 'warning', 'format' => 'nothing happened...'), | |
e1add254 | 2007 | 206 => array ('code' => 'warning', 'format' => '%s is not empty'), |
7587edca | 2008 | 207 => array ('code' => 'warning', 'format' => 'File upload failed, error: %s'), |
57777e4a | 2009 | |
24d3182a | 2010 | // records 300~399 with notices |
8ab645cf | 2011 | 300 => array ('code' => 'neutral', 'format' => '%s'), |
24d3182a | 2012 | |
8ab645cf AA |
2013 | ); |
2014 | // Handle the arguments. Is there any better way to do it? | |
a2b16202 | 2015 | foreach ($log_messages as $record) |
8ab645cf | 2016 | { |
55eefced | 2017 | if (! isset ($record['c']) || ! isset ($msginfo[$record['c']])) |
8ab645cf | 2018 | { |
41152018 AA |
2019 | $prefix = isset ($record['c']) ? $record['c'] . ': ' : ''; |
2020 | echo "<div class=msg_neutral>(${prefix}this message was lost)</div>"; | |
8ab645cf AA |
2021 | continue; |
2022 | } | |
2023 | if (isset ($record['a'])) | |
2024 | switch (count ($record['a'])) | |
baf37d01 | 2025 | { |
8ab645cf AA |
2026 | case 1: |
2027 | $msgtext = sprintf | |
2028 | ( | |
2029 | $msginfo[$record['c']]['format'], | |
2030 | $record['a'][0] | |
2031 | ); | |
2032 | break; | |
2033 | case 2: | |
2034 | $msgtext = sprintf | |
2035 | ( | |
2036 | $msginfo[$record['c']]['format'], | |
2037 | $record['a'][0], | |
2038 | $record['a'][1] | |
2039 | ); | |
2040 | break; | |
2041 | case 3: | |
2042 | $msgtext = sprintf | |
2043 | ( | |
2044 | $msginfo[$record['c']]['format'], | |
2045 | $record['a'][0], | |
2046 | $record['a'][1], | |
2047 | $record['a'][2] | |
2048 | ); | |
2049 | break; | |
2050 | case 4: | |
2051 | default: | |
2052 | $msgtext = sprintf | |
2053 | ( | |
2054 | $msginfo[$record['c']]['format'], | |
2055 | $record['a'][0], | |
2056 | $record['a'][1], | |
2057 | $record['a'][2], | |
2058 | $record['a'][3] | |
2059 | ); | |
2060 | break; | |
baf37d01 | 2061 | } |
8ab645cf AA |
2062 | else |
2063 | $msgtext = $msginfo[$record['c']]['format']; | |
2064 | echo '<div class=msg_' . $msginfo[$record['c']]['code'] . ">${msgtext}</div>"; | |
baf37d01 | 2065 | } |
a2b16202 | 2066 | $log_messages = array(); |
e673ee24 DO |
2067 | } |
2068 | ||
65e557dd | 2069 | // renders two tables: port link status and learned MAC list |
d10401bf | 2070 | function renderPortsInfo($object_id) |
65e557dd | 2071 | { |
2d33a804 | 2072 | $breed = detectDeviceBreed ($object_id); |
03522bd8 AA |
2073 | try |
2074 | { | |
2075 | if (permitted (NULL, NULL, 'get_link_status')) | |
2d33a804 | 2076 | { |
2077 | if (validBreedFunction ($breed, 'getportstatus')) | |
2078 | $linkStatus = queryDevice ($object_id, 'getportstatus'); | |
2079 | } | |
03522bd8 AA |
2080 | else |
2081 | showWarning ("You don't have permission to view ports link status"); | |
2082 | ||
2083 | if (permitted (NULL, NULL, 'get_mac_list')) | |
2d33a804 | 2084 | { |
2085 | if (validBreedFunction ($breed, 'getmaclist')) | |
2086 | $macList = sortPortList (queryDevice ($object_id, 'getmaclist')); | |
2087 | } | |
03522bd8 AA |
2088 | else |
2089 | showWarning ("You don't have permission to view learned MAC list"); | |
2090 | } | |
2091 | catch (RTGatewayError $e) | |
2092 | { | |
2093 | showError ($e->getMessage()); | |
2094 | return; | |
2095 | } | |
2096 | ||
65e557dd AA |
2097 | global $nextorder; |
2098 | echo "<table width='100%'><tr>"; | |
03522bd8 | 2099 | if (! empty ($linkStatus)) |
65e557dd | 2100 | { |
03522bd8 AA |
2101 | echo "<td valign='top' width='50%'>"; |
2102 | startPortlet('Link status'); | |
2103 | echo "<table width='80%' class='widetable' cellspacing=0 cellpadding='5px' align='center'><tr><th>Port<th><th>Link status<th>Link info</tr>"; | |
2104 | $order = 'even'; | |
2105 | foreach ($linkStatus as $pn => $link) | |
65e557dd | 2106 | { |
03522bd8 | 2107 | switch ($link['status']) |
65e557dd | 2108 | { |
03522bd8 AA |
2109 | case 'up': |
2110 | $img_filename = 'link-up.png'; | |
2111 | break; | |
2112 | case 'down': | |
2113 | $img_filename = 'link-down.png'; | |
2114 | break; | |
2115 | case 'disabled': | |
2116 | $img_filename = 'link-disabled.png'; | |
2117 | break; | |
2118 | default: | |
2119 | $img_filename = '1x1t.gif'; | |
2120 | } | |
9f78501e | 2121 | |
03522bd8 AA |
2122 | echo "<tr class='row_$order'>"; |
2123 | $order = $nextorder[$order]; | |
2124 | echo '<td>' . $pn; | |
2125 | echo '<td>' . '<img width=16 height=16 src="?module=chrome&uri=pix/' . $img_filename . '">'; | |
2126 | echo '<td>' . $link['status']; | |
2127 | $info = ''; | |
2128 | if (isset ($link['speed'])) | |
2129 | $info .= $link['speed']; | |
2130 | if (isset ($link['duplex'])) | |
2131 | { | |
cfb42424 | 2132 | if ($info != '') |
03522bd8 AA |
2133 | $info .= ', '; |
2134 | $info .= $link['duplex']; | |
65e557dd | 2135 | } |
03522bd8 AA |
2136 | echo '<td>' . $info; |
2137 | echo '</tr>'; | |
65e557dd | 2138 | } |
03522bd8 AA |
2139 | echo "</table></td>"; |
2140 | finishPortlet(); | |
65e557dd AA |
2141 | } |
2142 | ||
65e557dd AA |
2143 | if (! empty ($macList)) |
2144 | { | |
2145 | echo "<td valign='top' width='50%'>"; | |
2146 | $rendered_macs = ''; | |
2147 | $mac_count = 0; | |
2148 | $rendered_macs .= "<table width='80%' class='widetable' cellspacing=0 cellpadding='5px' align='center'><tr><th>MAC<th>Vlan<th>Port</tr>"; | |
2149 | $order = 'even'; | |
2150 | foreach ($macList as $pn => $list) | |
2151 | { | |
2152 | $order = $nextorder[$order]; | |
2153 | foreach ($list as $item) | |
2154 | { | |
2155 | ++$mac_count; | |
2156 | $rendered_macs .= "<tr class='row_$order'>"; | |
2157 | $rendered_macs .= '<td style="font-family: monospace">' . $item['mac']; | |
2158 | $rendered_macs .= '<td>' . $item['vid']; | |
2159 | $rendered_macs .= '<td>' . $pn; | |
2160 | $rendered_macs .= '</tr>'; | |
2161 | } | |
2162 | } | |
2163 | $rendered_macs .= "</table></td>"; | |
dec748f6 | 2164 | |
65e557dd AA |
2165 | startPortlet("Learned MACs ($mac_count)"); |
2166 | echo $rendered_macs; | |
2167 | finishPortlet(); | |
2168 | } | |
2169 | ||
2170 | echo "</td></tr></table>"; | |
2171 | } | |
2172 | ||
e673ee24 | 2173 | /* |
51c18782 | 2174 | The following conditions must be met: |
e673ee24 DO |
2175 | 1. We can mount onto free atoms only. This means: if any record for an atom |
2176 | already exists in RackSpace, it can't be used for mounting. | |
2177 | 2. We can't unmount from 'W' atoms. Operator should review appropriate comments | |
2178 | and either delete them before unmounting or refuse to unmount the object. | |
2179 | */ | |
d10401bf | 2180 | function renderRackSpaceForObject ($object_id) |
e673ee24 | 2181 | { |
e673ee24 DO |
2182 | // Always process occupied racks plus racks chosen by user. First get racks with |
2183 | // already allocated rackspace... | |
51c18782 | 2184 | $workingRacksData = getResidentRacksData ($object_id); |
e673ee24 | 2185 | // ...and then add those chosen by user (if any). |
2135fd83 | 2186 | if (isset($_REQUEST['rackmulti'])) |
e673ee24 | 2187 | foreach ($_REQUEST['rackmulti'] as $cand_id) |
e673ee24 DO |
2188 | if (!isset ($workingRacksData[$cand_id])) |
2189 | { | |
0cc24e9a | 2190 | $rackData = spotEntity ('rack', $cand_id); |
61a1d996 | 2191 | amplifyCell ($rackData); |
e673ee24 DO |
2192 | $workingRacksData[$cand_id] = $rackData; |
2193 | } | |
51690ad4 | 2194 | |
c17a36f0 AA |
2195 | // Get a list of rack ids that are parents of this object. |
2196 | $object = spotEntity ('object', $object_id); | |
2197 | $parentRacks = reduceSubarraysToColumn (getParents ($object, 'rack'), 'id'); | |
0a7feebb | 2198 | |
e673ee24 DO |
2199 | // Main layout starts. |
2200 | echo "<table border=0 class=objectview cellspacing=0 cellpadding=0><tr>"; | |
2201 | ||
2202 | // Left portlet with rack list. | |
2203 | echo "<td class=pcleft height='1%'>"; | |
2204 | startPortlet ('Racks'); | |
a8efc03e | 2205 | $allRacksData = listCells ('rack'); |
6d42599c AA |
2206 | |
2207 | // filter rack list to match only racks having common tags with the object (reducing $allRacksData) | |
55eefced | 2208 | if (! isset ($_REQUEST['show_all_racks']) && getConfigVar ('FILTER_RACKLIST_BY_TAGS') == 'yes') |
6d42599c AA |
2209 | { |
2210 | $matching_racks = array(); | |
6d42599c AA |
2211 | $matched_tags = array(); |
2212 | foreach ($allRacksData as $rack) | |
01205bb6 | 2213 | { |
b51c1007 | 2214 | $tag_chain = array_merge ($rack['etags'], $rack['itags']); |
6d42599c | 2215 | foreach ($object['etags'] as $tag) |
01205bb6 | 2216 | if (tagOnChain ($tag, $tag_chain)) |
6d42599c AA |
2217 | { |
2218 | $matching_racks[$rack['id']] = $rack; | |
2219 | $matched_tags[$tag['id']] = $tag; | |
2220 | break; | |
2221 | } | |
01205bb6 | 2222 | } |
6d42599c AA |
2223 | // add current object's racks even if they dont match filter |
2224 | foreach ($workingRacksData as $rack_id => $rack) | |
2225 | if (! isset ($matching_racks[$rack_id])) | |
2226 | $matching_racks[$rack_id] = $rack; | |
2227 | // if matching racks found, and rack list is reduced, show 'show all' link | |
55eefced | 2228 | if (count ($matching_racks) && count ($matching_racks) != count ($allRacksData)) |
6d42599c | 2229 | { |
1e9266ad | 2230 | $tmp = array(); |
6d42599c | 2231 | foreach ($matched_tags as $tag) |
1e9266ad DO |
2232 | $tmp[] = '{' . $tag['tag'] . '}'; |
2233 | $filter_text = implode (' or ', $tmp); | |
6d42599c AA |
2234 | $href_show_all = trim($_SERVER['REQUEST_URI'], '&'); |
2235 | $href_show_all .= htmlspecialchars('&show_all_racks=1'); | |
2236 | echo "(filtered by <span class='filter-text'>$filter_text</span>, <a href='$href_show_all'>show all</a>)<p>"; | |
2237 | $allRacksData = $matching_racks; | |
2238 | } | |
2239 | } | |
2240 | ||
4b8d413e | 2241 | if (count ($allRacksData) <= getConfigVar ('RACK_PRESELECT_THRESHOLD')) |
61a1d996 | 2242 | foreach ($allRacksData as $rack) |
51c18782 DO |
2243 | if (!array_key_exists ($rack['id'], $workingRacksData)) |
2244 | { | |
2245 | amplifyCell ($rack); | |
2246 | $workingRacksData[$rack['id']] = $rack; | |
2247 | } | |
2248 | foreach (array_keys ($workingRacksData) as $rackId) | |
2249 | applyObjectMountMask ($workingRacksData[$rackId], $object_id); | |
2250 | printOpFormIntro ('updateObjectAllocation'); | |
4b8d413e | 2251 | renderRackMultiSelect ('rackmulti[]', $allRacksData, array_keys ($workingRacksData)); |
51c18782 | 2252 | echo "<br><br>"; |
e673ee24 DO |
2253 | finishPortlet(); |
2254 | echo "</td>"; | |
2255 | ||
2256 | // Middle portlet with comment and submit. | |
2257 | echo "<td class=pcleft>"; | |
5c8bf2ba | 2258 | startPortlet ('Comment (for Rackspace History)'); |
e673ee24 DO |
2259 | echo "<textarea name=comment rows=10 cols=40></textarea><br>\n"; |
2260 | echo "<input type=submit value='Save' name=got_atoms>\n"; | |
51c18782 | 2261 | echo "<br><br>"; |
e673ee24 DO |
2262 | finishPortlet(); |
2263 | echo "</td>"; | |
2264 | ||
2265 | // Right portlet with rendered racks. If this form submit is not final, we have to | |
2266 | // reflect the former state of the grid in current form. | |
2267 | echo "<td class=pcright rowspan=2 height='1%'>"; | |
2268 | startPortlet ('Working copy'); | |
e8b94513 | 2269 | includeJQueryUI (false); |
65e557dd | 2270 | addJS ('js/racktables.js'); |
c82023ad | 2271 | addJS ('js/bulkselector.js'); |
e673ee24 DO |
2272 | echo '<table border=0 cellspacing=10 align=center><tr>'; |
2273 | foreach ($workingRacksData as $rack_id => $rackData) | |
2274 | { | |
c26d97b6 | 2275 | $is_ro = !rackModificationPermitted ($rackData, 'updateObjectAllocation'); |
e673ee24 DO |
2276 | // Order is important here: only original allocation is highlighted. |
2277 | highlightObject ($rackData, $object_id); | |
2278 | markupAtomGrid ($rackData, 'T'); | |
2279 | // If we have a form processed, discard user input and show new database | |
2280 | // contents. | |
c26d97b6 | 2281 | if (!$is_ro && isset ($_REQUEST['rackmulti'][0])) // is an update |
e673ee24 DO |
2282 | mergeGridFormToRack ($rackData); |
2283 | echo "<td valign=top>"; | |
c26d97b6 VS |
2284 | echo "<center>\n<h2 style='margin:0px'>${rackData['name']}</h2>\n"; |
2285 | $read_only_text = $is_ro ? '(read-only)' : ' '; | |
2286 | echo "<p style='color: red; margin-top:0px'>${read_only_text}</p>\n"; | |
e8b94513 | 2287 | echo "<table class=rack id=selectableRack border=0 cellspacing=0 cellpadding=1>\n"; |
57c69e9c | 2288 | echo "<tr><th width='10%'> </th>"; |
bd0bfb76 AD |
2289 | echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '0', ${rackData['height']})\">Front</a></th>"; |
2290 | echo "<th width='50%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '1', ${rackData['height']})\">Interior</a></th>"; | |
2291 | echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '2', ${rackData['height']})\">Back</a></th></tr>\n"; | |
c26d97b6 | 2292 | renderAtomGrid ($rackData, $is_ro); |
57c69e9c | 2293 | echo "<tr><th width='10%'> </th>"; |
bd0bfb76 AD |
2294 | echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '0', ${rackData['height']})\">Front</a></th>"; |
2295 | echo "<th width='50%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '1', ${rackData['height']})\">Interior</a></th>"; | |
2296 | echo "<th width='20%'><a href='javascript:;' onclick=\"toggleColumnOfAtoms('${rack_id}', '2', ${rackData['height']})\">Back</a></th></tr>\n"; | |
0a7feebb AD |
2297 | echo "</table>\n<br>\n"; |
2298 | // Determine zero-u checkbox status. | |
2299 | // If form has been submitted, use form data, otherwise use DB data. | |
c26d97b6 | 2300 | if (!$is_ro && isset($_REQUEST['op'])) |
0a7feebb AD |
2301 | $checked = isset($_REQUEST['zerou_'.$rack_id]) ? 'checked' : ''; |
2302 | else | |
2303 | $checked = in_array($rack_id, $parentRacks) ? 'checked' : ''; | |
c26d97b6 VS |
2304 | $disabled_text = $is_ro ? ' disabled' : ''; |
2305 | 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 | 2306 | echo "<input type='button' onclick='uncheckAll();' value='Uncheck all'>\n"; |
0a7feebb | 2307 | echo '</center></td>'; |
e673ee24 DO |
2308 | } |
2309 | echo "</tr></table>"; | |
2310 | finishPortlet(); | |
2311 | echo "</td>\n"; | |
2312 | ||
2313 | echo "</form>\n"; | |
2314 | echo "</tr></table>\n"; | |
2315 | } | |
2316 | ||
2317 | function renderMolecule ($mdata, $object_id) | |
2318 | { | |
2319 | // sort data out | |
2320 | $rackpack = array(); | |
2321 | global $loclist; | |
64b95774 | 2322 | foreach ($mdata as $rua) |
e673ee24 DO |
2323 | { |
2324 | $rack_id = $rua['rack_id']; | |
2325 | $unit_no = $rua['unit_no']; | |
2326 | $atom = $rua['atom']; | |
2327 | if (!isset ($rackpack[$rack_id])) | |
2328 | { | |
61a1d996 DO |
2329 | $rackData = spotEntity ('rack', $rack_id); |
2330 | amplifyCell ($rackData); | |
e673ee24 DO |
2331 | for ($i = $rackData['height']; $i > 0; $i--) |
2332 | for ($locidx = 0; $locidx < 3; $locidx++) | |
2333 | $rackData[$i][$locidx]['state'] = 'F'; | |
2334 | $rackpack[$rack_id] = $rackData; | |
2335 | } | |
2336 | $rackpack[$rack_id][$unit_no][$loclist[$atom]]['state'] = 'T'; | |
2337 | $rackpack[$rack_id][$unit_no][$loclist[$atom]]['object_id'] = $object_id; | |
2338 | } | |
2339 | // now we have some racks to render | |
64b95774 | 2340 | foreach ($rackpack as $rackData) |
e673ee24 DO |
2341 | { |
2342 | markAllSpans ($rackData); | |
2343 | echo "<table class=molecule cellspacing=0>\n"; | |
2344 | echo "<caption>${rackData['name']}</caption>\n"; | |
2345 | echo "<tr><th width='10%'> </th><th width='20%'>Front</th><th width='50%'>Interior</th><th width='20%'>Back</th></tr>\n"; | |
2346 | for ($i = $rackData['height']; $i > 0; $i--) | |
2347 | { | |
4dcd770e | 2348 | echo "<tr><th>" . inverseRackUnit ($i, $rackData) . "</th>"; |
e673ee24 DO |
2349 | for ($locidx = 0; $locidx < 3; $locidx++) |
2350 | { | |
2351 | $state = $rackData[$i][$locidx]['state']; | |
65e557dd | 2352 | echo "<td class='atom state_${state}'> </td>\n"; |
e673ee24 DO |
2353 | } |
2354 | echo "</tr>\n"; | |
2355 | } | |
2356 | echo "</table>\n"; | |
2357 | } | |
2358 | } | |
2359 | ||
23cdc7e9 | 2360 | function renderDepot () |
e673ee24 | 2361 | { |
23cdc7e9 | 2362 | global $pageno, $nextorder; |
23cdc7e9 | 2363 | $cellfilter = getCellFilter(); |
950dfa1f AA |
2364 | $objects = array(); |
2365 | $objects_count = getEntitiesCount ('object'); | |
db8255ac | 2366 | $showobjecttype = (getConfigVar ('SHOW_OBJECTTYPE') == 'yes'); |
23cdc7e9 DO |
2367 | |
2368 | echo "<table border=0 class=objectview>\n"; | |
2369 | echo "<tr><td class=pcleft>"; | |
2370 | ||
950dfa1f AA |
2371 | if ($objects_count == 0) |
2372 | echo '<h2>No objects exist</h2>'; | |
2373 | // 1st attempt: do not fetch all objects if cellfilter is empty and rendering empty result is enabled | |
2374 | elseif (! ($cellfilter['is_empty'] && renderEmptyResults ($cellfilter, 'objects', $objects_count))) | |
e673ee24 | 2375 | { |
2b16c179 | 2376 | $objects = applyCellFilter ('object', $cellfilter); |
20506de3 | 2377 | // 2nd attempt: do not render all fetched objects if rendering empty result is enabled |
950dfa1f | 2378 | if (! renderEmptyResults ($cellfilter, 'objects', count($objects))) |
1ebbf889 | 2379 | { |
4899096d AD |
2380 | startPortlet ('Objects (' . count ($objects) . ')'); |
2381 | echo '<br><br><table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>'; | |
db8255ac J |
2382 | echo '<tr><th>Common name</th>'; |
2383 | if ($showobjecttype) | |
2384 | echo '<th>Type</th>'; | |
2385 | echo '<th>Visible label</th><th>Asset tag</th><th>Row/Rack or Container</th></tr>'; | |
4899096d | 2386 | $order = 'odd'; |
3f8a25d6 DO |
2387 | # gather IDs of all objects and fetch rackspace info in one pass |
2388 | $idlist = array(); | |
2389 | foreach ($objects as $obj) | |
2390 | $idlist[] = $obj['id']; | |
2391 | $mountinfo = getMountInfo ($idlist); | |
cae81598 | 2392 | $containerinfo = getContainerInfo ($idlist); |
4899096d AD |
2393 | foreach ($objects as $obj) |
2394 | { | |
ec788aba AD |
2395 | $problem = ($obj['has_problems'] == 'yes') ? 'has_problems' : ''; |
2396 | echo "<tr class='row_${order} tdleft ${problem}' valign=top><td>" . mkA ("<strong>${obj['dname']}</strong>", 'object', $obj['id']); | |
4899096d AD |
2397 | if (count ($obj['etags'])) |
2398 | echo '<br><small>' . serializeTags ($obj['etags'], makeHref(array('page'=>$pageno, 'tab'=>'default')) . '&') . '</small>'; | |
db8255ac J |
2399 | echo '</td>'; |
2400 | if ($showobjecttype) | |
9563f56f | 2401 | echo "<td>" . decodeObjectType ($obj['objtype_id']) . "</td>"; |
8526b4cc | 2402 | echo "<td>${obj['label']}</td>"; |
4318ced5 | 2403 | echo "<td>${obj['asset_no']}</td>"; |
3f8a25d6 | 2404 | $places = array(); |
cae81598 AD |
2405 | if (array_key_exists ($obj['id'], $containerinfo)) |
2406 | foreach ($containerinfo[$obj['id']] as $ci) | |
20506de3 | 2407 | $places[] = mkA ($ci['container_dname'], 'object', $ci['container_id']); |
cae81598 | 2408 | if (array_key_exists ($obj['id'], $mountinfo)) |
3f8a25d6 DO |
2409 | foreach ($mountinfo[$obj['id']] as $mi) |
2410 | $places[] = mkA ($mi['row_name'], 'row', $mi['row_id']) . '/' . mkA ($mi['rack_name'], 'rack', $mi['rack_id']); | |
cae81598 AD |
2411 | if (! count ($places)) |
2412 | $places[] = 'Unmounted'; | |
4318ced5 | 2413 | echo "<td>" . implode (', ', $places) . '</td>'; |
4899096d AD |
2414 | echo '</tr>'; |
2415 | $order = $nextorder[$order]; | |
2416 | } | |
2417 | echo '</table>'; | |
2418 | finishPortlet(); | |
1ebbf889 | 2419 | } |
e673ee24 | 2420 | } |
23cdc7e9 DO |
2421 | |
2422 | echo "</td><td class=pcright width='25%'>"; | |
2423 | ||
95857b5c | 2424 | renderCellFilterPortlet ($cellfilter, 'object', $objects); |
23cdc7e9 | 2425 | echo "</td></tr></table>\n"; |
e673ee24 DO |
2426 | } |
2427 | ||
1ebbf889 AA |
2428 | // This function returns TRUE if the result set is too big to be rendered, and no filter is set. |
2429 | // In this case it renders the describing message instead. | |
2430 | function renderEmptyResults($cellfilter, $entities_name, $count = NULL) | |
2431 | { | |
2432 | if (!$cellfilter['is_empty']) | |
2433 | return FALSE; | |
2434 | if (isset ($_REQUEST['show_all_objects'])) | |
2435 | return FALSE; | |
2436 | $max = intval(getConfigVar('MAX_UNFILTERED_ENTITIES')); | |
2437 | if (0 == $max || $count <= $max) | |
2438 | return FALSE; | |
2439 | ||
2440 | $href_show_all = trim($_SERVER['REQUEST_URI'], '&'); | |
2441 | $href_show_all .= htmlspecialchars('&show_all_objects=1'); | |
2442 | $suffix = isset ($count) ? " ($count)" : ''; | |
2443 | echo <<<END | |
2444 | <p>Please set a filter to display the corresponging $entities_name. | |
2445 | <br><a href="$href_show_all">Show all $entities_name$suffix</a> | |
2446 | END; | |
2447 | return TRUE; | |
2448 | } | |
2449 | ||
e673ee24 | 2450 | // History viewer for history-enabled simple dictionaries. |
9b8174d7 | 2451 | function renderObjectHistory ($object_id) |
e673ee24 | 2452 | { |
e673ee24 DO |
2453 | $order = 'odd'; |
2454 | global $nextorder; | |
9b8174d7 AD |
2455 | echo '<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>'; |
2456 | 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>'; | |
2457 | $result = usePreparedSelectBlade | |
2458 | ( | |
2459 | 'SELECT ctime, user_name, name, label, asset_no, has_problems, comment FROM ObjectHistory WHERE id=? ORDER BY ctime', | |
2460 | array ($object_id) | |
2461 | ); | |
e673ee24 DO |
2462 | while ($row = $result->fetch (PDO::FETCH_NUM)) |
2463 | { | |
2464 | echo "<tr class=row_${order}><td>${row[0]}</td>"; | |
9b8174d7 | 2465 | for ($i = 1; $i <= 6; $i++) |
e673ee24 DO |
2466 | echo "<td>" . $row[$i] . "</td>"; |
2467 | echo "</tr>\n"; | |
2468 | $order = $nextorder[$order]; | |
2469 | } | |
2470 | echo "</table><br>\n"; | |
2471 | } | |
2472 | ||
2473 | function renderRackspaceHistory () | |
2474 | { | |
4fbb5a00 | 2475 | global $nextorder, $pageno, $tabno; |
e673ee24 DO |
2476 | $order = 'odd'; |
2477 | $history = getRackspaceHistory(); | |
2478 | // Show the last operation by default. | |
2479 | if (isset ($_REQUEST['op_id'])) | |
2480 | $op_id = $_REQUEST['op_id']; | |
2481 | elseif (isset ($history[0]['mo_id'])) | |
2482 | $op_id = $history[0]['mo_id']; | |
2483 | else $op_id = NULL; | |
dec748f6 | 2484 | |
e673ee24 DO |
2485 | $omid = NULL; |
2486 | $nmid = NULL; | |
2487 | $object_id = 1; | |
2488 | if ($op_id) | |
2489 | list ($omid, $nmid) = getOperationMolecules ($op_id); | |
2490 | ||
2491 | // Main layout starts. | |
2492 | echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>"; | |
2493 | ||
2494 | // Left top portlet with old allocation. | |
2495 | echo "<tr><td class=pcleft>"; | |
2496 | startPortlet ('Old allocation'); | |
2497 | if ($omid) | |
2498 | { | |
2499 | $oldMolecule = getMolecule ($omid); | |
2500 | renderMolecule ($oldMolecule, $object_id); | |
2501 | } | |
2502 | else | |
2503 | echo "nothing"; | |
2504 | finishPortlet(); | |
2505 | ||
2506 | echo '</td><td class=pcright>'; | |
2507 | ||
2508 | // Right top portlet with new allocation | |
2509 | startPortlet ('New allocation'); | |
2510 | if ($nmid) | |
2511 | { | |
2512 | $newMolecule = getMolecule ($nmid); | |
2513 | renderMolecule ($newMolecule, $object_id); | |
2514 | } | |
2515 | else | |
2516 | echo "nothing"; | |
2517 | finishPortlet(); | |
737a3f72 | 2518 | |
e673ee24 | 2519 | echo '</td></tr><tr><td colspan=2>'; |
737a3f72 | 2520 | |
e673ee24 DO |
2521 | // Bottom portlet with list |
2522 | ||
2523 | startPortlet ('Rackspace allocation history'); | |
2524 | echo "<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>\n"; | |
7fa7047a | 2525 | echo "<tr><th>timestamp</th><th>author</th><th>object</th><th>comment</th></tr>\n"; |
e673ee24 DO |
2526 | foreach ($history as $row) |
2527 | { | |
2528 | if ($row['mo_id'] == $op_id) | |
2529 | $class = 'hl'; | |
2530 | else | |
2531 | $class = "row_${order}"; | |
4fbb5a00 | 2532 | echo "<tr class=${class}><td><a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'op_id'=>$row['mo_id']))."'>${row['ctime']}</a></td>"; |
7fa7047a DO |
2533 | echo "<td>${row['user_name']}</td><td>"; |
2534 | renderCell (spotEntity ('object', $row['ro_id'])); | |
a0bdf6dc | 2535 | echo '</td><td>' . stringForTD ($row['comment'], 0) . '</td></tr>'; |
e673ee24 DO |
2536 | $order = $nextorder[$order]; |
2537 | } | |
2538 | echo "</table>\n"; | |
2539 | finishPortlet(); | |
737a3f72 | 2540 | |
e673ee24 | 2541 | echo '</td></tr></table>'; |
e673ee24 DO |
2542 | } |
2543 | ||
4318ced5 | 2544 | function renderIPSpaceRecords ($tree, $baseurl, $target = 0, $level = 1) |
d65353ad DO |
2545 | { |
2546 | $self = __FUNCTION__; | |
4318ced5 | 2547 | $knight = (getConfigVar ('IPV4_ENABLE_KNIGHT') == 'yes'); |
00276508 AA |
2548 | |
2549 | // scroll page to the highlighted item | |
2550 | if ($target && isset ($_REQUEST['hl_net'])) | |
65e557dd | 2551 | addAutoScrollScript ("net-$target"); |
00276508 | 2552 | |
d65353ad DO |
2553 | foreach ($tree as $item) |
2554 | { | |
6063fab7 | 2555 | $display_routers = (getConfigVar ('IPV4_TREE_RTR_AS_CELL') != 'none'); |
4318ced5 | 2556 | |
0137d53c DO |
2557 | if (isset ($item['id'])) |
2558 | { | |
1f54e1ba | 2559 | $decor = array ('indent' => $level); |
fec0c8da | 2560 | if ($item['symbol'] == 'node-collapsed') |
4318ced5 | 2561 | $decor['symbolurl'] = "${baseurl}&eid=${item['id']}&hl_net=1"; |
fec0c8da | 2562 | elseif ($item['symbol'] == 'node-expanded') |
4318ced5 AA |
2563 | $decor['symbolurl'] = $baseurl . ($item['parent_id'] ? "&eid=${item['parent_id']}&hl_net=1" : ''); |
2564 | $tr_class = ''; | |
21ee3351 | 2565 | if ($target == $item['id'] && isset ($_REQUEST['hl_net'])) |
64347dcf | 2566 | { |
5c717ce5 | 2567 | $decor['tdclass'] = ' highlight'; |
4318ced5 | 2568 | $tr_class = $decor['tdclass']; |
64347dcf | 2569 | } |
4318ced5 AA |
2570 | echo "<tr valign=top class=\"$tr_class\">"; |
2571 | printIPNetInfoTDs ($item, $decor); | |
2572 | ||
2573 | // capacity and usage | |
2574 | echo "<td class=tdcenter>"; | |
2575 | echo getRenderedIPNetCapacity ($item); | |
64347dcf | 2576 | echo "</td>"; |
4318ced5 AA |
2577 | |
2578 | if ($display_routers) | |
6063fab7 | 2579 | printRoutersTD (findNetRouters ($item), getConfigVar ('IPV4_TREE_RTR_AS_CELL')); |
0137d53c | 2580 | echo "</tr>"; |
55eefced | 2581 | if ($item['symbol'] == 'node-expanded' || $item['symbol'] == 'node-expanded-static') |
4318ced5 | 2582 | $self ($item['kids'], $baseurl, $target, $level + 1); |
0137d53c | 2583 | } |
26fc6e7c | 2584 | elseif (getConfigVar ('IPV4_TREE_SHOW_UNALLOCATED') == 'yes') |
0137d53c | 2585 | { |
4318ced5 | 2586 | // non-allocated (spare) IP range |
0137d53c | 2587 | echo "<tr valign=top>"; |
21ee3351 | 2588 | printIPNetInfoTDs ($item, array ('indent' => $level, 'knight' => $knight, 'tdclass' => 'sparenetwork')); |
00276508 | 2589 | |
4318ced5 | 2590 | // capacity and usage |
21ee3351 | 2591 | echo "<td class=tdcenter>"; |
4318ced5 | 2592 | echo getRenderedIPNetCapacity ($item); |
21ee3351 | 2593 | echo "</td>"; |
4318ced5 AA |
2594 | if ($display_routers) |
2595 | echo "<td></td>"; | |
21ee3351 | 2596 | echo "</tr>"; |
21ee3351 | 2597 | } |
21ee3351 AA |
2598 | } |
2599 | } | |
2600 | ||
4318ced5 | 2601 | function renderIPSpace() |
e673ee24 | 2602 | { |
4fbb5a00 | 2603 | global $pageno, $tabno; |
4318ced5 | 2604 | $realm = ($pageno == 'ipv4space' ? 'ipv4net' : 'ipv6net'); |
31c941ec | 2605 | $cellfilter = getCellFilter(); |
21ee3351 | 2606 | |
b99b4167 AA |
2607 | // expand request can take either natural values or "ALL". Zero means no expanding. |
2608 | $eid = isset ($_REQUEST['eid']) ? $_REQUEST['eid'] : 0; | |
2609 | ||
21ee3351 AA |
2610 | echo "<table border=0 class=objectview>\n"; |
2611 | echo "<tr><td class=pcleft>"; | |
950dfa1f AA |
2612 | |
2613 | $netlist = array(); | |
b99b4167 | 2614 | if (! ($cellfilter['is_empty'] && ! $eid && renderEmptyResults($cellfilter, 'IP nets', getEntitiesCount ($realm)))) |
21ee3351 | 2615 | { |
950dfa1f AA |
2616 | $top = NULL; |
2617 | foreach (listCells ($realm) as $net) | |
21ee3351 | 2618 | { |
55eefced | 2619 | if (isset ($top) && IPNetContains ($top, $net)) |
950dfa1f | 2620 | ; |
55eefced | 2621 | elseif (! count ($cellfilter['expression']) || judgeCell ($net, $cellfilter['expression'])) |
950dfa1f AA |
2622 | $top = $net; |
2623 | else | |
2624 | continue; | |
2625 | $netlist[$net['id']] = $net; | |
2626 | } | |
2627 | $netcount = count ($netlist); | |
950dfa1f AA |
2628 | $tree = prepareIPTree ($netlist, $eid); |
2629 | ||
2630 | if (! renderEmptyResults($cellfilter, 'IP nets', count($tree))) | |
2631 | { | |
2632 | startPortlet ("networks (${netcount})"); | |
2633 | echo '<h4>'; | |
2634 | $all = "<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'eid'=>'ALL')) . | |
2635 | $cellfilter['urlextra'] . "'>expand all</a>"; | |
2636 | $none = "<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'eid'=>'NONE')) . | |
2637 | $cellfilter['urlextra'] . "'>collapse all</a>"; | |
2638 | $auto = "<a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno)) . | |
2639 | $cellfilter['urlextra'] . "'>auto-collapse</a>"; | |
2640 | ||
2641 | if ($eid === 0) | |
2642 | echo 'auto-collapsing at threshold ' . getConfigVar ('TREE_THRESHOLD') . " ($all / $none)"; | |
2643 | elseif ($eid === 'ALL') | |
2644 | echo "expanding all ($auto / $none)"; | |
2645 | elseif ($eid === 'NONE') | |
2646 | echo "collapsing all ($all / $auto)"; | |
2647 | else | |
2648 | { | |
a0f0c0c7 AA |
2649 | try |
2650 | { | |
2651 | $netinfo = spotEntity ($realm, $eid); | |
2652 | echo "expanding ${netinfo['ip']}/${netinfo['mask']} ($auto / $all / $none)"; | |
2653 | } | |
2654 | catch (EntityNotFoundException $e) | |
2655 | { | |
2656 | // ignore invalid eid error | |
2657 | } | |
950dfa1f AA |
2658 | } |
2659 | echo "</h4><table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n"; | |
2660 | echo "<tr><th>prefix</th><th>name/tags</th><th>capacity</th>"; | |
2661 | if (getConfigVar ('IPV4_TREE_RTR_AS_CELL') != 'none') | |
2662 | echo "<th>routed by</th>"; | |
2663 | echo "</tr>\n"; | |
2664 | $baseurl = makeHref(array('page'=>$pageno, 'tab'=>$tabno)) . $cellfilter['urlextra']; | |
2665 | renderIPSpaceRecords ($tree, $baseurl, $eid); | |
2666 | echo "</table>\n"; | |
2667 | finishPortlet(); | |
21ee3351 | 2668 | } |
21ee3351 AA |
2669 | } |
2670 | ||
2671 | echo '</td><td class=pcright>'; | |
950dfa1f | 2672 | renderCellFilterPortlet ($cellfilter, $realm, $netlist); |
21ee3351 AA |
2673 | echo "</td></tr></table>\n"; |
2674 | } | |
2675 | ||
4318ced5 | 2676 | function renderIPSpaceEditor() |
21ee3351 | 2677 | { |
4318ced5 AA |
2678 | global $pageno; |
2679 | $realm = ($pageno == 'ipv4space' ? 'ipv4net' : 'ipv6net'); | |
4318ced5 | 2680 | $addrspaceList = listCells ($realm); |
93a49e5b AA |
2681 | startPortlet ('Manage existing (' . count ($addrspaceList) . ')'); |
2682 | if (count ($addrspaceList)) | |
21ee3351 | 2683 | { |
21ee3351 AA |
2684 | echo "<table class='widetable' border=0 cellpadding=5 cellspacing=0 align='center'>\n"; |
2685 | echo "<tr><th> </th><th>prefix</th><th>name</th><th>capacity</th></tr>"; | |
21ee3351 AA |
2686 | foreach ($addrspaceList as $netinfo) |
2687 | { | |
21ee3351 | 2688 | echo "<tr valign=top><td>"; |
93a49e5b | 2689 | if (! isIPNetworkEmpty ($netinfo)) |
21ee3351 AA |
2690 | printImageHREF ('nodestroy', 'There are ' . count ($netinfo['addrlist']) . ' allocations inside'); |
2691 | else | |
93a49e5b | 2692 | echo getOpLink (array ('op' => 'del', 'id' => $netinfo['id']), '', 'destroy', 'Delete this prefix'); |
6d8424f8 | 2693 | echo '</td><td class=tdleft>' . mkCellA ($netinfo) . '</td>'; |
a0bdf6dc | 2694 | echo '<td class=tdleft>' . stringForTD ($netinfo['name']); |
1f54e1ba DO |
2695 | if (count ($netinfo['etags'])) |
2696 | echo '<br><small>' . serializeTags ($netinfo['etags']) . '</small>'; | |
2697 | echo '</td><td>'; | |
4318ced5 | 2698 | echo getRenderedIPNetCapacity ($netinfo); |
b1e39212 | 2699 | echo '</tr>'; |
e673ee24 | 2700 | } |
04d619d0 DO |
2701 | echo "</table>"; |
2702 | finishPortlet(); | |
e673ee24 | 2703 | } |
93a49e5b AA |
2704 | } |
2705 | ||
2706 | function renderIPNewNetForm () | |
2707 | { | |
2708 | global $pageno; | |
2709 | if ($pageno == 'ipv6space') | |
2710 | { | |
2711 | $realm = 'ipv6net'; | |
3495ec6e | 2712 | $regexp = '^[a-fA-F0-9:]*:[a-fA-F0-9:\.]*/\d{1,3}$'; |
93a49e5b AA |
2713 | } |
2714 | else | |
2715 | { | |
2716 | $realm = 'ipv4net'; | |
3495ec6e | 2717 | $regexp = '^(\d{1,3}\.){3}\d{1,3}/\d{1,2}$'; |
93a49e5b AA |
2718 | } |
2719 | ||
2720 | // IP prefix validator | |
10f5133a | 2721 | addJS ('js/live_validation.js'); |
93a49e5b | 2722 | $regexp = addslashes ($regexp); |
10f5133a | 2723 | addJS (<<<END |
93a49e5b | 2724 | $(document).ready(function () { |
b895e6b4 | 2725 | $('form#add input[name="range"]').attr('match', '$regexp'); |
93a49e5b AA |
2726 | Validate.init(); |
2727 | }); | |
2728 | END | |
2729 | , TRUE); | |
dec748f6 | 2730 | |
93a49e5b | 2731 | startPortlet ('Add new'); |
10f5133a | 2732 | printOpFormIntro ('add'); |
e7b84015 AB |
2733 | echo '<table border=0 cellpadding=5 cellspacing=0 align=center>'; |
2734 | ||
93a49e5b AA |
2735 | // inputs column |
2736 | $prefix_value = empty ($_REQUEST['set-prefix']) ? '' : $_REQUEST['set-prefix']; | |
04c61e7e | 2737 | echo "<th class=tdright>Prefix:</th><td class=tdleft><input type=text name='range' size=36 class='live-validate' value='${prefix_value}'></td>"; |
e7b84015 | 2738 | echo '<tr><th class=tdright>VLAN:</th><td class=tdleft>'; |
04c61e7e AB |
2739 | echo getOptionTree ('vlan_ck', getAllVLANOptions(), array ('select_class' => 'vertical')) . '</td></tr>'; |
2740 | echo "<tr><th class=tdright>Name:</th><td class=tdleft><input type=text name='name' size='20'></td></tr>"; | |
e7b84015 AB |
2741 | echo '<tr><th class=tdright>Tags:</th><td class="tdleft">'; |
2742 | printTagsPicker (); | |
2743 | echo '</td></tr>'; | |
38707670 DO |
2744 | echo '<tr><td class=tdright><input type=checkbox name="is_connected" id="is_connected"></td>'; |
2745 | echo '<th class=tdleft><label for="is_connected">reserve subnet-router anycast address</label></th></tr>'; | |
93a49e5b | 2746 | echo "<tr><td colspan=2>"; |
04c61e7e | 2747 | printImageHREF ('CREATE', 'Add a new network', TRUE); |
93a49e5b | 2748 | echo '</td></tr>'; |
e7b84015 | 2749 | echo "</table></form><br><br>\n"; |
93a49e5b | 2750 | finishPortlet(); |
e673ee24 DO |
2751 | } |
2752 | ||
4318ced5 | 2753 | function getRenderedIPNetBacktrace ($range) |
e673ee24 | 2754 | { |
4318ced5 AA |
2755 | if (getConfigVar ('EXT_IPV4_VIEW') != 'yes') |
2756 | return array(); | |
e673ee24 | 2757 | |
4318ced5 AA |
2758 | $v = ($range['realm'] == 'ipv4net') ? 4 : 6; |
2759 | $space = "ipv${v}space"; // ipv4space, ipv6space | |
2760 | $tag = "\$ip${v}netid_"; // $ip4netid_, $ip6netid_ | |
dec748f6 | 2761 | |
4318ced5 AA |
2762 | $ret = array(); |
2763 | // Build a backtrace from all parent networks. | |
2764 | $clen = $range['mask']; | |
2765 | $backtrace = array(); | |
2766 | $backtrace['→'] = $range; | |
2767 | $key = ''; | |
2768 | while (NULL !== ($upperid = getIPAddressNetworkId ($range['ip_bin'], $clen))) | |
2769 | { | |
2770 | $upperinfo = spotEntity ($range['realm'], $upperid); | |
2771 | $clen = $upperinfo['mask']; | |
2772 | $key .= '↑'; | |
2773 | $backtrace[$key] = $upperinfo; | |
2774 | } | |
2775 | foreach (array_reverse ($backtrace) as $arrow => $ainfo) | |
2776 | { | |
2777 | $link = '<a href="' . makeHref (array ( | |
2778 | 'page' => $space, | |
2779 | 'tab' => 'default', | |
2780 | 'clear-cf' => '', | |
2781 | 'cfe' => '{' . $tag . $ainfo['id'] . '}', | |
2782 | 'hl_net' => 1, | |
2783 | 'eid' => $range['id'], | |
2784 | )) . '" title="View IP tree with this net as root">' . $arrow . '</a>'; | |
2785 | $ret[] = array ($link, getOutputOf ('renderCell', $ainfo)); | |
2786 | } | |
2787 | return $ret; | |
2788 | } | |
2789 | ||
d10401bf | 2790 | function renderIPNetwork ($id) |
4318ced5 AA |
2791 | { |
2792 | global $pageno; | |
2793 | $realm = $pageno; // 'ipv4net', 'ipv6net' | |
d10401bf | 2794 | $range = spotEntity ($realm, $id); |
4318ced5 | 2795 | loadIPAddrList ($range); |
2034d968 | 2796 | echo "<table border=0 class=objectview cellspacing=0 cellpadding=0>"; |
99ab184f DO |
2797 | echo "<tr><td colspan=2 align=center><h1>${range['ip']}/${range['mask']}</h1><h2>"; |
2798 | echo htmlspecialchars ($range['name'], ENT_QUOTES, 'UTF-8') . "</h2></td></tr>\n"; | |
2034d968 DO |
2799 | |
2800 | echo "<tr><td class=pcleft width='50%'>"; | |
646272be AA |
2801 | |
2802 | // render summary portlet | |
2803 | $summary = array(); | |
4318ced5 | 2804 | $summary['%% used'] = getRenderedIPNetCapacity ($range); |
2b6b0038 | 2805 | $summary = getRenderedIPNetBacktrace ($range) + $summary; |
4318ced5 | 2806 | if ($realm == 'ipv4net') |
001e61fa | 2807 | { |
4318ced5 AA |
2808 | $summary[] = array ('Netmask:', ip4_format ($range['mask_bin'])); |
2809 | $summary[] = array ('Netmask:', "0x" . strtoupper (implode ('', unpack ('H*', $range['mask_bin'])))); | |
2810 | $summary['Wildcard bits'] = ip4_format ( ~ $range['mask_bin']); | |
001e61fa | 2811 | } |
dec748f6 | 2812 | |
11e3af31 DO |
2813 | $reuse_domain = considerConfiguredConstraint ($range, '8021Q_MULTILINK_LISTSRC'); |
2814 | $domainclass = array(); | |
2815 | foreach (array_count_values (reduceSubarraysToColumn ($range['8021q'], 'domain_id')) as $domain_id => $vlan_count) | |
2816 | $domainclass[$domain_id] = $vlan_count == 1 ? '' : ($reuse_domain ? '{trwarning}' : '{trerror}'); | |
a5f9d1ca | 2817 | foreach ($range['8021q'] as $item) |
3f642516 | 2818 | $summary[] = array ($domainclass[$item['domain_id']] . 'VLAN:', formatVLANAsHyperlink (getVlanRow ($item['domain_id'] . '-' . $item['vlan_id']))); |
55eefced | 2819 | if (getConfigVar ('EXT_IPV4_VIEW') == 'yes' && count ($routers = findNetRouters ($range))) |
04d619d0 | 2820 | { |
646272be AA |
2821 | $summary['Routed by'] = ''; |
2822 | foreach ($routers as $rtr) | |
4318ced5 | 2823 | $summary['Routed by'] .= getOutputOf ('renderRouterCell', $rtr['ip_bin'], $rtr['iface'], spotEntity ('object', $rtr['id'])); |
04d619d0 | 2824 | } |
646272be AA |
2825 | $summary['tags'] = ''; |
2826 | renderEntitySummary ($range, 'summary', $summary); | |
e1ae3fb4 | 2827 | |
33973968 | 2828 | if ($range['comment'] != '') |
99ab184f DO |
2829 | { |
2830 | startPortlet ('Comment'); | |
2831 | echo '<div class=commentblock>' . string_insert_hrefs (htmlspecialchars ($range['comment'], ENT_QUOTES, 'UTF-8')) . '</div>'; | |
2832 | finishPortlet (); | |
2833 | } | |
2834 | ||
d10401bf | 2835 | renderFilesPortlet ($realm, $id); |
2034d968 | 2836 | echo "</td>\n"; |
e673ee24 | 2837 | |
2034d968 DO |
2838 | echo "<td class=pcright>"; |
2839 | startPortlet ('details'); | |
4318ced5 AA |
2840 | renderIPNetworkAddresses ($range); |
2841 | finishPortlet(); | |
2842 | echo "</td></tr></table>\n"; | |
2843 | } | |
e673ee24 | 2844 | |
4318ced5 AA |
2845 | // Used solely by renderSeparator |
2846 | function renderEmptyIPv6 ($ip_bin, $hl_ip) | |
2847 | { | |
2848 | $class = 'tdleft'; | |
2849 | if ($ip_bin === $hl_ip) | |
5c717ce5 | 2850 | $class .= ' highlight'; |
4318ced5 | 2851 | $fmt = ip6_format ($ip_bin); |
235124a6 | 2852 | echo "<tr class='$class'><td><a name='ip-$fmt' href='" . makeHref (array ('page' => 'ipaddress', 'ip' => $fmt)) . "'>" . $fmt; |
0b8d8309 AA |
2853 | $editable = permitted ('ipaddress', 'properties', 'editAddress') |
2854 | ? 'editable' | |
2855 | : ''; | |
cc2fa820 AD |
2856 | echo "</a></td><td><span class='rsvtext $editable id-$fmt op-upd-ip-name'></span></td>"; |
2857 | echo "<td><span class='rsvtext $editable id-$fmt op-upd-ip-comment'></span></td><td> </td></tr>\n"; | |
4318ced5 AA |
2858 | } |
2859 | ||
2860 | // Renders empty table line to shrink empty IPv6 address ranges. | |
2861 | // If the range consists of single address, renders the address instead of empty line. | |
2862 | // Renders address $hl_ip inside the range. | |
2863 | // Used solely by renderIPv6NetworkAddresses | |
2864 | function renderSeparator ($first, $last, $hl_ip) | |
2865 | { | |
2866 | $self = __FUNCTION__; | |
2867 | if (strcmp ($first, $last) > 0) | |
2868 | return; | |
2869 | if ($first == $last) | |
2870 | renderEmptyIPv6 ($first, $hl_ip); | |
2871 | elseif (isset ($hl_ip) && strcmp ($hl_ip, $first) >= 0 && strcmp ($hl_ip, $last) <= 0) | |
2872 | { // $hl_ip is inside the range $first - $last | |
2873 | $self ($first, ip_prev ($hl_ip), $hl_ip); | |
2874 | renderEmptyIPv6 ($hl_ip, $hl_ip); | |
2875 | $self (ip_next ($hl_ip), $last, $hl_ip); | |
2876 | } | |
2877 | else | |
cc2fa820 | 2878 | echo "<tr><td colspan=4 class=tdleft></td></tr>\n"; |
4318ced5 AA |
2879 | } |
2880 | ||
75e7c0c6 | 2881 | // calculates page number that contains given $ip (used by renderIPv6NetworkAddresses) |
4318ced5 AA |
2882 | function getPageNumOfIPv6 ($list, $ip_bin, $maxperpage) |
2883 | { | |
2884 | if (intval ($maxperpage) <= 0 || count ($list) <= $maxperpage) | |
2885 | return 0; | |
2886 | $keys = array_keys ($list); | |
2887 | for ($i = 1; $i <= count ($keys); $i++) | |
2888 | if (strcmp ($keys[$i-1], $ip_bin) >= 0) | |
2889 | return intval ($i / $maxperpage); | |
2890 | return intval (count ($list) / $maxperpage); | |
2891 | } | |
2892 | ||
2893 | function renderIPNetworkAddresses ($range) | |
2894 | { | |
2895 | switch (strlen ($range['ip_bin'])) | |
2896 | { | |
2897 | case 4: return renderIPv4NetworkAddresses ($range); | |
2898 | case 16: return renderIPv6NetworkAddresses ($range); | |
2899 | default: throw new InvalidArgException ("range['ip_bin']", $range['ip_bin']); | |
2900 | } | |
2901 | } | |
2902 | ||
247acd67 KZ |
2903 | function renderIPv4NetworkPageLink ($rangeid, $page, $title) |
2904 | { | |
2905 | global $pageno, $tabno; | |
2906 | return "<a href='".makeHref (array ('page' => $pageno, 'tab' => $tabno, 'id' => $rangeid, 'pg' => $page)) . "' title='".$title."'>".$page."</a> "; | |
2907 | } | |
2908 | ||
2909 | function renderIPv4NetworkPagination ($range, $page, $numpages) | |
2910 | { | |
2911 | $rendered_pager = ''; | |
2912 | $startip = ip4_bin2int ($range['ip_bin']); | |
2913 | $endip = ip4_bin2int (ip_last ($range)); | |
2914 | $rangeid = $range['id']; | |
2915 | // Should make this configurable perhaps | |
2916 | // How many pages before/after current page to show | |
2917 | $prepostpagecount = 8; | |
2918 | // Minimum pages where pagination does not happen | |
2919 | $paginationat = 16; // 16 pages is a /20, 32 is a /19 | |
2920 | $maxperpage = getConfigVar ('IPV4_ADDRS_PER_PAGE'); | |
2921 | if ($numpages <= $paginationat) | |
2922 | { | |
2923 | // create original pagination | |
2924 | for ($i = 0; $i < $numpages; $i++) | |
2925 | if ($i == $page) | |
2926 | $rendered_pager .= "<b>".$i."</b> "; | |
2927 | else | |
2928 | $rendered_pager .= renderIPv4NetworkPageLink($rangeid, $i, ip4_format(ip4_int2bin($startip + $i * $maxperpage))); | |
2929 | } | |
2930 | else // number of pages > page range, create ranged pagination | |
2931 | { | |
2932 | // page is within first subset | |
2933 | if ($page - $prepostpagecount <= 1) | |
2934 | { | |
2935 | for ($i = 0; $i < $page; $i++) | |
2936 | $rendered_pager .= renderIPv4NetworkPageLink($rangeid, $i, ip4_format(ip4_int2bin($startip + $i * $maxperpage))); | |
2937 | } | |
2938 | // render 0 ... [page - prepostpagecount] [page - prepostpagecount + 1] ... [page - 1] | |
2939 | else | |
2940 | { | |
2941 | $rendered_pager .= renderIPv4NetworkPageLink($rangeid, 0, ip4_format(ip4_int2bin($startip))); | |
2942 | $rendered_pager .= "... "; | |
2943 | for ($i = $page - $prepostpagecount; $i < $page; $i++) | |
2944 | $rendered_pager .= renderIPv4NetworkPageLink($rangeid, $i, ip4_format(ip4_int2bin($startip + $i * $maxperpage))); | |
2945 | } | |
2946 | // render current page | |
2947 | $rendered_pager .= "<b>".$page."</b> "; | |
2948 | // page is within last subset | |
2949 | if ($page + $prepostpagecount >= $numpages-2) | |
2950 | { | |
2951 | for ($i = $page+1; $i < $numpages; $i++) | |
2952 | $rendered_pager .= renderIPv4NetworkPageLink($rangeid, $i, ip4_format(ip4_int2bin($startip + $i * $maxperpage))); | |
2953 | } | |
2954 | // render [page + 1] [page + 2] ... [page + postpagecount] ... [end page] | |
2955 | else | |
2956 | { | |
2957 | for ($i = $page+1; $i <= $page+$prepostpagecount; $i++) | |
2958 | $rendered_pager .= renderIPv4NetworkPageLink($rangeid, $i, ip4_format(ip4_int2bin($startip + $i * $maxperpage))); | |
2959 | $rendered_pager .= "... "; | |
2960 | $rendered_pager .= renderIPv4NetworkPageLink($rangeid, ($numpages-1), ip4_format(ip4_int2bin($endip))); | |
2961 | } | |
2962 | } | |
2963 | return $rendered_pager; | |
2964 | } | |
2965 | ||
4318ced5 AA |
2966 | function renderIPv4NetworkAddresses ($range) |
2967 | { | |
9d5f6a80 | 2968 | global $pageno, $tabno, $aac_left; |
4318ced5 AA |
2969 | $startip = ip4_bin2int ($range['ip_bin']); |
2970 | $endip = ip4_bin2int (ip_last ($range)); | |
2971 | ||
2972 | if (isset ($_REQUEST['hl_ip'])) | |
00276508 | 2973 | { |
4318ced5 AA |
2974 | $hl_ip = ip4_bin2int (ip4_parse ($_REQUEST['hl_ip'])); |
2975 | addAutoScrollScript ('ip-' . $_REQUEST['hl_ip']); // scroll page to highlighted ip | |
00276508 AA |
2976 | } |
2977 | ||
79b57b18 AA |
2978 | // pager |
2979 | $maxperpage = getConfigVar ('IPV4_ADDRS_PER_PAGE'); | |
2980 | $address_count = $endip - $startip + 1; | |
2981 | $page = 0; | |
446c25c3 | 2982 | $rendered_pager = ''; |
79b57b18 AA |
2983 | if ($address_count > $maxperpage && $maxperpage > 0) |
2984 | { | |
2985 | $page = isset ($_REQUEST['pg']) ? $_REQUEST['pg'] : (isset ($hl_ip) ? intval (($hl_ip - $startip) / $maxperpage) : 0); | |
2986 | if ($numpages = ceil ($address_count / $maxperpage)) | |
2987 | { | |
4318ced5 | 2988 | echo '<h3>' . ip4_format (ip4_int2bin ($startip)) . ' ~ ' . ip4_format (ip4_int2bin ($endip)) . '</h3>'; |
247acd67 | 2989 | $rendered_pager = renderIPv4NetworkPagination ($range, $page, $numpages); |
79b57b18 AA |
2990 | } |
2991 | $startip = $startip + $page * $maxperpage; | |
2992 | $endip = min ($startip + $maxperpage - 1, $endip); | |
2993 | } | |
2994 | ||
446c25c3 | 2995 | echo $rendered_pager; |
beb9e88a | 2996 | echo "<table class='widetable' border=0 cellspacing=0 cellpadding=5 align='center' width='100%'>\n"; |
cc2fa820 | 2997 | echo "<tr><th>Address</th><th>Name</th><th>Comment</th><th>Allocation</th></tr>\n"; |
e673ee24 | 2998 | |
4318ced5 AA |
2999 | markupIPAddrList ($range['addrlist']); |
3000 | for ($ip = $startip; $ip <= $endip; $ip++) | |
3001 | { | |
3002 | $ip_bin = ip4_int2bin ($ip); | |
3003 | $dottedquad = ip4_format ($ip_bin); | |
5c717ce5 | 3004 | $tr_class = (isset ($hl_ip) && $hl_ip == $ip ? 'highlight' : ''); |
0cd7c0f6 AA |
3005 | if (isset ($range['addrlist'][$ip_bin])) |
3006 | $addr = $range['addrlist'][$ip_bin]; | |
3007 | else | |
e673ee24 | 3008 | { |
235124a6 | 3009 | 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 |
3010 | $editable = permitted ('ipaddress', 'properties', 'editAddress') |
3011 | ? 'editable' | |
3012 | : ''; | |
cc2fa820 AD |
3013 | echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-name'></span></td>"; |
3014 | echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-comment'></span></td><td></td></tr>\n"; | |
b2035dca DO |
3015 | continue; |
3016 | } | |
68c91b9c AA |
3017 | // render IP change history |
3018 | $title = ''; | |
3019 | $history_class = ''; | |
3020 | if (isset ($addr['last_log'])) | |
3021 | { | |
3022 | $title = ' title="' . htmlspecialchars ($addr['last_log']['user'] . ', ' . formatAge ($addr['last_log']['time']) , ENT_QUOTES) . '"'; | |
3023 | $history_class = 'hover-history underline'; | |
3024 | } | |
4318ced5 AA |
3025 | $tr_class .= ' ' . $addr['class']; |
3026 | echo "<tr class='tdleft $tr_class'>"; | |
235124a6 | 3027 | echo "<td><a class='$history_class' $title name='ip-$dottedquad' href='".makeHref(array('page'=>'ipaddress', 'ip'=>$addr['ip']))."'>${addr['ip']}</a></td>"; |
0b8d8309 | 3028 | $editable = |
cc2fa820 | 3029 | (empty ($addr['allocs']) || !empty ($addr['name']) || !empty ($addr['comment'])) |
0b8d8309 AA |
3030 | && permitted ('ipaddress', 'properties', 'editAddress') |
3031 | ? 'editable' | |
3032 | : ''; | |
cc2fa820 AD |
3033 | echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-name'>${addr['name']}</span></td>"; |
3034 | echo "<td><span class='rsvtext $editable id-$dottedquad op-upd-ip-comment'>${addr['comment']}</span></td>"; | |
0b8d8309 | 3035 | echo "<td>"; |
b2035dca | 3036 | $delim = ''; |
b2035dca DO |
3037 | if ( $addr['reserved'] == 'yes') |
3038 | { | |
2d318652 | 3039 | echo "<strong>RESERVED</strong> "; |
b2035dca DO |
3040 | $delim = '; '; |
3041 | } | |
212b565a | 3042 | foreach ($addr['allocs'] as $ref) |
b2035dca | 3043 | { |
9d5f6a80 | 3044 | echo $delim . $aac_left[$ref['type']]; |
e749a34f | 3045 | echo makeIPAllocLink ($ip_bin, $ref, TRUE); |
b2035dca DO |
3046 | $delim = '; '; |
3047 | } | |
3048 | if ($delim != '') | |
e0d6e38e | 3049 | $delim = '<br>'; |
212b565a AA |
3050 | foreach ($addr['vslist'] as $vs_id) |
3051 | { | |
3052 | $vs = spotEntity ('ipv4vs', $vs_id); | |
ad3e5e7e | 3053 | echo $delim . mkA ("${vs['name']}:${vs['vport']}/${vs['proto']}", 'ipv4vs', $vs['id']) . '→'; |
212b565a AA |
3054 | $delim = '<br>'; |
3055 | } | |
eacc0983 AA |
3056 | foreach ($addr['vsglist'] as $vs_id) |
3057 | { | |
3058 | $vs = spotEntity ('ipvs', $vs_id); | |
3059 | echo $delim . mkA ($vs['name'], 'ipvs', $vs['id']) . '→'; | |
3060 | $delim = '<br>'; | |
3061 | } | |
212b565a AA |
3062 | foreach ($addr['rsplist'] as $rsp_id) |
3063 | { | |
3064 | $rsp = spotEntity ('ipv4rspool', $rsp_id); | |
ad3e5e7e | 3065 | echo "${delim}→" . mkA ($rsp['name'], 'ipv4rspool', $rsp['id']); |
212b565a AA |
3066 | $delim = '<br>'; |
3067 | } | |
b2035dca | 3068 | echo "</td></tr>\n"; |
4318ced5 | 3069 | } |
2727c7df | 3070 | // end of iteration |
a8dc2982 AA |
3071 | if (permitted (NULL, NULL, 'set_reserve_comment')) |
3072 | addJS ('js/inplace-edit.js'); | |
e673ee24 DO |
3073 | |
3074 | echo "</table>"; | |
b956dd24 | 3075 | if ($rendered_pager != '') |
446c25c3 | 3076 | echo '<p>' . $rendered_pager . '</p>'; |
21ee3351 AA |
3077 | } |
3078 | ||
3079 | function renderIPv6NetworkAddresses ($netinfo) | |
3080 | { | |
9d5f6a80 | 3081 | global $pageno, $tabno, $aac_left; |
21ee3351 | 3082 | echo "<table class='widetable' border=0 cellspacing=0 cellpadding=5 align='center' width='100%'>\n"; |
cc2fa820 | 3083 | echo "<tr><th>Address</th><th>Name</th><th>Comment</th><th>Allocation</th></tr>\n"; |
21ee3351 | 3084 | |
4318ced5 AA |
3085 | $hl_ip = NULL; |
3086 | if (isset ($_REQUEST['hl_ip'])) | |
3087 | { | |
3088 | $hl_ip = ip6_parse ($_REQUEST['hl_ip']); | |
3089 | addAutoScrollScript ('ip-' . ip6_format ($hl_ip)); | |
3090 | } | |
21ee3351 | 3091 | |
21ee3351 AA |
3092 | $addresses = $netinfo['addrlist']; |
3093 | ksort ($addresses); | |
4318ced5 | 3094 | markupIPAddrList ($addresses); |
21ee3351 AA |
3095 | |
3096 | // pager | |
3097 | $maxperpage = getConfigVar ('IPV4_ADDRS_PER_PAGE'); | |
3098 | if (count ($addresses) > $maxperpage && $maxperpage > 0) | |
3099 | { | |
3100 | $page = isset ($_REQUEST['pg']) ? $_REQUEST['pg'] : (isset ($hl_ip) ? getPageNumOfIPv6 ($addresses, $hl_ip, $maxperpage) : 0); | |
3101 | $numpages = ceil (count ($addresses) / $maxperpage); | |
3102 | echo "<center><h3>$numpages pages:</h3>"; | |
3103 | for ($i=0; $i<$numpages; $i++) | |
3104 | { | |
3105 | if ($i == $page) | |
3106 | echo "<b>$i</b> "; | |
3107 | else | |
3108 | echo "<a href='" . makeHref (array ('page' => $pageno, 'tab' => $tabno, 'id' => $netinfo['id'], 'pg' => $i)) . "'>$i</a> "; | |
3109 | } | |
3110 | echo "</center>"; | |
3111 | } | |
3112 | ||
3113 | $i = 0; | |
dec748f6 | 3114 | $interruped = FALSE; |
4318ced5 AA |
3115 | $prev_ip = ip_prev ($netinfo['ip_bin']); |
3116 | foreach ($addresses as $ip_bin => $addr) | |
21ee3351 AA |
3117 | { |
3118 | if (isset ($page)) | |
3119 | { | |
3120 | ++$i; | |
3121 | if ($i <= $maxperpage * $page) | |
3122 | continue; | |
3123 | elseif ($i > $maxperpage * ($page + 1)) | |
3124 | { | |
3125 | $interruped = TRUE; | |
3126 | break; | |
3127 | } | |
3128 | } | |
3129 | ||
4318ced5 AA |
3130 | if ($ip_bin != ip_next ($prev_ip)) |
3131 | renderSeparator (ip_next ($prev_ip), ip_prev ($ip_bin), $hl_ip); | |
3132 | $prev_ip = $ip_bin; | |
3133 | ||
3134 | // render IP change history | |
3135 | $title = ''; | |
3136 | $history_class = ''; | |
3137 | if (isset ($addr['last_log'])) | |
3138 | { | |
3139 | $title = ' title="' . htmlspecialchars ($addr['last_log']['user'] . ', ' . formatAge ($addr['last_log']['time']) , ENT_QUOTES) . '"'; | |
3140 | $history_class = 'hover-history underline'; | |
3141 | } | |
3142 | ||