[pve-devel] [PATCH V2 manager 1/3] fix #2822: add iscsi, lvm, lvmthin & zfs storage for all cluster nodes
Stefan Hrdlicka
s.hrdlicka at proxmox.com
Wed Jun 22 16:39:27 CEST 2022
This adds a dropdown box for iSCSI, LVM, LVMThin & ZFS storage options where a
cluster node needs to be chosen. As default the current node is
selected. It restricts the the storage to be only availabe on the
selected node.
Signed-off-by: Stefan Hrdlicka <s.hrdlicka at proxmox.com>
---
www/manager6/storage/Base.js | 44 ++++++++++++++++++++++-
www/manager6/storage/IScsiEdit.js | 54 ++++++++++++++++++++++-------
www/manager6/storage/LVMEdit.js | 21 +++++++++--
www/manager6/storage/LvmThinEdit.js | 35 ++++++++++++++-----
www/manager6/storage/ZFSPoolEdit.js | 24 ++++++++++---
5 files changed, 148 insertions(+), 30 deletions(-)
diff --git a/www/manager6/storage/Base.js b/www/manager6/storage/Base.js
index 7f6d7a09..bb497a5f 100644
--- a/www/manager6/storage/Base.js
+++ b/www/manager6/storage/Base.js
@@ -34,8 +34,9 @@ Ext.define('PVE.panel.StorageBase', {
me.column2 = me.column2 || [];
me.column2.unshift(
{
- xtype: 'pveNodeSelector',
+ xtype: 'pveScanNodeSelector',
name: 'nodes',
+ reference: 'storageNodeRestriction',
disabled: me.storageId === 'local',
fieldLabel: gettext('Nodes'),
emptyText: gettext('All') + ' (' + gettext('No restrictions') +')',
@@ -74,6 +75,47 @@ Ext.define('PVE.panel.StorageBase', {
me.callParent();
},
+ getPveScanNodeSelector: function() {
+ return {
+ xtype: 'pveScanNodeSelector',
+ name: 'node',
+ itemId: 'pveScanNodeSelector',
+ fieldLabel: gettext('Scan node'),
+ allowBlank: false,
+ disallowedNodes: undefined,
+ onlineValidator: true,
+ preferredValue: Proxmox.NodeName,
+ submitValue: false,
+ autoEl: {
+ tag: 'div',
+ 'data-qtip': gettext('Look for availabe storage options from selected node.'),
+ },
+ };
+ },
+});
+
+Ext.define('PVE.storage.ComboBoxSetStoreNode', {
+ extend: 'Ext.form.field.ComboBox',
+ config: {
+ apiBaseUrl: '/api2/json/nodes/',
+ apiStoragePath: '',
+ },
+
+ setNodeName: function(value, storeLoad = true) {
+ let me = this;
+ if (value === null || value === '') {
+ value = Proxmox.NodeName;
+ }
+
+ let store = me.getStore();
+ let proxy = store.getProxy();
+ proxy.setUrl(me.apiBaseUrl + value + me.apiStoragePath);
+ this.clearValue();
+ if (storeLoad) {
+ store.load();
+ }
+ },
+
});
Ext.define('PVE.storage.BaseEdit', {
diff --git a/www/manager6/storage/IScsiEdit.js b/www/manager6/storage/IScsiEdit.js
index 2f35f882..c121273b 100644
--- a/www/manager6/storage/IScsiEdit.js
+++ b/www/manager6/storage/IScsiEdit.js
@@ -1,5 +1,5 @@
Ext.define('PVE.storage.IScsiScan', {
- extend: 'Ext.form.field.ComboBox',
+ extend: 'PVE.storage.ComboBoxSetStoreNode',
alias: 'widget.pveIScsiScan',
queryParam: 'portal',
@@ -10,6 +10,9 @@ Ext.define('PVE.storage.IScsiScan', {
loadingText: gettext('Scanning...'),
width: 350,
},
+ config: {
+ apiStoragePath: '/scan/iscsi',
+ },
doRawQuery: function() {
// do nothing
},
@@ -42,7 +45,7 @@ Ext.define('PVE.storage.IScsiScan', {
fields: ['target', 'portal'],
proxy: {
type: 'proxmox',
- url: `/api2/json/nodes/${me.nodename}/scan/iscsi`,
+ url: me.apiBaseUrl + me.nodename + me.apiStoragePath,
},
});
store.sort('target', 'ASC');
@@ -77,8 +80,40 @@ Ext.define('PVE.storage.IScsiInputPanel', {
initComponent: function() {
var me = this;
- me.column1 = [
- {
+ me.column1 = [];
+ let target = null;
+ if (me.isCreate) {
+ target = Ext.createWidget('pveIScsiScan', {
+ readOnly: !me.isCreate,
+ name: 'target',
+ value: '',
+ fieldLabel: 'Target',
+ allowBlank: false,
+ });
+
+ let pveScanNodeSelector = me.getPveScanNodeSelector();
+ pveScanNodeSelector.listeners = {
+ change: {
+ fn: function(field, value) {
+ target.setNodeName(value, false);
+ me.lookupReference('storageNodeRestriction').setValue(value);
+ },
+ },
+ };
+ pveScanNodeSelector.preferredValue = '';
+ pveScanNodeSelector.allowBlank = true;
+ pveScanNodeSelector.autoSelect = false;
+
+ me.column1.push(pveScanNodeSelector);
+ } else {
+ target = Ext.createWidget('displayfield', {
+ name: 'target',
+ value: '',
+ fieldLabel: gettext('Target'),
+ allowBlank: false,
+ });
+ }
+ me.column1.push({
xtype: me.isCreate ? 'textfield' : 'displayfield',
name: 'portal',
value: '',
@@ -94,15 +129,8 @@ Ext.define('PVE.storage.IScsiInputPanel', {
},
},
},
- {
- readOnly: !me.isCreate,
- xtype: me.isCreate ? 'pveIScsiScan' : 'displayfield',
- name: 'target',
- value: '',
- fieldLabel: 'Target',
- allowBlank: false,
- },
- ];
+ );
+ me.column1.push(target);
me.column2 = [
{
diff --git a/www/manager6/storage/LVMEdit.js b/www/manager6/storage/LVMEdit.js
index 2a9cd283..a58982e9 100644
--- a/www/manager6/storage/LVMEdit.js
+++ b/www/manager6/storage/LVMEdit.js
@@ -1,10 +1,13 @@
Ext.define('PVE.storage.VgSelector', {
- extend: 'Ext.form.field.ComboBox',
+ extend: 'PVE.storage.ComboBoxSetStoreNode',
alias: 'widget.pveVgSelector',
valueField: 'vg',
displayField: 'vg',
queryMode: 'local',
editable: false,
+ config: {
+ apiStoragePath: '/scan/lvm',
+ },
initComponent: function() {
var me = this;
@@ -17,7 +20,7 @@ Ext.define('PVE.storage.VgSelector', {
fields: ['vg', 'size', 'free'],
proxy: {
type: 'proxmox',
- url: '/api2/json/nodes/' + me.nodename + '/scan/lvm',
+ url: me.apiBaseUrl + me.nodename + me.apiStoragePath,
},
});
@@ -103,11 +106,23 @@ Ext.define('PVE.storage.LVMInputPanel', {
});
if (me.isCreate) {
- var vgField = Ext.create('PVE.storage.VgSelector', {
+ let vgField = Ext.create('PVE.storage.VgSelector', {
name: 'vgname',
+ reference: 'pveLVMVGSelector',
fieldLabel: gettext('Volume group'),
allowBlank: false,
});
+ let pveScanNodeSelector = me.getPveScanNodeSelector();
+ pveScanNodeSelector.listeners = {
+ change: {
+ fn: function(field, value) {
+ vgField.setNodeName(value);
+ me.lookupReference('storageNodeRestriction').setValue(value);
+ },
+ },
+ };
+
+ me.column1.push(pveScanNodeSelector);
var baseField = Ext.createWidget('pveFileSelector', {
name: 'base',
diff --git a/www/manager6/storage/LvmThinEdit.js b/www/manager6/storage/LvmThinEdit.js
index 4eab7740..da72dac7 100644
--- a/www/manager6/storage/LvmThinEdit.js
+++ b/www/manager6/storage/LvmThinEdit.js
@@ -1,5 +1,5 @@
Ext.define('PVE.storage.TPoolSelector', {
- extend: 'Ext.form.field.ComboBox',
+ extend: 'PVE.storage.ComboBoxSetStoreNode',
alias: 'widget.pveTPSelector',
queryParam: 'vg',
@@ -7,6 +7,10 @@ Ext.define('PVE.storage.TPoolSelector', {
displayField: 'lv',
editable: false,
+ config: {
+ apiStoragePath: '/scan/lvmthin',
+ },
+
doRawQuery: function() {
// nothing
},
@@ -40,7 +44,7 @@ Ext.define('PVE.storage.TPoolSelector', {
fields: ['lv'],
proxy: {
type: 'proxmox',
- url: '/api2/json/nodes/' + me.nodename + '/scan/lvmthin',
+ url: me.apiBaseUrl + me.nodename + me.apiStoragePath,
},
});
@@ -58,13 +62,16 @@ Ext.define('PVE.storage.TPoolSelector', {
});
Ext.define('PVE.storage.BaseVGSelector', {
- extend: 'Ext.form.field.ComboBox',
+ extend: 'PVE.storage.ComboBoxSetStoreNode',
alias: 'widget.pveBaseVGSelector',
valueField: 'vg',
displayField: 'vg',
queryMode: 'local',
editable: false,
+ config: {
+ apiStoragePath: '/scan/lvm',
+ },
initComponent: function() {
var me = this;
@@ -77,7 +84,7 @@ Ext.define('PVE.storage.BaseVGSelector', {
fields: ['vg', 'size', 'free'],
proxy: {
type: 'proxmox',
- url: '/api2/json/nodes/' + me.nodename + '/scan/lvm',
+ url: me.apiBaseUrl + me.nodename + me.apiStoragePath,
},
});
@@ -121,14 +128,12 @@ Ext.define('PVE.storage.LvmThinInputPanel', {
});
if (me.isCreate) {
- var vgField = Ext.create('PVE.storage.TPoolSelector', {
+ let vgField = Ext.create('PVE.storage.TPoolSelector', {
name: 'thinpool',
fieldLabel: gettext('Thin Pool'),
allowBlank: false,
});
-
- me.column1.push({
- xtype: 'pveBaseVGSelector',
+ let vgSelector = Ext.create('PVE.storage.BaseVGSelector', {
name: 'vgname',
fieldLabel: gettext('Volume group'),
listeners: {
@@ -140,6 +145,20 @@ Ext.define('PVE.storage.LvmThinInputPanel', {
},
},
});
+ let pveScanNodeSelector = me.getPveScanNodeSelector();
+ pveScanNodeSelector.listeners = {
+ change: {
+ fn: function(field, value) {
+ // don't reload the store, it requires a VG selected
+ vgField.setNodeName(value, false);
+ vgSelector.setNodeName(value);
+ me.lookupReference('storageNodeRestriction').setValue(value);
+ },
+ },
+ };
+ me.column1.push(pveScanNodeSelector);
+
+ me.column1.push(vgSelector);
me.column1.push(vgField);
}
diff --git a/www/manager6/storage/ZFSPoolEdit.js b/www/manager6/storage/ZFSPoolEdit.js
index 8e689f0c..c274d84a 100644
--- a/www/manager6/storage/ZFSPoolEdit.js
+++ b/www/manager6/storage/ZFSPoolEdit.js
@@ -1,5 +1,5 @@
Ext.define('PVE.storage.ZFSPoolSelector', {
- extend: 'Ext.form.field.ComboBox',
+ extend: 'PVE.storage.ComboBoxSetStoreNode',
alias: 'widget.pveZFSPoolSelector',
valueField: 'pool',
displayField: 'pool',
@@ -8,6 +8,9 @@ Ext.define('PVE.storage.ZFSPoolSelector', {
listConfig: {
loadingText: gettext('Scanning...'),
},
+ config: {
+ apiStoragePath: '/scan/zfs',
+ },
initComponent: function() {
var me = this;
@@ -20,10 +23,9 @@ Ext.define('PVE.storage.ZFSPoolSelector', {
fields: ['pool', 'size', 'free'],
proxy: {
type: 'proxmox',
- url: '/api2/json/nodes/' + me.nodename + '/scan/zfs',
+ url: me.apiBaseUrl + me.nodename + me.apiStoragePath,
},
});
-
store.sort('pool', 'ASC');
Ext.apply(me, {
@@ -45,11 +47,23 @@ Ext.define('PVE.storage.ZFSPoolInputPanel', {
me.column1 = [];
if (me.isCreate) {
- me.column1.push(Ext.create('PVE.storage.ZFSPoolSelector', {
+ let zfsPoolSelector = Ext.create('PVE.storage.ZFSPoolSelector', {
name: 'pool',
fieldLabel: gettext('ZFS Pool'),
allowBlank: false,
- }));
+ });
+ let pveScanNodeSelector = me.getPveScanNodeSelector();
+ pveScanNodeSelector.listeners = {
+ change: {
+ fn: function(field, value) {
+ zfsPoolSelector.setNodeName(value);
+ me.lookupReference('storageNodeRestriction').setValue(value);
+ },
+ },
+ };
+
+ me.column1.push(pveScanNodeSelector);
+ me.column1.push(zfsPoolSelector);
} else {
me.column1.push(Ext.createWidget('displayfield', {
name: 'pool',
--
2.30.2
More information about the pve-devel
mailing list