# Copyright 2011 OpenStack Foundation # Copyright 2013 Rackspace Hosting # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from __future__ import print_function import argparse import sys import time INSTANCE_METAVAR = '"opt=[,opt= ...] "' INSTANCE_ERROR = ("Instance argument(s) must be of the form --instance " + INSTANCE_METAVAR + " - see help for details.") NIC_ERROR = ("Invalid NIC argument: %s. Must specify either net-id or port-id " "but not both. Please refer to help.") NO_LOG_FOUND_ERROR = "ERROR: No published '%s' log was found for %s." try: import simplejson as json except ImportError: import json from troveclient import exceptions from troveclient import utils from troveclient.v1.modules import Module def _poll_for_status(poll_fn, obj_id, action, final_ok_states, poll_period=5, show_progress=True): """Block while an action is being performed, periodically printing progress. """ def print_progress(progress): if show_progress: msg = ('\rInstance %(action)s... %(progress)s%% complete' % dict(action=action, progress=progress)) else: msg = '\rInstance %(action)s...' % dict(action=action) sys.stdout.write(msg) sys.stdout.flush() print() while True: obj = poll_fn(obj_id) status = obj.status.lower() progress = getattr(obj, 'progress', None) or 0 if status in final_ok_states: print_progress(100) print("\nFinished") break elif status == "error": print("\nError %(action)s instance" % {'action': action}) break else: print_progress(progress) time.sleep(poll_period) def _print_instance(instance): info = instance._info.copy() info['flavor'] = instance.flavor['id'] if hasattr(instance, 'volume'): info['volume'] = instance.volume['size'] if 'used' in instance.volume: info['volume_used'] = instance.volume['used'] if hasattr(instance, 'ip'): info['ip'] = ', '.join(instance.ip) if hasattr(instance, 'datastore'): info['datastore'] = instance.datastore['type'] info['datastore_version'] = instance.datastore['version'] if hasattr(instance, 'configuration'): info['configuration'] = instance.configuration['id'] if hasattr(instance, 'replica_of'): info['replica_of'] = instance.replica_of['id'] if hasattr(instance, 'replicas'): replicas = [replica['id'] for replica in instance.replicas] info['replicas'] = ', '.join(replicas) info.pop('links', None) utils.print_dict(info) def _print_object(obj): # Get rid of those ugly links if obj._info.get('links'): del(obj._info['links']) # Fallback to str_id for flavors, where necessary if hasattr(obj, 'str_id'): obj._info['id'] = obj.id del(obj._info['str_id']) utils.print_dict(obj._info) def _find_instance_or_cluster(cs, instance_or_cluster): """Returns an instance or cluster, found by id, along with the type of resource, instance or cluster, that was found. Raises CommandError if none is found. """ try: return _find_instance(cs, instance_or_cluster), 'instance' except exceptions.CommandError: try: return _find_cluster(cs, instance_or_cluster), 'cluster' except Exception: raise exceptions.CommandError( "No instance or cluster with a name or ID of '%s' exists." % instance_or_cluster) def _find_instance(cs, instance): """Get an instance by ID.""" return utils.find_resource(cs.instances, instance) def _find_cluster(cs, cluster): """Get a cluster by ID.""" return utils.find_resource(cs.clusters, cluster) def _find_flavor(cs, flavor): """Get a flavor by ID.""" return utils.find_resource(cs.flavors, flavor) def _find_backup(cs, backup): """Get a backup by ID.""" return utils.find_resource(cs.backups, backup) def _find_module(cs, module): """Get a module by ID.""" return utils.find_resource(cs.modules, module) def _find_datastore(cs, datastore): """Get a datastore by ID.""" return utils.find_resource(cs.datastores, datastore) def _find_datastore_version(cs, datastore_version): """Get a datastore version by ID.""" return utils.find_resource(cs.datastores, datastore_version) # Flavor related calls @utils.arg('--datastore_type', metavar='', default=None, help='Type of the datastore. For eg: mysql.') @utils.arg("--datastore_version_id", metavar="", default=None, help="ID of the datastore version.") @utils.service_type('database') def do_flavor_list(cs, args): """Lists available flavors.""" if args.datastore_type and args.datastore_version_id: flavors = cs.flavors.list_datastore_version_associated_flavors( args.datastore_type, args.datastore_version_id) elif not args.datastore_type and not args.datastore_version_id: flavors = cs.flavors.list() else: raise exceptions.MissingArgs(['datastore_type', 'datastore_version_id']) # Fallback to str_id where necessary. _flavors = [] for f in flavors: if not f.id and hasattr(f, 'str_id'): f.id = f.str_id _flavors.append(f) utils.print_list(_flavors, ['id', 'name', 'ram'], labels={'ram': 'RAM'}) @utils.arg('flavor', metavar='', help='ID or name of the flavor.') @utils.service_type('database') def do_flavor_show(cs, args): """Shows details of a flavor.""" flavor = _find_flavor(cs, args.flavor) _print_object(flavor) # Instance related calls @utils.arg('--limit', metavar='', type=int, default=None, help='Limit the number of results displayed.') @utils.arg('--marker', metavar='', type=str, default=None, help='Begin displaying the results for IDs greater than the ' 'specified marker. When used with --limit, set this to ' 'the last ID displayed in the previous run.') @utils.arg('--include_clustered', '--include-clustered', dest='include_clustered', action="store_true", default=False, help="Include instances that are part of a cluster " "(default %(default)s). --include-clustered may be " "deprecated in the future, retaining just " "--include_clustered.") @utils.service_type('database') def do_list(cs, args): """Lists all the instances.""" instances = cs.instances.list(limit=args.limit, marker=args.marker, include_clustered=args.include_clustered) _print_instances(instances) def _print_instances(instances): for instance in instances: setattr(instance, 'flavor_id', instance.flavor['id']) if hasattr(instance, 'volume'): setattr(instance, 'size', instance.volume['size']) else: setattr(instance, 'size', '-') if hasattr(instance, 'datastore'): if instance.datastore.get('version'): setattr(instance, 'datastore_version', instance.datastore['version']) setattr(instance, 'datastore', instance.datastore['type']) utils.print_list(instances, ['id', 'name', 'datastore', 'datastore_version', 'status', 'flavor_id', 'size']) @utils.arg('--limit', metavar='', type=int, default=None, help='Limit the number of results displayed.') @utils.arg('--marker', metavar='', type=str, default=None, help='Begin displaying the results for IDs greater than the ' 'specified marker. When used with --limit, set this to ' 'the last ID displayed in the previous run.') @utils.service_type('database') def do_cluster_list(cs, args): """Lists all the clusters.""" clusters = cs.clusters.list(limit=args.limit, marker=args.marker) for cluster in clusters: setattr(cluster, 'datastore_version', cluster.datastore['version']) setattr(cluster, 'datastore', cluster.datastore['type']) setattr(cluster, 'task_name', cluster.task['name']) utils.print_list(clusters, ['id', 'name', 'datastore', 'datastore_version', 'task_name']) @utils.arg('instance', metavar='', help='ID or name of the instance.') @utils.service_type('database') def do_show(cs, args): """Shows details of an instance.""" instance = _find_instance(cs, args.instance) _print_instance(instance) @utils.arg('cluster', metavar='', help='ID or name of the cluster.') @utils.service_type('database') def do_cluster_show(cs, args): """Shows details of a cluster.""" cluster = _find_cluster(cs, args.cluster) info = cluster._info.copy() info['datastore'] = cluster.datastore['type'] info['datastore_version'] = cluster.datastore['version'] info['task_name'] = cluster.task['name'] info['task_description'] = cluster.task['description'] del info['task'] if hasattr(cluster, 'ip'): info['ip'] = ', '.join(cluster.ip) del info['instances'] cluster._info = info _print_object(cluster) @utils.arg('cluster', metavar='', help='ID or name of the cluster.') @utils.service_type('database') def do_cluster_instances(cs, args): """Lists all instances of a cluster.""" cluster = _find_cluster(cs, args.cluster) instances = cluster._info['instances'] for instance in instances: instance['flavor_id'] = instance['flavor']['id'] if instance.get('volume'): instance['size'] = instance['volume']['size'] utils.print_list( instances, ['id', 'name', 'flavor_id', 'size', 'status'], obj_is_dict=True) @utils.arg('--instance', metavar=INSTANCE_METAVAR, action='append', dest='instances', default=[], help="Add an instance to the cluster. Specify multiple " "times to create multiple instances. Valid options are: " "name=, flavor=, volume=, " "module=.") @utils.arg('cluster', metavar='', help='ID or name of the cluster.') @utils.service_type('database') def do_cluster_grow(cs, args): """Adds more instances to a cluster.""" cluster = _find_cluster(cs, args.cluster) instances = [] for instance_opts in args.instances: instance_info = {} for z in instance_opts.split(","): for (k, v) in [z.split("=", 1)[:2]]: if k == "name": instance_info[k] = v elif k == "flavor": flavor_id = _find_flavor(cs, v).id instance_info["flavorRef"] = str(flavor_id) elif k == "volume": instance_info["volume"] = {"size": v} else: instance_info[k] = v if not instance_info.get('flavorRef'): raise exceptions.CommandError( 'flavor is required. ' 'Instance arguments must be of the form ' '--instance ' ) instances.append(instance_info) cs.clusters.grow(cluster, instances=instances) @utils.arg('cluster', metavar='', help='ID or name of the cluster.') @utils.arg('instances', metavar='', nargs='+', default=[], help="Drop instance(s) from the cluster. Specify " "multiple ids to drop multiple instances.") @utils.service_type('database') def do_cluster_shrink(cs, args): """Drops instances from a cluster.""" cluster = _find_cluster(cs, args.cluster) instances = [{'id': _find_instance(cs, instance).id} for instance in args.instances] cs.clusters.shrink(cluster, instances=instances) @utils.arg('instance', metavar='', help='ID or name of the instance.') @utils.service_type('database') def do_delete(cs, args): """Deletes an instance.""" instance = _find_instance(cs, args.instance) cs.instances.delete(instance) @utils.arg('cluster', metavar='', help='ID or name of the cluster.') @utils.service_type('database') def do_cluster_delete(cs, args): """Deletes a cluster.""" cluster = _find_cluster(cs, args.cluster) cs.clusters.delete(cluster) @utils.arg('instance', metavar='', type=str, help='ID or name of the instance.') @utils.arg('--name', metavar='', type=str, default=None, help='Name of the instance.') @utils.arg('--configuration', metavar='', type=str, default=None, help='ID of the configuration reference to attach.') @utils.arg('--detach_replica_source', '--detach-replica-source', dest='detach_replica_source', action="store_true", default=False, help='Detach the replica instance from its replication source. ' '--detach-replica-source may be deprecated in the future ' 'in favor of just --detach_replica_source') @utils.arg('--remove_configuration', dest='remove_configuration', action="store_true", default=False, help='Drops the current configuration reference.') @utils.service_type('database') def do_update(cs, args): """Updates an instance: Edits name, configuration, or replica source.""" instance = _find_instance(cs, args.instance) cs.instances.edit(instance, args.configuration, args.name, args.detach_replica_source, args.remove_configuration) @utils.arg('name', metavar='', type=str, help='Name of the instance.') @utils.arg('--size', metavar='', type=int, default=None, help="Size of the instance disk volume in GB. " "Required when volume support is enabled.") @utils.arg('--volume_type', metavar='', type=str, default=None, help="Volume type. Optional when volume support is enabled.") @utils.arg('flavor', metavar='', help='Flavor ID or name of the instance.') @utils.arg('--databases', metavar='', help='Optional list of databases.', nargs="+", default=[]) @utils.arg('--users', metavar='', help='Optional list of users.', nargs="+", default=[]) @utils.arg('--backup', metavar='', default=None, help='A backup ID.') @utils.arg('--availability_zone', metavar='', default=None, help='The Zone hint to give to Nova.') @utils.arg('--datastore', metavar='', default=None, help='A datastore name or ID.') @utils.arg('--datastore_version', metavar='', default=None, help='A datastore version name or ID.') @utils.arg('--nic', metavar=",v4-fixed-ip=," "port-id=>", action='append', dest='nics', default=[], help="Create a NIC on the instance. " "Specify option multiple times to create multiple NICs. " "net-id: attach NIC to network with this ID " "(either port-id or net-id must be specified), " "v4-fixed-ip: IPv4 fixed address for NIC (optional), " "port-id: attach NIC to port with this ID " "(either port-id or net-id must be specified).") @utils.arg('--configuration', metavar='', default=None, help='ID of the configuration group to attach to the instance.') @utils.arg('--replica_of', metavar='', default=None, help='ID or name of an existing instance to replicate from.') @utils.arg('--replica_count', metavar='', type=int, default=1, help='Number of replicas to create (defaults to %(default)s).') @utils.arg('--module', metavar='', type=str, dest='modules', action='append', default=[], help='ID or name of the module to apply. Specify multiple ' 'times to apply multiple modules.') @utils.service_type('database') def do_create(cs, args): """Creates a new instance.""" volume = None replica_of_instance = None flavor_id = _find_flavor(cs, args.flavor).id if args.size: volume = {"size": args.size, "type": args.volume_type} restore_point = None if args.backup: restore_point = {"backupRef": args.backup} if args.replica_of: replica_of_instance = _find_instance(cs, args.replica_of) databases = [{'name': value} for value in args.databases] users = [{'name': n, 'password': p, 'databases': databases} for (n, p) in [z.split(':')[:2] for z in args.users]] nics = [] for nic_str in args.nics: nic_info = dict([(k, v) for (k, v) in [z.split("=", 1)[:2] for z in nic_str.split(",")]]) _validate_nic_info(nic_info, nic_str) nics.append(nic_info) modules = [] for module in args.modules: modules.append(_find_module(cs, module).id) instance = cs.instances.create(args.name, flavor_id, volume=volume, databases=databases, users=users, restorePoint=restore_point, availability_zone=args.availability_zone, datastore=args.datastore, datastore_version=args.datastore_version, nics=nics, configuration=args.configuration, replica_of=replica_of_instance, replica_count=args.replica_count, modules=modules) _print_instance(instance) def _validate_nic_info(nic_info, nic_str): # need one or the other, not both, not none (!= ~ XOR) if not (bool(nic_info.get('net-id')) != bool(nic_info.get('port-id'))): raise exceptions.ValidationError(NIC_ERROR % ("nic='%s'" % nic_str)) def _get_flavor(cs, opts_str): flavor_name, opts_str = _strip_option(opts_str, 'flavor', True) flavor_id = _find_flavor(cs, flavor_name).id return str(flavor_id), opts_str def _get_networks(opts_str): nic_args_list, opts_str = _strip_option(opts_str, 'nic', is_required=False, quotes_required=True, allow_multiple=True) nic_info_list = [] for nic_args in nic_args_list: orig_nic_args = nic_args = _unquote(nic_args) nic_info = {} net_id, nic_args = _strip_option(nic_args, 'net-id', False) port_id, nic_args = _strip_option(nic_args, 'port-id', False) fixed_ipv4, nic_args = _strip_option(nic_args, 'v4-fixed-ip', False) if nic_args: raise exceptions.ValidationError( "Unknown args '%s' in 'nic' option" % nic_args) if net_id: nic_info.update({'net-id': net_id}) if port_id: nic_info.update({'port-id': port_id}) if fixed_ipv4: nic_info.update({'v4-fixed-ip': fixed_ipv4}) _validate_nic_info(nic_info, orig_nic_args) nic_info_list.append(nic_info) return nic_info_list, opts_str def _unquote(value): def _strip_quotes(value, quote_char): if value: return value.strip(quote_char) return value return _strip_quotes(_strip_quotes(value, "'"), '"') def _get_volume(opts_str): volume_size, opts_str = _strip_option(opts_str, 'volume', is_required=True) volume_type, opts_str = _strip_option(opts_str, 'volume_type', is_required=False) volume_info = {"size": volume_size} if volume_type: volume_info.update({"type": volume_type}) return volume_info, opts_str def _get_availability_zone(opts_str): return _strip_option(opts_str, 'availability_zone', is_required=False) def _get_modules(cs, opts_str): modules, opts_str = _strip_option( opts_str, 'module', is_required=False, allow_multiple=True) module_list = [] for module in modules: module_info = {'id': _find_module(cs, module).id} module_list.append(module_info) return module_list, opts_str def _strip_option(opts_str, opt_name, is_required=True, quotes_required=False, allow_multiple=False): opt_value = [] if allow_multiple else None opts_str = opts_str.strip().strip(",") if opt_name in opts_str: try: split_str = '%s=' % opt_name parts = opts_str.split(split_str) before = parts[0] after = parts[1] if len(parts) > 2: if allow_multiple: after = split_str.join(parts[1:]) value, after = _strip_option( after, opt_name, is_required=is_required, quotes_required=quotes_required, allow_multiple=allow_multiple) opt_value.extend(value) else: raise exceptions.ValidationError(( "Option '%s' found more than once in argument " "--instance " % opt_name) + INSTANCE_METAVAR) # Handle complex (quoted) properties. Strip the quotes. quote = after[0] if quote in ["'", '"']: after = after[1:] else: if quotes_required: raise exceptions.ValidationError( "Invalid '%s' option. The value must be quoted. " "(Or perhaps you're missing quotes around the entire " "argument string)" % opt_name) quote = '' split_str = '%s,' % quote parts = after.split(split_str) value = str(parts[0]).strip() if allow_multiple: opt_value.append(value) opt_value = list(set(opt_value)) else: opt_value = value opts_str = before + split_str.join(parts[1:]) except IndexError: raise exceptions.ValidationError("Invalid '%s' parameter. %s." % (opt_name, INSTANCE_ERROR)) if is_required and not opt_value: msg = "Missing option '%s' for argument --instance " + INSTANCE_METAVAR raise exceptions.MissingArgs([opt_name], message=msg) return opt_value, opts_str.strip().strip(",") @utils.arg('name', metavar='', type=str, help='Name of the cluster.') @utils.arg('datastore', metavar='', help='A datastore name or ID.') @utils.arg('datastore_version', metavar='', help='A datastore version name or ID.') @utils.arg('--instance', metavar=INSTANCE_METAVAR, action='append', dest='instances', default=[], help="Create an instance for the cluster. Specify multiple " "times to create multiple instances. " "Valid options are: flavor=, " "volume=, volume_type=, " "nic=', v4-fixed-ip=, " "port-id=>' " "(where net-id=network_id, v4-fixed-ip=IPv4r_fixed_address, " "port-id=port_id), availability_zone=, " "module=.") @utils.service_type('database') def do_cluster_create(cs, args): """Creates a new cluster.""" instances = [] for instance_opts in args.instances: instance_info = {} flavor, instance_opts = _get_flavor(cs, instance_opts) instance_info["flavorRef"] = flavor volume, instance_opts = _get_volume(instance_opts) instance_info["volume"] = volume nics, instance_opts = _get_networks(instance_opts) if nics: instance_info["nics"] = nics availability_zone, instance_opts = _get_availability_zone( instance_opts) if availability_zone: instance_info["availability_zone"] = availability_zone modules, instance_opts = _get_modules(cs, instance_opts) if modules: instance_info["modules"] = modules if instance_opts: raise exceptions.ValidationError( "Unknown option(s) '%s' specified for instance" % instance_opts) instances.append(instance_info) if len(instances) == 0: raise exceptions.MissingArgs(['instance']) cluster = cs.clusters.create(args.name, args.datastore, args.datastore_version, instances=instances) cluster._info['task_name'] = cluster.task['name'] cluster._info['task_description'] = cluster.task['description'] del cluster._info['task'] cluster._info['datastore'] = cluster.datastore['type'] cluster._info['datastore_version'] = cluster.datastore['version'] del cluster._info['instances'] _print_object(cluster) @utils.arg('instance', metavar='', type=str, help='ID or name of the instance.') @utils.arg('flavor', metavar='', help='New flavor of the instance.') @utils.service_type('database') def do_resize_instance(cs, args): """Resizes an instance with a new flavor.""" instance = _find_instance(cs, args.instance) flavor_id = _find_flavor(cs, args.flavor).id cs.instances.resize_instance(instance, flavor_id) @utils.arg('instance', metavar='', type=str, help='ID or name of the instance.') @utils.arg('size', metavar='', type=int, default=None, help='New size of the instance disk volume in GB.') @utils.service_type('database') def do_resize_volume(cs, args): """Resizes the volume size of an instance.""" instance = _find_instance(cs, args.instance) cs.instances.resize_volume(instance, args.size) @utils.arg('instance', metavar='', type=str, help='ID or name of the instance.') @utils.service_type('database') def do_restart(cs, args): """Restarts an instance.""" instance = _find_instance(cs, args.instance) cs.instances.restart(instance) # Replication related commands @utils.arg('instance', metavar='', type=str, help='ID or name of the instance.') def do_detach_replica(cs, args): """Detaches a replica instance from its replication source.""" instance = _find_instance(cs, args.instance) cs.instances.edit(instance, detach_replica_source=True) @utils.arg('instance', metavar='', type=str, help='ID or name of the instance.') def do_promote_to_replica_source(cs, args): """Promotes a replica to be the new replica source of its set.""" instance = _find_instance(cs, args.instance) cs.instances.promote_to_replica_source(instance) @utils.arg('instance', metavar='', type=str, help='ID or name of the instance.') def do_eject_replica_source(cs, args): """Ejects a replica source from its set.""" instance = _find_instance(cs, args.instance) cs.instances.eject_replica_source(instance) # Backup related commands @utils.arg('backup', metavar='', help='ID of the backup.') @utils.service_type('database') def do_backup_show(cs, args): """Shows details of a backup.""" backup = _find_backup(cs, args.backup) _print_object(backup) @utils.arg('instance', metavar='', help='ID or name of the instance.') @utils.arg('--limit', metavar='', default=None, help='Return up to N number of the most recent backups.') @utils.arg('--marker', metavar='', type=str, default=None, help='Begin displaying the results for IDs greater than the ' 'specified marker. When used with --limit, set this to ' 'the last ID displayed in the previous run.') @utils.service_type('database') def do_backup_list_instance(cs, args): """Lists available backups for an instance.""" instance = _find_instance(cs, args.instance) wrapper = cs.instances.backups(instance, limit=args.limit, marker=args.marker) backups = wrapper.items while wrapper.next and not args.limit: wrapper = cs.instances.backups(instance, marker=wrapper.next) backups += wrapper.items utils.print_list(backups, ['id', 'name', 'status', 'parent_id', 'updated'], order_by='updated') @utils.arg('--limit', metavar='', default=None, help='Return up to N number of the most recent backups.') @utils.arg('--marker', metavar='', type=str, default=None, help='Begin displaying the results for IDs greater than the ' 'specified marker. When used with --limit, set this to ' 'the last ID displayed in the previous run.') @utils.arg('--datastore', metavar='', default=None, help='Name or ID of the datastore to list backups for.') @utils.service_type('database') def do_backup_list(cs, args): """Lists available backups.""" wrapper = cs.backups.list(limit=args.limit, datastore=args.datastore, marker=args.marker) backups = wrapper.items while wrapper.next and not args.limit: wrapper = cs.backups.list(marker=wrapper.next) backups += wrapper.items utils.print_list(backups, ['id', 'instance_id', 'name', 'status', 'parent_id', 'updated'], order_by='updated') @utils.arg('backup', metavar='', help='ID or name of the backup.') @utils.service_type('database') def do_backup_delete(cs, args): """Deletes a backup.""" backup = _find_backup(cs, args.backup) cs.backups.delete(backup) @utils.arg('instance', metavar='', help='ID or name of the instance.') @utils.arg('name', metavar='', help='Name of the backup.') @utils.arg('--description', metavar='', default=None, help='An optional description for the backup.') @utils.arg('--parent', metavar='', default=None, help='Optional ID of the parent backup to perform an' ' incremental backup from.') @utils.service_type('database') def do_backup_create(cs, args): """Creates a backup of an instance.""" instance = _find_instance(cs, args.instance) backup = cs.backups.create(args.name, instance, description=args.description, parent_id=args.parent) _print_object(backup) @utils.arg('name', metavar='', help='Name of the backup.') @utils.arg('backup', metavar='', help='Backup ID of the source backup.', default=None) @utils.arg('--region', metavar='', help='Region where the source ' 'backup resides.', default=None) @utils.arg('--description', metavar='', default=None, help='An optional description for the backup.') @utils.service_type('database') def do_backup_copy(cs, args): """Creates a backup from another backup.""" if args.backup: backup_ref = {"id": args.backup, "region": args.region} else: backup_ref = None backup = cs.backups.create(args.name, instance=None, description=args.description, parent_id=None, backup=backup_ref,) _print_object(backup) # Database related actions @utils.arg('instance', metavar='', help='ID or name of the instance.') @utils.arg('name', metavar='', help='Name of the database.') @utils.arg('--character_set', metavar='', default=None, help='Optional character set for database.') @utils.arg('--collate', metavar='', default=None, help='Optional collation type for database.') @utils.service_type('database') def do_database_create(cs, args): """Creates a database on an instance.""" instance = _find_instance(cs, args.instance) database_dict = {'name': args.name} if args.collate: database_dict['collate'] = args.collate if args.character_set: database_dict['character_set'] = args.character_set cs.databases.create(instance, [database_dict]) @utils.arg('instance', metavar='', help='ID or name of the instance.') @utils.service_type('database') def do_database_list(cs, args): """Lists available databases on an instance.""" instance = _find_instance(cs, args.instance) wrapper = cs.databases.list(instance) databases = wrapper.items while (wrapper.next): wrapper = cs.databases.list(instance, marker=wrapper.next) databases += wrapper.items utils.print_list(databases, ['name']) @utils.arg('instance', metavar='', help='ID or name of the instance.') @utils.arg('database', metavar='', help='Name of the database.') @utils.service_type('database') def do_database_delete(cs, args): """Deletes a database from an instance.""" instance = _find_instance(cs, args.instance) cs.databases.delete(instance, args.database) # User related actions @utils.arg('instance', metavar='', help='ID or name of the instance.') @utils.arg('name', metavar='', help='Name of user.') @utils.arg('password', metavar='', help='Password of user.') @utils.arg('--host', metavar='', default=None, help='Optional host of user.') @utils.arg('--databases', metavar='', help='Optional list of databases.', nargs="+", default=[]) @utils.service_type('database') def do_user_create(cs, args): """Creates a user on an instance.""" instance = _find_instance(cs, args.instance) databases = [{'name': value} for value in args.databases] user = {'name': args.name, 'password': args.password, 'databases': databases} if args.host: user['host'] = args.host cs.users.create(instance, [user]) @utils.arg('instance', metavar='', help='ID or name of the instance.') @utils.service_type('database') def do_user_list(cs, args): """Lists the users for an instance.""" instance = _find_instance(cs, args.instance) wrapper = cs.users.list(instance) users = wrapper.items while (wrapper.next): wrapper = cs.users.list(instance, marker=wrapper.next) users += wrapper.items for user in users: db_names = [db['name'] for db in user.databases] user.databases = ', '.join(db_names) utils.print_list(users, ['name', 'host', 'databases']) @utils.arg('instance', metavar='', help='ID or name of the instance.') @utils.arg('name', metavar='', help='Name of user.') @utils.arg('--host', metavar='', default=None, help='Optional host of user.') @utils.service_type('database') def do_user_delete(cs, args): """Deletes a user from an instance.""" instance = _find_instance(cs, args.instance) cs.users.delete(instance, args.name, hostname=args.host) @utils.arg('instance', metavar='', help='ID or name of the instance.') @utils.arg('name', metavar='', help='Name of user.') @utils.arg('--host', metavar='', default=None, help='Optional host of user.') @utils.service_type('database') def do_user_show(cs, args): """Shows details of a user of an instance.""" instance = _find_instance(cs, args.instance) user = cs.users.get(instance, args.name, hostname=args.host) _print_object(user) @utils.arg('instance', metavar='', help='ID or name of the instance.') @utils.arg('name', metavar='', help='Name of user.') @utils.arg('--host', metavar='', default=None, help='Optional host of user.') @utils.service_type('database') def do_user_show_access(cs, args): """Shows access details of a user of an instance.""" instance = _find_instance(cs, args.instance) access = cs.users.list_access(instance, args.name, hostname=args.host) utils.print_list(access, ['name']) @utils.arg('instance', metavar='', help='ID or name of the instance.') @utils.arg('name', metavar='', help='Name of user.') @utils.arg('--host', metavar='', default=None, help='Optional host of user.') @utils.arg('--new_name', metavar='', default=None, help='Optional new name of user.') @utils.arg('--new_password', metavar='', default=None, help='Optional new password of user.') @utils.arg('--new_host', metavar='', default=None, help='Optional new host of user.') @utils.service_type('database') def do_user_update_attributes(cs, args): """Updates a user's attributes on an instance. At least one optional argument must be provided. """ instance = _find_instance(cs, args.instance) new_attrs = {} if args.new_name: new_attrs['name'] = args.new_name if args.new_password: new_attrs['password'] = args.new_password if args.new_host: new_attrs['host'] = args.new_host cs.users.update_attributes(instance, args.name, newuserattr=new_attrs, hostname=args.host) @utils.arg('instance', metavar='', help='ID or name of the instance.') @utils.arg('name', metavar='', help='Name of user.') @utils.arg('--host', metavar='', default=None, help='Optional host of user.') @utils.arg('databases', metavar='', help='List of databases.', nargs="+", default=[]) @utils.service_type('database') def do_user_grant_access(cs, args): """Grants access to a database(s) for a user.""" instance = _find_instance(cs, args.instance) cs.users.grant(instance, args.name, args.databases, hostname=args.host) @utils.arg('instance', metavar='', help='ID or name of the instance.') @utils.arg('name', metavar='', help='Name of user.') @utils.arg('database', metavar='', help='A single database.') @utils.arg('--host', metavar='', default=None, help='Optional host of user.') @utils.service_type('database') def do_user_revoke_access(cs, args): """Revokes access to a database for a user.""" instance = _find_instance(cs, args.instance) cs.users.revoke(instance, args.name, args.database, hostname=args.host) # Limits related commands @utils.service_type('database') def do_limit_list(cs, args): """Lists the limits for a tenant.""" limits = cs.limits.list() # Pop the first one, its absolute limits absolute = limits.pop(0) _print_object(absolute) utils.print_list(limits, ['value', 'verb', 'remaining', 'unit']) # Root related commands @utils.arg('instance_or_cluster', metavar='', help='ID or name of the instance or cluster.') @utils.arg('--root_password', metavar='', default=None, help='Root password to set.') @utils.service_type('database') def do_root_enable(cs, args): """Enables root for an instance and resets if already exists.""" instance_or_cluster, resource_type = _find_instance_or_cluster( cs, args.instance_or_cluster) if resource_type == 'instance': root = cs.root.create_instance_root(instance_or_cluster, args.root_password) else: root = cs.root.create_cluster_root(instance_or_cluster, args.root_password) utils.print_dict({'name': root[0], 'password': root[1]}) @utils.arg('instance', metavar='', help='ID or name of the instance.') @utils.service_type('database') def do_root_disable(cs, args): """Disables root for an instance.""" instance = _find_instance(cs, args.instance) cs.root.disable_instance_root(instance) @utils.arg('instance_or_cluster', metavar='', help='ID or name of the instance or cluster.') @utils.service_type('database') def do_root_show(cs, args): """Gets status if root was ever enabled for an instance or cluster.""" instance_or_cluster, resource_type = _find_instance_or_cluster( cs, args.instance_or_cluster) if resource_type == 'instance': root = cs.root.is_instance_root_enabled(instance_or_cluster) else: root = cs.root.is_cluster_root_enabled(instance_or_cluster) utils.print_dict({'is_root_enabled': root.rootEnabled}) # security group related functions @utils.service_type('database') def do_secgroup_list(cs, args): """Lists all security groups.""" wrapper = cs.security_groups.list() sec_grps = wrapper.items while (wrapper.next): wrapper = cs.security_groups.list() sec_grps += wrapper.items utils.print_list(sec_grps, ['id', 'name', 'instance_id']) @utils.arg('security_group', metavar='', help='Security group ID.') @utils.service_type('database') def do_secgroup_show(cs, args): """Shows details of a security group.""" sec_grp = cs.security_groups.get(args.security_group) del sec_grp._info['rules'] _print_object(sec_grp) @utils.arg('security_group', metavar='', help='Security group ID.') @utils.arg('cidr', metavar='', help='CIDR address.') @utils.service_type('database') def do_secgroup_add_rule(cs, args): """Creates a security group rule.""" rules = cs.security_group_rules.create( args.security_group, args.cidr) utils.print_list(rules, [ 'id', 'security_group_id', 'protocol', 'from_port', 'to_port', 'cidr', 'created'], obj_is_dict=True) @utils.arg('security_group', metavar='', help='Security group ID.') @utils.service_type('database') def do_secgroup_list_rules(cs, args): """Lists all rules for a security group.""" sec_grp = cs.security_groups.get(args.security_group) rules = sec_grp._info['rules'] utils.print_list( rules, ['id', 'protocol', 'from_port', 'to_port', 'cidr'], obj_is_dict=True) @utils.arg('security_group_rule', metavar='', help='Name of security group rule.') @utils.service_type('database') def do_secgroup_delete_rule(cs, args): """Deletes a security group rule.""" cs.security_group_rules.delete(args.security_group_rule) @utils.service_type('database') def do_datastore_list(cs, args): """Lists available datastores.""" datastores = cs.datastores.list() utils.print_list(datastores, ['id', 'name']) @utils.arg('datastore', metavar='', help='ID of the datastore.') @utils.service_type('database') def do_datastore_show(cs, args): """Shows details of a datastore.""" datastore = cs.datastores.get(args.datastore) if hasattr(datastore, 'default_version'): datastore._info['default_version'] = getattr(datastore, 'default_version') _print_object(datastore) @utils.arg('datastore', metavar='', help='ID or name of the datastore.') @utils.service_type('database') def do_datastore_version_list(cs, args): """Lists available versions for a datastore.""" datastore_versions = cs.datastore_versions.list(args.datastore) utils.print_list(datastore_versions, ['id', 'name']) @utils.arg('--datastore', metavar='', default=None, help='ID or name of the datastore. Optional if the ID of the' ' datastore_version is provided.') @utils.arg('datastore_version', metavar='', help='ID or name of the datastore version.') @utils.service_type('database') def do_datastore_version_show(cs, args): """Shows details of a datastore version.""" if args.datastore: datastore_version = cs.datastore_versions.get(args.datastore, args.datastore_version) elif utils.is_uuid_like(args.datastore_version): datastore_version = cs.datastore_versions.get_by_uuid( args.datastore_version) else: raise exceptions.NoUniqueMatch('The datastore name or id is required' ' to retrieve a datastore version' ' by name.') _print_object(datastore_version) # configuration group related functions @utils.arg('instance', metavar='', type=str, help='ID or name of the instance.') @utils.arg('configuration', metavar='', type=str, help='ID of the configuration group to attach to the instance.') @utils.service_type('database') def do_configuration_attach(cs, args): """Attaches a configuration group to an instance.""" instance = _find_instance(cs, args.instance) cs.instances.modify(instance, args.configuration) @utils.arg('name', metavar='', help='Name of the configuration group.') @utils.arg('values', metavar='', help='Dictionary of the values to set.') @utils.arg('--datastore', metavar='', help='Datastore assigned to the configuration group. Required if ' 'default datastore is not configured.') @utils.arg('--datastore_version', metavar='', help='Datastore version ID assigned to the configuration group.') @utils.arg('--description', metavar='', default=None, help='An optional description for the configuration group.') @utils.service_type('database') def do_configuration_create(cs, args): """Creates a configuration group.""" config_grp = cs.configurations.create( args.name, args.values, description=args.description, datastore=args.datastore, datastore_version=args.datastore_version) config_grp._info['values'] = json.dumps(config_grp.values) _print_object(config_grp) @utils.arg('instance', metavar='', type=str, help='ID or name of the instance.') @utils.service_type('database') def do_configuration_default(cs, args): """Shows the default configuration of an instance.""" instance = _find_instance(cs, args.instance) configs = cs.instances.configuration(instance) utils.print_dict(configs._info['configuration']) @utils.arg('configuration_group', metavar='', help='ID of the configuration group.') @utils.service_type('database') def do_configuration_delete(cs, args): """Deletes a configuration group.""" cs.configurations.delete(args.configuration_group) @utils.arg('instance', metavar='', type=str, help='ID or name of the instance.') @utils.service_type('database') def do_configuration_detach(cs, args): """Detaches a configuration group from an instance.""" instance = _find_instance(cs, args.instance) cs.instances.modify(instance) @utils.arg('--datastore', metavar='', default=None, help='ID or name of the datastore to list configuration ' 'parameters for. Optional if the ID of the' ' datastore_version is provided.') @utils.arg('datastore_version', metavar='', help='Datastore version name or ID assigned to the ' 'configuration group.') @utils.arg('parameter', metavar='', help='Name of the configuration parameter.') @utils.service_type('database') def do_configuration_parameter_show(cs, args): """Shows details of a configuration parameter.""" if args.datastore: param = cs.configuration_parameters.get_parameter( args.datastore, args.datastore_version, args.parameter) elif utils.is_uuid_like(args.datastore_version): param = cs.configuration_parameters.get_parameter_by_version( args.datastore_version, args.parameter) _print_object(param) @utils.arg('--datastore', metavar='', default=None, help='ID or name of the datastore to list configuration ' 'parameters for. Optional if the ID of the' ' datastore_version is provided.') @utils.arg('datastore_version', metavar='', help='Datastore version name or ID assigned to the ' 'configuration group.') @utils.service_type('database') def do_configuration_parameter_list(cs, args): """Lists available parameters for a configuration group.""" if args.datastore: params = cs.configuration_parameters.parameters( args.datastore, args.datastore_version) elif utils.is_uuid_like(args.datastore_version): params = cs.configuration_parameters.parameters_by_version( args.datastore_version) else: raise exceptions.NoUniqueMatch('The datastore name or id is required' ' to retrieve the parameters for the' ' configuration group by name.') utils.print_list(params, ['name', 'type', 'min_size', 'max_size', 'restart_required']) @utils.arg('configuration_group', metavar='', help='ID of the configuration group.') @utils.arg('values', metavar='', help='Dictionary of the values to set.') @utils.service_type('database') def do_configuration_patch(cs, args): """Patches a configuration group.""" cs.configurations.edit(args.configuration_group, args.values) @utils.arg('configuration_group', metavar='', help='ID of the configuration group.') @utils.service_type('database') def do_configuration_instances(cs, args): """Lists all instances associated with a configuration group.""" params = cs.configurations.instances(args.configuration_group) utils.print_list(params, ['id', 'name']) @utils.service_type('database') def do_configuration_list(cs, args): """Lists all configuration groups.""" config_grps = cs.configurations.list() utils.print_list(config_grps, [ 'id', 'name', 'description', 'datastore_name', 'datastore_version_name']) @utils.arg('configuration_group', metavar='', help='ID of the configuration group.') @utils.service_type('database') def do_configuration_show(cs, args): """Shows details of a configuration group.""" config_grp = cs.configurations.get(args.configuration_group) config_grp._info['values'] = json.dumps(config_grp.values) del config_grp._info['datastore_version_id'] _print_object(config_grp) @utils.arg('configuration_group', metavar='', help='ID of the configuration group.') @utils.arg('values', metavar='', help='Dictionary of the values to set.') @utils.arg('--name', metavar='', default=None, help='Name of the configuration group.') @utils.arg('--description', metavar='', default=None, help='An optional description for the configuration group.') @utils.service_type('database') def do_configuration_update(cs, args): """Updates a configuration group.""" cs.configurations.update(args.configuration_group, args.values, args.name, args.description) @utils.arg('instance_id', metavar='', help='UUID for instance.') @utils.service_type('database') def do_metadata_list(cs, args): """Shows all metadata for instance .""" result = cs.metadata.list(args.instance_id) _print_object(result) @utils.arg('instance_id', metavar='', help='UUID for instance.') @utils.arg('key', metavar='', help='Key to display.') @utils.service_type('database') def do_metadata_show(cs, args): """Shows metadata entry for key and instance .""" result = cs.metadata.show(args.instance_id, args.key) _print_object(result) @utils.arg('instance_id', metavar='', help='UUID for instance.') @utils.arg('key', metavar='', help='Key to replace.') @utils.arg('value', metavar='', help='New value to assign to .') @utils.service_type('database') def do_metadata_edit(cs, args): """Replaces metadata value with a new one, this is non-destructive.""" cs.metadata.edit(args.instance_id, args.key, args.value) @utils.arg('instance_id', metavar='', help='UUID for instance.') @utils.arg('key', metavar='', help='Key to update.') @utils.arg('newkey', metavar='', help='New key.') @utils.arg('value', metavar='', help='Value to assign to .') @utils.service_type('database') def do_metadata_update(cs, args): """Updates metadata, this is destructive.""" cs.metadata.update(args.instance_id, args.key, args.newkey, args.value) @utils.arg('instance_id', metavar='', help='UUID for instance.') @utils.arg('key', metavar='', help='Key for assignment.') @utils.arg('value', metavar='', help='Value to assign to .') @utils.service_type('database') def do_metadata_create(cs, args): """Creates metadata in the database for instance .""" result = cs.metadata.create(args.instance_id, args.key, args.value) _print_object(result) @utils.arg('instance_id', metavar='', help='UUID for instance.') @utils.arg('key', metavar='', help='Metadata key to delete.') @utils.service_type('database') def do_metadata_delete(cs, args): """Deletes metadata for instance .""" cs.metadata.delete(args.instance_id, args.key) @utils.arg('--datastore', metavar='', help="Name or ID of datastore to list modules for. Use '%s' " "to list modules that apply to all datastores." % Module.ALL_KEYWORD) @utils.service_type('database') def do_module_list(cs, args): """Lists the modules available.""" datastore = None if args.datastore: if args.datastore.lower() == Module.ALL_KEYWORD: datastore = args.datastore.lower() else: datastore = _find_datastore(cs, args.datastore) module_list = cs.modules.list(datastore=datastore) field_list = ['id', 'name', 'type', 'datastore', 'datastore_version', 'auto_apply', 'tenant', 'visible'] is_admin = False if hasattr(cs.client, 'auth'): roles = cs.client.auth.auth_ref['user']['roles'] role_names = [role['name'] for role in roles] is_admin = 'admin' in role_names if not is_admin: field_list = field_list[:-2] utils.print_list( module_list, field_list, labels={'datastore_version': 'Version'}) @utils.arg('module', metavar='', help='ID or name of the module.') @utils.service_type('database') def do_module_show(cs, args): """Shows details of a module.""" module = _find_module(cs, args.module) _print_object(module) @utils.arg('name', metavar='', type=str, help='Name of the module.') @utils.arg('type', metavar='', type=str, help='Type of the module. The type must be supported by a ' 'corresponding module plugin on the datastore it is ' 'applied to.') @utils.arg('file', metavar='', type=argparse.FileType(mode='rb', bufsize=0), help='File containing data contents for the module.') @utils.arg('--description', metavar='', type=str, help='Description of the module.') @utils.arg('--datastore', metavar='', help='Name or ID of datastore this module can be applied to. ' 'If not specified, module can be applied to all datastores.') @utils.arg('--datastore_version', metavar='', help='Name or ID of datastore version this module can be applied ' 'to. If not specified, module can be applied to all versions.') @utils.arg('--auto_apply', action='store_true', default=False, help='Automatically apply this module when creating an instance ' 'or cluster.') @utils.arg('--all_tenants', action='store_true', default=False, help='Module is valid for all tenants (Admin only).') # This option is to suppress the module from module-list for non-admin @utils.arg('--hidden', action='store_true', default=False, help=argparse.SUPPRESS) @utils.arg('--live_update', action='store_true', default=False, help='Allow module to be updated even if it is already applied ' 'to a current instance or cluster. Automatically attempt to ' 'reapply this module if the contents change.') @utils.service_type('database') def do_module_create(cs, args): """Create a module.""" contents = args.file.read() if not contents: raise exceptions.ValidationError( "The file '%s' must contain some data" % args.file) module = cs.modules.create( args.name, args.type, contents, description=args.description, all_tenants=args.all_tenants, datastore=args.datastore, datastore_version=args.datastore_version, auto_apply=args.auto_apply, visible=not args.hidden, live_update=args.live_update) _print_object(module) @utils.arg('module', metavar='', type=str, help='Name or ID of the module.') @utils.arg('--name', metavar='', type=str, default=None, help='Name of the module.') @utils.arg('--type', metavar='', type=str, default=None, help='Type of the module. The type must be supported by a ' 'corresponding module plugin on the datastore it is ' 'applied to.') @utils.arg('--file', metavar='', type=argparse.FileType('rb', 0), default=None, help='File containing data contents for the module.') @utils.arg('--description', metavar='', type=str, default=None, help='Description of the module.') @utils.arg('--datastore', metavar='', help='Name or ID of datastore this module can be applied to. ' 'If not specified, module can be applied to all datastores.') @utils.arg('--all_datastores', dest='datastore', action='store_const', const=None, help='Module is valid for all datastores.') @utils.arg('--datastore_version', metavar='', help='Name or ID of datastore version this module can be applied ' 'to. If not specified, module can be applied to all versions.') @utils.arg('--all_datastore_versions', dest='datastore_version', action='store_const', const=None, help='Module is valid for all datastore version.') @utils.arg('--auto_apply', action='store_true', default=None, help='Automatically apply this module when creating an instance ' 'or cluster.') @utils.arg('--no_auto_apply', dest='auto_apply', action='store_false', default=None, help='Do not automatically apply this module when creating an ' 'instance or cluster.') @utils.arg('--all_tenants', action='store_true', default=None, help='Module is valid for all tenants (Admin only).') @utils.arg('--no_all_tenants', dest='all_tenants', action='store_false', default=None, help='Module is valid for current tenant only (Admin only).') # This option is to suppress the module from module-list for non-admin @utils.arg('--hidden', action='store_true', default=None, help=argparse.SUPPRESS) # This option is to allow the module to be seen from module-list for non-admin @utils.arg('--no_hidden', dest='hidden', action='store_false', default=None, help=argparse.SUPPRESS) @utils.arg('--live_update', action='store_true', default=None, help='Allow module to be updated or deleted even if it is already ' 'applied to a current instance or cluster. Automatically ' 'attempt to reapply this module if the contents change.') @utils.arg('--no_live_update', dest='live_update', action='store_false', default=None, help='Restricts a module from being updated or deleted if it is ' 'already applied to a current instance or cluster.') @utils.service_type('database') def do_module_update(cs, args): """Update a module.""" module = _find_module(cs, args.module) contents = args.file.read() if args.file else None visible = not args.hidden if args.hidden is not None else None datastore_args = {} if args.datastore: datastore_args['datastore'] = args.datastore if args.datastore_version: datastore_args['datastore_version'] = args.datastore_version updated_module = cs.modules.update( module, name=args.name, module_type=args.type, contents=contents, description=args.description, all_tenants=args.all_tenants, auto_apply=args.auto_apply, visible=visible, live_update=args.live_update, **datastore_args) _print_object(updated_module) @utils.arg('module', metavar='', help='ID or name of the module.') @utils.service_type('database') def do_module_delete(cs, args): """Delete a module.""" module = _find_module(cs, args.module) cs.modules.delete(module) @utils.arg('instance', metavar='', type=str, help='ID or name of the instance.') @utils.service_type('database') def do_module_list_instance(cs, args): """Lists the modules that have been applied to an instance.""" instance = _find_instance(cs, args.instance) module_list = cs.instances.modules(instance) utils.print_list( module_list, ['id', 'name', 'type', 'md5', 'created', 'updated']) @utils.arg('module', metavar='', type=str, help='ID or name of the module.') @utils.arg('--include_clustered', action="store_true", default=False, help="Include instances that are part of a cluster " "(default %(default)s).") @utils.arg('--limit', metavar='', default=None, help='Return up to N number of the most recent results.') @utils.arg('--marker', metavar='', type=str, default=None, help='Begin displaying the results for IDs greater than the ' 'specified marker. When used with --limit, set this to ' 'the last ID displayed in the previous run.') @utils.service_type('database') def do_module_instances(cs, args): """Lists the instances that have a particular module applied.""" module = _find_module(cs, args.module) wrapper = cs.modules.instances( module, limit=args.limit, marker=args.marker, include_clustered=args.include_clustered) instance_list = wrapper.items while not args.limit and wrapper.next: wrapper = cs.modules.instances(module, marker=wrapper.next) instance_list += wrapper.items _print_instances(instance_list) @utils.arg('cluster', metavar='', help='ID or name of the cluster.') @utils.service_type('database') def do_cluster_modules(cs, args): """Lists all modules for each instance of a cluster.""" cluster = _find_cluster(cs, args.cluster) instances = cluster._info['instances'] module_list = [] for instance in instances: new_list = cs.instances.modules(instance['id']) for item in new_list: item.instance_id = instance['id'] item.instance_name = instance['name'] module_list += new_list utils.print_list( module_list, ['instance_name', 'name', 'type', 'md5', 'created', 'updated'], labels={'name': 'Module Name', 'type': 'Module Type'}) @utils.arg('instance', metavar='', type=str, help='ID or name of the instance.') @utils.arg('modules', metavar='', type=str, nargs='+', default=[], help='ID or name of the module.') @utils.service_type('database') def do_module_apply(cs, args): """Apply modules to an instance.""" instance = _find_instance(cs, args.instance) modules = [] for module in args.modules: modules.append(_find_module(cs, module)) result_list = cs.instances.module_apply(instance, modules) utils.print_list( result_list, ['name', 'type', 'datastore', 'datastore_version', 'status', 'message'], labels={'datastore_version': 'Version'}) @utils.arg('instance', metavar='', type=str, help='ID or name of the instance.') @utils.arg('module', metavar='', type=str, help='ID or name of the module.') @utils.service_type('database') def do_module_remove(cs, args): """Remove a module from an instance.""" instance = _find_instance(cs, args.instance) module = _find_module(cs, args.module) cs.instances.module_remove(instance, module) @utils.arg('instance', metavar='', type=str, help='ID or name of the instance.') @utils.service_type('database') def do_module_query(cs, args): """Query the status of the modules on an instance.""" instance = _find_instance(cs, args.instance) result_list = cs.instances.module_query(instance) utils.print_list( result_list, ['name', 'type', 'datastore', 'datastore_version', 'status', 'message', 'created', 'updated'], labels={'datastore_version': 'Version'}) @utils.arg('instance', metavar='', type=str, help='ID or name of the instance.') @utils.arg('--directory', metavar='', type=str, help='Directory to write module content files in. It will ' 'be created if it does not exist. Defaults to the ' 'current directory.') @utils.arg('--prefix', metavar='', type=str, help='Prefix to prepend to generated filename for each module.') @utils.service_type('database') def do_module_retrieve(cs, args): """Retrieve module contents from an instance.""" instance = _find_instance(cs, args.instance) saved_modules = cs.instances.module_retrieve( instance, args.directory, args.prefix) for module_name, filename in saved_modules.items(): print("Module contents for '%s' written to '%s'" % (module_name, filename)) @utils.arg('instance', metavar='', help='Id or Name of the instance.') @utils.service_type('database') def do_log_list(cs, args): """Lists the log files available for instance.""" instance = _find_instance(cs, args.instance) log_list = cs.instances.log_list(instance) utils.print_list(log_list, ['name', 'type', 'status', 'published', 'pending', 'container', 'prefix']) @utils.arg('instance', metavar='', help='Id or Name of the instance.') @utils.arg('log_name', metavar='', help='Name of log to show.') @utils.service_type('database') def do_log_show(cs, args): """Instructs Trove guest to show details of log.""" try: instance = _find_instance(cs, args.instance) log_info = cs.instances.log_show(instance, args.log_name) _print_object(log_info) except exceptions.GuestLogNotFoundError: print(NO_LOG_FOUND_ERROR % (args.log_name, instance)) except Exception as ex: error_msg = ex.message.split('\n') print(error_msg[0]) @utils.arg('instance', metavar='', help='Id or Name of the instance.') @utils.arg('log_name', metavar='', help='Name of log to publish.') @utils.service_type('database') def do_log_enable(cs, args): """Instructs Trove guest to start collecting log details.""" try: instance = _find_instance(cs, args.instance) log_info = cs.instances.log_enable(instance, args.log_name) _print_object(log_info) except exceptions.GuestLogNotFoundError: print(NO_LOG_FOUND_ERROR % (args.log_name, instance)) except Exception as ex: error_msg = ex.message.split('\n') print(error_msg[0]) @utils.arg('instance', metavar='', help='Id or Name of the instance.') @utils.arg('log_name', metavar='', help='Name of log to publish.') @utils.arg('--discard', action='store_true', default=False, help='Discard published contents of specified log.') @utils.service_type('database') def do_log_disable(cs, args): """Instructs Trove guest to stop collecting log details.""" try: instance = _find_instance(cs, args.instance) log_info = cs.instances.log_disable(instance, args.log_name, discard=args.discard) _print_object(log_info) except exceptions.GuestLogNotFoundError: print(NO_LOG_FOUND_ERROR % (args.log_name, instance)) except Exception as ex: error_msg = ex.message.split('\n') print(error_msg[0]) @utils.arg('instance', metavar='', help='Id or Name of the instance.') @utils.arg('log_name', metavar='', help='Name of log to publish.') @utils.arg('--disable', action='store_true', default=False, help='Stop collection of specified log.') @utils.arg('--discard', action='store_true', default=False, help='Discard published contents of specified log.') @utils.service_type('database') def do_log_publish(cs, args): """Instructs Trove guest to publish latest log entries on instance.""" try: instance = _find_instance(cs, args.instance) log_info = cs.instances.log_publish( instance, args.log_name, disable=args.disable, discard=args.discard) _print_object(log_info) except exceptions.GuestLogNotFoundError: print(NO_LOG_FOUND_ERROR % (args.log_name, instance)) except Exception as ex: error_msg = ex.message.split('\n') print(error_msg[0]) @utils.arg('instance', metavar='', help='Id or Name of the instance.') @utils.arg('log_name', metavar='', help='Name of log to publish.') @utils.service_type('database') def do_log_discard(cs, args): """Instructs Trove guest to discard the container of the published log.""" try: instance = _find_instance(cs, args.instance) log_info = cs.instances.log_discard(instance, args.log_name) _print_object(log_info) except exceptions.GuestLogNotFoundError: print(NO_LOG_FOUND_ERROR % (args.log_name, instance)) except Exception as ex: error_msg = ex.message.split('\n') print(error_msg[0]) @utils.arg('instance', metavar='', help='Id or Name of the instance.') @utils.arg('log_name', metavar='', help='Name of log to publish.') @utils.arg('--publish', action='store_true', default=False, help='Publish latest entries from guest before display.') @utils.arg('--lines', metavar='', default=50, type=int, help='Publish latest entries from guest before display.') @utils.service_type('database') def do_log_tail(cs, args): """Display log entries for instance.""" try: instance = _find_instance(cs, args.instance) log_gen = cs.instances.log_generator(instance, args.log_name, args.publish, args.lines) for log_part in log_gen(): print(log_part, end="") except exceptions.GuestLogNotFoundError: print(NO_LOG_FOUND_ERROR % (args.log_name, instance)) except Exception as ex: error_msg = ex.message.split('\n') print(error_msg[0]) @utils.arg('instance', metavar='', help='Id or Name of the instance.') @utils.arg('log_name', metavar='', help='Name of log to publish.') @utils.arg('--publish', action='store_true', default=False, help='Publish latest entries from guest before display.') @utils.arg('--file', metavar='', default=None, help='Path of file to save log to for instance.') @utils.service_type('database') def do_log_save(cs, args): """Save log file for instance.""" try: instance = _find_instance(cs, args.instance) filename = cs.instances.log_save(instance, args.log_name, args.publish, args.file) print('Log "%s" written to %s' % (args.log_name, filename)) except exceptions.GuestLogNotFoundError: print(NO_LOG_FOUND_ERROR % (args.log_name, instance)) except Exception as ex: error_msg = ex.message.split('\n') print(error_msg[0]) # @utils.arg('datastore_version', # metavar='', # help='Datastore version name or UUID assigned to the ' # 'configuration group.') # @utils.arg('name', metavar='', # help='Name of the datastore configuration parameter.') # @utils.arg('restart_required', metavar='', # help='Flags the instance to require a restart if this ' # 'configuration parameter is new or changed.') # @utils.arg('data_type', metavar='', # help='Data type of the datastore configuration parameter.') # @utils.arg('--max_size', metavar='', # help='Maximum size of the datastore configuration parameter.') # @utils.arg('--min_size', metavar='', # help='Minimum size of the datastore configuration parameter.') # @utils.service_type('database') # def do_configuration_parameter_create(cs, args): # """Create datastore configuration parameter""" # cs.mgmt_config_params.create( # args.datastore_version, # args.name, # args.restart_required, # args.data_type, # args.max_size, # args.min_size, # ) # @utils.arg('datastore_version', # metavar='', # help='Datastore version name or UUID assigned to the ' # 'configuration group.') # @utils.arg('name', metavar='', # help='Name of the datastore configuration parameter.') # @utils.arg('restart_required', metavar='', # help='Sets the datastore configuration parameter if it ' # 'requires a restart or not.') # @utils.arg('data_type', metavar='', # help='Data type of the datastore configuration parameter.') # @utils.arg('--max_size', metavar='', # help='Maximum size of the datastore configuration parameter.') # @utils.arg('--min_size', metavar='', # help='Minimum size of the datastore configuration parameter.') # @utils.service_type('database') # def do_configuration_parameter_modify(cs, args): # """Modify datastore configuration parameter""" # cs.mgmt_config_params.modify( # args.datastore_version, # args.name, # args.restart_required, # args.data_type, # args.max_size, # args.min_size, # ) # @utils.arg('datastore_version', # metavar='', # help='Datastore version name or UUID assigned to the ' # 'configuration group.') # @utils.arg('name', metavar='', # help='UUID of the datastore configuration parameter.') # @utils.service_type('database') # def do_configuration_parameter_delete(cs, args): # """Modify datastore configuration parameter""" # cs.mgmt_config_params.delete( # args.datastore_version, # args.name, # )