]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: Pool delete
authorStephan Müller <smueller@suse.com>
Fri, 29 Jun 2018 12:18:46 +0000 (14:18 +0200)
committerStephan Müller <smueller@suse.com>
Tue, 9 Oct 2018 13:56:18 +0000 (15:56 +0200)
You can delete pools through the UI, this will generate a task that
deletes the pool in the background.

Fixes: https://tracker.ceph.com/issues/36355
Signed-off-by: Stephan Müller <smueller@suse.com>
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/app/shared/api/pool.service.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/api/pool.service.ts

index 4eae55d21cf6a13d76361a31850b3b768b88a9f1..94c0f51750d9d51df825454f4aad5becfa31f300 100644 (file)
@@ -2,9 +2,13 @@ import { HttpClientTestingModule } from '@angular/common/http/testing';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { RouterTestingModule } from '@angular/router/testing';
 
-import { TabsModule } from 'ngx-bootstrap/tabs/tabs.module';
+import { ToastModule } from 'ng2-toastr';
+import { BsModalService, TabsModule } from 'ngx-bootstrap';
 
 import { configureTestBed } from '../../../../testing/unit-test-helper';
+import { PoolService } from '../../../shared/api/pool.service';
+import { DeletionModalComponent } from '../../../shared/components/deletion-modal/deletion-modal.component';
+import { TaskWrapperService } from '../../../shared/services/task-wrapper.service';
 import { SharedModule } from '../../../shared/shared.module';
 import { PoolListComponent } from './pool-list.component';
 
@@ -14,7 +18,13 @@ describe('PoolListComponent', () => {
 
   configureTestBed({
     declarations: [PoolListComponent],
-    imports: [SharedModule, TabsModule.forRoot(), HttpClientTestingModule, RouterTestingModule]
+    imports: [
+      SharedModule,
+      ToastModule.forRoot(),
+      RouterTestingModule,
+      TabsModule.forRoot(),
+      HttpClientTestingModule
+    ]
   });
 
   beforeEach(() => {
@@ -26,4 +36,52 @@ describe('PoolListComponent', () => {
   it('should create', () => {
     expect(component).toBeTruthy();
   });
+
+  describe('pool deletion', () => {
+    let poolService: PoolService;
+    let taskWrapper: TaskWrapperService;
+
+    const setSelectedPool = (poolName: string) => {
+      component.selection.selected = [{ pool_name: poolName }];
+      component.selection.update();
+    };
+
+    const callDeletion = () => {
+      component.deletePoolModal();
+      const deletion: DeletionModalComponent = component.modalRef.content;
+      deletion.submitActionObservable();
+    };
+
+    const testPoolDeletion = (poolName) => {
+      setSelectedPool(poolName);
+      callDeletion();
+      expect(poolService.delete).toHaveBeenCalledWith(poolName);
+      expect(taskWrapper.wrapTaskAroundCall).toHaveBeenCalledWith({
+        task: {
+          name: 'pool/delete',
+          metadata: {
+            pool_name: poolName
+          }
+        },
+        call: undefined // because of stub
+      });
+    };
+
+    beforeEach(() => {
+      spyOn(TestBed.get(BsModalService), 'show').and.callFake((deletionClass, config) => {
+        return {
+          content: Object.assign(new deletionClass(), config.initialState)
+        };
+      });
+      poolService = TestBed.get(PoolService);
+      spyOn(poolService, 'delete').and.stub();
+      taskWrapper = TestBed.get(TaskWrapperService);
+      spyOn(taskWrapper, 'wrapTaskAroundCall').and.callThrough();
+    });
+
+    it('should pool deletion with two different pools', () => {
+      testPoolDeletion('somePoolName');
+      testPoolDeletion('aDifferentPoolName');
+    });
+  });
 });
index 6da0a6bfb6fad15adc99d78d5c5721e1c8d4c5fa..0e2562c2f44431eb03af9dcde9a5cac58061d62b 100644 (file)
@@ -1,9 +1,17 @@
 import { Component } from '@angular/core';
 
+import { BsModalRef, BsModalService } from 'ngx-bootstrap';
+
 import { PoolService } from '../../../shared/api/pool.service';
+import {
+  DeletionModalComponent
+} from '../../../shared/components/deletion-modal/deletion-modal.component';
 import { CdTableColumn } from '../../../shared/models/cd-table-column';
 import { CdTableFetchDataContext } from '../../../shared/models/cd-table-fetch-data-context';
 import { CdTableSelection } from '../../../shared/models/cd-table-selection';
+import { ExecutingTask } from '../../../shared/models/executing-task';
+import { FinishedTask } from '../../../shared/models/finished-task';
+import { TaskWrapperService } from '../../../shared/services/task-wrapper.service';
 import { Pool } from '../pool';
 
 @Component({
@@ -15,8 +23,14 @@ export class PoolListComponent {
   pools: Pool[] = [];
   columns: CdTableColumn[];
   selection = new CdTableSelection();
+  modalRef: BsModalRef;
+  executingTasks: ExecutingTask[] = [];
 
-  constructor(private poolService: PoolService) {
+  constructor(
+    private poolService: PoolService,
+    private taskWrapper: TaskWrapperService,
+    private modalService: BsModalService
+  ) {
     this.columns = [
       {
         prop: 'pool_name',
@@ -78,4 +92,18 @@ export class PoolListComponent {
       }
     );
   }
+
+  deletePoolModal() {
+    const name = this.selection.first().pool_name;
+    this.modalRef = this.modalService.show(DeletionModalComponent, {
+      initialState: {
+        itemDescription: 'Pool',
+        submitActionObservable: () =>
+          this.taskWrapper.wrapTaskAroundCall({
+            task: new FinishedTask('pool/delete', { pool_name: name }),
+            call: this.poolService.delete(name)
+          })
+      }
+    });
+  }
 }
index c0e4303c1d5b29e32161afd6c626c8613d94800e..afa5abff2cd6f5ebea3da4ebcdaf9c789f0c5b70 100644 (file)
@@ -54,6 +54,12 @@ describe('PoolService', () => {
     expect(req.request.body).toEqual({ application_metadata: [] });
   });
 
+  it('should call delete', () => {
+    service.delete('somePool').subscribe();
+    const req = httpTesting.expectOne(`${apiPath}/somePool`);
+    expect(req.request.method).toBe('DELETE');
+  });
+
   it(
     'should call list without parameter',
     fakeAsync(() => {
index 2716a88948634a76f6b24f5ae3d4982df2049ba0..183b1c4081d8829c347cc249a648ffd91f11ba7e 100644 (file)
@@ -23,6 +23,10 @@ export class PoolService {
     return this.http.put(`${this.apiPath}/${name}`, pool, { observe: 'response' });
   }
 
+  delete(name) {
+    return this.http.delete(`${this.apiPath}/${name}`, { observe: 'response' });
+  }
+
   get(poolName) {
     return this.http.get(`${this.apiPath}/${poolName}`);
   }