Project

General

Profile

Download (11.7 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) > 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
	$disklist = gmirror_get_disks();
112
	/* 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
		foreach ($parts as $part) {
118
			$all_consumers[] = $part;
119
		}
120
	}
121
	foreach ($disklist as $d) {
122
		if (!is_consumer_used($d) && !in_array($d, $all_consumers)) {
123
			$all_consumers[] = $d;
124
		}
125
	}
126
	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
	if (!is_valid_mirror($mirror)) {
140
		return array();
141
	}
142

    
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
	if (!is_valid_consumer($consumer) || !is_valid_mirror($mirror)) {
151
		return false;
152
	}
153

    
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
		if (in_array($consumer, $consumers)) {
177
			return true;
178
		}
179
	}
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
	if (!is_valid_mirror($mirror)) {
197
		return false;
198
	}
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
	}
207
	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
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
213
		return false;
214
	}
215
	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
	if (!is_valid_consumer($consumer)) {
221
		return false;
222
	}
223
	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
	if (!is_valid_mirror($mirror)) {
229
		return false;
230
	}
231
	$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
	global $balance_methods;
239
	if (!is_valid_mirror($mirror) || !in_array($balancemethod, $balance_methods)) {
240
		return false;
241
	}
242
	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
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
248
		return false;
249
	}
250
	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
	if (!is_valid_consumer($consumer)) {
256
		return array();
257
	}
258
	$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
	if (!is_valid_consumer($consumer)) {
271
		return array();
272
	}
273
	$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
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
285
		return false;
286
	}
287
	return mwexec("/sbin/gmirror deactivate " . escapeshellarg($mirror) . " " . escapeshellarg($consumer));
288
}
289

    
290
/* Reactivate a deactivated consumer */
291
function gmirror_activate_consumer($mirror, $consumer) {
292
	if (!is_valid_mirror($mirror) || !is_valid_consumer($consumer)) {
293
		return false;
294
	}
295
	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
	if (!is_valid_mirror($mirror)) {
301
		return false;
302
	}
303
	$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
	if (!is_valid_disk($disk) || !is_consumer_unused($disk)) {
313
		return array();
314
	}
315
	$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
	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
	$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
		if ($csize['name'] == $consumer) {
337
			return $csize['size'];
338
		}
339
	}
340
	return -1;
341
}
342
?>
(23-23/68)