]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/pybind/mgr/dashboard/services/rgw_client.py
update ceph source to reef 18.2.1
[ceph.git] / ceph / src / pybind / mgr / dashboard / services / rgw_client.py
index eca5c7913aae3c55039b2c364da75634a2104529..5120806d89c1eb6e1c178e3228c580218c374c2f 100644 (file)
@@ -1,4 +1,7 @@
 # -*- coding: utf-8 -*-
+# pylint: disable=C0302
+# pylint: disable=too-many-branches
+# pylint: disable=too-many-lines
 
 import ipaddress
 import json
@@ -8,14 +11,15 @@ import re
 import xml.etree.ElementTree as ET  # noqa: N814
 from subprocess import SubprocessError
 
-from mgr_util import build_url
+from mgr_util import build_url, name_to_config_section
 
 from .. import mgr
 from ..awsauth import S3Auth
 from ..exceptions import DashboardException
 from ..rest_client import RequestException, RestClient
 from ..settings import Settings
-from ..tools import dict_contains_path, dict_get, json_str_to_object
+from ..tools import dict_contains_path, dict_get, json_str_to_object, str_to_bool
+from .ceph_service import CephService
 
 try:
     from typing import Any, Dict, List, Optional, Tuple, Union
@@ -84,9 +88,19 @@ def _determine_rgw_addr(daemon_info: Dict[str, Any]) -> RgwDaemon:
     Parse RGW daemon info to determine the configured host (IP address) and port.
     """
     daemon = RgwDaemon()
-    daemon.host = daemon_info['metadata']['hostname']
+    rgw_dns_name = CephService.send_command('mon', 'config get',
+                                            who=name_to_config_section('rgw.' + daemon_info['metadata']['id']),  # noqa E501 #pylint: disable=line-too-long
+                                            key='rgw_dns_name').rstrip()
+
     daemon.port, daemon.ssl = _parse_frontend_config(daemon_info['metadata']['frontend_config#0'])
 
+    if rgw_dns_name:
+        daemon.host = rgw_dns_name
+    elif daemon.ssl:
+        daemon.host = daemon_info['metadata']['hostname']
+    else:
+        daemon.host = _parse_addr(daemon_info['addr'])
+
     return daemon
 
 
@@ -580,18 +594,15 @@ class RgwClient(RestClient):
         realms_info = self._get_realms_info()
         if 'realms' in realms_info and realms_info['realms']:
             return realms_info['realms']
-
         return []
 
-    def get_default_realm(self) -> str:
+    def get_default_realm(self):
         realms_info = self._get_realms_info()
         if 'default_info' in realms_info and realms_info['default_info']:
             realm_info = self._get_realm_info(realms_info['default_info'])
             if 'name' in realm_info and realm_info['name']:
                 return realm_info['name']
-        raise DashboardException(msg='Default realm not found.',
-                                 http_status_code=404,
-                                 component='rgw')
+        return None
 
     @RestClient.api_get('/{bucket_name}?versioning')
     def get_bucket_versioning(self, bucket_name, request=None):
@@ -863,3 +874,765 @@ class RgwClient(RestClient):
             msg = "Retention mode must be either COMPLIANCE or GOVERNANCE."
             raise DashboardException(msg=msg, component='rgw')
         return retention_period_days, retention_period_years
+
+
+class RgwMultisite:
+    def migrate_to_multisite(self, realm_name: str, zonegroup_name: str, zone_name: str,
+                             zonegroup_endpoints: str, zone_endpoints: str, access_key: str,
+                             secret_key: str):
+        rgw_realm_create_cmd = ['realm', 'create', '--rgw-realm', realm_name, '--default']
+        try:
+            exit_code, _, err = mgr.send_rgwadmin_command(rgw_realm_create_cmd, False)
+            if exit_code > 0:
+                raise DashboardException(e=err, msg='Unable to create realm',
+                                         http_status_code=500, component='rgw')
+        except SubprocessError as error:
+            raise DashboardException(error, http_status_code=500, component='rgw')
+
+        rgw_zonegroup_edit_cmd = ['zonegroup', 'rename', '--rgw-zonegroup', 'default',
+                                  '--zonegroup-new-name', zonegroup_name]
+        try:
+            exit_code, _, err = mgr.send_rgwadmin_command(rgw_zonegroup_edit_cmd, False)
+            if exit_code > 0:
+                raise DashboardException(e=err, msg='Unable to rename zonegroup to {}'.format(zonegroup_name),  # noqa E501  #pylint: disable=line-too-long
+                                         http_status_code=500, component='rgw')
+        except SubprocessError as error:
+            raise DashboardException(error, http_status_code=500, component='rgw')
+
+        rgw_zone_edit_cmd = ['zone', 'rename', '--rgw-zone',
+                             'default', '--zone-new-name', zone_name,
+                             '--rgw-zonegroup', zonegroup_name]
+        try:
+            exit_code, _, err = mgr.send_rgwadmin_command(rgw_zone_edit_cmd, False)
+            if exit_code > 0:
+                raise DashboardException(e=err, msg='Unable to rename zone to {}'.format(zone_name),  # noqa E501 #pylint: disable=line-too-long
+                                         http_status_code=500, component='rgw')
+        except SubprocessError as error:
+            raise DashboardException(error, http_status_code=500, component='rgw')
+
+        rgw_zonegroup_modify_cmd = ['zonegroup', 'modify',
+                                    '--rgw-realm', realm_name,
+                                    '--rgw-zonegroup', zonegroup_name]
+        if zonegroup_endpoints:
+            rgw_zonegroup_modify_cmd.append('--endpoints')
+            rgw_zonegroup_modify_cmd.append(zonegroup_endpoints)
+        rgw_zonegroup_modify_cmd.append('--master')
+        rgw_zonegroup_modify_cmd.append('--default')
+        try:
+            exit_code, _, err = mgr.send_rgwadmin_command(rgw_zonegroup_modify_cmd)
+            if exit_code > 0:
+                raise DashboardException(e=err, msg='Unable to modify zonegroup {}'.format(zonegroup_name),  # noqa E501  #pylint: disable=line-too-long
+                                         http_status_code=500, component='rgw')
+        except SubprocessError as error:
+            raise DashboardException(error, http_status_code=500, component='rgw')
+
+        rgw_zone_modify_cmd = ['zone', 'modify', '--rgw-realm', realm_name,
+                               '--rgw-zonegroup', zonegroup_name,
+                               '--rgw-zone', zone_name]
+        if zone_endpoints:
+            rgw_zone_modify_cmd.append('--endpoints')
+            rgw_zone_modify_cmd.append(zone_endpoints)
+        rgw_zone_modify_cmd.append('--master')
+        rgw_zone_modify_cmd.append('--default')
+        try:
+            exit_code, _, err = mgr.send_rgwadmin_command(rgw_zone_modify_cmd)
+            if exit_code > 0:
+                raise DashboardException(e=err, msg='Unable to modify zone',
+                                         http_status_code=500, component='rgw')
+        except SubprocessError as error:
+            raise DashboardException(error, http_status_code=500, component='rgw')
+
+        if access_key and secret_key:
+            rgw_zone_modify_cmd = ['zone', 'modify', '--rgw-zone', zone_name,
+                                   '--access-key', access_key, '--secret', secret_key]
+            try:
+                exit_code, _, err = mgr.send_rgwadmin_command(rgw_zone_modify_cmd)
+                if exit_code > 0:
+                    raise DashboardException(e=err, msg='Unable to modify zone',
+                                             http_status_code=500, component='rgw')
+            except SubprocessError as error:
+                raise DashboardException(error, http_status_code=500, component='rgw')
+
+    def create_realm(self, realm_name: str, default: bool):
+        rgw_realm_create_cmd = ['realm', 'create']
+        cmd_create_realm_options = ['--rgw-realm', realm_name]
+        if default != 'false':
+            cmd_create_realm_options.append('--default')
+        rgw_realm_create_cmd += cmd_create_realm_options
+        try:
+            exit_code, _, _ = mgr.send_rgwadmin_command(rgw_realm_create_cmd)
+            if exit_code > 0:
+                raise DashboardException(msg='Unable to create realm',
+                                         http_status_code=500, component='rgw')
+        except SubprocessError as error:
+            raise DashboardException(error, http_status_code=500, component='rgw')
+
+    def list_realms(self):
+        rgw_realm_list = {}
+        rgw_realm_list_cmd = ['realm', 'list']
+        try:
+            exit_code, out, _ = mgr.send_rgwadmin_command(rgw_realm_list_cmd)
+            if exit_code > 0:
+                raise DashboardException(msg='Unable to fetch realm list',
+                                         http_status_code=500, component='rgw')
+            rgw_realm_list = out
+        except SubprocessError as error:
+            raise DashboardException(error, http_status_code=500, component='rgw')
+        return rgw_realm_list
+
+    def get_realm(self, realm_name: str):
+        realm_info = {}
+        rgw_realm_info_cmd = ['realm', 'get', '--rgw-realm', realm_name]
+        try:
+            exit_code, out, _ = mgr.send_rgwadmin_command(rgw_realm_info_cmd)
+            if exit_code > 0:
+                raise DashboardException('Unable to get realm info',
+                                         http_status_code=500, component='rgw')
+            realm_info = out
+        except SubprocessError as error:
+            raise DashboardException(error, http_status_code=500, component='rgw')
+        return realm_info
+
+    def get_all_realms_info(self):
+        all_realms_info = {}
+        realms_info = []
+        rgw_realm_list = self.list_realms()
+        if 'realms' in rgw_realm_list:
+            if rgw_realm_list['realms'] != []:
+                for rgw_realm in rgw_realm_list['realms']:
+                    realm_info = self.get_realm(rgw_realm)
+                    realms_info.append(realm_info)
+                    all_realms_info['realms'] = realms_info  # type: ignore
+            else:
+                all_realms_info['realms'] = []  # type: ignore
+        if 'default_info' in rgw_realm_list and rgw_realm_list['default_info'] != '':
+            all_realms_info['default_realm'] = rgw_realm_list['default_info']  # type: ignore
+        else:
+            all_realms_info['default_realm'] = ''  # type: ignore
+        return all_realms_info
+
+    def edit_realm(self, realm_name: str, new_realm_name: str, default: str = ''):
+        rgw_realm_edit_cmd = []
+        if new_realm_name != realm_name:
+            rgw_realm_edit_cmd = ['realm', 'rename', '--rgw-realm',
+                                  realm_name, '--realm-new-name', new_realm_name]
+            try:
+                exit_code, _, err = mgr.send_rgwadmin_command(rgw_realm_edit_cmd, False)
+                if exit_code > 0:
+                    raise DashboardException(e=err, msg='Unable to edit realm',
+                                             http_status_code=500, component='rgw')
+            except SubprocessError as error:
+                raise DashboardException(error, http_status_code=500, component='rgw')
+        if default and str_to_bool(default):
+            rgw_realm_edit_cmd = ['realm', 'default', '--rgw-realm', new_realm_name]
+            try:
+                exit_code, _, _ = mgr.send_rgwadmin_command(rgw_realm_edit_cmd, False)
+                if exit_code > 0:
+                    raise DashboardException(msg='Unable to set {} as default realm'.format(new_realm_name),  # noqa E501  #pylint: disable=line-too-long
+                                             http_status_code=500, component='rgw')
+            except SubprocessError as error:
+                raise DashboardException(error, http_status_code=500, component='rgw')
+
+    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 create_zonegroup(self, realm_name: str, zonegroup_name: str,
+                         default: bool, master: bool, endpoints: str):
+        rgw_zonegroup_create_cmd = ['zonegroup', 'create']
+        cmd_create_zonegroup_options = ['--rgw-zonegroup', zonegroup_name]
+        if realm_name != 'null':
+            cmd_create_zonegroup_options.append('--rgw-realm')
+            cmd_create_zonegroup_options.append(realm_name)
+        if default != 'false':
+            cmd_create_zonegroup_options.append('--default')
+        if master != 'false':
+            cmd_create_zonegroup_options.append('--master')
+        if endpoints:
+            cmd_create_zonegroup_options.append('--endpoints')
+            cmd_create_zonegroup_options.append(endpoints)
+        rgw_zonegroup_create_cmd += cmd_create_zonegroup_options
+        try:
+            exit_code, out, err = mgr.send_rgwadmin_command(rgw_zonegroup_create_cmd)
+            if exit_code > 0:
+                raise DashboardException(e=err, msg='Unable to get realm info',
+                                         http_status_code=500, component='rgw')
+        except SubprocessError as error:
+            raise DashboardException(error, http_status_code=500, component='rgw')
+        return out
+
+    def list_zonegroups(self):
+        rgw_zonegroup_list = {}
+        rgw_zonegroup_list_cmd = ['zonegroup', 'list']
+        try:
+            exit_code, out, _ = mgr.send_rgwadmin_command(rgw_zonegroup_list_cmd)
+            if exit_code > 0:
+                raise DashboardException(msg='Unable to fetch zonegroup list',
+                                         http_status_code=500, component='rgw')
+            rgw_zonegroup_list = out
+        except SubprocessError as error:
+            raise DashboardException(error, http_status_code=500, component='rgw')
+        return rgw_zonegroup_list
+
+    def get_zonegroup(self, zonegroup_name: str):
+        zonegroup_info = {}
+        if zonegroup_name != 'default':
+            rgw_zonegroup_info_cmd = ['zonegroup', 'get', '--rgw-zonegroup', zonegroup_name]
+        else:
+            rgw_zonegroup_info_cmd = ['zonegroup', 'get', '--rgw-zonegroup',
+                                      zonegroup_name, '--rgw-realm', 'default']
+        try:
+            exit_code, out, _ = mgr.send_rgwadmin_command(rgw_zonegroup_info_cmd)
+            if exit_code > 0:
+                raise DashboardException('Unable to get zonegroup info',
+                                         http_status_code=500, component='rgw')
+            zonegroup_info = out
+        except SubprocessError as error:
+            raise DashboardException(error, http_status_code=500, component='rgw')
+        return zonegroup_info
+
+    def get_all_zonegroups_info(self):
+        all_zonegroups_info = {}
+        zonegroups_info = []
+        rgw_zonegroup_list = self.list_zonegroups()
+        if 'zonegroups' in rgw_zonegroup_list:
+            if rgw_zonegroup_list['zonegroups'] != []:
+                for rgw_zonegroup in rgw_zonegroup_list['zonegroups']:
+                    zonegroup_info = self.get_zonegroup(rgw_zonegroup)
+                    zonegroups_info.append(zonegroup_info)
+                all_zonegroups_info['zonegroups'] = zonegroups_info  # type: ignore
+            else:
+                all_zonegroups_info['zonegroups'] = []  # type: ignore
+        if 'default_info' in rgw_zonegroup_list and rgw_zonegroup_list['default_info'] != '':
+            all_zonegroups_info['default_zonegroup'] = rgw_zonegroup_list['default_info']
+        else:
+            all_zonegroups_info['default_zonegroup'] = ''  # type: ignore
+        return all_zonegroups_info
+
+    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]
+        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']:
+                self.delete_zone(zone['name'], 'true', pools)
+
+    def modify_zonegroup(self, realm_name: str, zonegroup_name: str, default: str, master: str,
+                         endpoints: str):
+
+        rgw_zonegroup_modify_cmd = ['zonegroup', 'modify',
+                                    '--rgw-realm', realm_name,
+                                    '--rgw-zonegroup', zonegroup_name]
+        if endpoints:
+            rgw_zonegroup_modify_cmd.append('--endpoints')
+            rgw_zonegroup_modify_cmd.append(endpoints)
+        if master and str_to_bool(master):
+            rgw_zonegroup_modify_cmd.append('--master')
+        if default and str_to_bool(default):
+            rgw_zonegroup_modify_cmd.append('--default')
+        try:
+            exit_code, _, err = mgr.send_rgwadmin_command(rgw_zonegroup_modify_cmd)
+            if exit_code > 0:
+                raise DashboardException(e=err, msg='Unable to modify zonegroup {}'.format(zonegroup_name),  # noqa E501  #pylint: disable=line-too-long
+                                         http_status_code=500, component='rgw')
+        except SubprocessError as error:
+            raise DashboardException(error, http_status_code=500, component='rgw')
+        self.update_period()
+
+    def add_or_remove_zone(self, zonegroup_name: str, zone_name: str, action: str):
+        if action == 'add':
+            rgw_zonegroup_add_zone_cmd = ['zonegroup', 'add', '--rgw-zonegroup',
+                                          zonegroup_name, '--rgw-zone', zone_name]
+            try:
+                exit_code, _, err = mgr.send_rgwadmin_command(rgw_zonegroup_add_zone_cmd)
+                if exit_code > 0:
+                    raise DashboardException(e=err, msg='Unable to add zone {} to zonegroup {}'.format(zone_name, zonegroup_name),  # noqa E501  #pylint: disable=line-too-long
+                                             http_status_code=500, component='rgw')
+            except SubprocessError as error:
+                raise DashboardException(error, http_status_code=500, component='rgw')
+            self.update_period()
+        if action == 'remove':
+            rgw_zonegroup_rm_zone_cmd = ['zonegroup', 'remove',
+                                         '--rgw-zonegroup', zonegroup_name, '--rgw-zone', zone_name]
+            try:
+                exit_code, _, err = mgr.send_rgwadmin_command(rgw_zonegroup_rm_zone_cmd)
+                if exit_code > 0:
+                    raise DashboardException(e=err, msg='Unable to remove zone {} from zonegroup {}'.format(zone_name, zonegroup_name),  # noqa E501  #pylint: disable=line-too-long
+                                             http_status_code=500, component='rgw')
+            except SubprocessError as error:
+                raise DashboardException(error, http_status_code=500, component='rgw')
+            self.update_period()
+
+    def get_placement_targets_by_zonegroup(self, zonegroup_name: str):
+        rgw_get_placement_cmd = ['zonegroup', 'placement',
+                                 'list', '--rgw-zonegroup', zonegroup_name]
+        try:
+            exit_code, out, err = mgr.send_rgwadmin_command(rgw_get_placement_cmd)
+            if exit_code > 0:
+                raise DashboardException(e=err, msg='Unable to get placement targets',
+                                         http_status_code=500, component='rgw')
+        except SubprocessError as error:
+            raise DashboardException(error, http_status_code=500, component='rgw')
+        return out
+
+    def add_placement_targets(self, zonegroup_name: str, placement_targets: List[Dict]):
+        rgw_add_placement_cmd = ['zonegroup', 'placement', 'add']
+        for placement_target in placement_targets:
+            cmd_add_placement_options = ['--rgw-zonegroup', zonegroup_name,
+                                         '--placement-id', placement_target['placement_id']]
+            if placement_target['tags']:
+                cmd_add_placement_options += ['--tags', placement_target['tags']]
+            rgw_add_placement_cmd += cmd_add_placement_options
+            try:
+                exit_code, _, err = mgr.send_rgwadmin_command(rgw_add_placement_cmd)
+                if exit_code > 0:
+                    raise DashboardException(e=err,
+                                             msg='Unable to add placement target {} to zonegroup {}'.format(placement_target['placement_id'], zonegroup_name),  # noqa E501  #pylint: disable=line-too-long
+                                             http_status_code=500, component='rgw')
+            except SubprocessError as error:
+                raise DashboardException(error, http_status_code=500, component='rgw')
+            self.update_period()
+            storage_classes = placement_target['storage_class'].split(",") if placement_target['storage_class'] else []  # noqa E501  #pylint: disable=line-too-long
+            if storage_classes:
+                for sc in storage_classes:
+                    cmd_add_placement_options = ['--storage-class', sc]
+                    try:
+                        exit_code, _, err = mgr.send_rgwadmin_command(
+                            rgw_add_placement_cmd + cmd_add_placement_options)
+                        if exit_code > 0:
+                            raise DashboardException(e=err,
+                                                     msg='Unable to add placement target {} to zonegroup {}'.format(placement_target['placement_id'], zonegroup_name),  # noqa E501  #pylint: disable=line-too-long
+                                                     http_status_code=500, component='rgw')
+                    except SubprocessError as error:
+                        raise DashboardException(error, http_status_code=500, component='rgw')
+                    self.update_period()
+
+    def modify_placement_targets(self, zonegroup_name: str, placement_targets: List[Dict]):
+        rgw_add_placement_cmd = ['zonegroup', 'placement', 'modify']
+        for placement_target in placement_targets:
+            cmd_add_placement_options = ['--rgw-zonegroup', zonegroup_name,
+                                         '--placement-id', placement_target['placement_id']]
+            if placement_target['tags']:
+                cmd_add_placement_options += ['--tags', placement_target['tags']]
+            rgw_add_placement_cmd += cmd_add_placement_options
+            storage_classes = placement_target['storage_class'].split(",") if placement_target['storage_class'] else []  # noqa E501  #pylint: disable=line-too-long
+            if storage_classes:
+                for sc in storage_classes:
+                    cmd_add_placement_options = []
+                    cmd_add_placement_options = ['--storage-class', sc]
+                    try:
+                        exit_code, _, err = mgr.send_rgwadmin_command(
+                            rgw_add_placement_cmd + cmd_add_placement_options)
+                        if exit_code > 0:
+                            raise DashboardException(e=err,
+                                                     msg='Unable to add placement target {} to zonegroup {}'.format(placement_target['placement_id'], zonegroup_name),  # noqa E501  #pylint: disable=line-too-long
+                                                     http_status_code=500, component='rgw')
+                    except SubprocessError as error:
+                        raise DashboardException(error, http_status_code=500, component='rgw')
+                    self.update_period()
+            else:
+                try:
+                    exit_code, _, err = mgr.send_rgwadmin_command(rgw_add_placement_cmd)
+                    if exit_code > 0:
+                        raise DashboardException(e=err,
+                                                 msg='Unable to add placement target {} to zonegroup {}'.format(placement_target['placement_id'], zonegroup_name),  # noqa E501  #pylint: disable=line-too-long
+                                                 http_status_code=500, component='rgw')
+                except SubprocessError as error:
+                    raise DashboardException(error, http_status_code=500, component='rgw')
+                self.update_period()
+
+    # pylint: disable=W0102
+    def edit_zonegroup(self, realm_name: str, zonegroup_name: str, new_zonegroup_name: str,
+                       default: str = '', master: str = '', endpoints: str = '',
+                       add_zones: List[str] = [], remove_zones: List[str] = [],
+                       placement_targets: List[Dict[str, str]] = []):
+        rgw_zonegroup_edit_cmd = []
+        if new_zonegroup_name != zonegroup_name:
+            rgw_zonegroup_edit_cmd = ['zonegroup', 'rename', '--rgw-zonegroup', zonegroup_name,
+                                      '--zonegroup-new-name', new_zonegroup_name]
+            try:
+                exit_code, _, err = mgr.send_rgwadmin_command(rgw_zonegroup_edit_cmd, False)
+                if exit_code > 0:
+                    raise DashboardException(e=err, msg='Unable to rename zonegroup to {}'.format(new_zonegroup_name),  # noqa E501  #pylint: disable=line-too-long
+                                             http_status_code=500, component='rgw')
+            except SubprocessError as error:
+                raise DashboardException(error, http_status_code=500, component='rgw')
+            self.update_period()
+        self.modify_zonegroup(realm_name, new_zonegroup_name, default, master, endpoints)
+        if add_zones:
+            for zone_name in add_zones:
+                self.add_or_remove_zone(new_zonegroup_name, zone_name, 'add')
+        if remove_zones:
+            for zone_name in remove_zones:
+                self.add_or_remove_zone(new_zonegroup_name, zone_name, 'remove')
+        existing_placement_targets = self.get_placement_targets_by_zonegroup(new_zonegroup_name)
+        existing_placement_targets_ids = [pt['key'] for pt in existing_placement_targets]
+        if placement_targets:
+            for pt in placement_targets:
+                if pt['placement_id'] in existing_placement_targets_ids:
+                    self.modify_placement_targets(new_zonegroup_name, placement_targets)
+                else:
+                    self.add_placement_targets(new_zonegroup_name, placement_targets)
+
+    def update_period(self):
+        rgw_update_period_cmd = ['period', 'update', '--commit']
+        try:
+            exit_code, _, err = mgr.send_rgwadmin_command(rgw_update_period_cmd)
+            if exit_code > 0:
+                raise DashboardException(e=err, msg='Unable to update period',
+                                         http_status_code=500, component='rgw')
+        except SubprocessError as error:
+            raise DashboardException(error, http_status_code=500, component='rgw')
+
+    def create_zone(self, zone_name, zonegroup_name, default, master, endpoints, access_key,
+                    secret_key):
+        rgw_zone_create_cmd = ['zone', 'create']
+        cmd_create_zone_options = ['--rgw-zone', zone_name]
+        if zonegroup_name != 'null':
+            cmd_create_zone_options.append('--rgw-zonegroup')
+            cmd_create_zone_options.append(zonegroup_name)
+        if default != 'false':
+            cmd_create_zone_options.append('--default')
+        if master != 'false':
+            cmd_create_zone_options.append('--master')
+        if endpoints != 'null':
+            cmd_create_zone_options.append('--endpoints')
+            cmd_create_zone_options.append(endpoints)
+        if access_key is not None:
+            cmd_create_zone_options.append('--access-key')
+            cmd_create_zone_options.append(access_key)
+        if secret_key is not None:
+            cmd_create_zone_options.append('--secret')
+            cmd_create_zone_options.append(secret_key)
+        rgw_zone_create_cmd += cmd_create_zone_options
+        try:
+            exit_code, out, err = mgr.send_rgwadmin_command(rgw_zone_create_cmd)
+            if exit_code > 0:
+                raise DashboardException(e=err, msg='Unable to create zone',
+                                         http_status_code=500, component='rgw')
+        except SubprocessError as error:
+            raise DashboardException(error, http_status_code=500, component='rgw')
+
+        self.update_period()
+        return out
+
+    def parse_secrets(self, user, data):
+        for key in data.get('keys', []):
+            if key.get('user') == user:
+                access_key = key.get('access_key')
+                secret_key = key.get('secret_key')
+                return access_key, secret_key
+        return '', ''
+
+    def modify_zone(self, zone_name: str, zonegroup_name: str, default: str, master: str,
+                    endpoints: str, access_key: str, secret_key: str):
+        rgw_zone_modify_cmd = ['zone', 'modify', '--rgw-zonegroup',
+                               zonegroup_name, '--rgw-zone', zone_name]
+        if endpoints:
+            rgw_zone_modify_cmd.append('--endpoints')
+            rgw_zone_modify_cmd.append(endpoints)
+        if default and str_to_bool(default):
+            rgw_zone_modify_cmd.append('--default')
+        if master and str_to_bool(master):
+            rgw_zone_modify_cmd.append('--master')
+        if access_key is not None:
+            rgw_zone_modify_cmd.append('--access-key')
+            rgw_zone_modify_cmd.append(access_key)
+        if secret_key is not None:
+            rgw_zone_modify_cmd.append('--secret')
+            rgw_zone_modify_cmd.append(secret_key)
+        try:
+            exit_code, _, err = mgr.send_rgwadmin_command(rgw_zone_modify_cmd)
+            if exit_code > 0:
+                raise DashboardException(e=err, msg='Unable to modify zone',
+                                         http_status_code=500, component='rgw')
+        except SubprocessError as error:
+            raise DashboardException(error, http_status_code=500, component='rgw')
+        self.update_period()
+
+    def add_placement_targets_zone(self, zone_name: str, placement_target: str, data_pool: str,
+                                   index_pool: str, data_extra_pool: str):
+        rgw_zone_add_placement_cmd = ['zone', 'placement', 'add', '--rgw-zone', zone_name,
+                                      '--placement-id', placement_target, '--data-pool', data_pool,
+                                      '--index-pool', index_pool,
+                                      '--data-extra-pool', data_extra_pool]
+        try:
+            exit_code, _, err = mgr.send_rgwadmin_command(rgw_zone_add_placement_cmd)
+            if exit_code > 0:
+                raise DashboardException(e=err, msg='Unable to add placement target {} to zone {}'.format(placement_target, zone_name),  # noqa E501 #pylint: disable=line-too-long
+                                         http_status_code=500, component='rgw')
+        except SubprocessError as error:
+            raise DashboardException(error, http_status_code=500, component='rgw')
+        self.update_period()
+
+    def add_storage_class_zone(self, zone_name: str, placement_target: str, storage_class: str,
+                               data_pool: str, compression: str):
+        rgw_zone_add_storage_class_cmd = ['zone', 'placement', 'add', '--rgw-zone', zone_name,
+                                          '--placement-id', placement_target,
+                                          '--storage-class', storage_class,
+                                          '--data-pool', data_pool,
+                                          '--compression', compression]
+        try:
+            exit_code, _, err = mgr.send_rgwadmin_command(rgw_zone_add_storage_class_cmd)
+            if exit_code > 0:
+                raise DashboardException(e=err, msg='Unable to add storage class {} to zone {}'.format(storage_class, zone_name),  # noqa E501 #pylint: disable=line-too-long
+                                         http_status_code=500, component='rgw')
+        except SubprocessError as error:
+            raise DashboardException(error, http_status_code=500, component='rgw')
+        self.update_period()
+
+    def edit_zone(self, zone_name: str, new_zone_name: str, zonegroup_name: str, default: str = '',
+                  master: str = '', endpoints: str = '', access_key: str = '', secret_key: str = '',
+                  placement_target: str = '', data_pool: str = '', index_pool: str = '',
+                  data_extra_pool: str = '', storage_class: str = '', data_pool_class: str = '',
+                  compression: str = ''):
+        if new_zone_name != zone_name:
+            rgw_zone_rename_cmd = ['zone', 'rename', '--rgw-zone',
+                                   zone_name, '--zone-new-name', new_zone_name]
+            try:
+                exit_code, _, err = mgr.send_rgwadmin_command(rgw_zone_rename_cmd, False)
+                if exit_code > 0:
+                    raise DashboardException(e=err, msg='Unable to rename zone to {}'.format(new_zone_name),  # noqa E501 #pylint: disable=line-too-long
+                                             http_status_code=500, component='rgw')
+            except SubprocessError as error:
+                raise DashboardException(error, http_status_code=500, component='rgw')
+            self.update_period()
+        self.modify_zone(new_zone_name, zonegroup_name, default, master, endpoints, access_key,
+                         secret_key)
+        self.add_placement_targets_zone(new_zone_name, placement_target,
+                                        data_pool, index_pool, data_extra_pool)
+        self.add_storage_class_zone(new_zone_name, placement_target, storage_class,
+                                    data_pool_class, compression)
+
+    def list_zones(self):
+        rgw_zone_list = {}
+        rgw_zone_list_cmd = ['zone', 'list']
+        try:
+            exit_code, out, _ = mgr.send_rgwadmin_command(rgw_zone_list_cmd)
+            if exit_code > 0:
+                raise DashboardException(msg='Unable to fetch zone list',
+                                         http_status_code=500, component='rgw')
+            rgw_zone_list = out
+        except SubprocessError as error:
+            raise DashboardException(error, http_status_code=500, component='rgw')
+        return rgw_zone_list
+
+    def get_zone(self, zone_name: str):
+        zone_info = {}
+        rgw_zone_info_cmd = ['zone', 'get', '--rgw-zone', zone_name]
+        try:
+            exit_code, out, _ = mgr.send_rgwadmin_command(rgw_zone_info_cmd)
+            if exit_code > 0:
+                raise DashboardException('Unable to get zone info',
+                                         http_status_code=500, component='rgw')
+            zone_info = out
+        except SubprocessError as error:
+            raise DashboardException(error, http_status_code=500, component='rgw')
+        return zone_info
+
+    def get_all_zones_info(self):
+        all_zones_info = {}
+        zones_info = []
+        rgw_zone_list = self.list_zones()
+        if 'zones' in rgw_zone_list:
+            if rgw_zone_list['zones'] != []:
+                for rgw_zone in rgw_zone_list['zones']:
+                    zone_info = self.get_zone(rgw_zone)
+                    zones_info.append(zone_info)
+                    all_zones_info['zones'] = zones_info  # type: ignore
+            else:
+                all_zones_info['zones'] = []
+        if 'default_info' in rgw_zone_list and rgw_zone_list['default_info'] != '':
+            all_zones_info['default_zone'] = rgw_zone_list['default_info']  # type: ignore
+        else:
+            all_zones_info['default_zone'] = ''  # type: ignore
+        return all_zones_info
+
+    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]
+        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_pools(pools)
+
+    def delete_pools(self, pools):
+        for pool in pools:
+            if mgr.rados.pool_exists(pool):
+                mgr.rados.delete_pool(pool)
+
+    def create_system_user(self, userName: str, zoneName: str):
+        rgw_user_create_cmd = ['user', 'create', '--uid', userName,
+                               '--display-name', userName, '--rgw-zone', zoneName, '--system']
+        try:
+            exit_code, out, _ = mgr.send_rgwadmin_command(rgw_user_create_cmd)
+            if exit_code > 0:
+                raise DashboardException(msg='Unable to create system user',
+                                         http_status_code=500, component='rgw')
+            return out
+        except SubprocessError as error:
+            raise DashboardException(error, http_status_code=500, component='rgw')
+
+    def get_user_list(self, zoneName: str):
+        all_users_info = []
+        user_list = []
+        rgw_user_list_cmd = ['user', 'list', '--rgw-zone', zoneName]
+        try:
+            exit_code, out, _ = mgr.send_rgwadmin_command(rgw_user_list_cmd)
+            if exit_code > 0:
+                raise DashboardException('Unable to get user list',
+                                         http_status_code=500, component='rgw')
+            user_list = out
+        except SubprocessError as error:
+            raise DashboardException(error, http_status_code=500, component='rgw')
+
+        if len(user_list) > 0:
+            for user_name in user_list:
+                rgw_user_info_cmd = ['user', 'info', '--uid', user_name, '--rgw-zone', zoneName]
+                try:
+                    exit_code, out, _ = mgr.send_rgwadmin_command(rgw_user_info_cmd)
+                    if exit_code > 0:
+                        raise DashboardException('Unable to get user info',
+                                                 http_status_code=500, component='rgw')
+                    all_users_info.append(out)
+                except SubprocessError as error:
+                    raise DashboardException(error, http_status_code=500, component='rgw')
+        return all_users_info
+
+    def get_multisite_status(self):
+        is_multisite_configured = True
+        rgw_realm_list = self.list_realms()
+        rgw_zonegroup_list = self.list_zonegroups()
+        rgw_zone_list = self.list_zones()
+        if len(rgw_realm_list['realms']) < 1 and len(rgw_zonegroup_list['zonegroups']) < 1 \
+                and len(rgw_zone_list['zones']) < 1:
+            is_multisite_configured = False
+        return is_multisite_configured
+
+    def get_multisite_sync_status(self):
+        rgw_multisite_sync_status_cmd = ['sync', 'status']
+        try:
+            exit_code, out, _ = mgr.send_rgwadmin_command(rgw_multisite_sync_status_cmd, False)
+            if exit_code > 0:
+                raise DashboardException('Unable to get sync status',
+                                         http_status_code=500, component='rgw')
+            if out:
+                return self.process_data(out)
+        except SubprocessError as error:
+            raise DashboardException(error, http_status_code=500, component='rgw')
+        return {}
+
+    def process_data(self, data):
+        primary_zone_data, metadata_sync_data = self.extract_metadata_and_primary_zone_data(data)
+        replica_zones_info = []
+        if metadata_sync_data != {}:
+            datasync_info = self.extract_datasync_info(data)
+            replica_zones_info = [self.extract_replica_zone_data(item) for item in datasync_info]
+
+        replica_zones_info_object = {
+            'metadataSyncInfo': metadata_sync_data,
+            'dataSyncInfo': replica_zones_info,
+            'primaryZoneData': primary_zone_data
+        }
+
+        return replica_zones_info_object
+
+    def extract_metadata_and_primary_zone_data(self, data):
+        primary_zone_info, metadata_sync_infoormation = self.extract_zones_data(data)
+
+        primary_zone_tree = primary_zone_info.split('\n') if primary_zone_info else []
+        realm = self.get_primary_zonedata(primary_zone_tree[0])
+        zonegroup = self.get_primary_zonedata(primary_zone_tree[1])
+        zone = self.get_primary_zonedata(primary_zone_tree[2])
+
+        primary_zone_data = [realm, zonegroup, zone]
+        zonegroup_info = self.get_zonegroup(zonegroup)
+        metadata_sync_data = {}
+        if len(zonegroup_info['zones']) > 1:
+            metadata_sync_data = self.extract_metadata_sync_data(metadata_sync_infoormation)
+
+        return primary_zone_data, metadata_sync_data
+
+    def extract_zones_data(self, data):
+        result = data
+        primary_zone_info = result.split('metadata sync')[0] if 'metadata sync' in result else None
+        metadata_sync_infoormation = result.split('metadata sync')[1] if 'metadata sync' in result else None  # noqa E501  #pylint: disable=line-too-long
+        return primary_zone_info, metadata_sync_infoormation
+
+    def extract_metadata_sync_data(self, metadata_sync_infoormation):
+        metadata_sync_info = metadata_sync_infoormation.split('data sync source')[0].strip() if 'data sync source' in metadata_sync_infoormation else None  # noqa E501  #pylint: disable=line-too-long
+
+        if metadata_sync_info == 'no sync (zone is master)':
+            return metadata_sync_info
+
+        metadata_sync_data = {}
+        metadata_sync_info_array = metadata_sync_info.split('\n') if metadata_sync_info else []
+        metadata_sync_data['syncstatus'] = metadata_sync_info_array[0].strip() if len(metadata_sync_info_array) > 0 else None  # noqa E501  #pylint: disable=line-too-long
+
+        for item in metadata_sync_info_array:
+            self.extract_metadata_sync_info(metadata_sync_data, item)
+
+        metadata_sync_data['fullSyncStatus'] = metadata_sync_info_array
+        return metadata_sync_data
+
+    def extract_metadata_sync_info(self, metadata_sync_data, item):
+        if 'oldest incremental change not applied:' in item:
+            metadata_sync_data['timestamp'] = item.split('applied:')[1].split()[0].strip()
+
+    def extract_datasync_info(self, data):
+        metadata_sync_infoormation = data.split('metadata sync')[1] if 'metadata sync' in data else None  # noqa E501  #pylint: disable=line-too-long
+        if 'data sync source' in metadata_sync_infoormation:
+            datasync_info = metadata_sync_infoormation.split('data sync source')[1].split('source:')
+            return datasync_info
+        return []
+
+    def extract_replica_zone_data(self, datasync_item):
+        replica_zone_data = {}
+        datasync_info_array = datasync_item.split('\n')
+        replica_zone_name = self.get_primary_zonedata(datasync_info_array[0])
+        replica_zone_data['name'] = replica_zone_name.strip()
+        replica_zone_data['syncstatus'] = datasync_info_array[1].strip()
+        replica_zone_data['fullSyncStatus'] = datasync_info_array
+        for item in datasync_info_array:
+            self.extract_metadata_sync_info(replica_zone_data, item)
+        return replica_zone_data
+
+    def get_primary_zonedata(self, data):
+        regex = r'\(([^)]+)\)'
+        match = re.search(regex, data)
+
+        if match and match.group(1):
+            return match.group(1)
+
+        return ''