]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: Add pool listing 21353/head
authorStephan Müller <smueller@suse.com>
Fri, 13 Apr 2018 15:43:18 +0000 (17:43 +0200)
committerStephan Müller <smueller@suse.com>
Fri, 20 Apr 2018 14:13:34 +0000 (16:13 +0200)
Adds a new top level menu entry, called "Pool", which lists all pools
and contains a minimalistic detail view.

Signed-off-by: Stephan Müller <smueller@suse.com>
qa/tasks/mgr/dashboard/test_pool.py
src/pybind/mgr/dashboard/controllers/pool.py
src/pybind/mgr/dashboard/frontend/src/app/app-routing.module.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/ceph.module.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-list/pool-list.component.html [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-list/pool-list.component.scss [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-list/pool-list.component.spec.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-list/pool-list.component.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool.module.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/core/navigation/navigation/navigation.component.html
src/pybind/mgr/dashboard/frontend/src/app/shared/api/pool.service.ts

index d04fd2b0be0d52b6b550628b313281aacca3422f..bae49fc8b360d827e42184802e632f82e40fea80 100644 (file)
@@ -31,6 +31,7 @@ class PoolTest(DashboardTestCase):
         for pool in data:
             self.assertIn('pool_name', pool)
             self.assertIn('type', pool)
+            self.assertIn('application_metadata', pool)
             self.assertIn('flags', pool)
             self.assertIn('flags_names', pool)
             self.assertNotIn('stats', pool)
@@ -61,6 +62,7 @@ class PoolTest(DashboardTestCase):
         for pool in data:
             self.assertIn('pool_name', pool)
             self.assertIn('type', pool)
+            self.assertIn('application_metadata', pool)
             self.assertIn('flags', pool)
             self.assertIn('stats', pool)
             self.assertIn('flags_names', pool)
@@ -93,7 +95,7 @@ class PoolTest(DashboardTestCase):
                         self.assertEqual(pool[k], int(v), '{}: {} != {}'.format(k, pool[k], v))
                     elif k == 'application_metadata':
                         self.assertEqual(pool[k],
-                                         {name: {} for name in data['application_metadata'].split(',')})
+                                         data['application_metadata'].split(','))
                     elif k == 'pool':
                         self.assertEqual(pool['pool_name'], v)
                     elif k in ['compression_mode', 'compression_algorithm',
index 6a8f605d02c08d60c6bd48567d90f4e168c28177..56f5c9a026b2a2264db8019764df8086d9b98de0 100644 (file)
@@ -27,6 +27,8 @@ class Pool(RESTController):
                 res[attr] = {1: 'replicated', 3: 'erasure'}[pool[attr]]
             elif attr == 'crush_rule':
                 res[attr] = crush_rules[pool[attr]]
+            elif attr == 'application_metadata':
+                res[attr] = pool[attr].keys()
             else:
                 res[attr] = pool[attr]
 
index 5c8e025abd99eeaf7177baddf0d9f84e772a72ba..f6b0ed126d2631dd4f80735af17a0cac03b35639 100644 (file)
@@ -15,6 +15,7 @@ import { DashboardComponent } from './ceph/dashboard/dashboard/dashboard.compone
 import {
   PerformanceCounterComponent
 } from './ceph/performance-counter/performance-counter/performance-counter.component';
+import { PoolListComponent } from './ceph/pool/pool-list/pool-list.component';
 import { RgwBucketListComponent } from './ceph/rgw/rgw-bucket-list/rgw-bucket-list.component';
 import { RgwDaemonListComponent } from './ceph/rgw/rgw-daemon-list/rgw-daemon-list.component';
 import { RgwUserListComponent } from './ceph/rgw/rgw-user-list/rgw-user-list.component';
@@ -47,6 +48,7 @@ const routes: Routes = [
   { path: 'block/rbd', component: RbdListComponent, canActivate: [AuthGuardService] },
   { path: 'rbd/add', component: RbdFormComponent, canActivate: [AuthGuardService] },
   { path: 'rbd/edit/:pool/:name', component: RbdFormComponent, canActivate: [AuthGuardService] },
+  { path: 'pool', component: PoolListComponent, canActivate: [AuthGuardService] },
   {
     path: 'perf_counters/:type/:id',
     component: PerformanceCounterComponent,
index 0f74b8234a6e9937e343362ab8b7a71f67cd32a4..add8458502cf90a672a70326e92f455e2db221a7 100644 (file)
@@ -7,6 +7,7 @@ import { CephfsModule } from './cephfs/cephfs.module';
 import { ClusterModule } from './cluster/cluster.module';
 import { DashboardModule } from './dashboard/dashboard.module';
 import { PerformanceCounterModule } from './performance-counter/performance-counter.module';
+import { PoolModule } from './pool/pool.module';
 import { RgwModule } from './rgw/rgw.module';
 
 @NgModule({
@@ -17,6 +18,7 @@ import { RgwModule } from './rgw/rgw.module';
     RgwModule,
     PerformanceCounterModule,
     BlockModule,
+    PoolModule,
     CephfsModule,
     SharedModule
   ],
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-list/pool-list.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-list/pool-list.component.html
new file mode 100644 (file)
index 0000000..5bda82e
--- /dev/null
@@ -0,0 +1,19 @@
+<nav aria-label="breadcrumb">
+  <ol class="breadcrumb">
+    <li class="breadcrumb-item active">Pools</li>
+  </ol>
+</nav>
+<cd-table [data]="pools"
+          (fetchData)="getPoolList()"
+          [columns]="columns"
+          selectionType="single"
+          (updateSelection)="updateSelection($event)">
+  <tabset cdTableDetail *ngIf="selection.hasSingleSelection">
+    <tab i18n-heading
+         heading="Details">
+      <cd-table-key-value [data]="selection.first()" [autoReload]="false">
+      </cd-table-key-value>
+    </tab>
+  </tabset>
+</cd-table>
+
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-list/pool-list.component.scss b/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-list/pool-list.component.scss
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-list/pool-list.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-list/pool-list.component.spec.ts
new file mode 100644 (file)
index 0000000..b5b32d5
--- /dev/null
@@ -0,0 +1,34 @@
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { TabsModule } from 'ngx-bootstrap/tabs/tabs.module';
+
+import { SharedModule } from '../../../shared/shared.module';
+import { PoolListComponent } from './pool-list.component';
+
+describe('PoolListComponent', () => {
+  let component: PoolListComponent;
+  let fixture: ComponentFixture<PoolListComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ PoolListComponent ],
+      imports: [
+        SharedModule,
+        TabsModule.forRoot(),
+        HttpClientTestingModule
+      ],
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(PoolListComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-list/pool-list.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-list/pool-list.component.ts
new file mode 100644 (file)
index 0000000..303eca2
--- /dev/null
@@ -0,0 +1,77 @@
+import { Component } from '@angular/core';
+
+import { PoolService } from '../../../shared/api/pool.service';
+import { CdTableColumn } from '../../../shared/models/cd-table-column';
+import { CdTableSelection } from '../../../shared/models/cd-table-selection';
+
+@Component({
+  selector: 'cd-pool-list',
+  templateUrl: './pool-list.component.html',
+  styleUrls: ['./pool-list.component.scss']
+})
+export class PoolListComponent {
+  pools = [];
+  columns: CdTableColumn[];
+  selection = new CdTableSelection();
+
+  constructor(
+    private poolService: PoolService,
+  ) {
+    this.columns = [
+      {
+        prop: 'pool_name',
+        name: 'Name',
+        flexGrow: 3
+      },
+      {
+        prop: 'type',
+        name: 'Type',
+        flexGrow: 2
+      },
+      {
+        prop: 'application_metadata',
+        name: 'Applications',
+        flexGrow: 3
+      },
+      {
+        prop: 'pg_placement_num',
+        name: 'Placement Groups',
+        flexGrow: 1,
+        cellClass: 'text-right'
+      },
+      {
+        prop: 'size',
+        name: 'Replica Size',
+        flexGrow: 1,
+        cellClass: 'text-right'
+      },
+      {
+        prop: 'last_change',
+        name: 'Last Change',
+        flexGrow: 1,
+        cellClass: 'text-right'
+      },
+      {
+        prop: 'erasure_code_profile',
+        name: 'Erasure Coded Profile',
+        flexGrow: 2
+      },
+      {
+        prop: 'crush_rule',
+        name: 'Crush Ruleset',
+        flexGrow: 2
+      }
+    ];
+  }
+
+  updateSelection(selection: CdTableSelection) {
+    this.selection = selection;
+  }
+
+  getPoolList() {
+    this.poolService.getList().subscribe((pools: any[]) => {
+      this.pools = pools;
+    });
+  }
+
+}
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool.module.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool.module.ts
new file mode 100644 (file)
index 0000000..bae60b5
--- /dev/null
@@ -0,0 +1,24 @@
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+
+import { TabsModule } from 'ngx-bootstrap/tabs';
+
+import { ServicesModule } from '../../shared/services/services.module';
+import { SharedModule } from '../../shared/shared.module';
+import { PoolListComponent } from './pool-list/pool-list.component';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    TabsModule,
+    SharedModule,
+    ServicesModule
+  ],
+  exports: [
+    PoolListComponent
+  ],
+  declarations: [
+    PoolListComponent
+  ]
+})
+export class PoolModule { }
index 54cde66a9075ce26a2ae0933a4024859e4498346..0a3d8fa5471f71e1970187ca19459ff01a4383c5 100644 (file)
         </ul>
       </li>
 
+      <!-- Pools -->
+      <li routerLinkActive="active"
+          class="tc_menuitem tc_menuitem_pool">
+        <a i18n
+           routerLink="/pool">Pool
+        </a>
+      </li>
+
       <!-- Block -->
       <li dropdown
           routerLinkActive="active"
index 96e9c8666c906401ed59e283b93cfa1cd65ada36..4a6da48a98770aefe5cc5cc077667c465fee5b36 100644 (file)
@@ -7,6 +7,10 @@ export class PoolService {
   constructor(private http: HttpClient) {
   }
 
+  getList () {
+    return this.http.get('api/pool');
+  }
+
   list(attrs = []) {
     const attrsStr = attrs.join(',');
     return this.http.get(`api/pool?attrs=${attrsStr}`).toPromise().then((resp: any) => {