]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: Replace Replica size and Erasure code profile with a single column 38125/head
authorAlfonso Martínez <almartin@redhat.com>
Wed, 2 Dec 2020 12:53:34 +0000 (13:53 +0100)
committerAvan Thakkar <athakkar@redhat.com>
Wed, 9 Dec 2020 13:14:18 +0000 (18:44 +0530)
Replaces Type, Replica Size & Erasure Coded Profile columns
with 'Data Protection' column. Hidden Crush Rule set column in case if any
admin finds it useful to show it can still be done by removing isHidden: true line.

Fixes: https://tracker.ceph.com/issues/47901
Signed-off-by: Avan Thakkar <athakkar@redhat.com>
Signed-off-by: Alfonso Martínez <almartin@redhat.com>
src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-details/pool-details.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-list/pool-list.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-list/pool-list.component.ts
src/pybind/mgr/dashboard/frontend/src/styles.scss
src/pybind/mgr/dashboard/frontend/src/testing/unit-test-helper.ts

index 72871636adcc77f6bceefd399f1cb0cf5d026d56..f30f954b5b65210c36f34b8718be135012d38792 100644 (file)
@@ -129,7 +129,8 @@ describe('PoolDetailsComponent', () => {
               pg_placement_num_target: 256,
               pool: 2,
               pool_name: 'somePool',
-              type: 'replicated'
+              type: 'replicated',
+              size: 3
             }
           },
           Mocks.getPool('somePool', 2)
index f7f8141255c9a4053c70bd9239852ef588095ff3..8a8af7b73494f354f74cd81605b4dce53beaf680 100644 (file)
@@ -11,8 +11,10 @@ import { of } from 'rxjs';
 import { RbdConfigurationListComponent } from '~/app/ceph/block/rbd-configuration-list/rbd-configuration-list.component';
 import { PgCategoryService } from '~/app/ceph/shared/pg-category.service';
 import { ConfigurationService } from '~/app/shared/api/configuration.service';
+import { ErasureCodeProfileService } from '~/app/shared/api/erasure-code-profile.service';
 import { PoolService } from '~/app/shared/api/pool.service';
 import { CriticalConfirmationModalComponent } from '~/app/shared/components/critical-confirmation-modal/critical-confirmation-modal.component';
+import { ErasureCodeProfile } from '~/app/shared/models/erasure-code-profile';
 import { ExecutingTask } from '~/app/shared/models/executing-task';
 import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
 import { ModalService } from '~/app/shared/services/modal.service';
@@ -28,10 +30,19 @@ describe('PoolListComponent', () => {
   let component: PoolListComponent;
   let fixture: ComponentFixture<PoolListComponent>;
   let poolService: PoolService;
+  let getECPList: jasmine.Spy;
 
   const getPoolList = (): Pool[] => {
     return [Mocks.getPool('a', 0), Mocks.getPool('b', 1), Mocks.getPool('c', 2)];
   };
+  const getECPProfiles = (): ErasureCodeProfile[] => {
+    const ecpProfile = new ErasureCodeProfile();
+    ecpProfile.name = 'default';
+    ecpProfile.k = 2;
+    ecpProfile.m = 1;
+
+    return [ecpProfile];
+  };
 
   configureTestBed({
     declarations: [PoolListComponent, PoolDetailsComponent, RbdConfigurationListComponent],
@@ -52,6 +63,8 @@ describe('PoolListComponent', () => {
     component.permissions.pool.read = true;
     poolService = TestBed.inject(PoolService);
     spyOn(poolService, 'getList').and.callFake(() => of(getPoolList()));
+    getECPList = spyOn(TestBed.inject(ErasureCodeProfileService), 'list');
+    getECPList.and.returnValue(of(getECPProfiles()));
     fixture.detectChanges();
   });
 
@@ -305,7 +318,8 @@ describe('PoolListComponent', () => {
             wr: { latest: 0, rate: 0, rates: [] },
             wr_bytes: { latest: 0, rate: 0, rates: [] }
           },
-          usage: 0
+          usage: 0,
+          data_protection: 'replica: ×3'
         }),
         o
       )
@@ -315,7 +329,7 @@ describe('PoolListComponent', () => {
       pool = Mocks.getPool('a', 0);
     });
 
-    it('transforms pools data correctly', () => {
+    it('transforms replicated pools data correctly', () => {
       pool = _.merge(pool, {
         stats: {
           bytes_used: { latest: 5, rate: 0, rates: [] },
@@ -341,7 +355,22 @@ describe('PoolListComponent', () => {
             percent_used: { latest: 0.25, rate: 0, rates: [] },
             rd_bytes: { latest: 6, rate: 4, rates: [2, 6] }
           },
-          usage: 0.25
+          usage: 0.25,
+          data_protection: 'replica: ×3'
+        })
+      );
+    });
+
+    it('transforms erasure pools data correctly', () => {
+      pool.type = 'erasure';
+      pool.erasure_code_profile = 'default';
+      component.ecProfileList = getECPProfiles();
+
+      expect(component.transformPoolsData([pool])).toEqual(
+        getPoolData({
+          type: 'erasure',
+          erasure_code_profile: 'default',
+          data_protection: 'EC: 2+1'
         })
       );
     });
@@ -370,7 +399,8 @@ describe('PoolListComponent', () => {
           pg_num: 32,
           pg_num_target: 16,
           pg_placement_num: 32,
-          pg_placement_num_target: 16
+          pg_placement_num_target: 16,
+          data_protection: 'replica: ×3'
         })
       );
     });
@@ -391,7 +421,8 @@ describe('PoolListComponent', () => {
           pg_num: 32,
           pg_num_target: 16,
           pg_placement_num: 32,
-          pg_placement_num_target: 16
+          pg_placement_num_target: 16,
+          data_protection: 'replica: ×3'
         })
       );
     });
index 24773c2f28828ce02137dd1e8c958b319fcbe7c2..ba2d9cbe521b1399ffb459695a7fecc2ac2f4519 100644 (file)
@@ -1,9 +1,11 @@
 import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
 
 import _ from 'lodash';
+import { mergeMap } from 'rxjs/operators';
 
 import { PgCategoryService } from '~/app/ceph/shared/pg-category.service';
 import { ConfigurationService } from '~/app/shared/api/configuration.service';
+import { ErasureCodeProfileService } from '~/app/shared/api/erasure-code-profile.service';
 import { PoolService } from '~/app/shared/api/pool.service';
 import { ListWithDetails } from '~/app/shared/classes/list-with-details.class';
 import { TableStatusViewCache } from '~/app/shared/classes/table-status-view-cache';
@@ -16,6 +18,7 @@ import { ViewCacheStatus } from '~/app/shared/enum/view-cache-status.enum';
 import { CdTableAction } from '~/app/shared/models/cd-table-action';
 import { CdTableColumn } from '~/app/shared/models/cd-table-column';
 import { CdTableSelection } from '~/app/shared/models/cd-table-selection';
+import { ErasureCodeProfile } from '~/app/shared/models/erasure-code-profile';
 import { ExecutingTask } from '~/app/shared/models/executing-task';
 import { FinishedTask } from '~/app/shared/models/finished-task';
 import { Permissions } from '~/app/shared/models/permissions';
@@ -57,10 +60,12 @@ export class PoolListComponent extends ListWithDetails implements OnInit {
   tableStatus = new TableStatusViewCache();
   cacheTiers: any[] = [];
   monAllowPoolDelete = false;
+  ecProfileList: ErasureCodeProfile[];
 
   constructor(
     private poolService: PoolService,
     private taskWrapper: TaskWrapperService,
+    private ecpService: ErasureCodeProfileService,
     private authStorageService: AuthStorageService,
     public taskListService: TaskListService,
     private modalService: ModalService,
@@ -120,44 +125,42 @@ export class PoolListComponent extends ListWithDetails implements OnInit {
         cellTransformation: CellTemplate.executing
       },
       {
-        prop: 'type',
-        name: $localize`Type`,
-        flexGrow: 2
+        prop: 'data_protection',
+        name: $localize`Data Protection`,
+        cellTransformation: CellTemplate.badge,
+        customTemplateConfig: {
+          class: 'badge-background-gray'
+        },
+        flexGrow: 1.3
       },
       {
         prop: 'application_metadata',
         name: $localize`Applications`,
-        flexGrow: 3
+        cellTransformation: CellTemplate.badge,
+        customTemplateConfig: {
+          class: 'badge-background-primary'
+        },
+        flexGrow: 1.5
       },
       {
         prop: 'pg_status',
         name: $localize`PG Status`,
-        flexGrow: 3,
+        flexGrow: 1.2,
         cellClass: ({ row, column, value }): any => {
           return this.getPgStatusCellClass(row, column, value);
         }
       },
-      {
-        prop: 'size',
-        name: $localize`Replica Size`,
-        flexGrow: 2,
-        cellClass: 'text-right'
-      },
-      {
-        prop: 'erasure_code_profile',
-        name: $localize`Erasure Coded Profile`,
-        flexGrow: 2
-      },
       {
         prop: 'crush_rule',
         name: $localize`Crush Ruleset`,
-        flexGrow: 3
+        isHidden: true,
+        flexGrow: 2
       },
       {
         name: $localize`Usage`,
         prop: 'usage',
         cellTemplate: this.poolUsageTpl,
-        flexGrow: 3
+        flexGrow: 1.2
       },
       {
         prop: 'stats.rd_bytes.rates',
@@ -165,7 +168,7 @@ export class PoolListComponent extends ListWithDetails implements OnInit {
         comparator: (_valueA: any, _valueB: any, rowA: Pool, rowB: Pool) =>
           compare('stats.rd_bytes.latest', rowA, rowB),
         cellTransformation: CellTemplate.sparkline,
-        flexGrow: 3
+        flexGrow: 1.5
       },
       {
         prop: 'stats.wr_bytes.rates',
@@ -173,7 +176,7 @@ export class PoolListComponent extends ListWithDetails implements OnInit {
         comparator: (_valueA: any, _valueB: any, rowA: Pool, rowB: Pool) =>
           compare('stats.wr_bytes.latest', rowA, rowB),
         cellTransformation: CellTemplate.sparkline,
-        flexGrow: 3
+        flexGrow: 1.5
       },
       {
         prop: 'stats.rd.rate',
@@ -192,7 +195,13 @@ export class PoolListComponent extends ListWithDetails implements OnInit {
     ];
 
     this.taskListService.init(
-      () => this.poolService.getList(),
+      () =>
+        this.ecpService.list().pipe(
+          mergeMap((ecProfileList: ErasureCodeProfile[]) => {
+            this.ecProfileList = ecProfileList;
+            return this.poolService.getList();
+          })
+        ),
       undefined,
       (pools) => {
         this.pools = this.transformPoolsData(pools);
@@ -232,6 +241,16 @@ export class PoolListComponent extends ListWithDetails implements OnInit {
     };
   }
 
+  getErasureCodeProfile(erasureCodeProfile: string) {
+    let ecpInfo = '';
+    _.forEach(this.ecProfileList, (ecpKey) => {
+      if (ecpKey['name'] === erasureCodeProfile) {
+        ecpInfo = `EC: ${ecpKey['k']}+${ecpKey['m']}`;
+      }
+    });
+    return ecpInfo;
+  }
+
   transformPoolsData(pools: any) {
     const requiredStats = [
       'bytes_used',
@@ -265,6 +284,14 @@ export class PoolListComponent extends ListWithDetails implements OnInit {
         pool.stats[stat].rates = pool.stats[stat].rates.map((point: any) => point[1]);
       });
       pool.cdIsBinary = true;
+
+      if (pool['type'] === 'erasure') {
+        const erasureCodeProfile = pool['erasure_code_profile'];
+        pool['data_protection'] = this.getErasureCodeProfile(erasureCodeProfile);
+      }
+      if (pool['type'] === 'replicated') {
+        pool['data_protection'] = `replica: ×${pool['size']}`;
+      }
     });
 
     return pools;
index 7d3538f5bf573c2d3c1ac375b74d35abda2b47ea..b4dcf0e431eb857fecbc85cdde418dff8d570197 100644 (file)
@@ -88,11 +88,13 @@ $grid-breakpoints: (
 }
 
 // Custom badges.
+.badge-background-gray,
 .badge-hdd {
   background-color: $gray-600;
   color: $white;
 }
 
+.badge-background-primary,
 .badge-ssd {
   background-color: $primary;
   color: $white;
index 28f88e1fac86cd9f131aecdf9df92cb87bf90b00..3e3d27a7ce64158096840804abc58c3e46ec8643 100644 (file)
@@ -404,7 +404,8 @@ export class Mocks {
       pg_num: 256,
       pg_placement_num: 256,
       pg_num_target: 256,
-      pg_placement_num_target: 256
+      pg_placement_num_target: 256,
+      size: 3
     });
   };