Project

General

Profile

Download (11.1 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	gmirror.inc
4
	Copyright (C) 2009-2014 Jim Pingle
5
	Copyright (C) 2013-2014 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
				$mirrors[$currentmirror]['components'][] = $all[2];
52
			}
53
		}
54
	}
55
	/* Return an hash of mirrors and components */
56
	return $mirrors;
57
}
58

    
59
/* Get only status word for a single mirror. */
60
function gmirror_get_status_single($mirror) {
61
	$status = "";
62
	$mirror_status = gmirror_get_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) < 1) {
71
?>
72
<div class="alert">
73
	<p>No Mirrors Found</p>
74
</div>
75
<?php
76
		return;
77
	}
78

    
79
?>
80
<table class="table table-striped">
81
	<thead>
82
		<tr>
83
			<th>Name</td>
84
			<th>Status</td>
85
			<th>Component</td>
86
		</tr>
87
	</thead>
88
	<tbody>
89
<?php foreach ($mirrors as $mirror => $name): ?>
90
		<tr>
91
			<td rowspan="<?=count($name["components"])?>"><?=$name['name']?></td>
92
			<td rowspan="<?=count($name["components"])?>"><?=$name['status']?></td>
93
			<td><?=$name['components'][0]?></td>
94
		</tr>
95
<?php if (count($name["components"]) > 1): ?>
96
		<?php foreach (array_slice($name["components"], 1) as $component): ?>
97
			<tr>
98
				<td><?=$component?></td>
99
			</tr>
100
		<?php endforeach; ?>
101
	<?php endif; ?>
102
<?php endforeach;
103
}
104

    
105
/* List all disks in the system (potential gmirror targets) */
106
function gmirror_get_disks() {
107
	$disklist = "";
108
	/* Get a list of disks in a scriptable way, exclude optical drives */
109
	exec("/sbin/geom disk status -s | /usr/bin/grep -v '[[:blank:]]*cd[[:digit:]]*' | /usr/bin/awk '{print $1;}'", $disklist);
110
	return $disklist;
111
}
112

    
113
/* List all potential gmirror consumers */
114
function gmirror_get_unused_consumers() {
115
	$consumerlist = "";
116
	$disklist = gmirror_get_disks();
117
	/* Get a list of consumers, exclude existing mirrors and diskid entries */
118
	exec("/sbin/geom part status -s | /usr/bin/egrep -v '(mirror|diskid)' | /usr/bin/awk '{print $1, $3;}'", $consumerlist);
119
	$all_consumers = array();
120
	foreach ($consumerlist as $cl) {
121
		$parts = explode(" ", $cl);
122
		foreach ($parts as $part)
123
			$all_consumers[] = $part;
124
	}
125
	foreach ($disklist as $d) {
126
		if (!is_consumer_used($d) && !in_array($d, $all_consumers)) {
127
			$all_consumers[] = $d;
128
		}
129
	}
130
	return $all_consumers;
131
}
132

    
133
/* List all existing geom mirrors */
134
function gmirror_get_mirrors() {
135
	$mirrorlist = "";
136
	exec("/sbin/gmirror list | /usr/bin/grep '^Geom name:' | /usr/bin/awk '{print $3;}'", $mirrorlist);
137
	return $mirrorlist;
138
}
139

    
140

    
141
/* List all consumers for a given mirror */
142
function gmirror_get_consumers_in_mirror($mirror) {
143
	if (!is_valid_mirror($mirror))
144
		return array();
145

    
146
	$consumers = array();
147
	exec("/sbin/gmirror status -s " . escapeshellarg($mirror) . " | /usr/bin/awk '{print $3;}'", $consumers);
148
	return $consumers;
149
}
150

    
151
/* Test if a given consumer is a member of an existing mirror */
152
function is_consumer_in_mirror($consumer, $mirror) {
153
	if (!is_valid_consumer($consumer) || !is_valid_mirror($mirror))
154
		return false;
155

    
156
	$mirrorconsumers = gmirror_get_consumers_in_mirror($mirror);
157
	return in_array(basename($consumer), $mirrorconsumers);
158
}
159

    
160
/* Test if a mirror exists */
161
function is_valid_mirror($mirror) {
162
	$mirrors = gmirror_get_mirrors();
163
	return in_array($mirror, $mirrors);
164
}
165

    
166
/* Test if a disk is valid/exists */
167
function is_valid_disk($disk) {
168
	$adisks = gmirror_get_disks();
169
	return in_array(basename($disk), $adisks);
170
}
171

    
172
/* Test if a consumer is valid and in use in a mirror */
173
function is_consumer_used($consumer) {
174
	$found = false;
175
	$mirrors = gmirror_get_mirrors();
176
	foreach ($mirrors as $mirror) {
177
		$consumers = gmirror_get_consumers_in_mirror($mirror);
178
		if (in_array($consumer, $consumers))
179
			return true;
180
	}
181
	return false;
182
}
183

    
184
/* Test if a consumer is valid and not in use */
185
function is_consumer_unused($consumer) {
186
	$consumers = gmirror_get_unused_consumers();
187
	return in_array($consumer, $consumers);
188
}
189

    
190
/* Test if a consumer is valid (either a disk or partition) */
191
function is_valid_consumer($consumer) {
192
	return (is_consumer_unused($consumer) || is_consumer_used($consumer));
193
}
194

    
195
/* Remove all disconnected drives from a mirror */
196
function gmirror_forget_disconnected($mirror) {
197
	if (!is_valid_mirror($mirror))
198
		return false;
199
	return mwexec("/sbin/gmirror forget " . escapeshellarg($mirror));
200
}
201

    
202
/* Insert another consumer into a mirror */
203
function gmirror_insert_consumer($mirror, $consumer) {
204
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer))
205
		return false;
206
	return mwexec("/sbin/gmirror insert " . escapeshellarg($mirror) . " " . escapeshellarg($consumer));
207
}
208

    
209
/* Remove consumer from a mirror and clear its metadata */
210
function gmirror_remove_consumer($mirror, $consumer) {
211
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer))
212
		return false;
213
	return mwexec("/sbin/gmirror remove " . escapeshellarg($mirror) . " " . escapeshellarg($consumer));
214
}
215

    
216
/* Wipe geom info from drive (if mirror is not running) */
217
function gmirror_clear_consumer($consumer) {
218
	if (!is_valid_consumer($consumer))
219
		return false;
220
	return mwexec("/sbin/gmirror clear " . escapeshellarg($consumer));
221
}
222

    
223
/* Find the balance method used by a given mirror */
224
function gmirror_get_mirror_balance($mirror) {
225
	if (!is_valid_mirror($mirror))
226
		return false;
227
	$balancemethod = "";
228
	exec("/sbin/gmirror list " . escapeshellarg($mirror) . " | /usr/bin/grep '^Balance:' | /usr/bin/awk '{print $2;}'", $balancemethod);
229
	return $balancemethod[0];
230
}
231

    
232
/* Change balance algorithm of the mirror */
233
function gmirror_configure_balance($mirror, $balancemethod) {
234
	global $balance_methods;
235
	if (!is_valid_mirror($mirror) || !in_array($balancemethod, $balance_methods))
236
		return false;
237
	return mwexec("/sbin/gmirror configure -b " . escapeshellarg($balancemethod) . " " . escapeshellarg($mirror));
238
}
239

    
240
/* Force a mirror member to rebuild */
241
function gmirror_force_rebuild($mirror, $consumer) {
242
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer))
243
		return false;
244
	return mwexec("/sbin/gmirror rebuild " . escapeshellarg($mirror) . " " . escapeshellarg($consumer));
245
}
246

    
247
/* Show all metadata on the physical consumer */
248
function gmirror_get_consumer_metadata($consumer) {
249
	if (!is_valid_consumer($consumer))
250
		return array();
251
	$output = "";
252
	exec("/sbin/gmirror dump " . escapeshellarg($consumer), $output);
253
	return array_map('trim', $output);
254
}
255

    
256
/* Test if a consumer has metadata, indicating it is a member of a mirror (active or inactive) */
257
function gmirror_consumer_has_metadata($consumer) {
258
	return (count(gmirror_get_consumer_metadata($consumer)) > 0);
259
}
260

    
261
/* Find the mirror to which this consumer belongs */
262
function gmirror_get_consumer_metadata_mirror($consumer) {
263
	if (!is_valid_consumer($consumer))
264
		return array();
265
	$metadata = gmirror_get_consumer_metadata($consumer);
266
	foreach ($metadata as $line) {
267
		if (substr($line, 0, 5) == "name:") {
268
			list ($key, $value) = explode(":", $line, 2);
269
			return trim($value);
270
		}
271
	}
272
}
273

    
274
/* Deactivate consumer, removing it from service in the mirror, but leave metadata intact */
275
function gmirror_deactivate_consumer($mirror, $consumer) {
276
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer))
277
		return false;
278
	return mwexec("/sbin/gmirror deactivate " . escapeshellarg($mirror) . " " . escapeshellarg($consumer));
279
}
280

    
281
/* Reactivate a deactivated consumer */
282
function gmirror_activate_consumer($mirror, $consumer) {
283
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer))
284
		return false;
285
	return mwexec("/sbin/gmirror activate " . escapeshellarg($mirror) . " " . escapeshellarg($consumer));
286
}
287

    
288
/* Find the size of the given mirror */
289
function gmirror_get_mirror_size($mirror) {
290
	if (!is_valid_mirror($mirror))
291
		return false;
292
	$mirrorsize = "";
293
	exec("/sbin/gmirror list " . escapeshellarg($mirror) . " | /usr/bin/grep 'Mediasize:' | /usr/bin/head -n 1 | /usr/bin/awk '{print $2;}'", $mirrorsize);
294
	return $mirrorsize[0];
295
}
296

    
297
/* Return a list of all potential consumers on a disk with sizes. The geom part
298
	list output is a little odd, we can't get the output for just the disk, if the disk contains
299
	slices those get output also. */
300
function gmirror_get_all_unused_consumer_sizes_on_disk($disk) {
301
	if (!is_valid_disk($disk) || !is_consumer_unused($disk))
302
		return array();
303
	$output = "";
304
	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);
305
	if (empty($output)) {
306
		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);
307
	}
308
	$disk_contents = array();
309
	foreach ($output as $line) {
310
		list($name, $size, $humansize) = explode(" ", $line, 3);
311
		$consumer = array();
312
		$consumer['name'] = $name;
313
		$consumer['size'] = $size;
314
		$consumer['humansize'] = $humansize;
315
		$disk_contents[] = $consumer;
316
	}
317
	return $disk_contents;
318
}
319

    
320
/* Get only the size for one specific potential consumer. */
321
function gmirror_get_unused_consumer_size($consumer) {
322
	$consumersizes = gmirror_get_all_unused_consumer_sizes_on_disk($consumer);
323
	foreach ($consumersizes as $csize) {
324
		if ($csize['name'] == $consumer)
325
			return $csize['size'];
326
	}
327
	return -1;
328
}
329
?>
(23-23/68)