From: Naman Munet Date: Tue, 6 Aug 2024 19:45:44 +0000 (+0530) Subject: mgr/dashboard: RGW multisite sync remove zones fix X-Git-Tag: v19.2.1~213^2 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=c1dadedb6d133a29fa557afdac4b8f47ff8b7a9f;p=ceph.git mgr/dashboard: RGW multisite sync remove zones fix Fixes: https://tracker.ceph.com/issues/66945 Signed-off-by: Naman Munet (cherry picked from commit 5eee7e8105167dc4f0542f62d041fbcb143611d0) --- diff --git a/src/pybind/mgr/dashboard/controllers/rgw.py b/src/pybind/mgr/dashboard/controllers/rgw.py old mode 100644 new mode 100755 index 710681d54b45b..82607994555d5 --- a/src/pybind/mgr/dashboard/controllers/rgw.py +++ b/src/pybind/mgr/dashboard/controllers/rgw.py @@ -178,9 +178,9 @@ class RgwMultisiteController(RESTController): @EndpointDoc("Create or update the sync flow") @CreatePermission def create_sync_flow(self, flow_id: str, flow_type: str, group_id: str, - source_zone: Optional[List[str]] = None, - destination_zone: Optional[List[str]] = None, - zones: Optional[List[str]] = None, + source_zone: Optional[str] = None, + destination_zone: Optional[str] = None, + zones: Optional[Dict[str, List]] = None, bucket_name=''): multisite_instance = RgwMultisite() return multisite_instance.create_sync_flow(group_id, flow_id, flow_type, zones, @@ -200,11 +200,10 @@ class RgwMultisiteController(RESTController): @EndpointDoc("Create or update the sync pipe") @CreatePermission def create_sync_pipe(self, group_id: str, pipe_id: str, + source_zones: Dict[str, Any], + destination_zones: Dict[str, Any], source_bucket: str = '', - source_zones: Optional[List[str]] = None, - destination_zones: Optional[List[str]] = None, - destination_bucket: str = '', - bucket_name: str = ''): + destination_bucket: str = '', bucket_name: str = ''): multisite_instance = RgwMultisite() return multisite_instance.create_sync_pipe(group_id, pipe_id, source_zones, destination_zones, source_bucket, diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/models/rgw-multisite.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/models/rgw-multisite.ts index bc2f8eafe5b45..e385ecd5ada2e 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/models/rgw-multisite.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/models/rgw-multisite.ts @@ -61,3 +61,8 @@ export enum FlowType { directional = 'directional', symmetrical = 'symmetrical' } + +export interface Zone { + added: string[]; + removed: string[]; +} diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-sync-flow-modal/rgw-multisite-sync-flow-modal.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-sync-flow-modal/rgw-multisite-sync-flow-modal.component.html index b7f614ef16b6f..50b0bf321bf21 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-sync-flow-modal/rgw-multisite-sync-flow-modal.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-sync-flow-modal/rgw-multisite-sync-flow-modal.component.html @@ -59,7 +59,23 @@ i18n>Source Zone
- + + This field is required.
@@ -67,7 +83,16 @@ for="destination_zone" i18n>Destination Zone
- + + This field is required.
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-sync-flow-modal/rgw-multisite-sync-flow-modal.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-sync-flow-modal/rgw-multisite-sync-flow-modal.component.ts old mode 100644 new mode 100755 index 126279bf11017..bf243f880d9b5 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-sync-flow-modal/rgw-multisite-sync-flow-modal.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-sync-flow-modal/rgw-multisite-sync-flow-modal.component.ts @@ -2,13 +2,13 @@ import { Component, OnInit } from '@angular/core'; import { UntypedFormControl, Validators } from '@angular/forms'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { RgwDaemonService } from '~/app/shared/api/rgw-daemon.service'; -import { ActionLabelsI18n } from '~/app/shared/constants/app.constants'; +import { ActionLabelsI18n, SucceededActionLabelsI18n } from '~/app/shared/constants/app.constants'; import { CdFormGroup } from '~/app/shared/forms/cd-form-group'; import { NotificationService } from '~/app/shared/services/notification.service'; import { catchError, switchMap } from 'rxjs/operators'; import { RgwZonegroupService } from '~/app/shared/api/rgw-zonegroup.service'; import { RgwDaemon } from '../models/rgw-daemon'; -import { FlowType, RgwZonegroup } from '../models/rgw-multisite'; +import { FlowType, RgwZonegroup, Zone } from '../models/rgw-multisite'; import { of } from 'rxjs'; import { SelectOption } from '~/app/shared/components/select/select-option.model'; import _ from 'lodash'; @@ -35,8 +35,8 @@ export class RgwMultisiteSyncFlowModalComponent implements OnInit { flowType = FlowType; icons = Icons; zones = new ZoneData(false, 'Filter Zones'); - sourceZones = new ZoneData(false, 'Filter Zones'); - destinationZones = new ZoneData(true, 'Filter or Add Zones'); + sourceZone: string; + destinationZone: string; constructor( public activeModal: NgbActiveModal, @@ -44,7 +44,8 @@ export class RgwMultisiteSyncFlowModalComponent implements OnInit { public notificationService: NotificationService, private rgwDaemonService: RgwDaemonService, private rgwZonegroupService: RgwZonegroupService, - private rgwMultisiteService: RgwMultisiteService + private rgwMultisiteService: RgwMultisiteService, + private succeededLabels: SucceededActionLabelsI18n ) {} ngOnInit(): void { @@ -90,13 +91,9 @@ export class RgwMultisiteSyncFlowModalComponent implements OnInit { zones.push(new SelectOption(false, zone.name, '')); }); this.zones.data.available = [...zones]; - this.sourceZones.data.available = [...zones]; if (this.editing) { if (this.groupType === FlowType.symmetrical) { - this.zones.data.selected = this.flowSelectedRow.zones; - } else { - this.destinationZones.data.selected = [this.flowSelectedRow.dest_zone]; - this.sourceZones.data.selected = [this.flowSelectedRow.source_zone]; + this.zones.data.selected = [...this.flowSelectedRow.zones]; } this.zoneSelection(); } @@ -145,15 +142,20 @@ export class RgwMultisiteSyncFlowModalComponent implements OnInit { this.currentFormGroupContext.patchValue({ zones: this.zones.data.selected }); - } else { - this.currentFormGroupContext.patchValue({ - source_zone: this.sourceZones.data.selected, - destination_zone: this.destinationZones.data.selected - }); } } + getZoneData(zoneDataToFilter: string[], zoneDataForCondition: string[]) { + return zoneDataToFilter.filter((zone: string) => !zoneDataForCondition.includes(zone)); + } + + assignZoneValue(zone: string[], selectedZone: string[]) { + return zone.length > 0 ? zone : selectedZone; + } + submit() { + const zones: Zone = { added: [], removed: [] }; + if (this.currentFormGroupContext.invalid) { return; } @@ -162,16 +164,24 @@ export class RgwMultisiteSyncFlowModalComponent implements OnInit { this.currentFormGroupContext.setErrors({ cdSubmitButton: true }); return; } + + if (this.groupType == FlowType.symmetrical) { + if (this.editing) { + zones.removed = this.getZoneData(this.flowSelectedRow.zones, this.zones.data.selected); + zones.added = this.getZoneData(this.zones.data.selected, this.flowSelectedRow.zones); + } + zones.added = this.assignZoneValue(zones.added, this.zones.data.selected); + } this.rgwMultisiteService - .createEditSyncFlow(this.currentFormGroupContext.getRawValue()) + .createEditSyncFlow({ ...this.currentFormGroupContext.getRawValue(), zones: zones }) .subscribe( () => { - const action = this.editing ? 'Modified' : 'Created'; + const action = this.editing ? this.succeededLabels.EDITED : this.succeededLabels.CREATED; this.notificationService.show( NotificationType.success, $localize`${action} Sync Flow '${this.currentFormGroupContext.getValue('flow_id')}'` ); - this.activeModal.close('success'); + this.activeModal.close(NotificationType.success); }, () => { // Reset the 'Submit' button. diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-sync-pipe-modal/rgw-multisite-sync-pipe-modal.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-sync-pipe-modal/rgw-multisite-sync-pipe-modal.component.ts old mode 100644 new mode 100755 index 73bca12ece3aa..da4475fe1cdd0 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-sync-pipe-modal/rgw-multisite-sync-pipe-modal.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-sync-pipe-modal/rgw-multisite-sync-pipe-modal.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { UntypedFormControl, Validators } from '@angular/forms'; import { CdFormGroup } from '~/app/shared/forms/cd-form-group'; -import { RgwZonegroup } from '../models/rgw-multisite'; +import { RgwZonegroup, Zone } from '../models/rgw-multisite'; import { SelectOption } from '~/app/shared/components/select/select-option.model'; import { catchError, switchMap } from 'rxjs/operators'; import { of } from 'rxjs'; @@ -15,6 +15,7 @@ import { RgwMultisiteService } from '~/app/shared/api/rgw-multisite.service'; import { NotificationType } from '~/app/shared/enum/notification-type.enum'; import { NotificationService } from '~/app/shared/services/notification.service'; import { ZoneData } from '../models/rgw-multisite-zone-selector'; +import { SucceededActionLabelsI18n } from '~/app/shared/constants/app.constants'; @Component({ selector: 'cd-rgw-multisite-sync-pipe-modal', @@ -36,7 +37,8 @@ export class RgwMultisiteSyncPipeModalComponent implements OnInit { private rgwDaemonService: RgwDaemonService, private rgwZonegroupService: RgwZonegroupService, private rgwMultisiteService: RgwMultisiteService, - private notificationService: NotificationService + private notificationService: NotificationService, + private succeededLabels: SucceededActionLabelsI18n ) {} ngOnInit(): void { @@ -84,8 +86,13 @@ export class RgwMultisiteSyncPipeModalComponent implements OnInit { this.sourceZones.data.available = [...zones]; if (this.editing) { this.pipeForm.get('pipe_id').disable(); - this.sourceZones.data.selected = this.pipeSelectedRow.source.zones; - this.destZones.data.selected = this.pipeSelectedRow.dest.zones; + this.sourceZones.data.selected = [...this.pipeSelectedRow.source.zones]; + this.destZones.data.selected = [...this.pipeSelectedRow.dest.zones]; + const availableDestZone: SelectOption[] = []; + this.pipeSelectedRow.dest.zones.forEach((zone: string) => { + availableDestZone.push(new SelectOption(true, zone, '')); + }); + this.destZones.data.available = availableDestZone; this.pipeForm.patchValue({ pipe_id: this.pipeSelectedRow.id, source_zones: this.pipeSelectedRow.source.zones, @@ -110,7 +117,18 @@ export class RgwMultisiteSyncPipeModalComponent implements OnInit { } } + getZoneData(zoneDataToFilter: string[], zoneDataForCondition: string[]) { + return zoneDataToFilter.filter((zone: string) => !zoneDataForCondition.includes(zone)); + } + + assignZoneValue(zone: string[], selectedZone: string[]) { + return zone.length > 0 ? zone : selectedZone; + } + submit() { + const sourceZones: Zone = { added: [], removed: [] }; + const destZones: Zone = { added: [], removed: [] }; + if (this.pipeForm.invalid) { return; } @@ -119,20 +137,48 @@ export class RgwMultisiteSyncPipeModalComponent implements OnInit { this.pipeForm.setErrors({ cdSubmitButton: true }); return; } - this.rgwMultisiteService.createEditSyncPipe(this.pipeForm.getRawValue()).subscribe( - () => { - const action = this.editing ? 'Modified' : 'Created'; - this.notificationService.show( - NotificationType.success, - $localize`${action} Sync Pipe '${this.pipeForm.getValue('pipe_id')}'` - ); - this.activeModal.close('success'); - }, - () => { - // Reset the 'Submit' button. - this.pipeForm.setErrors({ cdSubmitButton: true }); - this.activeModal.dismiss(); - } - ); + + if (this.editing) { + destZones.removed = this.getZoneData( + this.pipeSelectedRow.dest.zones, + this.destZones.data.selected + ); + destZones.added = this.getZoneData( + this.destZones.data.selected, + this.pipeSelectedRow.dest.zones + ); + sourceZones.removed = this.getZoneData( + this.pipeSelectedRow.source.zones, + this.sourceZones.data.selected + ); + sourceZones.added = this.getZoneData( + this.sourceZones.data.selected, + this.pipeSelectedRow.source.zones + ); + } + sourceZones.added = this.assignZoneValue(sourceZones.added, this.sourceZones.data.selected); + destZones.added = this.assignZoneValue(destZones.added, this.destZones.data.selected); + + this.rgwMultisiteService + .createEditSyncPipe({ + ...this.pipeForm.getRawValue(), + source_zones: sourceZones, + destination_zones: destZones + }) + .subscribe( + () => { + const action = this.editing ? this.succeededLabels.EDITED : this.succeededLabels.CREATED; + this.notificationService.show( + NotificationType.success, + $localize`${action} Sync Pipe '${this.pipeForm.getValue('pipe_id')}'` + ); + this.activeModal.close(NotificationType.success); + }, + () => { + // Reset the 'Submit' button. + this.pipeForm.setErrors({ cdSubmitButton: true }); + this.activeModal.dismiss(); + } + ); } } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-sync-policy-details/rgw-multisite-sync-policy-details.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-sync-policy-details/rgw-multisite-sync-policy-details.component.html index b9f16ab4d3c7b..8f45ce49bbf8e 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-sync-policy-details/rgw-multisite-sync-policy-details.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-sync-policy-details/rgw-multisite-sync-policy-details.component.html @@ -69,14 +69,6 @@ - - Due to some internal dependencies these actions are disabled, it will get enabled once the issue gets resolved. - @@ -118,6 +110,6 @@ - Are you sure you want to delete these Flow? + Deleting {{ resourceType | upperFirst }} may disrupt data synchronization diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-sync-policy-details/rgw-multisite-sync-policy-details.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-sync-policy-details/rgw-multisite-sync-policy-details.component.ts old mode 100644 new mode 100755 index b93c4ae788ec4..16cf5da4df8f5 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-sync-policy-details/rgw-multisite-sync-policy-details.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-sync-policy-details/rgw-multisite-sync-policy-details.component.ts @@ -16,6 +16,12 @@ import { TableComponent } from '~/app/shared/datatable/table/table.component'; import { RgwMultisiteSyncFlowModalComponent } from '../rgw-multisite-sync-flow-modal/rgw-multisite-sync-flow-modal.component'; import { FlowType } from '../models/rgw-multisite'; import { RgwMultisiteSyncPipeModalComponent } from '../rgw-multisite-sync-pipe-modal/rgw-multisite-sync-pipe-modal.component'; +import { NotificationType } from '~/app/shared/enum/notification-type.enum'; + +enum MultisiteResourceType { + flow = 'flow', + pipe = 'pipe' +} @Component({ selector: 'cd-rgw-multisite-sync-policy-details', @@ -33,6 +39,7 @@ export class RgwMultisiteSyncPolicyDetailsComponent implements OnChanges { @ViewChild('deleteTpl', { static: true }) deleteTpl: TemplateRef; + resourceType: MultisiteResourceType = MultisiteResourceType.flow; flowType = FlowType; modalRef: NgbModalRef; symmetricalFlowData: any = []; @@ -134,22 +141,17 @@ export class RgwMultisiteSyncPolicyDetailsComponent implements OnChanges { click: () => this.openModal(FlowType.directional), canBePrimary: (selection: CdTableSelection) => !selection.hasSelection }; - const dirEditAction: CdTableAction = { - permission: 'update', - icon: Icons.edit, - name: this.actionLabels.EDIT, - click: () => this.openModal(FlowType.directional, true), - disable: () => true // TODO: disabling 'edit' as we are not getting flow ID from backend which is needed for edit - }; const dirDeleteAction: CdTableAction = { permission: 'delete', icon: Icons.destroy, - disable: () => true, // TODO: disabling 'delete' as we are not getting flow ID from backend which is needed for deletion + // TODO: disabling 'delete' as we are not getting flow_id from backend which is needed for deletion + disable: () => + 'Deleting the directional flow is disabled in the UI. Please use CLI to delete the directional flow', name: this.actionLabels.DELETE, click: () => this.deleteFlow(FlowType.directional), - canBePrimary: (selection: CdTableSelection) => selection.hasMultiSelection + canBePrimary: (selection: CdTableSelection) => selection.hasSelection }; - this.dirFlowTableActions = [dirAddAction, dirEditAction, dirDeleteAction]; + this.dirFlowTableActions = [dirAddAction, dirDeleteAction]; const pipeAddAction: CdTableAction = { permission: 'create', icon: Icons.add, @@ -227,13 +229,14 @@ export class RgwMultisiteSyncPolicyDetailsComponent implements OnChanges { try { const res = await this.modalRef.result; - if (res === 'success') { + if (res === NotificationType.success) { this.loadData(); } } catch (err) {} } deleteFlow(flowType: FlowType) { + this.resourceType = MultisiteResourceType.flow; let selection = this.symFlowSelection; if (flowType === FlowType.directional) { selection = this.dirFlowSelection; @@ -295,13 +298,14 @@ export class RgwMultisiteSyncPolicyDetailsComponent implements OnChanges { try { const res = await this.modalRef.result; - if (res === 'success') { + if (res === NotificationType.success) { this.loadData(); } } catch (err) {} } deletePipe() { + this.resourceType = MultisiteResourceType.pipe; const pipeIds = this.pipeSelection.selected.map((pipe: any) => pipe.id); this.modalService.show(CriticalConfirmationModalComponent, { itemDescription: this.pipeSelection.hasSingleSelection ? $localize`Pipe` : $localize`Pipes`, diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw.module.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw.module.ts index aa51e7502bb53..6c02f82cc7fa1 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw.module.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw.module.ts @@ -220,11 +220,13 @@ const routes: Routes = [ { path: '', redirectTo: 'configuration', pathMatch: 'full' }, { path: 'configuration', - component: RgwMultisiteDetailsComponent + component: RgwMultisiteDetailsComponent, + data: { breadcrumbs: 'Configuration' } }, { path: 'sync-policy', component: RgwMultisiteSyncPolicyComponent, + data: { breadcrumbs: 'Sync-policy' }, children: [ { path: `${URLVerbs.CREATE}`, diff --git a/src/pybind/mgr/dashboard/openapi.yaml b/src/pybind/mgr/dashboard/openapi.yaml index 2e82bf220ce5b..a006d41ed685d 100644 --- a/src/pybind/mgr/dashboard/openapi.yaml +++ b/src/pybind/mgr/dashboard/openapi.yaml @@ -10891,6 +10891,8 @@ paths: required: - group_id - pipe_id + - source_zones + - destination_zones type: object responses: '200': diff --git a/src/pybind/mgr/dashboard/services/rgw_client.py b/src/pybind/mgr/dashboard/services/rgw_client.py old mode 100644 new mode 100755 index b604ba3e41cdf..c07b1260167a2 --- a/src/pybind/mgr/dashboard/services/rgw_client.py +++ b/src/pybind/mgr/dashboard/services/rgw_client.py @@ -1973,31 +1973,49 @@ class RgwMultisite: raise DashboardException(error, http_status_code=500, component='rgw') def create_sync_flow(self, group_id: str, flow_id: str, flow_type: str, - zones: Optional[List[str]] = None, bucket_name: str = '', - source_zone: Optional[List[str]] = None, - destination_zone: Optional[List[str]] = None): + zones: Optional[Dict[str, List]] = None, bucket_name: str = '', + source_zone: Optional[str] = None, + destination_zone: Optional[str] = None): rgw_sync_policy_cmd = ['sync', 'group', 'flow', 'create', '--group-id', group_id, '--flow-id', flow_id, '--flow-type', SyncFlowTypes[flow_type].value] + if bucket_name: + rgw_sync_policy_cmd += ['--bucket', bucket_name] + if SyncFlowTypes[flow_type].value == 'directional': + if source_zone is not None: - rgw_sync_policy_cmd += ['--source-zone', ','.join(source_zone)] + rgw_sync_policy_cmd += ['--source-zone', source_zone] + if destination_zone is not None: - rgw_sync_policy_cmd += ['--dest-zone', ','.join(destination_zone)] + rgw_sync_policy_cmd += ['--dest-zone', destination_zone] + + logger.info("Creating directional flow! %s", rgw_sync_policy_cmd) + try: + exit_code, _, err = mgr.send_rgwadmin_command(rgw_sync_policy_cmd) + if exit_code > 0: + raise DashboardException(f'Unable to create sync flow: {err}', + http_status_code=500, component='rgw') + except SubprocessError as error: + raise DashboardException(error, http_status_code=500, component='rgw') + else: - if zones: - rgw_sync_policy_cmd += ['--zones', ','.join(zones)] + if zones is not None and (zones['added'] or zones['removed']): + if len(zones['added']) > 0: + rgw_sync_policy_cmd += ['--zones', ','.join(zones['added'])] - if bucket_name: - rgw_sync_policy_cmd += ['--bucket', bucket_name] + logger.info("Creating symmetrical flow! %s", rgw_sync_policy_cmd) + try: + exit_code, _, err = mgr.send_rgwadmin_command(rgw_sync_policy_cmd) + if exit_code > 0: + raise DashboardException(f'Unable to create sync flow: {err}', + http_status_code=500, component='rgw') + except SubprocessError as error: + raise DashboardException(error, http_status_code=500, component='rgw') - try: - exit_code, _, err = mgr.send_rgwadmin_command(rgw_sync_policy_cmd) - if exit_code > 0: - raise DashboardException(f'Unable to create sync flow: {err}', - http_status_code=500, component='rgw') - except SubprocessError as error: - raise DashboardException(error, http_status_code=500, component='rgw') + if len(zones['removed']) > 0: + self.remove_sync_flow(group_id, flow_id, flow_type, source_zone, + destination_zone, zones['removed'], bucket_name) def remove_sync_flow(self, group_id: str, flow_id: str, flow_type: str, source_zone='', destination_zone='', @@ -2014,6 +2032,7 @@ class RgwMultisite: if bucket_name: rgw_sync_policy_cmd += ['--bucket', bucket_name] + logger.info("Removing sync flow! %s", rgw_sync_policy_cmd) try: exit_code, _, err = mgr.send_rgwadmin_command(rgw_sync_policy_cmd) if exit_code > 0: @@ -2023,36 +2042,44 @@ class RgwMultisite: raise DashboardException(error, http_status_code=500, component='rgw') def create_sync_pipe(self, group_id: str, pipe_id: str, - source_zones: Optional[List[str]] = None, - destination_zones: Optional[List[str]] = None, + source_zones: Dict[str, Any], + destination_zones: Dict[str, Any], source_bucket: str = '', destination_bucket: str = '', bucket_name: str = ''): - rgw_sync_policy_cmd = ['sync', 'group', 'pipe', 'create', - '--group-id', group_id, '--pipe-id', pipe_id] - if bucket_name: - rgw_sync_policy_cmd += ['--bucket', bucket_name] + if source_zones['added'] or destination_zones['added']: + rgw_sync_policy_cmd = ['sync', 'group', 'pipe', 'create', + '--group-id', group_id, '--pipe-id', pipe_id] - if source_zones: - rgw_sync_policy_cmd += ['--source-zones', ','.join(source_zones)] + if bucket_name: + rgw_sync_policy_cmd += ['--bucket', bucket_name] - if destination_zones: - rgw_sync_policy_cmd += ['--dest-zones', ','.join(destination_zones)] + if source_bucket: + rgw_sync_policy_cmd += ['--source-bucket', source_bucket] - if source_bucket: - rgw_sync_policy_cmd += ['--source-bucket', source_bucket] + if destination_bucket: + rgw_sync_policy_cmd += ['--dest-bucket', destination_bucket] - if destination_bucket: - rgw_sync_policy_cmd += ['--dest-bucket', destination_bucket] + if source_zones['added']: + rgw_sync_policy_cmd += ['--source-zones', ','.join(source_zones['added'])] - try: - exit_code, _, err = mgr.send_rgwadmin_command(rgw_sync_policy_cmd) - if exit_code > 0: - raise DashboardException(f'Unable to create sync pipe: {err}', - http_status_code=500, component='rgw') - except SubprocessError as error: - raise DashboardException(error, http_status_code=500, component='rgw') + if destination_zones['added']: + rgw_sync_policy_cmd += ['--dest-zones', ','.join(destination_zones['added'])] + + logger.info("Creating sync pipe!") + try: + exit_code, _, err = mgr.send_rgwadmin_command(rgw_sync_policy_cmd) + if exit_code > 0: + raise DashboardException(f'Unable to create sync pipe: {err}', + http_status_code=500, component='rgw') + except SubprocessError as error: + raise DashboardException(error, http_status_code=500, component='rgw') + + if source_zones['removed'] or destination_zones['removed']: + self.remove_sync_pipe(group_id, pipe_id, source_zones['removed'], + destination_zones['removed'], destination_bucket, + bucket_name) def remove_sync_pipe(self, group_id: str, pipe_id: str, source_zones: Optional[List[str]] = None, @@ -2073,6 +2100,7 @@ class RgwMultisite: if destination_bucket: rgw_sync_policy_cmd += ['--dest-bucket', destination_bucket] + logger.info("Removing sync pipe! %s", rgw_sync_policy_cmd) try: exit_code, _, err = mgr.send_rgwadmin_command(rgw_sync_policy_cmd) if exit_code > 0: @@ -2093,10 +2121,12 @@ class RgwMultisite: # create a sync flow with source and destination zones self.create_sync_flow(_SYNC_GROUP_ID, _SYNC_FLOW_ID, SyncFlowTypes.symmetrical.value, - zones=zone_names) + zones={'added': zone_names, 'removed': []}) # create a sync pipe with source and destination zones - self.create_sync_pipe(_SYNC_GROUP_ID, _SYNC_PIPE_ID, source_zones=['*'], - destination_zones=['*'], source_bucket='*', destination_bucket='*') + self.create_sync_pipe(_SYNC_GROUP_ID, _SYNC_PIPE_ID, + source_zones={'added': '*', 'removed': []}, + destination_zones={'added': '*', 'removed': []}, source_bucket='*', + destination_bucket='*') # period update --commit self.update_period()