]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: consider 'mon_allow_pool_delete' flag 28260/head
authorTatjana Dehler <tdehler@suse.com>
Tue, 28 May 2019 06:51:06 +0000 (08:51 +0200)
committerTatjana Dehler <tdehler@suse.com>
Wed, 29 May 2019 10:40:15 +0000 (12:40 +0200)
Check if the 'mon_allow_pool_delete' flag is set. If not,
disable the menu item to delete a pool. Show also a description
why the item is disabled.

Fixes: https://tracker.ceph.com/issues/39533
Signed-off-by: Tatjana Dehler <tdehler@suse.com>
qa/tasks/mgr/dashboard/test_cluster_configuration.py
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

index 450d9021106c06316b144acfa5726a99eddfa3d9..798afe9c19c17779009903b2749b3a1feed8ef04 100644 (file)
@@ -286,7 +286,6 @@ class ClusterConfigurationTest(DashboardTestCase):
         """
         This test case is intended to check the existence of all hard coded config options used by
         the dashboard.
-
         If you include further hard coded options in the dashboard, feel free to add them to the
         list.
         """
@@ -326,7 +325,8 @@ class ClusterConfigurationTest(DashboardTestCase):
             'osd_scrub_interval_randomize_ratio',  # osd-pg-scrub
             'osd_scrub_invalid_stats',  # osd-pg-scrub
             'osd_scrub_load_threshold',  # osd-pg-scrub
-            'osd_scrub_max_preemptions'  # osd-pg-scrub
+            'osd_scrub_max_preemptions',  # osd-pg-scrub
+            'mon_allow_pool_delete'  # pool-list
         ]
 
         for config_option in hard_coded_options:
index 21e553ba14721bdb0a0dd6e891e948d990c47c37..1ea2c6579bbc75fd27f1172b40c5fac9a6d9e60b 100644 (file)
@@ -8,6 +8,7 @@ import { TabsModule } from 'ngx-bootstrap/tabs';
 import { of } from 'rxjs';
 
 import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper';
+import { ConfigurationService } from '../../../shared/api/configuration.service';
 import { PoolService } from '../../../shared/api/pool.service';
 import { CriticalConfirmationModalComponent } from '../../../shared/components/critical-confirmation-modal/critical-confirmation-modal.component';
 import { ExecutingTask } from '../../../shared/models/executing-task';
@@ -67,6 +68,56 @@ describe('PoolListComponent', () => {
     expect(component.columns.every((column) => Boolean(column.prop))).toBeTruthy();
   });
 
+  describe('monAllowPoolDelete', () => {
+    let configurationService: ConfigurationService;
+
+    beforeEach(() => {
+      configurationService = TestBed.get(ConfigurationService);
+    });
+
+    it('should set value correctly if mon_allow_pool_delete flag is set to true', () => {
+      const configOption = {
+        name: 'mon_allow_pool_delete',
+        value: [
+          {
+            section: 'mon',
+            value: 'true'
+          }
+        ]
+      };
+      spyOn(configurationService, 'get').and.returnValue(of(configOption));
+      fixture = TestBed.createComponent(PoolListComponent);
+      component = fixture.componentInstance;
+      expect(component.monAllowPoolDelete).toBe(true);
+    });
+
+    it('should set value correctly if mon_allow_pool_delete flag is set to false', () => {
+      const configOption = {
+        name: 'mon_allow_pool_delete',
+        value: [
+          {
+            section: 'mon',
+            value: 'false'
+          }
+        ]
+      };
+      spyOn(configurationService, 'get').and.returnValue(of(configOption));
+      fixture = TestBed.createComponent(PoolListComponent);
+      component = fixture.componentInstance;
+      expect(component.monAllowPoolDelete).toBe(false);
+    });
+
+    it('should set value correctly if mon_allow_pool_delete flag is not set', () => {
+      const configOption = {
+        name: 'mon_allow_pool_delete'
+      };
+      spyOn(configurationService, 'get').and.returnValue(of(configOption));
+      fixture = TestBed.createComponent(PoolListComponent);
+      component = fixture.componentInstance;
+      expect(component.monAllowPoolDelete).toBe(false);
+    });
+  });
+
   describe('pool deletion', () => {
     let taskWrapper: TaskWrapperService;
 
@@ -348,4 +399,18 @@ describe('PoolListComponent', () => {
       expect(component.selectionCacheTiers).toEqual([]);
     });
   });
+
+  describe('getDisableDesc', () => {
+    it('should return message if mon_allow_pool_delete flag is set to false', () => {
+      component.monAllowPoolDelete = false;
+      expect(component.getDisableDesc()).toBe(
+        'Pool deletion is disabled by the mon_allow_pool_delete configuration setting.'
+      );
+    });
+
+    it('should return undefined if mon_allow_pool_delete flag is set to true', () => {
+      component.monAllowPoolDelete = true;
+      expect(component.getDisableDesc()).toBeUndefined();
+    });
+  });
 });
index 91e9b0ec2a8c89706e6fc09a64b3f4ace7454da4..78586e69bbd0c4142885a80536cedd7e0ed60613 100644 (file)
@@ -4,6 +4,7 @@ import { I18n } from '@ngx-translate/i18n-polyfill';
 import * as _ from 'lodash';
 import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';
 
+import { ConfigurationService } from '../../../shared/api/configuration.service';
 import { PoolService } from '../../../shared/api/pool.service';
 import { CriticalConfirmationModalComponent } from '../../../shared/components/critical-confirmation-modal/critical-confirmation-modal.component';
 import { ActionLabelsI18n, URLVerbs } from '../../../shared/constants/app.constants';
@@ -54,6 +55,7 @@ export class PoolListComponent implements OnInit {
   tableActions: CdTableAction[];
   viewCacheStatusList: any[];
   selectionCacheTiers: any[] = [];
+  monAllowPoolDelete = false;
 
   constructor(
     private poolService: PoolService,
@@ -65,6 +67,7 @@ export class PoolListComponent implements OnInit {
     private pgCategoryService: PgCategoryService,
     private dimlessPipe: DimlessPipe,
     private urlBuilder: URLBuilderService,
+    private configurationService: ConfigurationService,
     public actionLabels: ActionLabelsI18n
   ) {
     this.permissions = this.authStorageService.getPermissions();
@@ -86,9 +89,20 @@ export class PoolListComponent implements OnInit {
         permission: 'delete',
         icon: 'fa-trash-o',
         click: () => this.deletePoolModal(),
-        name: this.actionLabels.DELETE
+        name: this.actionLabels.DELETE,
+        disable: () => !this.selection.first() || !this.monAllowPoolDelete,
+        disableDesc: () => this.getDisableDesc()
       }
     ];
+
+    this.configurationService.get('mon_allow_pool_delete').subscribe((data: any) => {
+      if (_.has(data, 'value')) {
+        const monSection = _.find(data.value, (v) => {
+          return v.section === 'mon';
+        }) || { value: false };
+        this.monAllowPoolDelete = monSection.value === 'true' ? true : false;
+      }
+    });
   }
 
   ngOnInit() {
@@ -253,4 +267,12 @@ export class PoolListComponent implements OnInit {
     const cacheTierIds = this.selection.hasSingleSelection ? this.selection.first()['tiers'] : [];
     this.selectionCacheTiers = this.pools.filter((pool) => cacheTierIds.includes(pool.pool));
   }
+
+  getDisableDesc(): string | undefined {
+    if (!this.monAllowPoolDelete) {
+      return this.i18n(
+        'Pool deletion is disabled by the mon_allow_pool_delete configuration setting.'
+      );
+    }
+  }
 }