diff --git a/www/manager6/Makefile b/www/manager6/Makefile index a851264a4..d9ca43521 100644 --- a/www/manager6/Makefile +++ b/www/manager6/Makefile @@ -188,6 +188,7 @@ JSSRC= \ ha/Groups.js \ ha/Fencing.js \ dc/Summary.js \ + dc/Health.js \ dc/OptionView.js \ dc/StorageView.js \ dc/UserEdit.js \ diff --git a/www/manager6/dc/Health.js b/www/manager6/dc/Health.js new file mode 100644 index 000000000..121585706 --- /dev/null +++ b/www/manager6/dc/Health.js @@ -0,0 +1,184 @@ +Ext.define('PVE.dc.Health', { + extend: 'Ext.panel.Panel', + alias: 'widget.pveDcHealth', + + title: gettext('Datacenter Health'), + + bodyPadding: '0 20 0 20', + height: 200, + layout: 'column', + + defaults: { + columnWidth: 0.5, + xtype: 'box', + style: { + 'text-align':'center' + } + }, + + cepherrors: 0, + + updateStatus: function(store, records, success) { + var me = this; + if (!success) { + return; + } + + var cluster = { + iconCls:'good fa-check-circle', + text: gettext("Standalone node - no cluster defined") + }; + + var nodes = { + online: 0, + offline: 0 + }; + + // by default we have one node + var numNodes = 1; + var i; + + for (i = 0; i < records.length; i++) { + var item = records[i]; + if (item.data.type === 'node') { + nodes[item.data.online === 1 ? 'online':'offline']++; + } else if(item.data.type === 'cluster') { + cluster.text = gettext("Cluster") + ": "; + cluster.text += item.data.name + ", "; + cluster.text += gettext("Quorate") + ": "; + cluster.text += PVE.Utils.format_boolean(item.data.quorate); + if (item.data.quorate != 1) { + cluster.iconCls = 'critical fa-times-circle'; + } + + numNodes = item.data.nodes; + } + } + + if (numNodes !== (nodes.online + nodes.offline)) { + nodes.offline = numNodes - nodes.online; + } + + me.getComponent('clusterstatus').update(cluster); + me.getComponent('nodestatus').update(nodes); + }, + + updateCeph: function(store, records, success) { + var me = this; + var cephstatus = me.getComponent('ceph'); + if (!success || records.length < 1) { + me.cepherrors++; + cephstatus.setVisible(false); + + // after 3 unsuccessful tries of + // /nodes/localhost/ceph/status + // we give up (there probably is no ceph installed) + if (me.cepherrors >= 3) { + me.cephstore.stopUpdate(); + } + return; + } + + me.cepherrors = 0; + + var cephstate = { + iconCls: 'faded fa-question-circle', + text: '' + }; + + switch (records[0].data.health.overall_status) { + case 'HEALTH_OK': + cephstate.iconCls = 'good fa-check-circle'; + break; + case 'HEALTH_WARN': + cephstate.iconCls = 'warning fa-info-circle'; + break; + case 'HEALTH_ERR': + cephstate.iconCls = 'critical fa-times-circle'; + break; + default: + cephstate.iconCls = 'faded fa-question-circle'; + break; + } + cephstate.text = records[0].data.health.overall_status; + cephstatus.update(cephstate); + cephstatus.setVisible(true); + }, + + listeners: { + destroy: function() { + var me = this; + me.cephstore.stopUpdate(); + } + }, + + items: [ + { + itemId: 'clusterstatus', + data: { + iconCls: 'faded fa-question-circle', + text: '' + }, + tpl: [ + '

' + gettext('Status') + '

', + '', + '

', + '{text}' + ] + }, + { + itemId: 'nodestatus', + data: { + online: 0, + offline: 0 + }, + tpl: [ + '

' + gettext('Nodes') + '


', + '
', + '
', + ' ', + gettext('Online'), + '
', + '
{online}
', + '

', + '
', + ' ', + gettext('Offline'), + '
', + '
{offline}
', + '
' + ] + }, + { + itemId: 'ceph', + width: 250, + columnWidth: undefined, + data: { + text: '', + iconCls: 'faded fa-question-circle' + }, + tpl: [ + '

Ceph

', + '

', + gettext("Health") + ': {text}' + ], + hidden: true + } + ], + + initComponent: function() { + var me = this; + + me.cephstore = Ext.create('PVE.data.UpdateStore', { + interval: 3000, + storeid: 'pve-cluster-ceph', + proxy: { + type: 'pve', + url: '/api2/json/nodes/localhost/ceph/status' + } + }); + me.callParent(); + me.cephstore.startUpdate(); + me.mon(me.cephstore, 'load', me.updateCeph, me); + } +});