]> git.proxmox.com Git - pve-manager.git/blobdiff - www/manager6/ceph/Status.js
api: ceph: osd: create: rename size parameters
[pve-manager.git] / www / manager6 / ceph / Status.js
index 2de2ceed77715795d601c5ffcdc1681f01980695..e92c698b7008ebeecbaeaeff18f3b9bd98208e55 100644 (file)
@@ -5,15 +5,13 @@ Ext.define('PVE.node.CephStatus', {
     onlineHelp: 'chapter_pveceph',
 
     scrollable: true,
-
     bodyPadding: 5,
-
     layout: {
-       type: 'column'
+       type: 'column',
     },
 
     defaults: {
-       padding: 5
+       padding: 5,
     },
 
     items: [
@@ -23,18 +21,18 @@ Ext.define('PVE.node.CephStatus', {
            bodyPadding: 10,
            plugins: 'responsive',
            responsiveConfig: {
-               'width < 1900': {
+               'width < 1600': {
                    minHeight: 230,
-                   columnWidth: 1
+                   columnWidth: 1,
                },
-               'width >= 1900': {
+               'width >= 1600': {
                    minHeight: 500,
-                   columnWidth: 0.5
-               }
+                   columnWidth: 0.5,
+               },
            },
            layout: {
                type: 'hbox',
-               align: 'stretch'
+               align: 'stretch',
            },
            items: [
                {
@@ -49,7 +47,7 @@ Ext.define('PVE.node.CephStatus', {
                            flex: 1,
                            itemId: 'overallhealth',
                            xtype: 'pveHealthWidget',
-                           title: gettext('Status')
+                           title: gettext('Status'),
                        },
                        {
                            itemId: 'versioninfo',
@@ -64,7 +62,7 @@ Ext.define('PVE.node.CephStatus', {
                            style: {
                                'text-align': 'center',
                            },
-                       }
+                       },
                    ],
                },
                {
@@ -73,10 +71,11 @@ Ext.define('PVE.node.CephStatus', {
                    stateful: true,
                    stateId: 'ceph-status-warnings',
                    xtype: 'grid',
-                   // since we load the store manually,
-                   // to show the emptytext, we have to
-                   // specify an empty store
-                   store: { data:[] },
+                   // we load the store manually, to show an emptyText specify an empty intermediate store
+                   store: {
+                       trackRemoved: false,
+                       data: [],
+                   },
                    emptyText: gettext('No Warnings/Errors'),
                    columns: [
                        {
@@ -85,22 +84,21 @@ Ext.define('PVE.node.CephStatus', {
                            align: 'center',
                            width: 70,
                            renderer: function(value) {
-                               var health = PVE.Utils.map_ceph_health[value];
-                               var classes = PVE.Utils.get_health_icon(health);
-
-                               return '<i class="fa fa-fw ' + classes + '"></i>';
+                               let health = PVE.Utils.map_ceph_health[value];
+                               let icon = PVE.Utils.get_health_icon(health);
+                               return `<i class="fa fa-fw ${icon}"></i>`;
                            },
                            sorter: {
-                               sorterFn: function(a,b) {
-                                   var healthArr = ['HEALTH_ERR', 'HEALTH_WARN', 'HEALTH_OK'];
-                                   return healthArr.indexOf(b.data.severity) - healthArr.indexOf(a.data.severity);
-                               }
-                           }
+                               sorterFn: function(a, b) {
+                                   let health = ['HEALTH_ERR', 'HEALTH_WARN', 'HEALTH_OK'];
+                                   return health.indexOf(b.data.severity) - health.indexOf(a.data.severity);
+                               },
+                           },
                        },
                        {
                            dataIndex: 'summary',
                            header: gettext('Summary'),
-                           flex: 1
+                           flex: 1,
                        },
                        {
                            xtype: 'actioncolumn',
@@ -118,7 +116,7 @@ Ext.define('PVE.node.CephStatus', {
                                            width: 650,
                                            height: 400,
                                            layout: {
-                                               type: 'fit'
+                                               type: 'fit',
                                            },
                                            items: [{
                                                scrollable: true,
@@ -126,34 +124,34 @@ Ext.define('PVE.node.CephStatus', {
                                                xtype: 'box',
                                                html: [
                                                    '<span>' + Ext.htmlEncode(record.data.summary) + '</span>',
-                                                   '<pre>' + Ext.htmlEncode(record.data.detail) + '</pre>'
-                                               ]
-                                           }]
+                                                   '<pre>' + Ext.htmlEncode(record.data.detail) + '</pre>',
+                                               ],
+                                           }],
                                        });
                                        win.show();
-                                   }
-                               }
-                           ]
-                       }
-                   ]
-               }
-           ]
+                                   },
+                               },
+                           ],
+                       },
+                   ],
+               },
+           ],
        },
        {
            xtype: 'pveCephStatusDetail',
            itemId: 'statusdetail',
            plugins: 'responsive',
            responsiveConfig: {
-               'width < 1900': {
+               'width < 1600': {
                    columnWidth: 1,
-                   minHeight: 250
+                   minHeight: 250,
                },
-               'width >= 1900': {
+               'width >= 1600': {
                    columnWidth: 0.5,
-                   minHeight: 300
-               }
+                   minHeight: 300,
+               },
            },
-           title: gettext('Status')
+           title: gettext('Status'),
        },
        {
            title: gettext('Services'),
@@ -162,18 +160,18 @@ Ext.define('PVE.node.CephStatus', {
            plugins: 'responsive',
            layout: {
                type: 'hbox',
-               align: 'stretch'
+               align: 'stretch',
            },
            responsiveConfig: {
-               'width < 1900': {
+               'width < 1600': {
                    columnWidth: 1,
-                   minHeight: 200
+                   minHeight: 200,
                },
-               'width >= 1900': {
+               'width >= 1600': {
                    columnWidth: 0.5,
-                   minHeight: 200
-               }
-           }
+                   minHeight: 200,
+               },
+           },
        },
        {
            xtype: 'panel',
@@ -182,83 +180,94 @@ Ext.define('PVE.node.CephStatus', {
            bodyPadding: 5,
            layout: {
                type: 'hbox',
-               align: 'center'
+               align: 'center',
            },
            items: [
                {
                    flex: 1,
-                   xtype: 'proxmoxGauge',
-                   itemId: 'space',
-                   title: gettext('Usage')
+                   xtype: 'container',
+                   items: [
+                       {
+                           xtype: 'proxmoxGauge',
+                           itemId: 'space',
+                           title: gettext('Usage'),
+                       },
+                       {
+                           flex: 1,
+                           border: false,
+                       },
+                       {
+                           xtype: 'container',
+                           itemId: 'recovery',
+                           hidden: true,
+                           padding: 25,
+                           items: [
+                               {
+                                   itemId: 'recoverychart',
+                                   xtype: 'pveRunningChart',
+                                   title: gettext('Recovery') +'/ '+ gettext('Rebalance'),
+                                   renderer: PVE.Utils.render_bandwidth,
+                                   height: 100,
+                               },
+                               {
+                                   xtype: 'progressbar',
+                                   itemId: 'recoveryprogress',
+                               },
+                           ],
+                       },
+                   ],
                },
                {
                    flex: 2,
                    xtype: 'container',
                    defaults: {
                        padding: 0,
-                       height: 100
+                       height: 100,
                    },
                    items: [
                        {
                            itemId: 'reads',
                            xtype: 'pveRunningChart',
                            title: gettext('Reads'),
-                           renderer: PVE.Utils.render_bandwidth
+                           renderer: PVE.Utils.render_bandwidth,
                        },
                        {
                            itemId: 'writes',
                            xtype: 'pveRunningChart',
                            title: gettext('Writes'),
-                           renderer: PVE.Utils.render_bandwidth
-                       },
-                       {
-                           itemId: 'iops',
-                           xtype: 'pveRunningChart',
-                           hidden: true,
-                           title: 'IOPS', // do not localize
-                           renderer: Ext.util.Format.numberRenderer('0,000')
+                           renderer: PVE.Utils.render_bandwidth,
                        },
                        {
                            itemId: 'readiops',
                            xtype: 'pveRunningChart',
-                           hidden: true,
                            title: 'IOPS: ' + gettext('Reads'),
-                           renderer: Ext.util.Format.numberRenderer('0,000')
+                           renderer: Ext.util.Format.numberRenderer('0,000'),
                        },
                        {
                            itemId: 'writeiops',
                            xtype: 'pveRunningChart',
-                           hidden: true,
                            title: 'IOPS: ' + gettext('Writes'),
-                           renderer: Ext.util.Format.numberRenderer('0,000')
-                       }
-                   ]
-               }
-           ]
-       }
+                           renderer: Ext.util.Format.numberRenderer('0,000'),
+                       },
+                   ],
+               },
+           ],
+       },
     ],
 
     generateCheckData: function(health) {
        var result = [];
-       var checks = health.checks || {};
-       var keys = Ext.Object.getKeys(checks).sort();
+       let checks = health.checks || {};
 
-       Ext.Array.forEach(keys, function(key) {
-           var details = checks[key].detail || [];
+       Object.keys(checks).sort().forEach(key => {
+           let check = checks[key];
            result.push({
                id: key,
-               summary: checks[key].summary.message,
-               detail: Ext.Array.reduce(
-                           checks[key].detail,
-                           function(first, second) {
-                               return first + '\n' + second.message;
-                           },
-                           ''
-                       ),
-               severity: checks[key].severity
+               summary: check.summary.message,
+               detail: check.detail.reduce((acc, v) => `${acc}\n${v.message}`, ''),
+               severity: check.severity,
            });
        });
-
        return result;
     },
 
@@ -283,45 +292,59 @@ Ext.define('PVE.node.CephStatus', {
        me.getComponent('statusdetail').updateAll(me.metadata || {}, rec.data);
 
        // add performance data
-       var used = rec.data.pgmap.bytes_used;
-       var total = rec.data.pgmap.bytes_total;
+       let pgmap = rec.data.pgmap;
+       let used = pgmap.bytes_used;
+       let total = pgmap.bytes_total;
 
        var text = Ext.String.format(gettext('{0} of {1}'),
-           PVE.Utils.render_size(used),
-           PVE.Utils.render_size(total)
+           Proxmox.Utils.render_size(used),
+           Proxmox.Utils.render_size(total),
        );
 
        // update the usage widget
        me.down('#space').updateValue(used/total, text);
 
-       // TODO: logic for jewel (iops split in read/write)
+       let readiops = pgmap.read_op_per_sec;
+       let writeiops = pgmap.write_op_per_sec;
+       let reads = pgmap.read_bytes_sec || 0;
+       let writes = pgmap.write_bytes_sec || 0;
 
-       var iops = rec.data.pgmap.op_per_sec;
-       var readiops = rec.data.pgmap.read_op_per_sec;
-       var writeiops = rec.data.pgmap.write_op_per_sec;
-       var reads = rec.data.pgmap.read_bytes_sec || 0;
-       var writes = rec.data.pgmap.write_bytes_sec || 0;
-
-       if (iops !== undefined && me.version !== 'hammer') {
-           me.change_version('hammer');
-       } else if((readiops !== undefined || writeiops !== undefined) && me.version !== 'jewel') {
-           me.change_version('jewel');
-       }
        // update the graphs
        me.reads.addDataPoint(reads);
        me.writes.addDataPoint(writes);
-       me.iops.addDataPoint(iops);
        me.readiops.addDataPoint(readiops);
        me.writeiops.addDataPoint(writeiops);
-    },
 
-    change_version: function(version) {
-       var me = this;
-       me.version = version;
-       me.sp.set('ceph-version', version);
-       me.iops.setVisible(version === 'hammer');
-       me.readiops.setVisible(version === 'jewel');
-       me.writeiops.setVisible(version === 'jewel');
+       let degraded = pgmap.degraded_objects || 0;
+       let misplaced = pgmap.misplaced_objects || 0;
+       let unfound = pgmap.unfound_objects || 0;
+       let unhealthy = degraded + unfound + misplaced;
+       // update recovery
+       if (pgmap.recovering_objects_per_sec !== undefined || unhealthy > 0) {
+           let toRecover = pgmap.misplaced_total || pgmap.unfound_total || pgmap.degraded_total || 0;
+           if (toRecover === 0) {
+               return; // FIXME: unexpected return and leaves things possible visible when it shouldn't?
+           }
+           let recovered = toRecover - unhealthy || 0;
+           let speed = pgmap.recovering_bytes_per_sec || 0;
+
+           let recoveryRatio = recovered / total;
+           let txt = `${(recoveryRatio * 100).toFixed(2)}%`;
+           if (speed > 0) {
+               let obj_per_sec = speed / (4 * 1024 * 1024); // 4 MiB per Object
+               let duration = Proxmox.Utils.format_duration_human(unhealthy/obj_per_sec);
+               let speedTxt = PVE.Utils.render_bandwidth(speed);
+               txt += ` (${speedTxt} - ${duration} left)`;
+           }
+
+           me.down('#recovery').setVisible(true);
+           me.down('#recoveryprogress').updateValue(recoveryRatio);
+           me.down('#recoveryprogress').updateText(txt);
+           me.down('#recoverychart').addDataPoint(speed);
+       } else {
+           me.down('#recovery').setVisible(false);
+           me.down('#recoverychart').addDataPoint(0);
+       }
     },
 
     initComponent: function() {
@@ -336,8 +359,8 @@ Ext.define('PVE.node.CephStatus', {
            interval: 5000,
            proxy: {
                type: 'proxmox',
-               url: baseurl + '/status'
-           }
+               url: baseurl + '/status',
+           },
        });
 
        me.metadatastore = Ext.create('Proxmox.data.UpdateStore', {
@@ -345,8 +368,8 @@ Ext.define('PVE.node.CephStatus', {
            interval: 15*1000,
            proxy: {
                type: 'proxmox',
-               url: '/api2/json/cluster/ceph/metadata'
-           }
+               url: '/api2/json/cluster/ceph/metadata',
+           },
        });
 
        // save references for the updatefunction
@@ -356,40 +379,25 @@ Ext.define('PVE.node.CephStatus', {
        me.reads = me.down('#reads');
        me.writes = me.down('#writes');
 
-       // get ceph version
-       me.sp = Ext.state.Manager.getProvider();
-       me.version = me.sp.get('ceph-version');
-       me.change_version(me.version);
-
-       var regex = new RegExp("not (installed|initialized)", "i");
-       PVE.Utils.handleStoreErrorOrMask(me, me.store, regex, function(me, error){
-           me.store.stopUpdate();
-           PVE.Utils.showCephInstallOrMask(me, error.statusText, (nodename || 'localhost'),
-               function(win){
-                   me.mon(win, 'cephInstallWindowClosed', function(){
-                       me.store.startUpdate();
-                   });
-               }
-           );
-       });
+       // manages the "install ceph?" overlay
+       PVE.Utils.monitor_ceph_installed(me, me.store, nodename);
 
        me.mon(me.store, 'load', me.updateAll, me);
        me.mon(me.metadatastore, 'load', function(store, records, success) {
            if (!success || records.length < 1) {
                return;
            }
-           var rec = records[0];
-           me.metadata = rec.data;
+           me.metadata = records[0].data;
 
            // update services
-           me.getComponent('services').updateAll(rec.data, me.status || {});
+           me.getComponent('services').updateAll(me.metadata, me.status || {});
 
            // update detailstatus panel
-           me.getComponent('statusdetail').updateAll(rec.data, me.status || {});
+           me.getComponent('statusdetail').updateAll(me.metadata, me.status || {});
 
            let maxversion = [];
            let maxversiontext = "";
-           for (const [nodename, data] of Object.entries(me.metadata.node)) {
+           for (const [_nodename, data] of Object.entries(me.metadata.node)) {
                let version = data.version.parts;
                if (PVE.Utils.compare_ceph_versions(version, maxversion) > 0) {
                    maxversion = version;
@@ -403,6 +411,6 @@ Ext.define('PVE.node.CephStatus', {
        me.on('destroy', me.metadatastore.stopUpdate);
        me.store.startUpdate();
        me.metadatastore.startUpdate();
-    }
+    },
 
 });