]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/rgw: add realm bootstrap command based on rgwam
authorYehuda Sadeh <yehuda@redhat.com>
Mon, 24 May 2021 23:47:00 +0000 (16:47 -0700)
committerYehuda Sadeh <yehuda@redhat.com>
Wed, 24 Nov 2021 20:54:29 +0000 (12:54 -0800)
Signed-off-by: Yehuda Sadeh <yehuda@redhat.com>
src/pybind/mgr/rgw/__init__.py
src/pybind/mgr/rgw/module.py
src/pybind/mgr/rgw/types.py [new file with mode: 0644]

index 8f210ac9247ea49624b20582ca8206e56055fbcd..d4d473cd562f142f5065526e328ca70cc6fd57ed 100644 (file)
@@ -1 +1,5 @@
 from .module import Module
+
+import logging
+
+log = logging.getLogger(__name__)
index 859b764613649140d666e653a41ff10686f69e77..003dd8b7c88d5253cfe74f1925ff0c5f6246b34c 100644 (file)
@@ -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 (file)
index 0000000..f9f5448
--- /dev/null
@@ -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')
+
+