From: Redouane Kachach Date: Tue, 11 Oct 2022 11:36:24 +0000 (+0200) Subject: Fixing rwg spec parsing + improving error handling X-Git-Tag: v17.2.7~485^2~12 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=680b2006082c2eca65322cdd1a00492c8e0bcb37;p=ceph.git Fixing rwg spec parsing + improving error handling Signed-off-by: Redouane Kachach (cherry picked from commit 34ebd7c5b4a52ddc90748eeebe8835ccc17b8af7) --- diff --git a/src/pybind/mgr/rgw/module.py b/src/pybind/mgr/rgw/module.py index b6ff1bbaae81..1c3ee3cdf6b4 100644 --- a/src/pybind/mgr/rgw/module.py +++ b/src/pybind/mgr/rgw/module.py @@ -8,7 +8,7 @@ import functools from mgr_module import MgrModule, CLICommand, HandleCommandResult import orchestrator -from ceph.deployment.service_spec import RGWSpec, PlacementSpec +from ceph.deployment.service_spec import RGWSpec, PlacementSpec, SpecValidationError from typing import Any, Optional, Sequence, Iterator, List from ceph.rgw.types import RGWAMException, RGWAMEnvMgr, RealmToken @@ -16,6 +16,10 @@ from ceph.rgw.rgwam_core import EnvArgs, RGWAM from orchestrator import OrchestratorClientMixin, OrchestratorError +class RGWSpecParsingError(Exception): + pass + + class OrchestratorAPI(OrchestratorClientMixin): def __init__(self, mgr): super(OrchestratorAPI, self).__init__() @@ -28,6 +32,7 @@ class OrchestratorAPI(OrchestratorClientMixin): except (RuntimeError, OrchestratorError, ImportError) as e: return dict(available=False, message=f'Orchestrator is unavailable: {e}') + class RGWAMOrchMgr(RGWAMEnvMgr): def __init__(self, mgr): self.mgr = mgr @@ -130,7 +135,10 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule): """Bootstrap new rgw realm, zonegroup, and zone""" if inbuf: - rgw_specs = self._parse_rgw_specs(inbuf) + try: + rgw_specs = self._parse_rgw_specs(inbuf) + except RGWSpecParsingError as e: + return HandleCommandResult(retval=-errno.EINVAL, stderr=f'{e}') elif (realm_name and zonegroup_name and zone_name): placement_spec = PlacementSpec.from_string(placement) if placement else None rgw_specs = [RGWSpec(rgw_realm=realm_name, @@ -147,7 +155,7 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule): RGWAM(self.env).realm_bootstrap(spec, start_radosgw) except RGWAMException as e: self.log.error('cmd run exception: (%d) %s' % (e.retcode, e.message)) - return (e.retcode, e.message, e.stderr) + return HandleCommandResult(retval=e.retcode, stdout=e.stdout, stderr=e.stderr) return HandleCommandResult(retval=0, stdout="Realm(s) created correctly. Please, use 'ceph rgw realm tokens' to get the token.", stderr='') @@ -159,9 +167,22 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule): specs = [o for o in yaml_objs if o is not None] rgw_specs = [] for spec in specs: - rgw_spec = RGWSpec.from_json(spec) - rgw_spec.validate() - rgw_specs.append(rgw_spec) + # A secondary zone spec normally contains only the zone and the reaml token + # since no rgw_realm is specified in this case we extract it from the token + if 'rgw_realm_token' in spec: + realm_token = RealmToken.from_base64_str(spec['rgw_realm_token']) + if realm_token is None: + raise RGWSpecParsingError(f"Invalid realm token: {spec['rgw_realm_token']}") + spec['rgw_realm'] = realm_token.realm_name + + try: + rgw_spec = RGWSpec.from_json(spec) + rgw_spec.validate() + except SpecValidationError as e: + raise RGWSpecParsingError(f'RGW Spec parsing/validation error: {e}') + else: + rgw_specs.append(rgw_spec) + return rgw_specs @CLICommand('rgw realm zone-creds create', perm='rw') @@ -175,7 +196,7 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule): retval, out, err = RGWAM(self.env).realm_new_zone_creds(realm_name, endpoints, sys_uid) except RGWAMException as e: self.log.error('cmd run exception: (%d) %s' % (e.retcode, e.message)) - return (e.retcode, e.message, e.stderr) + return HandleCommandResult(retval=e.retcode, stdout=e.stdout, stderr=e.stderr) return HandleCommandResult(retval=retval, stdout=out, stderr=err) @@ -187,7 +208,7 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule): retval, out, err = RGWAM(self.env).realm_rm_zone_creds(realm_token) except RGWAMException as e: self.log.error('cmd run exception: (%d) %s' % (e.retcode, e.message)) - return (e.retcode, e.message, e.stderr) + return HandleCommandResult(retval=e.retcode, stdout=e.stdout, stderr=e.stderr) return HandleCommandResult(retval=retval, stdout=out, stderr=err) @@ -210,7 +231,7 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule): realms_info.append({'realm': realm_info['realm_name'], 'token': realm_token_s}) except RGWAMException as e: self.log.error(f'cmd run exception: ({e.retcode}) {e.message}') - return (e.retcode, e.message, e.stderr) + return HandleCommandResult(retval=e.retcode, stdout=e.stdout, stderr=e.stderr) return HandleCommandResult(retval=0, stdout=json.dumps(realms_info, indent=4), stderr='') @@ -225,7 +246,7 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule): return (retval, 'Zone updated successfully', '') except RGWAMException as e: self.log.error('cmd run exception: (%d) %s' % (e.retcode, e.message)) - return (e.retcode, e.message, e.stderr) + return HandleCommandResult(retval=e.retcode, stdout=e.stdout, stderr=e.stderr) @CLICommand('rgw zone create', perm='rw') @check_orchestrator() @@ -239,11 +260,16 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule): """Bootstrap new rgw zone that syncs with zone on another cluster in the same realm""" if inbuf: - rgw_specs = self._parse_rgw_specs(inbuf) + try: + rgw_specs = self._parse_rgw_specs(inbuf) + except RGWSpecParsingError as e: + return HandleCommandResult(retval=-errno.EINVAL, stderr=f'{e}') elif (zone_name and realm_token): + token = RealmToken.from_base64_str(realm_token) placement_spec = PlacementSpec.from_string(placement) if placement else None - rgw_specs = [RGWSpec(rgw_realm_token=realm_token, + rgw_specs = [RGWSpec(rgw_realm=token.realm_name, rgw_zone=zone_name, + rgw_realm_token=realm_token, rgw_frontend_port=port, placement=placement_spec)] else: @@ -257,7 +283,7 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule): break except RGWAMException as e: self.log.error('cmd run exception: (%d) %s' % (e.retcode, e.message)) - return (e.retcode, e.message, e.stderr) + return HandleCommandResult(retval=e.retcode, stdout=e.stdout, stderr=e.stderr) return HandleCommandResult(retval=retval, stdout=out, stderr=err) @@ -276,7 +302,7 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule): zonegroup_is_master) except RGWAMException as e: self.log.error('cmd run exception: (%d) %s' % (e.retcode, e.message)) - return (e.retcode, e.message, e.stderr) + return HandleCommandResult(retval=e.retcode, stdout=e.stdout, stderr=e.stderr) return HandleCommandResult(retval=retval, stdout=out, stderr=err) @@ -293,7 +319,7 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule): zone_name, update) except RGWAMException as e: self.log.error('cmd run exception: (%d) %s' % (e.retcode, e.message)) - return (e.retcode, e.message, e.stderr) + return HandleCommandResult(retval=e.retcode, stdout=e.stdout, stderr=e.stderr) return HandleCommandResult(retval=retval, stdout=out, stderr=err) diff --git a/src/python-common/ceph/deployment/service_spec.py b/src/python-common/ceph/deployment/service_spec.py index 5f31b38694b0..a5cf4e455f39 100644 --- a/src/python-common/ceph/deployment/service_spec.py +++ b/src/python-common/ceph/deployment/service_spec.py @@ -932,13 +932,7 @@ class RGWSpec(ServiceSpec): raise SpecValidationError( 'Cannot add RGW: Realm specified but no zone specified') if self.rgw_zone and not self.rgw_realm: - raise SpecValidationError( - 'Cannot add RGW: Zone specified but no realm specified') - if not (self.rgw_realm and not self.rgw_zonegroup): - if self.rgw_realm_token and not self.rgw_zone: - raise SpecValidationError('Cannot add RGW: Token specified but no zone specified') - elif self.rgw_zone and not self.rgw_realm_token: - raise SpecValidationError('Cannot add RGW: Zone specified but no token specified') + raise SpecValidationError('Cannot add RGW: Zone specified but no realm specified') yaml.add_representer(RGWSpec, ServiceSpec.yaml_representer) diff --git a/src/python-common/ceph/rgw/types.py b/src/python-common/ceph/rgw/types.py index 4b894f29755a..bf434168bf5d 100644 --- a/src/python-common/ceph/rgw/types.py +++ b/src/python-common/ceph/rgw/types.py @@ -1,5 +1,7 @@ import json import base64 +import binascii +import errno from abc import abstractmethod @@ -13,9 +15,9 @@ class RGWAMException(Exception): self.stderr = orig.stdout else: self.message = message - self.retcode = 0 - self.stdout = None - self.stderr = None + self.retcode = -errno.EINVAL + self.stdout = '' + self.stderr = message class RGWAMCmdRunException(RGWAMException): @@ -58,11 +60,13 @@ class RealmToken(JSONObj): @classmethod def from_base64_str(cls, realm_token_b64): - realm_token_b = base64.b64decode(realm_token_b64) - realm_token_s = realm_token_b.decode('utf-8') - realm_token = json.loads(realm_token_s) - return cls(**realm_token) - + try: + realm_token_b = base64.b64decode(realm_token_b64) + realm_token_s = realm_token_b.decode('utf-8') + realm_token = json.loads(realm_token_s) + return cls(**realm_token) + except binascii.Error: + return None class RGWZone(JSONObj): def __init__(self, zone_dict):