From: Stefan Hrdlicka <s.hrdlicka@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH V5 pve-manager 1/2] fix #2822: add iscsi, lvm, lvmthin & zfs storage for all cluster nodes
Date: Fri, 23 Sep 2022 14:46:50 +0200 [thread overview]
Message-ID: <20220923124651.484774-2-s.hrdlicka@proxmox.com> (raw)
In-Reply-To: <20220923124651.484774-1-s.hrdlicka@proxmox.com>
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@proxmox.com>
---
www/manager6/Makefile | 2 +
www/manager6/form/ComboBoxSetStoreNode.js | 16 ++++++
www/manager6/form/StorageScanNodeSelector.js | 30 +++++++++++
www/manager6/storage/Base.js | 1 +
www/manager6/storage/IScsiEdit.js | 32 +++++++++---
www/manager6/storage/LVMEdit.js | 29 +++++++++--
www/manager6/storage/LvmThinEdit.js | 52 +++++++++++++++-----
www/manager6/storage/ZFSPoolEdit.js | 28 +++++++++--
8 files changed, 166 insertions(+), 24 deletions(-)
create mode 100644 www/manager6/form/ComboBoxSetStoreNode.js
create mode 100644 www/manager6/form/StorageScanNodeSelector.js
diff --git a/www/manager6/Makefile b/www/manager6/Makefile
index d16770b1..81f5e5d8 100644
--- a/www/manager6/Makefile
+++ b/www/manager6/Makefile
@@ -27,6 +27,7 @@ JSSRC= \
form/CalendarEvent.js \
form/CephPoolSelector.js \
form/CephFSSelector.js \
+ form/ComboBoxSetStoreNode.js \
form/CompressionSelector.js \
form/ContentTypeSelector.js \
form/ControllerSelector.js \
@@ -62,6 +63,7 @@ JSSRC= \
form/SecurityGroupSelector.js \
form/SnapshotSelector.js \
form/SpiceEnhancementSelector.js \
+ form/StorageScanNodeSelector.js \
form/StorageSelector.js \
form/TFASelector.js \
form/TokenSelector.js \
diff --git a/www/manager6/form/ComboBoxSetStoreNode.js b/www/manager6/form/ComboBoxSetStoreNode.js
new file mode 100644
index 00000000..3490ddd7
--- /dev/null
+++ b/www/manager6/form/ComboBoxSetStoreNode.js
@@ -0,0 +1,16 @@
+Ext.define('PVE.form.ComboBoxSetStoreNode', {
+ extend: 'Ext.form.field.ComboBox',
+ config: {
+ apiBaseUrl: '/api2/json/nodes/',
+ apiSuffix: '',
+ },
+
+ setNodeName: function(value) {
+ let me = this;
+ value ||= Proxmox.NodeName;
+
+ me.getStore().getProxy().setUrl(`${me.apiBaseUrl}${value}${me.apiSuffix}`);
+ this.clearValue();
+ },
+
+});
diff --git a/www/manager6/form/StorageScanNodeSelector.js b/www/manager6/form/StorageScanNodeSelector.js
new file mode 100644
index 00000000..80188707
--- /dev/null
+++ b/www/manager6/form/StorageScanNodeSelector.js
@@ -0,0 +1,30 @@
+Ext.define('PVE.form.StorageScanNodeSelector', {
+ extend: 'PVE.form.NodeSelector',
+ xtype: 'pveStorageScanNodeSelector',
+
+ name: 'storageScanNode',
+ itemId: 'pveStorageScanNodeSelector',
+ fieldLabel: gettext('Scan node'),
+ allowBlank: true,
+ disallowedNodes: undefined,
+ autoSelect: false,
+ submitValue: false,
+ value: 'localhost',
+ autoEl: {
+ tag: 'div',
+ 'data-qtip': gettext('Scan for available storages on the selected node'),
+ },
+ triggers: {
+ clear: {
+ handler: function() {
+ let me = this;
+ me.setValue('localhost');
+ },
+ },
+ },
+ setValue: function(value) {
+ let me = this;
+ me.callParent([value]);
+ me.triggers.clear.setVisible(me.triggers.clear.isVisible() && value !== 'localhost');
+ },
+});
diff --git a/www/manager6/storage/Base.js b/www/manager6/storage/Base.js
index 7f6d7a09..1df7a8dd 100644
--- a/www/manager6/storage/Base.js
+++ b/www/manager6/storage/Base.js
@@ -36,6 +36,7 @@ Ext.define('PVE.panel.StorageBase', {
{
xtype: 'pveNodeSelector',
name: 'nodes',
+ reference: 'storageNodeRestriction',
disabled: me.storageId === 'local',
fieldLabel: gettext('Nodes'),
emptyText: gettext('All') + ' (' + gettext('No restrictions') +')',
diff --git a/www/manager6/storage/IScsiEdit.js b/www/manager6/storage/IScsiEdit.js
index 2f35f882..393de3c3 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.form.ComboBoxSetStoreNode',
alias: 'widget.pveIScsiScan',
queryParam: 'portal',
@@ -10,6 +10,9 @@ Ext.define('PVE.storage.IScsiScan', {
loadingText: gettext('Scanning...'),
width: 350,
},
+ config: {
+ apiSuffix: '/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.apiSuffix}`,
},
});
store.sort('target', 'ASC');
@@ -78,6 +81,23 @@ Ext.define('PVE.storage.IScsiInputPanel', {
var me = this;
me.column1 = [
+ {
+ xtype: 'pveStorageScanNodeSelector',
+ disabled: !me.isCreate,
+ hidden: !me.isCreate,
+ preferredValue: '',
+ allowBlank: true,
+ autoSelect: false,
+ listeners: {
+ change: {
+ fn: function(field, value) {
+ me.lookup('iScsiTargetScan').setNodeName(value);
+ me.lookup('storageNodeRestriction')
+ .setValue(value === 'localhost' ? '' : value);
+ },
+ },
+ },
+ },
{
xtype: me.isCreate ? 'textfield' : 'displayfield',
name: 'portal',
@@ -94,14 +114,14 @@ Ext.define('PVE.storage.IScsiInputPanel', {
},
},
},
- {
+ Ext.createWidget(me.isCreate ? 'pveIScsiScan' : 'displayfield', {
readOnly: !me.isCreate,
- xtype: me.isCreate ? 'pveIScsiScan' : 'displayfield',
name: 'target',
value: '',
- fieldLabel: 'Target',
+ fieldLabel: gettext('Target'),
allowBlank: false,
- },
+ reference: 'iScsiTargetScan',
+ }),
];
me.column2 = [
diff --git a/www/manager6/storage/LVMEdit.js b/www/manager6/storage/LVMEdit.js
index 2a9cd283..04d96786 100644
--- a/www/manager6/storage/LVMEdit.js
+++ b/www/manager6/storage/LVMEdit.js
@@ -1,10 +1,20 @@
Ext.define('PVE.storage.VgSelector', {
- extend: 'Ext.form.field.ComboBox',
+ extend: 'PVE.form.ComboBoxSetStoreNode',
alias: 'widget.pveVgSelector',
valueField: 'vg',
displayField: 'vg',
queryMode: 'local',
editable: false,
+ config: {
+ apiSuffix: '/scan/lvm',
+ },
+
+ setNodeName: function(value) {
+ let me = this;
+ me.callParent([value]);
+ me.getStore().load();
+ },
+
initComponent: function() {
var me = this;
@@ -17,7 +27,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.apiSuffix}`,
},
});
@@ -103,11 +113,24 @@ Ext.define('PVE.storage.LVMInputPanel', {
});
if (me.isCreate) {
- var vgField = Ext.create('PVE.storage.VgSelector', {
+ let vgField = Ext.create('PVE.storage.VgSelector', {
name: 'vgname',
fieldLabel: gettext('Volume group'),
+ reference: 'volumeGroupSelector',
allowBlank: false,
});
+ me.column1.push({
+ xtype: 'pveStorageScanNodeSelector',
+ listeners: {
+ change: {
+ fn: function(field, value) {
+ me.lookup('volumeGroupSelector').setNodeName(value);
+ me.lookup('storageNodeRestriction')
+ .setValue(value === 'localhost' ? '' : value);
+ },
+ },
+ },
+ });
var baseField = Ext.createWidget('pveFileSelector', {
name: 'base',
diff --git a/www/manager6/storage/LvmThinEdit.js b/www/manager6/storage/LvmThinEdit.js
index 4eab7740..e9202ffa 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.form.ComboBoxSetStoreNode',
alias: 'widget.pveTPSelector',
queryParam: 'vg',
@@ -7,6 +7,10 @@ Ext.define('PVE.storage.TPoolSelector', {
displayField: 'lv',
editable: false,
+ config: {
+ apiSuffix: '/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.apiSuffix}`,
},
});
@@ -58,13 +62,23 @@ Ext.define('PVE.storage.TPoolSelector', {
});
Ext.define('PVE.storage.BaseVGSelector', {
- extend: 'Ext.form.field.ComboBox',
+ extend: 'PVE.form.ComboBoxSetStoreNode',
alias: 'widget.pveBaseVGSelector',
valueField: 'vg',
displayField: 'vg',
queryMode: 'local',
editable: false,
+ config: {
+ apiSuffix: '/scan/lvm',
+ },
+
+ setNodeName: function(value) {
+ let me = this;
+ me.callParent([value]);
+ me.getStore().load();
+ },
+
initComponent: function() {
var me = this;
@@ -77,7 +91,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.apiSuffix}`,
},
});
@@ -121,27 +135,41 @@ Ext.define('PVE.storage.LvmThinInputPanel', {
});
if (me.isCreate) {
- var vgField = Ext.create('PVE.storage.TPoolSelector', {
- name: 'thinpool',
- fieldLabel: gettext('Thin Pool'),
- allowBlank: false,
+ me.column1.push({
+ xtype: 'pveStorageScanNodeSelector',
+ listeners: {
+ change: {
+ fn: function(field, value) {
+ me.lookup('thinPoolSelector').setNodeName(value);
+ me.lookup('volumeGroupSelector').setNodeName(value);
+ me.lookup('storageNodeRestriction')
+ .setValue(value === 'localhost' ? '' : value);
+ },
+ },
+ },
});
- me.column1.push({
- xtype: 'pveBaseVGSelector',
+ me.column1.push(Ext.create('PVE.storage.BaseVGSelector', {
name: 'vgname',
fieldLabel: gettext('Volume group'),
+ reference: 'volumeGroupSelector',
listeners: {
change: function(f, value) {
if (me.isCreate) {
+ let vgField = me.lookup('thinPoolSelector');
vgField.setVG(value);
vgField.setValue('');
}
},
},
- });
+ }));
- me.column1.push(vgField);
+ me.column1.push(Ext.create('PVE.storage.TPoolSelector', {
+ name: 'thinpool',
+ fieldLabel: gettext('Thin Pool'),
+ reference: 'thinPoolSelector',
+ allowBlank: false,
+ }));
}
me.column1.push(vgnameField);
diff --git a/www/manager6/storage/ZFSPoolEdit.js b/www/manager6/storage/ZFSPoolEdit.js
index 8e689f0c..98034de9 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.form.ComboBoxSetStoreNode',
alias: 'widget.pveZFSPoolSelector',
valueField: 'pool',
displayField: 'pool',
@@ -8,6 +8,16 @@ Ext.define('PVE.storage.ZFSPoolSelector', {
listConfig: {
loadingText: gettext('Scanning...'),
},
+ config: {
+ apiSuffix: '/scan/zfs',
+ },
+
+ setNodeName: function(value) {
+ let me = this;
+ me.callParent([value]);
+ me.getStore().load();
+ },
+
initComponent: function() {
var me = this;
@@ -20,10 +30,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.apiSuffix}`,
},
});
-
store.sort('pool', 'ASC');
Ext.apply(me, {
@@ -45,9 +54,22 @@ Ext.define('PVE.storage.ZFSPoolInputPanel', {
me.column1 = [];
if (me.isCreate) {
+ me.column1.push({
+ xtype: 'pveStorageScanNodeSelector',
+ listeners: {
+ change: {
+ fn: function(field, value) {
+ me.lookup('zfsPoolSelector').setNodeName(value);
+ me.lookup('storageNodeRestriction')
+ .setValue(value === 'localhost' ? '' : value);
+ },
+ },
+ },
+ });
me.column1.push(Ext.create('PVE.storage.ZFSPoolSelector', {
name: 'pool',
fieldLabel: gettext('ZFS Pool'),
+ reference: 'zfsPoolSelector',
allowBlank: false,
}));
} else {
--
2.30.2
next prev parent reply other threads:[~2022-09-23 12:47 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-09-23 12:46 [pve-devel] [PATCH V5 pve-manager 0/2] fix #2822: add iscsi, lvm, lvmthin & zfs Stefan Hrdlicka
2022-09-23 12:46 ` Stefan Hrdlicka [this message]
2022-09-29 12:02 ` [pve-devel] [PATCH V5 pve-manager 1/2] fix #2822: add iscsi, lvm, lvmthin & zfs storage for all cluster nodes Dominik Csapak
2022-09-23 12:46 ` [pve-devel] [PATCH V5 pve-manager 2/2] cleanup: "var" to "let", fix some indentation in related files Stefan Hrdlicka
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220923124651.484774-2-s.hrdlicka@proxmox.com \
--to=s.hrdlicka@proxmox.com \
--cc=pve-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox