X-Git-Url: http://git.datanom.net/omvzfs.git/blobdiff_plain/f891182fc1ca2217dfab6d0a90cf30b22d03545b..b71de6b53716e7c7d2670b88de09aa7db7f4e547:/src/Vdev.php diff --git a/src/Vdev.php b/src/Vdev.php index e740edf..a5f8f9c 100644 --- a/src/Vdev.php +++ b/src/Vdev.php @@ -1,54 +1,204 @@ */ -class Vdev { +class OMVModuleZFSVdev { // Attributes /** - * XXX + * Array holding disks * - * @var list $disks + * @var array $disks * @access private */ - protected $_disks; + private $disks; + + /** + * Name of pool + * + * @var string $pool pool name + * @access private + */ + private $pool; + + /** + * This vdev type + * + * @var OMVModuleZFSVdevType $type Vdev type + * @access private + */ + private $type; // Associations // Operations + /** + * Constructor + * + * @param $pool pool this mirror belongs to + * @throws OMVModuleZFSException + */ + + public function __construct($pool, $type, array $disks) { + switch ($type) { + case OMVModuleZFSVdevType::OMVMODULEZFSPLAIN: + break; + case OMVModuleZFSVdevType::OMVMODULEZFSMIRROR: + if (count($disks) < 2) + throw new OMVModuleZFSException("A mirror must contain at least 2 disks"); + break; + case OMVModuleZFSVdevType::OMVMODULEZFSRAIDZ1: + if (count($disks) < 3) + throw new OMVModuleZFSException("A Raidz1 must contain at least 3 disks"); + break; + case OMVModuleZFSVdevType::OMVMODULEZFSRAIDZ2: + if (count($disks) < 4) + throw new OMVModuleZFSException("A Raidz2 must contain at least 4 disks"); + break; + case OMVModuleZFSVdevType::OMVMODULEZFSRAIDZ3: + if (count($disks) < 5) + throw new OMVModuleZFSException("A Raidz3 must contain at least 5 disks"); + break; + default: + throw new OMVModuleZFSException("$type: Unknown zpool type"); + } + $this->pool = $pool; + $this->disks = $disks; + $this->type = $type; + } + + /** + * Helper function to execute an external program. + * @param command The command that will be executed. + * @param output If the output argument is present, then the specified + * array will be filled with every line of output from the command. + * Trailing whitespace, such as \n, is not included in this array. + * @return The exit code of the command. + * @throws E_EXEC_FAILED + */ + private function exec($command, &$output = NULL) { + OMVUtil::exec($command, $output, $result); + return $result; + } + + private function safeExec($disk, $add = true, $change = false) { + $result = 1; + + if ($add) { + if ($change || $this->type == OMVModuleZFSVdevType::OMVMODULEZFSMIRROR) { + $disk1 = $this->disks[0]; + $result = exec("zpool attach {$this->pool} $disk1 $disk", $err); + } else { + $result = exec("zpool add {$this->pool} $disk", $err); + } + } else { + if ($this->type == OMVModuleZFSVdevType::OMVMODULEZFSMIRROR) { + $disk1 = $this->disks[0]; + if (($res = exec("zpool offline {$this->pool} $disk", $err)) > 0) + $result = $res; + else + $result = exec("zpool detach {$this->pool} $disk", $err); + } else { + $result = 1; + $err = "Cannot remove $disk from {$this->pool}"; + } + } + + return ($result) ? $err : null; + } + /** - * XXX + * Add a disk to this Vdev * - * @param Disk $disk XXX - * @return void XXX + * @param $disk the disk + * @throws OMVModuleZFSException * @access public */ - public function addDisk($disk) { - trigger_error('Not Implemented!', E_USER_WARNING); + public function addDisk($disk, $changeType = false) { + if ($this->type != OMVModuleZFSVdevType::OMVMODULEZFSPLAIN || + $this->type != OMVModuleZFSVdevType::OMVMODULEZFSMIRROR) + throw new OMVModuleZFSException("A Raidz Vdev cannot be changed"); + + if (in_array($disk, $this->disks)) + throw new OMVModuleZFSException("$disk: Already part of Vdev"); + + if ($this->type == OMVModuleZFSVdevType::OMVMODULEZFSPLAIN && + count($this->disks) < 2 && $changeType) { + $this->type = OMVModuleZFSVdevType::OMVMODULEZFSMIRROR; + } + + if (($err = safeExec($disk, true, $changeType)) != null) + throw new OMVModuleZFSException($err); + else + array_push($this->disks, $disk); } /** - * XXX + * Remove a disk from Vdev * - * @param Disk $disk XXX - * @return void XXX + * @param $disk disk to remove + * @throws OMVModuleZFSException * @access public */ - public abstract function removeDisk($disk) { - trigger_error('Not Implemented!', E_USER_WARNING); - } + public function removeDisk($disk, $changeType = false) { + $new_disks = array(); + + if ($this->type != OMVModuleZFSVdevType::OMVMODULEZFSMIRROR) + throw new OMVModuleZFSException("Only inactive hot spares," . + "cache, top-level, or log devices can be removed"); + + if (count($this->disks) < 3 && ! $changeType) + throw new OMVModuleZFSException("A mirror must contain at least 2 disks"); + + if (! in_array($disk, $this->disks)) + throw new OMVModuleZFSException("$disk: Not part of Vdev"); + + if (($err = safeExec($disk, false, $changeType)) != null) + throw new OMVModuleZFSException($err); + else { + foreach ($this->disks as $_disk) { + if (strcmp($_disk, $disk) != 0) + array_push($new_disks, $_disk); + } + } + + $this->disks = $new_disks; + } /** - * XXX + * Get disk array * - * @return list XXX + * @return array with disks * @access public */ public function getDisks() { - trigger_error('Not Implemented!', E_USER_WARNING); + return $this->disks; + } + + /** + * Get pool + * + * @return string pool + * @access public + */ + public function getPool() { + return $this->pool; + } + + /** + * Get type + * + * @return OMVModuleZFSVdevType + * @access public + */ + public function getType() { + return $this->type; } }