]> git.datanom.net - omvzfs.git/blobdiff - src/Zpool.php
First complete implementation of Zpool class
[omvzfs.git] / src / Zpool.php
index ef4f83589cef20db1bae111e7b69f0c897d8605c..5896554e06fe405fb45ffa15414470df79468540 100644 (file)
 <?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 OMVModuleZFSZpool {
+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;
        }
 }
 
This page took 0.070918 seconds and 5 git commands to generate.