except NoRgwDaemonsException as e:
raise DashboardException(e, http_status_code=404, component='rgw')
- def delete(self, zonegroup_name, delete_pools, daemon_name=None):
+ def delete(self, zonegroup_name, delete_pools, pools: Optional[List[str]] = None,
+ daemon_name=None):
+ if pools is None:
+ pools = []
try:
instance = RgwClient.admin_instance(daemon_name)
- result = instance.delete_zonegroup(zonegroup_name, delete_pools)
+ result = instance.delete_zonegroup(zonegroup_name, delete_pools, pools)
return result
except NoRgwDaemonsException as e:
raise DashboardException(e, http_status_code=404, component='rgw')
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):
+ def delete(self, zone_name, delete_pools, pools: Optional[List[str]] = None,
+ zonegroup_name=None, daemon_name=None):
+ if pools is None:
+ pools = []
+ if zonegroup_name is None:
+ zonegroup_name = ''
try:
instance = RgwClient.admin_instance(daemon_name)
- result = instance.delete_zone(zonegroup_name, zone_name, delete_pools)
+ result = instance.delete_zone(zone_name, delete_pools, pools, zonegroup_name)
return result
except NoRgwDaemonsException as e:
raise DashboardException(e, http_status_code=404, component='rgw')
<form name="zoneForm"
[formGroup]="zoneForm"
novalidate>
- <div class="custom-control ms-4 mt-4">
+ <div class="modal-body ms-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>
+ This will delete your <strong>{{zone?.name}}</strong> Zone.
+ </label>
+ <ng-container *ngIf="includedPools.size">
+ <label class="mt-3"
+ i18n>
+ Do you want to delete the associated pools with the <strong>{{zone?.name}}</strong> Zone?</label>
+ <label class="mb-4"
+ i18n>
+ This will delete the following pools and any data stored in these pools:</label>
+ <strong *ngFor="let pool of includedPools"
+ class="block">{{ pool }}</strong>
+ <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>
</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">
-strong {
+.block {
display: block;
}
-import { Component, OnInit } from '@angular/core';
+import { AfterViewInit, Component, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
+import { PoolService } from '~/app/shared/api/pool.service';
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';
templateUrl: './rgw-multisite-zone-deletion-form.component.html',
styleUrls: ['./rgw-multisite-zone-deletion-form.component.scss']
})
-export class RgwMultisiteZoneDeletionFormComponent implements OnInit {
+export class RgwMultisiteZoneDeletionFormComponent implements OnInit, AfterViewInit {
zoneData$: any;
+ poolList$: any;
zone: any;
zoneForm: CdFormGroup;
displayText: boolean = false;
+ includedPools: Set<string> = new Set<string>();
constructor(
public activeModal: NgbActiveModal,
public actionLabels: ActionLabelsI18n,
public notificationService: NotificationService,
- private rgwZoneService: RgwZoneService
+ private rgwZoneService: RgwZoneService,
+ private poolService: PoolService
) {
this.createForm();
}
ngOnInit(): void {
this.zoneData$ = this.rgwZoneService.get(this.zone);
+ this.poolList$ = this.poolService.getList();
+ }
+
+ ngAfterViewInit(): void {
+ this.updateIncludedPools();
}
createForm() {
submit() {
this.rgwZoneService
- .delete(this.zone.parent, this.zone.name, this.zoneForm.value.deletePools)
+ .delete(this.zone.name, this.zoneForm.value.deletePools, this.includedPools, this.zone.parent)
.subscribe(
() => {
this.notificationService.show(
showDangerText() {
this.displayText = !this.displayText;
}
+
+ updateIncludedPools(): void {
+ if (!this.zoneData$ || !this.poolList$) {
+ return;
+ }
+ this.zoneData$.subscribe((data: any) => {
+ this.poolList$.subscribe((poolList: any) => {
+ for (const pool of poolList) {
+ for (const zonePool of Object.values(data)) {
+ if (typeof zonePool === 'string' && zonePool.includes(pool.pool_name)) {
+ this.includedPools.add(pool.pool_name);
+ } else if (Array.isArray(zonePool) && zonePool[0].val) {
+ for (const item of zonePool) {
+ const val = item.val;
+ if (val.storage_classes.STANDARD.data_pool === pool.pool_name) {
+ this.includedPools.add(val.storage_classes.STANDARD.data_pool);
+ }
+ if (val.data_extra_pool === pool.pool_name) {
+ this.includedPools.add(val.data_extra_pool);
+ }
+ if (val.index_pool === pool.pool_name) {
+ this.includedPools.add(val.index_pool);
+ }
+ }
+ }
+ }
+ }
+ });
+ });
+ }
}
<form name="zonegroupForm"
[formGroup]="zonegroupForm"
novalidate>
- <div class="modal-body ms-4 mt-4">
+ <div class="modal-body ms-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>
+ This will delete your <strong>{{zonegroup?.name}}</strong> Zonegroup.
+ </label>
+ <ng-container *ngIf="zonesList.length > 0">
+ <label class="mt-3"
+ i18n>
+ Do you want to delete the associated zones and pools with the <strong>{{zonegroup?.name}}</strong> Zonegroup?</label>
+ <ng-container *ngIf="includedPools.size > 0">
+ <label i18n>
+ This will delete the following:</label>
+ </ng-container>
+ <strong class="mt-3 mb-2 h5 block">Zones:</strong>
<div id="scroll">
- <strong *ngFor="let zone of data.zones">{{zone?.name}}</strong>
+ <strong *ngFor="let zone of zonesList"
+ class="block">{{zone}}</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>
+ <ng-container *ngIf="includedPools.size > 0">
+ <strong class="mt-3 mb-2 h5 block">Pools:</strong>
+ <div id="scroll"
+ class="mb-2">
+ <strong *ngFor="let pool of includedPools"
+ class="block">{{ pool }}</strong>
+ </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()">
+ <ng-container *ngIf="includedPools.size > 0 else noPoolsConfirmation">
+ <label class="custom-control-label"
+ for="deletePools"
+ i18n>Yes, I want to delete the zones and their pools.</label>
+ </ng-container>
+ </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>
</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">
</ng-container>
</cd-modal>
+
+<ng-template #noPoolsConfirmation>
+ <label class="custom-control-label"
+ for="deletePools"
+ i18n>Yes, I want to delete the zones.</label>
+</ng-template>
-strong {
+.block {
display: block;
}
-import { Component, OnInit } from '@angular/core';
+import { AfterViewInit, Component, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
+import { PoolService } from '~/app/shared/api/pool.service';
+import { RgwZoneService } from '~/app/shared/api/rgw-zone.service';
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';
templateUrl: './rgw-multisite-zonegroup-deletion-form.component.html',
styleUrls: ['./rgw-multisite-zonegroup-deletion-form.component.scss']
})
-export class RgwMultisiteZonegroupDeletionFormComponent implements OnInit {
+export class RgwMultisiteZonegroupDeletionFormComponent implements OnInit, AfterViewInit {
zonegroupData$: any;
+ poolList$: any;
+ zonesPools: Array<any> = [];
zonegroup: any;
+ zonesList: Array<any> = [];
zonegroupForm: CdFormGroup;
displayText: boolean = false;
+ includedPools: Set<string> = new Set<string>();
constructor(
public activeModal: NgbActiveModal,
public actionLabels: ActionLabelsI18n,
public notificationService: NotificationService,
- private rgwZonegroupService: RgwZonegroupService
+ private rgwZonegroupService: RgwZonegroupService,
+ private poolService: PoolService,
+ private rgwZoneService: RgwZoneService
) {
this.createForm();
}
ngOnInit(): void {
this.zonegroupData$ = this.rgwZonegroupService.get(this.zonegroup);
+ this.poolList$ = this.poolService.getList();
+ }
+
+ ngAfterViewInit(): void {
+ this.updateIncludedPools();
}
createForm() {
submit() {
this.rgwZonegroupService
- .delete(this.zonegroup.name, this.zonegroupForm.value.deletePools)
+ .delete(this.zonegroup.name, this.zonegroupForm.value.deletePools, this.includedPools)
.subscribe(() => {
this.notificationService.show(
NotificationType.success,
}
showDangerText() {
- this.displayText = !this.displayText;
+ if (this.includedPools.size > 0) {
+ this.displayText = !this.displayText;
+ }
+ }
+
+ updateIncludedPools(): void {
+ if (!this.zonegroupData$ || !this.poolList$) {
+ return;
+ }
+
+ this.zonegroupData$.subscribe((zgData: any) => {
+ for (const zone of zgData.zones) {
+ this.zonesList.push(zone.name);
+ this.rgwZoneService.get(zone).subscribe((zonesPools: any) => {
+ this.poolList$.subscribe((poolList: any) => {
+ for (const zonePool of Object.values(zonesPools)) {
+ for (const pool of poolList) {
+ if (typeof zonePool === 'string' && zonePool.includes(pool.pool_name)) {
+ this.includedPools.add(pool.pool_name);
+ } else if (Array.isArray(zonePool) && zonePool[0].val) {
+ for (const item of zonePool) {
+ const val = item.val;
+ if (val.storage_classes.STANDARD.data_pool === pool.pool_name) {
+ this.includedPools.add(val.storage_classes.STANDARD.data_pool);
+ }
+ if (val.data_extra_pool === pool.pool_name) {
+ this.includedPools.add(val.data_extra_pool);
+ }
+ if (val.index_pool === pool.pool_name) {
+ this.includedPools.add(val.index_pool);
+ }
+ }
+ }
+ }
+ }
+ });
+ });
+ }
+ });
}
}
</span>
<div class="btn-group align-inline-btns"
*ngIf="node.isFocused"
- [title]="title"
role="group">
- <button type="button"
- class="btn btn-light dropdown-toggle-split ms-1"
- (click)="openModal(node, true)"
- [disabled]="getDisable()">
- <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 [title]="editTitle"
+ i18n-title>
+ <button type="button"
+ class="btn btn-light dropdown-toggle-split ms-1"
+ (click)="openModal(node, true)"
+ [disabled]="getDisable()">
+ <i [ngClass]="[icons.edit]"></i>
+ </button>
+ </div>
+ <div [title]="deleteTitle"
+ i18n-title>
+ <button type="button"
+ class="btn btn-light ms-1"
+ [disabled]="isDeleteDisabled(node)"
+ (click)="delete(node)">
+ <i [ngClass]="[icons.destroy]"></i>
+ </button>
+ </div>
</div>
</ng-template>
</tree-root>
defaultZoneId = '';
multisiteInfo: object[] = [];
defaultsInfo: string[] = [];
- title: string = 'Edit';
showMigrateAction: boolean = false;
+ editTitle: string = 'Edit';
+ deleteTitle: string = 'Delete';
constructor(
private modalService: ModalService,
}
});
if (!isMasterZone) {
- this.title =
+ this.editTitle =
'Please create a master zone for each existing zonegroup to enable this feature';
return this.messages.noMasterZone;
} else {
- this.title = 'Edit';
+ this.editTitle = 'Edit';
return false;
}
}
return this.showMigrateAction;
}
+ isDeleteDisabled(node: TreeNode): boolean {
+ let disable: boolean = false;
+ let masterZonegroupCount: number = 0;
+ if (node.data.type === 'realm' && node.data.is_default && this.realms.length < 2) {
+ disable = true;
+ }
+
+ if (node.data.type === 'zonegroup') {
+ if (this.zonegroups.length < 2) {
+ this.deleteTitle = 'You can not delete the only zonegroup available';
+ disable = true;
+ } else if (node.data.is_default) {
+ this.deleteTitle = 'You can not delete the default zonegroup';
+ disable = true;
+ } else if (node.data.is_master) {
+ for (let zonegroup of this.zonegroups) {
+ if (zonegroup.is_master === true) {
+ masterZonegroupCount++;
+ if (masterZonegroupCount > 1) break;
+ }
+ }
+ if (masterZonegroupCount < 2) {
+ this.deleteTitle = 'You can not delete the only master zonegroup available';
+ disable = true;
+ }
+ }
+ }
+
+ if (node.data.type === 'zone') {
+ if (this.zones.length < 2) {
+ this.deleteTitle = 'You can not delete the only zone available';
+ disable = true;
+ } else if (node.data.is_default) {
+ this.deleteTitle = 'You can not delete the default zone';
+ disable = true;
+ } else if (node.data.is_master && node.data.zone_zonegroup.zones.length < 2) {
+ this.deleteTitle =
+ 'You can not delete the master zone as there are no more zones in this zonegroup';
+ disable = true;
+ }
+ }
+
+ if (!disable) {
+ this.deleteTitle = 'Delete';
+ }
+
+ return disable;
+ }
+
delete(node: TreeNode) {
if (node.data.type === 'realm') {
this.modalRef = this.modalService.show(CriticalConfirmationModalComponent, {
});
}
- delete(zonegroupName: string, zoneName: string, deletePools: boolean): Observable<any> {
+ delete(
+ zoneName: string,
+ deletePools: boolean,
+ pools: Set<string>,
+ zonegroupName: string
+ ): Observable<any> {
return this.rgwDaemonService.request((params: HttpParams) => {
params = params.appendAll({
- zonegroup_name: zonegroupName,
zone_name: zoneName,
- delete_pools: deletePools
+ delete_pools: deletePools,
+ pools: Array.from(pools.values()),
+ zonegroup_name: zonegroupName
});
return this.http.delete(`${this.url}/${zoneName}`, { params: params });
});
});
}
- delete(zonegroupName: string, deletePools: boolean): Observable<any> {
+ delete(zonegroupName: string, deletePools: boolean, pools: Set<string>): Observable<any> {
return this.rgwDaemonService.request((params: HttpParams) => {
params = params.appendAll({
zonegroup_name: zonegroupName,
- delete_pools: deletePools
+ delete_pools: deletePools,
+ pools: Array.from(pools.values())
});
return this.http.delete(`${this.url}/${zonegroupName}`, { params: params });
});
schema:
type: string
- in: query
- name: zonegroup_name
+ name: delete_pools
required: true
schema:
type: string
- - in: query
- name: delete_pools
- required: true
+ - allowEmptyValue: true
+ in: query
+ name: pools
+ schema:
+ type: string
+ - allowEmptyValue: true
+ in: query
+ name: zonegroup_name
schema:
type: string
- allowEmptyValue: true
required: true
schema:
type: string
+ - allowEmptyValue: true
+ in: query
+ name: pools
+ schema:
+ type: string
- allowEmptyValue: true
in: query
name: daemon_name
all_zonegroups_info['default_zonegroup'] = '' # type: ignore
return all_zonegroups_info
- def delete_zonegroup(self, zonegroup_name: str, delete_pools: str):
+ def delete_zonegroup(self, zonegroup_name: str, delete_pools: str, pools: List[str]):
if delete_pools == 'true':
zonegroup_info = self.get_zonegroup(zonegroup_name)
rgw_delete_zonegroup_cmd = ['zonegroup', 'delete', '--rgw-zonegroup', zonegroup_name]
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)
+ self.delete_zone(zone['name'], 'true', pools)
def create_zone(self, zone_name, zonegroup_name, default, master, endpoints, user,
createSystemUser, master_zone_of_master_zonegroup):
all_zones_info['default_zone'] = '' # type: ignore
return all_zones_info
- def delete_zone(self, zonegroup_name: str, zone_name: str, delete_pools: str):
+ def delete_zone(self, zone_name: str, delete_pools: str, pools: List[str],
+ zonegroup_name: 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)
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)
+ self.delete_pools(pools)
+
+ def delete_pools(self, pools):
+ for pool in pools:
+ if mgr.rados.pool_exists(pool):
+ mgr.rados.delete_pool(pool)
def get_multisite_status(self):
is_multisite_configured = True