Project

General

Profile

Download (11.7 KB) Statistics
| Branch: | Tag: | Revision:
1 52398a6b jim-p
<?php
2
/*
3
	gmirror.inc
4
	Copyright (C) 2009-2014 Jim Pingle
5 ed2d1343 Renato Botelho
	Copyright (C) 2013-2015 Electric Sheep Fencing, LP
6 52398a6b jim-p
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
global $balance_methods;
30
$balance_methods = array("load", "prefer", "round-robin", "split");
31
32
/* Create a status array for each mirror and its disk components. */
33
function gmirror_get_status() {
34
	$status = "";
35
	exec("/sbin/gmirror status -s", $status);
36
	$mirrors = array();
37
38
	/* Empty output = no mirrors found */
39
	if (count($status) > 0) {
40
		/* Loop through gmirror status output. */
41
		foreach ($status as $line) {
42
			/* Split the line by whitespace */
43
			$all = preg_split("/[\s\t]+/", trim($line), 3);
44
			if (count($all) == 3) {
45
				/* If there are three items on a line, it is mirror name, status, and component */
46
				$currentmirror = basename($all[0]);
47
				$mirrors[$currentmirror]['name'] = basename($all[0]);
48
				$mirrors[$currentmirror]['status'] = $all[1];
49 9ba87997 Phil Davis
				if (!is_array($mirrors[$currentmirror]['components'])) {
50 52398a6b jim-p
					$mirrors[$currentmirror]['components'] = array();
51 9ba87997 Phil Davis
				}
52 52398a6b jim-p
				$mirrors[$currentmirror]['components'][] = $all[2];
53
			}
54
		}
55
	}
56 9ba87997 Phil Davis
	/* Return an hash of mirrors and components */
57 52398a6b jim-p
	return $mirrors;
58
}
59
60
/* Get only status word for a single mirror. */
61
function gmirror_get_status_single($mirror) {
62
	$status = "";
63
	$mirror_status = gmirror_get_status();
64
	return $mirror_status[$mirror]['status'];
65
}
66
67
/* Generate an HTML formatted status for mirrors and disks in a small format for the widget */
68
function gmirror_html_status() {
69
	$mirrors = gmirror_get_status();
70
	$output = "";
71
	if (count($mirrors) > 0) {
72
		$output .= "<tr>\n";
73
		$output .= "<td width=\"40%\" class=\"vncellt\">Name</td>\n";
74
		$output .= "<td width=\"40%\" class=\"vncellt\">Status</td>\n";
75
		$output .= "<td width=\"20%\" class=\"vncellt\">Component</td>\n";
76
		$output .= "</tr>\n";
77
		foreach ($mirrors as $mirror => $name) {
78
			$components = count($name["components"]);
79
			$output .= "<tr>\n";
80
			$output .= "<td width=\"40%\" rowspan=\"{$components}\" class=\"listr\">{$name['name']}</td>\n";
81
			$output .= "<td width=\"40%\" rowspan=\"{$components}\" class=\"listr\">{$name['status']}</td>\n";
82
			$output .= "<td width=\"20%\" class=\"listr\">{$name['components'][0]}</td>\n";
83
			$output .= "</tr>\n";
84
			if (count($name["components"]) > 1) {
85
				$morecomponents = array_slice($name["components"], 1);
86
				foreach ($morecomponents as $component) {
87
					$output .= "<tr>\n";
88
					$output .= "<td width=\"20%\" class=\"listr\">{$component}</td>\n";
89
					$output .= "</tr>\n";
90
				}
91
			}
92
		}
93
	} else {
94
		$output .= "<tr><td colspan=\"3\" class=\"listr\">No Mirrors Found</td></tr>\n";
95
	}
96
	// $output .= "<tr><td colspan=\"3\" class=\"listr\">Updated at " . date("F j, Y, g:i:s a") . "</td></tr>\n";
97
	return $output;
98
}
99
100
/* List all disks in the system (potential gmirror targets) */
101
function gmirror_get_disks() {
102
	$disklist = "";
103
	/* Get a list of disks in a scriptable way, exclude optical drives */
104
	exec("/sbin/geom disk status -s | /usr/bin/grep -v '[[:blank:]]*cd[[:digit:]]*' | /usr/bin/awk '{print $1;}'", $disklist);
105
	return $disklist;
106
}
107
108
/* List all potential gmirror consumers */
109
function gmirror_get_unused_consumers() {
110
	$consumerlist = "";
111 0373c361 jim-p
	$disklist = gmirror_get_disks();
112 52398a6b jim-p
	/* Get a list of consumers, exclude existing mirrors and diskid entries */
113
	exec("/sbin/geom part status -s | /usr/bin/egrep -v '(mirror|diskid)' | /usr/bin/awk '{print $1, $3;}'", $consumerlist);
114
	$all_consumers = array();
115
	foreach ($consumerlist as $cl) {
116
		$parts = explode(" ", $cl);
117 9ba87997 Phil Davis
		foreach ($parts as $part) {
118 52398a6b jim-p
			$all_consumers[] = $part;
119 9ba87997 Phil Davis
		}
120 52398a6b jim-p
	}
121 0373c361 jim-p
	foreach ($disklist as $d) {
122
		if (!is_consumer_used($d) && !in_array($d, $all_consumers)) {
123
			$all_consumers[] = $d;
124
		}
125
	}
126 52398a6b jim-p
	return $all_consumers;
127
}
128
129
/* List all existing geom mirrors */
130
function gmirror_get_mirrors() {
131
	$mirrorlist = "";
132
	exec("/sbin/gmirror list | /usr/bin/grep '^Geom name:' | /usr/bin/awk '{print $3;}'", $mirrorlist);
133
	return $mirrorlist;
134
}
135
136
137
/* List all consumers for a given mirror */
138
function gmirror_get_consumers_in_mirror($mirror) {
139 9ba87997 Phil Davis
	if (!is_valid_mirror($mirror)) {
140 52398a6b jim-p
		return array();
141 9ba87997 Phil Davis
	}
142 52398a6b jim-p
143
	$consumers = array();
144
	exec("/sbin/gmirror status -s " . escapeshellarg($mirror) . " | /usr/bin/awk '{print $3;}'", $consumers);
145
	return $consumers;
146
}
147
148
/* Test if a given consumer is a member of an existing mirror */
149
function is_consumer_in_mirror($consumer, $mirror) {
150 9ba87997 Phil Davis
	if (!is_valid_consumer($consumer) || !is_valid_mirror($mirror)) {
151 52398a6b jim-p
		return false;
152 9ba87997 Phil Davis
	}
153 52398a6b jim-p
154
	$mirrorconsumers = gmirror_get_consumers_in_mirror($mirror);
155
	return in_array(basename($consumer), $mirrorconsumers);
156
}
157
158
/* Test if a mirror exists */
159
function is_valid_mirror($mirror) {
160
	$mirrors = gmirror_get_mirrors();
161
	return in_array($mirror, $mirrors);
162
}
163
164
/* Test if a disk is valid/exists */
165
function is_valid_disk($disk) {
166
	$adisks = gmirror_get_disks();
167
	return in_array(basename($disk), $adisks);
168
}
169
170
/* Test if a consumer is valid and in use in a mirror */
171
function is_consumer_used($consumer) {
172
	$found = false;
173
	$mirrors = gmirror_get_mirrors();
174
	foreach ($mirrors as $mirror) {
175
		$consumers = gmirror_get_consumers_in_mirror($mirror);
176 9ba87997 Phil Davis
		if (in_array($consumer, $consumers)) {
177 52398a6b jim-p
			return true;
178 9ba87997 Phil Davis
		}
179 52398a6b jim-p
	}
180
	return false;
181
}
182
183
/* Test if a consumer is valid and not in use */
184
function is_consumer_unused($consumer) {
185
	$consumers = gmirror_get_unused_consumers();
186
	return in_array($consumer, $consumers);
187
}
188
189
/* Test if a consumer is valid (either a disk or partition) */
190
function is_valid_consumer($consumer) {
191
	return (is_consumer_unused($consumer) || is_consumer_used($consumer));
192
}
193
194
/* Remove all disconnected drives from a mirror */
195
function gmirror_forget_disconnected($mirror) {
196 9ba87997 Phil Davis
	if (!is_valid_mirror($mirror)) {
197 52398a6b jim-p
		return false;
198 9ba87997 Phil Davis
	}
199 52398a6b jim-p
	return mwexec("/sbin/gmirror forget " . escapeshellarg($mirror));
200
}
201
202
/* Insert another consumer into a mirror */
203
function gmirror_insert_consumer($mirror, $consumer) {
204 9ba87997 Phil Davis
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
205 52398a6b jim-p
		return false;
206 9ba87997 Phil Davis
	}
207 52398a6b jim-p
	return mwexec("/sbin/gmirror insert " . escapeshellarg($mirror) . " " . escapeshellarg($consumer));
208
}
209
210
/* Remove consumer from a mirror and clear its metadata */
211
function gmirror_remove_consumer($mirror, $consumer) {
212 9ba87997 Phil Davis
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
213 52398a6b jim-p
		return false;
214 9ba87997 Phil Davis
	}
215 52398a6b jim-p
	return mwexec("/sbin/gmirror remove " . escapeshellarg($mirror) . " " . escapeshellarg($consumer));
216
}
217
218
/* Wipe geom info from drive (if mirror is not running) */
219
function gmirror_clear_consumer($consumer) {
220 9ba87997 Phil Davis
	if (!is_valid_consumer($consumer)) {
221 52398a6b jim-p
		return false;
222 9ba87997 Phil Davis
	}
223 52398a6b jim-p
	return mwexec("/sbin/gmirror clear " . escapeshellarg($consumer));
224
}
225
226
/* Find the balance method used by a given mirror */
227
function gmirror_get_mirror_balance($mirror) {
228 9ba87997 Phil Davis
	if (!is_valid_mirror($mirror)) {
229 52398a6b jim-p
		return false;
230 9ba87997 Phil Davis
	}
231 52398a6b jim-p
	$balancemethod = "";
232
	exec("/sbin/gmirror list " . escapeshellarg($mirror) . " | /usr/bin/grep '^Balance:' | /usr/bin/awk '{print $2;}'", $balancemethod);
233
	return $balancemethod[0];
234
}
235
236
/* Change balance algorithm of the mirror */
237
function gmirror_configure_balance($mirror, $balancemethod) {
238 2fc7b003 jim-p
	global $balance_methods;
239 9ba87997 Phil Davis
	if (!is_valid_mirror($mirror) || !in_array($balancemethod, $balance_methods)) {
240 52398a6b jim-p
		return false;
241 9ba87997 Phil Davis
	}
242 52398a6b jim-p
	return mwexec("/sbin/gmirror configure -b " . escapeshellarg($balancemethod) . " " . escapeshellarg($mirror));
243
}
244
245
/* Force a mirror member to rebuild */
246
function gmirror_force_rebuild($mirror, $consumer) {
247 9ba87997 Phil Davis
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
248 52398a6b jim-p
		return false;
249 9ba87997 Phil Davis
	}
250 52398a6b jim-p
	return mwexec("/sbin/gmirror rebuild " . escapeshellarg($mirror) . " " . escapeshellarg($consumer));
251
}
252
253
/* Show all metadata on the physical consumer */
254
function gmirror_get_consumer_metadata($consumer) {
255 9ba87997 Phil Davis
	if (!is_valid_consumer($consumer)) {
256 52398a6b jim-p
		return array();
257 9ba87997 Phil Davis
	}
258 52398a6b jim-p
	$output = "";
259
	exec("/sbin/gmirror dump " . escapeshellarg($consumer), $output);
260
	return array_map('trim', $output);
261
}
262
263
/* Test if a consumer has metadata, indicating it is a member of a mirror (active or inactive) */
264
function gmirror_consumer_has_metadata($consumer) {
265
	return (count(gmirror_get_consumer_metadata($consumer)) > 0);
266
}
267
268
/* Find the mirror to which this consumer belongs */
269
function gmirror_get_consumer_metadata_mirror($consumer) {
270 9ba87997 Phil Davis
	if (!is_valid_consumer($consumer)) {
271 52398a6b jim-p
		return array();
272 9ba87997 Phil Davis
	}
273 52398a6b jim-p
	$metadata = gmirror_get_consumer_metadata($consumer);
274
	foreach ($metadata as $line) {
275
		if (substr($line, 0, 5) == "name:") {
276
			list ($key, $value) = explode(":", $line, 2);
277
			return trim($value);
278
		}
279
	}
280
}
281
282
/* Deactivate consumer, removing it from service in the mirror, but leave metadata intact */
283
function gmirror_deactivate_consumer($mirror, $consumer) {
284 9ba87997 Phil Davis
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
285 52398a6b jim-p
		return false;
286 9ba87997 Phil Davis
	}
287 52398a6b jim-p
	return mwexec("/sbin/gmirror deactivate " . escapeshellarg($mirror) . " " . escapeshellarg($consumer));
288
}
289
290
/* Reactivate a deactivated consumer */
291
function gmirror_activate_consumer($mirror, $consumer) {
292 9ba87997 Phil Davis
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
293 52398a6b jim-p
		return false;
294 9ba87997 Phil Davis
	}
295 52398a6b jim-p
	return mwexec("/sbin/gmirror activate " . escapeshellarg($mirror) . " " . escapeshellarg($consumer));
296
}
297
298
/* Find the size of the given mirror */
299
function gmirror_get_mirror_size($mirror) {
300 9ba87997 Phil Davis
	if (!is_valid_mirror($mirror)) {
301 52398a6b jim-p
		return false;
302 9ba87997 Phil Davis
	}
303 52398a6b jim-p
	$mirrorsize = "";
304
	exec("/sbin/gmirror list " . escapeshellarg($mirror) . " | /usr/bin/grep 'Mediasize:' | /usr/bin/head -n 1 | /usr/bin/awk '{print $2;}'", $mirrorsize);
305
	return $mirrorsize[0];
306
}
307
308
/* Return a list of all potential consumers on a disk with sizes. The geom part
309
	list output is a little odd, we can't get the output for just the disk, if the disk contains
310
	slices those get output also. */
311
function gmirror_get_all_unused_consumer_sizes_on_disk($disk) {
312 9ba87997 Phil Davis
	if (!is_valid_disk($disk) || !is_consumer_unused($disk)) {
313 52398a6b jim-p
		return array();
314 9ba87997 Phil Davis
	}
315 52398a6b jim-p
	$output = "";
316
	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);
317 0373c361 jim-p
	if (empty($output)) {
318
		exec("/sbin/geom disk 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);
319
	}
320 52398a6b jim-p
	$disk_contents = array();
321
	foreach ($output as $line) {
322
		list($name, $size, $humansize) = explode(" ", $line, 3);
323
		$consumer = array();
324
		$consumer['name'] = $name;
325
		$consumer['size'] = $size;
326
		$consumer['humansize'] = $humansize;
327
		$disk_contents[] = $consumer;
328
	}
329
	return $disk_contents;
330
}
331
332
/* Get only the size for one specific potential consumer. */
333
function gmirror_get_unused_consumer_size($consumer) {
334
	$consumersizes = gmirror_get_all_unused_consumer_sizes_on_disk($consumer);
335
	foreach ($consumersizes as $csize) {
336 9ba87997 Phil Davis
		if ($csize['name'] == $consumer) {
337 52398a6b jim-p
			return $csize['size'];
338 9ba87997 Phil Davis
		}
339 52398a6b jim-p
	}
340
	return -1;
341
}
342 8b335b7a Ermal LUÇI
?>