Show configured cluster nodes with their addresses, votes, IDs. Also show cluster name, config_version, and node count.
Prepares for creating and joining a cluster over the WebUI. Signed-off-by: Thomas Lamprecht <t.lampre...@proxmox.com> --- www/manager6/Makefile | 1 + www/manager6/dc/Cluster.js | 202 +++++++++++++++++++++++++++++++++++++++++++++ www/manager6/dc/Config.js | 13 ++- 3 files changed, 212 insertions(+), 4 deletions(-) create mode 100644 www/manager6/dc/Cluster.js diff --git a/www/manager6/Makefile b/www/manager6/Makefile index ac9f6481..1f143061 100644 --- a/www/manager6/Makefile +++ b/www/manager6/Makefile @@ -192,6 +192,7 @@ JSSRC= \ dc/SecurityGroups.js \ dc/Config.js \ dc/NodeView.js \ + dc/Cluster.js \ Workspace.js lint: ${JSSRC} diff --git a/www/manager6/dc/Cluster.js b/www/manager6/dc/Cluster.js new file mode 100644 index 00000000..e0c5663a --- /dev/null +++ b/www/manager6/dc/Cluster.js @@ -0,0 +1,202 @@ +/*jslint confusion: true*/ +Ext.define('pve-cluster-nodes', { + extend: 'Ext.data.Model', + fields: [ + 'node', { type: 'integer', name: 'nodeid' }, 'ring0_addr', 'ring1_addr', + { type: 'integer', name: 'quorum_votes' } + ], + proxy: { + type: 'proxmox', + url: "/api2/json/cluster/config/nodes" + }, + idProperty: 'nodeid' +}); + +Ext.define('pve-cluster-info', { + extend: 'Ext.data.Model', + proxy: { + type: 'proxmox', + url: "/api2/json/cluster/config/join" + } +}); + +Ext.define('PVE.ClusterAdministration', { + extend: 'Ext.panel.Panel', + xtype: 'pveClusterAdministration', + + title: gettext('Cluster Administration'), + + border: false, + defaults: { border: false }, + + viewModel: { + parent: null, + data: { + totem: {}, + nodelist: [], + preferred_node: { + name: '', + fp: '', + addr: '' + }, + isInCluster: false, + nodecount: 0 + } + }, + + items: [ + { + xtype: 'panel', + title: gettext('Cluster Information'), + controller: { + xclass: 'Ext.app.ViewController', + + init: function(view) { + view.store = Ext.create('Proxmox.data.UpdateStore', { + autoStart: true, + interval: 15 * 1000, + storeid: 'pve-cluster-info', + model: 'pve-cluster-info' + }); + view.store.on('load', this.onLoad, this); + }, + + onLoad: function(store, records, success) { + var vm = this.getViewModel(); + if (!success || !records || !records[0].data) { + vm.set('totem', {}); + vm.set('isInCluster', false); + vm.set('nodelist', []); + vm.set('preferred_node', { + name: '', + addr: '', + fp: '' + }); + return; + } + var data = records[0].data; + vm.set('totem', data.totem); + vm.set('isInCluster', !!data.totem.cluster_name); + vm.set('nodelist', data.nodelist); + + var nodeinfo = Ext.Array.findBy(data.nodelist, function (el) { + return el.name === data.preferred_node; + }); + + vm.set('preferred_node', { + name: data.preferred_node, + addr: nodeinfo.pve_addr, + fp: nodeinfo.pve_fp + }); + }, + }, + layout: 'hbox', + bodyPadding: 5, + items: [ + { + xtype: 'displayfield', + fieldLabel: gettext('Cluster Name'), + bind: { + value: '{totem.cluster_name}', + hidden: '{!isInCluster}' + }, + flex: 1 + }, + { + xtype: 'displayfield', + fieldLabel: gettext('Config Version'), + bind: { + value: '{totem.config_version}', + hidden: '{!isInCluster}' + }, + flex: 1 + }, + { + xtype: 'displayfield', + fieldLabel: gettext('Number of Nodes'), + labelWidth: 120, + bind: { + value: '{nodecount}', + hidden: '{!isInCluster}' + }, + flex: 1 + }, + { + xtype: 'displayfield', + value: gettext('No cluster configured'), + bind: { + hidden: '{isInCluster}' + }, + flex: 1 + } + ] + }, + { + xtype: 'grid', + title: gettext('Cluster Nodes'), + controller: { + xclass: 'Ext.app.ViewController', + + init: function(view) { + view.setStore(Ext.create('Proxmox.data.UpdateStore', { + autoLoad: true, + xtype: 'update', + interval: 5 * 1000, + autoStart: true, + storeid: 'pve-cluster-nodes', + model: 'pve-cluster-nodes', + sorters: { + property: 'nodeid', + order: 'DESC' + } + })); + view.store.on('load', this.onLoad, this); + //Proxmox.Utils.monStoreErrors(view, view.getStore()); + }, + + onLoad: function(store, records, success) { + var vm = this.getViewModel(); + if (!success || !records) { + vm.set('nodecount', 0); + return; + } + vm.set('nodecount', records.length); + } + }, + /*tbar: [ + { + text: gettext('Isolate Node'), + reference: 'isolateButton', + hidden: true // TODO + } + ],*/ + columns: [ + { + header: gettext('Nodename'), + flex: 2, + dataIndex: 'name' + }, + { + header: gettext('ID'), + flex: 1, + dataIndex: 'nodeid' + }, + { + header: gettext('Votes'), + flex: 1, + dataIndex: 'quorum_votes' + }, + { + header: gettext('Ring 0'), + flex: 2, + dataIndex: 'ring0_addr' + }, + { + header: gettext('Ring 1'), + flex: 2, + dataIndex: 'ring1_addr' + } + ] + } + ] +}); diff --git a/www/manager6/dc/Config.js b/www/manager6/dc/Config.js index 17d7a96a..e574f5db 100644 --- a/www/manager6/dc/Config.js +++ b/www/manager6/dc/Config.js @@ -22,13 +22,18 @@ Ext.define('PVE.dc.Config', { if (caps.dc['Sys.Audit']) { me.items.push({ - title: gettext('Summary'), + title: gettext('Summary'), xtype: 'pveDcSummary', iconCls: 'fa fa-book', itemId: 'summary' - }); - - me.items.push({ + }, + { + title: gettext('Cluster'), + xtype: 'pveClusterAdministration', + iconCls: 'fa fa-server', + itemId: 'cluster' + }, + { xtype: 'pveDcOptionView', title: gettext('Options'), iconCls: 'fa fa-gear', -- 2.14.2 _______________________________________________ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel