# Copyright 2010 Jacob Kaplan-Moss # Copyright 2011 OpenStack LLC. # 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. import datetime import getpass import os import sys import time from novaclient import exceptions from novaclient import utils from novaclient.v1_1 import servers def _boot(cs, args, reservation_id=None, min_count=None, max_count=None): """Boot a new server.""" if min_count is None: min_count = 1 if max_count is None: max_count = min_count if min_count > max_count: raise exceptions.CommandError("min_instances should be <= " "max_instances") if not min_count or not max_count: raise exceptions.CommandError("min_instances nor max_instances should" "be 0") if not args.image and not args.block_device_mapping: raise exceptions.CommandError("you need to specify an Image ID " "or a block device mapping ") if not args.flavor: raise exceptions.CommandError("you need to specify a Flavor ID ") flavor = _find_flavor(cs, args.flavor) image = _find_image(cs, args.image) meta = dict(v.split('=', 1) for v in args.meta) files = {} for f in args.files: dst, src = f.split('=', 1) try: files[dst] = open(src) except IOError, e: raise exceptions.CommandError("Can't open '%s': %s" % (src, e)) # use the os-keypair extension key_name = None if args.key_name is not None: key_name = args.key_name if args.user_data: try: userdata = open(args.user_data) except IOError, e: raise exceptions.CommandError("Can't open '%s': %s" % \ (args.user_data, e)) else: userdata = None if args.availability_zone: availability_zone = args.availability_zone else: availability_zone = None if args.security_groups: security_groups = args.security_groups.split(',') else: security_groups = None block_device_mapping = {} for bdm in args.block_device_mapping: device_name, mapping = bdm.split('=', 1) block_device_mapping[device_name] = mapping nics = [] for nic_str in args.nics: nic_info = {"net-id": "", "v4-fixed-ip": ""} for kv_str in nic_str.split(","): k, v = kv_str.split("=", 1) nic_info[k] = v nics.append(nic_info) hints = {} if args.scheduler_hints: for hint in args.scheduler_hints: key, _sep, value = hint.partition('=') # NOTE(vish): multiple copies of the same hint will # result in a list of values if key in hints: if isinstance(hints[key], basestring): hints[key] = [hints[key]] hints[key] += [value] else: hints[key] = value boot_args = [args.name, image, flavor] if str(args.config_drive).lower() in ("true", "1"): config_drive = True elif str(args.config_drive).lower() in ("false", "0", "", "none"): config_drive = None else: config_drive = args.config_drive boot_kwargs = dict( meta=meta, files=files, key_name=key_name, reservation_id=reservation_id, min_count=min_count, max_count=max_count, userdata=userdata, availability_zone=availability_zone, security_groups=security_groups, block_device_mapping=block_device_mapping, nics=nics, scheduler_hints=hints, config_drive=config_drive) return boot_args, boot_kwargs @utils.arg('--flavor', default=None, metavar='', help="Flavor ID (see 'nova flavor-list').") @utils.arg('--image', default=None, metavar='', help="Image ID (see 'nova image-list'). ") @utils.arg('--meta', metavar="", action='append', default=[], help="Record arbitrary key/value metadata to /meta.js "\ "on the new server. Can be specified multiple times.") @utils.arg('--file', metavar="", action='append', dest='files', default=[], help="Store arbitrary files from locally to "\ "on the new server. You may store up to 5 files.") @utils.arg('--key_name', metavar='', help="Key name of keypair that should be created earlier with \ the command keypair-add") @utils.arg('name', metavar='', help='Name for the new server') @utils.arg('--user_data', default=None, metavar='', help="user data file to pass to be exposed by the metadata server.") @utils.arg('--availability_zone', default=None, metavar='', help="The availability zone for instance placement.") @utils.arg('--security_groups', default=None, metavar='', help="comma separated list of security group names.") @utils.arg('--block_device_mapping', metavar="", action='append', default=[], help="Block device mapping in the format " ":::.") @utils.arg('--hint', action='append', dest='scheduler_hints', default=[], metavar='', help="Send arbitrary key/value pairs to the scheduler for custom use.") @utils.arg('--nic', metavar="", action='append', dest='nics', default=[], help="Create a NIC on the server.\n" "Specify option multiple times to create multiple NICs.\n" "net-id: attach NIC to network with this UUID (optional)\n" "v4-fixed-ip: IPv4 fixed address for NIC (optional).") @utils.arg('--config-drive', metavar="", dest='config_drive', default=False, help="Enable config drive") @utils.arg('--poll', dest='poll', action="store_true", default=False, help='Blocks while instance builds so progress can be reported.') def do_boot(cs, args): """Boot a new server.""" boot_args, boot_kwargs = _boot(cs, args) extra_boot_kwargs = utils.get_resource_manager_extra_kwargs(do_boot, args) boot_kwargs.update(extra_boot_kwargs) server = cs.servers.create(*boot_args, **boot_kwargs) # Keep any information (like adminPass) returned by create info = server._info server = cs.servers.get(info['id']) info.update(server._info) flavor = info.get('flavor', {}) flavor_id = flavor.get('id', '') info['flavor'] = _find_flavor(cs, flavor_id).name image = info.get('image', {}) image_id = image.get('id', '') info['image'] = _find_image(cs, image_id).name info.pop('links', None) info.pop('addresses', None) utils.print_dict(info) if args.poll: _poll_for_status(cs.servers.get, info['id'], 'building', ['active']) def do_cloudpipe_list(cs, _args): """Print a list of all cloudpipe instances.""" cloudpipes = cs.cloudpipe.list() columns = ['Project Id', "Public IP", "Public Port", "Internal IP"] utils.print_list(cloudpipes, columns) @utils.arg('project', metavar='', help='Name of the project.') def do_cloudpipe_create(cs, args): """Create a cloudpipe instance for the given project""" cs.cloudpipe.create(args.project) 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" % locals() break else: print_progress(progress) time.sleep(poll_period) def _translate_flavor_keys(collection): convert = [('ram', 'memory_mb')] for item in collection: keys = item.__dict__.keys() for from_key, to_key in convert: if from_key in keys and to_key not in keys: setattr(item, to_key, item._info[from_key]) def _print_flavor_list(flavors): _translate_flavor_keys(flavors) utils.print_list(flavors, [ 'ID', 'Name', 'Memory_MB', 'Disk', 'Ephemeral', 'Swap', 'VCPUs', 'RXTX_Factor']) def do_flavor_list(cs, _args): """Print a list of available 'flavors' (sizes of servers).""" flavors = cs.flavors.list() for flavor in flavors: # int needed for numerical sort flavor.id = int(flavor.id) _print_flavor_list(flavors) @utils.arg('id', metavar='', help="Unique ID of the flavor to delete") def do_flavor_delete(cs, args): """Delete a specific flavor""" cs.flavors.delete(args.id) @utils.arg('flavor', metavar='', help="Name or ID of flavor") def do_flavor_show(cs, args): """Show details about the given flavor.""" flavor = _find_flavor(cs, args.flavor) _print_flavor(flavor) @utils.arg('name', metavar='', help="Name of the new flavor") @utils.arg('id', metavar='', help="Unique integer ID for the new flavor") @utils.arg('ram', metavar='', help="Memory size in MB") @utils.arg('disk', metavar='', help="Disk size in GB") @utils.arg('--ephemeral', metavar='', help="Ephemeral space size in GB (default 0)", default=0) @utils.arg('vcpus', metavar='', help="Number of vcpus") @utils.arg('--swap', metavar='', help="Swap space size in MB (default 0)", default=0) @utils.arg('--rxtx-factor', metavar='', help="RX/TX factor (default 1)", default=1) def do_flavor_create(cs, args): """Create a new flavor""" f = cs.flavors.create(args.name, args.ram, args.vcpus, args.disk, args.id, args.ephemeral, args.swap, args.rxtx_factor) _print_flavor_list([f]) def do_image_list(cs, _args): """Print a list of available images to boot from.""" image_list = cs.images.list() def parse_server_name(image): try: return image.server['id'] except (AttributeError, KeyError): return '' fmts = {'Server': parse_server_name} utils.print_list(image_list, ['ID', 'Name', 'Status', 'Server'], fmts) @utils.arg('image', metavar='', help="Name or ID of image") @utils.arg('action', metavar='', choices=['set', 'delete'], help="Actions: 'set' or 'delete'") @utils.arg('metadata', metavar='', nargs='+', action='append', default=[], help='Metadata to add/update or delete (only key is necessary on delete)') def do_image_meta(cs, args): """Set or Delete metadata on an image.""" image = _find_image(cs, args.image) metadata = _extract_metadata(args) if args.action == 'set': cs.images.set_meta(image, metadata) elif args.action == 'delete': cs.images.delete_meta(image, metadata.keys()) def _extract_metadata(args): metadata = {} for metadatum in args.metadata[0]: # Can only pass the key in on 'delete' # So this doesn't have to have '=' if metadatum.find('=') > -1: (key, value) = metadatum.split('=', 1) else: key = metadatum value = None metadata[key] = value return metadata def _print_image(image): info = image._info.copy() # ignore links, we don't need to present those info.pop('links') # try to replace a server entity to just an id server = info.pop('server', None) try: info['server'] = server['id'] except (KeyError, TypeError): pass # break up metadata and display each on its own row metadata = info.pop('metadata', {}) try: for key, value in metadata.items(): _key = 'metadata %s' % key info[_key] = value except AttributeError: pass utils.print_dict(info) def _print_flavor(flavor): info = flavor._info.copy() # ignore links, we don't need to present those info.pop('links') utils.print_dict(info) @utils.arg('image', metavar='', help="Name or ID of image") def do_image_show(cs, args): """Show details about the given image.""" image = _find_image(cs, args.image) _print_image(image) @utils.arg('image', metavar='', help='Name or ID of image.') def do_image_delete(cs, args): """ Delete an image. It should go without saying, but you can only delete images you created. """ image = _find_image(cs, args.image) image.delete() @utils.arg('--reservation_id', dest='reservation_id', metavar='', default=None, help='Only return instances that match reservation_id.') @utils.arg('--ip', dest='ip', metavar='', default=None, help='Search with regular expression match by IP address') @utils.arg('--ip6', dest='ip6', metavar='', default=None, help='Search with regular expression match by IPv6 address') @utils.arg('--name', dest='name', metavar='', default=None, help='Search with regular expression match by name') @utils.arg('--instance_name', dest='instance_name', metavar='', default=None, help='Search with regular expression match by instance name') @utils.arg('--status', dest='status', metavar='', default=None, help='Search by server status') @utils.arg('--flavor', dest='flavor', metavar='', type=int, default=None, help='Search by flavor ID') @utils.arg('--image', dest='image', metavar='', default=None, help='Search by image ID') @utils.arg('--host', dest='host', metavar='', default=None, help='Search instances by hostname to which they are assigned') @utils.arg('--all_tenants', dest='all_tenants', metavar='<0|1>', nargs='?', type=int, const=1, default=0, help='Display information from all tenants (Admin only).') def do_list(cs, args): """List active servers.""" all_tenants = int(os.environ.get("ALL_TENANTS", args.all_tenants)) search_opts = { 'all_tenants': all_tenants, 'reservation_id': args.reservation_id, 'ip': args.ip, 'ip6': args.ip6, 'name': args.name, 'image': args.image, 'flavor': args.flavor, 'status': args.status, 'host': args.host, 'instance_name': args.instance_name} id_col = 'ID' columns = [id_col, 'Name', 'Status', 'Networks'] formatters = {'Networks': utils._format_servers_list_networks} utils.print_list(cs.servers.list(search_opts=search_opts), columns, formatters) @utils.arg('--hard', dest='reboot_type', action='store_const', const=servers.REBOOT_HARD, default=servers.REBOOT_SOFT, help='Perform a hard reboot (instead of a soft one).') @utils.arg('server', metavar='', help='Name or ID of server.') @utils.arg('--poll', dest='poll', action="store_true", default=False, help='Blocks while instance is rebooting.') def do_reboot(cs, args): """Reboot a server.""" server = _find_server(cs, args.server) server.reboot(args.reboot_type) if args.poll: _poll_for_status(cs.servers.get, server.id, 'rebooting', ['active'], show_progress=False) @utils.arg('server', metavar='', help='Name or ID of server.') @utils.arg('image', metavar='', help="Name or ID of new image.") @utils.arg('--rebuild_password', dest='rebuild_password', metavar='', default=False, help="Set the provided password on the rebuild instance.") @utils.arg('--poll', dest='poll', action="store_true", default=False, help='Blocks while instance rebuilds so progress can be reported.') def do_rebuild(cs, args): """Shutdown, re-image, and re-boot a server.""" server = _find_server(cs, args.server) image = _find_image(cs, args.image) if args.rebuild_password is not False: _password = args.rebuild_password else: _password = None kwargs = utils.get_resource_manager_extra_kwargs(do_rebuild, args) s = server.rebuild(image, _password, **kwargs) _print_server(cs, s) if args.poll: _poll_for_status(cs.servers.get, server.id, 'rebuilding', ['active']) @utils.arg('server', metavar='', help='Name (old name) or ID of server.') @utils.arg('name', metavar='', help='New name for the server.') def do_rename(cs, args): """Rename a server.""" _find_server(cs, args.server).update(name=args.name) @utils.arg('server', metavar='', help='Name or ID of server.') @utils.arg('flavor', metavar='', help="Name or ID of new flavor.") @utils.arg('--poll', dest='poll', action="store_true", default=False, help='Blocks while instance resizes so progress can be reported.') def do_resize(cs, args): """Resize a server.""" server = _find_server(cs, args.server) flavor = _find_flavor(cs, args.flavor) kwargs = utils.get_resource_manager_extra_kwargs(do_resize, args) server.resize(flavor, **kwargs) if args.poll: _poll_for_status(cs.servers.get, server.id, 'resizing', ['active', 'verify_resize']) @utils.arg('server', metavar='', help='Name or ID of server.') def do_resize_confirm(cs, args): """Confirm a previous resize.""" _find_server(cs, args.server).confirm_resize() @utils.arg('server', metavar='', help='Name or ID of server.') def do_resize_revert(cs, args): """Revert a previous resize (and return to the previous VM).""" _find_server(cs, args.server).revert_resize() @utils.arg('server', metavar='', help='Name or ID of server.') @utils.arg('--poll', dest='poll', action="store_true", default=False, help='Blocks while instance migrates so progress can be reported.') def do_migrate(cs, args): """Migrate a server.""" server = _find_server(cs, args.server) server.migrate() if args.poll: _poll_for_status(cs.servers.get, server.id, 'migrating', ['active', 'verify_resize']) @utils.arg('server', metavar='', help='Name or ID of server.') def do_pause(cs, args): """Pause a server.""" _find_server(cs, args.server).pause() @utils.arg('server', metavar='', help='Name or ID of server.') def do_unpause(cs, args): """Unpause a server.""" _find_server(cs, args.server).unpause() @utils.arg('server', metavar='', help='Name or ID of server.') def do_stop(cs, args): """Stop a server.""" _find_server(cs, args.server).stop() @utils.arg('server', metavar='', help='Name or ID of server.') def do_start(cs, args): """Start a server.""" _find_server(cs, args.server).start() @utils.arg('server', metavar='', help='Name or ID of server.') def do_lock(cs, args): """Lock a server.""" _find_server(cs, args.server).lock() @utils.arg('server', metavar='', help='Name or ID of server.') def do_unlock(cs, args): """Unlock a server.""" _find_server(cs, args.server).unlock() @utils.arg('server', metavar='', help='Name or ID of server.') def do_suspend(cs, args): """Suspend a server.""" _find_server(cs, args.server).suspend() @utils.arg('server', metavar='', help='Name or ID of server.') def do_resume(cs, args): """Resume a server.""" _find_server(cs, args.server).resume() @utils.arg('server', metavar='', help='Name or ID of server.') def do_rescue(cs, args): """Rescue a server.""" utils.print_dict(_find_server(cs, args.server).rescue()[1]) @utils.arg('server', metavar='', help='Name or ID of server.') def do_unrescue(cs, args): """Unrescue a server.""" _find_server(cs, args.server).unrescue() @utils.arg('server', metavar='', help='Name or ID of server.') def do_diagnostics(cs, args): """Retrieve server diagnostics.""" server = _find_server(cs, args.server) utils.print_dict(cs.servers.diagnostics(server)[1]) @utils.arg('server', metavar='', help='Name or ID of server.') def do_actions(cs, args): """Retrieve server actions.""" server = _find_server(cs, args.server) utils.print_list( cs.servers.actions(server), ["Created_At", "Action", "Error"]) @utils.arg('server', metavar='', help='Name or ID of server.') def do_root_password(cs, args): """ Change the root password for a server. """ server = _find_server(cs, args.server) p1 = getpass.getpass('New password: ') p2 = getpass.getpass('Again: ') if p1 != p2: raise exceptions.CommandError("Passwords do not match.") server.change_password(p1) @utils.arg('server', metavar='', help='Name or ID of server.') @utils.arg('name', metavar='', help='Name of snapshot.') @utils.arg('--poll', dest='poll', action="store_true", default=False, help='Blocks while instance snapshots so progress can be reported.') def do_image_create(cs, args): """Create a new image by taking a snapshot of a running server.""" server = _find_server(cs, args.server) image_uuid = cs.servers.create_image(server, args.name) if args.poll: _poll_for_status(cs.images.get, image_uuid, 'snapshotting', ['active']) @utils.arg('server', metavar='', help="Name or ID of server") @utils.arg('action', metavar='', choices=['set', 'delete'], help="Actions: 'set' or 'delete'") @utils.arg('metadata', metavar='', nargs='+', action='append', default=[], help='Metadata to set or delete (only key is necessary on delete)') def do_meta(cs, args): """Set or Delete metadata on a server.""" server = _find_server(cs, args.server) metadata = _extract_metadata(args) if args.action == 'set': cs.servers.set_meta(server, metadata) elif args.action == 'delete': cs.servers.delete_meta(server, metadata.keys()) def _print_server(cs, server): # By default when searching via name we will do a # findall(name=blah) and due a REST /details which is not the same # as a .get() and doesn't get the information about flavors and # images. This fix it as we redo the call with the id which does a # .get() to get all informations. if not 'flavor' in server._info: server = _find_server(cs, server.id) networks = server.networks info = server._info.copy() for network_label, address_list in networks.items(): info['%s network' % network_label] = ', '.join(address_list) flavor = info.get('flavor', {}) flavor_id = flavor.get('id', '') info['flavor'] = '%s (%s)' % (_find_flavor(cs, flavor_id).name, flavor_id) image = info.get('image', {}) image_id = image.get('id', '') info['image'] = '%s (%s)' % (_find_image(cs, image_id).name, image_id) info.pop('links', None) info.pop('addresses', None) utils.print_dict(info) @utils.arg('server', metavar='', help='Name or ID of server.') def do_show(cs, args): """Show details about the given server.""" s = _find_server(cs, args.server) _print_server(cs, s) @utils.arg('server', metavar='', help='Name or ID of server.') def do_delete(cs, args): """Immediately shut down and delete a server.""" _find_server(cs, args.server).delete() def _find_server(cs, server): """Get a server by name or ID.""" return utils.find_resource(cs.servers, server) def _find_image(cs, image): """Get an image by name or ID.""" return utils.find_resource(cs.images, image) def _find_flavor(cs, flavor): """Get a flavor by name, ID, or RAM size.""" try: return utils.find_resource(cs.flavors, flavor) except exceptions.NotFound: return cs.flavors.find(ram=flavor) @utils.arg('server', metavar='', help='Name or ID of server.') @utils.arg('network_id', metavar='', help='Network ID.') def do_add_fixed_ip(cs, args): """Add new IP address to network.""" server = _find_server(cs, args.server) server.add_fixed_ip(args.network_id) @utils.arg('server', metavar='', help='Name or ID of server.') @utils.arg('address', metavar='
', help='IP Address.') def do_remove_fixed_ip(cs, args): """Remove an IP address from a server.""" server = _find_server(cs, args.server) server.remove_fixed_ip(args.address) def _find_volume(cs, volume): """Get a volume by ID.""" return utils.find_resource(cs.volumes, volume) def _find_volume_snapshot(cs, snapshot): """Get a volume snapshot by ID.""" return utils.find_resource(cs.volume_snapshots, snapshot) def _print_volume(volume): utils.print_dict(volume._info) def _print_volume_snapshot(snapshot): utils.print_dict(snapshot._info) def _translate_volume_keys(collection): convert = [('displayName', 'display_name'), ('volumeType', 'volume_type')] for item in collection: keys = item.__dict__.keys() for from_key, to_key in convert: if from_key in keys and to_key not in keys: setattr(item, to_key, item._info[from_key]) def _translate_volume_snapshot_keys(collection): convert = [('displayName', 'display_name'), ('volumeId', 'volume_id')] for item in collection: keys = item.__dict__.keys() for from_key, to_key in convert: if from_key in keys and to_key not in keys: setattr(item, to_key, item._info[from_key]) @utils.service_type('volume') def do_volume_list(cs, _args): """List all the volumes.""" volumes = cs.volumes.list() _translate_volume_keys(volumes) # Create a list of servers to which the volume is attached for vol in volumes: servers = [s.get('server_id') for s in vol.attachments] setattr(vol, 'attached_to', ','.join(map(str, servers))) utils.print_list(volumes, ['ID', 'Status', 'Display Name', 'Size', 'Volume Type', 'Attached to']) @utils.arg('volume', metavar='', help='ID of the volume.') @utils.service_type('volume') def do_volume_show(cs, args): """Show details about a volume.""" volume = _find_volume(cs, args.volume) _print_volume(volume) @utils.arg('size', metavar='', type=int, help='Size of volume in GB') @utils.arg('--snapshot_id', metavar='', help='Optional snapshot id to create the volume from. (Default=None)', default=None) @utils.arg('--display_name', metavar='', help='Optional volume name. (Default=None)', default=None) @utils.arg('--display_description', metavar='', help='Optional volume description. (Default=None)', default=None) @utils.arg('--volume_type', metavar='', help='Optional volume type. (Default=None)', default=None) @utils.service_type('volume') def do_volume_create(cs, args): """Add a new volume.""" cs.volumes.create(args.size, args.snapshot_id, args.display_name, args.display_description, args.volume_type) @utils.arg('volume', metavar='', help='ID of the volume to delete.') @utils.service_type('volume') def do_volume_delete(cs, args): """Remove a volume.""" volume = _find_volume(cs, args.volume) volume.delete() @utils.arg('server', metavar='', help='Name or ID of server.') @utils.arg('volume', metavar='', help='ID of the volume to attach.') @utils.arg('device', metavar='', help='Name of the device e.g. /dev/vdb.') def do_volume_attach(cs, args): """Attach a volume to a server.""" cs.volumes.create_server_volume(_find_server(cs, args.server).id, args.volume, args.device) @utils.arg('server', metavar='', help='Name or ID of server.') @utils.arg('attachment_id', metavar='', help='Attachment ID of the volume.') def do_volume_detach(cs, args): """Detach a volume from a server.""" cs.volumes.delete_server_volume(_find_server(cs, args.server).id, args.attachment_id) @utils.service_type('volume') def do_volume_snapshot_list(cs, _args): """List all the snapshots.""" snapshots = cs.volume_snapshots.list() _translate_volume_snapshot_keys(snapshots) utils.print_list(snapshots, ['ID', 'Volume ID', 'Status', 'Display Name', 'Size']) @utils.arg('snapshot', metavar='', help='ID of the snapshot.') @utils.service_type('volume') def do_volume_snapshot_show(cs, args): """Show details about a snapshot.""" snapshot = _find_volume_snapshot(cs, args.snapshot) _print_volume_snapshot(snapshot) @utils.arg('volume_id', metavar='', help='ID of the volume to snapshot') @utils.arg('--force', metavar='', help='Optional flag to indicate whether to snapshot a volume even if its ' 'attached to an instance. (Default=False)', default=False) @utils.arg('--display_name', metavar='', help='Optional snapshot name. (Default=None)', default=None) @utils.arg('--display_description', metavar='', help='Optional snapshot description. (Default=None)', default=None) @utils.service_type('volume') def do_volume_snapshot_create(cs, args): """Add a new snapshot.""" cs.volume_snapshots.create(args.volume_id, args.force, args.display_name, args.display_description) @utils.arg('snapshot_id', metavar='', help='ID of the snapshot to delete.') @utils.service_type('volume') def do_volume_snapshot_delete(cs, args): """Remove a snapshot.""" snapshot = _find_volume_snapshot(cs, args.snapshot_id) snapshot.delete() def _print_volume_type_list(vtypes): utils.print_list(vtypes, ['ID', 'Name']) @utils.service_type('volume') def do_volume_type_list(cs, args): """Print a list of available 'volume types'.""" vtypes = cs.volume_types.list() _print_volume_type_list(vtypes) @utils.arg('name', metavar='', help="Name of the new flavor") @utils.service_type('volume') def do_volume_type_create(cs, args): """Create a new volume type.""" vtype = cs.volume_types.create(args.name) _print_volume_type_list([vtype]) @utils.arg('id', metavar='', help="Unique ID of the volume type to delete") @utils.service_type('volume') def do_volume_type_delete(cs, args): """Delete a specific flavor""" cs.volume_types.delete(args.id) @utils.arg('server', metavar='', help='Name or ID of server.') @utils.arg('console_type', metavar='', help='Type of vnc console ("novnc" or "xvpvnc").') def do_get_vnc_console(cs, args): """Get a vnc console to a server.""" server = _find_server(cs, args.server) data = server.get_vnc_console(args.console_type) class VNCConsole: def __init__(self, console_dict): self.type = console_dict['type'] self.url = console_dict['url'] utils.print_list([VNCConsole(data['console'])], ['Type', 'Url']) def _print_floating_ip_list(floating_ips): utils.print_list(floating_ips, ['Ip', 'Instance Id', 'Fixed Ip', 'Pool']) @utils.arg('server', metavar='', help='Name or ID of server.') @utils.arg('--length', metavar='', default=None, help='Length in lines to tail.') def do_console_log(cs, args): """Get console log output of a server.""" server = _find_server(cs, args.server) data = server.get_console_output(length=args.length) print data @utils.arg('server', metavar='', help='Name or ID of server.') @utils.arg('address', metavar='
', help='IP Address.') def do_add_floating_ip(cs, args): """Add a floating IP address to a server.""" server = _find_server(cs, args.server) server.add_floating_ip(args.address) @utils.arg('server', metavar='', help='Name or ID of server.') @utils.arg('address', metavar='
', help='IP Address.') def do_remove_floating_ip(cs, args): """Remove a floating IP address from a server.""" server = _find_server(cs, args.server) server.remove_floating_ip(args.address) @utils.arg('server', metavar='', help='Name or ID of server.') @utils.arg('secgroup', metavar='', help='Name of Security Group.') def do_add_secgroup(cs, args): """Add a Security Group to a server.""" server = _find_server(cs, args.server) server.add_security_group(args.secgroup) @utils.arg('server', metavar='', help='Name or ID of server.') @utils.arg('secgroup', metavar='', help='Name of Security Group.') def do_remove_secgroup(cs, args): """Remove a Security Group from a server.""" server = _find_server(cs, args.server) server.remove_security_group(args.secgroup) @utils.arg('pool', metavar='', help='Name of Floating IP Pool. (Optional)', nargs='?', default=None) def do_floating_ip_create(cs, args): """Allocate a floating IP for the current tenant.""" _print_floating_ip_list([cs.floating_ips.create(pool=args.pool)]) @utils.arg('address', metavar='
', help='IP of Floating Ip.') def do_floating_ip_delete(cs, args): """De-allocate a floating IP.""" floating_ips = cs.floating_ips.list() for floating_ip in floating_ips: if floating_ip.ip == args.address: return cs.floating_ips.delete(floating_ip.id) raise exceptions.CommandError("Floating ip %s not found.", args.address) def do_floating_ip_list(cs, _args): """List floating ips for this tenant.""" _print_floating_ip_list(cs.floating_ips.list()) def do_floating_ip_pool_list(cs, _args): """List all floating ip pools.""" utils.print_list(cs.floating_ip_pools.list(), ['name']) def _print_dns_list(dns_entries): utils.print_list(dns_entries, ['ip', 'name', 'domain']) def _print_domain_list(domain_entries): utils.print_list(domain_entries, ['domain', 'scope', 'project', 'availability_zone']) def do_dns_domains(cs, args): """Print a list of available dns domains.""" domains = cs.dns_domains.domains() _print_domain_list(domains) @utils.arg('domain', metavar='', help='DNS domain') @utils.arg('--ip', metavar='', help='ip address', default=None) @utils.arg('--name', metavar='', help='DNS name', default=None) def do_dns_list(cs, args): """List current DNS entries for domain and ip or domain and name.""" if not (args.ip or args.name): raise exceptions.CommandError( "You must specify either --ip or --name") if args.name: entry = cs.dns_entries.get(args.domain, args.name) _print_dns_list([entry]) else: entries = cs.dns_entries.get_for_ip(args.domain, ip=args.ip) _print_dns_list(entries) @utils.arg('ip', metavar='', help='ip address') @utils.arg('name', metavar='', help='DNS name') @utils.arg('domain', metavar='', help='DNS domain') @utils.arg('--type', metavar='', help='dns type (e.g. "A")', default='A') def do_dns_create(cs, args): """Create a DNS entry for domain, name and ip.""" cs.dns_entries.create(args.domain, args.name, args.ip, args.type) @utils.arg('domain', metavar='', help='DNS domain') @utils.arg('name', metavar='', help='DNS name') def do_dns_delete(cs, args): """Delete the specified DNS entry.""" cs.dns_entries.delete(args.domain, args.name) @utils.arg('domain', metavar='', help='DNS domain') def do_dns_delete_domain(cs, args): """Delete the specified DNS domain.""" cs.dns_domains.delete(args.domain) @utils.arg('domain', metavar='', help='DNS domain') @utils.arg('--availability_zone', metavar='', help='Limit access to this domain to instances ' 'in the specified availability zone.', default=None) def do_dns_create_private_domain(cs, args): """Create the specified DNS domain.""" cs.dns_domains.create_private(args.domain, args.availability_zone) @utils.arg('domain', metavar='', help='DNS domain') @utils.arg('--project', metavar='', help='Limit access to this domain to users ' 'of the specified project.', default=None) def do_dns_create_public_domain(cs, args): """Create the specified DNS domain.""" cs.dns_domains.create_public(args.domain, args.project) def _print_secgroup_rules(rules): class FormattedRule: def __init__(self, obj): items = (obj if isinstance(obj, dict) else obj._info).items() for k, v in items: if k == 'ip_range': v = v.get('cidr') elif k == 'group': k = 'source_group' v = v.get('name') if v is None: v = '' setattr(self, k, v) rules = [FormattedRule(rule) for rule in rules] utils.print_list(rules, ['IP Protocol', 'From Port', 'To Port', 'IP Range', 'Source Group']) def _print_secgroups(secgroups): utils.print_list(secgroups, ['Name', 'Description']) def _get_secgroup(cs, secgroup): for s in cs.security_groups.list(): if secgroup == s.name: return s raise exceptions.CommandError("Secgroup %s not found" % secgroup) @utils.arg('secgroup', metavar='', help='ID of security group.') @utils.arg('ip_proto', metavar='', help='ip_proto (icmp, tcp, udp).') @utils.arg('from_port', metavar='', help='Port at start of range.') @utils.arg('to_port', metavar='', help='Port at end of range.') @utils.arg('cidr', metavar='', help='CIDR for address range.') def do_secgroup_add_rule(cs, args): """Add a rule to a security group.""" secgroup = _get_secgroup(cs, args.secgroup) rule = cs.security_group_rules.create(secgroup.id, args.ip_proto, args.from_port, args.to_port, args.cidr) _print_secgroup_rules([rule]) @utils.arg('secgroup', metavar='', help='ID of security group.') @utils.arg('ip_proto', metavar='', help='ip_proto (icmp, tcp, udp).') @utils.arg('from_port', metavar='', help='Port at start of range.') @utils.arg('to_port', metavar='', help='Port at end of range.') @utils.arg('cidr', metavar='', help='CIDR for address range.') def do_secgroup_delete_rule(cs, args): """Delete a rule from a security group.""" secgroup = _get_secgroup(cs, args.secgroup) for rule in secgroup.rules: if (rule['ip_protocol'] == args.ip_proto and rule['from_port'] == int(args.from_port) and rule['to_port'] == int(args.to_port) and rule['ip_range']['cidr'] == args.cidr): return cs.security_group_rules.delete(rule['id']) raise exceptions.CommandError("Rule not found") @utils.arg('name', metavar='', help='Name of security group.') @utils.arg('description', metavar='', help='Description of security group.') def do_secgroup_create(cs, args): """Create a security group.""" _print_secgroups([cs.security_groups.create(args.name, args.description)]) @utils.arg('secgroup', metavar='', help='Name of security group.') def do_secgroup_delete(cs, args): """Delete a security group.""" cs.security_groups.delete(_get_secgroup(cs, args.secgroup)) def do_secgroup_list(cs, args): """List security groups for the current tenant.""" _print_secgroups(cs.security_groups.list()) @utils.arg('secgroup', metavar='', help='Name of security group.') def do_secgroup_list_rules(cs, args): """List rules for a security group.""" secgroup = _get_secgroup(cs, args.secgroup) _print_secgroup_rules(secgroup.rules) @utils.arg('secgroup', metavar='', help='ID of security group.') @utils.arg('source_group', metavar='', help='ID of source group.') @utils.arg('--ip_proto', metavar='', help='ip_proto (icmp, tcp, udp).') @utils.arg('--from_port', metavar='', help='Port at start of range.') @utils.arg('--to_port', metavar='', help='Port at end of range.') def do_secgroup_add_group_rule(cs, args): """Add a source group rule to a security group.""" secgroup = _get_secgroup(cs, args.secgroup) source_group = _get_secgroup(cs, args.source_group) params = {} params['group_id'] = source_group.id if args.ip_proto or args.from_port or args.to_port: if not (args.ip_proto and args.from_port and args.to_port): raise exceptions.CommandError("ip_proto, from_port, and to_port" " must be specified together") params['ip_protocol'] = args.ip_proto params['from_port'] = args.from_port params['to_port'] = args.to_port rule = cs.security_group_rules.create(secgroup.id, **params) _print_secgroup_rules([rule]) @utils.arg('secgroup', metavar='', help='ID of security group.') @utils.arg('source_group', metavar='', help='ID of source group.') @utils.arg('--ip_proto', metavar='', help='ip_proto (icmp, tcp, udp).') @utils.arg('--from_port', metavar='', help='Port at start of range.') @utils.arg('--to_port', metavar='', help='Port at end of range.') def do_secgroup_delete_group_rule(cs, args): """Delete a source group rule from a security group.""" secgroup = _get_secgroup(cs, args.secgroup) source_group = _get_secgroup(cs, args.source_group) params = {} params['group_name'] = source_group.name if args.ip_proto or args.from_port or args.to_port: if not (args.ip_proto and args.from_port and args.to_port): raise exceptions.CommandError("ip_proto, from_port, and to_port" " must be specified together") params['ip_protocol'] = args.ip_proto params['from_port'] = int(args.from_port) params['to_port'] = int(args.to_port) for rule in secgroup.rules: if (rule.get('ip_protocol') == params.get('ip_protocol') and rule.get('from_port') == params.get('from_port') and rule.get('to_port') == params.get('to_port') and rule.get('group', {}).get('name') == \ params.get('group_name')): return cs.security_group_rules.delete(rule['id']) raise exceptions.CommandError("Rule not found") @utils.arg('name', metavar='', help='Name of key.') @utils.arg('--pub_key', metavar='', help='Path to a public ssh key.', default=None) def do_keypair_add(cs, args): """Create a new key pair for use with instances""" name = args.name pub_key = args.pub_key if pub_key: try: with open(pub_key) as f: pub_key = f.read() except IOError, e: raise exceptions.CommandError("Can't open or read '%s': %s" % \ (pub_key, e)) keypair = cs.keypairs.create(name, pub_key) if not pub_key: private_key = keypair.private_key print private_key @utils.arg('name', metavar='', help='Keypair name to delete.') def do_keypair_delete(cs, args): """Delete keypair by its id""" name = args.name cs.keypairs.delete(name) def do_keypair_list(cs, args): """Print a list of keypairs for a user""" keypairs = cs.keypairs.list() columns = ['Name', 'Fingerprint'] utils.print_list(keypairs, columns) def do_absolute_limits(cs, args): """Print a list of absolute limits for a user""" limits = cs.limits.get().absolute columns = ['Name', 'Value'] utils.print_list(limits, columns) def do_rate_limits(cs, args): """Print a list of rate limits for a user""" limits = cs.limits.get().rate columns = ['Verb', 'URI', 'Value', 'Remain', 'Unit', 'Next_Available'] utils.print_list(limits, columns) @utils.arg('--start', metavar='', help='Usage range start date ex 2012-01-20 (default: 4 weeks ago)', default=None) @utils.arg('--end', metavar='', help='Usage range end date, ex 2012-01-20 (default: tomorrow) ', default=None) def do_usage_list(cs, args): """List usage data for all tenants""" dateformat = "%Y-%m-%d" rows = ["Tenant ID", "Instances", "RAM MB-Hours", "CPU Hours", "Disk GB-Hours"] if args.start: start = datetime.datetime.strptime(args.start, dateformat) else: start = (datetime.datetime.today() - datetime.timedelta(weeks=4)) if args.end: end = datetime.datetime.strptime(args.end, dateformat) else: end = (datetime.datetime.today() + datetime.timedelta(days=1)) def simplify_usage(u): simplerows = map(lambda x: x.lower().replace(" ", "_"), rows) setattr(u, simplerows[0], u.tenant_id) setattr(u, simplerows[1], "%d" % len(u.server_usages)) setattr(u, simplerows[2], "%.2f" % u.total_memory_mb_usage) setattr(u, simplerows[3], "%.2f" % u.total_vcpus_usage) setattr(u, simplerows[4], "%.2f" % u.total_local_gb_usage) usage_list = cs.usage.list(start, end, detailed=True) print "Usage from %s to %s:" % (start.strftime(dateformat), end.strftime(dateformat)) for usage in usage_list: simplify_usage(usage) utils.print_list(usage_list, rows) @utils.arg('pk_filename', metavar='', nargs='?', default='pk.pem', help='Filename to write the private key to.') @utils.arg('cert_filename', metavar='', nargs='?', default='cert.pem', help='Filename to write the x509 cert.') def do_x509_create_cert(cs, args): """Create x509 cert for a user in tenant""" if os.path.exists(args.pk_filename): raise exceptions.CommandError("Unable to write privatekey - %s exists." % args.pk_filename) if os.path.exists(args.cert_filename): raise exceptions.CommandError("Unable to write x509 cert - %s exists." % args.cert_filename) certs = cs.certs.create() with open(args.pk_filename, 'w') as private_key: private_key.write(certs.private_key) print "Wrote private key to %s" % args.pk_filename with open(args.cert_filename, 'w') as cert: cert.write(certs.data) print "Wrote x509 certificate to %s" % args.cert_filename @utils.arg('filename', metavar='', nargs='?', default='cacert.pem', help='Filename to write the x509 root cert.') def do_x509_get_root_cert(cs, args): """Fetches the x509 root cert.""" if os.path.exists(args.filename): raise exceptions.CommandError("Unable to write x509 root cert - \ %s exists." % args.filename) with open(args.filename, 'w') as cert: cacert = cs.certs.get() cert.write(cacert.data) print "Wrote x509 root cert to %s" % args.filename def do_aggregate_list(cs, args): """Print a list of all aggregates.""" aggregates = cs.aggregates.list() columns = ['Id', 'Name', 'Availability Zone'] utils.print_list(aggregates, columns) @utils.arg('name', metavar='', help='Name of aggregate.') @utils.arg('availability_zone', metavar='', help='The availability zone of the aggregate.') def do_aggregate_create(cs, args): """Create a new aggregate with the specified details.""" aggregate = cs.aggregates.create(args.name, args.availability_zone) _print_aggregate_details(aggregate) @utils.arg('id', metavar='', help='Aggregate id to delete.') def do_aggregate_delete(cs, args): """Delete the aggregate by its id.""" cs.aggregates.delete(args.id) print "Aggregate %s has been successfully deleted." % args.id @utils.arg('id', metavar='', help='Aggregate id to update.') @utils.arg('name', metavar='', help='Name of aggregate.') @utils.arg('availability_zone', metavar='', help='The availability zone of the aggregate.', nargs='?') def do_aggregate_update(cs, args): """Update the aggregate's name and optionally availability zone.""" updates = {"name": args.name} if args.availability_zone: updates["availability_zone"] = args.availability_zone aggregate = cs.aggregates.update(args.id, updates) print "Aggregate %s has been successfully updated." % args.id _print_aggregate_details(aggregate) @utils.arg('id', metavar='', help='Aggregate id to update.') @utils.arg('metadata', metavar='', nargs='+', action='append', default=[], help='Metadata to add/update to aggregate') def do_aggregate_set_metadata(cs, args): """Update the metadata associated with the aggregate.""" metadata = _extract_metadata(args) aggregate = cs.aggregates.set_metadata(args.id, metadata) print "Aggregate %s has been successfully updated." % args.id _print_aggregate_details(aggregate) @utils.arg('id', metavar='', help='Host aggregate id to delete.') @utils.arg('host', metavar='', help='The host to add to the aggregate.') def do_aggregate_add_host(cs, args): """Add the host to the specified aggregate.""" aggregate = cs.aggregates.add_host(args.id, args.host) print "Aggregate %s has been successfully updated." % args.id _print_aggregate_details(aggregate) @utils.arg('id', metavar='', help='Host aggregate id to delete.') @utils.arg('host', metavar='', help='The host to add to the aggregate.') def do_aggregate_remove_host(cs, args): """Remove the specified host from the specified aggregate.""" aggregate = cs.aggregates.remove_host(args.id, args.host) print "Aggregate %s has been successfully updated." % args.id _print_aggregate_details(aggregate) @utils.arg('id', metavar='', help='Host aggregate id to delete.') def do_aggregate_details(cs, args): """Show details of the specified aggregate.""" _print_aggregate_details(cs.aggregates.get_details(args.id)) def _print_aggregate_details(aggregate): columns = ['Id', 'Name', 'Availability Zone', 'Hosts', 'Metadata'] utils.print_list([aggregate], columns) @utils.arg('server', metavar='', help='Name or ID of server.') @utils.arg('host', metavar='', help='destination host name.') @utils.arg('--block_migrate', action='store_true', dest='block_migrate', default=False, help='True in case of block_migration.\ (Default=False:live_migration)') @utils.arg('--disk_over_commit', action='store_true', dest='disk_over_commit', default=False, help='Allow overcommit.(Default=Flase)') def do_live_migration(cs, args): """Migrates a running instance to a new machine.""" _find_server(cs, args.server).live_migrate(args.host, args.block_migrate, args.disk_over_commit) @utils.arg('server', metavar='', help='Name or ID of server.') @utils.arg('--active', action='store_const', dest='state', default='error', const='active', help='Request the instance be reset to "active" state instead ' 'of "error" state (the default).') def do_reset_state(cs, args): """Reset the state of an instance""" _find_server(cs, args.server).reset_state(args.state) @utils.arg('host', metavar='', help='Name of host.') def do_host_describe(cs, args): """Describe a specific host""" result = cs.hosts.get(args.host) columns = ["HOST", "PROJECT", "cpu", "memory_mb", "disk_gb"] utils.print_list(result, columns) def do_host_list(cs, args): """List all hosts by service""" columns = ["host_name", "service"] result = cs.hosts.list_all() utils.print_list(result, columns) @utils.arg('host', metavar='', help='Name of host.') @utils.arg('--status', metavar='', default=None, dest='status', help='Either enable or disable a host.') @utils.arg('--maintenance', metavar='', default=None, dest='maintenance', help='Either put or resume host to/from maintenance.') def do_host_update(cs, args): """Update host settings.""" updates = {} columns = ["HOST"] if args.status: updates['status'] = args.status columns.append("status") if args.maintenance: updates['maintenance_mode'] = args.maintenance columns.append("maintenance_mode") result = cs.hosts.update(args.host, updates) utils.print_list([result], columns) @utils.arg('host', metavar='', help='Name of host.') @utils.arg('--action', metavar='', dest='action', choices=['startup', 'shutdown', 'reboot'], help='A power action: startup, reboot, or shutdown.') def do_host_action(cs, args): """Perform a power action on a host.""" result = cs.hosts.host_action(args.host, args.action) utils.print_list([result], ['HOST', 'power_action']) @utils.arg('--matching', metavar='', default=None, help='List hypervisors matching the given .') def do_hypervisor_list(cs, args): """List hypervisors.""" columns = ['ID', 'Hypervisor hostname'] if args.matching: utils.print_list(cs.hypervisors.search(args.matching), columns) else: # Since we're not outputting detail data, choose # detailed=False for server-side efficiency utils.print_list(cs.hypervisors.list(False), columns) @utils.arg('hostname', metavar='', help='The hypervisor hostname (or pattern) to search for.') def do_hypervisor_servers(cs, args): """List instances belonging to specific hypervisors.""" hypers = cs.hypervisors.search(args.hostname, servers=True) class InstanceOnHyper(object): def __init__(self, **kwargs): self.__dict__.update(kwargs) # Massage the result into a list to be displayed instances = [] for hyper in hypers: hyper_host = hyper.hypervisor_hostname hyper_id = hyper.id instances.extend([InstanceOnHyper(id=serv['uuid'], name=serv['name'], hypervisor_hostname=hyper_host, hypervisor_id=hyper_id) for serv in hyper.servers]) # Output the data utils.print_list(instances, ['ID', 'Name', 'Hypervisor ID', 'Hypervisor Hostname']) @utils.arg('hypervisor_id', metavar='', help='The ID of the hypervisor to show the details of.') def do_hypervisor_show(cs, args): """Display the details of the specified hypervisor.""" hyper = utils.find_resource(cs.hypervisors, args.hypervisor_id) # Build up the dict info = hyper._info.copy() info['service_id'] = info['service']['id'] info['service_host'] = info['service']['host'] del info['service'] utils.print_dict(info) @utils.arg('hypervisor_id', metavar='', help='The ID of the hypervisor to show the uptime of.') def do_hypervisor_uptime(cs, args): """Display the uptime of the specified hypervisor.""" hyper = cs.hypervisors.uptime(args.hypervisor_id) # Output the uptime information utils.print_dict(hyper._info.copy()) def do_hypervisor_stats(cs, args): """Get hypervisor statistics over all compute nodes.""" stats = cs.hypervisors.statistics() utils.print_dict(stats._info.copy()) def ensure_service_catalog_present(cs): if not hasattr(cs.client, 'service_catalog'): # Turn off token caching and re-auth cs.client.unauthenticate() cs.client.use_token_cache(False) cs.client.authenticate() def do_endpoints(cs, _args): """Discover endpoints that get returned from the authenticate services""" ensure_service_catalog_present(cs) catalog = cs.client.service_catalog.catalog for e in catalog['access']['serviceCatalog']: utils.print_dict(e['endpoints'][0], e['name']) def do_credentials(cs, _args): """Show user credentials returned from auth""" ensure_service_catalog_present(cs) catalog = cs.client.service_catalog.catalog utils.print_dict(catalog['access']['user'], "User Credentials") utils.print_dict(catalog['access']['token'], "Token") @utils.arg('server', metavar='', help='Name or ID of server.') @utils.arg('--port', dest='port', action='store', type=int, default=22, help='Optional flag to indicate which port to use for ssh. ' '(Default=22)') @utils.arg('--private', dest='private', action='store_true', default=False, help='Optional flag to indicate whether to use private address ' 'attached to an instance. (Default=False)') @utils.arg('--ipv6', dest='ipv6', action='store_true', default=False, help='Optional flag to indicate whether to use an IPv6 address ' 'attached to an instance. (Defaults to IPv4 address)') @utils.arg('--login', metavar='', help='Login to use.', default="root") @utils.arg('-i', '--identity', dest='identity', help='Private key file, same as the -i option to the ssh command.', default='') def do_ssh(cs, args): """SSH into a server.""" addresses = _find_server(cs, args.server).addresses address_type = "private" if args.private else "public" version = 6 if args.ipv6 else 4 if address_type not in addresses: print "ERROR: No %s addresses found for '%s'." % (address_type, args.server) return ip_address = None for address in addresses[address_type]: if address['version'] == version: ip_address = address['addr'] break identity = '-i %s' % args.identity if len(args.identity) else '' if ip_address: os.system("ssh -%d -p%d %s %s@%s" % (version, args.port, identity, args.login, ip_address)) else: pretty_version = "IPv%d" % version print "ERROR: No %s %s address found." % (address_type, pretty_version) return _quota_resources = ['instances', 'cores', 'ram', 'volumes', 'gigabytes', 'floating_ips', 'metadata_items', 'injected_files', 'injected_file_content_bytes'] def _quota_show(quotas): quota_dict = {} for resource in _quota_resources: quota_dict[resource] = getattr(quotas, resource, None) utils.print_dict(quota_dict) def _quota_update(manager, identifier, args): updates = {} for resource in _quota_resources: val = getattr(args, resource, None) if val is not None: updates[resource] = val if updates: manager.update(identifier, **updates) @utils.arg('tenant', metavar='', help='UUID of tenant to list the quotas for.') def do_quota_show(cs, args): """List the quotas for a tenant.""" _quota_show(cs.quotas.get(args.tenant)) @utils.arg('tenant', metavar='', help='UUID of tenant to list the default quotas for.') def do_quota_defaults(cs, args): """List the default quotas for a tenant.""" _quota_show(cs.quotas.defaults(args.tenant)) @utils.arg('tenant', metavar='', help='UUID of tenant to set the quotas for.') @utils.arg('--instances', metavar='', type=int, default=None, help='New value for the "instances" quota.') @utils.arg('--cores', metavar='', type=int, default=None, help='New value for the "cores" quota.') @utils.arg('--ram', metavar='', type=int, default=None, help='New value for the "ram" quota.') @utils.arg('--volumes', metavar='', type=int, default=None, help='New value for the "volumes" quota.') @utils.arg('--gigabytes', metavar='', type=int, default=None, help='New value for the "gigabytes" quota.') @utils.arg('--floating-ips', '--floating_ips', metavar='', type=int, default=None, help='New value for the "floating_ips" quota.') @utils.arg('--metadata-items', '--metadata_items', metavar='', type=int, default=None, help='New value for the "metadata_items" quota.') @utils.arg('--injected-files', '--injected_files', metavar='', type=int, default=None, help='New value for the "injected_files" quota.') @utils.arg('--injected-file-content-bytes', '--injected_file_content_bytes', metavar='', type=int, default=None, help='New value for the "injected_file_content_bytes" quota.') def do_quota_update(cs, args): """Update the quotas for a tenant.""" _quota_update(cs.quotas, args.tenant, args) @utils.arg('class_name', metavar='', help='Name of quota class to list the quotas for.') def do_quota_class_show(cs, args): """List the quotas for a quota class.""" _quota_show(cs.quota_classes.get(args.class_name)) @utils.arg('class_name', metavar='', help='Name of quota class to set the quotas for.') @utils.arg('--instances', metavar='', type=int, default=None, help='New value for the "instances" quota.') @utils.arg('--cores', metavar='', type=int, default=None, help='New value for the "cores" quota.') @utils.arg('--ram', metavar='', type=int, default=None, help='New value for the "ram" quota.') @utils.arg('--volumes', metavar='', type=int, default=None, help='New value for the "volumes" quota.') @utils.arg('--gigabytes', metavar='', type=int, default=None, help='New value for the "gigabytes" quota.') @utils.arg('--floating-ips', '--floating_ips', metavar='', type=int, default=None, help='New value for the "floating_ips" quota.') @utils.arg('--metadata-items', '--metadata_items', metavar='', type=int, default=None, help='New value for the "metadata_items" quota.') @utils.arg('--injected-files', '--injected_files', metavar='', type=int, default=None, help='New value for the "injected_files" quota.') @utils.arg('--injected-file-content-bytes', '--injected_file_content_bytes', metavar='', type=int, default=None, help='New value for the "injected_file_content_bytes" quota.') def do_quota_class_update(cs, args): """Update the quotas for a quota class.""" _quota_update(cs.quota_classes, args.class_name, args)