mirror of
https://github.com/ceph/ceph
synced 2025-02-24 03:27:10 +00:00
mgr/dashboard: Pool list shows current r/w byte usage in graph
Now the pool list will show the current read and write byte usage in the sparkline graph like it is already done in the OSD listing. Fixes: https://tracker.ceph.com/issues/39650 Signed-off-by: Stephan Müller <smueller@suse.com>
This commit is contained in:
parent
692b78891f
commit
2f18cf5770
@ -25,7 +25,7 @@ class PoolTest(DashboardTestCase):
|
||||
pool_list_stat_schema = JObj(sub_elems={
|
||||
'latest': int,
|
||||
'rate': float,
|
||||
'series': JList(JAny(none=False)),
|
||||
'rates': JList(JAny(none=False)),
|
||||
})
|
||||
|
||||
pool_list_stats_schema = JObj(sub_elems={
|
||||
|
@ -2,6 +2,7 @@ import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import * as _ from 'lodash';
|
||||
import { ToastModule } from 'ng2-toastr';
|
||||
import { BsModalService } from 'ngx-bootstrap/modal';
|
||||
import { TabsModule } from 'ngx-bootstrap/tabs';
|
||||
@ -257,14 +258,34 @@ describe('PoolListComponent', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('custom row comparators', () => {
|
||||
const expectCorrectComparator = (statsAttribute: string) => {
|
||||
const mockPool = (v) => ({ stats: { [statsAttribute]: { latest: v } } });
|
||||
const columnDefinition = _.find(
|
||||
component.columns,
|
||||
(column) => column.prop === `stats.${statsAttribute}.rates`
|
||||
);
|
||||
expect(columnDefinition.comparator(undefined, undefined, mockPool(2), mockPool(1))).toBe(1);
|
||||
expect(columnDefinition.comparator(undefined, undefined, mockPool(1), mockPool(2))).toBe(-1);
|
||||
};
|
||||
|
||||
it('compares read bytes correctly', () => {
|
||||
expectCorrectComparator('rd_bytes');
|
||||
});
|
||||
|
||||
it('compares write bytes correctly', () => {
|
||||
expectCorrectComparator('wr_bytes');
|
||||
});
|
||||
});
|
||||
|
||||
describe('transformPoolsData', () => {
|
||||
it('transforms pools data correctly', () => {
|
||||
const pools = [
|
||||
{
|
||||
stats: {
|
||||
bytes_used: { latest: 5, rate: 0, series: [] },
|
||||
max_avail: { latest: 15, rate: 0, series: [] },
|
||||
rd_bytes: { latest: 6, rate: 4, series: [[0, 2], [1, 6]] }
|
||||
bytes_used: { latest: 5, rate: 0, rates: [] },
|
||||
max_avail: { latest: 15, rate: 0, rates: [] },
|
||||
rd_bytes: { latest: 6, rate: 4, rates: [[0, 2], [1, 6]] }
|
||||
},
|
||||
pg_status: { 'active+clean': 8, down: 2 }
|
||||
}
|
||||
@ -274,12 +295,12 @@ describe('PoolListComponent', () => {
|
||||
cdIsBinary: true,
|
||||
pg_status: '8 active+clean, 2 down',
|
||||
stats: {
|
||||
bytes_used: { latest: 5, rate: 0, series: [] },
|
||||
max_avail: { latest: 15, rate: 0, series: [] },
|
||||
rd: { latest: 0, rate: 0, series: [] },
|
||||
rd_bytes: { latest: 6, rate: 4, series: [2, 6] },
|
||||
wr: { latest: 0, rate: 0, series: [] },
|
||||
wr_bytes: { latest: 0, rate: 0, series: [] }
|
||||
bytes_used: { latest: 5, rate: 0, rates: [] },
|
||||
max_avail: { latest: 15, rate: 0, rates: [] },
|
||||
rd: { latest: 0, rate: 0, rates: [] },
|
||||
rd_bytes: { latest: 6, rate: 4, rates: [2, 6] },
|
||||
wr: { latest: 0, rate: 0, rates: [] },
|
||||
wr_bytes: { latest: 0, rate: 0, rates: [] }
|
||||
},
|
||||
usage: 0.25
|
||||
}
|
||||
@ -294,12 +315,12 @@ describe('PoolListComponent', () => {
|
||||
cdIsBinary: true,
|
||||
pg_status: '',
|
||||
stats: {
|
||||
bytes_used: { latest: 0, rate: 0, series: [] },
|
||||
max_avail: { latest: 0, rate: 0, series: [] },
|
||||
rd: { latest: 0, rate: 0, series: [] },
|
||||
rd_bytes: { latest: 0, rate: 0, series: [] },
|
||||
wr: { latest: 0, rate: 0, series: [] },
|
||||
wr_bytes: { latest: 0, rate: 0, series: [] }
|
||||
bytes_used: { latest: 0, rate: 0, rates: [] },
|
||||
max_avail: { latest: 0, rate: 0, rates: [] },
|
||||
rd: { latest: 0, rate: 0, rates: [] },
|
||||
rd_bytes: { latest: 0, rate: 0, rates: [] },
|
||||
wr: { latest: 0, rate: 0, rates: [] },
|
||||
wr_bytes: { latest: 0, rate: 0, rates: [] }
|
||||
},
|
||||
usage: 0
|
||||
}
|
||||
|
@ -106,6 +106,8 @@ export class PoolListComponent implements OnInit {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
const compare = (prop: string, pool1: Pool, pool2: Pool) =>
|
||||
_.get(pool1, prop) > _.get(pool2, prop) ? 1 : -1;
|
||||
this.columns = [
|
||||
{
|
||||
prop: 'pool_name',
|
||||
@ -160,14 +162,18 @@ export class PoolListComponent implements OnInit {
|
||||
flexGrow: 3
|
||||
},
|
||||
{
|
||||
prop: 'stats.rd_bytes.series',
|
||||
prop: 'stats.rd_bytes.rates',
|
||||
name: this.i18n('Read bytes'),
|
||||
comparator: (_valueA, _valueB, rowA: Pool, rowB: Pool) =>
|
||||
compare('stats.rd_bytes.latest', rowA, rowB),
|
||||
cellTransformation: CellTemplate.sparkline,
|
||||
flexGrow: 3
|
||||
},
|
||||
{
|
||||
prop: 'stats.wr_bytes.series',
|
||||
prop: 'stats.wr_bytes.rates',
|
||||
name: this.i18n('Write bytes'),
|
||||
comparator: (_valueA, _valueB, rowA: Pool, rowB: Pool) =>
|
||||
compare('stats.wr_bytes.latest', rowA, rowB),
|
||||
cellTransformation: CellTemplate.sparkline,
|
||||
flexGrow: 3
|
||||
},
|
||||
@ -229,7 +235,7 @@ export class PoolListComponent implements OnInit {
|
||||
|
||||
transformPoolsData(pools: any) {
|
||||
const requiredStats = ['bytes_used', 'max_avail', 'rd_bytes', 'wr_bytes', 'rd', 'wr'];
|
||||
const emptyStat = { latest: 0, rate: 0, series: [] };
|
||||
const emptyStat = { latest: 0, rate: 0, rates: [] };
|
||||
|
||||
_.forEach(pools, (pool: Pool) => {
|
||||
pool['pg_status'] = this.transformPgStatus(pool['pg_status']);
|
||||
@ -242,7 +248,7 @@ export class PoolListComponent implements OnInit {
|
||||
pool['usage'] = avail > 0 ? stats.bytes_used.latest / avail : avail;
|
||||
|
||||
['rd_bytes', 'wr_bytes'].forEach((stat) => {
|
||||
pool.stats[stat].series = pool.stats[stat].series.map((point) => point[1]);
|
||||
pool.stats[stat].rates = pool.stats[stat].rates.map((point) => point[1]);
|
||||
});
|
||||
pool.cdIsBinary = true;
|
||||
});
|
||||
|
@ -1,7 +1,7 @@
|
||||
export class PoolStat {
|
||||
latest: number;
|
||||
rate: number;
|
||||
series: number[];
|
||||
rates: number[];
|
||||
}
|
||||
|
||||
export class PoolStats {
|
||||
|
@ -121,7 +121,7 @@ class CephService(object):
|
||||
s[stat_name] = {
|
||||
'latest': stat_series[0][1],
|
||||
'rate': get_rate(stat_series),
|
||||
'series': [i for i in stat_series]
|
||||
'rates': get_rates_from_data(stat_series)
|
||||
}
|
||||
pool['stats'] = s
|
||||
pools_w_stats.append(pool)
|
||||
@ -179,11 +179,7 @@ class CephService(object):
|
||||
:return: the derivative of mgr.get_counter()
|
||||
:rtype: list[tuple[int, float]]"""
|
||||
data = mgr.get_counter(svc_type, svc_name, path)[path]
|
||||
if not data:
|
||||
return [(0, 0.0)]
|
||||
if len(data) == 1:
|
||||
return [(data[0][0], 0.0)]
|
||||
return [(data2[0], differentiate(data1, data2)) for data1, data2 in pairwise(data)]
|
||||
return get_rates_from_data(data)
|
||||
|
||||
@classmethod
|
||||
def get_rate(cls, svc_type, svc_name, path):
|
||||
@ -260,11 +256,31 @@ class CephService(object):
|
||||
}
|
||||
|
||||
|
||||
def get_rates_from_data(data):
|
||||
"""
|
||||
>>> get_rates_from_data([])
|
||||
[(0, 0.0)]
|
||||
>>> get_rates_from_data([[1, 42]])
|
||||
[(1, 0.0)]
|
||||
>>> get_rates_from_data([[0, 100], [2, 101], [3, 100], [4, 100]])
|
||||
[(2, 0.5), (3, 1.0), (4, 0.0)]
|
||||
"""
|
||||
if not data:
|
||||
return [(0, 0.0)]
|
||||
if len(data) == 1:
|
||||
return [(data[0][0], 0.0)]
|
||||
return [(data2[0], differentiate(data1, data2)) for data1, data2 in pairwise(data)]
|
||||
|
||||
|
||||
def differentiate(data1, data2):
|
||||
"""
|
||||
>>> times = [0, 2]
|
||||
>>> values = [100, 101]
|
||||
>>> differentiate(*zip(times, values))
|
||||
0.5
|
||||
>>> times = [0, 2]
|
||||
>>> values = [100, 99]
|
||||
>>> differentiate(*zip(times, values))
|
||||
0.5
|
||||
"""
|
||||
return (data2[1] - data1[1]) / float(data2[0] - data1[0])
|
||||
return abs((data2[1] - data1[1]) / float(data2[0] - data1[0]))
|
||||
|
Loading…
Reference in New Issue
Block a user