adapt ceph status detail to luminous and make it more robust

they restructured the json interface
(e.g. they removed the timechecks from ceph status)

so we have to generate those differently

also make the whole thing more robust to changes,
as in do not bail out if one thing is missing, but check the needed
data only when we need it and omit that part

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
This commit is contained in:
Dominik Csapak 2017-07-20 16:16:13 +02:00 committed by Wolfgang Bumiller
parent d18bf116a3
commit 4a0bb01712
2 changed files with 66 additions and 69 deletions

View File

@ -153,7 +153,12 @@ Ext.define('PVE.node.CephStatus', {
me.down('#warnings').getStore().loadRawData(rec.data.health.summary, false); me.down('#warnings').getStore().loadRawData(rec.data.health.summary, false);
// update detailstatus panel // update detailstatus panel
me.getComponent('statusdetail').updateAll(rec); me.getComponent('statusdetail').updateAll(
rec.data.health || {},
rec.data.monmap || {},
rec.data.pgmap || {},
rec.data.osdmap || {},
rec.data.quorum_names || []);
// add performance data // add performance data
var used = rec.data.pgmap.bytes_used; var used = rec.data.pgmap.bytes_used;

View File

@ -85,59 +85,55 @@ Ext.define('PVE.ceph.StatusDetail', {
] ]
}], }],
updateAll: function(record) { updateAll: function(health, monmap, pgmap, osdmap, quorum_names) {
var me = this; var me = this;
me.suspendLayout = true; 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 ||
!record.data.health.health ||
!record.data.health.health.health_services ||
!record.data.health.health.health_services[0]) {
// only continue if we have all the data
return;
}
// update pgs sorted // update pgs sorted
var pgs_by_state = record.data.pgmap.pgs_by_state || []; var pgs_by_state = pgmap.pgs_by_state || [];
pgs_by_state.sort(function(a,b){ pgs_by_state.sort(function(a,b){
return (a.state_name < b.state_name)?-1:(a.state_name === b.state_name)?0:1; return (a.state_name < b.state_name)?-1:(a.state_name === b.state_name)?0:1;
}); });
me.getComponent('pgs').update({states: pgs_by_state}); me.getComponent('pgs').update({states: 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+) osds down/; var downinregex = /(\d+) osds down/;
Ext.Array.some(record.data.health.summary, function(item) { var monnameregex = /^mon.(\S+) /;
var found = item.summary.match(downinregex); 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.message.match(downinregex);
if (found !== null) { if (found !== null) {
downin_osds = parseInt(found[1],10); downin_osds = parseInt(found[1],10);
return true;
} }
}
return false; else if (Ext.String.startsWith(key, 'MON_')) {
if (!value.detail) {
return;
}
found = value.detail[0].match(monnameregex);
if (found !== null) {
if (!monmsgs[found[1]]) {
monmsgs[found[1]] = [];
}
monmsgs[found[1]].push({
text: value.detail.join("\n"),
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 downout_osds = down_osds - downin_osds;
var upin_osds = in_osds - downin_osds; var upin_osds = in_osds - downin_osds;
@ -152,28 +148,13 @@ Ext.define('PVE.ceph.StatusDetail', {
me.getComponent('osds').update(osds); me.getComponent('osds').update(osds);
// update the monitors // update the monitors
var mons = record.data.monmap.mons.sort(function(a,b) { var mons = monmap.mons.sort(function(a,b) {
return (a.name < b.name)?-1:(a.name > b.name)?1:0; return (a.name < b.name)?-1:(a.name > b.name)?1:0;
}); });
var monTimes = record.data.health.timechecks.mons || [];
var monHealth = record.data.health.health.health_services[0].mons || [];
var timechecks = {};
var healthchecks = {};
var monContainer = me.getComponent('monitors'); var monContainer = me.getComponent('monitors');
var i; var i;
for (i = 0; i < mons.length && i < monTimes.length; i++) {
timechecks[monTimes[i].name] = monTimes[i].health;
}
if (mons.length === 1) {
timechecks[mons[0].name] = "HEALTH_OK";
}
for (i = 0; i < mons.length && i < monHealth.length; i++) {
healthchecks[monHealth[i].name] = monHealth[i].health;
}
for (i = 0; i < mons.length; i++) { for (i = 0; i < mons.length; i++) {
var monitor = monContainer.getComponent('mon.' + mons[i].name); var monitor = monContainer.getComponent('mon.' + mons[i].name);
if (!monitor) { if (!monitor) {
@ -185,7 +166,7 @@ Ext.define('PVE.ceph.StatusDetail', {
itemId: 'mon.' + mons[i].name itemId: 'mon.' + mons[i].name
}); });
} }
monitor.updateMonitor(timechecks[mons[i].name], mons[i], record.data.quorum_names, healthchecks[mons[i].name]); monitor.updateMonitor(mons[i], monmsgs, quorum_names);
} }
me.suspendLayout = false; me.suspendLayout = false;
me.updateLayout(); me.updateLayout();
@ -200,6 +181,7 @@ Ext.define('PVE.ceph.MonitorWidget', {
data: { data: {
name: '0', name: '0',
health: 'HEALTH_ERR', health: 'HEALTH_ERR',
text: '',
iconCls: PVE.Utils.get_health_icon(), iconCls: PVE.Utils.get_health_icon(),
addr: '' addr: ''
}, },
@ -213,26 +195,34 @@ Ext.define('PVE.ceph.MonitorWidget', {
// timestate: the status from timechecks.mons // timestate: the status from timechecks.mons
// data: the monmap.mons data // data: the monmap.mons data
// quorum_names: the quorum_names array // quorum_names: the quorum_names array
updateMonitor: function(timestate, data, quorum_names, health) { updateMonitor: function(data, monmsgs, quorum_names) {
var me = this; var me = this;
var state = 'HEALTH_ERR'; var state = 'HEALTH_ERR';
var text = '';
var healthstates = { var healthstates = {
'HEALTH_OK': 3, 'HEALTH_OK': 3,
'HEALTH_WARN': 2, 'HEALTH_WARN': 2,
'HEALTH_ERR': 1 'HEALTH_ERR': 1
}; };
// if the monitor is part of the quorum if (quorum_names &&
// and has a timestate, get the timestate,
// otherwise the state is ERR
if (timestate && health && quorum_names &&
quorum_names.indexOf(data.name) !== -1) { quorum_names.indexOf(data.name) !== -1) {
state = (healthstates[health] < healthstates[timestate])? state = 'HEALTH_OK';
health : timestate; }
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, { me.update(Ext.apply(me.data, {
health: state, health: state,
text: text,
addr: data.addr, addr: data.addr,
name: data.name, name: data.name,
iconCls: PVE.Utils.get_health_icon(PVE.Utils.map_ceph_health[state]) iconCls: PVE.Utils.get_health_icon(PVE.Utils.map_ceph_health[state])
@ -254,7 +244,8 @@ Ext.define('PVE.ceph.MonitorWidget', {
renderTo: Ext.getBody(), renderTo: Ext.getBody(),
html: gettext('Monitor') + ': ' + me.data.name + '<br />' + html: gettext('Monitor') + ': ' + me.data.name + '<br />' +
gettext('Address') + ': ' + me.data.addr + '<br />' + gettext('Address') + ': ' + me.data.addr + '<br />' +
gettext('Health') + ': ' + me.data.health gettext('Health') + ': ' + me.data.health + '<br />' +
me.data.text
}); });
} }
me.tooltip.show(); me.tooltip.show();
@ -265,7 +256,8 @@ Ext.define('PVE.ceph.MonitorWidget', {
fn: function(events, element) { fn: function(events, element) {
var me = this.component; var me = this.component;
if (me.tooltip) { if (me.tooltip) {
me.tooltip.hide(); me.tooltip.destroy();
delete me.tooltip;
} }
} }
} }