Ext.define('PVE.ceph.StatusDetail', { extend: 'Ext.panel.Panel', alias: 'widget.pveCephStatusDetail', layout: { type: 'hbox', align: 'stretch' }, bodyPadding: '0 5', defaults: { xtype: 'box', style: { 'text-align':'center' } }, items: [{ flex: 1, itemId: 'osds', maxHeight: 250, scrollable: true, padding: '0 10 5 10', data: { total: 0, upin: 0, upout: 0, downin: 0, downout: 0, oldosds: [] }, tpl: [ '

' + 'OSDs' + '

', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '
', gettext('In'), '', gettext('Out'), '
', gettext('Up'), '{upin}{upout}
', gettext('Down'), '{downin}{downout}
', '
', gettext('Total'), ': {total}', '

', '', ' ' + gettext('Outdated OSDs') + "
", '
', '', '
osd.{id}:
', '
{version}

', '
', '
', '
', '
' ] }, { flex: 1, border: false, itemId: 'pgchart', xtype: 'polar', height: 184, innerPadding: 5, insetPadding: 5, colors: [ '#CFCFCF', '#21BF4B', '#FFCC00', '#FF6C59' ], store: { }, series: [ { type: 'pie', donut: 60, angleField: 'count', tooltip: { trackMouse: true, renderer: function(tooltip, record, ctx) { var html = record.get('text'); html += '
'; record.get('states').forEach(function(state) { html += '
' + state.state_name + ': ' + state.count.toString(); }); tooltip.setHtml(html); } }, subStyle: { strokeStyle: false } } ] }, { flex: 1.6, itemId: 'pgs', padding: '0 10', maxHeight: 250, scrollable: true, data: { states: [] }, tpl: [ '

' + 'PGs' + '

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

', '
', '
' ] }], // similar to mgr dashboard pgstates: { // clean clean: 1, active: 1, // working activating: 2, backfill_wait: 2, backfilling: 2, creating: 2, deep: 2, degraded: 2, forced_backfill: 2, forced_recovery: 2, peered: 2, peering: 2, recovering: 2, recovery_wait: 2, remapped: 2, repair: 2, scrubbing: 2, snaptrim: 2, snaptrim_wait: 2, // error backfill_toofull: 3, backfill_unfound: 3, down: 3, incomplete: 3, inconsistent: 3, recovery_toofull: 3, recovery_unfound: 3, snaptrim_error: 3, stale: 3, undersized: 3 }, statecategories: [ { text: gettext('Unknown'), count: 0, states: [], cls: 'faded' }, { text: gettext('Clean'), cls: 'good' }, { text: gettext('Working'), cls: 'warning' }, { text: gettext('Error'), cls: 'critical' } ], updateAll: function(metadata, status) { var me = this; me.suspendLayout = true; var maxversion = "0"; Object.values(metadata.version || {}).forEach(function(version) { if (PVE.Utils.compare_ceph_versions(version, maxversion) > 0) { maxversion = version; } }); var oldosds = []; if (metadata.osd) { metadata.osd.forEach(function(osd) { var version = PVE.Utils.parse_ceph_version(osd); if (version != maxversion) { oldosds.push({ id: osd.id, version: version }); } }); } // update PGs sorted var pgmap = status.pgmap || {}; 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.statecategories.forEach(function(cat) { cat.count = 0; cat.states = []; }); pgs_by_state.forEach(function(state) { var i; var states = state.state_name.split(/[^a-z]+/); var result = 0; for (i = 0; i < states.length; i++) { if (me.pgstates[states[i]] > result) { result = me.pgstates[states[i]]; } } // for the list state.cls = me.statecategories[result].cls; me.statecategories[result].count += state.count; me.statecategories[result].states.push(state); }); me.getComponent('pgchart').getStore().setData(me.statecategories); me.getComponent('pgs').update({states: pgs_by_state}); var downinregex = /(\d+) osds down/; var downin_osds = 0; var health = status.health || {}; // 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); } } }); var osdmap = status.osdmap || {}; if (typeof osdmap.osdmap != "undefined") { osdmap = osdmap.osdmap; } // update osds counts var total_osds = osdmap.num_osds || 0; var in_osds = osdmap.num_in_osds || 0; var up_osds = 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, oldosds: oldosds }; var osdcomponent = me.getComponent('osds'); osdcomponent.update(Ext.apply(osdcomponent.data, osds)); me.suspendLayout = false; me.updateLayout(); } });