From: Sebastian Wagner Date: Thu, 22 Feb 2018 13:52:08 +0000 (+0100) Subject: mgr/dashboard_v2: Move `dashboard/toplevel` to a new controller X-Git-Tag: v13.0.2~84^2~24 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=92ef46eb8f29e95654c02e61a9050d852ac7c02a;p=ceph.git mgr/dashboard_v2: Move `dashboard/toplevel` to a new controller Details: * Moved `/dashboard/toplevel` API endpoint to `/summary`. * Moved testcase to `tests/test_summary.py`. * Also renamed service in the frontend. Signed-off-by: Sebastian Wagner --- diff --git a/src/pybind/mgr/dashboard_v2/controllers/dashboard.py b/src/pybind/mgr/dashboard_v2/controllers/dashboard.py index 21637f4f9786..da8a3b341c4f 100644 --- a/src/pybind/mgr/dashboard_v2/controllers/dashboard.py +++ b/src/pybind/mgr/dashboard_v2/controllers/dashboard.py @@ -9,8 +9,7 @@ import time import cherrypy from mgr_module import CommandResult -from ..services.ceph_service import CephService -from ..tools import ApiController, AuthRequired, BaseController, NotificationQueue, ViewCache +from ..tools import ApiController, AuthRequired, BaseController, NotificationQueue LOG_BUFFER_SIZE = 30 @@ -55,35 +54,6 @@ class Dashboard(BaseController): for l in lines: buf.appendleft(l) - @ViewCache() - def _rbd_pool_ls(self): - return [pool['pool_name'] for pool in CephService.get_pool_list('rbd')] - - @cherrypy.expose - @cherrypy.tools.json_out() - def toplevel(self): - fsmap = self.mgr.get("fs_map") - - filesystems = [ - { - "id": f['id'], - "name": f['mdsmap']['fs_name'] - } - for f in fsmap['filesystems'] - ] - - _, data = self._rbd_pool_ls() - if data is None: - self.mgr.log.warning("Failed to get RBD pool list") - data = [] - data.sort() - - return { - 'health_status': self.health_data()['status'], - 'filesystems': filesystems, - 'rbd_pools': data - } - # pylint: disable=R0914 @cherrypy.expose @cherrypy.tools.json_out() diff --git a/src/pybind/mgr/dashboard_v2/controllers/summary.py b/src/pybind/mgr/dashboard_v2/controllers/summary.py new file mode 100644 index 000000000000..a3c0ed0fbd6f --- /dev/null +++ b/src/pybind/mgr/dashboard_v2/controllers/summary.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import + +import json + +import cherrypy + +from ..tools import AuthRequired, ApiController, BaseController +from ..services.ceph_service import CephService + + +@ApiController('summary') +@AuthRequired() +class Summary(BaseController): + def _rbd_pool_data(self): + pool_names = [pool['pool_name'] for pool in CephService.get_pool_list('rbd')] + return sorted(pool_names) + + def _health_status(self): + health_data = self.mgr.get("health") + return json.loads(health_data["json"])['status'] + + def _filesystems(self): + fsmap = self.mgr.get("fs_map") + return [ + { + "id": f['id'], + "name": f['mdsmap']['fs_name'] + } + for f in fsmap['filesystems'] + ] + + @cherrypy.expose + @cherrypy.tools.json_out() + def default(self): + return { + 'rbd_pools': self._rbd_pool_data(), + 'health_status': self._health_status(), + 'filesystems': self._filesystems(), + 'mgr_id': self.mgr.get_mgr_id(), + 'have_mon_connection': self.mgr.have_mon_connection() + } 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 6b33769a2f4a..1b7d6dfb2f16 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 @@ -32,7 +32,7 @@ + [ngStyle]="summaryData?.health_status | healthColor"> Dashboard @@ -129,14 +129,14 @@ class="dropdown-menu">
  • + *ngFor="let fs of summaryData?.filesystems"> {{ fs.name }}
  • + *ngIf="summaryData.filesystems.length === 0"> There are no filesystems
  • diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/core/navigation/navigation/navigation.component.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/core/navigation/navigation/navigation.component.ts index 37fae9d9e747..70087338dade 100644 --- a/src/pybind/mgr/dashboard_v2/frontend/src/app/core/navigation/navigation/navigation.component.ts +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/core/navigation/navigation/navigation.component.ts @@ -1,5 +1,5 @@ import { Component, OnInit } from '@angular/core'; -import { TopLevelService } from '../../../shared/services/top-level.service'; +import { SummaryService } from '../../../shared/services/summary.service'; @Component({ selector: 'cd-navigation', @@ -7,14 +7,14 @@ import { TopLevelService } from '../../../shared/services/top-level.service'; styleUrls: ['./navigation.component.scss'] }) export class NavigationComponent implements OnInit { - topLevelData: any; + summaryData: any; rbdPools: Array = []; - constructor(private topLevelService: TopLevelService) {} + constructor(private summaryService: SummaryService) {} ngOnInit() { - this.topLevelService.topLevelData$.subscribe((data: any) => { - this.topLevelData = data; + this.summaryService.summaryData$.subscribe((data: any) => { + this.summaryData = data; this.rbdPools = data.rbd_pools; }); } diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/services/services.module.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/services/services.module.ts index 2901b4b90e61..051f970ac6d4 100644 --- a/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/services/services.module.ts +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/services/services.module.ts @@ -3,14 +3,14 @@ import { NgModule } from '@angular/core'; import { ConfigurationService } from './configuration.service'; import { FormatterService } from './formatter.service'; +import { SummaryService } from './summary.service'; import { TcmuIscsiService } from './tcmu-iscsi.service'; -import { TopLevelService } from './top-level.service'; @NgModule({ imports: [ CommonModule ], declarations: [], - providers: [FormatterService, TopLevelService, TcmuIscsiService, ConfigurationService] + providers: [FormatterService, SummaryService, TcmuIscsiService, ConfigurationService] }) export class ServicesModule { } diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/services/summary.service.spec.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/services/summary.service.spec.ts new file mode 100644 index 000000000000..23af9836a147 --- /dev/null +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/services/summary.service.spec.ts @@ -0,0 +1,21 @@ +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { inject, TestBed } from '@angular/core/testing'; + +import { SharedModule } from '../shared.module'; +import { SummaryService } from './summary.service'; + +describe('SummaryService', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [SummaryService], + imports: [HttpClientTestingModule, SharedModule] + }); + }); + + it( + 'should be created', + inject([SummaryService], (service: SummaryService) => { + expect(service).toBeTruthy(); + }) + ); +}); diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/services/summary.service.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/services/summary.service.ts new file mode 100644 index 000000000000..0bc4566b43d4 --- /dev/null +++ b/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/services/summary.service.ts @@ -0,0 +1,31 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; + +import { Subject } from 'rxjs/Subject'; + +import { AuthStorageService } from './auth-storage.service'; + +@Injectable() +export class SummaryService { + // Observable sources + private summaryDataSource = new Subject(); + + // Observable streams + summaryData$ = this.summaryDataSource.asObservable(); + + constructor(private http: HttpClient, private authStorageService: AuthStorageService) { + this.refresh(); + } + + refresh() { + if (this.authStorageService.isLoggedIn()) { + this.http.get('/api/summary').subscribe(data => { + this.summaryDataSource.next(data); + }); + } + + setTimeout(() => { + this.refresh(); + }, 5000); + } +} diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/services/top-level.service.spec.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/services/top-level.service.spec.ts deleted file mode 100644 index 3962cb62b1f3..000000000000 --- a/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/services/top-level.service.spec.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { inject, TestBed } from '@angular/core/testing'; - -import { SharedModule } from '../shared.module'; -import { TopLevelService } from './top-level.service'; - -describe('TopLevelService', () => { - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [TopLevelService], - imports: [HttpClientTestingModule, SharedModule] - }); - }); - - it( - 'should be created', - inject([TopLevelService], (service: TopLevelService) => { - expect(service).toBeTruthy(); - }) - ); -}); diff --git a/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/services/top-level.service.ts b/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/services/top-level.service.ts deleted file mode 100644 index 5df5ee927570..000000000000 --- a/src/pybind/mgr/dashboard_v2/frontend/src/app/shared/services/top-level.service.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { HttpClient } from '@angular/common/http'; -import { Injectable } from '@angular/core'; - -import { Subject } from 'rxjs/Subject'; - -import { AuthStorageService } from './auth-storage.service'; - -@Injectable() -export class TopLevelService { - // Observable sources - private topLevelDataSource = new Subject(); - - // Observable streams - topLevelData$ = this.topLevelDataSource.asObservable(); - - constructor(private http: HttpClient, private authStorageService: AuthStorageService) { - this.refresh(); - } - - refresh() { - if (this.authStorageService.isLoggedIn()) { - this.http.get('/api/dashboard/toplevel').subscribe(data => { - this.topLevelDataSource.next(data); - }); - } - - setTimeout(() => { - this.refresh(); - }, 5000); - } -} diff --git a/src/pybind/mgr/dashboard_v2/tests/test_dashboard.py b/src/pybind/mgr/dashboard_v2/tests/test_dashboard.py index 739cb24bf8d5..833ebd542a96 100644 --- a/src/pybind/mgr/dashboard_v2/tests/test_dashboard.py +++ b/src/pybind/mgr/dashboard_v2/tests/test_dashboard.py @@ -6,18 +6,6 @@ from .helper import ControllerTestCase, authenticate class DashboardTest(ControllerTestCase): - @authenticate - def test_toplevel(self): - data = self._get("/api/dashboard/toplevel") - self.assertStatus(200) - - self.assertIn('filesystems', data) - self.assertIn('health_status', data) - self.assertIn('rbd_pools', data) - self.assertIsNotNone(data['filesystems']) - self.assertIsNotNone(data['health_status']) - self.assertIsNotNone(data['rbd_pools']) - @authenticate def test_health(self): data = self._get("/api/dashboard/health") diff --git a/src/pybind/mgr/dashboard_v2/tests/test_summary.py b/src/pybind/mgr/dashboard_v2/tests/test_summary.py new file mode 100644 index 000000000000..91a9f7a34df0 --- /dev/null +++ b/src/pybind/mgr/dashboard_v2/tests/test_summary.py @@ -0,0 +1,20 @@ +from dashboard_v2.tests.helper import ControllerTestCase, authenticate + + +class SummaryTest(ControllerTestCase): + + @authenticate + def test_summary(self): + data = self._get("/api/summary") + self.assertStatus(200) + + self.assertIn('filesystems', data) + self.assertIn('health_status', data) + self.assertIn('rbd_pools', data) + self.assertIn('mgr_id', data) + self.assertIn('have_mon_connection', data) + self.assertIsNotNone(data['filesystems']) + self.assertIsNotNone(data['health_status']) + self.assertIsNotNone(data['rbd_pools']) + self.assertIsNotNone(data['mgr_id']) + self.assertIsNotNone(data['have_mon_connection'])