[pve-devel] [PATCH WIP manager 2/2] gui: configure cluster-wide hosts through gui
Leo Nunner
l.nunner at proxmox.com
Thu Sep 14 12:03:41 CEST 2023
GUI components for the cluster-wide hosts configuration. It is located
under Datacenter > Hosts, and allows editing, adding and deleting
entries. They are searchable, and the edit window allows adding a
variable number of hostnames to each IP address. There is a separate
"apply" button, which starts a task to sync the hosts config to each
node in the cluster.
Signed-off-by: Leo Nunner <l.nunner at proxmox.com>
---
www/manager6/Makefile | 1 +
www/manager6/dc/Config.js | 6 +
www/manager6/dc/Hosts.js | 257 ++++++++++++++++++++++++++++++++++++++
3 files changed, 264 insertions(+)
create mode 100644 www/manager6/dc/Hosts.js
diff --git a/www/manager6/Makefile b/www/manager6/Makefile
index 59a5d8a7f..f34d5b2f2 100644
--- a/www/manager6/Makefile
+++ b/www/manager6/Makefile
@@ -157,6 +157,7 @@ JSSRC= \
dc/GroupView.js \
dc/Guests.js \
dc/Health.js \
+ dc/Hosts.js \
dc/Log.js \
dc/NodeView.js \
dc/NotificationEvents.js \
diff --git a/www/manager6/dc/Config.js b/www/manager6/dc/Config.js
index 9ba7b301f..332662516 100644
--- a/www/manager6/dc/Config.js
+++ b/www/manager6/dc/Config.js
@@ -178,6 +178,12 @@ Ext.define('PVE.dc.Config', {
iconCls: 'fa fa-bolt',
xtype: 'pveFencingView',
itemId: 'ha-fencing',
+ },
+ {
+ xtype: 'pveClusterHosts',
+ title: gettext('Hosts'),
+ iconCls: 'fa fa-globe',
+ itemId: 'hosts',
});
// always show on initial load, will be hiddea later if the SDN API calls don't exist,
// else it won't be shown at first if the user initially loads with DC selected
diff --git a/www/manager6/dc/Hosts.js b/www/manager6/dc/Hosts.js
new file mode 100644
index 000000000..57bf29054
--- /dev/null
+++ b/www/manager6/dc/Hosts.js
@@ -0,0 +1,257 @@
+Ext.define('pve-etc-hosts-entry', {
+ extend: 'Ext.data.Model',
+ fields: [
+ { name: 'ip', type: 'string' },
+ { name: 'hosts', type: 'string' },
+ { name: 'comment', type: 'string' },
+ ],
+});
+
+Ext.define('PVE.dc.HostsEditWindow', {
+ extend: 'Proxmox.window.Edit',
+
+ width: 600,
+
+ ip: undefined,
+
+ initComponent: function() {
+ var me = this;
+
+ Ext.apply(me, {
+ subject: "Hosts entry",
+ defaultFocus: 'textfield[name=ip]',
+ });
+
+ Ext.apply(me, {
+ items: [
+ {
+ xtype: 'textfield',
+ fieldLabel: gettext('IP'),
+ name: 'ip',
+ dataIndex: 'ip',
+ allowBlank: false,
+ vtype: 'IP64Address',
+ },
+ {
+ xtype: 'textfield',
+ fieldLabel: gettext('Comment'),
+ name: 'comment',
+ dataIndex: 'comment',
+ allowBlank: true,
+ },
+ {
+ xtype: 'fieldcontainer',
+ fieldLabel: gettext('Hostnames'),
+ items: [
+ {
+ xtype: 'proxmoxHostsEditPanel', name: 'hosts',
+ },
+ ],
+ },
+ ],
+ });
+
+ let base_url = `/api2/extjs/cluster/hosts`;
+ if (me.isCreate) {
+ me.url = base_url;
+ me.method = 'POST';
+ } else {
+ me.url = base_url + `/${me.ip}`;
+ me.method = 'PUT';
+ }
+
+ me.callParent();
+
+ let hostsPanel = me.down("proxmoxHostsEditPanel");
+ let hostsController = hostsPanel.getController();
+
+ me.setValues({ ip: me.ip });
+
+ if (!me.isCreate) { // do we already have data?
+ me.load();
+ } else { // if not, we create a single empty host entry
+ hostsController.addHost();
+ }
+ },
+});
+
+Ext.define('PVE.dc.ClusterHosts', {
+ extend: 'Ext.grid.Panel',
+ xtype: 'pveClusterHosts',
+
+ reload: function() {
+ let me = this;
+ let view = me.getView();
+ view.store.load();
+ },
+
+ layout: 'fit',
+
+ initComponent: function() {
+ let me = this;
+
+ me.store = Ext.create('Ext.data.Store', {
+ model: 'pve-etc-hosts-entry',
+ proxy: {
+ type: 'proxmox',
+ url: `/api2/json/cluster/hosts`,
+ },
+ sorters: [
+ {
+ property: 'ip',
+ direction: 'ASC',
+ },
+ ],
+ });
+
+ var sm = Ext.create('Ext.selection.RowModel', {});
+
+ var run_editor = function() {
+ var rec = sm.getSelection()[0];
+ if (!rec || !(rec.data.ip || rec.data.hosts)) {
+ return;
+ }
+
+ let win = Ext.create('PVE.dc.HostsEditWindow', {
+ isCreate: false,
+ ip: rec.data.ip,
+ });
+ win.on('destroy', me.reload, me);
+ win.show();
+ };
+
+ Ext.apply(me, {
+ tbar: [
+ {
+ text: gettext('Apply'),
+ itemId: 'applybtn',
+ handler: function() {
+ Proxmox.Utils.API2Request({
+ method: 'PUT',
+ url: `/cluster/hosts`,
+ waitMsgTarget: me,
+ success: function(response, opts) {
+ me.reload();
+ },
+ failure: function(response, opts) {
+ Ext.Msg.alert('Error', response.htmlStatus);
+ },
+ });
+ },
+ },
+ '|',
+ {
+ text: gettext('Add'),
+ itemId: 'addbtn',
+ handler: function() {
+ let win = Ext.create('PVE.dc.HostsEditWindow', {
+ isCreate: true,
+ ip: undefined,
+ });
+ win.on('destroy', me.reload, me);
+ win.show();
+ },
+ },
+ {
+ text: gettext('Edit'),
+ itemId: 'editbtn',
+ handler: run_editor,
+ },
+ {
+ text: gettext('Delete'),
+ itemId: 'deletebtn',
+ handler: function() {
+ let rec = sm.getSelection()[0];
+
+ Proxmox.Utils.API2Request({
+ method: 'DELETE',
+ url: `/cluster/hosts/${rec.data.ip}`,
+ waitMsgTarget: me,
+ success: function(response, opts) {
+ me.reload();
+ },
+ failure: function(response, opts) {
+ Ext.Msg.alert('Error', response.htmlStatus);
+ },
+ });
+ },
+ },
+ '->',
+ gettext('Search') + ':',
+ ' ',
+ {
+ xtype: 'textfield',
+ width: 200,
+ enableKeyEvents: true,
+ emptyText: gettext("IP, FQDN"),
+ listeners: {
+ keyup: {
+ buffer: 500,
+ fn: function(field) {
+ let needle = field.getValue().toLocaleLowerCase();
+ me.store.clearFilter(true);
+ me.store.filter([
+ {
+ filterFn: ({ data }) =>
+ data.ip?.toLocaleLowerCase().includes(needle) ||
+ data.hosts?.toLocaleLowerCase().includes(needle),
+ },
+ ]);
+ },
+ },
+ change: function(field, newValue, oldValue) {
+ if (newValue !== this.originalValue) {
+ this.triggers.clear.setVisible(true);
+ }
+ },
+ },
+ triggers: {
+ clear: {
+ cls: 'pmx-clear-trigger',
+ weight: -1,
+ hidden: true,
+ handler: function() {
+ this.triggers.clear.setVisible(false);
+ this.setValue(this.originalValue);
+ me.store.clearFilter();
+ },
+ },
+ },
+ },
+ ],
+ });
+
+ Ext.apply(me, {
+ bodystyle: {
+ width: '100% !important',
+ },
+ columns: [
+ {
+ text: gettext('IP'),
+ dataIndex: 'ip',
+ width: 150,
+ },
+ {
+ text: gettext('Hosts'),
+ dataIndex: 'hosts',
+ flex: 1,
+ },
+ {
+ text: gettext('Comment'),
+ dataIndex: 'comment',
+ flex: 1,
+ },
+ ],
+ });
+
+ Ext.apply(me, {
+ selModel: sm,
+ listeners: {
+ itemdblclick: run_editor,
+ },
+ });
+
+ me.callParent();
+ me.reload();
+ },
+});
--
2.39.2
More information about the pve-devel
mailing list