]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/rgw: add standalone cli util
authorYehuda Sadeh <yehuda@redhat.com>
Mon, 28 Jun 2021 21:53:14 +0000 (14:53 -0700)
committerYehuda Sadeh <yehuda@redhat.com>
Wed, 24 Nov 2021 20:54:30 +0000 (12:54 -0800)
for external testing

Signed-off-by: Yehuda Sadeh <yehuda@redhat.com>
src/pybind/mgr/rgw/__init__.py
src/pybind/mgr/rgw/cli.py [new file with mode: 0755]
src/pybind/mgr/rgw/module.py
src/pybind/mgr/rgw/rgwam.py
src/pybind/mgr/rgw/types.py

index d4d473cd562f142f5065526e328ca70cc6fd57ed..cfcdc91056e383406d38e403d036867927872baf 100644 (file)
@@ -1,4 +1,7 @@
-from .module import Module
+try:
+    from .module import Module
+except ImportError:
+    pass
 
 import logging
 
diff --git a/src/pybind/mgr/rgw/cli.py b/src/pybind/mgr/rgw/cli.py
new file mode 100755 (executable)
index 0000000..2b3287c
--- /dev/null
@@ -0,0 +1,222 @@
+#!@Python3_EXECUTABLE@
+# -*- mode:python -*-
+# vim: ts=4 sw=4 smarttab expandtab
+#
+# Processed in Makefile to add python #! line and version variable
+#
+#
+
+import subprocess
+import random
+import string
+import json
+import argparse
+import sys
+import socket
+import base64
+import logging
+
+from urllib.parse import urlparse
+
+from .rgwam import RGWAM, EnvArgs
+from .types import RGWAMEnvMgr, RGWAMException
+
+class RGWAMCLIMgr(RGWAMEnvMgr):
+    def __init__(self):
+        pass
+
+    def apply_rgw(self, svc_id, realm_name, zone_name, port = None):
+        return None
+
+    def list_daemons(self, service_name, daemon_type = None, daemon_id = None, hostname = None, refresh = True):
+        return []
+
+class RealmCommand:
+    def __init__(self, env, args):
+        self.env = env
+        self.args = args
+
+    def parse(self):
+        parser = argparse.ArgumentParser(
+            usage='''rgwam realm <subcommand>
+
+The subcommands are:
+   bootstrap                     Bootstrap new realm
+   new-zone-creds                Create credentials for connecting new zone
+''')
+        parser.add_argument('subcommand', help='Subcommand to run')
+        # parse_args defaults to [1:] for args, but you need to
+        # exclude the rest of the args too, or validation will fail
+        args = parser.parse_args(self.args[0:1])
+
+        sub = args.subcommand.replace('-', '_')
+
+        if not hasattr(self, sub):
+            print('Unrecognized subcommand:', args.subcommand)
+            parser.print_help()
+            exit(1)
+        # use dispatch pattern to invoke method with same name
+
+        return getattr(self, sub)
+
+    def bootstrap(self):
+        parser = argparse.ArgumentParser(
+            description='Bootstrap new realm',
+            usage='rgwam realm bootstrap [<args>]')
+        parser.add_argument('--realm')
+        parser.add_argument('--zonegroup')
+        parser.add_argument('--zone')
+        parser.add_argument('--endpoints')
+        parser.add_argument('--sys-uid')
+        parser.add_argument('--uid')
+        parser.add_argument('--start-radosgw', action='store_true', dest='start_radosgw', default=True)
+        parser.add_argument('--no-start-radosgw', action='store_false', dest='start_radosgw')
+
+        args = parser.parse_args(self.args[1:])
+
+        return RGWAM(self.env).realm_bootstrap(args.realm, args.zonegroup, args.zone, args.endpoints,
+                args.sys_uid, args.uid, args.start_radosgw)
+
+    def new_zone_creds(self):
+        parser = argparse.ArgumentParser(
+            description='Bootstrap new realm',
+            usage='rgwam realm new-zone-creds [<args>]')
+        parser.add_argument('--endpoints')
+        parser.add_argument('--sys-uid')
+
+        args = parser.parse_args(self.args[1:])
+
+        return RGWAM(self.env).realm_new_zone_creds(args.endpoints, args.sys_uid)
+
+
+class ZoneCommand:
+    def __init__(self, env, args):
+        self.env = env
+        self.args = args
+
+    def parse(self):
+        parser = argparse.ArgumentParser(
+            usage='''rgwam zone <subcommand>
+
+The subcommands are:
+   run                     run radosgw daemon in current zone
+''')
+        parser.add_argument('subcommand', help='Subcommand to run')
+        # parse_args defaults to [1:] for args, but you need to
+        # exclude the rest of the args too, or validation will fail
+        args = parser.parse_args(self.args[0:1])
+        if not hasattr(self, args.subcommand):
+            print('Unrecognized subcommand:', args.subcommand)
+            parser.print_help()
+            exit(1)
+        # use dispatch pattern to invoke method with same name
+        return getattr(self, args.subcommand)
+
+    def run(self):
+        parser = argparse.ArgumentParser(
+            description='Run radosgw daemon',
+            usage='rgwam zone run [<args>]')
+        parser.add_argument('--port')
+        parser.add_argument('--log-file')
+        parser.add_argument('--debug-ms')
+        parser.add_argument('--debug-rgw')
+
+        args = parser.parse_args(self.args[1:])
+
+        return RGWAM(self.env).run_radosgw(port = args.port)
+
+    def create(self):
+        parser = argparse.ArgumentParser(
+            description='Create new zone to join existing realm',
+            usage='rgwam zone create [<args>]')
+        parser.add_argument('--realm-token')
+        parser.add_argument('--zone')
+        parser.add_argument('--zonegroup')
+        parser.add_argument('--endpoints')
+        parser.add_argument('--start-radosgw', action='store_true', dest='start_radosgw', default=True)
+        parser.add_argument('--no-start-radosgw', action='store_false', dest='start_radosgw')
+
+        args = parser.parse_args(self.args[1:])
+
+        return RGWAM(self.env).zone_create(args.realm_token, args.zonegroup, args.zone, args.endpoints, args.start_radosgw)
+
+class CommonArgs:
+    def __init__(self, ns):
+        self.conf_path = ns.conf_path
+        self.ceph_name = ns.ceph_name
+        self.ceph_keyring = ns.ceph_keyring
+
+class TopLevelCommand:
+
+    def _parse(self):
+        parser = argparse.ArgumentParser(
+            description='RGW assist for multisite tool',
+            formatter_class=argparse.RawDescriptionHelpFormatter,
+            epilog='''
+The commands are:
+   realm bootstrap               Bootstrap new realm
+   realm new-zone-creds          Create credentials to connect new zone to realm
+   zone create                   Create new zone and connect it to existing realm
+   zone run                      Run radosgw in current zone
+''')
+
+        parser.add_argument('command', help='command to run', default=None)
+        parser.add_argument('-c', help='ceph conf path', dest='conf_path')
+        parser.add_argument('-n', help='ceph user name', dest='ceph_name')
+        parser.add_argument('-k', help='ceph keyring', dest='ceph_keyring')
+
+        removed_args = []
+
+        args = sys.argv[1:]
+        if len(args) > 0:
+            if hasattr(self, args[0]):
+                # remove -h/--help if top command is not empty so that top level help
+                # doesn't override subcommand, we'll add it later
+                help_args = [ '-h', '--help' ]
+                removed_args = [arg for arg in args if arg in help_args]
+                args = [arg for arg in args if arg not in help_args]
+
+        (ns, args) = parser.parse_known_args(args)
+        if not hasattr(self, ns.command) or ns.command[0] == '_':
+            print('Unrecognized command:', ns.command)
+            parser.print_help()
+            exit(1)
+        # use dispatch pattern to invoke method with same name
+        args += removed_args
+        return (getattr(self, ns.command), CommonArgs(ns), args)
+
+    def realm(self, env, args):
+        cmd = RealmCommand(env, args).parse()
+        return cmd()
+
+    def zone(self, env, args):
+        cmd = ZoneCommand(env, args).parse()
+        return cmd()
+
+
+def main():
+    logging.basicConfig(level=logging.INFO)
+
+    log = logging.getLogger(__name__)
+
+    (cmd, common_args, args)= TopLevelCommand()._parse()
+
+    env = EnvArgs(RGWAMCLIMgr(),
+                  common_args.conf_path,
+                  common_args.ceph_name,
+                  common_args.ceph_keyring)
+
+    try:
+        retval, out, err = cmd(env, args)
+        if retval != 0:
+            log.error('stdout: '+ out + '\nstderr: ' + err)
+            sys.exit(retval)
+    except RGWAMException as e:
+        print('ERROR: ' + e.message)
+
+    sys.exit(0)
+
+
+if __name__ == '__main__':
+    main()
+
index 20bd759cd22a25b08ddc3d384258d21bea47bd48..15525f6d32a5f285836d2f29760bc700e2ad6114 100644 (file)
@@ -6,13 +6,36 @@ import subprocess
 from mgr_module import MgrModule, CLICommand, HandleCommandResult, Option
 import orchestrator
 
+from ceph.deployment.service_spec import RGWSpec
+
 from typing import cast, Any, Optional, Sequence
 
 from . import *
-from .types import RGWAMException
+from .types import RGWAMException, RGWAMEnvMgr
 from .rgwam import EnvArgs, RGWAM
 
 
+class RGWAMOrchMgr(RGWAMEnvMgr):
+    def __init__(self, mgr):
+        self.mgr = mgr
+
+    def apply_rgw(self, svc_id, realm_name, zone_name, port = None):
+        spec = RGWSpec(service_id = svc_id,
+                       rgw_realm = realm_name,
+                       rgw_zone = zone_name,
+                       rgw_frontend_port = port)
+        completion = self.mgr.apply_rgw(spec)
+        orchestrator.raise_if_exception(completion)
+
+    def list_daemons(self, service_name, daemon_type = None, daemon_id = None, host = None, refresh = True):
+        completion = self.mgr.list_daemons(service_name,
+                                           daemon_type,
+                                           daemon_id=daemon_id,
+                                           host=host,
+                                           refresh=refresh)
+        return orchestrator.raise_if_exception(completion)
+
+
 class Module(orchestrator.OrchestratorClientMixin, MgrModule):
     MODULE_OPTIONS = []
 
@@ -29,7 +52,7 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
 
         with self.lock:
             self.inited = True
-            self.env = EnvArgs(self,
+            self.env = EnvArgs(RGWAMOrchMgr(self),
                                str(self.get_ceph_conf_path()),
                                f'mgr.{self.get_mgr_id()}',
                                str(self.get_ceph_option('keyring')))
index 521b86fe3429ba807b4712a3cad27bd0af7d7090..2b7634834480a82216bd806c72fadde561f644a6 100644 (file)
@@ -17,15 +17,11 @@ import base64
 import logging
 import errno
 
-import orchestrator
-
 from urllib.parse import urlparse
 
 from .types import RGWAMException, RGWAMCmdRunException, RGWPeriod, RGWUser, RealmToken
 from .diff import RealmsEPs
 
-from ceph.deployment.service_spec import RGWSpec
-
 
 DEFAULT_PORT = 8000
 
@@ -433,11 +429,7 @@ class RGWAM:
             if start_radosgw:
                 o = urlparse(ep)
                 svc_id = realm_name  + '.' + zone_name
-                spec = RGWSpec(service_id = svc_id,
-                               rgw_realm = realm_name,
-                               rgw_zone = zone_name,
-                               rgw_frontend_port = o.port)
-                self.env.mgr.apply_rgw(spec)
+                self.env.mgr.apply_rgw(svc_id, realm_name, zone_name, o.port)
 
         realm_token = RealmToken(ep, sys_user.uid, sys_access_key, sys_secret)
 
@@ -577,16 +569,9 @@ class RGWAM:
         #                       rgw_frontend_port = o.port)
         #        self.env.mgr.apply_rgw(spec)
 
-        spec = RGWSpec(service_id = svc_id,
-                       rgw_realm = realm_name,
-                       rgw_zone = zone_name)
-
-        completion = self.env.mgr.apply_rgw(spec)
-        orchestrator.raise_if_exception(completion)
+        self.env.mgr.apply_rgw(svc_id, realm_name, zone_name)
 
-        completion = self.env.mgr.list_daemons(svc_id, 'rgw', refresh=True)
-
-        daemons = orchestrator.raise_if_exception(completion)
+        daemons = self.env.mgr.list_daemons(svc_id, 'rgw', refresh=True)
 
         ep = []
         for s in daemons:
@@ -614,13 +599,11 @@ class RGWAM:
         hostname = None
         refresh = True
 
-        completion = self.env.mgr.list_daemons(service_name,
-                                               daemon_type,
-                                               daemon_id=daemon_id,
-                                               host=hostname,
-                                               refresh=refresh)
-
-        daemons = orchestrator.raise_if_exception(completion)
+        daemons = self.env.mgr.list_daemons(service_name,
+                                            daemon_type,
+                                            daemon_id=daemon_id,
+                                            host=hostname,
+                                            refresh=refresh)
 
         rep = RealmsEPs()
 
index 8ef0feaf76442215bdd66b843f70b098edaf851a..7f781c2fb0075d1bde6a67092476d3cc85415a05 100644 (file)
@@ -1,5 +1,7 @@
 import json
 
+from abc import abstractmethod
+
 class RGWAMException(Exception):
     def __init__(self, message, orig = None):
         if orig:
@@ -20,6 +22,15 @@ class RGWAMCmdRunException(RGWAMException):
         self.stdout = stdout
         self.stderr = stderr
 
+class RGWAMEnvMgr:
+    @abstractmethod
+    def apply_rgw(self, svc_id, realm_name, zone_name, port = None):
+        pass
+
+    @abstractmethod
+    def list_daemons(self, service_name, daemon_type = None, daemon_id = None, hostname = None, refresh = True):
+        pass
+
 
 class JSONObj:
     def to_json(self):