]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: Adding grafana component and backend changes
authorKanika Murarka <kmurarka@redhat.com>
Thu, 4 Oct 2018 15:29:14 +0000 (20:59 +0530)
committerKanika Murarka <kmurarka@redhat.com>
Thu, 4 Oct 2018 15:29:14 +0000 (20:59 +0530)
Fixes: https://tracker.ceph.com/issues/24999
Signed-off-by: Kanika Murarka <kmurarka@redhat.com>
src/pybind/mgr/dashboard/frontend/src/app/shared/api/settings.service.spec.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/shared/api/settings.service.ts [new file with mode: 0755]
src/pybind/mgr/dashboard/frontend/src/app/shared/components/components.module.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.html [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.scss [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.spec.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/settings.py

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 (file)
index 0000000..ef96ac1
--- /dev/null
@@ -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 (executable)
index 0000000..db52c96
--- /dev/null
@@ -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');
+  }
+}
index 6d1376b1a2a02269c37ebe236a0f3f73fd2d631c..c280f4c9e7331a8ef028385f649d58ccb88b0ae6 100644 (file)
@@ -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 (file)
index 0000000..34ff02c
--- /dev/null
@@ -0,0 +1,42 @@
+<!-- Embed dashboard -->
+<cd-loading-panel *ngIf="loading && grafanaExist"
+                  i18n>
+  Loading panel data...
+</cd-loading-panel>
+<cd-info-panel *ngIf="!grafanaExist">
+  <ng-container i18n>
+    Please consult the <a href="http://docs.ceph.com/docs/luminous/mgr/dashboard/" target="_blank">documentation</a> on how to configure and enable the monitoring functionality.
+  </ng-container>
+</cd-info-panel>
+<div class="row" *ngIf="grafanaExist">
+  <div class="col-md-12">
+    <div dropdown>
+      <button dropdownToggle
+              class="btn btn-sm dropdown-toggle"
+              data-toggle="dropdown"
+              title="Advanced Settings">
+        <i class="fa fa-cog"></i>
+        <span class="caret"></span>
+      </button>
+      <ul *dropdownMenu
+          class="dropdown-menu">
+        <li>
+          <a i18n
+             class="dropdown-item"
+             (click)="timePickerToggle()">{{ modeText }}
+          </a>
+        </li>
+      </ul>
+    </div>
+    <div class="grafana-container">
+      <iframe #iframe
+              id="iframe"
+              [src]="grafanaSrc"
+              class="grafana"
+              [ngClass]="panelStyle"
+              frameborder="0"
+              scrolling="no">
+      </iframe>
+    </div>
+  </div>
+</div>
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 (file)
index 0000000..fa054f6
--- /dev/null
@@ -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 (file)
index 0000000..18ac008
--- /dev/null
@@ -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<GrafanaComponent>;
+
+  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 (file)
index 0000000..d71c378
--- /dev/null
@@ -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();
+  }
+}
index 1b6d5d014e821da41bce119a4b186cfc67432f7b..c28e31d11ab86d8ad56baef2e59244917132bce3 100644 (file)
@@ -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)