pve-manager/www/manager6/ceph/StatusDetail.js
Dominik Csapak 84c0daf3e8 fix missing mons array in ceph status output
on setups with 1 monitor, timechecks has no monitor array

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
2016-11-23 11:39:58 +01:00

260 lines
6.1 KiB
JavaScript

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: '<h3>' + gettext('Monitors') + '</h3>'
}
]
},{
flex: 1,
itemId: 'osds',
data: {
total: 0,
upin: 0,
upout: 0,
downin: 0,
downout: 0
},
tpl: [
'<h3>' + gettext('OSDs') + '</h3>',
'<table class="osds">',
'<tr><td></td>',
'<td><i class="fa fa-fw good fa-circle"></i>',
gettext('In'),
'</td>',
'<td><i class="fa fa-fw warning fa-circle-o"></i>',
gettext('Out'),
'</td>',
'</tr>',
'<tr>',
'<td><i class="fa fa-fw good fa-arrow-circle-up"></i>',
gettext('Up'),
'</td>',
'<td>{upin}</td>',
'<td>{upout}</td>',
'</tr>',
'<tr>',
'<td><i class="fa fa-fw critical fa-arrow-circle-down"></i>',
gettext('Down'),
'</td>',
'<td>{downin}</td>',
'<td>{downout}</td>',
'</tr>',
'</table>',
'<br /><div>',
gettext('Total'),
': {total}',
'</div>'
]
},
{
flex: 1.6,
itemId: 'pgs',
padding: '0 10',
data: {
monitors: []
},
tpl: [
'<h3>' + gettext('PGs') + '</h3>',
'<tpl for="monitors">',
'<div class="left-aligned">{state_name}:</div>',
'<div class="right-aligned">{count}</div><br />',
'<div style="clear:both"></div>',
'</tpl>'
]
}],
updateAll: function(record) {
var me = this;
me.suspendLayout = true;
if (!record.data.pgmap ||
!record.data.osdmap ||
!record.data.osdmap.osdmap ||
!record.data.health ||
!record.data.health.timechecks ||
!record.data.monmap ||
!record.data.monmap.mons) {
// only continue if we have all the data
return;
}
// update pgs sorted
var pgs_by_state = record.data.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({monitors: pgs_by_state});
// update osds counts
// caution: this code is not the nicest,
// but since the status call only gives us
// the total, up and in value,
// we parse the health summary and look for the
// x/y in osds are down message
// to get the rest of the numbers
//
// the alternative would be to make a second api call,
// as soon as not all osds are up, but those are costly
var total_osds = record.data.osdmap.osdmap.num_osds || 0;
var in_osds = record.data.osdmap.osdmap.num_in_osds || 0;
var up_osds = record.data.osdmap.osdmap.num_up_osds || 0;
var out_osds = total_osds - in_osds;
var down_osds = total_osds - up_osds;
var downin_osds = 0;
var downinregex = /(\d+)\/(\d+) in osds are down/;
Ext.Array.some(record.data.health.summary, function(item) {
var found = item.summary.match(downinregex);
if (found !== null) {
// sanity check, test if the message is
// consistent with the direct value
// for in osds
if (found[2] == in_osds) {
downin_osds = parseInt(found[1],10);
return true;
}
}
return false;
});
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 = record.data.monmap.mons.sort(function(a,b) {
return (a.name < b.name)?-1:(a.name > b.name)?1:0;
});
var monTimes = record.data.health.timechecks.mons || [];
var timechecks = {};
var monContainer = me.getComponent('monitors');
var i;
for (i = 0; i < mons.length && i < monTimes.length; i++) {
timechecks[monTimes[i].name] = monTimes[i].health;
}
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(timechecks[mons[i].name], mons[i], record.data.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',
iconCls: PVE.Utils.get_health_icon(),
addr: ''
},
tpl: [
'{name}: ',
'<i class="fa fa-fw {iconCls}"></i>'
],
// expects 3 variables which are
// timestate: the status from timechecks.mons
// data: the monmap.mons data
// quorum_names: the quorum_names array
updateMonitor: function(timestate, data, quorum_names) {
var me = this;
var state = 'HEALTH_ERR';
// if the monitor is part of the quorum
// and has a timestate, get the timestate,
// otherwise the state is ERR
if (timestate && quorum_names &&
quorum_names.indexOf(data.name) !== -1) {
state = timestate;
}
me.update(Ext.apply(me.data, {
health: state,
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 + '<br />' +
gettext('Address') + ': ' + me.data.addr + '<br />' +
gettext('Health') + ': ' + me.data.health
});
}
me.tooltip.show();
}
},
mouseleave: {
element: 'el',
fn: function(events, element) {
var me = this.component;
if (me.tooltip) {
me.tooltip.hide();
}
}
}
}
});