From fc571f37b68dbb861556113aa52b926efdcd77da Mon Sep 17 00:00:00 2001 From: Kanika Murarka Date: Thu, 4 Oct 2018 20:59:14 +0530 Subject: [PATCH] mgr/dashboard: Adding grafana component and backend changes Fixes: https://tracker.ceph.com/issues/24999 Signed-off-by: Kanika Murarka --- .../app/shared/api/settings.service.spec.ts | 34 ++++++++ .../src/app/shared/api/settings.service.ts | 15 ++++ .../shared/components/components.module.ts | 11 ++- .../components/grafana/grafana.component.html | 42 +++++++++ .../components/grafana/grafana.component.scss | 33 +++++++ .../grafana/grafana.component.spec.ts | 32 +++++++ .../components/grafana/grafana.component.ts | 85 +++++++++++++++++++ src/pybind/mgr/dashboard/settings.py | 2 +- 8 files changed, 250 insertions(+), 4 deletions(-) create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/shared/api/settings.service.spec.ts create mode 100755 src/pybind/mgr/dashboard/frontend/src/app/shared/api/settings.service.ts create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.html create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.scss create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.spec.ts create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.ts diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/settings.service.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/settings.service.spec.ts new file mode 100644 index 00000000000..ef96ac1e4b2 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/settings.service.spec.ts @@ -0,0 +1,34 @@ +import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; +import { TestBed } from '@angular/core/testing'; + +import { configureTestBed } from '../../../testing/unit-test-helper'; +import { SettingsService } from './settings.service'; + +describe('SettingsService', () => { + let service: SettingsService; + let httpTesting: HttpTestingController; + + configureTestBed({ + providers: [SettingsService], + imports: [HttpClientTestingModule] + }); + + beforeEach(() => { + service = TestBed.get(SettingsService); + httpTesting = TestBed.get(HttpTestingController); + }); + + afterEach(() => { + httpTesting.verify(); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); + + it('should get protocol', () => { + service.getGrafanaApiUrl().subscribe(); + const req = httpTesting.expectOne('api/settings/GRAFANA_API_URL'); + expect(req.request.method).toBe('GET'); + }); +}); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/settings.service.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/settings.service.ts new file mode 100755 index 00000000000..db52c968ba5 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/settings.service.ts @@ -0,0 +1,15 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; + +import { ApiModule } from './api.module'; + +@Injectable({ + providedIn: ApiModule +}) +export class SettingsService { + constructor(private http: HttpClient) {} + + getGrafanaApiUrl() { + return this.http.get('api/settings/GRAFANA_API_URL'); + } +} diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/components.module.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/components.module.ts index 6d1376b1a2a..c280f4c9e73 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/components.module.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/components.module.ts @@ -4,12 +4,14 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { ChartsModule } from 'ng2-charts/ng2-charts'; import { AlertModule, ModalModule, PopoverModule, TooltipModule } from 'ngx-bootstrap'; +import { BsDropdownModule } from 'ngx-bootstrap/dropdown'; import { DirectivesModule } from '../directives/directives.module'; import { PipesModule } from '../pipes/pipes.module'; import { ConfirmationModalComponent } from './confirmation-modal/confirmation-modal.component'; import { DeletionModalComponent } from './deletion-modal/deletion-modal.component'; import { ErrorPanelComponent } from './error-panel/error-panel.component'; +import { GrafanaComponent } from './grafana/grafana.component'; import { HelperComponent } from './helper/helper.component'; import { InfoPanelComponent } from './info-panel/info-panel.component'; import { LoadingPanelComponent } from './loading-panel/loading-panel.component'; @@ -33,7 +35,8 @@ import { WarningPanelComponent } from './warning-panel/warning-panel.component'; ReactiveFormsModule, PipesModule, ModalModule.forRoot(), - DirectivesModule + DirectivesModule, + BsDropdownModule ], declarations: [ ViewCacheComponent, @@ -48,7 +51,8 @@ import { WarningPanelComponent } from './warning-panel/warning-panel.component'; ModalComponent, DeletionModalComponent, ConfirmationModalComponent, - WarningPanelComponent + WarningPanelComponent, + GrafanaComponent ], providers: [], exports: [ @@ -62,7 +66,8 @@ import { WarningPanelComponent } from './warning-panel/warning-panel.component'; InfoPanelComponent, UsageBarComponent, ModalComponent, - WarningPanelComponent + WarningPanelComponent, + GrafanaComponent ], entryComponents: [ModalComponent, DeletionModalComponent, ConfirmationModalComponent] }) diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.html b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.html new file mode 100644 index 00000000000..34ff02c737a --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.html @@ -0,0 +1,42 @@ + + + Loading panel data... + + + + Please consult the documentation on how to configure and enable the monitoring functionality. + + +
+
+
+ + +
+
+ +
+
+
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.scss b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.scss new file mode 100644 index 00000000000..fa054f6bfe3 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.scss @@ -0,0 +1,33 @@ +.grafana { + width: 100%; + height: 600px; + z-index: 0; +} + +.grafana_one { + height: 400px; +} + +.grafana_two { + height: 750px; +} + +.grafana_three { + height: 900px; +} + +button { + margin-bottom: 10px; + margin-left: 10px; + float: right; + i { + font-size: 14px; + padding: 2px; + } +} + +.dropdown-menu { + top: 20px; + right: 20px; + left: auto; +} diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.spec.ts new file mode 100644 index 00000000000..18ac00823a5 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.spec.ts @@ -0,0 +1,32 @@ +import { HttpClientModule } from '@angular/common/http'; + +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AlertModule } from 'ngx-bootstrap'; + +import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { SettingsService } from '../../../shared/api/settings.service'; +import { InfoPanelComponent } from '../info-panel/info-panel.component'; +import { LoadingPanelComponent } from '../loading-panel/loading-panel.component'; +import { GrafanaComponent } from './grafana.component'; + +describe('GrafanaComponent', () => { + let component: GrafanaComponent; + let fixture: ComponentFixture; + + configureTestBed({ + declarations: [GrafanaComponent, InfoPanelComponent, LoadingPanelComponent], + imports: [AlertModule.forRoot(), HttpClientModule], + providers: [SettingsService] + }); + + beforeEach(() => { + fixture = TestBed.createComponent(GrafanaComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.ts new file mode 100644 index 00000000000..d71c3780dac --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.ts @@ -0,0 +1,85 @@ +import { Component, Input, OnChanges, OnInit } from '@angular/core'; + +import { DomSanitizer } from '@angular/platform-browser'; +import { SafeUrl } from '@angular/platform-browser'; + +import { SettingsService } from '../../../shared/api/settings.service'; + +@Component({ + selector: 'cd-grafana', + templateUrl: './grafana.component.html', + styleUrls: ['./grafana.component.scss'] +}) +export class GrafanaComponent implements OnInit, OnChanges { + grafanaSrc: SafeUrl; + url: string; + protocol: string; + host: string; + dashboardPath: string; + port: number; + baseUrl: any; + panelStyle: any; + grafanaExist = false; + mode = '&kiosk'; + modeFlag = false; + modeText = 'Change time selection'; + loading = true; + styles = {}; + + @Input() + grafanaPath: string; + @Input() + grafanaStyle: string; + grafanaUrl: any; + + constructor(private sanitizer: DomSanitizer, private settingsService: SettingsService) {} + + ngOnInit() { + this.styles = { + one: 'grafana_one', + two: 'grafana_two', + three: 'grafana_three' + }; + this.settingsService.getGrafanaApiUrl().subscribe((data: any) => { + this.grafanaUrl = data.value; + if (this.grafanaUrl === '') { + this.grafanaExist = false; + return; + } else { + this.getFrame(); + } + }); + this.panelStyle = this.styles[this.grafanaStyle]; + } + + getFrame() { + this.baseUrl = this.grafanaUrl + '/d/'; + this.grafanaExist = true; + this.loading = false; + this.url = this.baseUrl + this.grafanaPath + '&refresh=2s' + this.mode; + this.grafanaSrc = this.sanitizer.bypassSecurityTrustResourceUrl(this.url); + } + + timePickerToggle() { + this.modeFlag = true; + this.mode = this.mode ? '' : '&kiosk'; + if (this.modeText === 'Return to default') { + this.modeText = 'Change time selection'; + this.reset(); + } else { + this.modeText = 'Return to default'; + } + this.getFrame(); + this.modeFlag = false; + } + + reset() { + this.mode = '&kiosk'; + this.modeText = 'Change time selection'; + this.getFrame(); + } + + ngOnChanges(changes) { + this.getFrame(); + } +} diff --git a/src/pybind/mgr/dashboard/settings.py b/src/pybind/mgr/dashboard/settings.py index 1b6d5d014e8..c28e31d11ab 100644 --- a/src/pybind/mgr/dashboard/settings.py +++ b/src/pybind/mgr/dashboard/settings.py @@ -32,7 +32,7 @@ class Options(object): RGW_API_SSL_VERIFY = (True, bool) # Grafana settings - GRAFANA_API_URL = ('http://localhost:3000', str) + GRAFANA_API_URL = ('', str) GRAFANA_API_USERNAME = ('admin', str) GRAFANA_API_PASSWORD = ('admin', str) GRAFANA_API_TOKEN = ('', str) -- 2.39.5