return None
rgw_client = RgwClient.instance(owner, daemon_name)
- zonegroup_name = RgwClient.admin_instance(daemon_name=daemon_name).get_default_zonegroup()
- policy_exists = multisite.policy_group_exists(_SYNC_GROUP_ID, zonegroup_name)
- if replication and not policy_exists:
- multisite.create_dashboard_admin_sync_group(zonegroup_name=zonegroup_name)
+ if replication:
+ zonegroup_name = RgwClient.admin_instance(
+ daemon_name=daemon_name).get_default_zonegroup()
+ policy_exists = multisite.policy_group_exists(_SYNC_GROUP_ID, zonegroup_name)
+ if not policy_exists:
+ multisite.create_dashboard_admin_sync_group(zonegroup_name=zonegroup_name)
+ return rgw_client.set_bucket_replication(bucket_name)
- return rgw_client.set_bucket_replication(bucket_name, replication)
+ return rgw_client.delete_bucket_replication(bucket_name)
def _get_replication(self, bucket_name: str, owner, daemon_name):
+ multisite = RgwMultisite()
rgw_client = RgwClient.instance(owner, daemon_name)
- return rgw_client.get_bucket_replication(bucket_name)
+ replication_config = rgw_client.get_bucket_replication(bucket_name)
+
+ # Check if there's a valid S3 replication config with actual rules
+ if replication_config and replication_config.get('Rule'):
+ return replication_config
+
+ # If no S3 replication config exists, check for sync policies
+ try:
+ sync_policy = multisite.get_sync_policy(bucket_name=bucket_name)
+ # Check if there are sync policy groups with 'enabled' status
+ if sync_policy and sync_policy.get('groups'):
+ for group in sync_policy['groups']:
+ group_status = group.get('status', '').lower()
+ if group_status == 'enabled':
+ # A sync policy exists but there is no S3 replication rule.
+ # The UI should direct the user to the multisite sync-policy
+ # page rather than showing this as a normal replication rule.
+ return {'syncPolicyOnly': True}
+ except Exception:
+ pass
+
+ return {'Role': ''}
@staticmethod
def strip_tenant_from_bucket_name(bucket_name):
<tr>
<td i18n
class="bold w-25">Replication policy</td>
- <td><pre>{{ selection.replication | json}}</pre></td>
+ <td>
+ @if(hasSyncPolicyOnly) {
+ Sync policy configured. View on
+ <a routerLink="/rgw/multisite/sync-policy"
+ i18n>Sync-policy page.</a>
+ } @else {
+ <pre>{{ selection.replication | json}}</pre>
+ }
+ </td>
</tr>
<tr>
<td i18n
lifecycleFormat: 'json' | 'xml' = 'json';
aclPermissions: Record<string, string[]> = {};
replicationStatus = $localize`Disabled`;
+ hasSyncPolicyOnly = false;
bucketRateLimit: RgwRateLimitConfig;
constructor(private rgwBucketService: RgwBucketService, private cd: ChangeDetectorRef) {}
extraxtDetailsfromResponse() {
this.aclPermissions = this.parseXmlAcl(this.selection.acl, this.selection.owner);
- if (this.selection.replication?.['Rule']?.['Status']) {
+ this.hasSyncPolicyOnly = this.selection.replication?.['syncPolicyOnly'] === true;
+ if (this.hasSyncPolicyOnly) {
+ this.replicationStatus = $localize`Enabled`;
+ } else if (this.selection.replication?.['Rule']?.['Status']) {
this.replicationStatus = this.selection.replication?.['Rule']?.['Status'];
+ } else {
+ this.replicationStatus = $localize`Disabled`;
}
this.rgwBucketService.getBucketRateLimit(this.selection.bid).subscribe((resp: any) => {
if (resp && resp.bucket_ratelimit !== undefined) {
<div class="form-item">
<legend class="cd-header"
i18n>Replication</legend>
- <ng-container *ngIf="{status: multisiteStatus$, isDefaultZg: isDefaultZoneGroup$ | async} as multisiteStatus; else loadingTpl">
+ <ng-container *ngIf="{status: multisiteStatus$ | async, isDefaultZg: isDefaultZoneGroup$ | async} as multisiteStatus; else loadingTpl">
<cds-checkbox name="replication"
formControlName="replication"
id="replication"
- [disabled]="!multisiteStatus.isDefaultZg && !multisiteStatus.status.available"
+ [disabled]="!multisiteStatus.isDefaultZg && !multisiteStatus?.status?.available"
+ [title]="!multisiteStatus.isDefaultZg && !multisiteStatus?.status?.available ? 'Please enable the multisite configuration' : ''"
+ i18n-title
i18n-helperText
i18n>Enable
<cd-help-text>Enables replication for the objects in the bucket.</cd-help-text>
return retention_period_days, retention_period_years
@RestClient.api_put('/{bucket_name}?replication')
- def set_bucket_replication(self, bucket_name, replication: bool, request=None):
+ def set_bucket_replication(self, bucket_name, request=None):
# pGenerate the minimum replication configuration
# required for enabling the replication
root = ET.Element('ReplicationConfiguration',
rule_id.text = _SYNC_PIPE_ID
status = ET.SubElement(rule, 'Status')
- status.text = 'Enabled' if replication else 'Disabled'
+ status.text = 'Enabled'
filter_elem = ET.SubElement(rule, 'Filter')
prefix = ET.SubElement(filter_elem, 'Prefix')
return None
raise e
+ @RestClient.api_delete('/{bucket_name}?replication')
+ def delete_bucket_replication(self, bucket_name, request=None):
+ # pylint: disable=unused-argument
+ try:
+ request()
+ except RequestException as e:
+ if e.content:
+ content = json_str_to_object(e.content)
+ if content.get('Code') == 'ReplicationConfigurationNotFoundError':
+ return None
+ raise DashboardException(msg=str(e), component='rgw')
+
@RestClient.api_post('?Action=CreateTopic&Name={name}')
def create_topic(self, request=None, name: str = '',
daemon_name: str = '',
# period update --commit
self.update_period()
+ @staticmethod
+ def _is_not_found_sync_policy_error(error: DashboardException) -> bool:
+ message = str(error).lower()
+ not_found_markers = ['not found', 'no such', 'does not exist']
+ return any(marker in message for marker in not_found_markers)
+
+ def remove_dashboard_admin_sync_group(self, zonegroup_name: str = ''):
+ if not self.policy_group_exists(_SYNC_GROUP_ID, zonegroup_name):
+ return
+
+ try:
+ self.remove_sync_pipe(_SYNC_GROUP_ID, _SYNC_PIPE_ID)
+ except DashboardException as error:
+ if not self._is_not_found_sync_policy_error(error):
+ raise
+
+ try:
+ self.remove_sync_flow(_SYNC_GROUP_ID, _SYNC_FLOW_ID,
+ SyncFlowTypes.symmetrical.value)
+ except DashboardException as error:
+ if not self._is_not_found_sync_policy_error(error):
+ raise
+
+ self.remove_sync_policy_group(_SYNC_GROUP_ID, update_period=True)
+
def policy_group_exists(self, group_name: str, zonegroup_name: str):
try:
_ = self.get_sync_policy_group(