Revision 52398a6b
Added by Jim Pingle about 11 years ago
etc/inc/gmirror.inc | ||
---|---|---|
1 |
<?php |
|
2 |
/* |
|
3 |
gmirror.inc |
|
4 |
Copyright (C) 2009-2014 Jim Pingle |
|
5 |
|
|
6 |
Redistribution and use in source and binary forms, with or without |
|
7 |
modification, are permitted provided that the following conditions are met: |
|
8 |
|
|
9 |
1. Redistributions of source code must retain the above copyright notice, |
|
10 |
this list of conditions and the following disclaimer. |
|
11 |
|
|
12 |
2. Redistributions in binary form must reproduce the above copyright |
|
13 |
notice, this list of conditions and the following disclaimer in the |
|
14 |
documentation and/or other materials provided with the distribution. |
|
15 |
|
|
16 |
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, |
|
17 |
INClUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY |
|
18 |
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
|
19 |
AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, |
|
20 |
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
21 |
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
22 |
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|
23 |
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
24 |
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
25 |
POSSIBILITY OF SUCH DAMAGE. |
|
26 |
*/ |
|
27 |
|
|
28 |
global $balance_methods; |
|
29 |
$balance_methods = array("load", "prefer", "round-robin", "split"); |
|
30 |
|
|
31 |
/* Create a status array for each mirror and its disk components. */ |
|
32 |
function gmirror_get_status() { |
|
33 |
$status = ""; |
|
34 |
exec("/sbin/gmirror status -s", $status); |
|
35 |
$mirrors = array(); |
|
36 |
|
|
37 |
/* Empty output = no mirrors found */ |
|
38 |
if (count($status) > 0) { |
|
39 |
/* Loop through gmirror status output. */ |
|
40 |
foreach ($status as $line) { |
|
41 |
/* Split the line by whitespace */ |
|
42 |
$all = preg_split("/[\s\t]+/", trim($line), 3); |
|
43 |
if (count($all) == 3) { |
|
44 |
/* If there are three items on a line, it is mirror name, status, and component */ |
|
45 |
$currentmirror = basename($all[0]); |
|
46 |
$mirrors[$currentmirror]['name'] = basename($all[0]); |
|
47 |
$mirrors[$currentmirror]['status'] = $all[1]; |
|
48 |
if (!is_array($mirrors[$currentmirror]['components'])) |
|
49 |
$mirrors[$currentmirror]['components'] = array(); |
|
50 |
$mirrors[$currentmirror]['components'][] = $all[2]; |
|
51 |
} |
|
52 |
} |
|
53 |
} |
|
54 |
/* Return an hash of mirrors and components */ |
|
55 |
return $mirrors; |
|
56 |
} |
|
57 |
|
|
58 |
/* Get only status word for a single mirror. */ |
|
59 |
function gmirror_get_status_single($mirror) { |
|
60 |
$status = ""; |
|
61 |
$mirror_status = gmirror_get_status(); |
|
62 |
var_dump($mirror_status); |
|
63 |
return $mirror_status[$mirror]['status']; |
|
64 |
} |
|
65 |
|
|
66 |
/* Generate an HTML formatted status for mirrors and disks in a small format for the widget */ |
|
67 |
function gmirror_html_status() { |
|
68 |
$mirrors = gmirror_get_status(); |
|
69 |
$output = ""; |
|
70 |
if (count($mirrors) > 0) { |
|
71 |
$output .= "<tr>\n"; |
|
72 |
$output .= "<td width=\"40%\" class=\"vncellt\">Name</td>\n"; |
|
73 |
$output .= "<td width=\"40%\" class=\"vncellt\">Status</td>\n"; |
|
74 |
$output .= "<td width=\"20%\" class=\"vncellt\">Component</td>\n"; |
|
75 |
$output .= "</tr>\n"; |
|
76 |
foreach ($mirrors as $mirror => $name) { |
|
77 |
$components = count($name["components"]); |
|
78 |
$output .= "<tr>\n"; |
|
79 |
$output .= "<td width=\"40%\" rowspan=\"{$components}\" class=\"listr\">{$name['name']}</td>\n"; |
|
80 |
$output .= "<td width=\"40%\" rowspan=\"{$components}\" class=\"listr\">{$name['status']}</td>\n"; |
|
81 |
$output .= "<td width=\"20%\" class=\"listr\">{$name['components'][0]}</td>\n"; |
|
82 |
$output .= "</tr>\n"; |
|
83 |
if (count($name["components"]) > 1) { |
|
84 |
$morecomponents = array_slice($name["components"], 1); |
|
85 |
foreach ($morecomponents as $component) { |
|
86 |
$output .= "<tr>\n"; |
|
87 |
$output .= "<td width=\"20%\" class=\"listr\">{$component}</td>\n"; |
|
88 |
$output .= "</tr>\n"; |
|
89 |
} |
|
90 |
} |
|
91 |
} |
|
92 |
} else { |
|
93 |
$output .= "<tr><td colspan=\"3\" class=\"listr\">No Mirrors Found</td></tr>\n"; |
|
94 |
} |
|
95 |
// $output .= "<tr><td colspan=\"3\" class=\"listr\">Updated at " . date("F j, Y, g:i:s a") . "</td></tr>\n"; |
|
96 |
return $output; |
|
97 |
} |
|
98 |
|
|
99 |
/* List all disks in the system (potential gmirror targets) */ |
|
100 |
function gmirror_get_disks() { |
|
101 |
$disklist = ""; |
|
102 |
/* Get a list of disks in a scriptable way, exclude optical drives */ |
|
103 |
exec("/sbin/geom disk status -s | /usr/bin/grep -v '[[:blank:]]*cd[[:digit:]]*' | /usr/bin/awk '{print $1;}'", $disklist); |
|
104 |
return $disklist; |
|
105 |
} |
|
106 |
|
|
107 |
/* List all potential gmirror consumers */ |
|
108 |
function gmirror_get_unused_consumers() { |
|
109 |
$consumerlist = ""; |
|
110 |
/* Get a list of consumers, exclude existing mirrors and diskid entries */ |
|
111 |
exec("/sbin/geom part status -s | /usr/bin/egrep -v '(mirror|diskid)' | /usr/bin/awk '{print $1, $3;}'", $consumerlist); |
|
112 |
$all_consumers = array(); |
|
113 |
foreach ($consumerlist as $cl) { |
|
114 |
$parts = explode(" ", $cl); |
|
115 |
foreach ($parts as $part) |
|
116 |
$all_consumers[] = $part; |
|
117 |
} |
|
118 |
return $all_consumers; |
|
119 |
} |
|
120 |
|
|
121 |
/* List all existing geom mirrors */ |
|
122 |
function gmirror_get_mirrors() { |
|
123 |
$mirrorlist = ""; |
|
124 |
exec("/sbin/gmirror list | /usr/bin/grep '^Geom name:' | /usr/bin/awk '{print $3;}'", $mirrorlist); |
|
125 |
return $mirrorlist; |
|
126 |
} |
|
127 |
|
|
128 |
|
|
129 |
/* List all consumers for a given mirror */ |
|
130 |
function gmirror_get_consumers_in_mirror($mirror) { |
|
131 |
if (!is_valid_mirror($mirror)) |
|
132 |
return array(); |
|
133 |
|
|
134 |
$consumers = array(); |
|
135 |
exec("/sbin/gmirror status -s " . escapeshellarg($mirror) . " | /usr/bin/awk '{print $3;}'", $consumers); |
|
136 |
return $consumers; |
|
137 |
} |
|
138 |
|
|
139 |
/* Test if a given consumer is a member of an existing mirror */ |
|
140 |
function is_consumer_in_mirror($consumer, $mirror) { |
|
141 |
if (!is_valid_consumer($consumer) || !is_valid_mirror($mirror)) |
|
142 |
return false; |
|
143 |
|
|
144 |
$mirrorconsumers = gmirror_get_consumers_in_mirror($mirror); |
|
145 |
return in_array(basename($consumer), $mirrorconsumers); |
|
146 |
} |
|
147 |
|
|
148 |
/* Test if a mirror exists */ |
|
149 |
function is_valid_mirror($mirror) { |
|
150 |
$mirrors = gmirror_get_mirrors(); |
|
151 |
return in_array($mirror, $mirrors); |
|
152 |
} |
|
153 |
|
|
154 |
/* Test if a disk is valid/exists */ |
|
155 |
function is_valid_disk($disk) { |
|
156 |
$adisks = gmirror_get_disks(); |
|
157 |
return in_array(basename($disk), $adisks); |
|
158 |
} |
|
159 |
|
|
160 |
/* Test if a consumer is valid and in use in a mirror */ |
|
161 |
function is_consumer_used($consumer) { |
|
162 |
$found = false; |
|
163 |
$mirrors = gmirror_get_mirrors(); |
|
164 |
foreach ($mirrors as $mirror) { |
|
165 |
$consumers = gmirror_get_consumers_in_mirror($mirror); |
|
166 |
if (in_array($consumer, $consumers)) |
|
167 |
return true; |
|
168 |
} |
|
169 |
return false; |
|
170 |
} |
|
171 |
|
|
172 |
/* Test if a consumer is valid and not in use */ |
|
173 |
function is_consumer_unused($consumer) { |
|
174 |
$consumers = gmirror_get_unused_consumers(); |
|
175 |
return in_array($consumer, $consumers); |
|
176 |
} |
|
177 |
|
|
178 |
/* Test if a consumer is valid (either a disk or partition) */ |
|
179 |
function is_valid_consumer($consumer) { |
|
180 |
return (is_consumer_unused($consumer) || is_consumer_used($consumer)); |
|
181 |
} |
|
182 |
|
|
183 |
/* Remove all disconnected drives from a mirror */ |
|
184 |
function gmirror_forget_disconnected($mirror) { |
|
185 |
if (!is_valid_mirror($mirror)) |
|
186 |
return false; |
|
187 |
return mwexec("/sbin/gmirror forget " . escapeshellarg($mirror)); |
|
188 |
} |
|
189 |
|
|
190 |
/* Insert another consumer into a mirror */ |
|
191 |
function gmirror_insert_consumer($mirror, $consumer) { |
|
192 |
if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) |
|
193 |
return false; |
|
194 |
return mwexec("/sbin/gmirror insert " . escapeshellarg($mirror) . " " . escapeshellarg($consumer)); |
|
195 |
} |
|
196 |
|
|
197 |
/* Remove consumer from a mirror and clear its metadata */ |
|
198 |
function gmirror_remove_consumer($mirror, $consumer) { |
|
199 |
if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) |
|
200 |
return false; |
|
201 |
return mwexec("/sbin/gmirror remove " . escapeshellarg($mirror) . " " . escapeshellarg($consumer)); |
|
202 |
} |
|
203 |
|
|
204 |
/* Wipe geom info from drive (if mirror is not running) */ |
|
205 |
function gmirror_clear_consumer($consumer) { |
|
206 |
if (!is_valid_consumer($consumer)) |
|
207 |
return false; |
|
208 |
return mwexec("/sbin/gmirror clear " . escapeshellarg($consumer)); |
|
209 |
} |
|
210 |
|
|
211 |
/* Find the balance method used by a given mirror */ |
|
212 |
function gmirror_get_mirror_balance($mirror) { |
|
213 |
if (!is_valid_mirror($mirror)) |
|
214 |
return false; |
|
215 |
$balancemethod = ""; |
|
216 |
exec("/sbin/gmirror list " . escapeshellarg($mirror) . " | /usr/bin/grep '^Balance:' | /usr/bin/awk '{print $2;}'", $balancemethod); |
|
217 |
return $balancemethod[0]; |
|
218 |
} |
|
219 |
|
|
220 |
/* Change balance algorithm of the mirror */ |
|
221 |
function gmirror_configure_balance($mirror, $balancemethod) { |
|
222 |
if (!is_valid_mirror($mirror) || !in_array($balancemethod, $balancemethods)) |
|
223 |
return false; |
|
224 |
return mwexec("/sbin/gmirror configure -b " . escapeshellarg($balancemethod) . " " . escapeshellarg($mirror)); |
|
225 |
} |
|
226 |
|
|
227 |
/* Force a mirror member to rebuild */ |
|
228 |
function gmirror_force_rebuild($mirror, $consumer) { |
|
229 |
if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) |
|
230 |
return false; |
|
231 |
return mwexec("/sbin/gmirror rebuild " . escapeshellarg($mirror) . " " . escapeshellarg($consumer)); |
|
232 |
} |
|
233 |
|
|
234 |
/* Show all metadata on the physical consumer */ |
|
235 |
function gmirror_get_consumer_metadata($consumer) { |
|
236 |
if (!is_valid_consumer($consumer)) |
|
237 |
return array(); |
|
238 |
$output = ""; |
|
239 |
exec("/sbin/gmirror dump " . escapeshellarg($consumer), $output); |
|
240 |
return array_map('trim', $output); |
|
241 |
} |
|
242 |
|
|
243 |
/* Test if a consumer has metadata, indicating it is a member of a mirror (active or inactive) */ |
|
244 |
function gmirror_consumer_has_metadata($consumer) { |
|
245 |
return (count(gmirror_get_consumer_metadata($consumer)) > 0); |
|
246 |
} |
|
247 |
|
|
248 |
/* Find the mirror to which this consumer belongs */ |
|
249 |
function gmirror_get_consumer_metadata_mirror($consumer) { |
|
250 |
if (!is_valid_consumer($consumer)) |
|
251 |
return array(); |
|
252 |
$metadata = gmirror_get_consumer_metadata($consumer); |
|
253 |
foreach ($metadata as $line) { |
|
254 |
if (substr($line, 0, 5) == "name:") { |
|
255 |
list ($key, $value) = explode(":", $line, 2); |
|
256 |
return trim($value); |
|
257 |
} |
|
258 |
} |
|
259 |
} |
|
260 |
|
|
261 |
/* Deactivate consumer, removing it from service in the mirror, but leave metadata intact */ |
|
262 |
function gmirror_deactivate_consumer($mirror, $consumer) { |
|
263 |
if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) |
|
264 |
return false; |
|
265 |
return mwexec("/sbin/gmirror deactivate " . escapeshellarg($mirror) . " " . escapeshellarg($consumer)); |
|
266 |
} |
|
267 |
|
|
268 |
/* Reactivate a deactivated consumer */ |
|
269 |
function gmirror_activate_consumer($mirror, $consumer) { |
|
270 |
if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) |
|
271 |
return false; |
|
272 |
return mwexec("/sbin/gmirror activate " . escapeshellarg($mirror) . " " . escapeshellarg($consumer)); |
|
273 |
} |
|
274 |
|
|
275 |
/* Find the size of the given mirror */ |
|
276 |
function gmirror_get_mirror_size($mirror) { |
|
277 |
if (!is_valid_mirror($mirror)) |
|
278 |
return false; |
|
279 |
$mirrorsize = ""; |
|
280 |
exec("/sbin/gmirror list " . escapeshellarg($mirror) . " | /usr/bin/grep 'Mediasize:' | /usr/bin/head -n 1 | /usr/bin/awk '{print $2;}'", $mirrorsize); |
|
281 |
return $mirrorsize[0]; |
|
282 |
} |
|
283 |
|
|
284 |
/* Return a list of all potential consumers on a disk with sizes. The geom part |
|
285 |
list output is a little odd, we can't get the output for just the disk, if the disk contains |
|
286 |
slices those get output also. */ |
|
287 |
function gmirror_get_all_unused_consumer_sizes_on_disk($disk) { |
|
288 |
if (!is_valid_disk($disk) || !is_consumer_unused($disk)) |
|
289 |
return array(); |
|
290 |
$output = ""; |
|
291 |
exec("/sbin/geom part list " . escapeshellarg($disk) . " | /usr/bin/egrep '(Name:|Mediasize:)' | /usr/bin/cut -c4- | /usr/bin/sed -l -e 'N;s/\\nMediasize://;P;D;' | /usr/bin/cut -c7-", $output); |
|
292 |
$disk_contents = array(); |
|
293 |
foreach ($output as $line) { |
|
294 |
list($name, $size, $humansize) = explode(" ", $line, 3); |
|
295 |
$consumer = array(); |
|
296 |
$consumer['name'] = $name; |
|
297 |
$consumer['size'] = $size; |
|
298 |
$consumer['humansize'] = $humansize; |
|
299 |
$disk_contents[] = $consumer; |
|
300 |
} |
|
301 |
return $disk_contents; |
|
302 |
} |
|
303 |
|
|
304 |
/* Get only the size for one specific potential consumer. */ |
|
305 |
function gmirror_get_unused_consumer_size($consumer) { |
|
306 |
$consumersizes = gmirror_get_all_unused_consumer_sizes_on_disk($consumer); |
|
307 |
foreach ($consumersizes as $csize) { |
|
308 |
if ($csize['name'] == $consumer) |
|
309 |
return $csize['size']; |
|
310 |
} |
|
311 |
return -1; |
|
312 |
} |
|
313 |
?> |
etc/rc | ||
---|---|---|
443 | 443 |
|
444 | 444 |
/bin/chmod a+rw /tmp/. |
445 | 445 |
|
446 |
# Check for GEOM mirrors |
|
447 |
GMIRROR_STATUS=`/sbin/gmirror status` |
|
448 |
if [ "${GMIRROR_STATUS}" != "" ]; then |
|
449 |
# Using a flag file at bootup saves an expensive exec/check on each page load. |
|
450 |
/usr/bin/touch /var/run/gmirror_active |
|
451 |
# Setup monitoring/notifications |
|
452 |
/usr/local/bin/minicron 60 /var/run/gmirror_status_check.pid /usr/local/sbin/gmirror_status_check.php |
|
453 |
fi |
|
454 |
|
|
446 | 455 |
echo "Bootup complete" |
447 | 456 |
|
448 | 457 |
/usr/local/bin/beep.sh start 2>&1 >/dev/null |
usr/local/sbin/gmirror_status_check.php | ||
---|---|---|
1 |
#!/usr/local/bin/php -f |
|
2 |
<?php |
|
3 |
/* |
|
4 |
diag_gmirror.php |
|
5 |
Copyright (C) 2014 Jim Pingle |
|
6 |
|
|
7 |
Redistribution and use in source and binary forms, with or without |
|
8 |
modification, are permitted provided that the following conditions are met: |
|
9 |
|
|
10 |
1. Redistributions of source code must retain the above copyright notice, |
|
11 |
this list of conditions and the following disclaimer. |
|
12 |
|
|
13 |
2. Redistributions in binary form must reproduce the above copyright |
|
14 |
notice, this list of conditions and the following disclaimer in the |
|
15 |
documentation and/or other materials provided with the distribution. |
|
16 |
|
|
17 |
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, |
|
18 |
INClUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY |
|
19 |
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
|
20 |
AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, |
|
21 |
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
22 |
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
23 |
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|
24 |
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
25 |
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
26 |
POSSIBILITY OF SUCH DAMAGE. |
|
27 |
*/ |
|
28 |
|
|
29 |
/* |
|
30 |
pfSense_BUILDER_BINARIES: /sbin/gmirror /sbin/geom /usr/bin/grep /usr/bin/egrep /usr/bin/cut /usr/bin/head |
|
31 |
pfSense_BUILDER_BINARIES: /sbin/mount /usr/bin/awk /usr/bin/sed |
|
32 |
pfSense_MODULE: gmirror |
|
33 |
*/ |
|
34 |
|
|
35 |
require_once("config.inc"); |
|
36 |
require_once("notices.inc"); |
|
37 |
require_once("globals.inc"); |
|
38 |
require_once("gmirror.inc"); |
|
39 |
|
|
40 |
global $g; |
|
41 |
$status_file = "{$g['varrun_path']}/gmirror.status"; |
|
42 |
|
|
43 |
$mirror_status = gmirror_get_status(); |
|
44 |
$mirror_list = array_keys($mirror_status); |
|
45 |
sort($mirror_list); |
|
46 |
$notices = array(); |
|
47 |
|
|
48 |
// Check for gmirror.status |
|
49 |
if (file_exists($status_file)) { |
|
50 |
// If it exists, read status in |
|
51 |
$previous_mirror_status = unserialize(file_get_contents($status_file)); |
|
52 |
$previous_mirror_list = array_keys($previous_mirror_status); |
|
53 |
sort($previous_mirror_list); |
|
54 |
if (count($previous_mirror_status) > 0) { |
|
55 |
// Check list of current mirrors vs old mirrors, notify if one has appeared/disappeared |
|
56 |
if ($mirror_list != $previous_mirror_list) |
|
57 |
$notices[] = sprintf(gettext("List of mirrors changed. Old: (%s) New: (%s)"), implode(", ", $previous_mirror_list), implode(", ", $mirror_list)); |
|
58 |
|
|
59 |
// For each mirror, check the mirror status, notify if changed |
|
60 |
foreach ($mirror_list as $mirror) { |
|
61 |
if (is_array($previous_mirror_status[$mirror])) { |
|
62 |
// Notify if the status changed |
|
63 |
if ($mirror_status[$mirror]['status'] != $previous_mirror_status[$mirror]['status']) { |
|
64 |
$notices[] = sprintf(gettext("Mirror %s status changed from %s to %s."), $mirror, $previous_mirror_status[$mirror]['status'], $mirror_status[$mirror]['status']); |
|
65 |
} |
|
66 |
// Notify if the drive count changed |
|
67 |
if (count($mirror_status[$mirror]['components']) != count($previous_mirror_status[$mirror]['components'])) { |
|
68 |
// Notify if the consumer count changed. |
|
69 |
$notices[] = sprintf(gettext("Mirror %s consumer count changed from %d to %d."), $mirror, count($previous_mirror_status[$mirror]['components']), count($mirror_status[$mirror]['components'])); |
|
70 |
} |
|
71 |
if (strtoupper($mirror_status[$mirror]['status']) == "DEGRADED") { |
|
72 |
// Check the drive status as it may be different. |
|
73 |
asort($mirror_status[$mirror]['components']); |
|
74 |
asort($previous_mirror_status[$mirror]['components']); |
|
75 |
if ($mirror_status[$mirror]['components'] != $previous_mirror_status[$mirror]['components']) |
|
76 |
$notices[] = sprintf(gettext("Mirror %s drive status changed. Old: (%s) New: (%s)"), |
|
77 |
$mirror, |
|
78 |
implode(", ", $previous_mirror_status[$mirror]['components']), |
|
79 |
implode(", ", $mirror_status[$mirror]['components'])); |
|
80 |
} |
|
81 |
} |
|
82 |
} |
|
83 |
} |
|
84 |
} |
|
85 |
if (count($notices)) { |
|
86 |
file_notice("gmirror", implode("\n ", $notices), "GEOM Mirror Status Change", 1); |
|
87 |
} |
|
88 |
// Write out current status if changed |
|
89 |
if ($mirror_status != $previous_mirror_status) |
|
90 |
file_put_contents($status_file, serialize($mirror_status)); |
|
91 |
|
|
92 |
?> |
usr/local/www/diag_gmirror.php | ||
---|---|---|
1 |
<?php |
|
2 |
/* |
|
3 |
diag_gmirror.php |
|
4 |
Copyright (C) 2014 Jim Pingle |
|
5 |
|
|
6 |
Redistribution and use in source and binary forms, with or without |
|
7 |
modification, are permitted provided that the following conditions are met: |
|
8 |
|
|
9 |
1. Redistributions of source code must retain the above copyright notice, |
|
10 |
this list of conditions and the following disclaimer. |
|
11 |
|
|
12 |
2. Redistributions in binary form must reproduce the above copyright |
|
13 |
notice, this list of conditions and the following disclaimer in the |
|
14 |
documentation and/or other materials provided with the distribution. |
|
15 |
|
|
16 |
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, |
|
17 |
INClUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY |
|
18 |
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
|
19 |
AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, |
|
20 |
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
21 |
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
22 |
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|
23 |
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
24 |
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
25 |
POSSIBILITY OF SUCH DAMAGE. |
|
26 |
*/ |
|
27 |
|
|
28 |
/* |
|
29 |
pfSense_BUILDER_BINARIES: /sbin/gmirror /sbin/geom /usr/bin/grep /usr/bin/egrep /usr/bin/cut /usr/bin/head |
|
30 |
pfSense_BUILDER_BINARIES: /sbin/mount /usr/bin/awk /usr/bin/sed |
|
31 |
pfSense_MODULE: gmirror |
|
32 |
*/ |
|
33 |
|
|
34 |
##|+PRIV |
|
35 |
##|*IDENT=page-diagnostics-gmirror |
|
36 |
##|*NAME=Diagnostics: GEOM Mirrors |
|
37 |
##|*DESCR=Allow access to the 'Diagnostics: GEOM Mirrors' page. |
|
38 |
##|*MATCH=diag_gmirror.php* |
|
39 |
##|-PRIV |
|
40 |
|
|
41 |
require_once("guiconfig.inc"); |
|
42 |
require_once("config.inc"); |
|
43 |
require_once("gmirror.inc"); |
|
44 |
|
|
45 |
$pgtitle = array(gettext("Diagnostics"), gettext("GEOM Mirrors")); |
|
46 |
|
|
47 |
include("head.inc"); |
|
48 |
|
|
49 |
?> |
|
50 |
|
|
51 |
<body link="#0000CC" vlink="#0000CC" alink="#0000CC" onload="<?=$jsevents["body"]["onload"];?>"> |
|
52 |
|
|
53 |
<?php include("fbegin.inc"); ?> |
|
54 |
|
|
55 |
<?PHP |
|
56 |
$action_list = array( |
|
57 |
"forget" => gettext("Forget all formerly connected consumers"), |
|
58 |
"clear" => gettext("Remove metadata from disk"), |
|
59 |
"insert" => gettext("Insert consumer into mirror"), |
|
60 |
"remove" => gettext("Remove consumer from mirror"), |
|
61 |
"activate" => gettext("Reactivate consumer on mirror"), |
|
62 |
"deactivate" => gettext("Deactivate consumer from mirror"), |
|
63 |
"rebuild" => gettext("Force rebuild of mirror consumer"), |
|
64 |
); |
|
65 |
|
|
66 |
/* User tried to pass a bogus action */ |
|
67 |
if (!empty($_REQUEST['action']) && !array_key_exists($_REQUEST['action'], $action_list)) { |
|
68 |
header("Location: diag_gmirror.php"); |
|
69 |
return; |
|
70 |
} |
|
71 |
|
|
72 |
if ($_POST) { |
|
73 |
if (!isset($_POST['confirm']) || ($_POST['confirm'] != gettext("Confirm"))) { |
|
74 |
header("Location: diag_gmirror.php"); |
|
75 |
return; |
|
76 |
} |
|
77 |
$input_errors = ""; |
|
78 |
|
|
79 |
if (($_POST['action'] != "clear") && !is_valid_mirror($_POST['mirror'])) |
|
80 |
$input_errors[] = gettext("You must supply a valid mirror name."); |
|
81 |
|
|
82 |
if (!empty($_POST['consumer']) && !is_valid_consumer($_POST['consumer'])) |
|
83 |
$input_errors[] = gettext("You must supply a valid consumer name"); |
|
84 |
|
|
85 |
/* Additional action-specific validation that hasn't already been tested */ |
|
86 |
switch ($_POST['action']) { |
|
87 |
case "insert": |
|
88 |
if (!is_consumer_unused($_POST['consumer'])) |
|
89 |
$input_errors[] = gettext("Consumer is already in use and cannot be inserted. Remove consumer from existing mirror first."); |
|
90 |
if (gmirror_consumer_has_metadata($_POST['consumer'])) |
|
91 |
$input_errors[] = gettext("Consumer has metadata from an existing mirror. Clear metadata before inserting consumer."); |
|
92 |
$mstat = gmirror_get_status_single($_POST['mirror']); |
|
93 |
if (strtoupper($mstat) != "COMPLETE") |
|
94 |
$input_errors[] = gettext("Mirror is not in a COMPLETE state, cannot insert consumer. Forget disconnected disks or wait for rebuild to finish."); |
|
95 |
break; |
|
96 |
case "clear": |
|
97 |
if (!is_consumer_unused($_POST['consumer'])) |
|
98 |
$input_errors[] = gettext("Consumer is in use and cannot be cleared. Deactivate disk first."); |
|
99 |
if (!gmirror_consumer_has_metadata($_POST['consumer'])) |
|
100 |
$input_errors[] = gettext("Consumer has no metadata to clear."); |
|
101 |
break; |
|
102 |
case "activate": |
|
103 |
if (is_consumer_in_mirror($_POST['consumer'], $_POST['mirror'])) |
|
104 |
$input_errors[] = gettext("Consumer is already present on specified mirror."); |
|
105 |
if (!gmirror_consumer_has_metadata($_POST['consumer'])) |
|
106 |
$input_errors[] = gettext("Consumer has no metadata and cannot be reactivated."); |
|
107 |
|
|
108 |
break; |
|
109 |
case "remove": |
|
110 |
case "deactivate": |
|
111 |
case "rebuild": |
|
112 |
if (!is_consumer_in_mirror($_POST['consumer'], $_POST['mirror'])) |
|
113 |
$input_errors[] = gettext("Consumer must be present on the specified mirror."); |
|
114 |
break; |
|
115 |
} |
|
116 |
|
|
117 |
$result = 0; |
|
118 |
if (empty($input_errors)) { |
|
119 |
switch ($_POST['action']) { |
|
120 |
case "forget": |
|
121 |
$result = gmirror_forget_disconnected($_POST['mirror']); |
|
122 |
break; |
|
123 |
case "clear": |
|
124 |
$result = gmirror_clear_consumer($_POST['consumer']); |
|
125 |
break; |
|
126 |
case "insert": |
|
127 |
$result = gmirror_insert_consumer($_POST['mirror'], $_POST['consumer']); |
|
128 |
break; |
|
129 |
case "remove": |
|
130 |
$result = gmirror_remove_consumer($_POST['mirror'], $_POST['consumer']); |
|
131 |
break; |
|
132 |
case "activate": |
|
133 |
$result = gmirror_activate_consumer($_POST['mirror'], $_POST['consumer']); |
|
134 |
break; |
|
135 |
case "deactivate": |
|
136 |
$result = gmirror_deactivate_consumer($_POST['mirror'], $_POST['consumer']); |
|
137 |
break; |
|
138 |
case "rebuild": |
|
139 |
$result = gmirror_force_rebuild($_POST['mirror'], $_POST['consumer']); |
|
140 |
break; |
|
141 |
} |
|
142 |
$redir = "Location: diag_gmirror.php"; |
|
143 |
if ($result != 0) { |
|
144 |
$redir .= "?error=" . urlencode($result); |
|
145 |
} |
|
146 |
/* If we reload the page too fast, the gmirror information may be missing or not up-to-date. */ |
|
147 |
sleep(3); |
|
148 |
header($redir); |
|
149 |
return; |
|
150 |
} |
|
151 |
} |
|
152 |
|
|
153 |
$mirror_status = gmirror_get_status(); |
|
154 |
$mirror_list = gmirror_get_mirrors(); |
|
155 |
$unused_disks = gmirror_get_disks(); |
|
156 |
$unused_consumers = array(); |
|
157 |
foreach ($unused_disks as $disk) { |
|
158 |
if (is_consumer_unused($disk)) |
|
159 |
$unused_consumers = array_merge($unused_consumers, gmirror_get_all_unused_consumer_sizes_on_disk($disk)); |
|
160 |
} |
|
161 |
|
|
162 |
if ($input_errors) |
|
163 |
print_input_errors($input_errors); |
|
164 |
if ($_GET["error"] && ($_GET["error"] != 0)) |
|
165 |
print_info_box(gettext("There was an error performing the chosen mirror operation. Check the System Log for details.")); |
|
166 |
|
|
167 |
?> |
|
168 |
<form action="diag_gmirror.php" method="POST" id="gmirror_form" name="gmirror_form"> |
|
169 |
<table width="100%" border="0" cellpadding="0" cellspacing="0"> |
|
170 |
<tr> |
|
171 |
<td id="mainarea"> |
|
172 |
<div class="tabcont"> |
|
173 |
<span class="vexpl"> |
|
174 |
<span class="red"> |
|
175 |
<strong><?=gettext("NOTE:")?> </strong> |
|
176 |
</span> |
|
177 |
<?=gettext("The options on this page are intended for use by advanced users only. This page is for managing existing mirrors, not creating new mirrors.")?> |
|
178 |
<br /> |
|
179 |
</span> |
|
180 |
<p/> |
|
181 |
<table width="100%" border="0" cellpadding="6" cellspacing="0"> |
|
182 |
|
|
183 |
<?PHP if ($_GET["action"]): ?> |
|
184 |
<tr> |
|
185 |
<td colspan="2" valign="top" class="listtopic"><?PHP echo gettext("Confirm Action"); ?></td> |
|
186 |
</tr> |
|
187 |
<tr> |
|
188 |
<td width="22%" valign="top" class="vncell"> </td> |
|
189 |
<td width="78%" class="vtable"> |
|
190 |
<strong><?PHP echo gettext("Please confirm the selected action"); ?></strong>: |
|
191 |
<br /> |
|
192 |
<br /><strong><?PHP echo gettext("Action"); ?>:</strong> <?PHP echo $action_list[$_GET["action"]]; ?> |
|
193 |
<input type="hidden" name="action" value="<?PHP echo htmlspecialchars($_GET["action"]); ?>" /> |
|
194 |
<?PHP if (!empty($_GET["mirror"])): ?> |
|
195 |
<br /><strong><?PHP echo gettext("Mirror"); ?>:</strong> <?PHP echo htmlspecialchars($_GET["mirror"]); ?> |
|
196 |
<input type="hidden" name="mirror" value="<?PHP echo htmlspecialchars($_GET["mirror"]); ?>" /> |
|
197 |
<?PHP endif; ?> |
|
198 |
<?PHP if (!empty($_GET["consumer"])): ?> |
|
199 |
<br /><strong><?PHP echo gettext("Consumer"); ?>:</strong> <?PHP echo htmlspecialchars($_GET["consumer"]); ?> |
|
200 |
<input type="hidden" name="consumer" value="<?PHP echo htmlspecialchars($_GET["consumer"]); ?>" /> |
|
201 |
<?PHP endif; ?> |
|
202 |
<br /> |
|
203 |
<br /><input type="submit" name="confirm" value="<?PHP echo gettext("Confirm"); ?>" /> |
|
204 |
</td> |
|
205 |
</tr> |
|
206 |
<?PHP else: ?> |
|
207 |
<tr> |
|
208 |
<td colspan="2" valign="top" class="listtopic"><?PHP echo gettext("GEOM Mirror information"); ?></td> |
|
209 |
</tr> |
|
210 |
|
|
211 |
<tr> |
|
212 |
<td width="22%" valign="top" class="vncell"><?PHP echo gettext("Mirror Status"); ?></td> |
|
213 |
<td width="78%" class="vtable"> |
|
214 |
|
|
215 |
<table width="100%" border="0" cellspacing="0" cellpadding="0" summary="gmirror status"> |
|
216 |
<tbody id="gmirror_status_table"> |
|
217 |
<?PHP if (count($mirror_status) > 0): ?> |
|
218 |
<tr> |
|
219 |
<td width="30%" class="vncellt"><?PHP echo gettext("Name"); ?></td> |
|
220 |
<td width="30%" class="vncellt"><?PHP echo gettext("Status"); ?></td> |
|
221 |
<td width="40%" class="vncellt"><?PHP echo gettext("Component"); ?></td> |
|
222 |
</tr> |
|
223 |
<?PHP foreach ($mirror_status as $mirror => $name): |
|
224 |
$components = count($name["components"]); ?> |
|
225 |
<tr> |
|
226 |
<td width="30%" rowspan="<?PHP echo $components; ?>" class="listr"> |
|
227 |
<?PHP echo htmlspecialchars($name['name']); ?> |
|
228 |
<br />Size: <?PHP echo gmirror_get_mirror_size($name['name']); ?> |
|
229 |
</td> |
|
230 |
<td width="30%" rowspan="<?PHP echo $components; ?>" class="listr"> |
|
231 |
<?PHP echo htmlspecialchars($name['status']); ?> |
|
232 |
<?PHP if (strtoupper($name['status']) == "DEGRADED"): ?> |
|
233 |
<br /><a href="diag_gmirror.php?action=forget&mirror=<?PHP echo htmlspecialchars($name['name']); ?>">[<?PHP echo gettext("Forget Disconnected Disks"); ?>]</a> |
|
234 |
<?PHP endif; ?> |
|
235 |
</td> |
|
236 |
<td width="40%" class="listr"> |
|
237 |
<?PHP echo $name['components'][0]; ?> |
|
238 |
<?PHP list($cname, $cstatus) = explode(" ", $name['components'][0], 2); ?> |
|
239 |
<br /> |
|
240 |
<?PHP if ((strtoupper($name['status']) == "COMPLETE") && (count($name["components"]) > 1)): ?> |
|
241 |
<a href="diag_gmirror.php?action=rebuild&consumer=<?PHP echo htmlspecialchars($cname); ?>&mirror=<?PHP echo htmlspecialchars($name['name']); ?>">[<?PHP echo gettext("Rebuild"); ?>]</a> |
|
242 |
<a href="diag_gmirror.php?action=deactivate&consumer=<?PHP echo htmlspecialchars($cname); ?>&mirror=<?PHP echo htmlspecialchars($name['name']); ?>">[<?PHP echo gettext("Deactivate"); ?>]</a> |
|
243 |
<a href="diag_gmirror.php?action=remove&consumer=<?PHP echo htmlspecialchars($cname); ?>&mirror=<?PHP echo htmlspecialchars($name['name']); ?>">[<?PHP echo gettext("Remove"); ?>]</a> |
|
244 |
<?PHP endif; ?> |
|
245 |
</td> |
|
246 |
</tr> |
|
247 |
<?PHP if (count($name["components"]) > 1): |
|
248 |
$morecomponents = array_slice($name["components"], 1); ?> |
|
249 |
<?PHP foreach ($morecomponents as $component): ?> |
|
250 |
<tr> |
|
251 |
<td width="40%" class="listr"> |
|
252 |
<?PHP echo $component; ?> |
|
253 |
<?PHP list($cname, $cstatus) = explode(" ", $component, 2); ?> |
|
254 |
<br /> |
|
255 |
<?PHP if ((strtoupper($name['status']) == "COMPLETE") && (count($name["components"]) > 1)): ?> |
|
256 |
<a href="diag_gmirror.php?action=rebuild&consumer=<?PHP echo htmlspecialchars($cname); ?>&mirror=<?PHP echo htmlspecialchars($name['name']); ?>">[<?PHP echo gettext("Rebuild"); ?>]</a> |
|
257 |
<a href="diag_gmirror.php?action=deactivate&consumer=<?PHP echo htmlspecialchars($cname); ?>&mirror=<?PHP echo htmlspecialchars($name['name']); ?>">[<?PHP echo gettext("Deactivate"); ?>]</a> |
|
258 |
<a href="diag_gmirror.php?action=remove&consumer=<?PHP echo htmlspecialchars($cname); ?>&mirror=<?PHP echo htmlspecialchars($name['name']); ?>">[<?PHP echo gettext("Remove"); ?>]</a> |
|
259 |
<?PHP endif; ?> |
|
260 |
</td> |
|
261 |
</tr> |
|
262 |
<?PHP endforeach; ?> |
|
263 |
<?PHP endif; ?> |
|
264 |
<?PHP endforeach; ?> |
|
265 |
<?PHP else: ?> |
|
266 |
<tr><td colspan="3" class="listr"><?PHP echo gettext("No Mirrors Found"); ?></td></tr> |
|
267 |
<?PHP endif; ?> |
|
268 |
</tbody> |
|
269 |
</table> |
|
270 |
<br /><?PHP echo gettext("Some disk operations may only be performed when there are multiple consumers present in a mirror."); ?> |
|
271 |
</td> |
|
272 |
</tr> |
|
273 |
|
|
274 |
<tr> |
|
275 |
<td colspan="2" valign="top" class="listtopic"><?PHP echo gettext("Consumer information"); ?></td> |
|
276 |
</tr> |
|
277 |
|
|
278 |
<tr> |
|
279 |
<td width="22%" valign="top" class="vncell"><?PHP echo gettext("Available Consumers"); ?></td> |
|
280 |
<td width="78%" class="vtable"> |
|
281 |
|
|
282 |
<table width="100%" border="0" cellspacing="0" cellpadding="0" summary="consumer list"> |
|
283 |
<tbody id="consumer_list"> |
|
284 |
<?PHP if (count($unused_consumers) > 0): ?> |
|
285 |
<tr> |
|
286 |
<td width="30%" class="vncellt"><?PHP echo gettext("Name"); ?></td> |
|
287 |
<td width="30%" class="vncellt"><?PHP echo gettext("Size"); ?></td> |
|
288 |
<td width="40%" class="vncellt"><?PHP echo gettext("Add to Mirror"); ?></td> |
|
289 |
</tr> |
|
290 |
<?PHP foreach ($unused_consumers as $consumer): ?> |
|
291 |
<tr> |
|
292 |
<td width="30%" class="listr"> |
|
293 |
<?PHP echo htmlspecialchars($consumer['name']); ?> |
|
294 |
</td> |
|
295 |
<td width="30%" class="listr"><?PHP echo htmlspecialchars($consumer['size']); ?> <?PHP echo htmlspecialchars($consumer['humansize']); ?></td> |
|
296 |
<td width="40%" class="listr"> |
|
297 |
<?PHP $oldmirror = gmirror_get_consumer_metadata_mirror($consumer['name']); |
|
298 |
if ($oldmirror): ?> |
|
299 |
<a href="diag_gmirror.php?action=activate&consumer=<?PHP echo htmlspecialchars($consumer['name']); ?>&mirror=<?PHP echo htmlspecialchars($oldmirror); ?>">[<?PHP echo gettext("Reactivate on:"); ?> <?PHP echo htmlspecialchars($oldmirror); ?>]</a> |
|
300 |
<br /><a href="diag_gmirror.php?action=clear&consumer=<?PHP echo htmlspecialchars($consumer['name']); ?>">[<?PHP echo gettext("Remove metadata from disk"); ?>]</a> |
|
301 |
<?PHP else: ?> |
|
302 |
<?PHP foreach ($mirror_list as $mirror): |
|
303 |
$mirror_size = gmirror_get_mirror_size($mirror); |
|
304 |
$consumer_size = gmirror_get_unused_consumer_size($consumer['name']); |
|
305 |
?> |
|
306 |
<?PHP if ($consumer_size > $mirror_size): ?> |
|
307 |
<a href="diag_gmirror.php?action=insert&consumer=<?PHP echo htmlspecialchars($consumer['name']); ?>&mirror=<?PHP echo htmlspecialchars($mirror); ?>"><?PHP echo htmlspecialchars($mirror); ?></a> |
|
308 |
<?PHP endif; ?> |
|
309 |
<?PHP endforeach; ?> |
|
310 |
<?PHP endif; ?> |
|
311 |
</td> |
|
312 |
</tr> |
|
313 |
<?PHP endforeach; ?> |
|
314 |
<?PHP else: ?> |
|
315 |
<tr><td colspan="3" class="listr"><?PHP echo gettext("No unused consumers found"); ?></td></tr> |
|
316 |
<?PHP endif; ?> |
|
317 |
</tbody> |
|
318 |
</table> |
|
319 |
<br /><?PHP echo gettext("Consumers may only be added to a mirror if they are larger than the size of the mirror."); ?> |
|
320 |
</td> |
|
321 |
</tr> |
|
322 |
|
|
323 |
<tr> |
|
324 |
<td colspan="2" valign="top" class=""> </td> |
|
325 |
</tr> |
|
326 |
<?PHP endif;?> |
|
327 |
</table> |
|
328 |
</div> |
|
329 |
</td> |
|
330 |
</tr> |
|
331 |
</table> |
|
332 |
</form> |
|
333 |
<?php require("fend.inc"); ?> |
|
334 |
</body> |
|
335 |
</html> |
|
336 |
|
|
337 |
<?php |
|
338 |
|
|
339 |
// Clear the loading indicator |
|
340 |
echo "<script type=\"text/javascript\">"; |
|
341 |
echo "jQuery('#loading').html('');"; |
|
342 |
echo "</script>"; |
|
343 |
|
|
344 |
?> |
usr/local/www/fbegin.inc | ||
---|---|---|
210 | 210 |
$diagnostics_menu[] = array(gettext("DNS Lookup"), "/diag_dns.php"); |
211 | 211 |
$diagnostics_menu[] = array(gettext("Edit File"), "/edit.php"); |
212 | 212 |
$diagnostics_menu[] = array(gettext("Factory Defaults"), "/diag_defaults.php"); |
213 |
|
|
214 |
if(file_exists("/var/run/gmirror_active")) |
|
215 |
$diagnostics_menu[] = array(gettext("GEOM Mirrors"), "/diag_gmirror.php" ); |
|
216 |
|
|
213 | 217 |
$diagnostics_menu[] = array(gettext("Halt System"), "/halt.php" ); |
214 | 218 |
$diagnostics_menu[] = array(gettext("Limiter Info"), "/diag_limiter_info.php" ); |
215 | 219 |
$diagnostics_menu[] = array(gettext("NDP Table"), "/diag_ndp.php" ); |
usr/local/www/widgets/include/gmirror_status.inc | ||
---|---|---|
1 |
<?php |
|
2 |
/* |
|
3 |
gmirror_status.widget.php |
|
4 |
Copyright (C) 2009-2010 Jim Pingle |
|
5 |
|
|
6 |
Redistribution and use in source and binary forms, with or without |
|
7 |
modification, are permitted provided that the following conditions are met: |
|
8 |
|
|
9 |
1. Redistributions of source code must retain the above copyright notice, |
|
10 |
this list of conditions and the following disclaimer. |
|
11 |
|
|
12 |
2. Redistributions in binary form must reproduce the above copyright |
|
13 |
notice, this list of conditions and the following disclaimer in the |
|
14 |
documentation and/or other materials provided with the distribution. |
|
15 |
|
|
16 |
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, |
|
17 |
INClUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY |
|
18 |
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
|
19 |
AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, |
|
20 |
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
21 |
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
22 |
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|
23 |
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
24 |
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
25 |
POSSIBILITY OF SUCH DAMAGE. |
|
26 |
*/ |
|
27 |
|
|
28 |
function gmirror_get_status() { |
|
29 |
$status = ""; |
|
30 |
exec("/sbin/gmirror status -s", $status); |
|
31 |
$mirrors = array(); |
|
32 |
|
|
33 |
/* Empty output = no mirrors found */ |
|
34 |
if (count($status) > 0) { |
|
35 |
/* Loop through gmirror status output. */ |
|
36 |
foreach ($status as $line) { |
|
37 |
/* Split the line by whitespace */ |
|
38 |
$all = preg_split("/[\s\t]+/", trim($line), 3); |
|
39 |
if (count($all) == 3) { |
|
40 |
/* If there are three items on a line, it is mirror name, status, and component */ |
|
41 |
$currentmirror = $all[0]; |
|
42 |
$mirrors[$currentmirror]["name"] = $all[0]; |
|
43 |
$mirrors[$currentmirror]["status"] = $all[1]; |
|
44 |
if (!is_array($mirrors[$currentmirror]["components"])) |
|
45 |
$mirrors[$currentmirror]["components"] = array(); |
|
46 |
$mirrors[$currentmirror]["components"][] = $all[2]; |
|
47 |
} |
|
48 |
} |
|
49 |
} |
|
50 |
/* Return an hash of mirrors and components */ |
|
51 |
return $mirrors; |
|
52 |
} |
|
53 |
|
|
54 |
function gmirror_html_status() { |
|
55 |
$mirrors = gmirror_get_status(); |
|
56 |
$output = ""; |
|
57 |
if (count($mirrors) > 0) { |
|
58 |
$output .= "<tr>\n"; |
|
59 |
$output .= "<td width=\"40%\" class=\"vncellt\">Name</td>\n"; |
|
60 |
$output .= "<td width=\"40%\" class=\"vncellt\">Status</td>\n"; |
|
61 |
$output .= "<td width=\"20%\" class=\"vncellt\">Component</td>\n"; |
|
62 |
$output .= "</tr>\n"; |
|
63 |
foreach ($mirrors as $mirror => $name) { |
|
64 |
$components = count($name["components"]); |
|
65 |
$output .= "<tr>\n"; |
|
66 |
$output .= "<td width=\"40%\" rowspan=\"{$components}\" class=\"listr\">{$name['name']}</td>\n"; |
|
67 |
$output .= "<td width=\"40%\" rowspan=\"{$components}\" class=\"listr\">{$name['status']}</td>\n"; |
|
68 |
$output .= "<td width=\"20%\" class=\"listr\">{$name['components'][0]}</td>\n"; |
|
69 |
$output .= "</tr>\n"; |
|
70 |
if (count($name["components"]) > 1) { |
|
71 |
$morecomponents = array_slice($name["components"], 1); |
|
72 |
foreach ($morecomponents as $component) { |
|
73 |
$output .= "<tr>\n"; |
|
74 |
$output .= "<td width=\"20%\" class=\"listr\">{$component}</td>\n"; |
|
75 |
$output .= "</tr>\n"; |
|
76 |
} |
|
77 |
} |
|
78 |
} |
|
79 |
} else { |
|
80 |
$output .= "<tr><td colspan=\"3\" class=\"listr\">No Mirrors Found</td></tr>\n"; |
|
81 |
} |
|
82 |
// $output .= "<tr><td colspan=\"3\" class=\"listr\">Updated at " . date("F j, Y, g:i:s a") . "</td></tr>\n"; |
|
83 |
return $output; |
|
84 |
} |
|
85 |
?> |
usr/local/www/widgets/widgets/gmirror_status.widget.php | ||
---|---|---|
28 | 28 |
$nocsrf = true; |
29 | 29 |
|
30 | 30 |
require_once("guiconfig.inc"); |
31 |
require_once("/usr/local/www/widgets/include/gmirror_status.inc");
|
|
31 |
require_once("gmirror.inc");
|
|
32 | 32 |
|
33 | 33 |
if ($_GET['textonly'] == "true") { |
34 | 34 |
header("Cache-Control: no-cache"); |
Also available in: Unified diff
Bring in proper gmirror support for the GUI and notifications.
Made a general gmirror library to perform various gmirror tasks and get information, using some of the former widget logic to start. Updated widget to use this new code.
Added a Diag > GEOM Mirrors page that displays information about existing mirrors and perform various management tasks. Current actions include rebuilding a drive, forgetting disconnected mirror drives, insert/remove, deactivate/activate, clearing medatada. It's now possible to use the GUI to rebuild a failed mirror by performing a forget, then insert action to replace a missing/dead drive.
Also included is a notification setup. Mirror status is polled every 60 seconds, and if any aspect of the mirror changes, notifications are issues that alert in the GUI and by SMTP, etc.