From c59f5afa7b311d27edc8f9399ed1845993219d14 Mon Sep 17 00:00:00 2001 From: Aashish Sharma Date: Tue, 4 Nov 2025 14:19:03 +0530 Subject: [PATCH] mgr/dashboard: allow deletion of non-default zone and zonegroup Fixes: https://tracker.ceph.com/issues/73708 Signed-off-by: Aashish Sharma --- src/pybind/mgr/dashboard/controllers/rgw.py | 12 +++++++---- ...-multisite-zone-deletion-form.component.ts | 8 +++++++- ...isite-zonegroup-deletion-form.component.ts | 7 ++++++- .../src/app/shared/api/rgw-zone.service.ts | 6 ++++-- .../app/shared/api/rgw-zonegroup.service.ts | 10 ++++++++-- src/pybind/mgr/dashboard/openapi.yaml | 10 ++++++++++ .../mgr/dashboard/services/rgw_client.py | 20 +++++++++++++------ 7 files changed, 57 insertions(+), 16 deletions(-) diff --git a/src/pybind/mgr/dashboard/controllers/rgw.py b/src/pybind/mgr/dashboard/controllers/rgw.py index c9eb6badd30..1b9d9fa36de 100755 --- a/src/pybind/mgr/dashboard/controllers/rgw.py +++ b/src/pybind/mgr/dashboard/controllers/rgw.py @@ -1459,12 +1459,14 @@ class RgwZonegroup(RESTController): result = multisite_instance.get_all_zonegroups_info() return result - def delete(self, zonegroup_name, delete_pools, pools: Optional[List[str]] = None): + def delete(self, zonegroup_name, delete_pools, pools: Optional[List[str]] = None, + realm_name: Optional[str] = None): if pools is None: pools = [] try: multisite_instance = RgwMultisite() - result = multisite_instance.delete_zonegroup(zonegroup_name, delete_pools, pools) + result = multisite_instance.delete_zonegroup(zonegroup_name, delete_pools, + pools, realm_name) return result except NoRgwDaemonsException as e: raise DashboardException(e, http_status_code=404, component='rgw') @@ -1516,14 +1518,16 @@ class RgwZone(RESTController): return result def delete(self, zone_name, delete_pools, pools: Optional[List[str]] = None, - zonegroup_name=None): + zonegroup_name=None, realm_name: Optional[str] = None): if pools is None: pools = [] if zonegroup_name is None: zonegroup_name = '' try: multisite_instance = RgwMultisite() - result = multisite_instance.delete_zone(zone_name, delete_pools, pools, zonegroup_name) + result = multisite_instance.delete_zone(zone_name, delete_pools, + pools, zonegroup_name, + realm_name) 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.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/models/rgw-multisite-zone-deletion-form/rgw-multisite-zone-deletion-form.component.ts index 44e832d3933..c23eaf3dfcf 100644 --- 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 @@ -48,7 +48,13 @@ export class RgwMultisiteZoneDeletionFormComponent implements OnInit, AfterViewI submit() { this.rgwZoneService - .delete(this.zone.name, this.zoneForm.value.deletePools, this.includedPools, this.zone.parent) + .delete( + this.zone.name, + this.zoneForm.value.deletePools, + this.includedPools, + this.zone.parent, + this.zone.second_parent + ) .subscribe( () => { this.notificationService.show( 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 index f96ec0ccffa..247c6398e38 100644 --- 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 @@ -52,7 +52,12 @@ export class RgwMultisiteZonegroupDeletionFormComponent implements OnInit, After submit() { this.rgwZonegroupService - .delete(this.zonegroup.name, this.zonegroupForm.value.deletePools, this.includedPools) + .delete( + this.zonegroup.name, + this.zonegroupForm.value.deletePools, + this.includedPools, + this.zonegroup.parent + ) .subscribe(() => { this.notificationService.show( NotificationType.success, diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-zone.service.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-zone.service.ts index bfa651fa1e2..c958b2e3928 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-zone.service.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-zone.service.ts @@ -49,14 +49,16 @@ export class RgwZoneService { zoneName: string, deletePools: boolean, pools: Set, - zonegroupName: string + zonegroupName: string, + realmName: string ): Observable { let params = new HttpParams(); params = params.appendAll({ zone_name: zoneName, delete_pools: deletePools, pools: Array.from(pools.values()), - zonegroup_name: zonegroupName + zonegroup_name: zonegroupName, + realm_name: realmName }); return this.http.delete(`${this.url}/${zoneName}`, { params: params }); } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-zonegroup.service.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-zonegroup.service.ts index 7f795c1d1d8..c1120a906f2 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-zonegroup.service.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-zonegroup.service.ts @@ -59,12 +59,18 @@ export class RgwZonegroupService { return this.http.get(`${this.url}/get_all_zonegroups_info`); } - delete(zonegroupName: string, deletePools: boolean, pools: Set): Observable { + delete( + zonegroupName: string, + deletePools: boolean, + pools: Set, + realmName: string + ): Observable { let params = new HttpParams(); params = params.appendAll({ zonegroup_name: zonegroupName, delete_pools: deletePools, - pools: Array.from(pools.values()) + pools: Array.from(pools.values()), + realm_name: realmName }); return this.http.delete(`${this.url}/${zonegroupName}`, { params: params }); } diff --git a/src/pybind/mgr/dashboard/openapi.yaml b/src/pybind/mgr/dashboard/openapi.yaml index 62414d628e7..b7cad47edb7 100755 --- a/src/pybind/mgr/dashboard/openapi.yaml +++ b/src/pybind/mgr/dashboard/openapi.yaml @@ -15338,6 +15338,11 @@ paths: name: zonegroup_name schema: type: string + - allowEmptyValue: true + in: query + name: realm_name + schema: + type: string responses: '202': content: @@ -15718,6 +15723,11 @@ paths: name: pools schema: type: string + - allowEmptyValue: true + in: query + name: realm_name + schema: + type: string responses: '202': content: diff --git a/src/pybind/mgr/dashboard/services/rgw_client.py b/src/pybind/mgr/dashboard/services/rgw_client.py index 3b62eb7b0d4..1ea1f0e63de 100755 --- a/src/pybind/mgr/dashboard/services/rgw_client.py +++ b/src/pybind/mgr/dashboard/services/rgw_client.py @@ -2035,7 +2035,9 @@ class RgwMultisite: all_zonegroups_info['default_zonegroup'] = '' # type: ignore return all_zonegroups_info - def delete_zonegroup(self, zonegroup_name: str, delete_pools: str, pools: List[str]): + def delete_zonegroup(self, zonegroup_name: str, + delete_pools: str, pools: List[str], + realm_name: Optional[str] = None): if delete_pools == 'true': zonegroup_info = self.get_zonegroup(zonegroup_name) rgw_delete_zonegroup_cmd = ['zonegroup', 'delete', '--rgw-zonegroup', zonegroup_name] @@ -2046,7 +2048,7 @@ class RgwMultisite: http_status_code=500, component='rgw') except SubprocessError as error: raise DashboardException(error, http_status_code=500, component='rgw') - self.update_period() + self.update_period(realm_name=realm_name) if delete_pools == 'true': for zone in zonegroup_info['zones']: self.delete_zone(zone['name'], 'true', pools) @@ -2346,8 +2348,14 @@ class RgwMultisite: else: self.add_placement_targets(new_zonegroup_name, placement_targets) - def update_period(self): + def update_period(self, realm_name=None, realm_id=None): rgw_update_period_cmd = ['period', 'update', '--commit'] + if realm_name: + rgw_update_period_cmd.append('--rgw-realm') + rgw_update_period_cmd.append(realm_name) + if realm_id: + rgw_update_period_cmd.append('--realm-id') + rgw_update_period_cmd.append(realm_id) try: exit_code, _, err = mgr.send_rgwadmin_command(rgw_update_period_cmd) if exit_code > 0: @@ -2556,7 +2564,7 @@ class RgwMultisite: return all_zones_info def delete_zone(self, zone_name: str, delete_pools: str, pools: List[str], - zonegroup_name: str = '',): + zonegroup_name: str = '', realm_name: Optional[str] = None): 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] @@ -2568,7 +2576,7 @@ class RgwMultisite: http_status_code=500, component='rgw') except SubprocessError as error: raise DashboardException(error, http_status_code=500, component='rgw') - self.update_period() + self.update_period(realm_name=realm_name) try: exit_code, _, _ = mgr.send_rgwadmin_command(rgw_delete_zone_cmd) if exit_code > 0: @@ -2576,7 +2584,7 @@ class RgwMultisite: http_status_code=500, component='rgw') except SubprocessError as error: raise DashboardException(error, http_status_code=500, component='rgw') - self.update_period() + self.update_period(realm_name=realm_name) if delete_pools == 'true': self.delete_pools(pools) -- 2.39.5