* Applied same fix as in nautilus.
* Adapted Pool list columns to avoid constant resizing.
* Added 'decimals' argument to dimless pipe in order for
stats to fit in Pool list columns.
Fixes: https://tracker.ceph.com/issues/38284
Signed-off-by: Alfonso MartÃnez <almartin@redhat.com>
<th i18n>Name</th>
<th i18n>PG status</th>
<th i18n>Usage</th>
- <th colspan="2"
- i18n>Read</th>
- <th colspan="2"
- i18n>Write</th>
+ <th i18n width="10%">Read Bytes</th>
+ <th i18n width="10%">Read Ops</th>
+ <th i18n width="10%">Write Bytes</th>
+ <th i18n width="10%">Write Ops</th>
</tr>
</thead>
<tbody>
<cd-usage-bar [totalBytes]="pool.stats.bytes_used.latest + pool.stats.max_avail.latest" [usedBytes]="pool.stats.bytes_used.latest"></cd-usage-bar>
</td>
<td>
- {{ pool.stats.rd_bytes.rate | dimless }}
+ {{ pool.stats.rd_bytes.rate | dimless:1 }}
</td>
<td>
- {{ pool.stats.rd.rate | dimless }} ops
+ {{ pool.stats.rd.rate | dimless:1 }} ops
</td>
<td>
- {{ pool.stats.wr_bytes.rate | dimless }}
+ {{ pool.stats.wr_bytes.rate | dimless:1 }}
</td>
<td>
- {{ pool.stats.wr.rate | dimless }} ops
+ {{ pool.stats.wr.rate | dimless:1 }} ops
</td>
</tr>
</tbody>
expect(pipe).toBeTruthy();
});
+ it('transforms 1230.4567 with default decimals (4)', () => {
+ const value = 1234.5678;
+ expect(pipe.transform(value)).toBe('1.2346k');
+ });
+
+ it('transforms 1230.4567 with 0 decimals', () => {
+ const value = 1234.5678;
+ expect(pipe.transform(value, 0)).toBe('1k');
+ });
+
+ it('transforms 1230.4567 with 1 decimal', () => {
+ const value = 1234.5678;
+ expect(pipe.transform(value, 1)).toBe('1.2k');
+ });
+
+ it('transforms 55.01 with 1 decimal', () => {
+ const value = 55.01;
+ expect(pipe.transform(value, 1)).toBe('55');
+ });
+
it('transforms 1000^0', () => {
const value = Math.pow(1000, 0);
expect(pipe.transform(value)).toBe('1');
import { Pipe, PipeTransform } from '@angular/core';
import { FormatterService } from '../services/formatter.service';
+import * as _ from 'lodash';
+
@Pipe({
name: 'dimless'
})
export class DimlessPipe implements PipeTransform {
constructor(private formatter: FormatterService) {}
- transform(value: any, args?: any): any {
+ transform(value: any, decimals?: number): any {
+ if (_.isUndefined(decimals)) {
+ decimals = 4;
+ }
+
return this.formatter.format_number(value, 1000, [
'',
'k',
'E',
'Z',
'Y'
- ]);
+ ], decimals);
}
}
expect(service.format_number('1.2', 1024, formats)).toBe('1.2B');
expect(service.format_number('1', 1024, formats)).toBe('1B');
expect(service.format_number('1024', 1024, formats)).toBe('1KiB');
+ expect(service.format_number(55.000001, 1000, formats, 1)).toBe('55B');
expect(service.format_number(23.45678 * Math.pow(1024, 3), 1024, formats)).toBe('23.4568GiB');
});
if (!_.isNumber(n)) {
return '-';
}
- const unit = n < 1 ? 0 : Math.floor(Math.log(n) / Math.log(divisor));
- const truncatedFloat = this.truncate(n / Math.pow(divisor, unit), decimals);
- return truncatedFloat === '' ? '-' : truncatedFloat + units[unit];
+ let unit = n < 1 ? 0 : Math.floor(Math.log(n) / Math.log(divisor));
+ unit = unit >= units.length ? units.length - 1 : unit;
+ let result = _.round(n / Math.pow(divisor, unit), decimals).toString();
+ if (result === '') {
+ return '-';
+ }
+ if (units[unit] !== '') {
+ result = `${result}${units[unit]}`;
+ }
+ return result;
}
/**
"""
from __future__ import absolute_import
+import collections
import errno
from distutils.version import StrictVersion
from distutils.util import strtobool
import socket
import tempfile
import threading
+import time
from uuid import uuid4
from OpenSSL import crypto
]
OPTIONS.extend(options_schema_list())
+ __pool_stats = collections.defaultdict(lambda: collections.defaultdict(
+ lambda: collections.deque(maxlen=10)))
+
def __init__(self, *args, **kwargs):
super(Module, self).__init__(*args, **kwargs)
CherryPyConfig.__init__(self)
def notify(self, notify_type, notify_id):
NotificationQueue.new_notification(notify_type, notify_id)
+ def get_updated_pool_stats(self):
+ df = self.get('df')
+ pool_stats = dict([(p['id'], p['stats']) for p in df['pools']])
+ now = time.time()
+ for pool_id, stats in pool_stats.items():
+ for stat_name, stat_val in stats.items():
+ self.__pool_stats[pool_id][stat_name].append((now, stat_val))
+
+ return self.__pool_stats
+
class StandbyModule(MgrStandbyModule, CherryPyConfig):
def __init__(self, *args, **kwargs):
# -*- coding: utf-8 -*-
from __future__ import absolute_import
-import time
-import collections
-from collections import defaultdict
import json
from mgr_module import CommandResult
pools_w_stats = []
pg_summary = mgr.get("pg_summary")
- pool_stats = defaultdict(lambda: defaultdict(
- lambda: collections.deque(maxlen=10)))
-
- df = mgr.get("df")
- pool_stats_dict = dict([(p['id'], p['stats']) for p in df['pools']])
- now = time.time()
- for pool_id, stats in pool_stats_dict.items():
- for stat_name, stat_val in stats.items():
- pool_stats[pool_id][stat_name].appendleft((now, stat_val))
+ pool_stats = mgr.get_updated_pool_stats()
for pool in pools:
pool['pg_status'] = pg_summary['by_pool'][pool['pool'].__str__()]
def get_rate(series):
if len(series) >= 2:
- return differentiate(*series[0:1])
+ return differentiate(*list(series)[-2:])
return 0
for stat_name, stat_series in stats.items():