3 require_once("openmediavault/object.inc");
4 require_once("openmediavault/config.inc");
5 require_once("openmediavault/error.inc");
6 require_once("openmediavault/util.inc");
7 require_once("openmediavault/rpcservice.inc");
8 require_once("openmediavault/notify.inc");
9 require_once("zfs/Utils.php");
10 require_once("zfs/Dataset.php");
11 require_once("zfs/Snapshot.php");
12 require_once("zfs/Zvol.php");
13 require_once("zfs/Zpool.php");
14 require_once("zfs/NotifyListener.php");
16 class OMVRpcServiceZFS extends OMVRpcServiceAbstract {
17 public function getName() {
18 return "ZFS"; // RPC Service name. Same as in .js files
21 /* Initialize the RPC service. Different methods of the RPC service are declared here*/
22 public function initialize() {
23 $this->registerMethod("addPool");
24 $this->registerMethod("getObjectTree");
25 $this->registermethod("passParam");
26 $this->registermethod("addObject");
27 $this->registermethod("deleteObject");
28 $this->registermethod("getProperties");
29 $this->registermethod("setProperties");
30 $this->registermethod("inherit");
31 $this->registermethod("getSharedParams");
32 $this->registermethod("createShare");
33 $this->registermethod("getObjectDetails");
36 public function addPool($params, $context) {
37 $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR));
38 // Validate the parameters of the RPC service method.
39 $this->validateMethodParams($params, '{
42 "pooltype":{"type":"string","enum":["basic","mirror",' .
43 '"raidz1","raidz2","raidz3"]},
44 "force":{"type":"boolean"},
45 "mountpoint":{"type":"string"},
46 "name":{"type":"string"},
47 "devices":{"type":"string"}
50 switch ($params['pooltype']) {
52 $pooltype = OMVModuleZFSVdevType::OMVMODULEZFSPLAIN;
55 $pooltype = OMVModuleZFSVdevType::OMVMODULEZFSMIRROR;
58 $pooltype = OMVModuleZFSVdevType::OMVMODULEZFSRAIDZ1;
61 $pooltype = OMVModuleZFSVdevType::OMVMODULEZFSRAIDZ2;
64 $pooltype = OMVModuleZFSVdevType::OMVMODULEZFSRAIDZ3;
67 throw new OMVModuleZFSException("Incorrect pool type specified");
70 //Check for user supplied options
72 if ($params['force']) {
75 if (strlen($params['mountpoint']) > 0) {
76 $opts .= "-m " . $params['mountpoint'] . " ";
79 //Use /dev/disk/by-path as deafult when creating new pools as suggested in ZoL FAQ.
80 $disks = preg_split("/[,;]/", $params['devices']);
81 if (file_exists("/dev/disk/by-path/")) {
83 foreach ($disks as $disk) {
84 $tmp_disks[] = OMVModuleZFSUtil::getDiskPath($disk);
89 $vdev = new OMVModuleZFSVdev($params['name'], $pooltype, $disks);
90 $pool = new OMVModuleZFSZpool($vdev, $opts);
91 //Ugly fix to solve the problem of blkid not displaying info on newly created pools
93 $pool->import($pool->getName());
96 public function getObjectTree($params, $context) {
97 $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR));
98 $objects = OMVModuleZFSUtil::getZFSFlatArray();
100 foreach ($objects as $a){
101 $new[$a['parentid']][] = $a;
103 $tree = OMVModuleZFSUtil::createTree($new, $new['root']);
104 OMVModuleZFSUtil::addMissingOMVMntEnt(); //Adds missing ZFS filesystems to the OMV core
108 public function passParam($params, $context) {
109 $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR));
110 // Validate the parameters of the RPC service method.
111 $this->validateMethodParams($params, '{
114 "key":{"type":"string"},
115 "value":{"type":"string"}
118 return array($params['key'] => $params['value']);
121 public function addObject($params, $context) {
122 $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR));
123 // Validate the parameters of the RPC service method.
124 $this->validateMethodParams($params, '{
127 "type":{"type":"string","enum":["filesystem","snapshot",' .
129 "path":{"type":"string"},
130 "name":{"type":"string"},
131 "size":{"type":"string"}
134 switch ($params['type']) {
136 $name = $params['path'] . "/" . $params['name'];
137 $tmp = new OMVModuleZFSDataset($name);
140 $name = $params['path'] . "@" . $params['name'];
141 $tmp = new OMVModuleZFSSnapshot($name);
144 $name = $params['path'] . "/" . $params['name'];
145 $tmp = new OMVModuleZFSZvol($name);
146 $tmp->create($params['size']);
149 throw new OMVModuleZFSException("Illegal type provided: " . $params['type']);
154 public function deleteObject($params, $context) {
155 $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR));
156 // Validate the parameters of the RPC service method.
157 $this->validateMethodParams($params, '{
160 "type":{"type":"string","enum":["Filesystem","Snapshot",' .
161 '"Volume","Clone","Pool"]},
162 "name":{"type":"string"}
166 $name = $params['name'];
167 switch ($params['type']) {
169 OMVModuleZFSUtil::deleteShares($name);
170 $tmp = new OMVModuleZFSDataset($name);
174 $tmp = new OMVModuleZFSDataset($name);
178 $tmp = new OMVModuleZFSSnapshot($name);
182 $tmp = new OMVModuleZFSZvol($name);
186 $disks = OMVModuleZFSUtil::getDevDisksByPool($name);
187 $pooluuid = OMVModuleZFSUtil::getUUIDbyName($name);
188 $tmp = new OMVModuleZFSZpool($name);
190 $xpath = "//system/fstab/mntent[fsname='" . $pooluuid . "' and type='zfs']";
191 $object = $xmlConfig->get($xpath);
192 $xmlConfig->delete($xpath);
193 $dispatcher = &OMVNotifyDispatcher::getInstance();
194 $dispatcher->notify(OMV_NOTIFY_DELETE,"org.openmediavault.system.fstab.mntent", $object);
195 OMVModuleZFSUtil::clearZFSLabel($disks);
198 throw new OMVModuleZFSException("Illegal type provided: " . $params['type']);
203 public function getProperties($params, $context) {
204 $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR));
205 // Validate the parameters of the RPC service method.
206 $this->validateMethodParams($params, '{
209 "type":{"type":"string"},
210 "name":{"type":"string"},
211 "start":{"type":"integer"},
212 "limit":{'.$GLOBALS['OMV_JSONSCHEMA_COUNTFIELD'].'},
213 "sortfield":{'.$GLOBALS['OMV_JSONSCHEMA_SORTFIELD'].'},
214 "sortdir":{'.$GLOBALS['OMV_JSONSCHEMA_SORTDIR'].'}
218 $name = $params['name'];
219 switch ($params['type']) {
222 $tmp = new OMVModuleZFSDataset($name);
225 $tmp = new OMVModuleZFSSnapshot($name);
228 $tmp = new OMVModuleZFSZvol($name);
231 $tmp = new OMVModuleZFSZpool($name);
234 throw new OMVModuleZFSException("Illegal type provided: " . $params['type']);
237 $properties = $tmp->getProperties();
238 foreach ($properties as $propertyk => $propertyv) {
239 if (!(strcmp($propertyv['source'], "-") == 0)) {
240 $objects[] = array('property' => $propertyk,
241 'value' => $propertyv['value'],
242 'source' => $propertyv['source'],
243 'modified' => "false");
249 public function setProperties($params, $context) {
250 $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR));
251 // Validate the parameters of the RPC service method.
252 $this->validateMethodParams($params, '{
255 "type":{"type":"string","enum":["Filesystem","Snapshot",' .
256 '"Volume","Clone","Pool"]},
257 "name":{"type":"string"},
258 "properties":{"type":"array","items":{
261 "property":{"type":"string"},
262 "value":{"type":"string"}}}}
266 switch ($params['type']) {
269 $tmp = new OMVModuleZFSDataset($params['name']);
272 $tmp = new OMVModuleZFSSnapshot($params['name']);
275 $tmp = new OMVModuleZFSZvol($params['name']);
278 $tmp = new OMVModuleZFSZpool($params['name']);
281 throw new OMVModuleZFSException("Illegal type provided: " . $params['type']);
284 foreach ($params['properties'] as $property) {
285 $objects[$property['property']] = $property['value'];
287 $tmp->setProperties($objects);
290 public function inherit($params, $context) {
291 $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR));
292 // Validate the parameters of the RPC service method.
293 $this->validateMethodParams($params, '{
296 "type":{"type":"string","enum":["Filesystem","Snapshot",' .
297 '"Volume","Clone","Pool"]},
298 "name":{"type":"string"},
299 "property":{"type":"string"}
302 // Create a background process.
303 $bgStatusFilename = $this->createBgProcStatus();
304 $pid = $this->fork();
305 if($pid > 0) { // Parent process.
306 $this->initializeBgProcStatus($bgStatusFilename, $pid);
307 return $bgStatusFilename;
311 $bgOutputFilename = $this->createBgProcOutput();
312 $this->updateBgProcStatus($bgStatusFilename, "outputfilename", $bgOutputFilename);
313 switch ($params['type']) {
316 $tmp = new OMVModuleZFSDataset($params['name']);
319 $tmp = new OMVModuleZFSSnapshot($params['name']);
322 $tmp = new OMVModuleZFSZvol($params['name']);
325 $tmp = new OMVModuleZFSZpool($params['name']);
328 throw new OMVModuleZFSException("Illegal type provided: " . $params['type']);
331 $tmp->inherit($params['property']);
332 $this->finalizeBgProcStatus($bgStatusFilename, $output);
334 } catch(Exception $e) {
335 $this->finalizeBgProcStatus($bgStatusFilename, "", $e);
340 public function getSharedParams($params, $context) {
341 $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR));
342 // Validate the parameters of the RPC service method.
343 $this->validateMethodParams($params, '{
346 "type":{"type":"string"},
347 "name":{"type":"string"}
351 $ds = new OMVModuleZFSDataset($params['name']);
352 $mountpoint = $ds->getMountPoint();
354 "mountpoint" => $mountpoint,
355 "name" => $params['name'],
356 "type" => $params['type']);
359 public function createShare($params, $context) {
361 $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR));
362 // Validate the parameters of the RPC service method.
363 $this->validateMethodParams($params, '{
366 "name":{"type":"string"},
367 "type":{"type":"string","enum":["Filesystem","Clone"]},
368 "sharename":{'.$GLOBALS['OMV_JSONSCHEMA_SHARENAME'].'},
369 "comment":{"type":"string"},
370 "mode":{"type":"string","enum":["700","750","755",'.
371 '"770","775","777"],"optional":true},
372 "mountpoint":{"type":"string"}
376 //Get the UUID of the Pool
377 $poolname = OMVModuleZFSUtil::getPoolname($params['name']);
378 $pooluuid = OMVModuleZFSUtil::getUUIDbyName($poolname);
380 //Get the mntent object and fetch it's uuid.
381 $xpath = "//system/fstab/mntent[fsname='" . $pooluuid . "']";
382 $mountpoint = $xmlConfig->get($xpath);
383 $mntentref = $mountpoint['uuid'];
385 // Prepare the configuration object. Use the name of the shared
386 // folder as the relative directory name of the share.
387 switch ($params['type']) {
389 $tmp = new OMVModuleZFSDataset($params['name']);
392 $tmp = new OMVModuleZFSDataset($params['name']);
395 throw new OMVModuleZFSException("Illegal type provided: " . $params['type']);
399 $uuid = OMVUtil::uuid();
400 $pathName = $tmp->getMountPoint();
401 $reldirpath = OMVModuleZFSUtil::getReldirpath($pathName);
404 "name" => $params['sharename'],
405 "comment" => $params['comment'],
406 "mntentref" => $mntentref,
407 "reldirpath" => $reldirpath
410 // Set the configuration object.
412 // Check uniqueness. The share name must be global unique because
413 // the name is also used when exporting a shared folder via NFS for
415 $xpath = sprintf("//system/shares/sharedfolder[name='%s']",
417 if(TRUE === $xmlConfig->exists($xpath)) {
418 throw new OMVException(OMVErrorMsg::E_CONFIG_OBJECT_UNIQUENESS,
419 gettext("A shared folder with the given name already exists"));
422 // Add empty list of privileges per default.
423 $object['privileges'] = array();
425 // Append object to configuration.
426 $success = $xmlConfig->set("//system/shares",
427 array("sharedfolder" => $object));
428 if(FALSE === $success) {
429 throw new OMVException(OMVErrorMsg::E_CONFIG_SET_OBJECT_FAILED);
432 // Append the file mode field to the notification object if set.
434 $object['mode'] = "775";
435 if(array_key_exists("mode", $params)) {
436 $object['mode'] = $params['mode'];
439 // Change group owner of directory to configured default group,
441 if(FALSE === chgrp($pathName, $GLOBALS['OMV_USERMGMT_DEFAULT_GROUP'])) {
442 throw new OMVException(OMVErrorMsg::E_MISC_FAILURE,
443 sprintf("Failed to set file group to '%s' for '%s'",
444 $GLOBALS['OMV_USERMGMT_DEFAULT_GROUP'], $pathName));
447 // Set the setgid bit. Setting this permission means that all files
448 // created in the folder will inherit the group of the folder rather
449 // than the primary group of the user who creates the file.
450 $mode = fileperms($pathName) | 02000;
451 if(FALSE === chmod($pathName, $mode)) {
452 throw new OMVException(OMVErrorMsg::E_MISC_FAILURE,
453 sprintf("Failed to set file mode to '%o' for '%s'",
457 // Notify configuration changes.
458 $dispatcher = &OMVNotifyDispatcher::getInstance();
459 $dispatcher->notify(OMV_NOTIFY_CREATE,"org.openmediavault.system.shares.sharedfolder", $object);
460 // Return the configuration object.
464 public function getObjectDetails($params, $context) {
465 $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR));
466 // Validate the parameters of the RPC service method.
467 $this->validateMethodParams($params, '{
470 "name":{"type":"string"},
471 "type":{"type":"string"}
475 switch ($params['type']) {
477 $output .= "Filesystem details (zfs get all):\n\r\n\r";
478 $cmd = "zfs get all {$params['name']}";
481 $output .= "Volume details (zfs get all):\n\r\n\r";
482 $cmd = "zfs get all {$params['name']}";
485 $output .= "Snapshot details (zfs get all):\n\r\n\r";
486 $cmd = "zfs get all {$params['name']}";
489 $output .= "Pool details (zpool get all):\n\r\n\r";
490 $cmd = "zpool get all {$params['name']}";
493 throw new OMVModuleZFSException("Incorrect type provided");
495 OMVModuleZFSUtil::exec($cmd,$out,$res);
496 $output .= implode("\n\r", $out);
497 return array("details" => $output);
501 // Register the RPC service.
502 $rpcServiceMgr = &OMVRpcServiceMgr::getInstance(); // Get the "root" instance for the Services
503 $rpcServiceMgr->registerService(new OMVRpcServiceZFS()); // Register a new instance of the RPC service described above