]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: Clicking on a down OSD raises an error
authorPatrick Nawracay <pnawracay@suse.com>
Mon, 27 Aug 2018 13:23:48 +0000 (15:23 +0200)
committerPatrick Nawracay <pnawracay@suse.com>
Tue, 4 Sep 2018 06:27:03 +0000 (08:27 +0200)
Fixes: http://tracker.ceph.com/issues/24530
Signed-off-by: Patrick Nawracay <pnawracay@suse.com>
src/pybind/mgr/dashboard/controllers/osd.py
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-details/osd-details.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-details/osd-details.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-details/osd-details.component.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-list/osd-list.component.html
src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table/table.component.scss

index 3d30df83ed1e4cf061c03dff4cd62bb3a4b99265..f734092d6c385b579b85ec0f95457294403180d3 100644 (file)
@@ -4,7 +4,7 @@ from __future__ import absolute_import
 from . import ApiController, RESTController, UpdatePermission
 from .. import mgr, logger
 from ..security import Scope
-from ..services.ceph_service import CephService
+from ..services.ceph_service import CephService, SendCommandError
 from ..services.exception import handle_send_command_error
 from ..tools import str_to_bool
 
@@ -56,7 +56,21 @@ class Osd(RESTController):
 
     @handle_send_command_error('osd')
     def get(self, svc_id):
-        histogram = CephService.send_command('osd', srv_spec=svc_id, prefix='perf histogram dump')
+        """
+        Returns collected data about an OSD.
+
+        :return: Returns the requested data. The `histogram` key man contain a
+                 string with an error that occurred when the OSD is down.
+        """
+        try:
+            histogram = CephService.send_command('osd', srv_spec=svc_id,
+                                                 prefix='perf histogram dump')
+        except SendCommandError as e:
+            if 'osd down' in e.message:
+                histogram = e.message
+            else:
+                raise
+
         return {
             'osd_map': self.get_osd_map()[svc_id],
             'osd_metadata': mgr.get_metadata('osd', svc_id),
index c511d54e78c13f36b9dc821014a55227c92aea07..d5773faf446312017f4328c95cab2500412068e6 100644 (file)
     </cd-table-performance-counter>
   </tab>
   <tab heading="Histogram">
-    <h3 *ngIf="osd.loaded && osd.histogram_failed">
-      Histogram not available -> <span class="text-warning">{{ osd.histogram_failed }}</span>
-    </h3>
+    <cd-warning-panel i18n *ngIf="osd.loaded && osd.histogram_failed">
+      Histogram not available: {{ osd.histogram_failed }}
+    </cd-warning-panel>
+
     <div class="row" *ngIf="osd.loaded && osd.details.histogram">
       <div class="col-md-6">
         <h4>Writes</h4>
index a8d07224583c4f74761512cff1b63f9f4484e870..8146c6d1b301982c0656d0642bacb1f64e1cb2f2 100644 (file)
@@ -1,9 +1,13 @@
 import { HttpClientModule } from '@angular/common/http';
+import { DebugElement } from '@angular/core';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 
+import { of } from 'rxjs';
+
 import { TabsModule } from 'ngx-bootstrap';
 
 import { configureTestBed } from '../../../../../testing/unit-test-helper';
+import { OsdService } from '../../../../shared/api/osd.service';
 import { DataTableModule } from '../../../../shared/datatable/datatable.module';
 import { CdTableSelection } from '../../../../shared/models/cd-table-selection';
 import { SharedModule } from '../../../../shared/shared.module';
@@ -14,6 +18,9 @@ import { OsdDetailsComponent } from './osd-details.component';
 describe('OsdDetailsComponent', () => {
   let component: OsdDetailsComponent;
   let fixture: ComponentFixture<OsdDetailsComponent>;
+  let debugElement: DebugElement;
+  let osdService: OsdService;
+  let getDetailsSpy;
 
   configureTestBed({
     imports: [
@@ -23,7 +30,8 @@ describe('OsdDetailsComponent', () => {
       DataTableModule,
       SharedModule
     ],
-    declarations: [OsdDetailsComponent, OsdPerformanceHistogramComponent]
+    declarations: [OsdDetailsComponent, OsdPerformanceHistogramComponent],
+    providers: [OsdService]
   });
 
   beforeEach(() => {
@@ -31,6 +39,10 @@ describe('OsdDetailsComponent', () => {
     component = fixture.componentInstance;
 
     component.selection = new CdTableSelection();
+    debugElement = fixture.debugElement;
+    osdService = debugElement.injector.get(OsdService);
+
+    getDetailsSpy = spyOn(osdService, 'getDetails');
 
     fixture.detectChanges();
   });
@@ -38,4 +50,30 @@ describe('OsdDetailsComponent', () => {
   it('should create', () => {
     expect(component).toBeTruthy();
   });
+
+  it('should fail creating a histogram', () => {
+    const detailDataWithoutHistogram = {
+      osd_map: {},
+      osd_metadata: {},
+      histogram: 'osd down'
+    };
+    getDetailsSpy.and.returnValue(of(detailDataWithoutHistogram));
+    component.osd = { tree: { id: 0 } };
+    component.refresh();
+    expect(getDetailsSpy).toHaveBeenCalled();
+    expect(component.osd.histogram_failed).toBe('osd down');
+  });
+
+  it('should succeed creating a histogram', () => {
+    const detailDataWithHistogram = {
+      osd_map: {},
+      osd_metdata: {},
+      histogram: {}
+    };
+    getDetailsSpy.and.returnValue(of(detailDataWithHistogram));
+    component.osd = { tree: { id: 0 } };
+    component.refresh();
+    expect(getDetailsSpy).toHaveBeenCalled();
+    expect(component.osd.histogram_failed).toBe('');
+  });
 });
index f7b250f2c061835a92acc64eb6807e06ae44ec3f..08bf6e3f00187b7cc39bf656940e4771dc69c646 100644 (file)
@@ -34,6 +34,7 @@ export class OsdDetailsComponent implements OnChanges {
   refresh() {
     this.osdService.getDetails(this.osd.tree.id).subscribe((data: any) => {
       this.osd.details = data;
+      this.osd.histogram_failed = '';
       if (!_.isObject(data.histogram)) {
         this.osd.histogram_failed = data.histogram;
         this.osd.details.histogram = undefined;
index 6bff31d1f1468e1cb0fc51244658d9806d8b3a35..159bda03a29700361173af9d85fa7bafde76473f 100644 (file)
   </cd-osd-details>
 </cd-table>
 
-<ng-template #statusColor
-             let-value="value">
+<ng-template #statusColor let-value="value">
   <span *ngFor="let state of value; last as last">
-    <span [class.text-success]="'up' === state || 'in' === state"
-          [class.text-warning]="'down' === state || 'out' === state">
-      {{ state }}</span>
-    <span *ngIf="!last">, </span>
+    <span class="label"
+           [ngClass]="{'label-success': ['in', 'up'].includes(state), 'label-danger': ['down', 'out'].includes(state)}">{{ state }}</span>
+    <span *ngIf="!last">&nbsp;</span>
   </span>
 </ng-template>
 
index 5f916eb7fe2c165b26cf6d15c3d32b9b87daced4..05584f5bfe719649f0f0c620a76949021f2d0000 100644 (file)
       padding-bottom: 5px;
     }
     .datatable-body-row {
+      .label {
+        font-size: 0.9em;
+      }
       &.clickable:hover .datatable-row-group {
         background-color: $color-table-hover-row;
         transition-property: background;