]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
mgr/dashboard: delete rgw multisite
authorPedro Gonzalez Gomez <pegonzal@redhat.com>
Mon, 20 Mar 2023 18:53:06 +0000 (19:53 +0100)
committerAashish Sharma <aasharma@li-e74156cc-2f67-11b2-a85c-e98659a63c5c.ibm.com>
Thu, 10 Aug 2023 11:54:19 +0000 (17:24 +0530)
Signed-off-by: Pedro Gonzalez Gomez <pegonzal@redhat.com>
(cherry picked from commit dae8168e29bc864058000256e01d1ce514c6f068)

18 files changed:
src/pybind/mgr/dashboard/controllers/rgw.py
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/models/rgw-multisite-zone-deletion-form/rgw-multisite-zone-deletion-form.component.html [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/models/rgw-multisite-zone-deletion-form/rgw-multisite-zone-deletion-form.component.scss [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/models/rgw-multisite-zone-deletion-form/rgw-multisite-zone-deletion-form.component.spec.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/models/rgw-multisite-zone-deletion-form/rgw-multisite-zone-deletion-form.component.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/models/rgw-multisite-zonegroup-deletion-form/rgw-multisite-zonegroup-deletion-form.component.html [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/models/rgw-multisite-zonegroup-deletion-form/rgw-multisite-zonegroup-deletion-form.component.scss [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/models/rgw-multisite-zonegroup-deletion-form/rgw-multisite-zonegroup-deletion-form.component.spec.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/models/rgw-multisite-zonegroup-deletion-form/rgw-multisite-zonegroup-deletion-form.component.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-details/rgw-multisite-details.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-details/rgw-multisite-details.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-details/rgw-multisite-details.component.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw.module.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-realm.service.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-zone.service.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-zonegroup.service.ts
src/pybind/mgr/dashboard/openapi.yaml
src/pybind/mgr/dashboard/services/rgw_client.py

index b5230a1fe39960af6f0670f5a525207e2c5e19a9..331d2067fd03ca50291459657c8c000164820692 100644 (file)
@@ -756,6 +756,14 @@ class RgwRealm(RESTController):
         except NoRgwDaemonsException as e:
             raise DashboardException(e, http_status_code=404, component='rgw')
 
+    def delete(self, realm_name, daemon_name=None):
+        try:
+            instance = RgwClient.admin_instance(daemon_name)
+            result = instance.delete_realm(realm_name)
+            return result
+        except NoRgwDaemonsException as e:
+            raise DashboardException(e, http_status_code=404, component='rgw')
+
 
 @APIRouter('/rgw/zonegroup', Scope.RGW)
 class RgwZonegroup(RESTController):
@@ -801,6 +809,14 @@ class RgwZonegroup(RESTController):
         except NoRgwDaemonsException as e:
             raise DashboardException(e, http_status_code=404, component='rgw')
 
+    def delete(self, zonegroup_name, delete_pools, daemon_name=None):
+        try:
+            instance = RgwClient.admin_instance(daemon_name)
+            result = instance.delete_zonegroup(zonegroup_name, delete_pools)
+            return result
+        except NoRgwDaemonsException as e:
+            raise DashboardException(e, http_status_code=404, component='rgw')
+
 
 @APIRouter('/rgw/zone', Scope.RGW)
 class RgwZone(RESTController):
@@ -845,3 +861,11 @@ class RgwZone(RESTController):
             return result
         except NoRgwDaemonsException as e:
             raise DashboardException(e, http_status_code=404, component='rgw')
+
+    def delete(self, zonegroup_name, zone_name, delete_pools, daemon_name=None):
+        try:
+            instance = RgwClient.admin_instance(daemon_name)
+            result = instance.delete_zone(zonegroup_name, zone_name, delete_pools)
+            return result
+        except NoRgwDaemonsException as e:
+            raise DashboardException(e, http_status_code=404, component='rgw')
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/models/rgw-multisite-zone-deletion-form/rgw-multisite-zone-deletion-form.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/models/rgw-multisite-zone-deletion-form/rgw-multisite-zone-deletion-form.component.html
new file mode 100644 (file)
index 0000000..030cfe6
--- /dev/null
@@ -0,0 +1,55 @@
+<cd-modal [modalRef]="activeModal">
+  <ng-container i18n="form title"
+                class="modal-title">Delete Zone</ng-container>
+
+  <ng-container class="modal-content">
+    <form name="zoneForm"
+          [formGroup]="zoneForm"
+          novalidate>
+      <div class="custom-control ms-4 mt-4">
+        <label i18n>
+            Do you want to delete all pools associated with it?</label>
+        <label class="mb-4"
+               i18n>
+            This will delete the following pools and any data stored in these pools:</label>
+        <ng-container *ngIf="zoneData$ | async as data">
+          <div id="scroll">
+            <ng-container *ngFor="let pool of data.placement_pools">
+              <strong>{{pool?.val.data_extra_pool}}</strong>
+              <strong>{{pool?.val.index_pool}}</strong>
+              <strong>{{pool?.val.storage_classes.STANDARD.data_pool}}</strong>
+            </ng-container>
+          </div>
+        </ng-container>
+        <div class="form-group">
+          <div class="custom-control custom-checkbox mt-2">
+            <input type="checkbox"
+                   class="custom-control-input"
+                   name="deletePools"
+                   id="deletePools"
+                   formControlName="deletePools"
+                   (change)="showDangerText()">
+            <label class="custom-control-label"
+                   for="deletePools"
+                   i18n>Yes, I want to delete the pools.</label>
+          </div>
+          <div *ngIf="displayText"
+               class="me-4">
+            <cd-alert-panel type="danger"
+                            i18n>
+                            This will delete all the data in the pools!
+            </cd-alert-panel>
+          </div>
+        </div>
+      </div>
+
+      <div class="modal-footer">
+        <cd-form-button-panel (submitActionEvent)="submit()"
+                              [form]="zoneForm"
+                              [submitText]="actionLabels.DELETE">
+        </cd-form-button-panel>
+      </div>
+    </form>
+  </ng-container>
+
+</cd-modal>
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/models/rgw-multisite-zone-deletion-form/rgw-multisite-zone-deletion-form.component.scss b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/models/rgw-multisite-zone-deletion-form/rgw-multisite-zone-deletion-form.component.scss
new file mode 100644 (file)
index 0000000..f1d1d1b
--- /dev/null
@@ -0,0 +1,9 @@
+strong {
+  display: block;
+}
+
+#scroll {
+  height: 100%;
+  max-height: 10rem;
+  overflow: auto;
+}
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/models/rgw-multisite-zone-deletion-form/rgw-multisite-zone-deletion-form.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/models/rgw-multisite-zone-deletion-form/rgw-multisite-zone-deletion-form.component.spec.ts
new file mode 100644 (file)
index 0000000..947ef3c
--- /dev/null
@@ -0,0 +1,30 @@
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { RouterTestingModule } from '@angular/router/testing';
+import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
+import { ToastrModule } from 'ngx-toastr';
+import { SharedModule } from '~/app/shared/shared.module';
+import { configureTestBed } from '~/testing/unit-test-helper';
+
+import { RgwMultisiteZoneDeletionFormComponent } from './rgw-multisite-zone-deletion-form.component';
+
+describe('RgwMultisiteZoneDeletionFormComponent', () => {
+  let component: RgwMultisiteZoneDeletionFormComponent;
+  let fixture: ComponentFixture<RgwMultisiteZoneDeletionFormComponent>;
+
+  configureTestBed({
+    declarations: [RgwMultisiteZoneDeletionFormComponent],
+    imports: [SharedModule, HttpClientTestingModule, ToastrModule.forRoot(), RouterTestingModule],
+    providers: [NgbActiveModal]
+  });
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(RgwMultisiteZoneDeletionFormComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/models/rgw-multisite-zone-deletion-form/rgw-multisite-zone-deletion-form.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/models/rgw-multisite-zone-deletion-form/rgw-multisite-zone-deletion-form.component.ts
new file mode 100644 (file)
index 0000000..bc4fb28
--- /dev/null
@@ -0,0 +1,60 @@
+import { Component, OnInit } from '@angular/core';
+import { FormControl } from '@angular/forms';
+import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
+import { RgwZoneService } from '~/app/shared/api/rgw-zone.service';
+import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
+import { NotificationType } from '~/app/shared/enum/notification-type.enum';
+import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
+import { NotificationService } from '~/app/shared/services/notification.service';
+
+@Component({
+  selector: 'cd-rgw-multisite-zone-deletion-form',
+  templateUrl: './rgw-multisite-zone-deletion-form.component.html',
+  styleUrls: ['./rgw-multisite-zone-deletion-form.component.scss']
+})
+export class RgwMultisiteZoneDeletionFormComponent implements OnInit {
+  zoneData$: any;
+  zone: any;
+  zoneForm: CdFormGroup;
+  displayText: boolean = false;
+
+  constructor(
+    public activeModal: NgbActiveModal,
+    public actionLabels: ActionLabelsI18n,
+    public notificationService: NotificationService,
+    private rgwZoneService: RgwZoneService
+  ) {
+    this.createForm();
+  }
+
+  ngOnInit(): void {
+    this.zoneData$ = this.rgwZoneService.get(this.zone);
+  }
+
+  createForm() {
+    this.zoneForm = new CdFormGroup({
+      deletePools: new FormControl(false)
+    });
+  }
+
+  submit() {
+    this.rgwZoneService
+      .delete(this.zone.parent, this.zone.name, this.zoneForm.value.deletePools)
+      .subscribe(
+        () => {
+          this.notificationService.show(
+            NotificationType.success,
+            $localize`Zone: '${this.zone.name}' deleted successfully`
+          );
+          this.activeModal.close();
+        },
+        () => {
+          this.zoneForm.setErrors({ cdSubmitButton: true });
+        }
+      );
+  }
+
+  showDangerText() {
+    this.displayText = !this.displayText;
+  }
+}
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/models/rgw-multisite-zonegroup-deletion-form/rgw-multisite-zonegroup-deletion-form.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/models/rgw-multisite-zonegroup-deletion-form/rgw-multisite-zonegroup-deletion-form.component.html
new file mode 100644 (file)
index 0000000..62edde4
--- /dev/null
@@ -0,0 +1,58 @@
+<cd-modal [modalRef]="activeModal">
+  <ng-container i18n="form title"
+                class="modal-title">Delete Zonegroup</ng-container>
+
+  <ng-container class="modal-content">
+    <form name="zonegroupForm"
+          [formGroup]="zonegroupForm"
+          novalidate>
+      <div class="modal-body ms-4 mt-4">
+        <label i18n>
+            Are you sure that you want to delete the selected zonegroup and its zones?</label>
+        <label i18n>
+            This will delete the following zones and pools and any data stored in these pools:</label>
+        <ng-container *ngIf="zonegroupData$ | async as data">
+          <strong class="mt-3 mb-2 h5">Zones:</strong>
+          <div id="scroll">
+            <strong *ngFor="let zone of data.zones">{{zone?.name}}</strong>
+          </div>
+          <strong class="mt-3 mb-2 h5">Pools:</strong>
+          <div id="scroll"
+               class="mb-2">
+            <ng-container *ngFor="let pool of data.placement_targets">
+              <strong *ngIf="pool.name !== 'default-placement'">{{pool?.name}}</strong>
+            </ng-container>
+          </div>
+        </ng-container>
+        <div class="form-group">
+          <div class="custom-control custom-checkbox mt-2">
+            <input type="checkbox"
+                   class="custom-control-input"
+                   name="deletePools"
+                   id="deletePools"
+                   formControlName="deletePools"
+                   (change)="showDangerText()">
+            <label class="custom-control-label"
+                   for="deletePools"
+                   i18n>Yes, I want to delete the zones and their pools.</label>
+          </div>
+          <div *ngIf="displayText"
+               class="me-4">
+            <cd-alert-panel type="danger"
+                            i18n>
+                            This will delete all the data in the pools!
+            </cd-alert-panel>
+          </div>
+        </div>
+      </div>
+
+      <div class="modal-footer">
+        <cd-form-button-panel (submitActionEvent)="submit()"
+                              [form]="zonegroupForm"
+                              [submitText]="actionLabels.DELETE ">
+        </cd-form-button-panel>
+      </div>
+    </form>
+  </ng-container>
+
+</cd-modal>
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/models/rgw-multisite-zonegroup-deletion-form/rgw-multisite-zonegroup-deletion-form.component.scss b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/models/rgw-multisite-zonegroup-deletion-form/rgw-multisite-zonegroup-deletion-form.component.scss
new file mode 100644 (file)
index 0000000..f1d1d1b
--- /dev/null
@@ -0,0 +1,9 @@
+strong {
+  display: block;
+}
+
+#scroll {
+  height: 100%;
+  max-height: 10rem;
+  overflow: auto;
+}
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/models/rgw-multisite-zonegroup-deletion-form/rgw-multisite-zonegroup-deletion-form.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/models/rgw-multisite-zonegroup-deletion-form/rgw-multisite-zonegroup-deletion-form.component.spec.ts
new file mode 100644 (file)
index 0000000..3ee39f2
--- /dev/null
@@ -0,0 +1,30 @@
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { RouterTestingModule } from '@angular/router/testing';
+import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
+import { ToastrModule } from 'ngx-toastr';
+import { SharedModule } from '~/app/shared/shared.module';
+import { configureTestBed } from '~/testing/unit-test-helper';
+
+import { RgwMultisiteZonegroupDeletionFormComponent } from './rgw-multisite-zonegroup-deletion-form.component';
+
+describe('RgwMultisiteZonegroupDeletionFormComponent', () => {
+  let component: RgwMultisiteZonegroupDeletionFormComponent;
+  let fixture: ComponentFixture<RgwMultisiteZonegroupDeletionFormComponent>;
+
+  configureTestBed({
+    declarations: [RgwMultisiteZonegroupDeletionFormComponent],
+    imports: [SharedModule, HttpClientTestingModule, ToastrModule.forRoot(), RouterTestingModule],
+    providers: [NgbActiveModal]
+  });
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(RgwMultisiteZonegroupDeletionFormComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/models/rgw-multisite-zonegroup-deletion-form/rgw-multisite-zonegroup-deletion-form.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/models/rgw-multisite-zonegroup-deletion-form/rgw-multisite-zonegroup-deletion-form.component.ts
new file mode 100644 (file)
index 0000000..f7ee6f3
--- /dev/null
@@ -0,0 +1,55 @@
+import { Component, OnInit } from '@angular/core';
+import { FormControl } from '@angular/forms';
+import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
+import { RgwZonegroupService } from '~/app/shared/api/rgw-zonegroup.service';
+import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
+import { NotificationType } from '~/app/shared/enum/notification-type.enum';
+import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
+import { NotificationService } from '~/app/shared/services/notification.service';
+
+@Component({
+  selector: 'cd-rgw-multisite-zonegroup-deletion-form',
+  templateUrl: './rgw-multisite-zonegroup-deletion-form.component.html',
+  styleUrls: ['./rgw-multisite-zonegroup-deletion-form.component.scss']
+})
+export class RgwMultisiteZonegroupDeletionFormComponent implements OnInit {
+  zonegroupData$: any;
+  zonegroup: any;
+  zonegroupForm: CdFormGroup;
+  displayText: boolean = false;
+
+  constructor(
+    public activeModal: NgbActiveModal,
+    public actionLabels: ActionLabelsI18n,
+    public notificationService: NotificationService,
+    private rgwZonegroupService: RgwZonegroupService
+  ) {
+    this.createForm();
+  }
+
+  ngOnInit(): void {
+    this.zonegroupData$ = this.rgwZonegroupService.get(this.zonegroup);
+  }
+
+  createForm() {
+    this.zonegroupForm = new CdFormGroup({
+      deletePools: new FormControl(false)
+    });
+  }
+
+  submit() {
+    this.rgwZonegroupService
+      .delete(this.zonegroup.name, this.zonegroupForm.value.deletePools)
+      .subscribe(() => {
+        this.notificationService.show(
+          NotificationType.success,
+          $localize`Zone: '${this.zonegroup.name}' deleted successfully`
+        );
+        this.activeModal.close();
+      });
+  }
+
+  showDangerText() {
+    this.displayText = !this.displayText;
+  }
+}
index 50e17b41b1ada5d599d7e99a152a36f44ed286ff..3dcb290c64141099be18100e7fa1ba56976374cc 100644 (file)
                           ngbDropdownToggle>
                     <i [ngClass]="[icons.edit]"></i>
                   </button>
+                  <button type="button"
+                          title="Delete"
+                          class="btn btn-light ms-1"
+                          i18n-title
+                          (click)="delete(node)">
+                    <i [ngClass]="[icons.destroy]"></i>
+                  </button>
                 </div>
               </ng-template>
             </tree-root>
index 1b0c0d65a41a64818da92ea7b321edce739fb9cc..173bdb4bd820e1134019f10585d101f4ceaea509 100644 (file)
@@ -2,6 +2,7 @@ import { HttpClientTestingModule } from '@angular/common/http/testing';
 import { DebugElement } from '@angular/core';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { TreeModule } from '@circlon/angular-tree-component';
+import { ToastrModule } from 'ngx-toastr';
 import { SharedModule } from '~/app/shared/shared.module';
 
 import { RgwMultisiteDetailsComponent } from './rgw-multisite-details.component';
@@ -14,7 +15,7 @@ describe('RgwMultisiteDetailsComponent', () => {
   beforeEach(async () => {
     await TestBed.configureTestingModule({
       declarations: [RgwMultisiteDetailsComponent],
-      imports: [HttpClientTestingModule, TreeModule, SharedModule]
+      imports: [HttpClientTestingModule, TreeModule, SharedModule, ToastrModule.forRoot()]
     }).compileComponents();
   });
 
index a07e45d11ac77ec165d7176db1888ac545d5fdde..0a8e598f6e73b1311e1ba066e079120df287e1f6 100644 (file)
@@ -12,15 +12,20 @@ import { forkJoin, Subscription } from 'rxjs';
 import { RgwRealmService } from '~/app/shared/api/rgw-realm.service';
 import { RgwZoneService } from '~/app/shared/api/rgw-zone.service';
 import { RgwZonegroupService } from '~/app/shared/api/rgw-zonegroup.service';
+import { CriticalConfirmationModalComponent } from '~/app/shared/components/critical-confirmation-modal/critical-confirmation-modal.component';
 import { ActionLabelsI18n, TimerServiceInterval } from '~/app/shared/constants/app.constants';
 import { Icons } from '~/app/shared/enum/icons.enum';
+import { NotificationType } from '~/app/shared/enum/notification-type.enum';
 import { CdTableAction } from '~/app/shared/models/cd-table-action';
 import { CdTableSelection } from '~/app/shared/models/cd-table-selection';
 import { Permission } from '~/app/shared/models/permissions';
 import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
 import { ModalService } from '~/app/shared/services/modal.service';
+import { NotificationService } from '~/app/shared/services/notification.service';
 import { TimerService } from '~/app/shared/services/timer.service';
 import { RgwRealm, RgwZone, RgwZonegroup } from '../models/rgw-multisite';
+import { RgwMultisiteZoneDeletionFormComponent } from '../models/rgw-multisite-zone-deletion-form/rgw-multisite-zone-deletion-form.component';
+import { RgwMultisiteZonegroupDeletionFormComponent } from '../models/rgw-multisite-zonegroup-deletion-form/rgw-multisite-zonegroup-deletion-form.component';
 import { RgwMultisiteRealmFormComponent } from '../rgw-multisite-realm-form/rgw-multisite-realm-form.component';
 import { RgwMultisiteZoneFormComponent } from '../rgw-multisite-zone-form/rgw-multisite-zone-form.component';
 import { RgwMultisiteZonegroupFormComponent } from '../rgw-multisite-zonegroup-form/rgw-multisite-zonegroup-form.component';
@@ -56,6 +61,7 @@ export class RgwMultisiteDetailsComponent implements OnDestroy, OnInit {
       }
     }
   };
+  modalRef: NgbModalRef;
 
   realms: RgwRealm[] = [];
   zonegroups: RgwZonegroup[] = [];
@@ -79,7 +85,8 @@ export class RgwMultisiteDetailsComponent implements OnDestroy, OnInit {
     public timerServiceVariable: TimerServiceInterval,
     public rgwRealmService: RgwRealmService,
     public rgwZonegroupService: RgwZonegroupService,
-    public rgwZoneService: RgwZoneService
+    public rgwZoneService: RgwZoneService,
+    private notificationService: NotificationService
   ) {
     this.permission = this.authStorageService.getPermissions().rgw;
     const createRealmAction: CdTableAction = {
@@ -300,4 +307,35 @@ export class RgwMultisiteDetailsComponent implements OnDestroy, OnInit {
       }
     }
   }
+
+  delete(node: TreeNode) {
+    if (node.data.type === 'realm') {
+      this.modalRef = this.modalService.show(CriticalConfirmationModalComponent, {
+        itemDescription: $localize`${node.data.type} ${node.data.name}`,
+        itemNames: [`${node.data.name}`],
+        submitAction: () => {
+          this.rgwRealmService.delete(node.data.name).subscribe(
+            () => {
+              this.modalRef.close();
+              this.notificationService.show(
+                NotificationType.success,
+                $localize`Realm: '${node.data.name}' deleted successfully`
+              );
+            },
+            () => {
+              this.modalRef.componentInstance.stopLoadingSpinner();
+            }
+          );
+        }
+      });
+    } else if (node.data.type === 'zonegroup') {
+      this.modalRef = this.modalService.show(RgwMultisiteZonegroupDeletionFormComponent, {
+        zonegroup: node.data
+      });
+    } else if (node.data.type === 'zone') {
+      this.modalRef = this.modalService.show(RgwMultisiteZoneDeletionFormComponent, {
+        zone: node.data
+      });
+    }
+  }
 }
index 2205ffa6083d757540a956e9f6e840405c4bcaa7..d3a48ad6b2244152e71f4d31390c8018d374997c 100644 (file)
@@ -34,6 +34,8 @@ import { ModuleStatusGuardService } from '~/app/shared/services/module-status-gu
 import { RgwMultisiteRealmFormComponent } from './rgw-multisite-realm-form/rgw-multisite-realm-form.component';
 import { RgwMultisiteZonegroupFormComponent } from './rgw-multisite-zonegroup-form/rgw-multisite-zonegroup-form.component';
 import { RgwMultisiteZoneFormComponent } from './rgw-multisite-zone-form/rgw-multisite-zone-form.component';
+import { RgwMultisiteZoneDeletionFormComponent } from './models/rgw-multisite-zone-deletion-form/rgw-multisite-zone-deletion-form.component';
+import { RgwMultisiteZonegroupDeletionFormComponent } from './models/rgw-multisite-zonegroup-deletion-form/rgw-multisite-zonegroup-deletion-form.component';
 
 @NgModule({
   imports: [
@@ -77,7 +79,9 @@ import { RgwMultisiteZoneFormComponent } from './rgw-multisite-zone-form/rgw-mul
     RgwMultisiteDetailsComponent,
     RgwMultisiteRealmFormComponent,
     RgwMultisiteZonegroupFormComponent,
-    RgwMultisiteZoneFormComponent
+    RgwMultisiteZoneFormComponent,
+    RgwMultisiteZoneDeletionFormComponent,
+    RgwMultisiteZonegroupDeletionFormComponent
   ]
 })
 export class RgwModule {}
index bacdedc19dc58eb29bd313b0fe4538bc3d29b933..63bb7b8c657f2cd260af951c013d3861deb32004 100644 (file)
@@ -52,6 +52,15 @@ export class RgwRealmService {
     });
   }
 
+  delete(realmName: string): Observable<any> {
+    return this.rgwDaemonService.request((params: HttpParams) => {
+      params = params.appendAll({
+        realm_name: realmName
+      });
+      return this.http.delete(`${this.url}/${realmName}`, { params: params });
+    });
+  }
+
   getRealmTree(realm: RgwRealm, defaultRealmId: string) {
     let nodes = {};
     let realmIds = [];
index 707154f247535eee16bedcbc92c66b76d177c2d8..a8530c9558e77fb3bf2f6307514ca9bdcd3f6f7b 100644 (file)
@@ -52,6 +52,17 @@ export class RgwZoneService {
     });
   }
 
+  delete(zonegroupName: string, zoneName: string, deletePools: boolean): Observable<any> {
+    return this.rgwDaemonService.request((params: HttpParams) => {
+      params = params.appendAll({
+        zonegroup_name: zonegroupName,
+        zone_name: zoneName,
+        delete_pools: deletePools
+      });
+      return this.http.delete(`${this.url}/${zoneName}`, { params: params });
+    });
+  }
+
   getZoneTree(zone: RgwZone, defaultZoneId: string, zonegroup?: RgwZonegroup, realm?: RgwRealm) {
     let nodes = {};
     let zoneIds = [];
index b16d0f7e928edd8594f3c504fb03b57af28e16d3..c8bec7338374784cb350b61a52718b1dfdb64810 100644 (file)
@@ -44,6 +44,16 @@ export class RgwZonegroupService {
     });
   }
 
+  delete(zonegroupName: string, deletePools: boolean): Observable<any> {
+    return this.rgwDaemonService.request((params: HttpParams) => {
+      params = params.appendAll({
+        zonegroup_name: zonegroupName,
+        delete_pools: deletePools
+      });
+      return this.http.delete(`${this.url}/${zonegroupName}`, { params: params });
+    });
+  }
+
   getZonegroupTree(zonegroup: RgwZonegroup, defaultZonegroupId: string, realm?: RgwRealm) {
     let nodes = {};
     nodes['id'] = zonegroup.id;
index f1a39c4df51260e3188be48633bbbea374669488..efb49555f06a0823a5595da9d34e54989a5e2897 100644 (file)
@@ -8415,7 +8415,43 @@ paths:
       - jwt: []
       tags:
       - RgwRealm
-  /api/rgw/realm/get_realm_tokens:
+  /api/rgw/realm/{realm_name}:
+    delete:
+      parameters:
+      - in: path
+        name: realm_name
+        required: true
+        schema:
+          type: string
+      - allowEmptyValue: true
+        in: query
+        name: daemon_name
+        schema:
+          type: string
+      responses:
+        '202':
+          content:
+            application/vnd.ceph.api.v1.0+json:
+              type: object
+          description: Operation is still executing. Please check the task queue.
+        '204':
+          content:
+            application/vnd.ceph.api.v1.0+json:
+              type: object
+          description: Resource deleted.
+        '400':
+          description: Operation exception. Please check the response body for details.
+        '401':
+          description: Unauthenticated access. Please login first.
+        '403':
+          description: Unauthorized access. Please check your permissions.
+        '500':
+          description: Unexpected error. Please check the response body for the stack
+            trace.
+      security:
+      - jwt: []
+      tags:
+      - RgwRealm
     get:
       parameters: []
       responses:
@@ -9340,6 +9376,52 @@ paths:
       tags:
       - RgwZone
   /api/rgw/zone/{zone_name}:
+    delete:
+      parameters:
+      - in: path
+        name: zone_name
+        required: true
+        schema:
+          type: string
+      - in: query
+        name: zonegroup_name
+        required: true
+        schema:
+          type: string
+      - in: query
+        name: delete_pools
+        required: true
+        schema:
+          type: string
+      - allowEmptyValue: true
+        in: query
+        name: daemon_name
+        schema:
+          type: string
+      responses:
+        '202':
+          content:
+            application/vnd.ceph.api.v1.0+json:
+              type: object
+          description: Operation is still executing. Please check the task queue.
+        '204':
+          content:
+            application/vnd.ceph.api.v1.0+json:
+              type: object
+          description: Resource deleted.
+        '400':
+          description: Operation exception. Please check the response body for details.
+        '401':
+          description: Unauthenticated access. Please login first.
+        '403':
+          description: Unauthorized access. Please check your permissions.
+        '500':
+          description: Unexpected error. Please check the response body for the stack
+            trace.
+      security:
+      - jwt: []
+      tags:
+      - RgwZone
     get:
       parameters:
       - in: path
@@ -9468,6 +9550,47 @@ paths:
       tags:
       - RgwZonegroup
   /api/rgw/zonegroup/{zonegroup_name}:
+    delete:
+      parameters:
+      - in: path
+        name: zonegroup_name
+        required: true
+        schema:
+          type: string
+      - in: query
+        name: delete_pools
+        required: true
+        schema:
+          type: string
+      - allowEmptyValue: true
+        in: query
+        name: daemon_name
+        schema:
+          type: string
+      responses:
+        '202':
+          content:
+            application/vnd.ceph.api.v1.0+json:
+              type: object
+          description: Operation is still executing. Please check the task queue.
+        '204':
+          content:
+            application/vnd.ceph.api.v1.0+json:
+              type: object
+          description: Resource deleted.
+        '400':
+          description: Operation exception. Please check the response body for details.
+        '401':
+          description: Unauthenticated access. Please login first.
+        '403':
+          description: Unauthorized access. Please check your permissions.
+        '500':
+          description: Unexpected error. Please check the response body for the stack
+            trace.
+      security:
+      - jwt: []
+      tags:
+      - RgwZonegroup
     get:
       parameters:
       - in: path
index 836531b65f9977da3ee78ee2675ce68eb5e5715f..09719af20acfd396ce4f8cc828bc330a16fe38b2 100644 (file)
@@ -651,6 +651,16 @@ class RgwClient(RestClient):
             all_realms_info['default_realm'] = ''  # type: ignore
         return all_realms_info
 
+    def delete_realm(self, realm_name: str):
+        rgw_delete_realm_cmd = ['realm', 'rm', '--rgw-realm', realm_name]
+        try:
+            exit_code, _, _ = mgr.send_rgwadmin_command(rgw_delete_realm_cmd)
+            if exit_code > 0:
+                raise DashboardException(msg='Unable to delete realm',
+                                         http_status_code=500, component='rgw')
+        except SubprocessError as error:
+            raise DashboardException(error, http_status_code=500, component='rgw')
+
     def update_period(self):
         rgw_update_period_cmd = ['period', 'update', '--commit']
         try:
@@ -755,6 +765,23 @@ class RgwClient(RestClient):
             all_zonegroups_info['default_zonegroup'] = ''  # type: ignore
         return all_zonegroups_info
 
+    def delete_zonegroup(self, zonegroup_name: str, delete_pools: str):
+        if delete_pools == 'true':
+            zonegroup_info = self.get_zonegroup(zonegroup_name)
+        rgw_delete_zonegroup_cmd = ['zonegroup', 'delete', '--rgw-zonegroup', zonegroup_name]
+        try:
+            exit_code, _, _ = mgr.send_rgwadmin_command(rgw_delete_zonegroup_cmd)
+            if exit_code > 0:
+                raise DashboardException(msg='Unable to delete zonegroup',
+                                         http_status_code=500, component='rgw')
+        except SubprocessError as error:
+            raise DashboardException(error, http_status_code=500, component='rgw')
+        self.update_period()
+        if delete_pools == 'true':
+            for zone in zonegroup_info['zones']:
+                zone_info = self.get_zone(zone['name'])
+                self.delete_zone_pools(zone['name'], zone_info)
+
     def create_zone(self, zone_name, zonegroup_name, default, master, endpoints, user):
         if user != 'null':
             access_key, secret_key = _get_user_keys(user)
@@ -835,6 +862,55 @@ class RgwClient(RestClient):
             all_zones_info['default_zone'] = ''  # type: ignore
         return all_zones_info
 
+    def delete_zone(self, zonegroup_name: str, zone_name: str, delete_pools: str):
+        rgw_remove_zone_from_zonegroup_cmd = ['zonegroup', 'remove', '--rgw-zonegroup',
+                                              zonegroup_name, '--rgw-zone', zone_name]
+        rgw_delete_zone_cmd = ['zone', 'delete', '--rgw-zone', zone_name]
+        zone_info = self.get_zone(zone_name)
+        if zonegroup_name:
+            try:
+                exit_code, _, _ = mgr.send_rgwadmin_command(rgw_remove_zone_from_zonegroup_cmd)
+                if exit_code > 0:
+                    raise DashboardException(msg='Unable to remove zone from zonegroup',
+                                             http_status_code=500, component='rgw')
+            except SubprocessError as error:
+                raise DashboardException(error, http_status_code=500, component='rgw')
+            self.update_period()
+        try:
+            exit_code, _, _ = mgr.send_rgwadmin_command(rgw_delete_zone_cmd)
+            if exit_code > 0:
+                raise DashboardException(msg='Unable to delete zone',
+                                         http_status_code=500, component='rgw')
+        except SubprocessError as error:
+            raise DashboardException(error, http_status_code=500, component='rgw')
+        self.update_period()
+        if delete_pools == 'true':
+            self.delete_zone_pools(zone_name, zone_info)
+
+    def delete_zone_pools(self, zone_name, zone_info):
+        # pylint: disable=unused-variable
+        for key, value in zone_info.items():
+            if zone_name in value:
+                if mgr.rados.pool_exists(value):
+                    mgr.rados.delete_pool(value)
+        self.search_and_delete_pools(zone_info['placement_pools'], zone_name)
+
+    def search_and_delete_pools(self, obj, pool_name):
+        if isinstance(obj, dict):
+            # pylint: disable=unused-variable
+            for key, value in obj.items():
+                if isinstance(value, str) and pool_name in value:
+                    if mgr.rados.pool_exists(value):
+                        mgr.rados.delete_pool(value)
+                self.search_and_delete_pools(value, pool_name)
+        elif isinstance(obj, list):
+            for item in obj:
+                self.search_and_delete_pools(item, pool_name)
+        else:
+            if isinstance(obj, str) and pool_name in obj:
+                if mgr.rados.pool_exists(obj):
+                    mgr.rados.delete_pool(obj)
+
     def get_multisite_status(self):
         is_multisite_configured = True
         rgw_realm_list = self.list_realms()