From: Yehuda Sadeh Date: Mon, 28 Jun 2021 21:53:14 +0000 (-0700) Subject: mgr/rgw: add standalone cli util X-Git-Tag: v17.1.0~340^2~11 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=32cff8f16b4f55bae39f434157e41681b49f32a8;p=ceph.git mgr/rgw: add standalone cli util for external testing Signed-off-by: Yehuda Sadeh --- diff --git a/src/pybind/mgr/rgw/__init__.py b/src/pybind/mgr/rgw/__init__.py index d4d473cd562..cfcdc91056e 100644 --- a/src/pybind/mgr/rgw/__init__.py +++ b/src/pybind/mgr/rgw/__init__.py @@ -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 index 00000000000..2b3287cbaa3 --- /dev/null +++ b/src/pybind/mgr/rgw/cli.py @@ -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 + +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 []') + 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 []') + 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 + +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 []') + 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 []') + 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() + diff --git a/src/pybind/mgr/rgw/module.py b/src/pybind/mgr/rgw/module.py index 20bd759cd22..15525f6d32a 100644 --- a/src/pybind/mgr/rgw/module.py +++ b/src/pybind/mgr/rgw/module.py @@ -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'))) diff --git a/src/pybind/mgr/rgw/rgwam.py b/src/pybind/mgr/rgw/rgwam.py index 521b86fe342..2b763483448 100644 --- a/src/pybind/mgr/rgw/rgwam.py +++ b/src/pybind/mgr/rgw/rgwam.py @@ -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() diff --git a/src/pybind/mgr/rgw/types.py b/src/pybind/mgr/rgw/types.py index 8ef0feaf764..7f781c2fb00 100644 --- a/src/pybind/mgr/rgw/types.py +++ b/src/pybind/mgr/rgw/types.py @@ -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):