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