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 <[email protected]>
---
 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



_______________________________________________
pve-devel mailing list
[email protected]
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

Reply via email to