]> git.datanom.net - omvzfs.git/blame - gui/rpc/zfs.inc
Another attempt to integrate with OMV shared folders.
[omvzfs.git] / gui / rpc / zfs.inc
CommitLineData
6b3ce31b
MR
1<?php
2
3require_once("openmediavault/object.inc");
4require_once("openmediavault/config.inc");
5require_once("openmediavault/error.inc");
6require_once("openmediavault/util.inc");
7require_once("openmediavault/rpcservice.inc");
8require_once("openmediavault/notify.inc");
9require_once("zfs/Utils.php");
10require_once("zfs/Dataset.php");
11require_once("zfs/Snapshot.php");
12require_once("zfs/Zvol.php");
503ffcc8 13require_once("zfs/Zpool.php");
c0253592 14require_once("zfs/NotifyListener.php");
6b3ce31b
MR
15
16class OMVRpcServiceZFS extends OMVRpcServiceAbstract {
a36352f7
NB
17 public function getName() {
18 return "ZFS"; // RPC Service name. Same as in .js files
19 }
6b3ce31b 20
a36352f7
NB
21 /* Initialize the RPC service. Different methods of the RPC service are declared here*/
22 public function initialize() {
42856e8b 23 $this->registerMethod("addPool");
a36352f7
NB
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");
54b9d43e 33 $this->registermethod("getObjectDetails");
a36352f7 34 }
6b3ce31b 35
42856e8b
NB
36 public function addPool($params, $context) {
37 $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR));
ecee099b
NB
38 // Validate the parameters of the RPC service method.
39 $this->validateMethodParams($params, '{
40 "type":"object",
41 "properties":{
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"}
48 }
49 }');
42856e8b
NB
50 switch ($params['pooltype']) {
51 case "basic":
52 $pooltype = OMVModuleZFSVdevType::OMVMODULEZFSPLAIN;
53 break;
54 case "mirror":
55 $pooltype = OMVModuleZFSVdevType::OMVMODULEZFSMIRROR;
56 break;
57 case "raidz1":
58 $pooltype = OMVModuleZFSVdevType::OMVMODULEZFSRAIDZ1;
59 break;
60 case "raidz2":
61 $pooltype = OMVModuleZFSVdevType::OMVMODULEZFSRAIDZ2;
62 break;
63 case "raidz3":
64 $pooltype = OMVModuleZFSVdevType::OMVMODULEZFSRAIDZ3;
65 break;
66 default:
67 throw new OMVModuleZFSException("Incorrect pool type specified");
68 break;
69 }
7d6b772c
NB
70 //Check for user supplied options
71 $opts = "";
72 if ($params['force']) {
73 $opts .= "-f ";
74 }
c6117b32
NB
75 if (strlen($params['mountpoint']) > 0) {
76 $opts .= "-m " . $params['mountpoint'] . " ";
77 }
78
e20fe312 79 //Use /dev/disk/by-path as deafult when creating new pools as suggested in ZoL FAQ.
42856e8b 80 $disks = preg_split("/[,;]/", $params['devices']);
e20fe312
NB
81 if (file_exists("/dev/disk/by-path/")) {
82 $tmp_disks = array();
83 foreach ($disks as $disk) {
84 $tmp_disks[] = OMVModuleZFSUtil::getDiskPath($disk);
85 }
86 $disks = $tmp_disks;
87 }
88
42856e8b 89 $vdev = new OMVModuleZFSVdev($params['name'], $pooltype, $disks);
7d6b772c 90 $pool = new OMVModuleZFSZpool($vdev, $opts);
57667eb1
NB
91 //Ugly fix to solve the problem of blkid not displaying info on newly created pools
92 $pool->export();
93 $pool->import($pool->getName());
42856e8b
NB
94 }
95
6b3ce31b
MR
96 public function getObjectTree($params, $context) {
97 $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR));
98 $objects = OMVModuleZFSUtil::getZFSFlatArray();
99 $new = array();
100 foreach ($objects as $a){
101 $new[$a['parentid']][] = $a;
102 }
103 $tree = OMVModuleZFSUtil::createTree($new, $new['root']);
a36352f7 104 OMVModuleZFSUtil::addMissingOMVMntEnt(); //Adds missing ZFS filesystems to the OMV core
6b3ce31b
MR
105 return $tree;
106 }
107
108 public function passParam($params, $context) {
109 $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR));
ecee099b
NB
110 // Validate the parameters of the RPC service method.
111 $this->validateMethodParams($params, '{
112 "type":"object",
113 "properties":{
114 "key":{"type":"string"},
115 "value":{"type":"string"}
116 }
117 }');
6b3ce31b
MR
118 return array($params['key'] => $params['value']);
119 }
120
121 public function addObject($params, $context) {
122 $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR));
ecee099b
NB
123 // Validate the parameters of the RPC service method.
124 $this->validateMethodParams($params, '{
125 "type":"object",
126 "properties":{
127 "type":{"type":"string","enum":["filesystem","snapshot",' .
128 '"volume"]},
129 "path":{"type":"string"},
130 "name":{"type":"string"},
131 "size":{"type":"string"}
132 }
133 }');
6b3ce31b 134 switch ($params['type']) {
57667eb1 135 case "filesystem":
6b3ce31b
MR
136 $name = $params['path'] . "/" . $params['name'];
137 $tmp = new OMVModuleZFSDataset($name);
138 break;
57667eb1 139 case "snapshot":
6b3ce31b
MR
140 $name = $params['path'] . "@" . $params['name'];
141 $tmp = new OMVModuleZFSSnapshot($name);
142 break;
57667eb1 143 case "volume":
6b3ce31b
MR
144 $name = $params['path'] . "/" . $params['name'];
145 $tmp = new OMVModuleZFSZvol($name);
146 $tmp->create($params['size']);
147 break;
148 default:
149 throw new OMVModuleZFSException("Illegal type provided: " . $params['type']);
150 break;
151 }
152 }
153
154 public function deleteObject($params, $context) {
155 $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR));
ecee099b
NB
156 // Validate the parameters of the RPC service method.
157 $this->validateMethodParams($params, '{
158 "type":"object",
159 "properties":{
160 "type":{"type":"string","enum":["Filesystem","Snapshot",' .
161 '"Volume","Clone","Pool"]},
162 "name":{"type":"string"}
163 }
164 }');
97e4887b
NB
165 global $xmlConfig;
166 $name = $params['name'];
6b3ce31b 167 switch ($params['type']) {
81500319 168 case "Filesystem":
216661f4
NB
169 OMVModuleZFSUtil::deleteShares($name);
170 $tmp = new OMVModuleZFSDataset($name);
171 $tmp->destroy();
172 break;
81500319 173 case "Clone":
6b3ce31b
MR
174 $tmp = new OMVModuleZFSDataset($name);
175 $tmp->destroy();
176 break;
177 case "Snapshot":
6b3ce31b
MR
178 $tmp = new OMVModuleZFSSnapshot($name);
179 $tmp->destroy();
180 break;
181 case "Volume":
6b3ce31b
MR
182 $tmp = new OMVModuleZFSZvol($name);
183 $tmp->destroy();
184 break;
503ffcc8 185 case "Pool":
97e4887b
NB
186 $disks = OMVModuleZFSUtil::getDevDisksByPool($name);
187 $pooluuid = OMVModuleZFSUtil::getUUIDbyName($name);
503ffcc8
MR
188 $tmp = new OMVModuleZFSZpool($name);
189 $tmp->destroy();
97e4887b
NB
190 $xpath = "//system/fstab/mntent[fsname='" . $pooluuid . "' and type='zfs']";
191 $object = $xmlConfig->get($xpath);
192 $xmlConfig->delete($xpath);
97e4887b 193 OMVModuleZFSUtil::clearZFSLabel($disks);
503ffcc8 194 break;
6b3ce31b
MR
195 default:
196 throw new OMVModuleZFSException("Illegal type provided: " . $params['type']);
197 break;
198 }
199 }
200
201 public function getProperties($params, $context) {
202 $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR));
ecee099b
NB
203 // Validate the parameters of the RPC service method.
204 $this->validateMethodParams($params, '{
205 "type":"object",
206 "properties":{
207 "type":{"type":"string"},
208 "name":{"type":"string"},
209 "start":{"type":"integer"},
210 "limit":{'.$GLOBALS['OMV_JSONSCHEMA_COUNTFIELD'].'},
211 "sortfield":{'.$GLOBALS['OMV_JSONSCHEMA_SORTFIELD'].'},
212 "sortdir":{'.$GLOBALS['OMV_JSONSCHEMA_SORTDIR'].'}
213 }
214 }');
6b3ce31b
MR
215 $objects = array();
216 $name = $params['name'];
217 switch ($params['type']) {
5ff626ba
MR
218 case "Filesystem":
219 case "Clone":
6b3ce31b
MR
220 $tmp = new OMVModuleZFSDataset($name);
221 break;
222 case "Snapshot":
223 $tmp = new OMVModuleZFSSnapshot($name);
224 break;
225 case "Volume":
226 $tmp = new OMVModuleZFSZvol($name);
227 break;
503ffcc8 228 case "Pool":
a36352f7
NB
229 $tmp = new OMVModuleZFSZpool($name);
230 break;
6b3ce31b
MR
231 default:
232 throw new OMVModuleZFSException("Illegal type provided: " . $params['type']);
233 break;
234 }
235 $properties = $tmp->getProperties();
236 foreach ($properties as $propertyk => $propertyv) {
237 if (!(strcmp($propertyv['source'], "-") == 0)) {
238 $objects[] = array('property' => $propertyk,
239 'value' => $propertyv['value'],
240 'source' => $propertyv['source'],
241 'modified' => "false");
242 }
243 }
244 return $objects;
245 }
246
247 public function setProperties($params, $context) {
248 $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR));
ecee099b
NB
249 // Validate the parameters of the RPC service method.
250 $this->validateMethodParams($params, '{
251 "type":"object",
252 "properties":{
253 "type":{"type":"string","enum":["Filesystem","Snapshot",' .
254 '"Volume","Clone","Pool"]},
255 "name":{"type":"string"},
256 "properties":{"type":"array","items":{
257 "type":"object",
258 "properties":{
259 "property":{"type":"string"},
260 "value":{"type":"string"}}}}
261 }
262 }');
cc1caa78 263 global $xmlConfig;
6b3ce31b 264 switch ($params['type']) {
5ff626ba
MR
265 case "Filesystem":
266 case "Clone":
6b3ce31b
MR
267 $tmp = new OMVModuleZFSDataset($params['name']);
268 break;
269 case "Snapshot":
270 $tmp = new OMVModuleZFSSnapshot($params['name']);
271 break;
272 case "Volume":
273 $tmp = new OMVModuleZFSZvol($params['name']);
274 break;
503ffcc8
MR
275 case "Pool":
276 $tmp = new OMVModuleZFSZpool($params['name']);
277 break;
6b3ce31b
MR
278 default:
279 throw new OMVModuleZFSException("Illegal type provided: " . $params['type']);
280 break;
81500319 281 }
6b3ce31b 282 foreach ($params['properties'] as $property) {
cc1caa78
NB
283 unset($objects);
284 $objects = array();
6b3ce31b 285 $objects[$property['property']] = $property['value'];
cc1caa78
NB
286 $tmp->setProperties($objects);
287 if ((strcmp($property['property'], "mountpoint") === 0) && (strcmp($params['type'], "Filesystem") === 0)) {
288 OMVModuleZFSUtil::relocateFilesystem($params['name']);
289 }
6b3ce31b 290 }
6b3ce31b
MR
291 }
292
293 public function inherit($params, $context) {
294 $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR));
ecee099b
NB
295 // Validate the parameters of the RPC service method.
296 $this->validateMethodParams($params, '{
297 "type":"object",
298 "properties":{
299 "type":{"type":"string","enum":["Filesystem","Snapshot",' .
300 '"Volume","Clone","Pool"]},
301 "name":{"type":"string"},
302 "property":{"type":"string"}
303 }
304 }');
6b3ce31b
MR
305 // Create a background process.
306 $bgStatusFilename = $this->createBgProcStatus();
307 $pid = $this->fork();
308 if($pid > 0) { // Parent process.
309 $this->initializeBgProcStatus($bgStatusFilename, $pid);
310 return $bgStatusFilename;
311 }
312 // Child process.
313 try {
314 $bgOutputFilename = $this->createBgProcOutput();
315 $this->updateBgProcStatus($bgStatusFilename, "outputfilename", $bgOutputFilename);
316 switch ($params['type']) {
5ff626ba
MR
317 case "Filesystem":
318 case "Clone":
6b3ce31b
MR
319 $tmp = new OMVModuleZFSDataset($params['name']);
320 break;
321 case "Snapshot":
322 $tmp = new OMVModuleZFSSnapshot($params['name']);
323 break;
324 case "Volume":
325 $tmp = new OMVModuleZFSZvol($params['name']);
326 break;
503ffcc8
MR
327 case "Pool":
328 $tmp = new OMVModuleZFSZpool($params['name']);
329 break;
6b3ce31b
MR
330 default:
331 throw new OMVModuleZFSException("Illegal type provided: " . $params['type']);
332 break;
333 }
334 $tmp->inherit($params['property']);
335 $this->finalizeBgProcStatus($bgStatusFilename, $output);
336 exit(0);
337 } catch(Exception $e) {
338 $this->finalizeBgProcStatus($bgStatusFilename, "", $e);
339 exit(1);
340 }
341 }
342
343 public function getSharedParams($params, $context) {
344 $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR));
ecee099b
NB
345 // Validate the parameters of the RPC service method.
346 $this->validateMethodParams($params, '{
347 "type":"object",
348 "properties":{
349 "type":{"type":"string"},
350 "name":{"type":"string"}
351 }
352 }');
6b3ce31b 353 $objects = array();
cc1caa78
NB
354 //$ds = new OMVModuleZFSDataset($params['name']);
355 //$mountpoint = $ds->getMountPoint();
6b3ce31b 356 return array(
cc1caa78 357 //"mountpoint" => $mountpoint,
6b3ce31b
MR
358 "name" => $params['name'],
359 "type" => $params['type']);
360 }
361
362 public function createShare($params, $context) {
363 global $xmlConfig;
364 $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR));
ecee099b
NB
365 // Validate the parameters of the RPC service method.
366 $this->validateMethodParams($params, '{
367 "type":"object",
368 "properties":{
369 "name":{"type":"string"},
370 "type":{"type":"string","enum":["Filesystem","Clone"]},
371 "sharename":{'.$GLOBALS['OMV_JSONSCHEMA_SHARENAME'].'},
372 "comment":{"type":"string"},
373 "mode":{"type":"string","enum":["700","750","755",'.
374 '"770","775","777"],"optional":true},
375 "mountpoint":{"type":"string"}
376 }
377 }');
cc1caa78
NB
378
379 // The field 'reldirpath' may not contain the characters '..'. This
380 // is because of security reasons: the given canonicalized absolute
381 // path MUST be below the given mount point.
382 if(1 == preg_match("/\.\./", $params['mountpoint'])) {
383 throw new OMVException(OMVErrorMsg::E_RPC_SERVICE_METHOD_INVALID_PARAMS,
384 sprintf(gettext("The field '%s' contains forbidden two-dot symbols"), "mountpoint"));
385 }
386
6b3ce31b
MR
387 // Prepare the configuration object. Use the name of the shared
388 // folder as the relative directory name of the share.
389 switch ($params['type']) {
5ff626ba 390 case "Filesystem":
a36352f7
NB
391 $tmp = new OMVModuleZFSDataset($params['name']);
392 break;
5ff626ba 393 case "Clone":
a36352f7 394 $tmp = new OMVModuleZFSDataset($params['name']);
6b3ce31b
MR
395 break;
396 default:
397 throw new OMVModuleZFSException("Illegal type provided: " . $params['type']);
398 break;
399 }
400
cc1caa78
NB
401 $poolname = OMVModuleZFSUtil::getPoolname($params['name']);
402 $pooluuid = OMVModuleZFSUtil::getUUIDbyName($poolname);
403 $dir = $tmp->getMountPoint();
404
405 //Get the mntent object and fetch it's uuid.
406 $xpath = "//system/fstab/mntent[fsname='" . $pooluuid . "' and dir='" . $dir . "' and type='zfs']";
407 $mountpoint = $xmlConfig->get($xpath);
408 $mntentref = $mountpoint['uuid'];
409
6b3ce31b 410 $uuid = OMVUtil::uuid();
cc1caa78
NB
411 $pathName = $dir . "/" . trim($params['mountpoint'], "/");
412 $reldirpath = trim($params['mountpoint'], "/");
6b3ce31b
MR
413 $object = array(
414 "uuid" => $uuid,
415 "name" => $params['sharename'],
cc1caa78 416 "comment" => $params['comment'] . "*** ZFS share on " . $params['name'] . " ***",
6b3ce31b
MR
417 "mntentref" => $mntentref,
418 "reldirpath" => $reldirpath
419 );
420
421 // Set the configuration object.
422 $success = FALSE;
423 // Check uniqueness. The share name must be global unique because
424 // the name is also used when exporting a shared folder via NFS for
425 // example.
426 $xpath = sprintf("//system/shares/sharedfolder[name='%s']",
427 $params['name']);
428 if(TRUE === $xmlConfig->exists($xpath)) {
429 throw new OMVException(OMVErrorMsg::E_CONFIG_OBJECT_UNIQUENESS,
430 gettext("A shared folder with the given name already exists"));
431 }
432
433 // Add empty list of privileges per default.
434 $object['privileges'] = array();
435
436 // Append object to configuration.
437 $success = $xmlConfig->set("//system/shares",
438 array("sharedfolder" => $object));
439 if(FALSE === $success) {
440 throw new OMVException(OMVErrorMsg::E_CONFIG_SET_OBJECT_FAILED);
441 }
442
443 // Append the file mode field to the notification object if set.
444 // Defaults to 775.
445 $object['mode'] = "775";
446 if(array_key_exists("mode", $params)) {
447 $object['mode'] = $params['mode'];
448 }
449
cc1caa78
NB
450 // Create the shared folder directory if necessary.
451 if(FALSE === file_exists($pathName)) {
452 // Create the directory. Note, the function seems to have a bug
453 // when using the mask parameter. E.g. octdec("777") does not
454 // create the correct permissions as expected, thus change the
455 // mode using chmod.
456 if(FALSE === mkdir($pathName, 0700, TRUE)) {
457 throw new OMVException(OMVErrorMsg::E_MISC_FAILURE,
458 sprintf("Failed to create the directory '%s'", $pathName));
459 }
460 // Change the directory mode.
461 if(FALSE === chmod($pathName, octdec($object['mode']))) {
462 throw new OMVException(OMVErrorMsg::E_MISC_FAILURE,
463 sprintf("Failed to set file mode to '%s' for '%s'",
464 $object['mode'], $pathName));
465 }
466 }
467
6b3ce31b
MR
468 // Change group owner of directory to configured default group,
469 // e.g. 'users'.
470 if(FALSE === chgrp($pathName, $GLOBALS['OMV_USERMGMT_DEFAULT_GROUP'])) {
471 throw new OMVException(OMVErrorMsg::E_MISC_FAILURE,
472 sprintf("Failed to set file group to '%s' for '%s'",
473 $GLOBALS['OMV_USERMGMT_DEFAULT_GROUP'], $pathName));
474 }
475
476 // Set the setgid bit. Setting this permission means that all files
477 // created in the folder will inherit the group of the folder rather
478 // than the primary group of the user who creates the file.
479 $mode = fileperms($pathName) | 02000;
480 if(FALSE === chmod($pathName, $mode)) {
481 throw new OMVException(OMVErrorMsg::E_MISC_FAILURE,
482 sprintf("Failed to set file mode to '%o' for '%s'",
483 $mode, $pathName));
484 }
485
486 // Notify configuration changes.
487 $dispatcher = &OMVNotifyDispatcher::getInstance();
488 $dispatcher->notify(OMV_NOTIFY_CREATE,"org.openmediavault.system.shares.sharedfolder", $object);
489 // Return the configuration object.
490 return $object;
6b3ce31b
MR
491 }
492
54b9d43e
NB
493 public function getObjectDetails($params, $context) {
494 $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR));
495 // Validate the parameters of the RPC service method.
496 $this->validateMethodParams($params, '{
497 "type":"object",
498 "properties":{
499 "name":{"type":"string"},
500 "type":{"type":"string"}
501 }
502 }');
503 $output = "";
504 switch ($params['type']) {
505 case "Filesystem":
506 $output .= "Filesystem details (zfs get all):\n\r\n\r";
507 $cmd = "zfs get all {$params['name']}";
508 break;
509 case "Volume":
510 $output .= "Volume details (zfs get all):\n\r\n\r";
511 $cmd = "zfs get all {$params['name']}";
512 break;
513 case "Snapshot":
514 $output .= "Snapshot details (zfs get all):\n\r\n\r";
515 $cmd = "zfs get all {$params['name']}";
516 break;
517 case "Pool":
518 $output .= "Pool details (zpool get all):\n\r\n\r";
519 $cmd = "zpool get all {$params['name']}";
520 break;
521 default:
522 throw new OMVModuleZFSException("Incorrect type provided");
523 }
524 OMVModuleZFSUtil::exec($cmd,$out,$res);
525 $output .= implode("\n\r", $out);
526 return array("details" => $output);
527 }
6b3ce31b
MR
528}
529
530// Register the RPC service.
81500319 531$rpcServiceMgr = &OMVRpcServiceMgr::getInstance(); // Get the "root" instance for the Services
6b3ce31b
MR
532$rpcServiceMgr->registerService(new OMVRpcServiceZFS()); // Register a new instance of the RPC service described above
533?>
534
This page took 0.115333 seconds and 5 git commands to generate.