X-Git-Url: http://git.datanom.net/omvzfs.git/blobdiff_plain/b76f4e1734bec3862fa9326982e50386e7a6b6c1..5e58d5e209b854076b39994d3e561a6d642e2dba:/src/Zpool.php diff --git a/src/Zpool.php b/src/Zpool.php index 61a31d2..f336ee6 100644 --- a/src/Zpool.php +++ b/src/Zpool.php @@ -13,7 +13,7 @@ require_once("Exception.php"); * @copyright Michael Rasmussen */ class OMVModuleZFSZpool extends OMVModuleAbstract - implements OMVNotifyListener { + implements OMVINotifyListener { // Attributes /** * Name of pool @@ -28,7 +28,7 @@ class OMVModuleZFSZpool extends OMVModuleAbstract * * @var array $vdevs * @access private - * @accociation OMVModuleZFSVdev to vdevs + * @association OMVModuleZFSVdev to vdevs */ private $vdevs; @@ -37,7 +37,7 @@ class OMVModuleZFSZpool extends OMVModuleAbstract * * @var array $spare * @access private - * @accociation OMVModuleZFSVdev to spare + * @association OMVModuleZFSVdev to spare */ private $spare; @@ -46,7 +46,7 @@ class OMVModuleZFSZpool extends OMVModuleAbstract * * @var array $log * @access private - * @accociation OMVModuleZFSVdev to log + * @association OMVModuleZFSVdev to log */ private $log; @@ -55,7 +55,7 @@ class OMVModuleZFSZpool extends OMVModuleAbstract * * @var array $cache * @access private - * @accociation OMVModuleZFSVdev to cache + * @association OMVModuleZFSVdev to cache */ private $cache; @@ -89,7 +89,7 @@ class OMVModuleZFSZpool extends OMVModuleAbstract * * @var array $snapshot * @access private - * @accociation OMVModuleZFSSnapshot to snapshot + * @association OMVModuleZFSSnapshot to snapshot */ private $snapshot; @@ -98,7 +98,7 @@ class OMVModuleZFSZpool extends OMVModuleAbstract * * @var Dataset $dataset * @access private - * @accociation OMVModuleZFSDataset to dataset + * @association OMVModuleZFSDataset to dataset */ private $dataset; @@ -107,7 +107,7 @@ class OMVModuleZFSZpool extends OMVModuleAbstract * * @var Zvol $zvol * @access private - * @accociation OMVModuleZFSZvol to zvol + * @association OMVModuleZFSZvol to zvol */ private $zvol; @@ -115,40 +115,49 @@ class OMVModuleZFSZpool extends OMVModuleAbstract /** * Constructor * - * @param $pool pool this mirror belongs to + * @param $vdev OMVModuleZFSVdev or array(OMVModuleZFSVdev) * @throws OMVModuleZFSException */ public function __construct($vdev) { + $create_pool = true; + if (is_array($vdev)) { $cmd = $this->getCommandString($vdev); $name = $vdev[0]->getPool(); $type = $vdev[0]->getType(); - } - else { + } else if ($vdev instanceof OMVModuleZFSVdev) { $cmd = $this->getCommandString(array($vdev)); $name = $vdev->getPool(); $type = $vdev->getType(); + } else { + // Assume we make an instance of an existing pool + $create_pool = false; } - $cmd = "zpool create $name $cmd"; - OMVUtil::exec($cmd, $output, $result); - if ($result) - throw new OMVModuleZFSException($output); - else { - $this->vdevs = array(); - $this->spare = array(); - $this->log = array(); - $this->cache = array(); - $this->features = array(); - $this->name = $name; - $this->type = $type; - if (is_array($vdev)) - $this->vdevs = $vdev; - else - array_push ($this->vdevs, $vdev); - $this->size = $this->getAttribute("size"); - $this->mountPoint = $this->getAttribute("mountpoint"); + $this->vdevs = array(); + $this->spare = null; + $this->log = null; + $this->cache = null; + $this->features = array(); + if ($create_pool) { + $cmd = "zpool create $name $cmd"; + + OMVUtil::exec($cmd, $output, $result); + if ($result) + throw new OMVModuleZFSException($output); + else { + $this->name = $name; + $this->type = $type; + if (is_array($vdev)) + $this->vdevs = $vdev; + else + array_push ($this->vdevs, $vdev); + $this->size = $this->getAttribute("size"); + $this->mountPoint = $this->getAttribute("mountpoint"); + } + } else { + $this->assemblePool($vdev); } } @@ -181,12 +190,13 @@ class OMVModuleZFSZpool extends OMVModuleAbstract * @access public */ public function addVdev(array $vdevs) { - $cmd = "zpool add " . $this->getName() . " " . $this->getCommandString($vdevs); + $cmd = "zpool add " . $this->name . " " . $this->getCommandString($vdevs); OMVUtil::exec($cmd, $output, $result); if ($result) throw new OMVModuleZFSException($output); else $this->vdevs = array_merge($this->vdevs, $vdevs); + $this->size = $this->getAttribute("size"); } /** @@ -213,7 +223,7 @@ class OMVModuleZFSZpool extends OMVModuleAbstract if ($cache->getType() != OMVModuleZFSVdevType::OMVMODULEZFSPLAIN) throw new OMVModuleZFSException("Only a plain Vdev can be added as cache"); - $cmd = "zpool add " . $this->getName() . " cache " . $this->getCommandString($vdevs); + $cmd = "zpool add " . $this->name . " cache " . $this->getCommandString($vdevs); OMVUtil::exec($cmd, $output, $result); if ($result) throw new OMVModuleZFSException($output); @@ -233,30 +243,20 @@ class OMVModuleZFSZpool extends OMVModuleAbstract * @access public */ public function removeCache(array $disks = null) { - $errors = array(); - $exception = null; - if (! $disks) $disks = $this->cache; - foreach ($disks as $disk) { - $cmd = "zpool remove " . $this->getName() . " $disk"; - OMVUtil::exec($cmd, $output, $result); - if ($result) - array_push ($errors, $output); - else - $this->cache = $this->removeDisk($this->cache, $disk); - } + foreach ($disks as $disk) + $dist_str .= "$disk "; - foreach ($errors as $error) { - if ($exception) - $exception .= "\n$error"; - else - $exception = $error; + $cmd = "zpool remove " . $this->name . " $dist_str"; + OMVUtil::exec($cmd, $output, $result); + if ($result) + throw new OMVModuleZFSException($output); + else { + foreach ($disks as $disk) + $this->cache = $this->removeDisk($this->cache, $disk); } - - if ($exception) - throw new OMVModuleZFSException($exception); } /** @@ -274,20 +274,45 @@ class OMVModuleZFSZpool extends OMVModuleAbstract * * @param OMVModuleZFSVdev $log * @return void + * @throws OMVModuleZFSException * @access public */ public function addLog(OMVModuleZFSVdev $log) { - trigger_error('Not Implemented!', E_USER_WARNING); + if ($log->getType() == OMVModuleZFSVdevType::OMVMODULEZFSPLAIN || + $log->getType() == OMVModuleZFSVdevType::OMVMODULEZFSMIRROR) { + $cmd = "zpool add " . $this->name . " log " . $this->getCommandString($vdevs); + OMVUtil::exec($cmd, $output, $result); + if ($result) + throw new OMVModuleZFSException($output); + + $this->log = $log; + } else + throw new OMVModuleZFSException("Only a plain Vdev or mirror Vdev can be added as log"); } /** * XXX * * @return void + * @throws OMVModuleZFSException * @access public */ public function removeLog() { - trigger_error('Not Implemented!', E_USER_WARNING); + foreach ($this->log as $vdev) { + if ($vdev->getType() == OMVModuleZFSVdevType::OMVMODULEZFSMIRROR) { + $cmd = "zpool remove " . $this->name . " mirror-$i"; + } else { + $disks = $vdev->getDisks(); + foreach ($disks as $disk) + $dist_str .= "$disk "; + $cmd = "zpool remove " . $this->name . " $disk_str"; + } + OMVUtil::exec($cmd, $output, $result); + if ($result) + throw new OMVModuleZFSException($output); + else + $this->log = array(); + } } /** @@ -297,29 +322,55 @@ class OMVModuleZFSZpool extends OMVModuleAbstract * @access public */ public function getLog() { - trigger_error('Not Implemented!', E_USER_WARNING); + return $this->log; } /** * XXX * - * @param array $spares + * @param OMVModuleZFSVdev $spares * @return void + * @throws OMVModuleZFSException * @access public */ - public function addSpare(array $spares) { - trigger_error('Not Implemented!', E_USER_WARNING); + public function addSpare(OMVModuleZFSVdev $spares) { + if ($spares->getType() != OMVModuleZFSVdevType::OMVMODULEZFSPLAIN) + throw new OMVModuleZFSException("Only a plain Vdev can be added as spares"); + + $cmd = "zpool add " . $this->name . " spare " . $this->getCommandString($vdevs); + OMVUtil::exec($cmd, $output, $result); + if ($result) + throw new OMVModuleZFSException($output); + + $disks = $spares->getDisks(); + foreach ($disks as $disk) { + array_push ($this->spare, $disk); + } } /** * XXX * - * @param Disk $spare + * @param array $disks * @return void + * @throws OMVModuleZFSException * @access public */ - public function removeSpare($spare) { - trigger_error('Not Implemented!', E_USER_WARNING); + public function removeSpare(array $disks = null) { + if (! $disks) + $disks = $this->spare; + + foreach ($disks as $disk) + $dist_str .= "$disk "; + + $cmd = "zpool remove " . $this->name . " $dist_str"; + OMVUtil::exec($cmd, $output, $result); + if ($result) + throw new OMVModuleZFSException($output); + else { + foreach ($disks as $disk) + $this->spare = $this->removeDisk($this->spare, $disk); + } } /** @@ -329,7 +380,7 @@ class OMVModuleZFSZpool extends OMVModuleAbstract * @access public */ public function getSpares() { - trigger_error('Not Implemented!', E_USER_WARNING); + return $this->spare; } /** @@ -339,7 +390,7 @@ class OMVModuleZFSZpool extends OMVModuleAbstract * @access public */ public function getSize() { - trigger_error('Not Implemented!', E_USER_WARNING); + return $this->size; } /** @@ -349,7 +400,7 @@ class OMVModuleZFSZpool extends OMVModuleAbstract * @access public */ public function getMountPoint() { - trigger_error('Not Implemented!', E_USER_WARNING); + return $this->mountPoint; } /** @@ -357,30 +408,64 @@ class OMVModuleZFSZpool extends OMVModuleAbstract * * @param array $features * @return void + * @throws OMVModuleZFSException * @access public */ public function setFeatures(array $features) { - trigger_error('Not Implemented!', E_USER_WARNING); + foreach ($features as $feature => $value) { + $cmd = "zpool set $feature=$value " . $this->name; + OMVUtil::exec($cmd, $output, $result); + if ($result) + throw new OMVModuleZFSException($output); + } + $this->features = $this->getAllAttributes(); } /** - * XXX + * We only return array of features for which the user can + * change in GUI. * - * @return list + * @return array of features * @access public */ public function getFeatures() { - trigger_error('Not Implemented!', E_USER_WARNING); + $attrs = array(); + $featureSet = array( + 'recordsize', /* default 131072. 512 <= n^2 <= 131072*/ + 'checksum', /* on | off */ + 'compression', /* off | lzjb | gzip | zle | lz4 */ + 'atime', /* on | off */ + 'aclmode', /* discard | groupmask | passthrough | restricted */ + 'aclinherit', /* discard | noallow | restricted | passthrough | passthrough-x */ + 'casesensitivity', /* sensitive | insensitive | mixed */ + 'primarycache', /* all | none | metadata */ + 'secondarycache', /* all | none | metadata */ + 'logbias', /* latency | throughput */ + 'dedup', /* on | off */ + 'sync' /* standard | always | disabled */ + ); + if (array_count_values($this->features) < 1) + $this->features = getAllAttributes(); + foreach ($this->features as $attr => $val) { + if (in_array($attr, $featureSet)) + $attrs[$attr] = $val; + } + + return $attrs; } /** * XXX * * @return void + * @throws OMVModuleZFSException * @access public */ public function export() { - trigger_error('Not Implemented!', E_USER_WARNING); + $cmd = "zpool export " . $this->name; + OMVUtil::exec($cmd, $output, $result); + if ($result) + throw new OMVModuleZFSException($output); } /** @@ -388,58 +473,109 @@ class OMVModuleZFSZpool extends OMVModuleAbstract * * @param string $name * @return void + * @throws OMVModuleZFSException * @access public */ - public function import($name) { - trigger_error('Not Implemented!', E_USER_WARNING); + public function import($name = null) { + if ($name) + $cmd = "zpool import $name"; + else + $cmd = "zpool import"; + OMVUtil::exec($cmd, $output, $result); + if ($result) + throw new OMVModuleZFSException($output); } /** * XXX * * @return void + * @throws OMVModuleZFSException * @access public */ public function scrub() { - trigger_error('Not Implemented!', E_USER_WARNING); + $cmd = "zpool scrub " . $this->name; + OMVUtil::exec($cmd, $output, $result); + if ($result) + throw new OMVModuleZFSException($output); } /** * XXX * * @return string + * @throws OMVModuleZFSException * @access public */ public function status() { - trigger_error('Not Implemented!', E_USER_WARNING); + $cmd = "zpool status " . $this->name; + OMVUtil::exec($cmd, $output, $result); + if ($result) + throw new OMVModuleZFSException($output); } public function bindListeners(OMVNotifyDispatcher $dispatcher) { - $dispatcher->addListener( - OMV_NOTIFY_EVENT, - "org.openmediavault.module.service.nfs.start", - array($this, "onNotify")); - $dispatcher->addListener( - OMV_NOTIFY_EVENT, - "org.openmediavault.module.service.nfs.stop", - array($this, "onNotify")); - $dispatcher->addListener( - OMV_NOTIFY_EVENT, - "org.openmediavault.module.service.nfs.applyconfig", - array($this, "onNotify")); + // Update service if configuration has been modified + $dispatcher->addListener( + OMV_NOTIFY_MODIFY, + "org.openmediavault.services.nfs", + array($this, "onUpdateNFSService")); + $dispatcher->addListener( + OMV_NOTIFY_CREATE, + "org.openmediavault.services.nfs.shares.share", + array($this, "onCreateNFSShare")); + $dispatcher->addListener( + OMV_NOTIFY_DELETE, + "org.openmediavault.services.nfs.shares.share", + array($this, "onDeleteNFSShare")); + $dispatcher->addListener( + OMV_NOTIFY_MODIFY, + "org.openmediavault.services.nfs.shares.share", + array($this, "onUpdateNFSShare")); } /** * XXX - * org.openmediavault.module.service..start - * org.openmediavault.module.service..stop - * org.openmediavault.module.service..applyconfig + * org.openmediavault.services.nfs + * + * @param string event + * @access public + */ + public function onUpdateNFSService($args) { + $this->debug(sprintf("onUpdateNFSService args=%s", var_export($args, true))); + } + + /** + * XXX + * org.openmediavault.services.nfs.shares.share + * + * @param string event + * @access public + */ + public function onCreateNFSShare($args) { + $this->debug(sprintf("onCreateNFSShare args=%s", var_export($args, true))); + } + + /** + * XXX + * org.openmediavault.services.nfs.shares.share + * + * @param string event + * @access public + */ + public function onDeleteNFSShare($args) { + $this->debug(sprintf("onDeleteNFSShare args=%s", var_export($args, true))); + } + + /** + * XXX + * org.openmediavault.services.nfs.shares.share * * @param string event * @access public */ - public function onNotify($event) { - trigger_error('Not Implemented!', E_USER_WARNING); + public function onUpdateNFSShare($args) { + $this->debug(sprintf("onUpdateNFSShare args=%s", var_export($args, true))); } /** @@ -453,6 +589,10 @@ class OMVModuleZFSZpool extends OMVModuleAbstract $adds = array(); foreach ($vdevs as $vdev) { + if (is_object($vdev) == false) + throw new OMVMODULEZFSException("Not object of class OMVModuleZFSVdev"); + if (is_a($vdev, OMVModuleZFSVdev) == false) + throw new OMVMODULEZFSException("Object is not of class OMVModuleZFSVdev"); $type = $vdev->getType(); $command = ""; @@ -496,6 +636,28 @@ class OMVModuleZFSZpool extends OMVModuleAbstract return $output; } + /** + * Get all attributes from pool + * @return array of attributes + * @throws OMVModuleZFSException + */ + private function getAllAttributes() { + $attrs = array(); + $cmd = "zfs get -H all {$this->name}"; + + OMVUtil::exec($cmd, $output, $result); + if ($result) + throw new OMVModuleZFSException($output); + $res = preg_match_all("/$pool\s+(\w+)\s+([\w\d\.]+).*/", $output, $matches, PREG_SET_ORDER); + if ($res == false || $res == 0) + throw new OMVModuleZFSException("Error return by zpool get all: $output"); + foreach ($matches as $match) { + $attrs[$match[1]] = $match[2]; + } + + return $attrs; + } + /** * Remove a disk from array * @@ -513,6 +675,151 @@ class OMVModuleZFSZpool extends OMVModuleAbstract return $new_disks; } + + /** + * Construct existing pool + * + * @param string $name + * @return void + * @throws OMVModuleZFSException + */ + private function assemblePool($name) { + $cmd = "zpool list -Hv $name"; + $types = 'mirror|raidz1|raidz2|raidz3'; + $dev = null; + $type = null; + $log = false; + $cache = false; + $start = true; + + OMVUtil::exec($cmd, $output, $result); + if ($result) + throw new OMVModuleZFSException($output); + $res = preg_match("/$name\s+([\w\d]+)\s+.*/", $output, $matches); + if ($res == false || $res == 0) + throw new OMVModuleZFSException("Error return by zpool list: $output"); + + $this->name = $name; + $lines = split("\n", $output); + foreach($lines as $line) { + if ($start) { + if (preg_match("/^\s*NAME/", $line)) + $start = false; + continue; + } else { + if (preg_match("/^\s*$/", $line)) { + if ($dev) { + output($part, $type, $dev); + } + break; + } else if (preg_match("/^\s*($name|logs|cache|spares)/", $line, $match)) { + if ($dev) { + output($part, $type, $dev); + $dev = null; + $type = null; + } + $part = $match[1]; + } else { + switch ($part) { + case $name: + if (preg_match("/^\s*($types)/", $line, $match)) { + /* new vdev */ + if ($type) { + output(null, $type, $dev); + $dev = null; + } + $type = $match[1]; + } else if (preg_match("/^\s*([\w\d]+)\s+/", $line, $match)) { + if ($dev) + $dev .= " $match[1]"; + else + $dev = "$match[1]"; + } + break; + case 'logs': + if (preg_match("/^\s*([\w\d]+)\s+/", $line, $match)) { + if ($dev) + $dev .= " $match[1]"; + else + $dev = "$match[1]"; + } + break; + case 'cache': + case 'spares': + if (preg_match("/^\s*([\w\d]+)\s+/", $line, $match)) { + if ($dev) + $dev .= " $match[1]"; + else + $dev = "$match[1]"; + } + break; + default: + throw new Exception("$part: Unknown pool part"); + } + } + } + } + $this->size = $this->getAttribute("size"); + $this->mountPoint = $this->getAttribute("mountpoint"); + } + + /** + * Create pool config from parsed input + * + * @param string $part + * @param string $type + * @param string $dev + * @return void + * @throws OMVModuleZFSException + */ + private function output($part, $type, $dev) { + $disks = split(" ", $dev); + switch ($part) { + case 'logs': + if ($type && $type != 'mirror') + throw new Exception("$type: Logs can only be mirror or plain"); + if ($type) + $this->log = new OMVModuleZFSVdev($this->name, OMVModuleZFSVdevType::OMVMODULEZFSMIRROR, $disks); + else + $this->log = new OMVModuleZFSVdev($this->name, OMVModuleZFSVdevType::OMVMODULEZFSPLAIN, $disks); + break; + case 'cache': + if ($type) + throw new Exception("$type: cache can only be plain"); + $this->cache = new OMVModuleZFSVdev($this->name, OMVModuleZFSVdevType::OMVMODULEZFSPLAIN, $disks); + break; + case 'spares': + if ($type) + throw new Exception("$type: spares can only be plain"); + $this->spare = new OMVModuleZFSVdev($this->name, OMVModuleZFSVdevType::OMVMODULEZFSPLAIN, $disks); + break; + default: + if ($type) { + switch ($type) { + case 'mirror': + array_push($this->vdevs, new OMVModuleZFSVdev($this->name, OMVModuleZFSVdevType::OMVMODULEZFSMIRROR, $disks)); + $this->type = OMVModuleZFSVdevType::OMVMODULEZFSMIRROR; + break; + case 'raidz1': + array_push($this->vdevs, new OMVModuleZFSVdev($this->name, OMVModuleZFSVdevType::OMVMODULEZFSRAIDZ1, $disks)); + $this->type = OMVModuleZFSVdevType::OMVMODULEZFSRAIDZ1; + break; + case 'raidz2': + array_push($this->vdevs, new OMVModuleZFSVdev($this->name, OMVModuleZFSVdevType::OMVMODULEZFSRAIDZ2, $disks)); + $this->type = OMVModuleZFSVdevType::OMVMODULEZFSRAIDZ2; + break; + case 'raidz3': + array_push($this->vdevs, new OMVModuleZFSVdev($this->name, OMVModuleZFSVdevType::OMVMODULEZFSRAIDZ3, $disks)); + $this->type = OMVModuleZFSVdevType::OMVMODULEZFSRAIDZ3; + break; + } + } else { + array_push($this->vdevs, new OMVModuleZFSVdev($this->name, OMVModuleZFSVdevType::OMVMODULEZFSPLAIN, $disks)); + $this->type = OMVModuleZFSVdevType::OMVMODULEZFSPLAIN; + } + } + } + } ?>