diff options
Diffstat (limited to 'keystone/cli.py')
-rw-r--r-- | keystone/cli.py | 505 |
1 files changed, 253 insertions, 252 deletions
diff --git a/keystone/cli.py b/keystone/cli.py index 93e362056..e178a31b6 100644 --- a/keystone/cli.py +++ b/keystone/cli.py @@ -33,316 +33,317 @@ config.register_cli_bool('id-only', class BaseApp(cli.log.LoggingApp): - def __init__(self, *args, **kw): - kw.setdefault('name', self.__class__.__name__.lower()) - super(BaseApp, self).__init__(*args, **kw) - - def add_default_params(self): - for args, kw in DEFAULT_PARAMS: - self.add_param(*args, **kw) - - def _parse_keyvalues(self, args): - kv = {} - for x in args: - key, value = x.split('=', 1) - # make lists if there are multiple values - if key.endswith('[]'): - key = key[:-2] - existing = kv.get(key, []) - existing.append(value) - kv[key] = existing - else: - kv[key] = value - return kv + def __init__(self, *args, **kw): + kw.setdefault('name', self.__class__.__name__.lower()) + super(BaseApp, self).__init__(*args, **kw) + + def add_default_params(self): + for args, kw in DEFAULT_PARAMS: + self.add_param(*args, **kw) + + def _parse_keyvalues(self, args): + kv = {} + for x in args: + key, value = x.split('=', 1) + # make lists if there are multiple values + if key.endswith('[]'): + key = key[:-2] + existing = kv.get(key, []) + existing.append(value) + kv[key] = existing + else: + kv[key] = value + return kv class DbSync(BaseApp): - """Sync the database.""" + """Sync the database.""" - name = 'db_sync' + name = 'db_sync' - def __init__(self, *args, **kw): - super(DbSync, self).__init__(*args, **kw) + def __init__(self, *args, **kw): + super(DbSync, self).__init__(*args, **kw) - def main(self): - for k in ['identity', 'catalog', 'policy', 'token']: - driver = utils.import_object(getattr(CONF, k).driver) - if hasattr(driver, 'db_sync'): - driver.db_sync() + def main(self): + for k in ['identity', 'catalog', 'policy', 'token']: + driver = utils.import_object(getattr(CONF, k).driver) + if hasattr(driver, 'db_sync'): + driver.db_sync() class ClientCommand(BaseApp): - ACTION_MAP = None - - def _attr_name(self): - return '%ss' % self.__class__.__name__.lower() - - def _cmd_name(self): - return self.__class__.__name__.lower() - - def __init__(self, *args, **kw): - super(ClientCommand, self).__init__(*args, **kw) - if not self.ACTION_MAP: - self.ACTION_MAP = {'help': 'help'} - self.add_param('action', nargs='?', default='help') - self.add_param('keyvalues', nargs='*') - self.client = kc.Client(CONF.endpoint, token=CONF.auth_token) - self.handle = getattr(self.client, self._attr_name()) - self._build_action_map() - - def _build_action_map(self): - actions = {} - for k in dir(self.handle): - if not k.startswith('_'): - actions[k] = k - self.ACTION_MAP.update(actions) - - def main(self): - """Given some keyvalues create the appropriate data in Keystone.""" - action_name = self.ACTION_MAP[self.params.action] - if action_name == 'help': - self.print_help() - sys.exit(1) - - kv = self._parse_keyvalues(self.params.keyvalues) - try: - f = getattr(self.handle, action_name) - resp = f(**kv) - except Exception: - logging.exception('') - raise - - if CONF.id_only and getattr(resp, 'id'): - print resp.id - return - - if resp is None: - return - - # NOTE(termie): this is ugly but it is mostly because the keystoneclient - # code doesn't give us very serializable instance objects - if type(resp) in [type(list()), type(tuple())]: - o = [] - for r in resp: - d = {} - for k, v in sorted(r.__dict__.iteritems()): - if k[0] == '_' or k == 'manager': - continue - d[k] = v - o.append(d) - else: - o = {} - for k, v in sorted(resp.__dict__.iteritems()): - if k[0] == '_' or k == 'manager': - continue - o[k] = v - - print json.dumps(o) - - def print_help(self): - CONF.set_usage(CONF.usage.replace( - 'COMMAND', '%s SUBCOMMAND' % self._cmd_name())) - CONF.print_help() - - methods = self._get_methods() - print_commands(methods) - - def _get_methods(self): - o = {} - for k in dir(self.handle): - if k.startswith('_'): - continue - if k in ('find', 'findall', 'api', 'resource_class'): - continue - o[k] = getattr(self.handle, k) - return o + ACTION_MAP = None + + def _attr_name(self): + return '%ss' % self.__class__.__name__.lower() + + def _cmd_name(self): + return self.__class__.__name__.lower() + + def __init__(self, *args, **kw): + super(ClientCommand, self).__init__(*args, **kw) + if not self.ACTION_MAP: + self.ACTION_MAP = {'help': 'help'} + self.add_param('action', nargs='?', default='help') + self.add_param('keyvalues', nargs='*') + self.client = kc.Client(CONF.endpoint, token=CONF.auth_token) + self.handle = getattr(self.client, self._attr_name()) + self._build_action_map() + + def _build_action_map(self): + actions = {} + for k in dir(self.handle): + if not k.startswith('_'): + actions[k] = k + self.ACTION_MAP.update(actions) + + def main(self): + """Given some keyvalues create the appropriate data in Keystone.""" + action_name = self.ACTION_MAP[self.params.action] + if action_name == 'help': + self.print_help() + sys.exit(1) + + kv = self._parse_keyvalues(self.params.keyvalues) + try: + f = getattr(self.handle, action_name) + resp = f(**kv) + except Exception: + logging.exception('') + raise + + if CONF.id_only and getattr(resp, 'id'): + print resp.id + return + + if resp is None: + return + + # NOTE(termie): this is ugly but it is mostly because the + # keystoneclient code doesn't give us very + # serializable instance objects + if type(resp) in [type(list()), type(tuple())]: + o = [] + for r in resp: + d = {} + for k, v in sorted(r.__dict__.iteritems()): + if k[0] == '_' or k == 'manager': + continue + d[k] = v + o.append(d) + else: + o = {} + for k, v in sorted(resp.__dict__.iteritems()): + if k[0] == '_' or k == 'manager': + continue + o[k] = v + + print json.dumps(o) + + def print_help(self): + CONF.set_usage(CONF.usage.replace( + 'COMMAND', '%s SUBCOMMAND' % self._cmd_name())) + CONF.print_help() + + methods = self._get_methods() + print_commands(methods) + + def _get_methods(self): + o = {} + for k in dir(self.handle): + if k.startswith('_'): + continue + if k in ('find', 'findall', 'api', 'resource_class'): + continue + o[k] = getattr(self.handle, k) + return o class Role(ClientCommand): - """Role CRUD functions.""" - pass + """Role CRUD functions.""" + pass class Service(ClientCommand): - """Service CRUD functions.""" - pass + """Service CRUD functions.""" + pass class Token(ClientCommand): - """Token CRUD functions.""" - pass + """Token CRUD functions.""" + pass class Tenant(ClientCommand): - """Tenant CRUD functions.""" - pass + """Tenant CRUD functions.""" + pass class User(ClientCommand): - """User CRUD functions.""" + """User CRUD functions.""" - pass + pass class Ec2(ClientCommand): - def _attr_name(self): - return self.__class__.__name__.lower() + def _attr_name(self): + return self.__class__.__name__.lower() CMDS = {'db_sync': DbSync, - 'role': Role, - 'service': Service, - 'token': Token, - 'tenant': Tenant, - 'user': User, - 'ec2': Ec2, - } + 'role': Role, + 'service': Service, + 'token': Token, + 'tenant': Tenant, + 'user': User, + 'ec2': Ec2, + } class CommandLineGenerator(object): - """A keystoneclient lookalike to generate keystone-manage commands. + """A keystoneclient lookalike to generate keystone-manage commands. - One would use it like so: + One would use it like so: - >>> gen = CommandLineGenerator(id_only=None) - >>> cl = gen.ec2.create(user_id='foo', tenant_id='foo') - >>> cl.to_argv() - ... ['keystone-manage', - '--id-only', - 'ec2', - 'create', - 'user_id=foo', - 'tenant_id=foo'] + >>> gen = CommandLineGenerator(id_only=None) + >>> cl = gen.ec2.create(user_id='foo', tenant_id='foo') + >>> cl.to_argv() + ... ['keystone-manage', + '--id-only', + 'ec2', + 'create', + 'user_id=foo', + 'tenant_id=foo'] - """ + """ - cmd = 'keystone-manage' + cmd = 'keystone-manage' - def __init__(self, cmd=None, execute=False, **kw): - if cmd: - self.cmd = cmd - self.flags = kw - self.execute = execute + def __init__(self, cmd=None, execute=False, **kw): + if cmd: + self.cmd = cmd + self.flags = kw + self.execute = execute - def __getattr__(self, key): - return _Manager(self, key) + def __getattr__(self, key): + return _Manager(self, key) class _Manager(object): - def __init__(self, parent, name): - self.parent = parent - self.name = name + def __init__(self, parent, name): + self.parent = parent + self.name = name - def __getattr__(self, key): - return _CommandLine(cmd=self.parent.cmd, - flags=self.parent.flags, - manager=self.name, - method=key, - execute=self.parent.execute) + def __getattr__(self, key): + return _CommandLine(cmd=self.parent.cmd, + flags=self.parent.flags, + manager=self.name, + method=key, + execute=self.parent.execute) class _CommandLine(object): - def __init__(self, cmd, flags, manager, method, execute=False): - self.cmd = cmd - self.flags = flags - self.manager = manager - self.method = method - self.execute = execute - self.kw = {} - - def __call__(self, **kw): - self.kw = kw - if self.execute: - logging.debug('generated cli: %s', str(self)) - out = StringIO.StringIO() - old_out = sys.stdout - sys.stdout = out - try: - main(self.to_argv()) - except SystemExit as e: - pass - finally: - sys.stdout = old_out - rv = out.getvalue().strip().split('\n')[-1] - try: - loaded = json.loads(rv) - if type(loaded) in [type(list()), type(tuple())]: - return [DictWrapper(**x) for x in loaded] - elif type(loaded) is type(dict()): - return DictWrapper(**loaded) - except Exception: - logging.exception('Could not parse JSON: %s', rv) - return rv - return self - - def __flags(self): - o = [] - for k, v in self.flags.iteritems(): - k = k.replace('_', '-') - if v is None: - o.append('--%s' % k) - else: - o.append('--%s=%s' % (k, str(v))) - return o - - def __manager(self): - if self.manager.endswith('s'): - return self.manager[:-1] - return self.manager - - def __kw(self): - o = [] - for k, v in self.kw.iteritems(): - o.append('%s=%s' % (k, str(v))) - return o - - def to_argv(self): - return ([self.cmd] - + self.__flags() - + [self.__manager(), self.method] - + self.__kw()) - - def __str__(self): - args = self.to_argv() - return ' '.join(args[:1] + ['"%s"' % x for x in args[1:]]) + def __init__(self, cmd, flags, manager, method, execute=False): + self.cmd = cmd + self.flags = flags + self.manager = manager + self.method = method + self.execute = execute + self.kw = {} + + def __call__(self, **kw): + self.kw = kw + if self.execute: + logging.debug('generated cli: %s', str(self)) + out = StringIO.StringIO() + old_out = sys.stdout + sys.stdout = out + try: + main(self.to_argv()) + except SystemExit as e: + pass + finally: + sys.stdout = old_out + rv = out.getvalue().strip().split('\n')[-1] + try: + loaded = json.loads(rv) + if type(loaded) in [type(list()), type(tuple())]: + return [DictWrapper(**x) for x in loaded] + elif type(loaded) is type(dict()): + return DictWrapper(**loaded) + except Exception: + logging.exception('Could not parse JSON: %s', rv) + return rv + return self + + def __flags(self): + o = [] + for k, v in self.flags.iteritems(): + k = k.replace('_', '-') + if v is None: + o.append('--%s' % k) + else: + o.append('--%s=%s' % (k, str(v))) + return o + + def __manager(self): + if self.manager.endswith('s'): + return self.manager[:-1] + return self.manager + + def __kw(self): + o = [] + for k, v in self.kw.iteritems(): + o.append('%s=%s' % (k, str(v))) + return o + + def to_argv(self): + return ([self.cmd] + + self.__flags() + + [self.__manager(), self.method] + + self.__kw()) + + def __str__(self): + args = self.to_argv() + return ' '.join(args[:1] + ['"%s"' % x for x in args[1:]]) class DictWrapper(dict): - def __getattr__(self, key): - try: - return self[key] - except KeyError: - raise AttributeError(key) + def __getattr__(self, key): + try: + return self[key] + except KeyError: + raise AttributeError(key) def print_commands(cmds): - print - print "Available commands:" - o = [] - max_length = max([len(k) for k in cmds]) + 2 - for k, cmd in sorted(cmds.iteritems()): - initial_indent = '%s%s: ' % (' ' * (max_length - len(k)), k) - tw = textwrap.TextWrapper(initial_indent=initial_indent, - subsequent_indent=' ' * (max_length + 2), - width=80) - o.extend(tw.wrap( - (cmd.__doc__ and cmd.__doc__ or 'no docs').strip().split('\n')[0])) - print '\n'.join(o) + print + print "Available commands:" + o = [] + max_length = max([len(k) for k in cmds]) + 2 + for k, cmd in sorted(cmds.iteritems()): + initial_indent = '%s%s: ' % (' ' * (max_length - len(k)), k) + tw = textwrap.TextWrapper(initial_indent=initial_indent, + subsequent_indent=' ' * (max_length + 2), + width=80) + o.extend(tw.wrap( + (cmd.__doc__ and cmd.__doc__ or 'no docs').strip().split('\n')[0])) + print '\n'.join(o) def run(cmd, args): - return CMDS[cmd](argv=args).run() + return CMDS[cmd](argv=args).run() def main(argv=None, config_files=None): - CONF.reset() - args = CONF(config_files=config_files, args=argv) + CONF.reset() + args = CONF(config_files=config_files, args=argv) - if len(args) < 2: - CONF.print_help() - print_commands(CMDS) - sys.exit(1) + if len(args) < 2: + CONF.print_help() + print_commands(CMDS) + sys.exit(1) - cmd = args[1] - if cmd in CMDS: - return run(cmd, (args[:1] + args[2:])) + cmd = args[1] + if cmd in CMDS: + return run(cmd, (args[:1] + args[2:])) |