From 1a9aa765af454b060a1bdee15839faf7b0529cda Mon Sep 17 00:00:00 2001 From: Tiago Melo Date: Wed, 28 Feb 2018 18:45:49 +0000 Subject: [PATCH] mgr/dashboard_v2: extract cephfs chart into a component Signed-off-by: Tiago Melo --- .../cephfs-chart/cephfs-chart.component.html | 12 ++ .../cephfs-chart/cephfs-chart.component.scss | 6 + .../cephfs-chart.component.spec.ts | 29 ++++ .../cephfs-chart/cephfs-chart.component.ts | 128 ++++++++++++++++++ .../src/app/ceph/cephfs/cephfs.module.ts | 3 +- .../ceph/cephfs/cephfs/cephfs.component.html | 10 +- .../ceph/cephfs/cephfs/cephfs.component.scss | 7 - .../cephfs/cephfs/cephfs.component.spec.ts | 3 +- .../ceph/cephfs/cephfs/cephfs.component.ts | 119 +--------------- 9 files changed, 188 insertions(+), 129 deletions(-) create mode 100644 src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.html create mode 100644 src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.scss create mode 100644 src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.spec.ts create mode 100644 src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.ts diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.html b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.html new file mode 100644 index 00000000000..b98d70838a0 --- /dev/null +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.html @@ -0,0 +1,12 @@ +
+ + +
+
+
+
diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.scss b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.scss new file mode 100644 index 00000000000..23aaa354765 --- /dev/null +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.scss @@ -0,0 +1,6 @@ +.chart-container { + position: relative; + margin: auto; + height: 500px; + width: 100%; +} diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.spec.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.spec.ts new file mode 100644 index 00000000000..6d552041f1c --- /dev/null +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.spec.ts @@ -0,0 +1,29 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ChartsModule } from 'ng2-charts/ng2-charts'; + +import { CephfsChartComponent } from './cephfs-chart.component'; + +describe('CephfsChartComponent', () => { + let component: CephfsChartComponent; + let fixture: ComponentFixture; + + beforeEach( + async(() => { + TestBed.configureTestingModule({ + imports: [ChartsModule], + declarations: [CephfsChartComponent] + }).compileComponents(); + }) + ); + + beforeEach(() => { + fixture = TestBed.createComponent(CephfsChartComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.ts new file mode 100644 index 00000000000..fb4a394a77d --- /dev/null +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs-chart/cephfs-chart.component.ts @@ -0,0 +1,128 @@ +import { Component, Input, OnChanges, OnInit } from '@angular/core'; + +import * as _ from 'lodash'; + +@Component({ + selector: 'cd-cephfs-chart', + templateUrl: './cephfs-chart.component.html', + styleUrls: ['./cephfs-chart.component.scss'] +}) +export class CephfsChartComponent implements OnChanges, OnInit { + @Input() mdsCounter: any; + + lhsCounter = 'mds.inodes'; + rhsCounter = 'mds_server.handle_client_request'; + + chart: any; + + constructor() {} + + ngOnInit() { + if (_.isUndefined(this.mdsCounter)) { + return; + } + + const lhsData = this.convert_timeseries(this.mdsCounter[this.lhsCounter]); + const rhsData = this.delta_timeseries(this.mdsCounter[this.rhsCounter]); + + this.chart = { + datasets: [ + { + label: this.lhsCounter, + yAxisID: 'LHS', + data: lhsData, + tension: 0.1 + }, + { + label: this.rhsCounter, + yAxisID: 'RHS', + data: rhsData, + tension: 0.1 + } + ], + options: { + responsive: true, + maintainAspectRatio: false, + legend: { + position: 'top' + }, + scales: { + xAxes: [ + { + position: 'top', + type: 'time', + time: { + displayFormats: { + quarter: 'MMM YYYY' + } + } + } + ], + yAxes: [ + { + id: 'LHS', + type: 'linear', + position: 'left', + min: 0 + }, + { + id: 'RHS', + type: 'linear', + position: 'right', + min: 0 + } + ] + } + }, + chartType: 'line' + }; + } + + ngOnChanges() { + if (!this.chart) { + return; + } + + const lhsData = this.convert_timeseries(this.mdsCounter[this.lhsCounter]); + const rhsData = this.delta_timeseries(this.mdsCounter[this.rhsCounter]); + + this.chart.datasets[0].data = lhsData; + this.chart.datasets[1].data = rhsData; + } + + // Convert ceph-mgr's time series format (list of 2-tuples + // with seconds-since-epoch timestamps) into what chart.js + // can handle (list of objects with millisecs-since-epoch + // timestamps) + convert_timeseries(sourceSeries) { + const data = []; + _.each(sourceSeries, dp => { + data.push({ + x: dp[0] * 1000, + y: dp[1] + }); + }); + + return data; + } + + delta_timeseries(sourceSeries) { + let i; + let prev = sourceSeries[0]; + const result = []; + for (i = 1; i < sourceSeries.length; i++) { + const cur = sourceSeries[i]; + const tdelta = cur[0] - prev[0]; + const vdelta = cur[1] - prev[1]; + const rate = vdelta / tdelta; + + result.push({ + x: cur[0] * 1000, + y: rate + }); + + prev = cur; + } + return result; + } +} diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs.module.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs.module.ts index 2c1432d168e..c47051c18e6 100644 --- a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs.module.ts +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs.module.ts @@ -6,6 +6,7 @@ import { ProgressbarModule } from 'ngx-bootstrap/progressbar'; import { AppRoutingModule } from '../../app-routing.module'; import { SharedModule } from '../../shared/shared.module'; +import { CephfsChartComponent } from './cephfs-chart/cephfs-chart.component'; import { CephfsService } from './cephfs.service'; import { CephfsComponent } from './cephfs/cephfs.component'; import { ClientsComponent } from './clients/clients.component'; @@ -18,7 +19,7 @@ import { ClientsComponent } from './clients/clients.component'; ChartsModule, ProgressbarModule.forRoot() ], - declarations: [CephfsComponent, ClientsComponent], + declarations: [CephfsComponent, ClientsComponent, CephfsChartComponent], providers: [CephfsService] }) export class CephfsModule {} diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs/cephfs.component.html b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs/cephfs.component.html index 2333f770b66..eb970cec270 100644 --- a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs/cephfs.component.html +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs/cephfs.component.html @@ -48,15 +48,9 @@
+ *ngFor="let mdsCounter of objectValues(mdsCounters); trackBy: trackByFn">
-
- - -
+
diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs/cephfs.component.scss b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs/cephfs.component.scss index 567fbf3aa15..d82829af85c 100644 --- a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs/cephfs.component.scss +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs/cephfs.component.scss @@ -1,10 +1,3 @@ -.chart-container { - position: relative; - margin: auto; - height: 500px; - width: 100%; -} - .progress { margin-bottom: 0px; } diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs/cephfs.component.spec.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs/cephfs.component.spec.ts index 03e5b1ba3bc..3df655defa6 100644 --- a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs/cephfs.component.spec.ts +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs/cephfs.component.spec.ts @@ -6,6 +6,7 @@ import { BsDropdownModule, ProgressbarModule } from 'ngx-bootstrap'; import { Observable } from 'rxjs/Observable'; import { SharedModule } from '../../../shared/shared.module'; +import { CephfsChartComponent } from '../cephfs-chart/cephfs-chart.component'; import { CephfsService } from '../cephfs.service'; import { CephfsComponent } from './cephfs.component'; @@ -36,7 +37,7 @@ describe('CephfsComponent', () => { BsDropdownModule.forRoot(), ProgressbarModule.forRoot() ], - declarations: [CephfsComponent], + declarations: [CephfsComponent, CephfsChartComponent], providers: [ { provide: CephfsService, useValue: fakeFilesystemService } ] diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs/cephfs.component.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs/cephfs.component.ts index 1cd93f3a9ca..d8fe382fec6 100644 --- a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs/cephfs.component.ts +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cephfs/cephfs/cephfs.component.ts @@ -2,6 +2,7 @@ import { Component, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/c import { ActivatedRoute } from '@angular/router'; import * as _ from 'lodash'; +import { Subscription } from 'rxjs/Subscription'; import { DimlessBinaryPipe } from '../../../shared/pipes/dimless-binary.pipe'; import { DimlessPipe } from '../../../shared/pipes/dimless.pipe'; @@ -16,15 +17,10 @@ export class CephfsComponent implements OnInit, OnDestroy { @ViewChild('poolProgressTmpl') poolProgressTmpl: TemplateRef; @ViewChild('activityTmpl') activityTmpl: TemplateRef; - routeParamsSubscribe: any; + routeParamsSubscribe: Subscription; objectValues = Object.values; - single: any[]; - multi: any[]; - - view: any[] = [700, 400]; - id: number; name: string; ranks: any; @@ -34,11 +30,6 @@ export class CephfsComponent implements OnInit, OnDestroy { mdsCounters = {}; - lhsCounter = 'mds.inodes'; - rhsCounter = 'mds_server.handle_client_request'; - charts = {}; - interval: any; - constructor( private route: ActivatedRoute, private cephfsService: CephfsService, @@ -113,119 +104,23 @@ export class CephfsComponent implements OnInit, OnDestroy { ]; this.name = data.cephfs.name; this.clientCount = data.cephfs.client_count; - this.draw_chart(); }); - } - draw_chart() { this.cephfsService.getMdsCounters(this.id).subscribe(data => { - const topChart = true; - _.each(this.mdsCounters, (value, key) => { if (data[key] === undefined) { delete this.mdsCounters[key]; } }); - _.each(data, (mdsData, mdsName) => { - const lhsData = this.convert_timeseries(mdsData[this.lhsCounter]); - const rhsData = this.delta_timeseries(mdsData[this.rhsCounter]); - - if (this.mdsCounters[mdsName] === undefined) { - this.mdsCounters[mdsName] = { - datasets: [ - { - label: this.lhsCounter, - yAxisID: 'LHS', - data: lhsData, - tension: 0.1 - }, - { - label: this.rhsCounter, - yAxisID: 'RHS', - data: rhsData, - tension: 0.1 - } - ], - options: { - responsive: true, - maintainAspectRatio: false, - legend: { - position: 'top', - display: topChart - }, - scales: { - xAxes: [ - { - position: 'top', - type: 'time', - display: topChart, - time: { - displayFormats: { - quarter: 'MMM YYYY' - } - } - } - ], - yAxes: [ - { - id: 'LHS', - type: 'linear', - position: 'left', - min: 0 - }, - { - id: 'RHS', - type: 'linear', - position: 'right', - min: 0 - } - ] - } - }, - chartType: 'line' - }; - } else { - this.mdsCounters[mdsName].datasets[0].data = lhsData; - this.mdsCounters[mdsName].datasets[1].data = rhsData; - } + _.each(data, (mdsData: any, mdsName) => { + mdsData.name = mdsName; + this.mdsCounters[mdsName] = mdsData; }); }); } - // Convert ceph-mgr's time series format (list of 2-tuples - // with seconds-since-epoch timestamps) into what chart.js - // can handle (list of objects with millisecs-since-epoch - // timestamps) - convert_timeseries(sourceSeries) { - const data = []; - _.each(sourceSeries, dp => { - data.push({ - x: dp[0] * 1000, - y: dp[1] - }); - }); - - return data; - } - - delta_timeseries(sourceSeries) { - let i; - let prev = sourceSeries[0]; - const result = []; - for (i = 1; i < sourceSeries.length; i++) { - const cur = sourceSeries[i]; - const tdelta = cur[0] - prev[0]; - const vdelta = cur[1] - prev[1]; - const rate = vdelta / tdelta; - - result.push({ - x: cur[0] * 1000, - y: rate - }); - - prev = cur; - } - return result; + trackByFn(index, item) { + return item.name; } } -- 2.39.5