From: Tiago Melo Date: Mon, 19 Feb 2018 10:16:03 +0000 (+0000) Subject: mgr/dashboard_v2: add mirroring page X-Git-Tag: v13.0.2~84^2~20 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=24e5ee11a8c0950dfafc504db6da05a7b9644fd6;p=ceph.git mgr/dashboard_v2: add mirroring page Signed-off-by: Tiago Melo --- diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/app-routing.module.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/app-routing.module.ts index 7e7e84106cb..8883796d367 100644 --- a/src/pybind/mgr/dashboard_v2/frontend/src/app/app-routing.module.ts +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/app-routing.module.ts @@ -2,6 +2,7 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { IscsiComponent } from './ceph/block/iscsi/iscsi.component'; +import { MirroringComponent } from './ceph/block/mirroring/mirroring.component'; import { PoolDetailComponent } from './ceph/block/pool-detail/pool-detail.component'; import { CephfsComponent } from './ceph/cephfs/cephfs/cephfs.component'; import { ClientsComponent } from './ceph/cephfs/clients/clients.component'; @@ -40,6 +41,7 @@ const routes: Routes = [ { path: 'cephfs/:id/clients', component: ClientsComponent, canActivate: [AuthGuardService] }, { path: 'cephfs/:id', component: CephfsComponent, canActivate: [AuthGuardService] }, { path: 'configuration', component: ConfigurationComponent, canActivate: [AuthGuardService] }, + { path: 'mirroring', component: MirroringComponent, canActivate: [AuthGuardService] }, { path: '404', component: NotFoundComponent }, { path: 'osd', component: OsdListComponent, canActivate: [AuthGuardService] }, { path: '**', redirectTo: '/404'} diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/block/block.module.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/block/block.module.ts index b1c71c52a7c..6e094fa04d6 100644 --- a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/block/block.module.ts +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/block/block.module.ts @@ -2,13 +2,16 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; -import { TabsModule } from 'ngx-bootstrap'; +import { ProgressbarModule } from 'ngx-bootstrap/progressbar'; +import { TabsModule } from 'ngx-bootstrap/tabs'; import { ComponentsModule } from '../../shared/components/components.module'; import { PipesModule } from '../../shared/pipes/pipes.module'; import { ServicesModule } from '../../shared/services/services.module'; import { SharedModule } from '../../shared/shared.module'; import { IscsiComponent } from './iscsi/iscsi.component'; +import { MirrorHealthColorPipe } from './mirror-health-color.pipe'; +import { MirroringComponent } from './mirroring/mirroring.component'; import { PoolDetailComponent } from './pool-detail/pool-detail.component'; @NgModule({ @@ -16,6 +19,7 @@ import { PoolDetailComponent } from './pool-detail/pool-detail.component'; CommonModule, FormsModule, TabsModule.forRoot(), + ProgressbarModule.forRoot(), SharedModule, ComponentsModule, PipesModule, @@ -23,7 +27,9 @@ import { PoolDetailComponent } from './pool-detail/pool-detail.component'; ], declarations: [ PoolDetailComponent, - IscsiComponent + IscsiComponent, + MirroringComponent, + MirrorHealthColorPipe ] }) export class BlockModule { } diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/block/mirror-health-color.pipe.spec.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/block/mirror-health-color.pipe.spec.ts new file mode 100644 index 00000000000..f22bcf2a599 --- /dev/null +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/block/mirror-health-color.pipe.spec.ts @@ -0,0 +1,8 @@ +import { MirrorHealthColorPipe } from './mirror-health-color.pipe'; + +describe('MirrorHealthColorPipe', () => { + it('create an instance', () => { + const pipe = new MirrorHealthColorPipe(); + expect(pipe).toBeTruthy(); + }); +}); diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/block/mirror-health-color.pipe.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/block/mirror-health-color.pipe.ts new file mode 100644 index 00000000000..43d880ffb1a --- /dev/null +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/block/mirror-health-color.pipe.ts @@ -0,0 +1,17 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ + name: 'mirrorHealthColor' +}) +export class MirrorHealthColorPipe implements PipeTransform { + transform(value: any, args?: any): any { + if (value === 'warning') { + return 'label label-warning'; + } else if (value === 'error') { + return 'label label-danger'; + } else if (value === 'success') { + return 'label label-success'; + } + return 'label label-info'; + } +} diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/block/mirroring/mirroring.component.html b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/block/mirroring/mirroring.component.html new file mode 100644 index 00000000000..405889e4bda --- /dev/null +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/block/mirroring/mirroring.component.html @@ -0,0 +1,89 @@ + + + + +
+
+
+ Daemons + + + +
+
+ +
+
+ Pools + + + +
+
+
+ +
+
+
+ Images + + + + + + + + + + + + + + +
+
+
+ + + {{ value }} + + + + {{ value }} + + + + Syncing + + + + + + diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/block/mirroring/mirroring.component.scss b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/block/mirroring/mirroring.component.scss new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/block/mirroring/mirroring.component.spec.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/block/mirroring/mirroring.component.spec.ts new file mode 100644 index 00000000000..accc5641819 --- /dev/null +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/block/mirroring/mirroring.component.spec.ts @@ -0,0 +1,50 @@ +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ProgressbarModule } from 'ngx-bootstrap/progressbar'; +import { TabsModule } from 'ngx-bootstrap/tabs'; +import { Observable } from 'rxjs/Observable'; + +import { RbdMirroringService } from '../../../shared/services/rbd-mirroring.service'; +import { SharedModule } from '../../../shared/shared.module'; +import { BlockModule } from '../block.module'; +import { MirrorHealthColorPipe } from '../mirror-health-color.pipe'; +import { MirroringComponent } from './mirroring.component'; + +describe('MirroringComponent', () => { + let component: MirroringComponent; + let fixture: ComponentFixture; + + const fakeService = { + get: (service_type: string, service_id: string) => { + return Observable.create(observer => { + return () => console.log('disposed'); + }); + } + }; + + beforeEach( + async(() => { + TestBed.configureTestingModule({ + declarations: [MirroringComponent, MirrorHealthColorPipe], + imports: [ + SharedModule, + TabsModule.forRoot(), + ProgressbarModule.forRoot(), + HttpClientTestingModule + ], + providers: [{ provide: RbdMirroringService, useValue: fakeService }] + }).compileComponents(); + }) + ); + + beforeEach(() => { + fixture = TestBed.createComponent(MirroringComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/block/mirroring/mirroring.component.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/block/mirroring/mirroring.component.ts new file mode 100644 index 00000000000..b89a23f8251 --- /dev/null +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/block/mirroring/mirroring.component.ts @@ -0,0 +1,146 @@ +import { HttpClient } from '@angular/common/http'; +import { Component, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core'; + +import * as _ from 'lodash'; + +import { ViewCacheStatus } from '../../../shared/enum/view-cache-status.enum'; +import { CephShortVersionPipe } from '../../../shared/pipes/ceph-short-version.pipe'; +import { RbdMirroringService } from '../../../shared/services/rbd-mirroring.service'; + +@Component({ + selector: 'cd-mirroring', + templateUrl: './mirroring.component.html', + styleUrls: ['./mirroring.component.scss'] +}) +export class MirroringComponent implements OnInit, OnDestroy { + @ViewChild('healthTmpl') healthTmpl: TemplateRef; + @ViewChild('stateTmpl') stateTmpl: TemplateRef; + @ViewChild('syncTmpl') syncTmpl: TemplateRef; + @ViewChild('progressTmpl') progressTmpl: TemplateRef; + + contentData: any; + interval: any; + + status: ViewCacheStatus; + daemons = { + data: [], + columns: [] + }; + pools = { + data: [], + columns: {} + }; + image_error = { + data: [], + columns: {} + }; + image_syncing = { + data: [], + columns: {} + }; + image_ready = { + data: [], + columns: {} + }; + + constructor( + private http: HttpClient, + private rbdMirroringService: RbdMirroringService, + private cephShortVersionPipe: CephShortVersionPipe + ) { } + + ngOnInit() { + this.daemons.columns = [ + { prop: 'instance_id', name: 'Instance', flexGrow: 2 }, + { prop: 'id', name: 'ID', flexGrow: 2 }, + { prop: 'server_hostname', name: 'Hostname', flexGrow: 2 }, + { + prop: 'server_hostname', + name: 'Version', + pipe: this.cephShortVersionPipe, + flexGrow: 2 + }, + { + prop: 'health', + name: 'Health', + cellTemplate: this.healthTmpl, + flexGrow: 1 + } + ]; + + this.pools.columns = [ + { prop: 'name', name: 'Name', flexGrow: 2 }, + { prop: 'mirror_mode', name: 'Mode', flexGrow: 2 }, + { prop: 'leader_id', name: 'Leader', flexGrow: 2 }, + { prop: 'image_local_count', name: '# Local', flexGrow: 2 }, + { prop: 'image_remote_count', name: '# Remote', flexGrow: 2 }, + { + prop: 'health', + name: 'Health', + cellTemplate: this.healthTmpl, + flexGrow: 1 + } + ]; + + this.image_error.columns = [ + { prop: 'pool_name', name: 'Pool', flexGrow: 2 }, + { prop: 'name', name: 'Image', flexGrow: 2 }, + { prop: 'description', name: 'Issue', flexGrow: 4 }, + { + prop: 'state', + name: 'State', + cellTemplate: this.stateTmpl, + flexGrow: 1 + } + ]; + + this.image_syncing.columns = [ + { prop: 'pool_name', name: 'Pool', flexGrow: 2 }, + { prop: 'name', name: 'Image', flexGrow: 2 }, + { + prop: 'progress', + name: 'Progress', + cellTemplate: this.progressTmpl, + flexGrow: 2 + }, + { + prop: 'state', + name: 'State', + cellTemplate: this.syncTmpl, + flexGrow: 1 + } + ]; + + this.image_ready.columns = [ + { prop: 'pool_name', name: 'Pool', flexGrow: 2 }, + { prop: 'name', name: 'Image', flexGrow: 2 }, + { prop: 'description', name: 'Description', flexGrow: 4 }, + { + prop: 'state', + name: 'State', + cellTemplate: this.stateTmpl, + flexGrow: 1 + } + ]; + + setTimeout(() => { + this.interval = this.refresh(); + }, 30000); + } + + ngOnDestroy() { + clearInterval(this.interval); + } + + refresh() { + this.rbdMirroringService.get().subscribe((data: any) => { + this.daemons.data = data.content_data.daemons; + this.pools.data = data.content_data.pools; + this.image_error.data = data.content_data.image_error; + this.image_syncing.data = data.content_data.image_syncing; + this.image_ready.data = data.content_data.image_ready; + + this.status = data.status; + }); + } +} diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/core/navigation/navigation/navigation.component.html b/src/pybind/mgr/dashboard_v2/frontend/src/app/core/navigation/navigation/navigation.component.html index 378e70a9571..e8981802eed 100644 --- a/src/pybind/mgr/dashboard_v2/frontend/src/app/core/navigation/navigation/navigation.component.html +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/core/navigation/navigation/navigation.component.html @@ -86,17 +86,31 @@ class="dropdown tc_menuitem tc_menuitem_block"> + data-toggle="dropdown" + [ngStyle]="blockHealthColor()"> Block