From: Stephan Müller Date: Fri, 29 Jun 2018 12:18:46 +0000 (+0200) Subject: mgr/dashboard: Pool delete X-Git-Tag: v14.0.1~96^2~7 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=6b86243c3adc0bdddf313ccd1b993cdb67f2799e;p=ceph.git mgr/dashboard: Pool delete 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 --- 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 index 4eae55d21cf6a..94c0f51750d9d 100644 --- 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 @@ -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'); + }); + }); }); 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 index 6da0a6bfb6fad..0e2562c2f4443 100644 --- 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 @@ -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) + }) + } + }); + } } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/pool.service.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/pool.service.spec.ts index c0e4303c1d5b2..afa5abff2cd6f 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/pool.service.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/pool.service.spec.ts @@ -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(() => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/pool.service.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/pool.service.ts index 2716a88948634..183b1c4081d88 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/pool.service.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/pool.service.ts @@ -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}`); }