X-Git-Url: http://git.datanom.net/omvzfs.git/blobdiff_plain/16c5355de303f315d12eb3568f1f86a2df8fe192..HEAD:/gui/rpc/zfs.inc diff --git a/gui/rpc/zfs.inc b/gui/rpc/zfs.inc index af69ec4..22011e4 100644 --- a/gui/rpc/zfs.inc +++ b/gui/rpc/zfs.inc @@ -30,10 +30,25 @@ class OMVRpcServiceZFS extends OMVRpcServiceAbstract { $this->registermethod("inherit"); $this->registermethod("getSharedParams"); $this->registermethod("createShare"); + $this->registermethod("getObjectDetails"); + $this->registermethod("expandPool"); } public function addPool($params, $context) { $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR)); + // Validate the parameters of the RPC service method. + $this->validateMethodParams($params, '{ + "type":"object", + "properties":{ + "pooltype":{"type":"string","enum":["basic","mirror",' . + '"raidz1","raidz2","raidz3"]}, + "force":{"type":"boolean"}, + "mountpoint":{"type":"string"}, + "name":{"type":"string"}, + "devices":{"type":"string"}, + "diskpath":{"type":"boolean"} + } + }'); switch ($params['pooltype']) { case "basic": $pooltype = OMVModuleZFSVdevType::OMVMODULEZFSPLAIN; @@ -63,14 +78,23 @@ class OMVRpcServiceZFS extends OMVRpcServiceAbstract { $opts .= "-m " . $params['mountpoint'] . " "; } - //Use /dev/disk/by-path as deafult when creating new pools as suggested in ZoL FAQ. $disks = preg_split("/[,;]/", $params['devices']); - if (file_exists("/dev/disk/by-path/")) { - $tmp_disks = array(); - foreach ($disks as $disk) { - $tmp_disks[] = OMVModuleZFSUtil::getDiskPath($disk); + foreach ($disks as $disk) { + OMVModuleZFSUtil::setGPTLabel($disk); + } + //Use /dev/disk/by-path as suggested in ZoL FAQ. + if ($params['diskpath']) { + try { + if (file_exists("/dev/disk/by-path/")) { + $tmp_disks = array(); + foreach ($disks as $disk) { + $tmp_disks[] = OMVModuleZFSUtil::getDiskPath($disk); + } + $disks = $tmp_disks; + } + } catch (OMVModuleZFSException $e) { + //Do nothing if an excpetion is thrown } - $disks = $tmp_disks; } $vdev = new OMVModuleZFSVdev($params['name'], $pooltype, $disks); @@ -94,17 +118,44 @@ class OMVRpcServiceZFS extends OMVRpcServiceAbstract { public function passParam($params, $context) { $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR)); - //$msg = "Key=" . $params['key'] . ";Value=" . $params['value'] . ";"; - //throw new OMVModuleZFSException($msg); + // Validate the parameters of the RPC service method. + $this->validateMethodParams($params, '{ + "type":"object", + "properties":{ + "key":{"type":"string"}, + "value":{"type":"string"} + } + }'); return array($params['key'] => $params['value']); } public function addObject($params, $context) { $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR)); + // Validate the parameters of the RPC service method. + $this->validateMethodParams($params, '{ + "type":"object", + "properties":{ + "type":{"type":"string","enum":["filesystem","snapshot",' . + '"volume","clone"]}, + "path":{"type":"string"}, + "name":{"type":"string"}, + "size":{"type":"string"}, + "clonename":{"type":"string"}, + "mountpoint":{"type":"string"} + } + }'); switch ($params['type']) { + case "clone": + $tmp = new OMVModuleZFSSnapshot($params['path']); + $tmp->clonesnap($params['clonename']); + break; case "filesystem": $name = $params['path'] . "/" . $params['name']; $tmp = new OMVModuleZFSDataset($name); + if (strlen($params['mountpoint']) > 0) { + $properties = array("mountpoint"=>$params['mountpoint']); + $tmp->setProperties($properties); + } break; case "snapshot": $name = $params['path'] . "@" . $params['name']; @@ -123,27 +174,40 @@ class OMVRpcServiceZFS extends OMVRpcServiceAbstract { public function deleteObject($params, $context) { $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR)); + // Validate the parameters of the RPC service method. + $this->validateMethodParams($params, '{ + "type":"object", + "properties":{ + "type":{"type":"string","enum":["Filesystem","Snapshot",' . + '"Volume","Pool"]}, + "name":{"type":"string"} + } + }'); + global $xmlConfig; + $name = $params['name']; switch ($params['type']) { case "Filesystem": - case "Clone": - $name = $params['name']; + OMVModuleZFSUtil::deleteShares($name); $tmp = new OMVModuleZFSDataset($name); $tmp->destroy(); break; case "Snapshot": - $name = $params['name']; $tmp = new OMVModuleZFSSnapshot($name); $tmp->destroy(); break; case "Volume": - $name = $params['name']; $tmp = new OMVModuleZFSZvol($name); $tmp->destroy(); break; case "Pool": - $name = $params['name']; + $disks = OMVModuleZFSUtil::getDevDisksByPool($name); + $pooluuid = OMVModuleZFSUtil::getUUIDbyName($name); $tmp = new OMVModuleZFSZpool($name); $tmp->destroy(); + $xpath = "//system/fstab/mntent[fsname='" . $pooluuid . "' and type='zfs']"; + $object = $xmlConfig->get($xpath); + $xmlConfig->delete($xpath); + OMVModuleZFSUtil::clearZFSLabel($disks); break; default: throw new OMVModuleZFSException("Illegal type provided: " . $params['type']); @@ -153,11 +217,22 @@ class OMVRpcServiceZFS extends OMVRpcServiceAbstract { public function getProperties($params, $context) { $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR)); + // Validate the parameters of the RPC service method. + $this->validateMethodParams($params, '{ + "type":"object", + "properties":{ + "type":{"type":"string"}, + "name":{"type":"string"}, + "start":{"type":"integer"}, + "limit":{'.$GLOBALS['OMV_JSONSCHEMA_COUNTFIELD'].'}, + "sortfield":{'.$GLOBALS['OMV_JSONSCHEMA_SORTFIELD'].'}, + "sortdir":{'.$GLOBALS['OMV_JSONSCHEMA_SORTDIR'].'} + } + }'); $objects = array(); $name = $params['name']; switch ($params['type']) { case "Filesystem": - case "Clone": $tmp = new OMVModuleZFSDataset($name); break; case "Snapshot": @@ -187,10 +262,23 @@ class OMVRpcServiceZFS extends OMVRpcServiceAbstract { public function setProperties($params, $context) { $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR)); - $objects = array(); + // Validate the parameters of the RPC service method. + $this->validateMethodParams($params, '{ + "type":"object", + "properties":{ + "type":{"type":"string","enum":["Filesystem","Snapshot",' . + '"Volume","Pool"]}, + "name":{"type":"string"}, + "properties":{"type":"array","items":{ + "type":"object", + "properties":{ + "property":{"type":"string"}, + "value":{"type":"string"}}}} + } + }'); + global $xmlConfig; switch ($params['type']) { case "Filesystem": - case "Clone": $tmp = new OMVModuleZFSDataset($params['name']); break; case "Snapshot": @@ -207,13 +295,28 @@ class OMVRpcServiceZFS extends OMVRpcServiceAbstract { break; } foreach ($params['properties'] as $property) { + unset($objects); + $objects = array(); $objects[$property['property']] = $property['value']; + $tmp->setProperties($objects); + if ((strcmp($property['property'], "mountpoint") === 0) && (strcmp($params['type'], "Filesystem") === 0)) { + OMVModuleZFSUtil::relocateFilesystem($params['name']); + } } - $tmp->setProperties($objects); } public function inherit($params, $context) { $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR)); + // Validate the parameters of the RPC service method. + $this->validateMethodParams($params, '{ + "type":"object", + "properties":{ + "type":{"type":"string","enum":["Filesystem","Snapshot",' . + '"Volume","Pool"]}, + "name":{"type":"string"}, + "property":{"type":"string"} + } + }'); // Create a background process. $bgStatusFilename = $this->createBgProcStatus(); $pid = $this->fork(); @@ -227,7 +330,6 @@ class OMVRpcServiceZFS extends OMVRpcServiceAbstract { $this->updateBgProcStatus($bgStatusFilename, "outputfilename", $bgOutputFilename); switch ($params['type']) { case "Filesystem": - case "Clone": $tmp = new OMVModuleZFSDataset($params['name']); break; case "Snapshot": @@ -254,11 +356,19 @@ class OMVRpcServiceZFS extends OMVRpcServiceAbstract { public function getSharedParams($params, $context) { $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR)); + // Validate the parameters of the RPC service method. + $this->validateMethodParams($params, '{ + "type":"object", + "properties":{ + "type":{"type":"string"}, + "name":{"type":"string"} + } + }'); $objects = array(); - $ds = new OMVModuleZFSDataset($params['name']); - $mountpoint = $ds->getMountPoint(); + //$ds = new OMVModuleZFSDataset($params['name']); + //$mountpoint = $ds->getMountPoint(); return array( - "mountpoint" => $mountpoint, + //"mountpoint" => $mountpoint, "name" => $params['name'], "type" => $params['type']); } @@ -266,42 +376,55 @@ class OMVRpcServiceZFS extends OMVRpcServiceAbstract { public function createShare($params, $context) { global $xmlConfig; $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR)); - - //Get the UUID of the Pool - $poolname = OMVModuleZFSUtil::getPoolname($params['name']); - $pooluuid = OMVModuleZFSUtil::getUUIDbyName($poolname); - - //Get the mntent object and fetch it's uuid. - $xpath = "//system/fstab/mntent[fsname=" . $pooluuid . "]"; - $mountpoint = $xmlConfig->get($xpath); - $mntentref = $mountpoint['uuid']; - + // Validate the parameters of the RPC service method. + $this->validateMethodParams($params, '{ + "type":"object", + "properties":{ + "name":{"type":"string"}, + "type":{"type":"string","enum":["Filesystem"]}, + "sharename":{'.$GLOBALS['OMV_JSONSCHEMA_SHARENAME'].'}, + "comment":{"type":"string"}, + "mode":{"type":"string","enum":["700","750","755",'. + '"770","775","777"],"optional":true}, + "mountpoint":{"type":"string"} + } + }'); + + // The field 'reldirpath' may not contain the characters '..'. This + // is because of security reasons: the given canonicalized absolute + // path MUST be below the given mount point. + if(1 == preg_match("/\.\./", $params['mountpoint'])) { + throw new OMVException(OMVErrorMsg::E_RPC_SERVICE_METHOD_INVALID_PARAMS, + sprintf(gettext("The field '%s' contains forbidden two-dot symbols"), "mountpoint")); + } + // Prepare the configuration object. Use the name of the shared // folder as the relative directory name of the share. switch ($params['type']) { case "Filesystem": $tmp = new OMVModuleZFSDataset($params['name']); break; - case "Clone": - $tmp = new OMVModuleZFSDataset($params['name']); - break; default: throw new OMVModuleZFSException("Illegal type provided: " . $params['type']); break; } + $poolname = OMVModuleZFSUtil::getPoolname($params['name']); + $pooluuid = OMVModuleZFSUtil::getUUIDbyName($poolname); + $dir = $tmp->getMountPoint(); + + //Get the mntent object and fetch it's uuid. + $xpath = "//system/fstab/mntent[fsname='" . $pooluuid . "' and dir='" . $dir . "' and type='zfs']"; + $mountpoint = $xmlConfig->get($xpath); + $mntentref = $mountpoint['uuid']; + $uuid = OMVUtil::uuid(); - $pathName = $tmp->getMountPoint(); - $subdirs = preg_split('/\//',$pathName); - $reldirpath = ""; - for ($i=2;$i $uuid, "name" => $params['sharename'], - "comment" => $params['comment'], + "comment" => $params['comment'] . "*** ZFS share on " . $params['name'] . " ***", "mntentref" => $mntentref, "reldirpath" => $reldirpath ); @@ -335,6 +458,24 @@ class OMVRpcServiceZFS extends OMVRpcServiceAbstract { $object['mode'] = $params['mode']; } + // Create the shared folder directory if necessary. + if(FALSE === file_exists($pathName)) { + // Create the directory. Note, the function seems to have a bug + // when using the mask parameter. E.g. octdec("777") does not + // create the correct permissions as expected, thus change the + // mode using chmod. + if(FALSE === mkdir($pathName, 0700, TRUE)) { + throw new OMVException(OMVErrorMsg::E_MISC_FAILURE, + sprintf("Failed to create the directory '%s'", $pathName)); + } + // Change the directory mode. + if(FALSE === chmod($pathName, octdec($object['mode']))) { + throw new OMVException(OMVErrorMsg::E_MISC_FAILURE, + sprintf("Failed to set file mode to '%s' for '%s'", + $object['mode'], $pathName)); + } + } + // Change group owner of directory to configured default group, // e.g. 'users'. if(FALSE === chgrp($pathName, $GLOBALS['OMV_USERMGMT_DEFAULT_GROUP'])) { @@ -360,6 +501,114 @@ class OMVRpcServiceZFS extends OMVRpcServiceAbstract { return $object; } + public function getObjectDetails($params, $context) { + $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR)); + // Validate the parameters of the RPC service method. + $this->validateMethodParams($params, '{ + "type":"object", + "properties":{ + "name":{"type":"string"}, + "type":{"type":"string"} + } + }'); + $output = ""; + switch ($params['type']) { + case "Filesystem": + $output .= "Filesystem details (zfs get all):\n\r\n\r"; + $cmd = "zfs get all {$params['name']}"; + break; + case "Volume": + $output .= "Volume details (zfs get all):\n\r\n\r"; + $cmd = "zfs get all {$params['name']}"; + break; + case "Snapshot": + $output .= "Snapshot details (zfs get all):\n\r\n\r"; + $cmd = "zfs get all {$params['name']}"; + break; + case "Pool": + $output .= "Pool status (zpool status):\n\r\n\r"; + $cmd = "zpool status {$params['name']}"; + OMVModuleZFSUtil::exec($cmd,$out,$res); + $output .= implode("\n\r", $out); + unset($out); + $output .= "\n\r\n\rPool details (zpool get all):\n\r\n\r"; + $cmd = "zpool get all {$params['name']}"; + OMVModuleZFSUtil::exec($cmd,$out,$res); + $output .= implode("\n\r", $out); + unset($out); + $output .= "\n\r\n\rPool filesystem details (zfs get all):\n\r\n\r"; + $cmd = "zfs get all {$params['name']}"; + break; + default: + throw new OMVModuleZFSException("Incorrect type provided"); + } + OMVModuleZFSUtil::exec($cmd,$out,$res); + $output .= implode("\n\r", $out); + return array("details" => $output); + } + + public function expandPool($params, $context) { + $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR)); + // Validate the parameters of the RPC service method. + $this->validateMethodParams($params, '{ + "type":"object", + "properties":{ + "vdevtype":{"type":"string","enum":["basic","mirror",' . + '"raidz1","raidz2","raidz3"]}, + "name":{"type":"string"}, + "devices":{"type":"string"}, + "force":{"type":"boolean"}, + "diskpath":{"type":"boolean"} + } + }'); + $pool = new OMVModuleZFSZpool($params['name']); + switch ($params['vdevtype']) { + case "basic": + $pooltype = OMVModuleZFSVdevType::OMVMODULEZFSPLAIN; + break; + case "mirror": + $pooltype = OMVModuleZFSVdevType::OMVMODULEZFSMIRROR; + break; + case "raidz1": + $pooltype = OMVModuleZFSVdevType::OMVMODULEZFSRAIDZ1; + break; + case "raidz2": + $pooltype = OMVModuleZFSVdevType::OMVMODULEZFSRAIDZ2; + break; + case "raidz3": + $pooltype = OMVModuleZFSVdevType::OMVMODULEZFSRAIDZ3; + break; + default: + throw new OMVModuleZFSException("Incorrect pool type specified"); + break; + } + if ($params['force']) { + $opts .= "-f "; + } + $disks = preg_split("/[,;]/", $params['devices']); + foreach ($disks as $disk) { + OMVModuleZFSUtil::setGPTLabel($disk); + } + //Use /dev/disk/by-path as suggested in ZoL FAQ. + if ($params['diskpath']) { + try { + if (file_exists("/dev/disk/by-path/")) { + $tmp_disks = array(); + foreach ($disks as $disk) { + $tmp_disks[] = OMVModuleZFSUtil::getDiskPath($disk); + } + $disks = $tmp_disks; + } + } catch (OMVModuleZFSException $e) { + //Do nothing if an exception is thrown + } + } + $vdev[] = new OMVModuleZFSVdev($params['name'], $pooltype, $disks); + $pool->addVdev($vdev, $opts); + //Ugly fix to solve the problem of blkid not displaying info on newly created pools + $pool->export(); + $pool->import($pool->getName()); + } } // Register the RPC service.