]> git.proxmox.com Git - pve-manager.git/blobdiff - www/manager6/ceph/StatusDetail.js
ui: eslint: fix various spacing related issues
[pve-manager.git] / www / manager6 / ceph / StatusDetail.js
index 6517ab7b83a155ed28923bed2f698a9a32bf7026..716b6a019e26fc3465ef582be534aa01e120b0f6 100644 (file)
@@ -4,40 +4,33 @@ Ext.define('PVE.ceph.StatusDetail', {
 
     layout: {
        type: 'hbox',
-       align: 'stretch'
+       align: 'stretch',
     },
 
-    bodyPadding: '0 5 20',
+    bodyPadding: '0 5',
     defaults: {
        xtype: 'box',
        style: {
-           'text-align':'center'
-       }
+           'text-align': 'center',
+       },
     },
 
     items: [{
-       flex: 1,
-       itemId: 'monitors',
-       xtype: 'container',
-       items: [
-           {
-               xtype: 'box',
-               width: '100%',
-               html: '<h3>' + gettext('Monitors') + '</h3>'
-           }
-       ]
-    },{
        flex: 1,
        itemId: 'osds',
+       maxHeight: 250,
+       scrollable: true,
+       padding: '0 10 5 10',
        data: {
            total: 0,
            upin: 0,
            upout: 0,
            downin: 0,
-           downout: 0
+           downout: 0,
+           oldosds: [],
        },
        tpl: [
-           '<h3>' + gettext('OSDs') + '</h3>',
+           '<h3>' + 'OSDs' + '</h3>',
            '<table class="osds">',
            '<tr><td></td>',
            '<td><i class="fa fa-fw good fa-circle"></i>',
@@ -65,85 +58,217 @@ Ext.define('PVE.ceph.StatusDetail', {
            '<br /><div>',
            gettext('Total'),
            ': {total}',
-           '</div>'
-       ]
+           '</div><br />',
+           '<tpl if="oldosds.length &gt; 0">',
+           '<i class="fa fa-refresh warning"></i> ' + gettext('Outdated OSDs') + "<br>",
+           '<div class="osds">',
+           '<tpl for="oldosds">',
+           '<div class="left-aligned">osd.{id}:</div>',
+           '<div class="right-aligned">{version}</div><br />',
+           '<div style="clear:both"></div>',
+           '</tpl>',
+           '</div>',
+           '</tpl>',
+       ],
+    },
+    {
+       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 += '<br>';
+                       record.get('states').forEach(function(state) {
+                           html += '<br>' +
+                               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: {
-           monitors: []
+           states: [],
        },
        tpl: [
-           '<h3>' + gettext('PGs') + '</h3>',
-           '<tpl for="monitors">',
-           '<div class="left-aligned">{state_name}:</div>',
+           '<h3>' + 'PGs' + '</h3>',
+           '<tpl for="states">',
+           '<div class="left-aligned"><i class ="fa fa-circle {cls}"></i> {state_name}:</div>',
            '<div class="right-aligned">{count}</div><br />',
            '<div style="clear:both"></div>',
-           '</tpl>'
-       ]
+           '</tpl>',
+       ],
     }],
 
-    updateAll: function(record) {
+    // 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;
 
-       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;
+       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 pgs_by_state = record.data.pgmap.pgs_by_state || [];
-       pgs_by_state.sort(function(a,b){
+       // 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.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
+       me.statecategories.forEach(function(cat) {
+           cat.count = 0;
+           cat.states = [];
+       });
 
-       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;
+       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 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;
+       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);
                }
            }
-
-           return false;
        });
 
+       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;
@@ -152,127 +277,14 @@ Ext.define('PVE.ceph.StatusDetail', {
            upin: upin_osds,
            upout: upout_osds,
            downin: downin_osds,
-           downout: downout_osds
+           downout: downout_osds,
+           oldosds: oldosds,
        };
-       me.getComponent('osds').update(osds);
+       var osdcomponent = me.getComponent('osds');
+       osdcomponent.update(Ext.apply(osdcomponent.data, 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 monHealth = record.data.health.health.health_services[0].mons || [];
-       var timechecks = {};
-       var healthchecks = {};
-       var monContainer = me.getComponent('monitors');
-       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++) {
-           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, healthchecks[mons[i].name]);
-       }
        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, health) {
-       var me = this;
-       var state = 'HEALTH_ERR';
-       var healthstates = {
-           'HEALTH_OK': 3,
-           'HEALTH_WARN': 2,
-           'HEALTH_ERR': 1
-       };
-
-       // if the monitor is part of the quorum
-       // and has a timestate, get the timestate,
-       // otherwise the state is ERR
-       if (timestate && health && quorum_names &&
-           quorum_names.indexOf(data.name) !== -1) {
-           state = (healthstates[health] < healthstates[timestate])?
-                   health : 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();
-               }
-           }
-       }
-    }
 });
+