Ext.define('PVE.ceph.Services', {
extend: 'Ext.panel.Panel',
alias: 'widget.pveCephServices',
layout: {
type: 'hbox',
align: 'stretch',
},
bodyPadding: '0 5 20',
defaults: {
xtype: 'box',
style: {
'text-align': 'center',
},
},
items: [
{
flex: 1,
xtype: 'pveCephServiceList',
itemId: 'mons',
title: gettext('Monitors'),
},
{
flex: 1,
xtype: 'pveCephServiceList',
itemId: 'mgrs',
title: gettext('Managers'),
},
{
flex: 1,
xtype: 'pveCephServiceList',
itemId: 'mdss',
title: gettext('Meta Data Servers'),
},
],
updateAll: function(metadata, status) {
var me = this;
const healthstates = {
'HEALTH_UNKNOWN': 0,
'HEALTH_ERR': 1,
'HEALTH_WARN': 2,
'HEALTH_UPGRADE': 3,
'HEALTH_OLD': 4,
'HEALTH_OK': 5,
};
// order guarantee since es2020, but browsers did so before. Note, integers would break it.
const healthmap = Object.keys(healthstates);
let maxversion = "00.0.00";
Object.values(metadata.version || {}).forEach(function(version) {
if (PVE.Utils.compare_ceph_versions(version, maxversion) > 0) {
maxversion = version;
}
});
var quorummap = status && status.quorum_names ? status.quorum_names : [];
let monmessages = {}, mgrmessages = {}, mdsmessages = {};
if (status) {
if (status.health) {
Ext.Object.each(status.health.checks, function(key, value, _obj) {
if (!Ext.String.startsWith(key, "MON_")) {
return;
}
for (let i = 0; i < value.detail.length; i++) {
let match = value.detail[i].message.match(/mon.([a-zA-Z0-9\-.]+)/);
if (!match) {
continue;
}
let monid = match[1];
if (!monmessages[monid]) {
monmessages[monid] = {
worstSeverity: healthstates.HEALTH_OK,
messages: [],
};
}
let severityIcon = PVE.Utils.get_ceph_icon_html(value.severity, true);
let details = value.detail.reduce((acc, v) => `${acc}\n${v.message}`, '');
monmessages[monid].messages.push(severityIcon + details);
if (healthstates[value.severity] < monmessages[monid].worstSeverity) {
monmessages[monid].worstSeverity = healthstates[value.severity];
}
}
});
}
if (status.mgrmap) {
mgrmessages[status.mgrmap.active_name] = "active";
status.mgrmap.standbys.forEach(function(mgr) {
mgrmessages[mgr.name] = "standby";
});
}
if (status.fsmap) {
status.fsmap.by_rank.forEach(function(mds) {
mdsmessages[mds.name] = 'rank: ' + mds.rank + "; " + mds.status;
});
}
}
let checks = {
mon: function(mon) {
if (quorummap.indexOf(mon.name) !== -1) {
mon.health = healthstates.HEALTH_OK;
} else {
mon.health = healthstates.HEALTH_ERR;
}
if (monmessages[mon.name]) {
if (monmessages[mon.name].worstSeverity < mon.health) {
mon.health = monmessages[mon.name].worstSeverity;
}
Array.prototype.push.apply(mon.messages, monmessages[mon.name].messages);
}
return mon;
},
mgr: function(mgr) {
if (mgrmessages[mgr.name] === 'active') {
mgr.title = '' + mgr.title + '';
mgr.statuses.push(gettext('Status') + ': active');
} else if (mgrmessages[mgr.name] === 'standby') {
mgr.statuses.push(gettext('Status') + ': standby');
} else if (mgr.health > healthstates.HEALTH_WARN) {
mgr.health = healthstates.HEALTH_WARN;
}
return mgr;
},
mds: function(mds) {
if (mdsmessages[mds.name]) {
mds.title = '' + mds.title + '';
mds.statuses.push(gettext('Status') + ': ' + mdsmessages[mds.name]+"");
} else if (mds.addr !== Proxmox.Utils.unknownText) {
mds.statuses.push(gettext('Status') + ': standby');
}
return mds;
},
};
for (let type of ['mon', 'mgr', 'mds']) {
var ids = Object.keys(metadata[type] || {});
me[type] = {};
for (let id of ids) {
const [name, host] = id.split('@');
let result = {
id: id,
health: healthstates.HEALTH_OK,
statuses: [],
messages: [],
name: name,
title: metadata[type][id].name || name,
host: host,
version: PVE.Utils.parse_ceph_version(metadata[type][id]),
service: metadata[type][id].service,
addr: metadata[type][id].addr || metadata[type][id].addrs || Proxmox.Utils.unknownText,
};
result.statuses = [
gettext('Host') + ": " + host,
gettext('Address') + ": " + result.addr,
];
if (checks[type]) {
result = checks[type](result);
}
if (result.service && !result.version) {
result.messages.push(
PVE.Utils.get_ceph_icon_html('HEALTH_UNKNOWN', true) +
gettext('Stopped'),
);
result.health = healthstates.HEALTH_UNKNOWN;
}
if (!result.version && result.addr === Proxmox.Utils.unknownText) {
result.health = healthstates.HEALTH_UNKNOWN;
}
if (result.version) {
result.statuses.push(gettext('Version') + ": " + result.version);
if (result.version !== maxversion) {
if (metadata.version[host] === maxversion) {
if (result.health > healthstates.HEALTH_OLD) {
result.health = healthstates.HEALTH_OLD;
}
result.messages.push(
PVE.Utils.get_ceph_icon_html('HEALTH_OLD', true) +
gettext('A newer version was installed but old version still running, please restart'),
);
} else {
if (result.health > healthstates.HEALTH_UPGRADE) {
result.health = healthstates.HEALTH_UPGRADE;
}
result.messages.push(
PVE.Utils.get_ceph_icon_html('HEALTH_UPGRADE', true) +
gettext('Other cluster members use a newer version of this service, please upgrade and restart'),
);
}
}
}
result.statuses.push(''); // empty line
result.text = result.statuses.concat(result.messages).join('
');
result.health = healthmap[result.health];
me[type][id] = result;
}
}
me.getComponent('mons').updateAll(Object.values(me.mon));
me.getComponent('mgrs').updateAll(Object.values(me.mgr));
me.getComponent('mdss').updateAll(Object.values(me.mds));
},
});
Ext.define('PVE.ceph.ServiceList', {
extend: 'Ext.container.Container',
xtype: 'pveCephServiceList',
style: {
'text-align': 'center',
},
defaults: {
xtype: 'box',
style: {
'text-align': 'center',
},
},
items: [
{
itemId: 'title',
data: {
title: '',
},
tpl: '