From 42856e8b3cb0b621218f11d7828a51d03d77ae33 Mon Sep 17 00:00:00 2001 From: Niclas Berglind Date: Tue, 2 Sep 2014 22:00:56 +0200 Subject: [PATCH] Initial implementation of GUI for adding ZFS pools plus minor bugfixes. Signed-off-by: Niclas Berglind --- .../omv/module/admin/storage/zfs/Overview.js | 166 ++++++++++++++++++ gui/rpc/zfs.inc | 28 +++ src/Utils.php | 52 +++--- src/Vdev.php | 4 +- src/Zpool.php | 4 +- 5 files changed, 228 insertions(+), 26 deletions(-) diff --git a/gui/js/omv/module/admin/storage/zfs/Overview.js b/gui/js/omv/module/admin/storage/zfs/Overview.js index 306edcf..832b5e0 100644 --- a/gui/js/omv/module/admin/storage/zfs/Overview.js +++ b/gui/js/omv/module/admin/storage/zfs/Overview.js @@ -1,6 +1,160 @@ // require("js/omv/tree/Panel.js") // require("js/omv/module/admin/storage/zfs/TreePanel.js") // require("js/omv/workspace/window/Grid.js") +// require("js/omv/form/field/CheckboxGrid.js") + +Ext.define("OMV.module.admin.storage.zfs.AddPool", { + extend: "OMV.workspace.window.Form", + requires: [ + "OMV.data.Store", + "OMV.data.Model", + "OMV.data.proxy.Rpc", + "OMV.form.field.CheckboxGrid" + ], + + rpcService: "ZFS", + rpcSetMethod: "addPool", + title: _("Create ZFS pool"), + autoLoadData: false, + hideResetButton: true, + width: 550, + height: 260, + + getFormItems: function() { + var me = this; + return [{ + xtype: "textfield", + name: "name", + fieldLabel: _("Name") + },{ + xtype: "combo", + name: "pooltype", + fieldLabel: _("Pool type"), + queryMode: "local", + store: Ext.create("Ext.data.ArrayStore", { + fields: [ "value", "text" ], + data: [ + [ "basic", _("Basic") ], + [ "mirror", _("Mirror") ], + [ "raidz1", _("RAID-Z1") ], + [ "raidz2", _("RAID-Z2") ], + [ "raidz3", _("RAID-Z3") ] + ] + }), + displayField: "text", + valueField: "value", + allowBlank: false, + editable: false, + triggerAction: "all", + value: "raidz1", + listeners: { + scope: me, + change: function(combo, value) { + var devicesField = this.findField("devices"); + switch(value) { + case "basic": + devicesField.minSelections = 1; + break; + case "mirror": + devicesField.minSelections = 2; + break; + case "raidz1": + devicesField.minSelections = 3; + break; + case "raidz2": + devicesField.minSelections = 4; + case "raidz3": + devicesField.minSelections = 5; + break; + default: + devicesField.minSelections = 2; + break; + } + devicesField.validate(); + } + } + },{ + xtype: "checkboxgridfield", + name: "devices", + fieldLabel: _("Devices"), + valueField: "devicefile", + minSelections: 3, // Min. number of devices for RAIDZ-1 + useStringValue: true, + height: 130, + store: Ext.create("OMV.data.Store", { + autoLoad: true, + model: OMV.data.Model.createImplicit({ + idProperty: "devicefile", + fields: [ + { name: "devicefile", type: "string" }, + { name: "size", type: "string" }, + { name: "vendor", type: "string" }, + { name: "serialnumber", type: "string" } + ] + }), + proxy: { + type: "rpc", + appendSortParams: false, + rpcData: { + service: "RaidMgmt", + method: "getCandidates" + } + }, + sorters: [{ + direction: "ASC", + property: "devicefile" + }] + }), + gridConfig: { + stateful: true, + stateId: "1866b5d0-327e-11e4-8c21-0800200c9a66", + columns: [{ + text: _("Device"), + sortable: true, + dataIndex: "devicefile", + stateId: "devicefile", + flex: 1 + },{ + xtype: "binaryunitcolumn", + text: _("Capacity"), + sortable: true, + dataIndex: "size", + stateId: "size", + width: 50, + flex: 1 + },{ + text: _("Vendor"), + sortable: true, + dataIndex: "vendor", + stateId: "vendor", + flex: 1 + },{ + text: _("Serial Number"), + sortable: true, + dataIndex: "serialnumber", + stateId: "serialnumber", + flex: 1 + }] + } + }]; + }, + + doSubmit: function() { + var me = this; + OMV.MessageBox.show({ + title: _("Confirmation"), + msg: _("Do you really want to create the ZFS pool?"), + buttons: Ext.Msg.YESNO, + fn: function(answer) { + if(answer === "no") + return; + me.superclass.doSubmit.call(me); + }, + scope: me, + icon: Ext.Msg.QUESTION + }); + } +}); Ext.define("OMV.module.admin.storage.zfs.AddObject", { extend: "OMV.workspace.window.Form", @@ -441,6 +595,18 @@ Ext.define("OMV.module.admin.storage.zfs.Overview", { me.callParent(arguments); }, + onAddButton: function() { + var me = this; + Ext.create("OMV.module.admin.storage.zfs.AddPool", { + listeners: { + scope: me, + submit: function() { + this.doReload(); + } + } + }).show(); + }, + onAddObjButton: function() { var me = this; var sm = me.getSelectionModel(); diff --git a/gui/rpc/zfs.inc b/gui/rpc/zfs.inc index 3d61e1a..f0b64f6 100644 --- a/gui/rpc/zfs.inc +++ b/gui/rpc/zfs.inc @@ -19,6 +19,7 @@ class OMVRpcServiceZFS extends OMVRpcServiceAbstract { /* Initialize the RPC service. Different methods of the RPC service are declared here*/ public function initialize() { + $this->registerMethod("addPool"); $this->registerMethod("getObjectTree"); $this->registermethod("passParam"); $this->registermethod("addObject"); @@ -30,6 +31,33 @@ class OMVRpcServiceZFS extends OMVRpcServiceAbstract { $this->registermethod("createShare"); } + public function addPool($params, $context) { + $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR)); + switch ($params['pooltype']) { + 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; + } + $disks = preg_split("/[,;]/", $params['devices']); + $vdev = new OMVModuleZFSVdev($params['name'], $pooltype, $disks); + $pool = new OMVModuleZFSZpool($vdev); + } + public function getObjectTree($params, $context) { $this->validateMethodContext($context, array("role" => OMV_ROLE_ADMINISTRATOR)); $objects = OMVModuleZFSUtil::getZFSFlatArray(); diff --git a/src/Utils.php b/src/Utils.php index 251157a..527d0f3 100644 --- a/src/Utils.php +++ b/src/Utils.php @@ -17,12 +17,18 @@ class OMVModuleZFSUtil { preg_match('/^([A-Za-z0-9]+)\/?.*$/', $name, $result); $name = $result[1]; unset($result); - $cmd = "blkid -o full"; + $cmd = "zpool get guid " . $name . " 2>&1"; OMVModuleZFSUtil::exec($cmd, $out, $res); - foreach($out as $line) { - if(preg_match('/^.*LABEL=\"' . $name . '\" UUID=\"([A-Za-z0-9]+)\".*TYPE=\"zfs_member\"$/', $line, $result)) { - return($result[1]); + if (isset($out)) { + $headers = preg_split('/[\s]+/', $out[0]); + for ($i=0; $iget($xpath); - if(is_null($object)) { - $uuid = OMVUtil::uuid(); - $ds = new OMVModuleZFSDataset($name); - $dir = $ds->getMountPoint(); - $object = array( - "uuid" => $uuid, - "fsname" => $pooluuid, - "dir" => $dir, - "type" => "zfs", - "opts" => "rw,relatime,xattr", - "freq" => "0", - "passno" => "2" - ); - $xmlConfig->set("//system/fstab",array("mntent" => $object)); - $dispatcher = &OMVNotifyDispatcher::getInstance(); - $dispatcher->notify(OMV_NOTIFY_CREATE,"org.openmediavault.system.fstab.mntent", $object); + if (isset($pooluuid)) { + $xpath = "//system/fstab/mntent[fsname=" . $pooluuid . "]"; + $object = $xmlConfig->get($xpath); + if(is_null($object)) { + $uuid = OMVUtil::uuid(); + $ds = new OMVModuleZFSDataset($name); + $dir = $ds->getMountPoint(); + $object = array( + "uuid" => $uuid, + "fsname" => $pooluuid, + "dir" => $dir, + "type" => "zfs", + "opts" => "rw,relatime,xattr", + "freq" => "0", + "passno" => "2" + ); + $xmlConfig->set("//system/fstab",array("mntent" => $object)); + $dispatcher = &OMVNotifyDispatcher::getInstance(); + $dispatcher->notify(OMV_NOTIFY_CREATE,"org.openmediavault.system.fstab.mntent", $object); + } } } return null; diff --git a/src/Vdev.php b/src/Vdev.php index 2c5f999..a5f8f9c 100644 --- a/src/Vdev.php +++ b/src/Vdev.php @@ -188,7 +188,7 @@ class OMVModuleZFSVdev { * @access public */ public function getPool() { - return $pool; + return $this->pool; } /** @@ -198,7 +198,7 @@ class OMVModuleZFSVdev { * @access public */ public function getType() { - return $type; + return $this->type; } } diff --git a/src/Zpool.php b/src/Zpool.php index 61220a6..c8d4ae9 100644 --- a/src/Zpool.php +++ b/src/Zpool.php @@ -145,11 +145,11 @@ class OMVModuleZFSZpool extends OMVModuleAbstract $this->cache = null; $this->features = array(); if ($create_pool) { - $cmd = "zpool create $name $cmd"; + $cmd = "zpool create $name $cmd 2>&1"; OMVUtil::exec($cmd, $output, $result); if ($result) - throw new OMVModuleZFSException($output); + throw new OMVModuleZFSException(implode("\n", $output)); else { $this->name = $name; $this->type = $type; -- 2.39.2