<?php
-require_once 'Vdev.php';
-require_once 'Snapshot.php';
-require_once 'Dataset.php';
-require_once 'Zvol.php';
+require_once("Vdev.php");
+require_once("Snapshot.php");
+require_once("Dataset.php");
+require_once("Zvol.php");
+require_once("Exception.php");
/**
- * XXX detailed description
+ * Class containing information about the pool
*
- * @author XXX
- * @version XXX
- * @copyright XXX
+ * @author Michael Rasmussen
+ * @version 0.1
+ * @copyright Michael Rasmussen <mir@datanom.net>
*/
-class Zpool {
+class OMVModuleZFSZpool extends OMVModuleAbstract
+ implements OMVNotifyListener {
// Attributes
/**
- * XXX
+ * Name of pool
*
* @var string $name
* @access private
*/
- private $_name;
+ private $name;
/**
- * XXX
+ * List of Vdev
*
- * @var list<Vdev> $vdevs
+ * @var array $vdevs
* @access private
+ * @association OMVModuleZFSVdev to vdevs
*/
- private $_vdevs;
+ private $vdevs;
/**
- * XXX
+ * List of spares
*
- * @var list<Disk> $spare
+ * @var array $spare
* @access private
+ * @association OMVModuleZFSVdev to spare
*/
- private $_spare;
+ private $spare;
/**
- * XXX
+ * List of log
*
- * @var Log $log
+ * @var array $log
* @access private
+ * @association OMVModuleZFSVdev to log
*/
- private $_log;
+ private $log;
/**
- * XXX
+ * List of cache
*
- * @var Cache $cache
+ * @var array $cache
* @access private
+ * @association OMVModuleZFSVdev to cache
*/
- private $_cache;
+ private $cache;
/**
- * XXX
+ * Pool size
*
* @var int $size
* @access private
*/
- private $_size;
+ private $size;
/**
- * XXX
+ * Pool's mountpoint
*
* @var string $mountPoint
* @access private
*/
- private $_mountPoint;
+ private $mountPoint;
/**
- * XXX
+ * List of features
*
- * @var list<Feature> $features
+ * @var array $features
* @access private
*/
- private $_features;
+ private $features;
// Associations
/**
- * XXX
+ * Array of OMVModuleZFSSnapshot.
*
- * @var Snapshot $unnamed
+ * @var array $snapshot
* @access private
- * @accociation Snapshot to unnamed
+ * @association OMVModuleZFSSnapshot to snapshot
*/
- #var $unnamed;
+ private $snapshot;
/**
- * XXX
+ * Array of OMVModuleZFSDataset
*
- * @var Dataset $unnamed
+ * @var Dataset $dataset
* @access private
- * @accociation Dataset to unnamed
+ * @association OMVModuleZFSDataset to dataset
*/
- #var $unnamed;
+ private $dataset;
/**
- * XXX
+ * Array of OMVModuleZFSZvol
*
- * @var Zvol $unnamed
+ * @var Zvol $zvol
* @access private
- * @accociation Zvol to unnamed
+ * @association OMVModuleZFSZvol to zvol
*/
- #var $unnamed;
-
- /**
- * XXX
- *
- * @var Vdev $unnamed
- * @access private
- * @accociation Vdev to unnamed
- */
- #var $unnamed;
+ private $zvol;
// Operations
+ /**
+ * Constructor
+ *
+ * @param $vdev OMVModuleZFSVdev or array(OMVModuleZFSVdev)
+ * @throws OMVModuleZFSException
+ */
+
+ public function __construct($vdev) {
+ if (is_array($vdev)) {
+ $cmd = $this->getCommandString($vdev);
+ $name = $vdev[0]->getPool();
+ $type = $vdev[0]->getType();
+ }
+ else {
+ $cmd = $this->getCommandString(array($vdev));
+ $name = $vdev->getPool();
+ $type = $vdev->getType();
+ }
+ $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");
+ }
+ }
+
/**
- * XXX
+ * Get pool name
*
- * @return string XXX
+ * @return string
* @access public
*/
public function getName() {
- trigger_error('Not Implemented!', E_USER_WARNING);
+ return $this->name;
}
/**
- * XXX
+ * Get array of Vdev
*
- * @return list<Vdev> XXX
+ * @return array
* @access public
*/
public function getVdevs() {
- trigger_error('Not Implemented!', E_USER_WARNING);
+ return $this->vdevs;
}
/**
- * XXX
+ * Add Vdev to pool
*
- * @param Vdev $vdev XXX
- * @return void XXX
+ * @param array $vdev array of OMVModuleZFSVdev
+ * @return void
+ * @throws OMVModuleZFSException
* @access public
*/
- public function addVdev($vdev) {
- trigger_error('Not Implemented!', E_USER_WARNING);
+ public function addVdev(array $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");
}
/**
* XXX
*
- * @param Vdev $vdev XXX
- * @return void XXX
+ * @param OMVModuleZFSVdev $vdev
+ * @return void
+ * @throws OMVModuleZFSException
* @access public
*/
- public function removeVdev($vdev) {
- trigger_error('Not Implemented!', E_USER_WARNING);
+ public function removeVdev(OMVModuleZFSVdev $vdev) {
+ throw new OMVModuleZFSException("Cannot remove vdevs from a pool");
}
/**
* XXX
*
- * @param Cache $cache XXX
- * @return void XXX
+ * @param OMVModuleZFSVdev $cache
+ * @return void
+ * @throws OMVModuleZFSException
* @access public
*/
- public function addCache($cache) {
- trigger_error('Not Implemented!', E_USER_WARNING);
+ public function addCache(OMVModuleZFSVdev $cache) {
+ if ($cache->getType() != OMVModuleZFSVdevType::OMVMODULEZFSPLAIN)
+ throw new OMVModuleZFSException("Only a plain Vdev can be added as cache");
+
+ $cmd = "zpool add " . $this->name . " cache " . $this->getCommandString($vdevs);
+ OMVUtil::exec($cmd, $output, $result);
+ if ($result)
+ throw new OMVModuleZFSException($output);
+
+ $disks = $cache->getDisks();
+ foreach ($disks as $disk) {
+ array_push ($this->cache, $disk);
+ }
}
/**
* XXX
*
- * @return void XXX
+ * @param array $disks
+ * @return void
+ * @throws OMVModuleZFSException
* @access public
*/
- public function removeCache() {
- trigger_error('Not Implemented!', E_USER_WARNING);
+ public function removeCache(array $disks = null) {
+ if (! $disks)
+ $disks = $this->cache;
+
+ 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->cache = $this->removeDisk($this->cache, $disk);
+ }
}
/**
* XXX
*
- * @return Cache XXX
+ * @return Cache
* @access public
*/
public function getCache() {
- trigger_error('Not Implemented!', E_USER_WARNING);
+ return $this->cache;
}
/**
* XXX
*
- * @param Log $log XXX
- * @return void XXX
+ * @param OMVModuleZFSVdev $log
+ * @return void
* @access public
*/
- public function addLog($log) {
- trigger_error('Not Implemented!', E_USER_WARNING);
+ public function addLog(OMVModuleZFSVdev $log) {
+ 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 XXX
+ * @return void
* @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();
+ }
}
/**
* XXX
*
- * @return Log XXX
+ * @return Log
* @access public
*/
public function getLog() {
- trigger_error('Not Implemented!', E_USER_WARNING);
+ return $this->log;
}
/**
* XXX
*
- * @param Disk $spare XXX
- * @return void XXX
+ * @param OMVModuleZFSVdev $spares
+ * @return void
* @access public
*/
- public function addSpare($spare) {
- 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 XXX
- * @return void XXX
+ * @param array $disks
+ * @return void
* @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);
+ }
}
/**
* XXX
*
- * @return list<Disk> XXX
+ * @return list<Disk>
* @access public
*/
public function getSpares() {
- trigger_error('Not Implemented!', E_USER_WARNING);
+ return $this->spare;
}
/**
* XXX
*
- * @return int XXX
+ * @return int
* @access public
*/
public function getSize() {
- trigger_error('Not Implemented!', E_USER_WARNING);
+ return $this->size;
}
/**
* XXX
*
- * @return string XXX
+ * @return string
* @access public
*/
public function getMountPoint() {
- trigger_error('Not Implemented!', E_USER_WARNING);
+ return $this->mountPoint;
}
/**
* XXX
*
- * @param list<Feature> $features XXX
- * @return void XXX
+ * @param array $features
+ * @return void
* @access public
*/
- public function setFeatures($features) {
- trigger_error('Not Implemented!', E_USER_WARNING);
+ public function setFeatures(array $features) {
+ 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<Feature> XXX
+ * @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 XXX
+ * @return void
* @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);
}
/**
* XXX
*
- * @param string $name XXX
- * @return void XXX
+ * @param string $name
+ * @return void
* @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 XXX
+ * @return void
* @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 XXX
+ * @return string
* @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) {
+ // 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.<servicename>.start
- * org.openmediavault.module.service.<servicename>.stop
- * org.openmediavault.module.service.<servicename>.applyconfig
+ * org.openmediavault.services.nfs
*
* @param string event
* @access public
*/
- public function onNotify($event) {
- trigger_error('Not Implemented!', E_USER_WARNING);
+ 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 applyConfig() {
- trigger_error('Not Implemented!', E_USER_WARNING);
+ 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 stopService() {
- trigger_error('Not Implemented!', E_USER_WARNING);
+ 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 startService() {
- trigger_error('Not Implemented!', E_USER_WARNING);
+ public function onUpdateNFSShare($args) {
+ $this->debug(sprintf("onUpdateNFSShare args=%s", var_export($args, true)));
+ }
+
+ /**
+ * Convert array of Vdev to command string
+ *
+ * @param array $vdevs
+ * @return string
+ * @throws OMVMODULEZFSException
+ */
+ private function getCommandString(array $vdevs) {
+ $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 = "";
+
+ switch ($type) {
+ case OMVModuleZFSVdevType::OMVMODULEZFSPLAIN: break;
+ case OMVModuleZFSVdevType::OMVMODULEZFSMIRROR: $command = "mirror"; break;
+ case OMVModuleZFSVdevType::OMVMODULEZFSRAIDZ1: $command = "raidz1"; break;
+ case OMVModuleZFSVdevType::OMVMODULEZFSRAIDZ2: $command = "raidz2"; break;
+ case OMVModuleZFSVdevType::OMVMODULEZFSRAIDZ3: $command = "raidz3"; break;
+ default:
+ throw new OMVMODULEZFSException("Unknown Vdev type");
+ }
+ $disks = $vdev->getDisks();
+ $diskStr = "";
+ foreach($disks as $disk) {
+ $diskStr .= " $disk";
+ }
+
+ array_push ($adds, $command . $diskStr);
+ }
+
+ return join(" ", $adds);
+ }
+
+ /**
+ * Get an attribute from pool
+ *
+ * @param string $attribute
+ * @return string value
+ */
+ private function getAttribute($attribute) {
+ $cmd = "zpool list -H -o $attribute {$this->name}";
+ OMVUtil::exec($cmd, $output, $result);
+ if ($result) {
+ $cmd = "zfs list -H -o $attribute {$this->name}";
+ OMVUtil::exec($cmd, $output, $result);
+ if ($result)
+ return null;
+ }
+
+ return $output;
+ }
+
+ /**
+ * Get all attributes from pool
+ * @return array of attributes
+ */
+ 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
+ *
+ * @param array $array
+ * @param string $disk
+ * @return array
+ */
+ private function removeDisk(array $array, $disk) {
+ $new_disks = array();
+
+ foreach ($array as $item) {
+ if (strcmp($item, $disk) != 0)
+ array_push ($new_disks, $item);
+ }
+
+ return $new_disks;
}
}