Project

General

Profile

Download (11.2 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	gmirror.inc
4
	Copyright (C) 2009-2014 Jim Pingle
5
	Copyright (C) 2013-2015 Electric Sheep Fencing, LP
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
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
				if (!is_array($mirrors[$currentmirror]['components'])) {
50
					$mirrors[$currentmirror]['components'] = array();
51
				}
52
				$mirrors[$currentmirror]['components'][] = $all[2];
53
			}
54
		}
55
	}
56
	/* Return an hash of mirrors and components */
57
	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) < 1) {
72
?>
73
<div class="alert alert-warning" role="alert">
74
	<p>No Mirrors Found</p>
75
</div>
76
<?php
77
		return;
78
	}
79

    
80
?>
81
<table class="table table-striped table-hover">
82
	<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
}
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
	$disklist = gmirror_get_disks();
118
	/* 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
		foreach ($parts as $part) {
124
			$all_consumers[] = $part;
125
		}
126
	}
127
	foreach ($disklist as $d) {
128
		if (!is_consumer_used($d) && !in_array($d, $all_consumers)) {
129
			$all_consumers[] = $d;
130
		}
131
	}
132
	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
	if (!is_valid_mirror($mirror)) {
146
		return array();
147
	}
148

    
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
	if (!is_valid_consumer($consumer) || !is_valid_mirror($mirror)) {
157
		return false;
158
	}
159

    
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
		if (in_array($consumer, $consumers)) {
183
			return true;
184
		}
185
	}
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
	if (!is_valid_mirror($mirror)) {
203
		return false;
204
	}
205
	return mwexec("/sbin/gmirror forget " . escapeshellarg($mirror));
206
}
207

    
208
/* Insert another consumer into a mirror */
209
function gmirror_insert_consumer($mirror, $consumer) {
210
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
211
		return false;
212
	}
213
	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
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
219
		return false;
220
	}
221
	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
	if (!is_valid_consumer($consumer)) {
227
		return false;
228
	}
229
	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
	if (!is_valid_mirror($mirror)) {
235
		return false;
236
	}
237
	$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
	global $balance_methods;
245
	if (!is_valid_mirror($mirror) || !in_array($balancemethod, $balance_methods)) {
246
		return false;
247
	}
248
	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
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
254
		return false;
255
	}
256
	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
	if (!is_valid_consumer($consumer)) {
262
		return array();
263
	}
264
	$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
	if (!is_valid_consumer($consumer)) {
277
		return array();
278
	}
279
	$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
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
291
		return false;
292
	}
293
	return mwexec("/sbin/gmirror deactivate " . escapeshellarg($mirror) . " " . escapeshellarg($consumer));
294
}
295

    
296
/* Reactivate a deactivated consumer */
297
function gmirror_activate_consumer($mirror, $consumer) {
298
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
299
		return false;
300
	}
301
	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
	if (!is_valid_mirror($mirror)) {
307
		return false;
308
	}
309
	$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
	if (!is_valid_disk($disk) || !is_consumer_unused($disk)) {
319
		return array();
320
	}
321
	$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
	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
	$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
		if ($csize['name'] == $consumer) {
343
			return $csize['size'];
344
		}
345
	}
346
	return -1;
347
}
348
?>
(22-22/65)