Ext.define('PVE.ceph.StatusDetail', { extend: 'Ext.panel.Panel', alias: 'widget.pveCephStatusDetail', layout: { type: 'hbox', align: 'stretch' }, bodyPadding: '0 5 20', defaults: { xtype: 'box', style: { 'text-align':'center' } }, items: [{ flex: 1, itemId: 'monitors', xtype: 'container', items: [ { xtype: 'box', width: '100%', html: '

' + gettext('Monitors') + '

' } ] },{ flex: 1, itemId: 'osds', data: { total: 0, upin: 0, upout: 0, downin: 0, downout: 0 }, tpl: [ '

' + gettext('OSDs') + '

', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '
', gettext('In'), '', gettext('Out'), '
', gettext('Up'), '{upin}{upout}
', gettext('Down'), '{downin}{downout}
', '
', gettext('Total'), ': {total}', '
' ] }, { flex: 1.6, itemId: 'pgs', padding: '0 10', data: { states: [] }, tpl: [ '

' + gettext('PGs') + '

', '', '
{state_name}:
', '
{count}

', '
', '
' ] }], updateAll: function(health, monmap, pgmap, osdmap, quorum_names) { var me = this; me.suspendLayout = true; // update pgs sorted var pgs_by_state = pgmap.pgs_by_state || []; pgs_by_state.sort(function(a,b){ return (a.state_name < b.state_name)?-1:(a.state_name === b.state_name)?0:1; }); me.getComponent('pgs').update({states: pgs_by_state}); var downinregex = /(\d+) osds down/; var monnameregex = /^mon.(\S+) /; var downin_osds = 0; var monmsgs = {}; // we collect monitor/osd information from the checks Ext.Object.each(health.checks, function(key, value, obj) { var found = null; if (key === 'OSD_DOWN') { found = value.summary.message.match(downinregex); if (found !== null) { downin_osds = parseInt(found[1],10); } } else if (Ext.String.startsWith(key, 'MON_')) { if (!value.detail) { return; } found = value.detail[0].message.match(monnameregex); if (found !== null) { if (!monmsgs[found[1]]) { monmsgs[found[1]] = []; } monmsgs[found[1]].push({ text: Ext.Array.reduce(value.detail, function(first, second) { return first + '\n' + second.message; }, ''), severity: value.severity }); } } }); // update osds counts var total_osds = osdmap.osdmap.num_osds || 0; var in_osds = osdmap.osdmap.num_in_osds || 0; var up_osds = osdmap.osdmap.num_up_osds || 0; var out_osds = total_osds - in_osds; var down_osds = total_osds - up_osds; var downout_osds = down_osds - downin_osds; var upin_osds = in_osds - downin_osds; var upout_osds = up_osds - upin_osds; var osds = { total: total_osds, upin: upin_osds, upout: upout_osds, downin: downin_osds, downout: downout_osds }; me.getComponent('osds').update(osds); // update the monitors var mons = monmap.mons.sort(function(a,b) { return (a.name < b.name)?-1:(a.name > b.name)?1:0; }); var monContainer = me.getComponent('monitors'); var i; for (i = 0; i < mons.length; i++) { var monitor = monContainer.getComponent('mon.' + mons[i].name); if (!monitor) { // since mons are already sorted, and // we always have a sorted list // we can add it at the mons+1 position (because of the title) monitor = monContainer.insert(i+1, { xtype: 'pveCephMonitorWidget', itemId: 'mon.' + mons[i].name }); } monitor.updateMonitor(mons[i], monmsgs, quorum_names); } me.suspendLayout = false; me.updateLayout(); } }); Ext.define('PVE.ceph.MonitorWidget', { extend: 'Ext.Component', alias: 'widget.pveCephMonitorWidget', userCls: 'monitor inline-block', data: { name: '0', health: 'HEALTH_ERR', text: '', iconCls: PVE.Utils.get_health_icon(), addr: '' }, tpl: [ '{name}: ', '' ], // expects 3 variables which are // timestate: the status from timechecks.mons // data: the monmap.mons data // quorum_names: the quorum_names array updateMonitor: function(data, monmsgs, quorum_names) { var me = this; var state = 'HEALTH_ERR'; var text = ''; var healthstates = { 'HEALTH_OK': 3, 'HEALTH_WARN': 2, 'HEALTH_ERR': 1 }; if (quorum_names && quorum_names.indexOf(data.name) !== -1) { state = 'HEALTH_OK'; } if (monmsgs[data.name]) { Ext.Array.forEach(monmsgs[data.name], function(msg) { if (healthstates[msg.severity] < healthstates[state]) { state = msg.severity; } text += msg.text + "\n"; }); } me.update(Ext.apply(me.data, { health: state, text: text, addr: data.addr, name: data.name, iconCls: PVE.Utils.get_health_icon(PVE.Utils.map_ceph_health[state]) })); }, listeners: { mouseenter: { element: 'el', fn: function(events, element) { var me = this.component; if (!me) { return; } if (!me.tooltip) { me.tooltip = Ext.create('Ext.tip.ToolTip', { target: me.el, trackMouse: true, renderTo: Ext.getBody(), html: gettext('Monitor') + ': ' + me.data.name + '
' + gettext('Address') + ': ' + me.data.addr + '
' + gettext('Health') + ': ' + me.data.health + '
' + me.data.text }); } me.tooltip.show(); } }, mouseleave: { element: 'el', fn: function(events, element) { var me = this.component; if (me.tooltip) { me.tooltip.destroy(); delete me.tooltip; } } } } });