diff --git a/src/pybind/mgr/dashboard_v2/controllers/monitor.py b/src/pybind/mgr/dashboard_v2/controllers/monitor.py new file mode 100644 index 00000000000..ef245d54580 --- /dev/null +++ b/src/pybind/mgr/dashboard_v2/controllers/monitor.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import + +import json + +import cherrypy + +from ..tools import ApiController, AuthRequired, BaseController + + +@ApiController('monitor') +@AuthRequired() +class Monitor(BaseController): + @cherrypy.expose + @cherrypy.tools.json_out() + def default(self): + in_quorum, out_quorum = [], [] + + counters = ['mon.num_sessions'] + + mon_status_json = self.mgr.get("mon_status") + mon_status = json.loads(mon_status_json['json']) + + for mon in mon_status["monmap"]["mons"]: + mon["stats"] = {} + for counter in counters: + data = self.mgr.get_counter("mon", mon["name"], counter) + if data is not None: + mon["stats"][counter.split(".")[1]] = data[counter] + else: + mon["stats"][counter.split(".")[1]] = [] + if mon["rank"] in mon_status["quorum"]: + in_quorum.append(mon) + else: + out_quorum.append(mon) + + return { + 'mon_status': mon_status, + 'in_quorum': in_quorum, + 'out_quorum': out_quorum + } 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 96afda40669..b5c2dc06bbb 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 @@ -3,6 +3,7 @@ import { RouterModule, Routes } from '@angular/router'; import { PoolDetailComponent } from './ceph/block/pool-detail/pool-detail.component'; import { HostsComponent } from './ceph/cluster/hosts/hosts.component'; +import { MonitorComponent } from './ceph/cluster/monitor/monitor.component'; import { DashboardComponent } from './ceph/dashboard/dashboard/dashboard.component'; import { PerformanceCounterComponent @@ -13,11 +14,8 @@ import { AuthGuardService } from './shared/services/auth-guard.service'; const routes: Routes = [ { path: '', redirectTo: 'dashboard', pathMatch: 'full' }, - { - path: 'dashboard', - component: DashboardComponent, - canActivate: [AuthGuardService] - }, + { path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuardService] }, + { path: 'hosts', component: HostsComponent, canActivate: [AuthGuardService] }, { path: 'login', component: LoginComponent }, { path: 'hosts', component: HostsComponent, canActivate: [AuthGuardService] }, { @@ -30,11 +28,12 @@ const routes: Routes = [ path: 'perf_counters/:type/:id', component: PerformanceCounterComponent, canActivate: [AuthGuardService] - } + }, + { path: 'monitor', component: MonitorComponent, canActivate: [AuthGuardService] } ]; @NgModule({ imports: [RouterModule.forRoot(routes, { useHash: true })], exports: [RouterModule] }) -export class AppRoutingModule {} +export class AppRoutingModule { } diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/cluster.module.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/cluster.module.ts index c05675e74d2..463f0106b8c 100644 --- a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/cluster.module.ts +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/cluster.module.ts @@ -4,6 +4,8 @@ import { NgModule } from '@angular/core'; import { ComponentsModule } from '../../shared/components/components.module'; import { SharedModule } from '../../shared/shared.module'; import { HostsComponent } from './hosts/hosts.component'; +import { MonitorService } from './monitor.service'; +import { MonitorComponent } from './monitor/monitor.component'; import { ServiceListPipe } from './service-list.pipe'; @NgModule({ @@ -14,10 +16,12 @@ import { ServiceListPipe } from './service-list.pipe'; ], declarations: [ HostsComponent, - ServiceListPipe + ServiceListPipe, + MonitorComponent, ], providers: [ - ServiceListPipe + ServiceListPipe, + MonitorService ] }) -export class ClusterModule { } +export class ClusterModule {} diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/monitor.service.spec.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/monitor.service.spec.ts new file mode 100644 index 00000000000..1d5f7de97b7 --- /dev/null +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/monitor.service.spec.ts @@ -0,0 +1,21 @@ +import { HttpClientModule } from '@angular/common/http'; +import { + HttpClientTestingModule, + HttpTestingController +} from '@angular/common/http/testing'; +import { inject, TestBed } from '@angular/core/testing'; + +import { MonitorService } from './monitor.service'; + +describe('MonitorService', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [MonitorService], + imports: [HttpClientTestingModule, HttpClientModule] + }); + }); + + it('should be created', inject([MonitorService], (service: MonitorService) => { + expect(service).toBeTruthy(); + })); +}); diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/monitor.service.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/monitor.service.ts new file mode 100644 index 00000000000..5a61870660c --- /dev/null +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/monitor.service.ts @@ -0,0 +1,11 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; + +@Injectable() +export class MonitorService { + constructor(private http: HttpClient) {} + + getMonitor() { + return this.http.get('/api/monitor'); + } +} diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/monitor/monitor.component.html b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/monitor/monitor.component.html new file mode 100644 index 00000000000..5c8f0fcc399 --- /dev/null +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/cluster/monitor/monitor.component.html @@ -0,0 +1,80 @@ + + +