From fd417c1716ff101796e4dfd206754bcf080cc18c Mon Sep 17 00:00:00 2001 From: Adam King Date: Mon, 25 Mar 2024 12:13:32 -0400 Subject: [PATCH] mgr/rgw: add support to modify zonegroup parameters This is being done with `radosgw-admin zonegroup set` rather than `radosgw-admin zonegroup modify` as I don't think the hostnames parameter (which is the primary focus for this specific change) can be set using the modify command. The nice bit about that is it should in theory make it easy to extend this to allow setting other parameters to be modified in the zonegroup in the future. Signed-off-by: Adam King (cherry picked from commit 5f7c6d58cc90ff139c1f8f8b950ef37d8597f92f) --- src/pybind/mgr/rgw/module.py | 18 +++++-- .../ceph/deployment/service_spec.py | 4 +- src/python-common/ceph/rgw/rgwam_core.py | 52 +++++++++++++++++-- 3 files changed, 65 insertions(+), 9 deletions(-) diff --git a/src/pybind/mgr/rgw/module.py b/src/pybind/mgr/rgw/module.py index f48e2e09fc323..1b589541932b0 100644 --- a/src/pybind/mgr/rgw/module.py +++ b/src/pybind/mgr/rgw/module.py @@ -28,7 +28,7 @@ if TYPE_CHECKING: from typing_extensions import Protocol class MgrModuleProtocol(Protocol): - def tool_exec(self, args: List[str]) -> Tuple[int, str, str]: + def tool_exec(self, args: List[str], timeout: int = 10, stdin: Optional[bytes] = None) -> Tuple[int, str, str]: ... def apply_rgw(self, spec: RGWSpec) -> OrchResult[str]: @@ -66,9 +66,9 @@ class RGWAMOrchMgr(RGWAMEnvMgr): def __init__(self, mgr: MgrModuleProtocol): self.mgr = mgr - def tool_exec(self, prog: str, args: List[str]) -> Tuple[List[str], int, str, str]: + def tool_exec(self, prog: str, args: List[str], stdin: Optional[bytes] = None) -> Tuple[List[str], int, str, str]: cmd = [prog] + args - rc, stdout, stderr = self.mgr.tool_exec(args=cmd) + rc, stdout, stderr = self.mgr.tool_exec(args=cmd, stdin=stdin) return cmd, rc, stdout, stderr def apply_rgw(self, spec: RGWSpec) -> None: @@ -286,6 +286,18 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule): self.log.error('cmd run exception: (%d) %s' % (e.retcode, e.message)) return HandleCommandResult(retval=e.retcode, stdout=e.stdout, stderr=e.stderr) + @CLICommand('rgw zonegroup modify', perm='rw') + def update_zonegroup_info(self, realm_name: str, zonegroup_name: str, zone_name: str, hostnames: List[str]) -> HandleCommandResult: + try: + retval, out, err = RGWAM(self.env).zonegroup_modify(realm_name, + zonegroup_name, + zone_name, + hostnames) + return HandleCommandResult(retval, 'Zonegroup updated successfully', '') + except RGWAMException as e: + self.log.error('cmd run exception: (%d) %s' % (e.retcode, e.message)) + return HandleCommandResult(retval=e.retcode, stdout=e.stdout, stderr=e.stderr) + @CLICommand('rgw zone create', perm='rw') @check_orchestrator def _cmd_rgw_zone_create(self, diff --git a/src/python-common/ceph/deployment/service_spec.py b/src/python-common/ceph/deployment/service_spec.py index f6d290f071888..3e9e301102462 100644 --- a/src/python-common/ceph/deployment/service_spec.py +++ b/src/python-common/ceph/deployment/service_spec.py @@ -1169,10 +1169,11 @@ class RGWSpec(ServiceSpec): rgw_realm_token: Optional[str] = None, update_endpoints: Optional[bool] = False, zone_endpoints: Optional[str] = None, # comma separated endpoints list + zonegroup_hostnames: Optional[str] = None, rgw_user_counters_cache: Optional[bool] = False, rgw_user_counters_cache_size: Optional[int] = None, rgw_bucket_counters_cache: Optional[bool] = False, - rgw_bucket_counters_cache_size: Optional[int] = None + rgw_bucket_counters_cache_size: Optional[int] = None, ): assert service_type == 'rgw', service_type @@ -1212,6 +1213,7 @@ class RGWSpec(ServiceSpec): self.rgw_realm_token = rgw_realm_token self.update_endpoints = update_endpoints self.zone_endpoints = zone_endpoints + self.zonegroup_hostnames = zonegroup_hostnames #: To track op metrics by user config value rgw_user_counters_cache must be set to true self.rgw_user_counters_cache = rgw_user_counters_cache diff --git a/src/python-common/ceph/rgw/rgwam_core.py b/src/python-common/ceph/rgw/rgwam_core.py index 7041ea1544f00..333f490158525 100644 --- a/src/python-common/ceph/rgw/rgwam_core.py +++ b/src/python-common/ceph/rgw/rgwam_core.py @@ -149,11 +149,12 @@ class RGWCmdBase: opt_arg(self.cmd_suffix, '--rgw-zone', zone_env.zone.name) opt_arg(self.cmd_suffix, '--zone-id', zone_env.zone.id) - def run(self, cmd): + def run(self, cmd, stdin=None): args = cmd + self.cmd_suffix - cmd, returncode, stdout, stderr = self.mgr.tool_exec(self.prog, args) + cmd, returncode, stdout, stderr = self.mgr.tool_exec(self.prog, args, stdin) log.debug('cmd=%s' % str(cmd)) + log.debug(f'stdin={stdin}') log.debug('stdout=%s' % stdout) if returncode != 0: @@ -174,8 +175,8 @@ class RGWAdminJSONCmd(RGWAdminCmd): def __init__(self, zone_env: ZoneEnv): super().__init__(zone_env) - def run(self, cmd): - stdout, _ = RGWAdminCmd.run(self, cmd) + def run(self, cmd, stdin=None): + stdout, _ = RGWAdminCmd.run(self, cmd, stdin) return json.loads(stdout) @@ -237,9 +238,13 @@ class ZonegroupOp: def get(self, zonegroup: EntityKey = None): ze = ZoneEnv(self.env) params = ['zonegroup', 'get'] - opt_arg(params, '--rgw-zonegroup', zonegroup) return RGWAdminJSONCmd(ze).run(params) + def set(self, zonegroup: EntityKey, zg_json: str): + ze = ZoneEnv(self.env) + params = ['zonegroup', 'set'] + return RGWAdminJSONCmd(ze).run(params, stdin=zg_json.encode('utf-8')) + def create(self, realm: EntityKey, zg: EntityKey = None, endpoints=None, is_master=True): ze = ZoneEnv(self.env, realm=realm).init_zg(zg, gen=True) @@ -724,6 +729,43 @@ class RGWAM: return (0, success_message, '') + def zonegroup_modify(self, realm_name, zonegroup_name, zone_name, hostnames): + if realm_name is None: + raise RGWAMException('Realm name is a mandatory parameter') + if zone_name is None: + raise RGWAMException('Zone name is a mandatory parameter') + if zonegroup_name is None: + raise RGWAMException('Zonegroup name is a mandatory parameter') + + realm = EntityName(realm_name) + zone = EntityName(zone_name) + period_info = self.period_op().get(realm) + period = RGWPeriod(period_info) + logging.info('Period: ' + period.id) + zonegroup = period.find_zonegroup_by_name(zonegroup_name) + if not zonegroup: + raise RGWAMException(f'zonegroup {zonegroup_name} not found') + zg = EntityName(zonegroup.name) + zg_json = self.zonegroup_op().get(zg) + + if hostnames: + zg_json['hostnames'] = hostnames + + try: + self.zonegroup_op().set(zg, json.dumps(zg_json)) + except RGWAMException as e: + raise RGWAMException('failed to set zonegroup', e) + + try: + period_info = self.period_op().update(realm, zg, zone, True) + except RGWAMException as e: + raise RGWAMException('failed to update period', e) + + period = RGWPeriod(period_info) + logging.debug(period.to_json()) + + return (0, f'Modified zonegroup {zonegroup_name} of realm {realm_name}', '') + def get_realms_info(self): realms_info = [] for realm_name in self.realm_op().list(): -- 2.39.5