From fc2fb976d0b6d3e9bea7b5d80f354fd620f5a120 Mon Sep 17 00:00:00 2001 From: Yehuda Sadeh Date: Mon, 24 May 2021 16:47:00 -0700 Subject: [PATCH] mgr/rgw: add realm bootstrap command based on rgwam Signed-off-by: Yehuda Sadeh --- src/pybind/mgr/rgw/__init__.py | 4 + src/pybind/mgr/rgw/module.py | 32 +++++++- src/pybind/mgr/rgw/types.py | 129 +++++++++++++++++++++++++++++++++ 3 files changed, 163 insertions(+), 2 deletions(-) create mode 100644 src/pybind/mgr/rgw/types.py diff --git a/src/pybind/mgr/rgw/__init__.py b/src/pybind/mgr/rgw/__init__.py index 8f210ac9247..d4d473cd562 100644 --- a/src/pybind/mgr/rgw/__init__.py +++ b/src/pybind/mgr/rgw/__init__.py @@ -1 +1,5 @@ from .module import Module + +import logging + +log = logging.getLogger(__name__) diff --git a/src/pybind/mgr/rgw/module.py b/src/pybind/mgr/rgw/module.py index 859b7646136..003dd8b7c88 100644 --- a/src/pybind/mgr/rgw/module.py +++ b/src/pybind/mgr/rgw/module.py @@ -7,7 +7,9 @@ from mgr_module import MgrModule, CLICommand, HandleCommandResult, Option from typing import cast, Any, Optional, Sequence -log = logging.getLogger(__name__) +from . import * +from .types import RGWAMException +from .rgwam import CephCommonArgs, RGWAM class Module(MgrModule): @@ -26,6 +28,11 @@ class Module(MgrModule): # ensure config options members are initialized; see config_notify() self.config_notify() + self.ceph_common_args = CephCommonArgs(str(self.get_ceph_conf_path()), + f'mgr.{self.get_mgr_id()}', + str(self.get_ceph_option('keyring'))) + + def config_notify(self) -> None: """ This method is called whenever one of our config options is changed. @@ -46,10 +53,10 @@ class Module(MgrModule): self.get_ceph_option(opt)) self.log.debug(' native option %s = %s', opt, getattr(self, opt)) + @CLICommand('rgw admin', perm='rw') def _cmd_rgw_admin(self, params: Sequence[str]): """rgw admin""" - log.error('self.config=%s' % str(self.get_ceph_conf_path())) run_cmd = [ './bin/radosgw-admin', '-c', str(self.get_ceph_conf_path()), '-k', str(self.get_ceph_option('keyring')), @@ -66,6 +73,27 @@ class Module(MgrModule): return HandleCommandResult(retval=result.returncode, stdout=out, stderr=err) + @CLICommand('rgw realm bootstrap', perm='rw') + def _cmd_rgw_realm_bootstrap(self, + realm_name : Optional[str] = None, + zonegroup_name: Optional[str] = None, + zone_name: Optional[str] = None, + endpoints: Optional[str] = None, + sys_uid: Optional[str] = None, + uid: Optional[str] = None, + start_radosgw: Optional[bool] = False): + """Bootstrap new rgw realm, zonegroup, and zone""" + + + try: + retval, out, err = RGWAM(self.ceph_common_args).realm_bootstrap(realm_name, zonegroup_name, + zone_name, endpoints, sys_uid, uid, 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=retval, stdout=out, stderr=err) + def shutdown(self) -> None: """ This method is called by the mgr when the module needs to shut diff --git a/src/pybind/mgr/rgw/types.py b/src/pybind/mgr/rgw/types.py new file mode 100644 index 00000000000..f9f5448af8f --- /dev/null +++ b/src/pybind/mgr/rgw/types.py @@ -0,0 +1,129 @@ +import json + +class RGWAMException(Exception): + def __init__(self, message, orig = None): + if orig: + self.message = message + ': ' + orig.message + self.retcode = orig.retcode + self.stdout = orig.stdout + self.stderr = orig.stdout + else: + self.message = message + self.retcode = 0 + self.stdout = None + self.stderr = None + +class RGWAMCmdRunException(RGWAMException): + def __init__(self, cmd, retcode, stdout, stderr): + super().__init__('Command error (%d): %s\nstdout:%s\nstderr:%s' % (retcode, cmd, stdout, stderr)) + self.retcode = retcode + self.stdout = stdout + self.stderr = stderr + + +class JSONObj: + def to_json(self): + return json.dumps(self, default=lambda o: o.__dict__, indent=4) + +class RealmToken(JSONObj): + def __init__(self, endpoint, uid, access_key, secret): + self.endpoint = endpoint + self.uid = uid + self.access_key = access_key + self.secret = secret + +class RGWZone(JSONObj): + def __init__(self, zone_dict): + self.id = zone_dict['id'] + self.name = zone_dict['name'] + self.endpoints = zone_dict['endpoints'] + +class RGWZoneGroup(JSONObj): + def __init__(self, zg_dict): + self.id = zg_dict['id'] + self.name = zg_dict['name'] + self.api_name = zg_dict['api_name'] + self.is_master = zg_dict['is_master'] + self.endpoints = zg_dict['endpoints'] + + self.zones_by_id = {} + self.zones_by_name = {} + self.all_endpoints = [] + + for zone in zg_dict['zones']: + z = RGWZone(zone) + self.zones_by_id[zone['id']] = z + self.zones_by_name[zone['name']] = z + self.all_endpoints += z.endpoints + + def endpoint_exists(self, endpoint): + for ep in self.all_endpoints: + if ep == endpoint: + return True + return False + + def get_zone_endpoints(self, zone_id): + z = self.zones_by_id.get(zone_id) + if not z: + return None + + return z.endpoints + +class RGWPeriod(JSONObj): + def __init__(self, period_dict): + self.id = period_dict['id'] + self.epoch = period_dict['epoch'] + self.master_zone = period_dict['master_zone'] + self.master_zonegroup = period_dict['master_zonegroup'] + pm = period_dict['period_map'] + self.zonegroups_by_id = {} + self.zonegroups_by_name = {} + + for zg in pm['zonegroups']: + self.zonegroups_by_id[zg['id']] = RGWZoneGroup(zg) + self.zonegroups_by_name[zg['name']] = RGWZoneGroup(zg) + + def endpoint_exists(self, endpoint): + for _, zg in self.zonegroups_by_id.items(): + if zg.endpoint_exists(endpoint): + return True + return False + + def find_zonegroup_by_name(self, zonegroup): + if not zonegroup: + return self.find_zonegroup_by_id(self.master_zonegroup) + return self.zonegroups_by_name.get(zonegroup) + + def find_zonegroup_by_id(self, zonegroup): + return self.zonegroups_by_id.get(zonegroup) + + def get_zone_endpoints(self, zonegroup_id, zone_id): + zg = self.zonegroups_by_id.get(zonegroup_id) + if not zg: + return None + + return zg.get_zone_endpoints(zone_id) + + + +class RGWAccessKey(JSONObj): + def __init__(self, d): + self.uid = d['user'] + self.access_key = d['access_key'] + self.secret_key = d['secret_key'] + +class RGWUser(JSONObj): + def __init__(self, d): + self.uid = d['user_id'] + self.display_name = d['display_name'] + self.email = d['email'] + + self.keys = [] + + for k in d['keys']: + self.keys.append(RGWAccessKey(k)) + + is_system = d.get('system') or 'false' + self.system = (is_system == 'true') + + -- 2.39.5