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> --- changes v1 -> v2: * re-used an already defined gettext for "no cluster configured" (Dominik) * removed commented out code (Dominik) * use a diff store for the node grid to avoid flickering * ensure that the updates stores stop refreshing once the view is destroyed, else we got a "leaky" store which continues to load even if we do not show this panel anymore. www/manager6/Makefile | 1 + www/manager6/dc/Cluster.js | 200 +++++++++++++++++++++++++++++++++++++++++++++ www/manager6/dc/Config.js | 13 ++- 3 files changed, 210 insertions(+), 4 deletions(-) create mode 100644 www/manager6/dc/Cluster.js diff --git a/www/manager6/Makefile b/www/manager6/Makefile index a01880f7..0796aa2c 100644 --- a/www/manager6/Makefile +++ b/www/manager6/Makefile @@ -193,6 +193,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..10e25bf0 --- /dev/null +++ b/www/manager6/dc/Cluster.js @@ -0,0 +1,200 @@ +/*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); + view.on('destroy', view.store.stopUpdate); + }, + + 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('Standalone node - no cluster defined'), + bind: { + hidden: '{isInCluster}' + }, + flex: 1 + } + ] + }, + { + xtype: 'grid', + title: gettext('Cluster Nodes'), + controller: { + xclass: 'Ext.app.ViewController', + + init: function(view) { + view.rstore = Ext.create('Proxmox.data.UpdateStore', { + autoLoad: true, + xtype: 'update', + interval: 5 * 1000, + autoStart: true, + storeid: 'pve-cluster-nodes', + model: 'pve-cluster-nodes' + }); + view.setStore(Ext.create('Proxmox.data.DiffStore', { + rstore: view.rstore, + sorters: { + property: 'nodeid', + order: 'DESC' + } + })); + Proxmox.Utils.monStoreErrors(view, view.rstore); + view.store.on('load', this.onLoad, this); + view.on('destroy', view.rstore.stopUpdate); + }, + + onLoad: function(store, records, success) { + var vm = this.getViewModel(); + if (!success || !records) { + vm.set('nodecount', 0); + return; + } + vm.set('nodecount', records.length); + } + }, + 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