# -*- coding: utf-8 -*-
+# pylint: disable=C0302
+# pylint: disable=too-many-branches
+# pylint: disable=too-many-lines
import ipaddress
import json
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
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
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):
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 ''