From c62686441c2ad9409f0a3a7fe87dd7c679a8ddd8 Mon Sep 17 00:00:00 2001 From: Michael Rasmussen Date: Mon, 24 Feb 2014 00:36:37 +0100 Subject: [PATCH] Latest version --- OMVModulePoolType.php | 11 +- OMVModuleZPool.php | 333 ++++++++++++++++++++++++++++++++++++------ README | 5 +- test.php | 9 +- 4 files changed, 302 insertions(+), 56 deletions(-) diff --git a/OMVModulePoolType.php b/OMVModulePoolType.php index f346bd9..c58ef76 100644 --- a/OMVModulePoolType.php +++ b/OMVModulePoolType.php @@ -25,11 +25,10 @@ */ class OMVModulePoolType { const OMVModulePoolType_TYPE_NONE = 0; - const OMVModulePoolType_TYPE_STRIPE = 1; - const OMVModulePoolType_TYPE_MIRROR = 2; - const OMVModulePoolType_TYPE_RAIDZ1 = 3; - const OMVModulePoolType_TYPE_RAIDZ2 = 4; - const OMVModulePoolType_TYPE_RAIDZ3 = 5; + const OMVModulePoolType_TYPE_MIRROR = 1; + const OMVModulePoolType_TYPE_RAIDZ1 = 2; + const OMVModulePoolType_TYPE_RAIDZ2 = 3; + const OMVModulePoolType_TYPE_RAIDZ3 = 4; /** * Return OMVModulePoolType as string. @@ -40,8 +39,6 @@ class OMVModulePoolType { public static function toString($type) { if ($type === self::OMVModulePoolType_TYPE_NONE) { return 'OMVModulePoolType_TYPE_NONE'; - } else if ($type === self::OMVModulePoolType_TYPE_STRIPE) { - return 'OMVModulePoolType_TYPE_STRIPE'; } else if ($type === self::OMVModulePoolType_TYPE_MIRROR) { return 'OMVModulePoolType_TYPE_MIRROR'; } else if ($type === self::OMVModulePoolType_TYPE_RAIDZ1) { diff --git a/OMVModuleZPool.php b/OMVModuleZPool.php index cceeebe..9859e00 100644 --- a/OMVModuleZPool.php +++ b/OMVModuleZPool.php @@ -24,7 +24,8 @@ * @class OMVModuleZPool. */ -require 'OMVModulePoolType.php'; +require ('OMVModulePoolType.php'); +require ('OMVModulePoolAction.php'); class OMVModuleZPool { @@ -33,23 +34,42 @@ class OMVModuleZPool { private $mirror_log; private $cache; private $spare; + private $alloc; + private $status; // one of null, ok, degraded, faulted, scrub, resilver + private $debug; /** * Constructor of class OMVModuleZPool. * @param params Array which can contain all or a subset of * the following fields: - * \em atime Either true or false. Default is true. - * \em compress Either true or false. Default is false. - * \em dedub Either true or false. Default is false. - * \em name Name for pool - * \em size Size of pool in either MB or GB. 100M or 100G. - * \em sync Either true or false. Default is false. - * \em type See OMVModulePoolType. - * \em vdevs Number of vdevs in pool. Default is 1. + * + * @param options Array which can contain all or a subset of + * the following fields: + * * @param debug Print debug information to STDERR. * @throws Exception. */ - public function __construct(array $params = array(), $debug = false) { + public function __construct(array $params = array(), array $options = array(), $debug = false) { $this->params = array( 'atime' => 'on', 'compress' => 'off', @@ -60,6 +80,7 @@ class OMVModuleZPool { 'type' => OMVModulePoolType::OMVModulePoolType_TYPE_NONE, 'vdevs' => 1 ); + $this->debug = $debug; foreach ($params as $key => $value) { if (array_key_exists($key, $this->params)) { @@ -70,7 +91,13 @@ class OMVModuleZPool { } } - if ($debug) { + foreach ($options as $key => $value) { + $this->validate($key, $value, true); + } + + $this->status = null; + + if ($this->debug) { fprintf(STDERR, "OMVModuleZPool instantiate with the following params\n"); foreach ($this->params as $key => $value) { $param = ($key == 'type') ? OMVModulePoolType::toString($value) : $value; @@ -81,37 +108,169 @@ class OMVModuleZPool { /** * Create pool. - * @param disks Array of disks. Format: /dev/sdx or /dev/vdx. + * @param disks Array of disks. Format: /dev/disk/by-id/... + * @param name Name for the pool. + * @param options Array which can contain all or a subset of + * the following fields: + * + * @throws Exception. + */ + public function createPool(array $disks, $name = null, array $options = array()) { + return $this->updatePool(OMVModulePoolAction::OMVModulePoolAction_TYPE_CREATE, + $disks, count($disks), $name, $options); + } + + /** + * Add pool. + * @param disks Array of disks. Format: /dev/disk/by-id/... + * @param name Name for the pool. * @param options Array which can contain all or a subset of * the following fields: - * \em log Array which contains the following fields: - * \em disks Array of disks. Format: /dev/sdx or /dev/vdx. - * \em mirror Either true or false. Default is false. - * \em cache Disk to use for cache. Default use internal. - * \em spare Array of disks. Format: /dev/sdx or /dev/vdx. + * * @throws Exception. */ - public function createPool(array $disks, array $options = array()) { - $disk_num = count($disks); + public function addPool(array $disks, $name = null, array $options = array()) { + $this->initPool($name); + return $this->updatePool(OMVModulePoolAction::OMVModulePoolAction_TYPE_ADD, + $disks, count($disks), $name, $options); + } + + public function removeDevice(array $disks, $name = null) { + } + + public function destroyPool($name = null) { + } + + public function scrubPool($name = null) { + } + + public function exportPool($name = null){ + } + + public function importPool($name = null){ + } + + /* + * public function attachDevice($extingDisk, $newDisk, $name = null) + * public function detachDevice($disk, $name = null) + * public function onlineDevice($disk, $name = null) + * public function offlineDevice($disk, $name = null) + * public function replaceDevice($extingDisk, $newDisk, $name = null) + * public function upgradePool($name = null) + */ + + private function initPool($name = null) { + // Replace with OMVUtil::exec + $this->validateName($name); + } + + private function validateName($name = null) { + $oldname = null; + if ($name != null) { + $oldname = $this->params['name']; + $this->params['name'] = $name; + } + if (! $this->params['name'] || ! preg_match('/^\w+$/', $this->params['name'])) { + if ($oldname) { + $this->params['name'] = $oldname; + } + throw new Exception("Name of pool cannot be null or empty"); + } + } + + /** + * Update pool. + * @param action Action to be taken. create or add. + * @param disks Array of disks. Format: /dev/disk/by-id/... + * @param disk_num Number of disk(s) in the pool. + * @param name Name for the pool. + * @param options Array which can contain all or a subset of + * the following fields: + * + * @throws Exception. + */ + private function updatePool($action, array $disks, $disk_num, $name = null, array $options = array()) { + OMVModulePoolAction::toString($action); + $cmd = 'zpool ' . OMVModulePoolAction::getAction($action); if ($disk_num < 1) { throw new Exception("Pool must have at least 1 disk"); }; + $this->validateName($name); + foreach ($options as $key => $value) { + $this->validate($key, $value, true); + } + switch ($action) { + case OMVModulePoolAction::OMVModulePoolAction_TYPE_CREATE: + $cmd .= ' ' . $this->params['name']; + break; + case OMVModulePoolAction::OMVModulePoolAction_TYPE_ADD: + $cmd .= ' ' . $this->params['name']; + break; + } switch ($this->params['type']) { case OMVModulePoolType::OMVModulePoolType_TYPE_NONE: print "Create basic pool\n"; - if ($disk_num % $this->params['vdevs']) { - throw new Exception("$disk_num disk(s) != ".$this->params['vdevs']." vdev(s)"); + if ($this->params['vdevs'] != 1) { + throw new Exception("A basic zpool can only have 1 vdev"); } - foreach ($options as $key => $value) { - $this->validate($key, $value, OMVPoolType::OMV_TYPE_NONE); + $vdev = ''; + foreach ($disks as $disk) { + $vdev .= ($vdev) ? " $disk" : "$disk"; } + $cmd .= " $vdev"; break; case OMVModulePoolType::OMVModulePoolType_TYPE_MIRROR: print "Create mirrored pool\n"; if ($disk_num / $this->params['vdevs'] < 2 || ($disk_num / $this->params['vdevs']) % $this->params['vdevs']) { throw new Exception("$disk_num disk(s) cannot be evenly distributed to ". - $this->params['vdevs']." vdev(s) and form a proper mirror"); + $this->params['vdevs']." vdev(s) and form a proper stripe or mirror"); + } + $vdevs = array(); + $disk_sum = $disk_num / $this->params['vdevs']; + $s = ''; + for ($i = 1, $num = 0; $i <= $disk_num; $i++) { + $s .= ($s) ? " ${disks[$i-1]}" : "${disks[$i-1]}"; + if ($i % $disk_sum == 0) { + $vdevs[$num++] = $s; + $s = ''; + } + } + foreach ($vdevs as $vdev) { + $cmd .= " mirror $vdev"; } break; case OMVModulePoolType::OMVModulePoolType_TYPE_RAIDZ1: @@ -121,46 +280,130 @@ class OMVModuleZPool { throw new Exception("$disk_num disk and ".$this->params['vdevs']. " vdev(s) cannot provide mininum 3 disks per vdev for raidz1"); } + $vdevs = array(); + $disk_sum = $disk_num / $this->params['vdevs']; + $s = ''; + for ($i = 1, $num = 0; $i <= $disk_num; $i++) { + $s .= ($s) ? " ${disks[$i-1]}" : "${disks[$i-1]}"; + if ($i % $disk_sum == 0) { + $vdevs[$num++] = $s; + $s = ''; + } + } + foreach ($vdevs as $vdev) { + $cmd .= " raidz1 $vdev"; + } break; case OMVModulePoolType::OMVModulePoolType_TYPE_RAIDZ2: print "Create raidz2 pool\n"; - if ($disk_num / $this->params['vdevs'] < 5 || + if ($disk_num / $this->params['vdevs'] < 4 || ($disk_num / $this->params['vdevs']) % $this->params['vdevs']) { throw new Exception("$disk_num disk and ".$this->params['vdevs']. - " vdev(s) cannot provide mininum 5 disks per vdev for raidz2"); + " vdev(s) cannot provide mininum 4 disks per vdev for raidz2"); + } + $vdevs = array(); + $disk_sum = $disk_num / $this->params['vdevs']; + $s = ''; + for ($i = 1, $num = 0; $i <= $disk_num; $i++) { + $s .= ($s) ? " ${disks[$i-1]}" : "${disks[$i-1]}"; + if ($i % $disk_sum == 0) { + $vdevs[$num++] = $s; + $s = ''; + } + } + foreach ($vdevs as $vdev) { + $cmd .= " raidz2 $vdev"; } break; case OMVModulePoolType::OMVModulePoolType_TYPE_RAIDZ3: print "Create raidz3 pool\n"; - if ($disk_num / $this->params['vdevs'] < 8 || + if ($disk_num / $this->params['vdevs'] < 5 || ($disk_num / $this->params['vdevs']) % $this->params['vdevs']) { throw new Exception("$disk_num disk and ".$this->params['vdevs']. - " vdev(s) cannot provide mininum 8 disks per vdev for raidz3"); + " vdev(s) cannot provide mininum 5 disks per vdev for raidz3"); + } + $vdevs = array(); + $disk_sum = $disk_num / $this->params['vdevs']; + $s = ''; + for ($i = 1, $num = 0; $i <= $disk_num; $i++) { + $s .= ($s) ? " ${disks[$i-1]}" : "${disks[$i-1]}"; + if ($i % $disk_sum == 0) { + $vdevs[$num++] = $s; + $s = ''; + } + } + foreach ($vdevs as $vdev) { + $cmd .= " raidz3 $vdev"; } break; } - } - - private function validate($key, $value, $type = -1) { - if ($type > -1) { - switch ($type) { - case OMVModulePoolType::OMVModulePoolType_TYPE_NONE: - print "Create basic pool\n"; + foreach ($options as $key => $value) { + switch ($key) { + case 'log': + $cmd .= " log"; + if ($value['mirror'] === true) { + $cmd .= " mirror"; + } + foreach ($value['disks'] as $disk) { + $cmd .= " $disk"; + } break; - case OMVModulePoolType::OMVModulePoolType_TYPE_MIRROR: - print "Create mirrored pool\n"; + case 'cache': + $cmd .= " cache"; + foreach ($value as $disk) { + $cmd .= " $disk"; + } break; - case OMVModulePoolType::OMVModulePoolType_TYPE_RAIDZ1: - print "Create raidz1 pool\n"; + case 'spare': + $cmd .= " spare"; + foreach ($value as $disk) { + $cmd .= " $disk"; + } break; - case OMVModulePoolType::OMVModulePoolType_TYPE_RAIDZ2: - print "Create raidz2 pool\n"; + } + } + if ($this->debug) { + fprintf(STDERR, "%s\n", $cmd); + } + + return $cmd; + } + + /** + * Validate options. + * @param key Option to validate. + * @param value Value for option to validate. + * @param type See OMVModulePoolType. + * @throws Exception if option is invalid. + */ + private function validate($key, $value, $options = false) { + if ($options) { + switch ($key) { + case 'log': + if (! is_array($value) || ! array_key_exists('mirror', $value) || + ! array_key_exists('disks', $value)) { + throw new Exception("log option missing disks array or mirror value"); + } + if ($value['mirror'] === true && count($value['disks']) != 2) { + throw new Exception("Two disks is required to form a log mirror"); + } + $this->log = $value['disks']; + $this->mirror_log = $value['mirror']; + break; + case 'cache': + if (! is_array($value)) { + throw new Exception("log option missing disks array or mirror value"); + } + $this->cache = $value; break; - case OMVModulePoolType::OMVModulePoolType_TYPE_RAIDZ3: - print "Create raidz3 pool\n"; + case 'spare': + if (! is_array($value)) { + throw new Exception("log option missing disks array or mirror value"); + } + $this->spare = $value; break; default: - throw new Exception("$type: Unknown OMVModulePoolType"); + throw new Exception("$key: Not valid option"); } } else { switch ($key) { @@ -179,7 +422,7 @@ class OMVModuleZPool { break; case 'type': if (OMVModulePoolType::OMVModulePoolType_TYPE_NONE > $value || - OMVModulePoolType::OMVModulePoolType_TYPE_RAIDZ3 < $value) { + OMVModulePoolType::OMVModulePoolType_TYPE_RAIDZ3 < $value) { throw new Exception("$key: Value must be type of OMVPoolType found '$value'"); } break; diff --git a/README b/README index d3d8309..4a61f1d 100644 --- a/README +++ b/README @@ -1,7 +1,8 @@ Objects: - zpool -- vdev -- disk + - vdev + - disk - zvol - dataset +- snapshot diff --git a/test.php b/test.php index 88efc50..7647e68 100644 --- a/test.php +++ b/test.php @@ -1,6 +1,11 @@ 1, 'vdevs' => 2), true); - $c->createPool(array('/dev/sda', '/dev/sdb', '/dev/sdc', '/dev/sdd')); + $c = new OMVModuleZPool(array('type' => 1, 'vdevs' => 2), array(), true); + $c->addPool(array('/dev/sda', '/dev/sdb', '/dev/sdc', '/dev/sdd'), 'test', + array('log' => array('disks' => ['/dev/sde', '/dev/sdf'], 'mirror' => true), + 'cache' => ['/dev/sdg'], + 'spare' => ['/dev/sdh', '/dev/sdi']) + ); + //var_dump($c); ?> -- 2.39.2