from .module import Module
except ImportError:
pass
-
-import logging
-
-log = logging.getLogger(__name__)
+++ /dev/null
-#!@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()
-
+++ /dev/null
-class ZoneEPs:
- def __init__(self):
- self.endpoints = set()
-
- def add(self, ep):
- if not ep:
- return
-
- self.endpoints.add(ep)
-
- def diff(self, zep):
- return list(self.endpoints.difference(zep.endpoints))
-
- def get_all(self):
- for ep in self.endpoints:
- yield ep
-
-
-
-class RealmEPs:
- def __init__(self):
- self.zones = {}
-
- def add(self, zone, ep = None):
- if not zone:
- return
-
- z = self.zones.get(zone)
- if not z:
- z = ZoneEPs()
- self.zones[zone] = z
-
- z.add(ep)
-
- def diff(self, rep):
- result = {}
- for z, zep in rep.zones.items():
- myzep = self.zones.get(z)
- if not myzep:
- continue
-
-
- d = myzep.diff(zep)
- if len(d) > 0:
- result[z] = myzep.diff(zep)
-
- return result
-
- def get_all(self):
- for z, zep in self.zones.items():
- eps = []
- for ep in zep.get_all():
- eps.append(ep)
- yield z, eps
-
-
-
-class RealmsEPs:
- def __init__(self):
- self.realms = {}
-
- def add(self, realm, zone = None, ep = None):
- if not realm:
- return
-
- r = self.realms.get(realm)
- if not r:
- r = RealmEPs()
- self.realms[realm] = r
-
- r.add(zone, ep)
-
- def diff(self, rep):
- result = {}
-
- for r, rep in rep.realms.items():
- myrealm = self.realms.get(r)
- if not myrealm:
- continue
-
- d = myrealm.diff(rep)
- if d:
- result[r] = d
-
- return result
-
- def get_all(self):
- result = {}
- for r, rep in self.realms.items():
- zs = {}
- for z, eps in rep.get_all():
- zs[z] = eps
-
- result[r] = zs
-
- return result
-
-
from typing import cast, Any, Optional, Sequence
from . import *
-from .types import RGWAMException, RGWAMEnvMgr
-from .rgwam import EnvArgs, RGWAM
+from ceph.rgw.types import RGWAMException, RGWAMEnvMgr
+from ceph.rgw.rgwam_core import EnvArgs, RGWAM
class RGWAMOrchMgr(RGWAMEnvMgr):
+++ /dev/null
-#!@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
-import errno
-
-from urllib.parse import urlparse
-
-from .types import RGWAMException, RGWAMCmdRunException, RGWPeriod, RGWUser, RealmToken
-from .diff import RealmsEPs
-
-
-DEFAULT_PORT = 8000
-
-log = logging.getLogger(__name__)
-
-
-def bool_str(x):
- return 'true' if x else 'false'
-
-def rand_alphanum_lower(l):
- return ''.join(random.choices(string.ascii_lowercase + string.digits, k=l))
-
-def gen_name(prefix, suffix_len):
- return prefix + rand_alphanum_lower(suffix_len)
-
-def set_or_gen(val, gen, prefix):
- if val:
- return val
- if gen:
- return gen_name(prefix, 8)
-
- return None
-
-def get_endpoints(endpoints, period = None):
- if endpoints:
- return endpoints
-
- hostname = socket.getfqdn()
-
- port = DEFAULT_PORT
-
- while True:
- ep = 'http://%s:%d' % (hostname, port)
- if not period or not period.endpoint_exists(ep):
- return ep
- port += 1
-
-
-class EnvArgs:
- def __init__(self, mgr, ceph_conf, ceph_name, ceph_keyring):
- self.mgr = mgr
- self.ceph_conf = ceph_conf
- self.ceph_name = ceph_name
- self.ceph_keyring = ceph_keyring
-
-class EntityKey:
- def __init__(self, name = None, id = None):
- self.name = name
- self.id = id
-
- def safe_vals(ek):
- if not ek:
- return None, None
- return ek.name, ek.id
-
-class EntityName(EntityKey):
- def __init__(self, name = None):
- super().__init__(name = name)
-
-class EntityID(EntityKey):
- def __init__(self, id = None):
- super().__init__(id = id)
-
-class ZoneEnv:
- def __init__(self, env : EnvArgs, realm : EntityKey = None, zg : EntityKey = None, zone : EntityKey = None):
- self.env = env
- self.realm = realm
- self.zg = zg
- self.zone = zone
-
- def set(self, env : EnvArgs = None, realm : EntityKey = None, zg : EntityKey = None, zone : EntityKey = None):
- if env:
- self.env = env
- if realm:
- self.realm = realm
- if zg:
- self.zg = zg
- if zone:
- self.zone = zone
-
- return self
-
- def _init_entity(self, ek : EntityKey, gen, prefix):
- name, id = EntityKey.safe_vals(ek)
- name = set_or_gen(name, gen, prefix)
-
- return EntityKey(name, id)
-
- def init_realm(self, realm : EntityKey = None, gen = False):
- self.realm = self._init_entity(realm, gen, 'realm-')
- return self
-
- def init_zg(self, zg : EntityKey = None, gen = False):
- self.zg = self._init_entity(zg, gen, 'zg-')
- return self
-
- def init_zone(self, zone : EntityKey = None, gen = False):
- self.zone = self._init_entity(zone, gen, 'zone-')
- return self
-
-def opt_arg(params, cmd, arg):
- if arg:
- params += [ cmd, arg ]
-
-def opt_arg_bool(params, flag, arg):
- if arg:
- params += [ flag ]
-
-class RGWCmdBase:
- def __init__(self, prog, zone_env : ZoneEnv):
- env = zone_env.env
- self.cmd_prefix = [ prog ]
- self.cmd_suffix = [ ]
- opt_arg(self.cmd_prefix, '-c', env.ceph_conf )
- opt_arg(self.cmd_prefix, '-n', env.ceph_name )
- opt_arg(self.cmd_prefix, '-k', env.ceph_keyring )
- if zone_env.realm:
- opt_arg(self.cmd_suffix, '--rgw-realm', zone_env.realm.name )
- opt_arg(self.cmd_suffix, '--realm-id', zone_env.realm.id )
- if zone_env.zg:
- opt_arg(self.cmd_suffix, '--rgw-zonegroup', zone_env.zg.name )
- opt_arg(self.cmd_suffix, '--zonegroup-id', zone_env.zg.id )
- if zone_env.zone:
- opt_arg(self.cmd_suffix, '--rgw-zone', zone_env.zone.name )
- opt_arg(self.cmd_suffix, '--zone-id', zone_env.zone.id )
-
- def run(self, cmd):
- run_cmd = self.cmd_prefix + cmd + self.cmd_suffix
- result = subprocess.run(run_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-
- stdout = result.stdout.decode('utf-8')
- stderr = result.stderr.decode('utf-8')
-
- log.debug('cmd=%s' % str(cmd))
-
- log.debug('stdout=%s' % stdout)
-
- if result.returncode != 0:
- cmd_str = ' '.join(run_cmd)
- log.error('ERROR: command exited with error status (%d): %s\nstdout=%s\nstderr=%s' % (result.returncode, cmd_str, stdout, stderr))
- raise RGWAMCmdRunException(cmd_str, -result.returncode, stdout, stderr)
-
- return (stdout, stderr)
-
-class RGWAdminCmd(RGWCmdBase):
- def __init__(self, zone_env : ZoneEnv):
- super().__init__('radosgw-admin', zone_env)
-
-class RGWAdminJSONCmd(RGWAdminCmd):
- def __init__(self, zone_env : ZoneEnv):
- super().__init__(zone_env)
-
- def run(self, cmd):
- stdout, _ = RGWAdminCmd.run(self, cmd)
-
- return json.loads(stdout)
-
-
-class RGWCmd(RGWCmdBase):
- def __init__(self, zone_env : ZoneEnv):
- super().__init__('radosgw', env)
-
-class RealmOp:
- def __init__(self, env : EnvArgs):
- self.env = env
-
- def list(self):
- ze = ZoneEnv(self.env)
-
- params = [ 'realm',
- 'list' ]
-
- return RGWAdminJSONCmd(ze).run(params)
-
-
- def get(self, realm : EntityKey = None):
-
- ze = ZoneEnv(self.env, realm = realm)
-
- params = [ 'realm',
- 'get' ]
-
- return RGWAdminJSONCmd(ze).run(params)
-
- def create(self, realm : EntityKey = None):
- ze = ZoneEnv(self.env).init_realm(realm = realm, gen = True)
-
- params = [ 'realm',
- 'create' ]
-
- return RGWAdminJSONCmd(ze).run(params)
-
- def pull(self, url, access_key, secret, set_default = False):
- params = [ 'realm',
- 'pull',
- '--url', url,
- '--access-key', access_key,
- '--secret', secret ]
-
- ze = ZoneEnv(self.env)
-
- return RGWAdminJSONCmd(ze).run(params)
-
-
-class ZonegroupOp:
- def __init__(self, env : EnvArgs):
- self.env = env
-
- def create(self, realm : EntityKey, zg : EntityKey = None, endpoints = None, is_master = True):
- ze = ZoneEnv(self.env, realm = realm).init_zg(zg, gen = True)
-
- params = [ 'zonegroup',
- 'create' ]
-
- opt_arg_bool(params, '--master', is_master)
- opt_arg(params, '--endpoints', endpoints)
-
- stdout, _ = RGWAdminCmd(ze).run( params)
-
- return json.loads(stdout)
-
-
-class ZoneOp:
- def __init__(self, env : EnvArgs):
- self.env = env
-
- def get(self, zone : EntityKey):
- ze = ZoneEnv(self.env, zone = zone)
-
- params = [ 'zone',
- 'get' ]
-
- return RGWAdminJSONCmd(ze).run(params)
-
- def create(self, realm : EntityKey, zonegroup : EntityKey, zone : EntityKey = None,
- endpoints = None, is_master = True,
- access_key = None, secret = None):
-
- ze = ZoneEnv(self.env, realm = realm, zg = zonegroup).init_zone(zone, gen = True)
-
- params = [ 'zone',
- 'create' ]
-
- opt_arg_bool(params, '--master', is_master)
- opt_arg(params, '--access-key', access_key)
- opt_arg(params, '--secret', secret)
- opt_arg(params, '--endpoints', endpoints)
-
- return RGWAdminJSONCmd(ze).run(params)
-
- def modify(self, zone : EntityKey, zg : EntityKey, endpoints = None, is_master = None, access_key = None, secret = None):
- ze = ZoneEnv(self.env, zone = zone, zg = zg)
-
- params = [ 'zone',
- 'modify' ]
-
- opt_arg_bool(params, '--master', is_master)
- opt_arg(params, '--access-key', access_key)
- opt_arg(params, '--secret', secret)
- opt_arg(params, '--endpoints', endpoints)
-
- return RGWAdminJSONCmd(ze).run(params)
-
-class PeriodOp:
- def __init__(self, env):
- self.env = env
-
- def update(self, realm : EntityKey, zonegroup : EntityKey, zone : EntityKey, commit = True):
- ze = ZoneEnv(self.env, realm = realm, zg = zonegroup, zone = zone)
-
- params = [ 'period',
- 'update' ]
-
- opt_arg_bool(params, '--commit', commit)
-
- return RGWAdminJSONCmd(ze).run(params)
-
- def get(self, realm = None):
- ze = ZoneEnv(self.env, realm = realm)
- params = [ 'period',
- 'get' ]
-
- return RGWAdminJSONCmd(ze).run(params)
-
-class UserOp:
- def __init__(self, env):
- self.env = env
-
- def create(self, zone : EntityKey, zg : EntityKey, uid = None, uid_prefix = None, display_name = None, email = None, is_system = False):
- ze = ZoneEnv(self.env, zone = zone, zg = zg)
-
- u = uid or gen_name(uid_prefix or 'user-', 6)
-
- dn = display_name or u
-
- params = [ 'user',
- 'create',
- '--uid', u,
- '--display-name', dn ]
-
- opt_arg(params, '--email', email )
- opt_arg_bool(params, '--system', is_system)
-
- return RGWAdminJSONCmd(ze).run(params)
-
- def info(self, zone : EntityKey, zg : EntityKey, uid = None, access_key = None):
- ze = ZoneEnv(self.env, zone = zone, zg = zg)
-
- params = [ 'user',
- 'info' ]
-
- opt_arg(params, '--uid', uid )
- opt_arg(params, '--access-key', access_key)
-
- return RGWAdminJSONCmd(ze).run(params)
-
- def rm(self, zone : EntityKey, zg : EntityKey, uid = None, access_key = None):
- ze = ZoneEnv(self.env, zone = zone, zg = zg)
-
- params = [ 'user',
- 'rm' ]
-
- opt_arg(params, '--uid', uid )
- opt_arg(params, '--access-key', access_key)
-
- return RGWAdminCmd(ze).run(params)
-
- def rm_key(self, zone : EntityKey, zg : EntityKey, access_key = None):
- ze = ZoneEnv(self.env, zone = zone, zg = zg)
-
- params = [ 'key',
- 'remove' ]
-
- opt_arg(params, '--access-key', access_key)
-
- return RGWAdminCmd(ze).run(params)
-
-class RGWAM:
- def __init__(self, env):
- self.env = env
-
- def realm_op(self):
- return RealmOp(self.env)
-
- def period_op(self):
- return PeriodOp(self.env)
-
- def zonegroup_op(self):
- return ZonegroupOp(self.env)
-
- def zone_op(self):
- return ZoneOp(self.env)
-
- def user_op(self):
- return UserOp(self.env)
-
- def realm_bootstrap(self, realm_name, zonegroup_name, zone_name, endpoints, sys_uid, uid, start_radosgw):
- endpoints = get_endpoints(endpoints)
-
- try:
- realm_info = self.realm_op().create(EntityName(realm_name))
- except RGWAMException as e:
- raise RGWAMException('failed to create realm', e)
-
- realm_name = realm_info['name']
- realm_id = realm_info['id']
-
- realm = EntityID(realm_id)
-
- logging.info('Created realm %s (%s)' % (realm_name, realm_id))
-
- try:
- zg_info = self.zonegroup_op().create(realm, EntityName(zonegroup_name), endpoints, is_master = True)
- except RGWAMException as e:
- raise RGWAMException('failed to create zonegroup', e)
-
- zg_name = zg_info['name']
- zg_id = zg_info['id']
- logging.info('Created zonegroup %s (%s)' % (zg_name, zg_id))
-
- zg = EntityName(zg_name)
-
- try:
- zone_info = self.zone_op().create(realm, zg, EntityName(zone_name), endpoints, is_master = True)
- except RGWAMException as e:
- raise RGWAMException('failed to create zone', e)
-
- zone_name = zone_info['name']
- zone_id = zone_info['id']
- logging.info('Created zone %s (%s)' % (zone_name, zone_id))
-
- zone = EntityName(zone_name)
-
- try:
- period_info = self.period_op().update(realm, EntityName(zg_name), zone, commit = True)
- except RGWAMCmdRunException as e:
- raise RGWAMException('failed to update period', e)
-
- period = RGWPeriod(period_info)
-
- logging.info('Period: ' + period.id)
-
- try:
- sys_user_info = self.user_op().create(zone, zg, uid = sys_uid, uid_prefix = 'user-sys', is_system = True)
- except RGWAMException as e:
- raise RGWAMException('failed to create system user', e)
-
- sys_user = RGWUser(sys_user_info)
-
- logging.info('Created system user: %s' % sys_user.uid)
-
- sys_access_key = ''
- sys_secret = ''
-
- if len(sys_user.keys) > 0:
- sys_access_key = sys_user.keys[0].access_key
- sys_secret = sys_user.keys[0].secret_key
-
- try:
- zone_info = self.zone_op().modify(zone, zg, endpoints, None, sys_access_key, sys_secret)
- except RGWAMException as e:
- raise RGWAMException('failed to modify zone info', e)
-
- try:
- user_info = self.user_op().create(zone, zg, uid = uid, is_system = False)
- except RGWAMException as e:
- raise RGWAMException('failed to create user', e)
-
- user = RGWUser(user_info)
-
- logging.info('Created regular user: %s' % user.uid)
-
- eps = endpoints.split(',')
- ep = ''
- if len(eps) > 0:
- ep = eps[0]
- if start_radosgw:
- o = urlparse(ep)
- svc_id = realm_name + '.' + zone_name
- self.env.mgr.apply_rgw(svc_id, realm_name, zone_name, o.port)
-
- realm_token = RealmToken(realm_id, ep, sys_user.uid, sys_access_key, sys_secret)
-
- logging.info(realm_token.to_json())
-
- realm_token_b = realm_token.to_json().encode('utf-8')
- return (0, 'Realm Token: %s' % base64.b64encode(realm_token_b).decode('utf-8'), '')
-
- def realm_new_zone_creds(self, realm_name, endpoints, sys_uid):
- try:
- period_info = self.period_op().get(EntityName(realm_name))
- except RGWAMException as e:
- raise RGWAMException('failed to fetch period info', e)
-
- period = RGWPeriod(period_info)
-
- master_zg = EntityID(period.master_zonegroup)
- master_zone = EntityID(period.master_zone)
-
- try:
- zone_info = self.zone_op().get(zone = master_zone)
- except RGWAMException as e:
- raise RGWAMException('failed to access master zone', e)
-
- zone_name = zone_info['name']
- zone_id = zone_info['id']
-
- logging.info('Period: ' + period.id)
- logging.info('Master zone: ' + period.master_zone)
-
- if period.master_zone != zone_id:
- return (-errno.EINVAL, '', 'Command needs to run on master zone')
-
- ep = ''
- if not endpoints:
- eps = period.get_zone_endpoints(period.master_zonegroup, period.master_zone)
- else:
- eps = endpoints.split(',')
-
- if len(eps) > 0:
- ep = eps[0]
-
- try:
- sys_user_info = self.user_op().create(master_zone, master_zg, uid = sys_uid, uid_prefix = 'user-sys', is_system = True)
- except RGWAMException as e:
- raise RGWAMException('failed to create system user', e)
-
- sys_user = RGWUser(sys_user_info)
-
- logging.info('Created system user: %s' % sys_user.uid)
-
- sys_access_key = ''
- sys_secret = ''
-
- if len(sys_user.keys) > 0:
- sys_access_key = sys_user.keys[0].access_key
- sys_secret = sys_user.keys[0].secret_key
-
- realm_token = RealmToken(period.realm_id, ep, sys_user.uid, sys_access_key, sys_secret)
-
- logging.info(realm_token.to_json())
-
- realm_token_b = realm_token.to_json().encode('utf-8')
- return (0, 'Realm Token: %s' % base64.b64encode(realm_token_b).decode('utf-8'), '')
-
- def realm_rm_zone_creds(self, realm_token_b64):
- if not realm_token_b64:
- print('missing realm token')
- return False
-
- realm_token_b = base64.b64decode(realm_token_b64)
- realm_token_s = realm_token_b.decode('utf-8')
-
- realm_token = json.loads(realm_token_s)
-
- access_key = realm_token['access_key']
- realm_id = realm_token['realm_id']
-
- try:
- period_info = self.period_op().get(EntityID(realm_id))
- except RGWAMException as e:
- raise RGWAMException('failed to fetch period info', e)
-
- period = RGWPeriod(period_info)
-
- master_zg = EntityID(period.master_zonegroup)
- master_zone = EntityID(period.master_zone)
-
- logging.info('Period: ' + period.id)
- logging.info('Master zone: ' + period.master_zone)
-
- try:
- zone_info = self.zone_op().get(zone = master_zone)
- except RGWAMException as e:
- raise RGWAMException('failed to access master zone', e)
-
- zone_name = zone_info['name']
- zone_id = zone_info['id']
-
- if period.master_zone != zone_id:
- return (-errno.EINVAL, '', 'Command needs to run on master zone')
-
- try:
- user_info = self.user_op().info(master_zone, master_zg, access_key = access_key)
- except RGWAMException as e:
- raise RGWAMException('failed to create system user', e)
-
- user = RGWUser(user_info)
-
- only_key = True
-
- for k in user.keys:
- if k.access_key != access_key:
- only_key = False
- break
-
- success_message = ''
-
- if only_key:
- # the only key this user has is the one defined in the token
- # can remove the user completely
-
- try:
- self.user_op().rm(master_zone, master_zg, uid = user.uid)
- except RGWAMException as e:
- raise RGWAMException('failed removing user ' + user,uid, e)
-
- success_message = 'Removed uid ' + user.uid
- else:
- try:
- self.user_op().rm_key(master_zone, master_zg, access_key = access_key)
- except RGWAMException as e:
- raise RGWAMException('failed removing access key ' + access_key + '(uid = ' + user.uid + ')', e)
-
- success_message = 'Removed access key ' + access_key + '(uid = ' + user.uid + ')'
-
- return (0, success_message, '')
-
- def zone_create(self, realm_token_b64, zonegroup_name = None, zone_name = None, endpoints = None, start_radosgw = True):
- if not realm_token_b64:
- print('missing realm access config')
- return False
-
- realm_token_b = base64.b64decode(realm_token_b64)
- realm_token_s = realm_token_b.decode('utf-8')
-
- realm_token = json.loads(realm_token_s)
-
- access_key = realm_token['access_key']
- secret = realm_token['secret']
-
- try:
- realm_info = self.realm_op().pull(realm_token['endpoint'], access_key, secret, set_default = True)
- except RGWAMException as e:
- raise RGWAMException('failed to pull realm', e)
-
- realm_name = realm_info['name']
- realm_id = realm_info['id']
- logging.info('Pulled realm %s (%s)' % (realm_name, realm_id))
-
- realm = EntityID(realm_id)
-
- period_info = self.period_op().get(realm)
-
- period = RGWPeriod(period_info)
-
- logging.info('Period: ' + period.id)
-
- zonegroup = period.find_zonegroup_by_name(zonegroup_name)
- if not zonegroup:
- raise RGWAMException('zonegroup %s not found' % (zonegroup or '<none>'))
-
- zg = EntityName(zonegroup.name)
-
- try:
- zone_info = self.zone_op().create(realm, zg, EntityName(zone_name), endpoints, False,
- access_key, secret)
- except RGWAMException as e:
- raise RGWAMException('failed to create zone', e)
-
- zone_name = zone_info['name']
- zone_id = zone_info['id']
-
- zone = EntityName(zone_name)
-
- success_message = 'Created zone %s (%s)' % (zone_name, zone_id)
- logging.info(success_message)
-
- try:
- period_info = self.period_op().update(realm, zg, zone, True)
- except RGWAMException as e:
- raise RGWAMException('failed to update period', e)
-
- period = RGWPeriod(period_info)
-
- logging.debug(period.to_json())
-
- svc_id = realm_name + '.' + zone_name
-
- #if endpoints:
- # eps = endpoints.split(',')
- # ep = ''
- # if len(eps) > 0:
- # ep = eps[0]
- # o = urlparse(ep)
- # port = o.port
- # 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)
-
- daemons = self.env.mgr.list_daemons(svc_id, 'rgw', refresh=True)
-
- ep = []
- for s in daemons:
- for p in s.ports:
- ep.append('http://%s:%d' % (s.hostname, p))
-
- log.error('ERROR: ep=%s' % ','.join(ep))
-
- try:
- zone_info = self.zone_op().modify(zone, zg, endpoints = ','.join(ep))
- except RGWAMException as e:
- raise RGWAMException('failed to modify zone', e)
-
- return (0, success_message, '')
-
-
- def _get_daemon_eps(self, realm_name = None, zonegroup_name = None, zone_name = None):
- # get running daemons info
- service_name = None
- if realm_name and zone_name:
- service_name = 'rgw.%s.%s' % (realm_name, zone_name)
-
- daemon_type = 'rgw'
- daemon_id = None
- hostname = None
- refresh = True
-
- daemons = self.env.mgr.list_daemons(service_name,
- daemon_type,
- daemon_id=daemon_id,
- host=hostname,
- refresh=refresh)
-
- rep = RealmsEPs()
-
- for s in daemons:
- for p in s.ports:
- svc_id = s.service_id()
- l = svc_id.split('.')
- if len(l) < 2:
- log.error('ERROR: service id cannot be parsed: (svc_id=%s)' % svc_id)
- continue
-
- svc_realm = l[0]
- svc_zone = l[1]
-
- if realm_name and svc_realm != realm_name:
- log.debug('skipping realm %s' % svc_realm)
- continue
-
- if zone_name and svc_zone != zone_name:
- log.debug('skipping zone %s' % svc_zone)
- continue
-
- ep = 'http://%s:%d' % (s.hostname, p) # ssl?
-
- rep.add(svc_realm, svc_zone, ep)
-
- return rep
-
-
-
- def _get_rgw_eps(self, realm_name = None, zonegroup_name = None, zone_name = None):
- rep = RealmsEPs()
-
- try:
- realm_list_ret = self.realm_op().list()
- except RGWAMException as e:
- raise RGWAMException('failed to list realms', e)
-
- realms = realm_list_ret.get('realms') or []
-
- zones_map = {}
-
- for realm in realms:
- if realm_name and realm != realm_name:
- log.debug('skipping realm %s' % realm)
- continue
-
- period_info = self.period_op().get(EntityName(realm))
-
- period = RGWPeriod(period_info)
-
- zones_map[realm] = {}
-
- for zg in period.iter_zonegroups():
- if zonegroup_name and zg.name != zonegroup_name:
- log.debug('skipping zonegroup %s' % zg.name)
- continue
-
- for zone in zg.iter_zones():
- if zone_name and zone.name != zone_name:
- log.debug('skipping zone %s' % zone.name)
- continue
-
- zones_map[realm][zone.name] = zg.name
-
- if len(zone.endpoints) == 0:
- rep.add(realm, zone.name, None)
- continue
-
- for ep in zone.endpoints:
- rep.add(realm, zone.name, ep)
-
- return (rep, zones_map)
-
- def realm_reconcile(self, realm_name = None, zonegroup_name = None, zone_name = None, update = False):
-
- daemon_rep = self._get_daemon_eps(realm_name, zonegroup_name, zone_name)
-
- rgw_rep, zones_map = self._get_rgw_eps(realm_name, zonegroup_name, zone_name)
-
- diff = daemon_rep.diff(rgw_rep)
-
- diffj = json.dumps(diff)
-
- if not update:
- return (0, diffj, '')
-
- for realm, realm_diff in diff.items():
- for zone, endpoints in realm_diff.items():
-
- zg = zones_map[realm][zone]
-
- try:
- zone_info = self.zone_op().modify(EntityName(zone), EntityName(zg), endpoints = ','.join(diff[realm][zone]))
- except RGWAMException as e:
- raise RGWAMException('failed to modify zone', e)
-
- try:
- period_info = self.period_op().update(EntityName(realm), EntityName(zg), EntityName(zone), True)
- except RGWAMException as e:
- raise RGWAMException('failed to update period', e)
-
- return (0, 'Updated: ' + diffj, '')
-
-
- def run_radosgw(self, port = None, log_file = None, debug_ms = None, debug_rgw = None):
-
- fe_cfg = 'beast'
- if port:
- fe_cfg += ' port=%s' % port
-
-
- params = [ '--rgw-frontends', fe_cfg ]
-
- if log_file:
- params += [ '--log-file', log_file ]
-
- if debug_ms:
- params += [ '--debug-ms', debug_ms ]
-
- if debug_rgw:
- params += [ '--debug-rgw', debug_rgw ]
-
- (retcode, stdout, stderr) = RGWCmd(self.env).run(params)
-
- return (retcode, stdout, stderr)
-
+++ /dev/null
-import json
-
-from abc import abstractmethod
-
-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 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):
- return json.dumps(self, default=lambda o: o.__dict__, indent=4)
-
-class RealmToken(JSONObj):
- def __init__(self, realm_id, endpoint, uid, access_key, secret):
- self.realm_id = realm_id
- 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
-
- def iter_zones(self):
- for zone in self.zones_by_id.values():
- yield zone
-
-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']
- self.realm_name = period_dict['realm_name']
- self.realm_id = period_dict['realm_id']
- 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)
-
- def iter_zonegroups(self):
- for zg in self.zonegroups_by_id.values():
- yield zg
-
-
-
-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')
-
-
--- /dev/null
+import logging
+
+log = logging.getLogger(__name__)
--- /dev/null
+class ZoneEPs:
+ def __init__(self):
+ self.endpoints = set()
+
+ def add(self, ep):
+ if not ep:
+ return
+
+ self.endpoints.add(ep)
+
+ def diff(self, zep):
+ return list(self.endpoints.difference(zep.endpoints))
+
+ def get_all(self):
+ for ep in self.endpoints:
+ yield ep
+
+
+
+class RealmEPs:
+ def __init__(self):
+ self.zones = {}
+
+ def add(self, zone, ep = None):
+ if not zone:
+ return
+
+ z = self.zones.get(zone)
+ if not z:
+ z = ZoneEPs()
+ self.zones[zone] = z
+
+ z.add(ep)
+
+ def diff(self, rep):
+ result = {}
+ for z, zep in rep.zones.items():
+ myzep = self.zones.get(z)
+ if not myzep:
+ continue
+
+
+ d = myzep.diff(zep)
+ if len(d) > 0:
+ result[z] = myzep.diff(zep)
+
+ return result
+
+ def get_all(self):
+ for z, zep in self.zones.items():
+ eps = []
+ for ep in zep.get_all():
+ eps.append(ep)
+ yield z, eps
+
+
+
+class RealmsEPs:
+ def __init__(self):
+ self.realms = {}
+
+ def add(self, realm, zone = None, ep = None):
+ if not realm:
+ return
+
+ r = self.realms.get(realm)
+ if not r:
+ r = RealmEPs()
+ self.realms[realm] = r
+
+ r.add(zone, ep)
+
+ def diff(self, rep):
+ result = {}
+
+ for r, rep in rep.realms.items():
+ myrealm = self.realms.get(r)
+ if not myrealm:
+ continue
+
+ d = myrealm.diff(rep)
+ if d:
+ result[r] = d
+
+ return result
+
+ def get_all(self):
+ result = {}
+ for r, rep in self.realms.items():
+ zs = {}
+ for z, eps in rep.get_all():
+ zs[z] = eps
+
+ result[r] = zs
+
+ return result
+
+
--- /dev/null
+# -*- 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
+import errno
+
+from urllib.parse import urlparse
+
+from .types import RGWAMException, RGWAMCmdRunException, RGWPeriod, RGWUser, RealmToken
+from .diff import RealmsEPs
+
+
+DEFAULT_PORT = 8000
+
+log = logging.getLogger(__name__)
+
+
+def bool_str(x):
+ return 'true' if x else 'false'
+
+def rand_alphanum_lower(l):
+ return ''.join(random.choices(string.ascii_lowercase + string.digits, k=l))
+
+def gen_name(prefix, suffix_len):
+ return prefix + rand_alphanum_lower(suffix_len)
+
+def set_or_gen(val, gen, prefix):
+ if val:
+ return val
+ if gen:
+ return gen_name(prefix, 8)
+
+ return None
+
+def get_endpoints(endpoints, period = None):
+ if endpoints:
+ return endpoints
+
+ hostname = socket.getfqdn()
+
+ port = DEFAULT_PORT
+
+ while True:
+ ep = 'http://%s:%d' % (hostname, port)
+ if not period or not period.endpoint_exists(ep):
+ return ep
+ port += 1
+
+
+class EnvArgs:
+ def __init__(self, mgr, ceph_conf, ceph_name, ceph_keyring):
+ self.mgr = mgr
+ self.ceph_conf = ceph_conf
+ self.ceph_name = ceph_name
+ self.ceph_keyring = ceph_keyring
+
+class EntityKey:
+ def __init__(self, name = None, id = None):
+ self.name = name
+ self.id = id
+
+ def safe_vals(ek):
+ if not ek:
+ return None, None
+ return ek.name, ek.id
+
+class EntityName(EntityKey):
+ def __init__(self, name = None):
+ super().__init__(name = name)
+
+class EntityID(EntityKey):
+ def __init__(self, id = None):
+ super().__init__(id = id)
+
+class ZoneEnv:
+ def __init__(self, env : EnvArgs, realm : EntityKey = None, zg : EntityKey = None, zone : EntityKey = None):
+ self.env = env
+ self.realm = realm
+ self.zg = zg
+ self.zone = zone
+
+ def set(self, env : EnvArgs = None, realm : EntityKey = None, zg : EntityKey = None, zone : EntityKey = None):
+ if env:
+ self.env = env
+ if realm:
+ self.realm = realm
+ if zg:
+ self.zg = zg
+ if zone:
+ self.zone = zone
+
+ return self
+
+ def _init_entity(self, ek : EntityKey, gen, prefix):
+ name, id = EntityKey.safe_vals(ek)
+ name = set_or_gen(name, gen, prefix)
+
+ return EntityKey(name, id)
+
+ def init_realm(self, realm : EntityKey = None, gen = False):
+ self.realm = self._init_entity(realm, gen, 'realm-')
+ return self
+
+ def init_zg(self, zg : EntityKey = None, gen = False):
+ self.zg = self._init_entity(zg, gen, 'zg-')
+ return self
+
+ def init_zone(self, zone : EntityKey = None, gen = False):
+ self.zone = self._init_entity(zone, gen, 'zone-')
+ return self
+
+def opt_arg(params, cmd, arg):
+ if arg:
+ params += [ cmd, arg ]
+
+def opt_arg_bool(params, flag, arg):
+ if arg:
+ params += [ flag ]
+
+class RGWCmdBase:
+ def __init__(self, prog, zone_env : ZoneEnv):
+ env = zone_env.env
+ self.cmd_prefix = [ prog ]
+ self.cmd_suffix = [ ]
+ opt_arg(self.cmd_prefix, '-c', env.ceph_conf )
+ opt_arg(self.cmd_prefix, '-n', env.ceph_name )
+ opt_arg(self.cmd_prefix, '-k', env.ceph_keyring )
+ if zone_env.realm:
+ opt_arg(self.cmd_suffix, '--rgw-realm', zone_env.realm.name )
+ opt_arg(self.cmd_suffix, '--realm-id', zone_env.realm.id )
+ if zone_env.zg:
+ opt_arg(self.cmd_suffix, '--rgw-zonegroup', zone_env.zg.name )
+ opt_arg(self.cmd_suffix, '--zonegroup-id', zone_env.zg.id )
+ if zone_env.zone:
+ opt_arg(self.cmd_suffix, '--rgw-zone', zone_env.zone.name )
+ opt_arg(self.cmd_suffix, '--zone-id', zone_env.zone.id )
+
+ def run(self, cmd):
+ run_cmd = self.cmd_prefix + cmd + self.cmd_suffix
+ result = subprocess.run(run_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
+ stdout = result.stdout.decode('utf-8')
+ stderr = result.stderr.decode('utf-8')
+
+ log.debug('cmd=%s' % str(cmd))
+
+ log.debug('stdout=%s' % stdout)
+
+ if result.returncode != 0:
+ cmd_str = ' '.join(run_cmd)
+ log.error('ERROR: command exited with error status (%d): %s\nstdout=%s\nstderr=%s' % (result.returncode, cmd_str, stdout, stderr))
+ raise RGWAMCmdRunException(cmd_str, -result.returncode, stdout, stderr)
+
+ return (stdout, stderr)
+
+class RGWAdminCmd(RGWCmdBase):
+ def __init__(self, zone_env : ZoneEnv):
+ super().__init__('radosgw-admin', zone_env)
+
+class RGWAdminJSONCmd(RGWAdminCmd):
+ def __init__(self, zone_env : ZoneEnv):
+ super().__init__(zone_env)
+
+ def run(self, cmd):
+ stdout, _ = RGWAdminCmd.run(self, cmd)
+
+ return json.loads(stdout)
+
+
+class RGWCmd(RGWCmdBase):
+ def __init__(self, zone_env : ZoneEnv):
+ super().__init__('radosgw', env)
+
+class RealmOp:
+ def __init__(self, env : EnvArgs):
+ self.env = env
+
+ def list(self):
+ ze = ZoneEnv(self.env)
+
+ params = [ 'realm',
+ 'list' ]
+
+ return RGWAdminJSONCmd(ze).run(params)
+
+
+ def get(self, realm : EntityKey = None):
+
+ ze = ZoneEnv(self.env, realm = realm)
+
+ params = [ 'realm',
+ 'get' ]
+
+ return RGWAdminJSONCmd(ze).run(params)
+
+ def create(self, realm : EntityKey = None):
+ ze = ZoneEnv(self.env).init_realm(realm = realm, gen = True)
+
+ params = [ 'realm',
+ 'create' ]
+
+ return RGWAdminJSONCmd(ze).run(params)
+
+ def pull(self, url, access_key, secret, set_default = False):
+ params = [ 'realm',
+ 'pull',
+ '--url', url,
+ '--access-key', access_key,
+ '--secret', secret ]
+
+ ze = ZoneEnv(self.env)
+
+ return RGWAdminJSONCmd(ze).run(params)
+
+
+class ZonegroupOp:
+ def __init__(self, env : EnvArgs):
+ self.env = env
+
+ def create(self, realm : EntityKey, zg : EntityKey = None, endpoints = None, is_master = True):
+ ze = ZoneEnv(self.env, realm = realm).init_zg(zg, gen = True)
+
+ params = [ 'zonegroup',
+ 'create' ]
+
+ opt_arg_bool(params, '--master', is_master)
+ opt_arg(params, '--endpoints', endpoints)
+
+ stdout, _ = RGWAdminCmd(ze).run( params)
+
+ return json.loads(stdout)
+
+
+class ZoneOp:
+ def __init__(self, env : EnvArgs):
+ self.env = env
+
+ def get(self, zone : EntityKey):
+ ze = ZoneEnv(self.env, zone = zone)
+
+ params = [ 'zone',
+ 'get' ]
+
+ return RGWAdminJSONCmd(ze).run(params)
+
+ def create(self, realm : EntityKey, zonegroup : EntityKey, zone : EntityKey = None,
+ endpoints = None, is_master = True,
+ access_key = None, secret = None):
+
+ ze = ZoneEnv(self.env, realm = realm, zg = zonegroup).init_zone(zone, gen = True)
+
+ params = [ 'zone',
+ 'create' ]
+
+ opt_arg_bool(params, '--master', is_master)
+ opt_arg(params, '--access-key', access_key)
+ opt_arg(params, '--secret', secret)
+ opt_arg(params, '--endpoints', endpoints)
+
+ return RGWAdminJSONCmd(ze).run(params)
+
+ def modify(self, zone : EntityKey, zg : EntityKey, endpoints = None, is_master = None, access_key = None, secret = None):
+ ze = ZoneEnv(self.env, zone = zone, zg = zg)
+
+ params = [ 'zone',
+ 'modify' ]
+
+ opt_arg_bool(params, '--master', is_master)
+ opt_arg(params, '--access-key', access_key)
+ opt_arg(params, '--secret', secret)
+ opt_arg(params, '--endpoints', endpoints)
+
+ return RGWAdminJSONCmd(ze).run(params)
+
+class PeriodOp:
+ def __init__(self, env):
+ self.env = env
+
+ def update(self, realm : EntityKey, zonegroup : EntityKey, zone : EntityKey, commit = True):
+ ze = ZoneEnv(self.env, realm = realm, zg = zonegroup, zone = zone)
+
+ params = [ 'period',
+ 'update' ]
+
+ opt_arg_bool(params, '--commit', commit)
+
+ return RGWAdminJSONCmd(ze).run(params)
+
+ def get(self, realm = None):
+ ze = ZoneEnv(self.env, realm = realm)
+ params = [ 'period',
+ 'get' ]
+
+ return RGWAdminJSONCmd(ze).run(params)
+
+class UserOp:
+ def __init__(self, env):
+ self.env = env
+
+ def create(self, zone : EntityKey, zg : EntityKey, uid = None, uid_prefix = None, display_name = None, email = None, is_system = False):
+ ze = ZoneEnv(self.env, zone = zone, zg = zg)
+
+ u = uid or gen_name(uid_prefix or 'user-', 6)
+
+ dn = display_name or u
+
+ params = [ 'user',
+ 'create',
+ '--uid', u,
+ '--display-name', dn ]
+
+ opt_arg(params, '--email', email )
+ opt_arg_bool(params, '--system', is_system)
+
+ return RGWAdminJSONCmd(ze).run(params)
+
+ def info(self, zone : EntityKey, zg : EntityKey, uid = None, access_key = None):
+ ze = ZoneEnv(self.env, zone = zone, zg = zg)
+
+ params = [ 'user',
+ 'info' ]
+
+ opt_arg(params, '--uid', uid )
+ opt_arg(params, '--access-key', access_key)
+
+ return RGWAdminJSONCmd(ze).run(params)
+
+ def rm(self, zone : EntityKey, zg : EntityKey, uid = None, access_key = None):
+ ze = ZoneEnv(self.env, zone = zone, zg = zg)
+
+ params = [ 'user',
+ 'rm' ]
+
+ opt_arg(params, '--uid', uid )
+ opt_arg(params, '--access-key', access_key)
+
+ return RGWAdminCmd(ze).run(params)
+
+ def rm_key(self, zone : EntityKey, zg : EntityKey, access_key = None):
+ ze = ZoneEnv(self.env, zone = zone, zg = zg)
+
+ params = [ 'key',
+ 'remove' ]
+
+ opt_arg(params, '--access-key', access_key)
+
+ return RGWAdminCmd(ze).run(params)
+
+class RGWAM:
+ def __init__(self, env):
+ self.env = env
+
+ def realm_op(self):
+ return RealmOp(self.env)
+
+ def period_op(self):
+ return PeriodOp(self.env)
+
+ def zonegroup_op(self):
+ return ZonegroupOp(self.env)
+
+ def zone_op(self):
+ return ZoneOp(self.env)
+
+ def user_op(self):
+ return UserOp(self.env)
+
+ def realm_bootstrap(self, realm_name, zonegroup_name, zone_name, endpoints, sys_uid, uid, start_radosgw):
+ endpoints = get_endpoints(endpoints)
+
+ try:
+ realm_info = self.realm_op().create(EntityName(realm_name))
+ except RGWAMException as e:
+ raise RGWAMException('failed to create realm', e)
+
+ realm_name = realm_info['name']
+ realm_id = realm_info['id']
+
+ realm = EntityID(realm_id)
+
+ logging.info('Created realm %s (%s)' % (realm_name, realm_id))
+
+ try:
+ zg_info = self.zonegroup_op().create(realm, EntityName(zonegroup_name), endpoints, is_master = True)
+ except RGWAMException as e:
+ raise RGWAMException('failed to create zonegroup', e)
+
+ zg_name = zg_info['name']
+ zg_id = zg_info['id']
+ logging.info('Created zonegroup %s (%s)' % (zg_name, zg_id))
+
+ zg = EntityName(zg_name)
+
+ try:
+ zone_info = self.zone_op().create(realm, zg, EntityName(zone_name), endpoints, is_master = True)
+ except RGWAMException as e:
+ raise RGWAMException('failed to create zone', e)
+
+ zone_name = zone_info['name']
+ zone_id = zone_info['id']
+ logging.info('Created zone %s (%s)' % (zone_name, zone_id))
+
+ zone = EntityName(zone_name)
+
+ try:
+ period_info = self.period_op().update(realm, EntityName(zg_name), zone, commit = True)
+ except RGWAMCmdRunException as e:
+ raise RGWAMException('failed to update period', e)
+
+ period = RGWPeriod(period_info)
+
+ logging.info('Period: ' + period.id)
+
+ try:
+ sys_user_info = self.user_op().create(zone, zg, uid = sys_uid, uid_prefix = 'user-sys', is_system = True)
+ except RGWAMException as e:
+ raise RGWAMException('failed to create system user', e)
+
+ sys_user = RGWUser(sys_user_info)
+
+ logging.info('Created system user: %s' % sys_user.uid)
+
+ sys_access_key = ''
+ sys_secret = ''
+
+ if len(sys_user.keys) > 0:
+ sys_access_key = sys_user.keys[0].access_key
+ sys_secret = sys_user.keys[0].secret_key
+
+ try:
+ zone_info = self.zone_op().modify(zone, zg, endpoints, None, sys_access_key, sys_secret)
+ except RGWAMException as e:
+ raise RGWAMException('failed to modify zone info', e)
+
+ try:
+ user_info = self.user_op().create(zone, zg, uid = uid, is_system = False)
+ except RGWAMException as e:
+ raise RGWAMException('failed to create user', e)
+
+ user = RGWUser(user_info)
+
+ logging.info('Created regular user: %s' % user.uid)
+
+ eps = endpoints.split(',')
+ ep = ''
+ if len(eps) > 0:
+ ep = eps[0]
+ if start_radosgw:
+ o = urlparse(ep)
+ svc_id = realm_name + '.' + zone_name
+ self.env.mgr.apply_rgw(svc_id, realm_name, zone_name, o.port)
+
+ realm_token = RealmToken(realm_id, ep, sys_user.uid, sys_access_key, sys_secret)
+
+ logging.info(realm_token.to_json())
+
+ realm_token_b = realm_token.to_json().encode('utf-8')
+ return (0, 'Realm Token: %s' % base64.b64encode(realm_token_b).decode('utf-8'), '')
+
+ def realm_new_zone_creds(self, realm_name, endpoints, sys_uid):
+ try:
+ period_info = self.period_op().get(EntityName(realm_name))
+ except RGWAMException as e:
+ raise RGWAMException('failed to fetch period info', e)
+
+ period = RGWPeriod(period_info)
+
+ master_zg = EntityID(period.master_zonegroup)
+ master_zone = EntityID(period.master_zone)
+
+ try:
+ zone_info = self.zone_op().get(zone = master_zone)
+ except RGWAMException as e:
+ raise RGWAMException('failed to access master zone', e)
+
+ zone_name = zone_info['name']
+ zone_id = zone_info['id']
+
+ logging.info('Period: ' + period.id)
+ logging.info('Master zone: ' + period.master_zone)
+
+ if period.master_zone != zone_id:
+ return (-errno.EINVAL, '', 'Command needs to run on master zone')
+
+ ep = ''
+ if not endpoints:
+ eps = period.get_zone_endpoints(period.master_zonegroup, period.master_zone)
+ else:
+ eps = endpoints.split(',')
+
+ if len(eps) > 0:
+ ep = eps[0]
+
+ try:
+ sys_user_info = self.user_op().create(master_zone, master_zg, uid = sys_uid, uid_prefix = 'user-sys', is_system = True)
+ except RGWAMException as e:
+ raise RGWAMException('failed to create system user', e)
+
+ sys_user = RGWUser(sys_user_info)
+
+ logging.info('Created system user: %s' % sys_user.uid)
+
+ sys_access_key = ''
+ sys_secret = ''
+
+ if len(sys_user.keys) > 0:
+ sys_access_key = sys_user.keys[0].access_key
+ sys_secret = sys_user.keys[0].secret_key
+
+ realm_token = RealmToken(period.realm_id, ep, sys_user.uid, sys_access_key, sys_secret)
+
+ logging.info(realm_token.to_json())
+
+ realm_token_b = realm_token.to_json().encode('utf-8')
+ return (0, 'Realm Token: %s' % base64.b64encode(realm_token_b).decode('utf-8'), '')
+
+ def realm_rm_zone_creds(self, realm_token_b64):
+ if not realm_token_b64:
+ print('missing realm token')
+ return False
+
+ realm_token_b = base64.b64decode(realm_token_b64)
+ realm_token_s = realm_token_b.decode('utf-8')
+
+ realm_token = json.loads(realm_token_s)
+
+ access_key = realm_token['access_key']
+ realm_id = realm_token['realm_id']
+
+ try:
+ period_info = self.period_op().get(EntityID(realm_id))
+ except RGWAMException as e:
+ raise RGWAMException('failed to fetch period info', e)
+
+ period = RGWPeriod(period_info)
+
+ master_zg = EntityID(period.master_zonegroup)
+ master_zone = EntityID(period.master_zone)
+
+ logging.info('Period: ' + period.id)
+ logging.info('Master zone: ' + period.master_zone)
+
+ try:
+ zone_info = self.zone_op().get(zone = master_zone)
+ except RGWAMException as e:
+ raise RGWAMException('failed to access master zone', e)
+
+ zone_name = zone_info['name']
+ zone_id = zone_info['id']
+
+ if period.master_zone != zone_id:
+ return (-errno.EINVAL, '', 'Command needs to run on master zone')
+
+ try:
+ user_info = self.user_op().info(master_zone, master_zg, access_key = access_key)
+ except RGWAMException as e:
+ raise RGWAMException('failed to create system user', e)
+
+ user = RGWUser(user_info)
+
+ only_key = True
+
+ for k in user.keys:
+ if k.access_key != access_key:
+ only_key = False
+ break
+
+ success_message = ''
+
+ if only_key:
+ # the only key this user has is the one defined in the token
+ # can remove the user completely
+
+ try:
+ self.user_op().rm(master_zone, master_zg, uid = user.uid)
+ except RGWAMException as e:
+ raise RGWAMException('failed removing user ' + user,uid, e)
+
+ success_message = 'Removed uid ' + user.uid
+ else:
+ try:
+ self.user_op().rm_key(master_zone, master_zg, access_key = access_key)
+ except RGWAMException as e:
+ raise RGWAMException('failed removing access key ' + access_key + '(uid = ' + user.uid + ')', e)
+
+ success_message = 'Removed access key ' + access_key + '(uid = ' + user.uid + ')'
+
+ return (0, success_message, '')
+
+ def zone_create(self, realm_token_b64, zonegroup_name = None, zone_name = None, endpoints = None, start_radosgw = True):
+ if not realm_token_b64:
+ print('missing realm access config')
+ return False
+
+ realm_token_b = base64.b64decode(realm_token_b64)
+ realm_token_s = realm_token_b.decode('utf-8')
+
+ realm_token = json.loads(realm_token_s)
+
+ access_key = realm_token['access_key']
+ secret = realm_token['secret']
+
+ try:
+ realm_info = self.realm_op().pull(realm_token['endpoint'], access_key, secret, set_default = True)
+ except RGWAMException as e:
+ raise RGWAMException('failed to pull realm', e)
+
+ realm_name = realm_info['name']
+ realm_id = realm_info['id']
+ logging.info('Pulled realm %s (%s)' % (realm_name, realm_id))
+
+ realm = EntityID(realm_id)
+
+ period_info = self.period_op().get(realm)
+
+ period = RGWPeriod(period_info)
+
+ logging.info('Period: ' + period.id)
+
+ zonegroup = period.find_zonegroup_by_name(zonegroup_name)
+ if not zonegroup:
+ raise RGWAMException('zonegroup %s not found' % (zonegroup or '<none>'))
+
+ zg = EntityName(zonegroup.name)
+
+ try:
+ zone_info = self.zone_op().create(realm, zg, EntityName(zone_name), endpoints, False,
+ access_key, secret)
+ except RGWAMException as e:
+ raise RGWAMException('failed to create zone', e)
+
+ zone_name = zone_info['name']
+ zone_id = zone_info['id']
+
+ zone = EntityName(zone_name)
+
+ success_message = 'Created zone %s (%s)' % (zone_name, zone_id)
+ logging.info(success_message)
+
+ try:
+ period_info = self.period_op().update(realm, zg, zone, True)
+ except RGWAMException as e:
+ raise RGWAMException('failed to update period', e)
+
+ period = RGWPeriod(period_info)
+
+ logging.debug(period.to_json())
+
+ svc_id = realm_name + '.' + zone_name
+
+ #if endpoints:
+ # eps = endpoints.split(',')
+ # ep = ''
+ # if len(eps) > 0:
+ # ep = eps[0]
+ # o = urlparse(ep)
+ # port = o.port
+ # 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)
+
+ daemons = self.env.mgr.list_daemons(svc_id, 'rgw', refresh=True)
+
+ ep = []
+ for s in daemons:
+ for p in s.ports:
+ ep.append('http://%s:%d' % (s.hostname, p))
+
+ log.error('ERROR: ep=%s' % ','.join(ep))
+
+ try:
+ zone_info = self.zone_op().modify(zone, zg, endpoints = ','.join(ep))
+ except RGWAMException as e:
+ raise RGWAMException('failed to modify zone', e)
+
+ return (0, success_message, '')
+
+
+ def _get_daemon_eps(self, realm_name = None, zonegroup_name = None, zone_name = None):
+ # get running daemons info
+ service_name = None
+ if realm_name and zone_name:
+ service_name = 'rgw.%s.%s' % (realm_name, zone_name)
+
+ daemon_type = 'rgw'
+ daemon_id = None
+ hostname = None
+ refresh = True
+
+ daemons = self.env.mgr.list_daemons(service_name,
+ daemon_type,
+ daemon_id=daemon_id,
+ host=hostname,
+ refresh=refresh)
+
+ rep = RealmsEPs()
+
+ for s in daemons:
+ for p in s.ports:
+ svc_id = s.service_id()
+ l = svc_id.split('.')
+ if len(l) < 2:
+ log.error('ERROR: service id cannot be parsed: (svc_id=%s)' % svc_id)
+ continue
+
+ svc_realm = l[0]
+ svc_zone = l[1]
+
+ if realm_name and svc_realm != realm_name:
+ log.debug('skipping realm %s' % svc_realm)
+ continue
+
+ if zone_name and svc_zone != zone_name:
+ log.debug('skipping zone %s' % svc_zone)
+ continue
+
+ ep = 'http://%s:%d' % (s.hostname, p) # ssl?
+
+ rep.add(svc_realm, svc_zone, ep)
+
+ return rep
+
+
+
+ def _get_rgw_eps(self, realm_name = None, zonegroup_name = None, zone_name = None):
+ rep = RealmsEPs()
+
+ try:
+ realm_list_ret = self.realm_op().list()
+ except RGWAMException as e:
+ raise RGWAMException('failed to list realms', e)
+
+ realms = realm_list_ret.get('realms') or []
+
+ zones_map = {}
+
+ for realm in realms:
+ if realm_name and realm != realm_name:
+ log.debug('skipping realm %s' % realm)
+ continue
+
+ period_info = self.period_op().get(EntityName(realm))
+
+ period = RGWPeriod(period_info)
+
+ zones_map[realm] = {}
+
+ for zg in period.iter_zonegroups():
+ if zonegroup_name and zg.name != zonegroup_name:
+ log.debug('skipping zonegroup %s' % zg.name)
+ continue
+
+ for zone in zg.iter_zones():
+ if zone_name and zone.name != zone_name:
+ log.debug('skipping zone %s' % zone.name)
+ continue
+
+ zones_map[realm][zone.name] = zg.name
+
+ if len(zone.endpoints) == 0:
+ rep.add(realm, zone.name, None)
+ continue
+
+ for ep in zone.endpoints:
+ rep.add(realm, zone.name, ep)
+
+ return (rep, zones_map)
+
+ def realm_reconcile(self, realm_name = None, zonegroup_name = None, zone_name = None, update = False):
+
+ daemon_rep = self._get_daemon_eps(realm_name, zonegroup_name, zone_name)
+
+ rgw_rep, zones_map = self._get_rgw_eps(realm_name, zonegroup_name, zone_name)
+
+ diff = daemon_rep.diff(rgw_rep)
+
+ diffj = json.dumps(diff)
+
+ if not update:
+ return (0, diffj, '')
+
+ for realm, realm_diff in diff.items():
+ for zone, endpoints in realm_diff.items():
+
+ zg = zones_map[realm][zone]
+
+ try:
+ zone_info = self.zone_op().modify(EntityName(zone), EntityName(zg), endpoints = ','.join(diff[realm][zone]))
+ except RGWAMException as e:
+ raise RGWAMException('failed to modify zone', e)
+
+ try:
+ period_info = self.period_op().update(EntityName(realm), EntityName(zg), EntityName(zone), True)
+ except RGWAMException as e:
+ raise RGWAMException('failed to update period', e)
+
+ return (0, 'Updated: ' + diffj, '')
+
+
+ def run_radosgw(self, port = None, log_file = None, debug_ms = None, debug_rgw = None):
+
+ fe_cfg = 'beast'
+ if port:
+ fe_cfg += ' port=%s' % port
+
+
+ params = [ '--rgw-frontends', fe_cfg ]
+
+ if log_file:
+ params += [ '--log-file', log_file ]
+
+ if debug_ms:
+ params += [ '--debug-ms', debug_ms ]
+
+ if debug_rgw:
+ params += [ '--debug-rgw', debug_rgw ]
+
+ (retcode, stdout, stderr) = RGWCmd(self.env).run(params)
+
+ return (retcode, stdout, stderr)
+
--- /dev/null
+import json
+
+from abc import abstractmethod
+
+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 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):
+ return json.dumps(self, default=lambda o: o.__dict__, indent=4)
+
+class RealmToken(JSONObj):
+ def __init__(self, realm_id, endpoint, uid, access_key, secret):
+ self.realm_id = realm_id
+ 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
+
+ def iter_zones(self):
+ for zone in self.zones_by_id.values():
+ yield zone
+
+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']
+ self.realm_name = period_dict['realm_name']
+ self.realm_id = period_dict['realm_id']
+ 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)
+
+ def iter_zonegroups(self):
+ for zg in self.zonegroups_by_id.values():
+ yield zg
+
+
+
+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')
+
+
--- /dev/null
+#!@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 ceph.rgw.rgwam_core import RGWAM, EnvArgs
+from ceph.rgw.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()
+