Project

General

Profile

Download (11.2 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 1180e4f0 Sjon Hortensius
	/* 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 7d5b007c Sjon Hortensius
	if (count($mirrors) < 1) {
72
?>
73 0f64b71f Jared Dillard
<div class="alert alert-warning" role="alert">
74 7d5b007c Sjon Hortensius
	<p>No Mirrors Found</p>
75
</div>
76
<?php
77
		return;
78 52398a6b jim-p
	}
79 7d5b007c Sjon Hortensius
80
?>
81 89f64f0f Sander van Leeuwen
<table class="table table-striped table-hover">
82 7d5b007c Sjon Hortensius
	<thead>
83
		<tr>
84
			<th>Name</td>
85
			<th>Status</td>
86
			<th>Component</td>
87
		</tr>
88
	</thead>
89
	<tbody>
90
<?php foreach ($mirrors as $mirror => $name): ?>
91
		<tr>
92
			<td rowspan="<?=count($name["components"])?>"><?=$name['name']?></td>
93
			<td rowspan="<?=count($name["components"])?>"><?=$name['status']?></td>
94
			<td><?=$name['components'][0]?></td>
95
		</tr>
96
<?php if (count($name["components"]) > 1): ?>
97
		<?php foreach (array_slice($name["components"], 1) as $component): ?>
98
			<tr>
99
				<td><?=$component?></td>
100
			</tr>
101
		<?php endforeach; ?>
102
	<?php endif; ?>
103
<?php endforeach;
104 52398a6b jim-p
}
105
106
/* List all disks in the system (potential gmirror targets) */
107
function gmirror_get_disks() {
108
	$disklist = "";
109
	/* Get a list of disks in a scriptable way, exclude optical drives */
110
	exec("/sbin/geom disk status -s | /usr/bin/grep -v '[[:blank:]]*cd[[:digit:]]*' | /usr/bin/awk '{print $1;}'", $disklist);
111
	return $disklist;
112
}
113
114
/* List all potential gmirror consumers */
115
function gmirror_get_unused_consumers() {
116
	$consumerlist = "";
117 0373c361 jim-p
	$disklist = gmirror_get_disks();
118 52398a6b jim-p
	/* Get a list of consumers, exclude existing mirrors and diskid entries */
119
	exec("/sbin/geom part status -s | /usr/bin/egrep -v '(mirror|diskid)' | /usr/bin/awk '{print $1, $3;}'", $consumerlist);
120
	$all_consumers = array();
121
	foreach ($consumerlist as $cl) {
122
		$parts = explode(" ", $cl);
123 9ba87997 Phil Davis
		foreach ($parts as $part) {
124 52398a6b jim-p
			$all_consumers[] = $part;
125 9ba87997 Phil Davis
		}
126 52398a6b jim-p
	}
127 0373c361 jim-p
	foreach ($disklist as $d) {
128
		if (!is_consumer_used($d) && !in_array($d, $all_consumers)) {
129
			$all_consumers[] = $d;
130
		}
131
	}
132 52398a6b jim-p
	return $all_consumers;
133
}
134
135
/* List all existing geom mirrors */
136
function gmirror_get_mirrors() {
137
	$mirrorlist = "";
138
	exec("/sbin/gmirror list | /usr/bin/grep '^Geom name:' | /usr/bin/awk '{print $3;}'", $mirrorlist);
139
	return $mirrorlist;
140
}
141
142
143
/* List all consumers for a given mirror */
144
function gmirror_get_consumers_in_mirror($mirror) {
145 9ba87997 Phil Davis
	if (!is_valid_mirror($mirror)) {
146 52398a6b jim-p
		return array();
147 9ba87997 Phil Davis
	}
148 52398a6b jim-p
149
	$consumers = array();
150
	exec("/sbin/gmirror status -s " . escapeshellarg($mirror) . " | /usr/bin/awk '{print $3;}'", $consumers);
151
	return $consumers;
152
}
153
154
/* Test if a given consumer is a member of an existing mirror */
155
function is_consumer_in_mirror($consumer, $mirror) {
156 9ba87997 Phil Davis
	if (!is_valid_consumer($consumer) || !is_valid_mirror($mirror)) {
157 52398a6b jim-p
		return false;
158 9ba87997 Phil Davis
	}
159 52398a6b jim-p
160
	$mirrorconsumers = gmirror_get_consumers_in_mirror($mirror);
161
	return in_array(basename($consumer), $mirrorconsumers);
162
}
163
164
/* Test if a mirror exists */
165
function is_valid_mirror($mirror) {
166
	$mirrors = gmirror_get_mirrors();
167
	return in_array($mirror, $mirrors);
168
}
169
170
/* Test if a disk is valid/exists */
171
function is_valid_disk($disk) {
172
	$adisks = gmirror_get_disks();
173
	return in_array(basename($disk), $adisks);
174
}
175
176
/* Test if a consumer is valid and in use in a mirror */
177
function is_consumer_used($consumer) {
178
	$found = false;
179
	$mirrors = gmirror_get_mirrors();
180
	foreach ($mirrors as $mirror) {
181
		$consumers = gmirror_get_consumers_in_mirror($mirror);
182 9ba87997 Phil Davis
		if (in_array($consumer, $consumers)) {
183 52398a6b jim-p
			return true;
184 9ba87997 Phil Davis
		}
185 52398a6b jim-p
	}
186
	return false;
187
}
188
189
/* Test if a consumer is valid and not in use */
190
function is_consumer_unused($consumer) {
191
	$consumers = gmirror_get_unused_consumers();
192
	return in_array($consumer, $consumers);
193
}
194
195
/* Test if a consumer is valid (either a disk or partition) */
196
function is_valid_consumer($consumer) {
197
	return (is_consumer_unused($consumer) || is_consumer_used($consumer));
198
}
199
200
/* Remove all disconnected drives from a mirror */
201
function gmirror_forget_disconnected($mirror) {
202 9ba87997 Phil Davis
	if (!is_valid_mirror($mirror)) {
203 52398a6b jim-p
		return false;
204 9ba87997 Phil Davis
	}
205 52398a6b jim-p
	return mwexec("/sbin/gmirror forget " . escapeshellarg($mirror));
206
}
207
208
/* Insert another consumer into a mirror */
209
function gmirror_insert_consumer($mirror, $consumer) {
210 9ba87997 Phil Davis
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
211 52398a6b jim-p
		return false;
212 9ba87997 Phil Davis
	}
213 52398a6b jim-p
	return mwexec("/sbin/gmirror insert " . escapeshellarg($mirror) . " " . escapeshellarg($consumer));
214
}
215
216
/* Remove consumer from a mirror and clear its metadata */
217
function gmirror_remove_consumer($mirror, $consumer) {
218 9ba87997 Phil Davis
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
219 52398a6b jim-p
		return false;
220 9ba87997 Phil Davis
	}
221 52398a6b jim-p
	return mwexec("/sbin/gmirror remove " . escapeshellarg($mirror) . " " . escapeshellarg($consumer));
222
}
223
224
/* Wipe geom info from drive (if mirror is not running) */
225
function gmirror_clear_consumer($consumer) {
226 9ba87997 Phil Davis
	if (!is_valid_consumer($consumer)) {
227 52398a6b jim-p
		return false;
228 9ba87997 Phil Davis
	}
229 52398a6b jim-p
	return mwexec("/sbin/gmirror clear " . escapeshellarg($consumer));
230
}
231
232
/* Find the balance method used by a given mirror */
233
function gmirror_get_mirror_balance($mirror) {
234 9ba87997 Phil Davis
	if (!is_valid_mirror($mirror)) {
235 52398a6b jim-p
		return false;
236 9ba87997 Phil Davis
	}
237 52398a6b jim-p
	$balancemethod = "";
238
	exec("/sbin/gmirror list " . escapeshellarg($mirror) . " | /usr/bin/grep '^Balance:' | /usr/bin/awk '{print $2;}'", $balancemethod);
239
	return $balancemethod[0];
240
}
241
242
/* Change balance algorithm of the mirror */
243
function gmirror_configure_balance($mirror, $balancemethod) {
244 2fc7b003 jim-p
	global $balance_methods;
245 9ba87997 Phil Davis
	if (!is_valid_mirror($mirror) || !in_array($balancemethod, $balance_methods)) {
246 52398a6b jim-p
		return false;
247 9ba87997 Phil Davis
	}
248 52398a6b jim-p
	return mwexec("/sbin/gmirror configure -b " . escapeshellarg($balancemethod) . " " . escapeshellarg($mirror));
249
}
250
251
/* Force a mirror member to rebuild */
252
function gmirror_force_rebuild($mirror, $consumer) {
253 9ba87997 Phil Davis
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
254 52398a6b jim-p
		return false;
255 9ba87997 Phil Davis
	}
256 52398a6b jim-p
	return mwexec("/sbin/gmirror rebuild " . escapeshellarg($mirror) . " " . escapeshellarg($consumer));
257
}
258
259
/* Show all metadata on the physical consumer */
260
function gmirror_get_consumer_metadata($consumer) {
261 9ba87997 Phil Davis
	if (!is_valid_consumer($consumer)) {
262 52398a6b jim-p
		return array();
263 9ba87997 Phil Davis
	}
264 52398a6b jim-p
	$output = "";
265
	exec("/sbin/gmirror dump " . escapeshellarg($consumer), $output);
266
	return array_map('trim', $output);
267
}
268
269
/* Test if a consumer has metadata, indicating it is a member of a mirror (active or inactive) */
270
function gmirror_consumer_has_metadata($consumer) {
271
	return (count(gmirror_get_consumer_metadata($consumer)) > 0);
272
}
273
274
/* Find the mirror to which this consumer belongs */
275
function gmirror_get_consumer_metadata_mirror($consumer) {
276 9ba87997 Phil Davis
	if (!is_valid_consumer($consumer)) {
277 52398a6b jim-p
		return array();
278 9ba87997 Phil Davis
	}
279 52398a6b jim-p
	$metadata = gmirror_get_consumer_metadata($consumer);
280
	foreach ($metadata as $line) {
281
		if (substr($line, 0, 5) == "name:") {
282
			list ($key, $value) = explode(":", $line, 2);
283
			return trim($value);
284
		}
285
	}
286
}
287
288
/* Deactivate consumer, removing it from service in the mirror, but leave metadata intact */
289
function gmirror_deactivate_consumer($mirror, $consumer) {
290 9ba87997 Phil Davis
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
291 52398a6b jim-p
		return false;
292 9ba87997 Phil Davis
	}
293 52398a6b jim-p
	return mwexec("/sbin/gmirror deactivate " . escapeshellarg($mirror) . " " . escapeshellarg($consumer));
294
}
295
296
/* Reactivate a deactivated consumer */
297
function gmirror_activate_consumer($mirror, $consumer) {
298 9ba87997 Phil Davis
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
299 52398a6b jim-p
		return false;
300 9ba87997 Phil Davis
	}
301 52398a6b jim-p
	return mwexec("/sbin/gmirror activate " . escapeshellarg($mirror) . " " . escapeshellarg($consumer));
302
}
303
304
/* Find the size of the given mirror */
305
function gmirror_get_mirror_size($mirror) {
306 9ba87997 Phil Davis
	if (!is_valid_mirror($mirror)) {
307 52398a6b jim-p
		return false;
308 9ba87997 Phil Davis
	}
309 52398a6b jim-p
	$mirrorsize = "";
310
	exec("/sbin/gmirror list " . escapeshellarg($mirror) . " | /usr/bin/grep 'Mediasize:' | /usr/bin/head -n 1 | /usr/bin/awk '{print $2;}'", $mirrorsize);
311
	return $mirrorsize[0];
312
}
313
314
/* Return a list of all potential consumers on a disk with sizes. The geom part
315
	list output is a little odd, we can't get the output for just the disk, if the disk contains
316
	slices those get output also. */
317
function gmirror_get_all_unused_consumer_sizes_on_disk($disk) {
318 9ba87997 Phil Davis
	if (!is_valid_disk($disk) || !is_consumer_unused($disk)) {
319 52398a6b jim-p
		return array();
320 9ba87997 Phil Davis
	}
321 52398a6b jim-p
	$output = "";
322
	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);
323 0373c361 jim-p
	if (empty($output)) {
324
		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);
325
	}
326 52398a6b jim-p
	$disk_contents = array();
327
	foreach ($output as $line) {
328
		list($name, $size, $humansize) = explode(" ", $line, 3);
329
		$consumer = array();
330
		$consumer['name'] = $name;
331
		$consumer['size'] = $size;
332
		$consumer['humansize'] = $humansize;
333
		$disk_contents[] = $consumer;
334
	}
335
	return $disk_contents;
336
}
337
338
/* Get only the size for one specific potential consumer. */
339
function gmirror_get_unused_consumer_size($consumer) {
340
	$consumersizes = gmirror_get_all_unused_consumer_sizes_on_disk($consumer);
341
	foreach ($consumersizes as $csize) {
342 9ba87997 Phil Davis
		if ($csize['name'] == $consumer) {
343 52398a6b jim-p
			return $csize['size'];
344 9ba87997 Phil Davis
		}
345 52398a6b jim-p
	}
346
	return -1;
347
}
348 8b335b7a Ermal LUÇI
?>