2011-02-25 02:00:13 -08:00
|
|
|
# Copyright 2010 Jacob Kaplan-Moss
|
2011-02-24 13:54:10 -04:00
|
|
|
|
|
|
|
# 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.
|
|
|
|
|
2011-01-25 14:01:22 -06:00
|
|
|
import getpass
|
|
|
|
import os
|
|
|
|
|
2011-08-03 17:41:33 -04:00
|
|
|
from novaclient import exceptions
|
|
|
|
from novaclient import utils
|
|
|
|
from novaclient.v1_1 import client
|
2011-08-03 16:36:03 -04:00
|
|
|
from novaclient.v1_1 import servers
|
2011-01-25 14:01:22 -06:00
|
|
|
|
|
|
|
|
2011-08-03 17:41:33 -04:00
|
|
|
CLIENT_CLASS = client.Client
|
|
|
|
|
2011-01-25 14:01:22 -06:00
|
|
|
|
|
|
|
AUTO_KEY = object()
|
|
|
|
|
|
|
|
|
2011-08-04 17:07:22 -04:00
|
|
|
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:
|
2011-08-06 00:41:48 -07:00
|
|
|
raise exceptions.CommandError("min_instances should be <= "
|
|
|
|
"max_instances")
|
2011-08-04 17:07:22 -04:00
|
|
|
if not min_count or not max_count:
|
2011-08-06 00:41:48 -07:00
|
|
|
raise exceptions.CommandError("min_instances nor max_instances should"
|
|
|
|
"be 0")
|
2011-08-04 17:07:22 -04:00
|
|
|
|
2011-08-29 23:18:47 -05:00
|
|
|
if not args.image:
|
2011-08-30 08:39:17 -05:00
|
|
|
raise exceptions.CommandError("you need to specify a Image ID ")
|
2011-08-29 23:18:47 -05:00
|
|
|
if not args.flavor:
|
2011-08-30 08:39:17 -05:00
|
|
|
raise exceptions.CommandError("you need to specify a Flavor ID ")
|
2011-08-29 23:18:47 -05:00
|
|
|
|
|
|
|
flavor = args.flavor
|
|
|
|
image = args.image
|
2011-08-04 17:07:22 -04:00
|
|
|
|
|
|
|
metadata = dict(v.split('=') 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))
|
|
|
|
|
2011-10-17 13:57:56 -07:00
|
|
|
# use the os-keypair extension
|
2011-10-12 13:57:26 +04:00
|
|
|
key_name = None
|
|
|
|
if args.key_name is not None:
|
|
|
|
key_name = args.key_name
|
2011-10-17 13:57:56 -07:00
|
|
|
|
|
|
|
# or use file injection functionality (independent of os-keypair extension)
|
|
|
|
keyfile = None
|
2011-10-17 14:18:38 -07:00
|
|
|
if args.key_path is AUTO_KEY:
|
2011-08-04 17:07:22 -04:00
|
|
|
possible_keys = [os.path.join(os.path.expanduser('~'), '.ssh', k)
|
|
|
|
for k in ('id_dsa.pub', 'id_rsa.pub')]
|
|
|
|
for k in possible_keys:
|
|
|
|
if os.path.exists(k):
|
|
|
|
keyfile = k
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
raise exceptions.CommandError("Couldn't find a key file: tried "
|
|
|
|
"~/.ssh/id_dsa.pub or ~/.ssh/id_rsa.pub")
|
2011-10-12 13:57:26 +04:00
|
|
|
elif args.key_path:
|
|
|
|
keyfile = args.key_path
|
2011-08-04 17:07:22 -04:00
|
|
|
|
|
|
|
if keyfile:
|
|
|
|
try:
|
|
|
|
files['/root/.ssh/authorized_keys2'] = open(keyfile)
|
|
|
|
except IOError, e:
|
|
|
|
raise exceptions.CommandError("Can't open '%s': %s" % (keyfile, e))
|
|
|
|
|
2011-10-10 19:40:05 +05:30
|
|
|
if args.user_data:
|
2011-10-17 12:46:05 +05:30
|
|
|
try:
|
|
|
|
user_data = open(args.user_data)
|
|
|
|
except IOError, e:
|
|
|
|
raise exceptions.CommandError("Can't open '%s': %s" % \
|
|
|
|
(args.user_data, e))
|
2011-10-10 19:40:05 +05:30
|
|
|
else:
|
|
|
|
user_data = 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
|
2011-11-09 10:36:16 -08:00
|
|
|
|
2011-10-25 13:45:59 -07:00
|
|
|
block_device_mapping = {}
|
|
|
|
for bdm in args.block_device_mapping:
|
|
|
|
device_name, mapping = bdm.split('=', 1)
|
|
|
|
block_device_mapping[device_name] = mapping
|
2011-11-09 10:36:16 -08:00
|
|
|
|
2011-11-15 18:32:16 -08:00
|
|
|
nics = []
|
|
|
|
for nic_str in args.nics:
|
|
|
|
nic_info = {"net-id": "", "v4-fixed-ip": ""}
|
|
|
|
for kv_str in nic_str.split(","):
|
2011-11-16 08:47:37 -08:00
|
|
|
k, v = kv_str.split("=")
|
2011-11-15 18:32:16 -08:00
|
|
|
nic_info[k] = v
|
|
|
|
nics.append(nic_info)
|
|
|
|
|
2011-10-12 13:57:26 +04:00
|
|
|
return (args.name, image, flavor, metadata, files, key_name,
|
2011-10-10 19:40:05 +05:30
|
|
|
reservation_id, min_count, max_count, user_data, \
|
2011-11-15 18:32:16 -08:00
|
|
|
availability_zone, security_groups, block_device_mapping, nics)
|
2011-08-03 17:41:33 -04:00
|
|
|
|
2011-08-06 00:41:48 -07:00
|
|
|
|
2011-08-03 17:41:33 -04:00
|
|
|
@utils.arg('--flavor',
|
|
|
|
default=None,
|
|
|
|
metavar='<flavor>',
|
2011-08-29 23:18:47 -05:00
|
|
|
help="Flavor ID (see 'nova flavor-list').")
|
2011-08-03 17:41:33 -04:00
|
|
|
@utils.arg('--image',
|
|
|
|
default=None,
|
|
|
|
metavar='<image>',
|
2011-08-29 23:18:47 -05:00
|
|
|
help="Image ID (see 'nova image-list'). ")
|
2011-08-03 17:41:33 -04:00
|
|
|
@utils.arg('--meta',
|
|
|
|
metavar="<key=value>",
|
|
|
|
action='append',
|
|
|
|
default=[],
|
|
|
|
help="Record arbitrary key/value metadata. "\
|
|
|
|
"May be give multiple times.")
|
|
|
|
@utils.arg('--file',
|
|
|
|
metavar="<dst-path=src-path>",
|
|
|
|
action='append',
|
|
|
|
dest='files',
|
|
|
|
default=[],
|
|
|
|
help="Store arbitrary files from <src-path> locally to <dst-path> "\
|
|
|
|
"on the new server. You may store up to 5 files.")
|
2011-10-12 13:57:26 +04:00
|
|
|
@utils.arg('--key_path',
|
|
|
|
metavar='<key_path>',
|
2011-08-03 17:41:33 -04:00
|
|
|
nargs='?',
|
|
|
|
const=AUTO_KEY,
|
|
|
|
help="Key the server with an SSH keypair. "\
|
|
|
|
"Looks in ~/.ssh for a key, "\
|
2011-10-17 14:09:25 -07:00
|
|
|
"or takes an explicit <path> to one. (uses --file functionality)")
|
2011-10-12 13:57:26 +04:00
|
|
|
@utils.arg('--key_name',
|
|
|
|
metavar='<key_name>',
|
|
|
|
help="Key name of keypair that should be created earlier with \
|
|
|
|
the command keypair-add")
|
2011-08-03 17:41:33 -04:00
|
|
|
@utils.arg('name', metavar='<name>', help='Name for the new server')
|
2011-10-10 19:40:05 +05:30
|
|
|
@utils.arg('--user_data',
|
|
|
|
default=None,
|
|
|
|
metavar='<user-data>',
|
2011-10-17 12:46:05 +05:30
|
|
|
help="user data file to pass to be exposed by the metadata server.")
|
2011-10-10 19:40:05 +05:30
|
|
|
@utils.arg('--availability_zone',
|
|
|
|
default=None,
|
|
|
|
metavar='<availability-zone>',
|
|
|
|
help="zone id.")
|
|
|
|
@utils.arg('--security_groups',
|
|
|
|
default=None,
|
|
|
|
metavar='<security_groups>',
|
|
|
|
help="comma separated list of security group names.")
|
2011-10-25 13:45:59 -07:00
|
|
|
@utils.arg('--block_device_mapping',
|
|
|
|
metavar="<dev_name=mapping>",
|
|
|
|
action='append',
|
|
|
|
default=[],
|
|
|
|
help="Block device mapping in the format "
|
|
|
|
"<dev_name=<id>:<type>:<size(GB)>:<delete_on_terminate>.")
|
2011-11-15 18:32:16 -08:00
|
|
|
@utils.arg('--nic',
|
|
|
|
metavar="<net-id=net-uuid,v4-fixed-ip=ip-addr>",
|
|
|
|
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).")
|
2011-08-03 17:41:33 -04:00
|
|
|
def do_boot(cs, args):
|
|
|
|
"""Boot a new server."""
|
2011-10-12 13:57:26 +04:00
|
|
|
name, image, flavor, metadata, files, key_name, reservation_id, \
|
2011-10-10 19:40:05 +05:30
|
|
|
min_count, max_count, user_data, availability_zone, \
|
2011-11-15 18:32:16 -08:00
|
|
|
security_groups, block_device_mapping, nics = _boot(cs, args)
|
2011-08-03 17:41:33 -04:00
|
|
|
|
2011-08-04 17:07:22 -04:00
|
|
|
server = cs.servers.create(args.name, image, flavor,
|
|
|
|
meta=metadata,
|
|
|
|
files=files,
|
|
|
|
min_count=min_count,
|
2011-10-10 19:40:05 +05:30
|
|
|
max_count=max_count,
|
|
|
|
userdata=user_data,
|
|
|
|
availability_zone=availability_zone,
|
2011-10-17 14:09:25 -07:00
|
|
|
security_groups=security_groups,
|
2011-10-25 13:45:59 -07:00
|
|
|
key_name=key_name,
|
2011-11-15 18:32:16 -08:00
|
|
|
block_device_mapping=block_device_mapping,
|
|
|
|
nics=nics)
|
2011-08-08 11:44:41 -04:00
|
|
|
|
2011-11-04 19:57:52 +00:00
|
|
|
# Keep any information (like adminPass) returned by create
|
2011-08-08 11:44:41 -04:00
|
|
|
info = server._info
|
2011-11-04 19:57:52 +00:00
|
|
|
server = cs.servers.get(info['id'])
|
|
|
|
info.update(server._info)
|
2011-08-08 11:44:41 -04:00
|
|
|
|
|
|
|
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)
|
2011-08-03 17:41:33 -04:00
|
|
|
|
|
|
|
|
2011-08-04 17:07:22 -04:00
|
|
|
@utils.arg('--flavor',
|
|
|
|
default=None,
|
|
|
|
metavar='<flavor>',
|
2011-08-29 23:18:47 -05:00
|
|
|
help="Flavor ID (see 'nova flavor-list')")
|
2011-08-04 17:07:22 -04:00
|
|
|
@utils.arg('--image',
|
|
|
|
default=None,
|
|
|
|
metavar='<image>',
|
2011-08-29 23:18:47 -05:00
|
|
|
help="Image ID (see 'nova image-list').")
|
2011-08-04 17:07:22 -04:00
|
|
|
@utils.arg('--meta',
|
|
|
|
metavar="<key=value>",
|
|
|
|
action='append',
|
|
|
|
default=[],
|
|
|
|
help="Record arbitrary key/value metadata. "\
|
|
|
|
"May be give multiple times.")
|
|
|
|
@utils.arg('--file',
|
|
|
|
metavar="<dst-path=src-path>",
|
|
|
|
action='append',
|
|
|
|
dest='files',
|
|
|
|
default=[],
|
|
|
|
help="Store arbitrary files from <src-path> locally to <dst-path> "\
|
|
|
|
"on the new server. You may store up to 5 files.")
|
|
|
|
@utils.arg('--key',
|
|
|
|
metavar='<path>',
|
|
|
|
nargs='?',
|
|
|
|
const=AUTO_KEY,
|
|
|
|
help="Key the server with an SSH keypair. "\
|
|
|
|
"Looks in ~/.ssh for a key, "\
|
|
|
|
"or takes an explicit <path> to one.")
|
|
|
|
@utils.arg('--reservation_id',
|
|
|
|
default=None,
|
|
|
|
metavar='<reservation_id>',
|
|
|
|
help="Reservation ID (a UUID). "\
|
|
|
|
"If unspecified will be generated by the server.")
|
|
|
|
@utils.arg('--min_instances',
|
|
|
|
default=None,
|
|
|
|
type=int,
|
|
|
|
metavar='<number>',
|
|
|
|
help="The minimum number of instances to build. "\
|
|
|
|
"Defaults to 1.")
|
|
|
|
@utils.arg('--max_instances',
|
|
|
|
default=None,
|
|
|
|
type=int,
|
|
|
|
metavar='<number>',
|
|
|
|
help="The maximum number of instances to build. "\
|
|
|
|
"Defaults to 'min_instances' setting.")
|
|
|
|
@utils.arg('name', metavar='<name>', help='Name for the new server')
|
|
|
|
def do_zone_boot(cs, args):
|
|
|
|
"""Boot a new server, potentially across Zones."""
|
|
|
|
reservation_id = args.reservation_id
|
|
|
|
min_count = args.min_instances
|
|
|
|
max_count = args.max_instances
|
|
|
|
name, image, flavor, metadata, \
|
2011-10-10 19:40:05 +05:30
|
|
|
files, reservation_id, min_count, max_count,\
|
|
|
|
user_data, availability_zone, security_groups = \
|
2011-08-04 17:07:22 -04:00
|
|
|
_boot(cs, args,
|
|
|
|
reservation_id=reservation_id,
|
|
|
|
min_count=min_count,
|
|
|
|
max_count=max_count)
|
|
|
|
|
|
|
|
reservation_id = cs.zones.boot(args.name, image, flavor,
|
|
|
|
meta=metadata,
|
|
|
|
files=files,
|
|
|
|
reservation_id=reservation_id,
|
|
|
|
min_count=min_count,
|
|
|
|
max_count=max_count)
|
|
|
|
print "Reservation ID=", reservation_id
|
2011-10-19 10:54:27 -07:00
|
|
|
|
2011-08-03 17:41:33 -04:00
|
|
|
|
2011-08-04 17:07:22 -04:00
|
|
|
def _translate_flavor_keys(collection):
|
|
|
|
convert = [('ram', 'memory_mb'), ('disk', 'local_gb')]
|
|
|
|
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])
|
2011-08-03 17:41:33 -04:00
|
|
|
|
|
|
|
|
|
|
|
def do_flavor_list(cs, args):
|
|
|
|
"""Print a list of available 'flavors' (sizes of servers)."""
|
|
|
|
flavors = cs.flavors.list()
|
|
|
|
_translate_flavor_keys(flavors)
|
|
|
|
utils.print_list(flavors, [
|
|
|
|
'ID',
|
|
|
|
'Name',
|
|
|
|
'Memory_MB',
|
|
|
|
'Swap',
|
|
|
|
'Local_GB',
|
|
|
|
'VCPUs',
|
2011-12-01 11:09:38 -06:00
|
|
|
'RXTX_Factor'])
|
2011-08-03 17:41:33 -04:00
|
|
|
|
2011-08-06 00:41:48 -07:00
|
|
|
|
2011-08-03 17:41:33 -04:00
|
|
|
def do_image_list(cs, args):
|
|
|
|
"""Print a list of available images to boot from."""
|
2011-10-30 17:20:47 -05:00
|
|
|
image_list = cs.images.list()
|
2011-12-07 11:12:35 -05:00
|
|
|
|
|
|
|
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)
|
2011-08-03 17:41:33 -04:00
|
|
|
|
2011-10-10 19:40:05 +05:30
|
|
|
|
2011-08-31 12:59:21 -04:00
|
|
|
@utils.arg('image',
|
|
|
|
metavar='<image>',
|
|
|
|
help="Name or ID of image")
|
|
|
|
@utils.arg('action',
|
|
|
|
metavar='<action>',
|
|
|
|
choices=['set', 'delete'],
|
|
|
|
help="Actions: 'set' or 'delete'")
|
2011-10-10 19:40:05 +05:30
|
|
|
@utils.arg('metadata',
|
2011-08-31 12:59:21 -04:00
|
|
|
metavar='<key=value>',
|
|
|
|
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)
|
2011-10-10 19:40:05 +05:30
|
|
|
metadata = {}
|
2011-08-31 12:59:21 -04:00
|
|
|
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:
|
2011-10-10 19:40:05 +05:30
|
|
|
(key, value) = metadatum.split('=', 1)
|
2011-08-31 12:59:21 -04:00
|
|
|
else:
|
|
|
|
key = metadatum
|
|
|
|
value = None
|
|
|
|
|
|
|
|
metadata[key] = value
|
|
|
|
|
|
|
|
if args.action == 'set':
|
|
|
|
cs.images.set_meta(image, metadata)
|
|
|
|
elif args.action == 'delete':
|
|
|
|
cs.images.delete_meta(image, metadata.keys())
|
|
|
|
|
2011-10-10 19:40:05 +05:30
|
|
|
|
2011-08-31 12:59:21 -04:00
|
|
|
def _print_image(image):
|
|
|
|
info = image._info.copy()
|
2011-12-07 11:40:45 -05:00
|
|
|
|
|
|
|
# ignore links, we don't need to present those
|
2011-08-31 12:59:21 -04:00
|
|
|
info.pop('links')
|
2011-12-07 11:40:45 -05:00
|
|
|
|
|
|
|
# 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
|
|
|
|
|
2011-08-31 12:59:21 -04:00
|
|
|
utils.print_dict(info)
|
|
|
|
|
2011-10-10 19:40:05 +05:30
|
|
|
|
2011-08-31 12:59:21 -04:00
|
|
|
@utils.arg('image',
|
|
|
|
metavar='<image>',
|
|
|
|
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)
|
2011-08-06 00:41:48 -07:00
|
|
|
|
2011-10-10 19:40:05 +05:30
|
|
|
|
2011-08-03 17:41:33 -04:00
|
|
|
@utils.arg('image', metavar='<image>', 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()
|
|
|
|
|
2011-08-06 00:41:48 -07:00
|
|
|
|
2011-08-03 17:41:33 -04:00
|
|
|
@utils.arg('--reservation_id',
|
|
|
|
dest='reservation_id',
|
|
|
|
metavar='<reservation_id>',
|
|
|
|
default=None,
|
|
|
|
help='Only return instances that match reservation_id.')
|
|
|
|
@utils.arg('--recurse_zones',
|
|
|
|
dest='recurse_zones',
|
|
|
|
metavar='<0|1>',
|
|
|
|
nargs='?',
|
|
|
|
type=int,
|
|
|
|
const=1,
|
|
|
|
default=0,
|
|
|
|
help='Recurse through all zones if set.')
|
|
|
|
@utils.arg('--ip',
|
|
|
|
dest='ip',
|
|
|
|
metavar='<ip_regexp>',
|
|
|
|
default=None,
|
|
|
|
help='Search with regular expression match by IP address')
|
|
|
|
@utils.arg('--ip6',
|
|
|
|
dest='ip6',
|
|
|
|
metavar='<ip6_regexp>',
|
|
|
|
default=None,
|
|
|
|
help='Search with regular expression match by IPv6 address')
|
|
|
|
@utils.arg('--name',
|
2011-08-11 21:38:41 -07:00
|
|
|
dest='name',
|
2011-08-03 17:41:33 -04:00
|
|
|
metavar='<name_regexp>',
|
|
|
|
default=None,
|
2011-08-11 21:38:41 -07:00
|
|
|
help='Search with regular expression match by name')
|
2011-08-03 17:41:33 -04:00
|
|
|
@utils.arg('--instance_name',
|
2011-08-11 21:38:41 -07:00
|
|
|
dest='instance_name',
|
2011-08-03 17:41:33 -04:00
|
|
|
metavar='<name_regexp>',
|
|
|
|
default=None,
|
|
|
|
help='Search with regular expression match by instance name')
|
2011-08-11 21:38:41 -07:00
|
|
|
@utils.arg('--status',
|
|
|
|
dest='status',
|
|
|
|
metavar='<status>',
|
|
|
|
default=None,
|
|
|
|
help='Search by server status')
|
|
|
|
@utils.arg('--flavor',
|
|
|
|
dest='flavor',
|
|
|
|
metavar='<flavor>',
|
|
|
|
type=int,
|
|
|
|
default=None,
|
|
|
|
help='Search by flavor ID')
|
|
|
|
@utils.arg('--image',
|
|
|
|
dest='image',
|
|
|
|
metavar='<image>',
|
|
|
|
default=None,
|
|
|
|
help='Search by image ID')
|
|
|
|
@utils.arg('--host',
|
|
|
|
dest='host',
|
|
|
|
metavar='<hostname>',
|
|
|
|
default=None,
|
|
|
|
help='Search instances by hostname to which they are assigned')
|
2011-08-03 17:41:33 -04:00
|
|
|
def do_list(cs, args):
|
|
|
|
"""List active servers."""
|
|
|
|
recurse_zones = args.recurse_zones
|
|
|
|
search_opts = {
|
|
|
|
'reservation_id': args.reservation_id,
|
|
|
|
'recurse_zones': recurse_zones,
|
|
|
|
'ip': args.ip,
|
|
|
|
'ip6': args.ip6,
|
|
|
|
'name': args.name,
|
2011-08-11 21:41:50 -07:00
|
|
|
'image': args.image,
|
|
|
|
'flavor': args.flavor,
|
|
|
|
'status': args.status,
|
|
|
|
'host': args.host,
|
2011-08-11 21:45:26 -07:00
|
|
|
'instance_name': args.instance_name}
|
2011-08-04 18:39:21 +00:00
|
|
|
|
2011-08-03 17:41:33 -04:00
|
|
|
if recurse_zones:
|
2011-08-04 18:39:21 +00:00
|
|
|
id_col = 'UUID'
|
2011-08-03 17:41:33 -04:00
|
|
|
else:
|
2011-08-04 18:39:21 +00:00
|
|
|
id_col = 'ID'
|
|
|
|
|
|
|
|
columns = [id_col, 'Name', 'Status', 'Networks']
|
|
|
|
formatters = {'Networks': _format_servers_list_networks}
|
2011-08-06 00:41:48 -07:00
|
|
|
utils.print_list(cs.servers.list(search_opts=search_opts), columns,
|
|
|
|
formatters)
|
2011-08-04 18:39:21 +00:00
|
|
|
|
|
|
|
|
|
|
|
def _format_servers_list_networks(server):
|
|
|
|
output = []
|
|
|
|
for (network, addresses) in server.networks.items():
|
|
|
|
if len(addresses) == 0:
|
|
|
|
continue
|
|
|
|
addresses_csv = ', '.join(addresses)
|
|
|
|
group = "%s=%s" % (network, addresses_csv)
|
|
|
|
output.append(group)
|
|
|
|
|
|
|
|
return '; '.join(output)
|
|
|
|
|
2011-08-03 17:41:33 -04:00
|
|
|
|
|
|
|
@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='<server>', help='Name or ID of server.')
|
|
|
|
def do_reboot(cs, args):
|
|
|
|
"""Reboot a server."""
|
|
|
|
_find_server(cs, args.server).reboot(args.reboot_type)
|
|
|
|
|
2011-08-06 00:41:48 -07:00
|
|
|
|
2011-08-03 17:41:33 -04:00
|
|
|
@utils.arg('server', metavar='<server>', help='Name or ID of server.')
|
|
|
|
@utils.arg('image', metavar='<image>', help="Name or ID of new image.")
|
2011-11-09 07:10:46 -08:00
|
|
|
@utils.arg('--rebuild_password', dest='rebuild_password',
|
|
|
|
metavar='<rebuild_password>', default=False,
|
2011-08-23 23:17:25 -04:00
|
|
|
help="Set the provided password on the rebuild instance.")
|
2011-08-03 17:41:33 -04:00
|
|
|
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)
|
2011-08-23 23:17:25 -04:00
|
|
|
|
2011-11-09 07:10:46 -08:00
|
|
|
if args.rebuild_password != False:
|
|
|
|
_password = args.rebuild_password
|
2011-08-23 23:17:25 -04:00
|
|
|
else:
|
|
|
|
_password = None
|
|
|
|
|
|
|
|
s = server.rebuild(image, _password)
|
|
|
|
_print_server(cs, s)
|
2011-08-03 17:41:33 -04:00
|
|
|
|
2011-08-06 00:41:48 -07:00
|
|
|
|
|
|
|
@utils.arg('server', metavar='<server>',
|
|
|
|
help='Name (old name) or ID of server.')
|
2011-08-03 17:41:33 -04:00
|
|
|
@utils.arg('name', metavar='<name>', help='New name for the server.')
|
|
|
|
def do_rename(cs, args):
|
|
|
|
"""Rename a server."""
|
|
|
|
_find_server(cs, args.server).update(name=args.name)
|
|
|
|
|
2011-08-06 00:41:48 -07:00
|
|
|
|
2011-08-03 17:41:33 -04:00
|
|
|
@utils.arg('server', metavar='<server>', help='Name or ID of server.')
|
|
|
|
@utils.arg('flavor', metavar='<flavor>', help="Name or ID of new flavor.")
|
|
|
|
def do_resize(cs, args):
|
|
|
|
"""Resize a server."""
|
|
|
|
server = _find_server(cs, args.server)
|
|
|
|
flavor = _find_flavor(cs, args.flavor)
|
|
|
|
server.resize(flavor)
|
|
|
|
|
2011-08-06 00:41:48 -07:00
|
|
|
|
2011-08-03 17:41:33 -04:00
|
|
|
@utils.arg('server', metavar='<server>', help='Name or ID of server.')
|
|
|
|
def do_resize_confirm(cs, args):
|
|
|
|
"""Confirm a previous resize."""
|
|
|
|
_find_server(cs, args.server).confirm_resize()
|
|
|
|
|
2011-08-06 00:41:48 -07:00
|
|
|
|
2011-08-03 17:41:33 -04:00
|
|
|
@utils.arg('server', metavar='<server>', 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()
|
|
|
|
|
2011-08-06 00:41:48 -07:00
|
|
|
|
2011-08-04 17:07:22 -04:00
|
|
|
@utils.arg('server', metavar='<server>', help='Name or ID of server.')
|
|
|
|
def do_migrate(cs, args):
|
|
|
|
"""Migrate a server."""
|
|
|
|
_find_server(cs, args.server).migrate()
|
|
|
|
|
2011-08-06 00:41:48 -07:00
|
|
|
|
2011-08-04 17:07:22 -04:00
|
|
|
@utils.arg('server', metavar='<server>', help='Name or ID of server.')
|
|
|
|
def do_pause(cs, args):
|
|
|
|
"""Pause a server."""
|
|
|
|
_find_server(cs, args.server).pause()
|
|
|
|
|
2011-08-06 00:41:48 -07:00
|
|
|
|
2011-08-04 17:07:22 -04:00
|
|
|
@utils.arg('server', metavar='<server>', help='Name or ID of server.')
|
|
|
|
def do_unpause(cs, args):
|
|
|
|
"""Unpause a server."""
|
|
|
|
_find_server(cs, args.server).unpause()
|
|
|
|
|
2011-08-06 00:41:48 -07:00
|
|
|
|
2011-08-04 17:07:22 -04:00
|
|
|
@utils.arg('server', metavar='<server>', help='Name or ID of server.')
|
|
|
|
def do_suspend(cs, args):
|
|
|
|
"""Suspend a server."""
|
|
|
|
_find_server(cs, args.server).suspend()
|
|
|
|
|
2011-08-06 00:41:48 -07:00
|
|
|
|
2011-08-04 17:07:22 -04:00
|
|
|
@utils.arg('server', metavar='<server>', help='Name or ID of server.')
|
|
|
|
def do_resume(cs, args):
|
|
|
|
"""Resume a server."""
|
|
|
|
_find_server(cs, args.server).resume()
|
|
|
|
|
2011-08-06 00:41:48 -07:00
|
|
|
|
2011-08-04 17:07:22 -04:00
|
|
|
@utils.arg('server', metavar='<server>', help='Name or ID of server.')
|
|
|
|
def do_rescue(cs, args):
|
|
|
|
"""Rescue a server."""
|
|
|
|
_find_server(cs, args.server).rescue()
|
|
|
|
|
2011-08-06 00:41:48 -07:00
|
|
|
|
2011-08-04 17:07:22 -04:00
|
|
|
@utils.arg('server', metavar='<server>', help='Name or ID of server.')
|
|
|
|
def do_unrescue(cs, args):
|
|
|
|
"""Unrescue a server."""
|
|
|
|
_find_server(cs, args.server).unrescue()
|
|
|
|
|
2011-08-06 00:41:48 -07:00
|
|
|
|
2011-08-04 17:07:22 -04:00
|
|
|
@utils.arg('server', metavar='<server>', help='Name or ID of server.')
|
|
|
|
def do_diagnostics(cs, args):
|
|
|
|
"""Retrieve server diagnostics."""
|
|
|
|
utils.print_dict(cs.servers.diagnostics(args.server)[1])
|
|
|
|
|
2011-08-06 00:41:48 -07:00
|
|
|
|
2011-08-04 17:07:22 -04:00
|
|
|
@utils.arg('server', metavar='<server>', help='Name or ID of server.')
|
|
|
|
def do_actions(cs, args):
|
|
|
|
"""Retrieve server actions."""
|
|
|
|
utils.print_list(
|
|
|
|
cs.servers.actions(args.server),
|
|
|
|
["Created_At", "Action", "Error"])
|
|
|
|
|
|
|
|
|
2011-08-03 17:41:33 -04:00
|
|
|
@utils.arg('server', metavar='<server>', 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)
|
|
|
|
|
2011-08-06 00:41:48 -07:00
|
|
|
|
2011-08-03 17:41:33 -04:00
|
|
|
@utils.arg('server', metavar='<server>', help='Name or ID of server.')
|
|
|
|
@utils.arg('name', metavar='<name>', help='Name of snapshot.')
|
2011-08-04 12:35:41 -04:00
|
|
|
def do_image_create(cs, args):
|
2011-08-03 17:41:33 -04:00
|
|
|
"""Create a new image by taking a snapshot of a running server."""
|
|
|
|
server = _find_server(cs, args.server)
|
|
|
|
cs.servers.create_image(server, args.name)
|
|
|
|
|
2011-10-10 19:40:05 +05:30
|
|
|
|
2011-09-01 11:40:16 -04:00
|
|
|
@utils.arg('server',
|
|
|
|
metavar='<server>',
|
|
|
|
help="Name or ID of server")
|
|
|
|
@utils.arg('action',
|
|
|
|
metavar='<action>',
|
|
|
|
choices=['set', 'delete'],
|
|
|
|
help="Actions: 'set' or 'delete'")
|
|
|
|
@utils.arg('metadata',
|
|
|
|
metavar='<key=value>',
|
|
|
|
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 = {}
|
|
|
|
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:
|
2011-10-10 19:40:05 +05:30
|
|
|
(key, value) = metadatum.split('=', 1)
|
2011-09-01 11:40:16 -04:00
|
|
|
else:
|
|
|
|
key = metadatum
|
|
|
|
value = None
|
|
|
|
|
|
|
|
metadata[key] = value
|
|
|
|
|
|
|
|
if args.action == 'set':
|
|
|
|
cs.servers.set_meta(server, metadata)
|
|
|
|
elif args.action == 'delete':
|
|
|
|
cs.servers.delete_meta(server, metadata.keys())
|
2011-08-06 00:41:48 -07:00
|
|
|
|
|
|
|
|
2011-08-23 23:17:25 -04:00
|
|
|
def _print_server(cs, server):
|
2011-09-01 20:15:53 -05:00
|
|
|
# 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)
|
|
|
|
|
2011-08-23 23:17:25 -04:00
|
|
|
networks = server.networks
|
|
|
|
info = server._info.copy()
|
2011-08-04 18:39:21 +00:00
|
|
|
for network_label, address_list in networks.items():
|
|
|
|
info['%s network' % network_label] = ', '.join(address_list)
|
2011-08-03 17:41:33 -04:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2011-08-04 15:53:30 -04:00
|
|
|
info.pop('links', None)
|
2011-08-04 18:39:21 +00:00
|
|
|
info.pop('addresses', None)
|
|
|
|
|
2011-08-03 17:41:33 -04:00
|
|
|
utils.print_dict(info)
|
|
|
|
|
2011-08-06 00:41:48 -07:00
|
|
|
|
2011-08-23 23:17:25 -04:00
|
|
|
@utils.arg('server', metavar='<server>', 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)
|
|
|
|
|
|
|
|
|
2011-08-03 17:41:33 -04:00
|
|
|
@utils.arg('server', metavar='<server>', help='Name or ID of server.')
|
|
|
|
def do_delete(cs, args):
|
|
|
|
"""Immediately shut down and delete a server."""
|
|
|
|
_find_server(cs, args.server).delete()
|
|
|
|
|
2011-08-06 00:41:48 -07:00
|
|
|
|
2011-08-03 17:41:33 -04:00
|
|
|
def _find_server(cs, server):
|
|
|
|
"""Get a server by name or ID."""
|
2011-08-22 15:13:26 -04:00
|
|
|
return utils.find_resource(cs.servers, server)
|
2011-08-03 17:41:33 -04:00
|
|
|
|
2011-08-06 00:41:48 -07:00
|
|
|
|
2011-08-03 17:41:33 -04:00
|
|
|
def _find_image(cs, image):
|
|
|
|
"""Get an image by name or ID."""
|
2011-08-22 15:13:26 -04:00
|
|
|
return utils.find_resource(cs.images, image)
|
2011-08-03 17:41:33 -04:00
|
|
|
|
2011-08-06 00:41:48 -07:00
|
|
|
|
2011-08-03 17:41:33 -04:00
|
|
|
def _find_flavor(cs, flavor):
|
|
|
|
"""Get a flavor by name, ID, or RAM size."""
|
|
|
|
try:
|
2011-08-22 15:13:26 -04:00
|
|
|
return utils.find_resource(cs.flavors, flavor)
|
2011-08-03 17:41:33 -04:00
|
|
|
except exceptions.NotFound:
|
|
|
|
return cs.flavors.find(ram=flavor)
|
2011-01-25 14:01:22 -06:00
|
|
|
|
2011-08-06 00:41:48 -07:00
|
|
|
|
2011-08-04 17:07:22 -04:00
|
|
|
# --zone_username is required since --username is already used.
|
|
|
|
@utils.arg('zone', metavar='<zone_id>', help='ID of the zone', default=None)
|
|
|
|
@utils.arg('--api_url', dest='api_url', default=None, help='New URL.')
|
|
|
|
@utils.arg('--zone_username', dest='zone_username', default=None,
|
|
|
|
help='New zone username.')
|
2011-11-09 07:10:46 -08:00
|
|
|
@utils.arg('--zone_password', dest='zone_password', default=None,
|
|
|
|
help='New password.')
|
2011-08-04 17:07:22 -04:00
|
|
|
@utils.arg('--weight_offset', dest='weight_offset', default=None,
|
|
|
|
help='Child Zone weight offset.')
|
|
|
|
@utils.arg('--weight_scale', dest='weight_scale', default=None,
|
|
|
|
help='Child Zone weight scale.')
|
|
|
|
def do_zone(cs, args):
|
|
|
|
"""Show or edit a child zone. No zone arg for this zone."""
|
|
|
|
zone = cs.zones.get(args.zone)
|
|
|
|
|
|
|
|
# If we have some flags, update the zone
|
|
|
|
zone_delta = {}
|
|
|
|
if args.api_url:
|
|
|
|
zone_delta['api_url'] = args.api_url
|
|
|
|
if args.zone_username:
|
|
|
|
zone_delta['username'] = args.zone_username
|
2011-11-09 07:10:46 -08:00
|
|
|
if args.zone_password:
|
|
|
|
zone_delta['password'] = args.zone_password
|
2011-08-04 17:07:22 -04:00
|
|
|
if args.weight_offset:
|
|
|
|
zone_delta['weight_offset'] = args.weight_offset
|
|
|
|
if args.weight_scale:
|
|
|
|
zone_delta['weight_scale'] = args.weight_scale
|
|
|
|
if zone_delta:
|
|
|
|
zone.update(**zone_delta)
|
|
|
|
else:
|
|
|
|
utils.print_dict(zone._info)
|
|
|
|
|
2011-08-06 00:41:48 -07:00
|
|
|
|
2011-08-04 17:07:22 -04:00
|
|
|
def do_zone_info(cs, args):
|
|
|
|
"""Get this zones name and capabilities."""
|
|
|
|
zone = cs.zones.info()
|
|
|
|
utils.print_dict(zone._info)
|
|
|
|
|
2011-08-06 00:41:48 -07:00
|
|
|
|
2011-08-30 07:13:44 -07:00
|
|
|
@utils.arg('zone_name', metavar='<zone_name>',
|
|
|
|
help='Name of the child zone being added.')
|
|
|
|
@utils.arg('api_url', metavar='<api_url>', help="URL for the Zone's Auth API")
|
2011-08-26 15:20:02 -05:00
|
|
|
@utils.arg('--zone_username', metavar='<zone_username>',
|
|
|
|
help='Optional Authentication username. (Default=None)',
|
|
|
|
default=None)
|
2011-11-09 07:10:46 -08:00
|
|
|
@utils.arg('--zone_password', metavar='<zone_password>',
|
2011-08-26 15:20:02 -05:00
|
|
|
help='Authentication password. (Default=None)',
|
|
|
|
default=None)
|
|
|
|
@utils.arg('--weight_offset', metavar='<weight_offset>',
|
|
|
|
help='Child Zone weight offset (Default=0.0))',
|
|
|
|
default=0.0)
|
|
|
|
@utils.arg('--weight_scale', metavar='<weight_scale>',
|
|
|
|
help='Child Zone weight scale (Default=1.0).',
|
|
|
|
default=1.0)
|
2011-08-04 17:07:22 -04:00
|
|
|
def do_zone_add(cs, args):
|
|
|
|
"""Add a new child zone."""
|
2011-08-30 07:13:44 -07:00
|
|
|
zone = cs.zones.create(args.zone_name, args.api_url,
|
2011-11-09 07:10:46 -08:00
|
|
|
args.zone_username, args.zone_password,
|
2011-08-30 07:13:44 -07:00
|
|
|
args.weight_offset, args.weight_scale)
|
2011-08-04 17:07:22 -04:00
|
|
|
utils.print_dict(zone._info)
|
|
|
|
|
2011-08-06 00:41:48 -07:00
|
|
|
|
2011-08-04 17:07:22 -04:00
|
|
|
@utils.arg('zone', metavar='<zone>', help='Name or ID of the zone')
|
|
|
|
def do_zone_delete(cs, args):
|
|
|
|
"""Delete a zone."""
|
|
|
|
cs.zones.delete(args.zone)
|
|
|
|
|
2011-08-06 00:41:48 -07:00
|
|
|
|
2011-08-04 17:07:22 -04:00
|
|
|
def do_zone_list(cs, args):
|
|
|
|
"""List the children of a zone."""
|
|
|
|
utils.print_list(cs.zones.list(), ['ID', 'Name', 'Is Active', \
|
|
|
|
'API URL', 'Weight Offset', 'Weight Scale'])
|
|
|
|
|
2011-08-06 00:41:48 -07:00
|
|
|
|
2011-08-04 17:07:22 -04:00
|
|
|
@utils.arg('server', metavar='<server>', help='Name or ID of server.')
|
|
|
|
@utils.arg('network_id', metavar='<network_id>', 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)
|
|
|
|
|
2011-08-06 00:41:48 -07:00
|
|
|
|
2011-08-04 17:07:22 -04:00
|
|
|
@utils.arg('server', metavar='<server>', help='Name or ID of server.')
|
|
|
|
@utils.arg('address', metavar='<address>', 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)
|
2011-09-29 08:09:50 -07:00
|
|
|
|
|
|
|
|
|
|
|
def _find_volume(cs, volume):
|
|
|
|
"""Get a volume by ID."""
|
|
|
|
return utils.find_resource(cs.volumes, volume)
|
|
|
|
|
2011-11-09 10:36:16 -08:00
|
|
|
|
|
|
|
def _find_volume_snapshot(cs, snapshot):
|
|
|
|
"""Get a volume snapshot by ID."""
|
|
|
|
return utils.find_resource(cs.volume_snapshots, snapshot)
|
|
|
|
|
2011-09-29 08:09:50 -07:00
|
|
|
|
|
|
|
def _print_volume(cs, volume):
|
|
|
|
utils.print_dict(volume._info)
|
|
|
|
|
|
|
|
|
2011-11-09 10:36:16 -08:00
|
|
|
def _print_volume_snapshot(cs, snapshot):
|
2011-10-19 10:54:27 -07:00
|
|
|
utils.print_dict(snapshot._info)
|
|
|
|
|
|
|
|
|
2011-09-29 08:09:50 -07:00
|
|
|
def _translate_volume_keys(collection):
|
|
|
|
convert = [('displayName', 'display_name')]
|
|
|
|
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])
|
|
|
|
|
|
|
|
|
2011-11-09 10:36:16 -08:00
|
|
|
def _translate_volume_snapshot_keys(collection):
|
2011-10-19 10:54:27 -07:00
|
|
|
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])
|
|
|
|
|
|
|
|
|
2011-09-29 08:09:50 -07:00
|
|
|
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 = [server.get('serverId') for server in vol.attachments]
|
|
|
|
setattr(vol, 'attached_to', ','.join(map(str, servers)))
|
|
|
|
utils.print_list(volumes, ['ID', 'Status', 'Display Name',
|
|
|
|
'Size', 'Attached to'])
|
|
|
|
|
|
|
|
|
|
|
|
@utils.arg('volume', metavar='<volume>', help='ID of the volume.')
|
|
|
|
def do_volume_show(cs, args):
|
|
|
|
"""Show details about a volume."""
|
|
|
|
volume = _find_volume(cs, args.volume)
|
|
|
|
_print_volume(cs, volume)
|
|
|
|
|
|
|
|
|
|
|
|
@utils.arg('size',
|
|
|
|
metavar='<size>',
|
|
|
|
type=int,
|
|
|
|
help='Size of volume in GB')
|
2011-10-19 08:31:16 -07:00
|
|
|
@utils.arg('--snapshot_id',
|
|
|
|
metavar='<snapshot_id>',
|
|
|
|
help='Optional snapshot id to create the volume from. (Default=None)',
|
|
|
|
default=None)
|
2011-09-29 08:09:50 -07:00
|
|
|
@utils.arg('--display_name', metavar='<display_name>',
|
|
|
|
help='Optional volume name. (Default=None)',
|
|
|
|
default=None)
|
|
|
|
@utils.arg('--display_description', metavar='<display_description>',
|
|
|
|
help='Optional volume description. (Default=None)',
|
|
|
|
default=None)
|
|
|
|
def do_volume_create(cs, args):
|
|
|
|
"""Add a new volume."""
|
2011-10-19 08:31:16 -07:00
|
|
|
cs.volumes.create(args.size,
|
|
|
|
args.snapshot_id,
|
|
|
|
args.display_name,
|
|
|
|
args.display_description)
|
2011-09-29 08:09:50 -07:00
|
|
|
|
|
|
|
|
|
|
|
@utils.arg('volume', metavar='<volume>', help='ID of the volume to delete.')
|
|
|
|
def do_volume_delete(cs, args):
|
|
|
|
"""Remove a volume."""
|
|
|
|
volume = _find_volume(cs, args.volume)
|
|
|
|
volume.delete()
|
|
|
|
|
|
|
|
|
|
|
|
@utils.arg('server',
|
|
|
|
metavar='<server>',
|
|
|
|
help='Name or ID of server.')
|
|
|
|
@utils.arg('volume',
|
|
|
|
metavar='<volume>',
|
|
|
|
type=int,
|
|
|
|
help='ID of the volume to attach.')
|
|
|
|
@utils.arg('device', metavar='<device>',
|
|
|
|
help='Name of the device e.g. /dev/vdb.')
|
|
|
|
def do_volume_attach(cs, args):
|
|
|
|
"""Attach a volume to a server."""
|
2011-10-16 15:21:53 -07:00
|
|
|
cs.volumes.create_server_volume(_find_server(cs, args.server).id,
|
|
|
|
args.volume,
|
|
|
|
args.device)
|
2011-09-29 08:09:50 -07:00
|
|
|
|
|
|
|
|
|
|
|
@utils.arg('server',
|
|
|
|
metavar='<server>',
|
|
|
|
help='Name or ID of server.')
|
|
|
|
@utils.arg('attachment_id',
|
|
|
|
metavar='<volume>',
|
|
|
|
type=int,
|
|
|
|
help='Attachment ID of the volume.')
|
|
|
|
def do_volume_detach(cs, args):
|
|
|
|
"""Detach a volume from a server."""
|
2011-10-16 15:21:53 -07:00
|
|
|
cs.volumes.delete_server_volume(_find_server(cs, args.server).id,
|
|
|
|
args.attachment_id)
|
2011-10-16 15:27:25 -07:00
|
|
|
|
2011-11-16 08:47:37 -08:00
|
|
|
|
2011-11-09 10:36:16 -08:00
|
|
|
def do_volume_snapshot_list(cs, args):
|
2011-10-19 10:54:27 -07:00
|
|
|
"""List all the snapshots."""
|
2011-11-09 10:36:16 -08:00
|
|
|
snapshots = cs.volume_snapshots.list()
|
|
|
|
_translate_volume_snapshot_keys(snapshots)
|
2011-10-19 10:54:27 -07:00
|
|
|
utils.print_list(snapshots, ['ID', 'Volume ID', 'Status', 'Display Name',
|
|
|
|
'Size'])
|
|
|
|
|
|
|
|
|
|
|
|
@utils.arg('snapshot', metavar='<snapshot>', help='ID of the snapshot.')
|
2011-11-09 10:36:16 -08:00
|
|
|
def do_volume_snapshot_show(cs, args):
|
2011-10-19 10:54:27 -07:00
|
|
|
"""Show details about a snapshot."""
|
2011-11-09 10:36:16 -08:00
|
|
|
snapshot = _find_volume_snapshot(cs, args.snapshot)
|
|
|
|
_print_volume_snapshot(cs, snapshot)
|
2011-10-19 10:54:27 -07:00
|
|
|
|
|
|
|
|
|
|
|
@utils.arg('volume_id',
|
|
|
|
metavar='<volume_id>',
|
|
|
|
type=int,
|
|
|
|
help='ID of the volume to snapshot')
|
|
|
|
@utils.arg('--force',
|
2011-11-09 10:36:16 -08:00
|
|
|
metavar='<True|False>',
|
2011-10-19 10:54:27 -07:00
|
|
|
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='<display_name>',
|
|
|
|
help='Optional snapshot name. (Default=None)',
|
|
|
|
default=None)
|
|
|
|
@utils.arg('--display_description', metavar='<display_description>',
|
|
|
|
help='Optional snapshot description. (Default=None)',
|
|
|
|
default=None)
|
2011-11-09 10:36:16 -08:00
|
|
|
def do_volume_snapshot_create(cs, args):
|
2011-10-19 10:54:27 -07:00
|
|
|
"""Add a new snapshot."""
|
2011-11-09 10:36:16 -08:00
|
|
|
cs.volume_snapshots.create(args.volume_id,
|
2011-10-19 10:54:27 -07:00
|
|
|
args.force,
|
|
|
|
args.display_name,
|
|
|
|
args.display_description)
|
|
|
|
|
|
|
|
|
|
|
|
@utils.arg('snapshot_id',
|
|
|
|
metavar='<snapshot_id>',
|
|
|
|
help='ID of the snapshot to delete.')
|
2011-11-09 10:36:16 -08:00
|
|
|
def do_volume_snapshot_delete(cs, args):
|
2011-10-19 10:54:27 -07:00
|
|
|
"""Remove a snapshot."""
|
2011-11-09 10:36:16 -08:00
|
|
|
snapshot = _find_volume_snapshot(cs, args.snapshot_id)
|
2011-10-19 10:54:27 -07:00
|
|
|
snapshot.delete()
|
|
|
|
|
|
|
|
|
2011-10-11 07:54:33 +00:00
|
|
|
def _print_floating_ip_list(floating_ips):
|
|
|
|
utils.print_list(floating_ips, ['Ip', 'Instance Id', 'Fixed Ip'])
|
|
|
|
|
|
|
|
|
2011-10-11 04:07:08 +00:00
|
|
|
@utils.arg('server', metavar='<server>', help='Name or ID of server.')
|
|
|
|
@utils.arg('address', metavar='<address>', 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='<server>', help='Name or ID of server.')
|
|
|
|
@utils.arg('address', metavar='<address>', 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)
|
|
|
|
|
|
|
|
|
|
|
|
def do_floating_ip_create(cs, args):
|
|
|
|
"""Allocate a floating IP for the current tenant."""
|
2011-10-11 07:54:33 +00:00
|
|
|
_print_floating_ip_list([cs.floating_ips.create()])
|
2011-10-11 04:07:08 +00:00
|
|
|
|
|
|
|
|
|
|
|
@utils.arg('address', metavar='<address>', 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)
|
2011-10-11 04:18:30 +00:00
|
|
|
raise exceptions.CommandError("Floating ip %s not found.", args.address)
|
2011-10-11 04:07:08 +00:00
|
|
|
|
|
|
|
|
|
|
|
def do_floating_ip_list(cs, args):
|
|
|
|
"""List floating ips for this tenant."""
|
2011-10-11 07:54:33 +00:00
|
|
|
_print_floating_ip_list(cs.floating_ips.list())
|
2011-10-14 17:43:57 +00:00
|
|
|
|
|
|
|
|
2011-10-11 08:24:14 +00:00
|
|
|
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':
|
2011-10-11 22:10:23 +00:00
|
|
|
v = v.get('cidr')
|
|
|
|
elif k == 'group':
|
|
|
|
k = 'source_group'
|
|
|
|
v = v.get('name')
|
|
|
|
if v == None:
|
|
|
|
v = ''
|
|
|
|
|
2011-10-11 08:24:14 +00:00
|
|
|
setattr(self, k, v)
|
|
|
|
|
|
|
|
rules = [FormattedRule(rule) for rule in rules]
|
2011-10-11 22:10:23 +00:00
|
|
|
utils.print_list(rules, ['IP Protocol', 'From Port', 'To Port',
|
|
|
|
'IP Range', 'Source Group'])
|
2011-10-11 08:24:14 +00:00
|
|
|
|
|
|
|
|
|
|
|
def _print_secgroups(secgroups):
|
2011-10-11 20:40:01 +00:00
|
|
|
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)
|
2011-10-11 08:24:14 +00:00
|
|
|
|
|
|
|
|
2011-10-11 07:48:55 +00:00
|
|
|
@utils.arg('secgroup', metavar='<secgroup>', help='ID of security group.')
|
|
|
|
@utils.arg('ip_proto', metavar='<ip_proto>', help='ip_proto (icmp, tcp, udp).')
|
|
|
|
@utils.arg('from_port', metavar='<from_port>', help='Port at start of range.')
|
|
|
|
@utils.arg('to_port', metavar='<to_port>', help='Port at end of range.')
|
2011-10-11 20:40:01 +00:00
|
|
|
@utils.arg('cidr', metavar='<cidr>', help='CIDR for address range.')
|
2011-10-11 07:48:55 +00:00
|
|
|
def do_secgroup_add_rule(cs, args):
|
|
|
|
"""Add a rule to a security group."""
|
2011-10-11 22:10:23 +00:00
|
|
|
secgroup = _get_secgroup(cs, args.secgroup)
|
2011-10-11 20:40:01 +00:00
|
|
|
rule = cs.security_group_rules.create(secgroup.id,
|
2011-10-11 07:48:55 +00:00
|
|
|
args.ip_proto,
|
|
|
|
args.from_port,
|
|
|
|
args.to_port,
|
2011-10-11 20:40:01 +00:00
|
|
|
args.cidr)
|
2011-10-11 07:48:55 +00:00
|
|
|
_print_secgroup_rules([rule])
|
|
|
|
|
|
|
|
|
|
|
|
@utils.arg('secgroup', metavar='<secgroup>', help='ID of security group.')
|
|
|
|
@utils.arg('ip_proto', metavar='<ip_proto>', help='ip_proto (icmp, tcp, udp).')
|
|
|
|
@utils.arg('from_port', metavar='<from_port>', help='Port at start of range.')
|
|
|
|
@utils.arg('to_port', metavar='<to_port>', help='Port at end of range.')
|
2011-10-11 20:40:01 +00:00
|
|
|
@utils.arg('cidr', metavar='<cidr>', help='CIDR for address range.')
|
2011-10-11 07:48:55 +00:00
|
|
|
def do_secgroup_delete_rule(cs, args):
|
|
|
|
"""Delete a rule from a security group."""
|
|
|
|
|
2011-10-11 22:10:23 +00:00
|
|
|
secgroup = _get_secgroup(cs, args.secgroup)
|
2011-10-11 07:48:55 +00:00
|
|
|
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='<name>', help='Name of security group.')
|
|
|
|
@utils.arg('description', metavar='<description>',
|
|
|
|
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)])
|
|
|
|
|
|
|
|
|
2011-10-11 20:40:01 +00:00
|
|
|
@utils.arg('secgroup', metavar='<secgroup>', help='Name of security group.')
|
2011-10-11 07:48:55 +00:00
|
|
|
def do_secgroup_delete(cs, args):
|
|
|
|
"""Delete a security group."""
|
2011-10-11 20:40:01 +00:00
|
|
|
cs.security_groups.delete(_get_secgroup(cs, args.secgroup))
|
2011-10-11 07:48:55 +00:00
|
|
|
|
|
|
|
|
|
|
|
def do_secgroup_list(cs, args):
|
|
|
|
"""List security groups for the curent tenant."""
|
|
|
|
_print_secgroups(cs.security_groups.list())
|
|
|
|
|
|
|
|
|
2011-10-11 20:40:01 +00:00
|
|
|
@utils.arg('secgroup', metavar='<secgroup>', help='Name of security group.')
|
2011-10-11 07:48:55 +00:00
|
|
|
def do_secgroup_list_rules(cs, args):
|
|
|
|
"""List rules for a security group."""
|
2011-10-11 20:40:01 +00:00
|
|
|
secgroup = _get_secgroup(cs, args.secgroup)
|
2011-10-11 08:24:14 +00:00
|
|
|
_print_secgroup_rules(secgroup.rules)
|
2011-10-11 22:10:23 +00:00
|
|
|
|
|
|
|
|
|
|
|
@utils.arg('secgroup', metavar='<secgroup>', help='ID of security group.')
|
|
|
|
@utils.arg('source_group', metavar='<source_group>',
|
|
|
|
help='ID of source group.')
|
|
|
|
@utils.arg('--ip_proto', metavar='<ip_proto>',
|
|
|
|
help='ip_proto (icmp, tcp, udp).')
|
|
|
|
@utils.arg('--from_port', metavar='<from_port>',
|
|
|
|
help='Port at start of range.')
|
|
|
|
@utils.arg('--to_port', metavar='<to_port>', 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='<secgroup>', help='ID of security group.')
|
|
|
|
@utils.arg('source_group', metavar='<source_group>',
|
|
|
|
help='ID of source group.')
|
|
|
|
@utils.arg('--ip_proto', metavar='<ip_proto>',
|
|
|
|
help='ip_proto (icmp, tcp, udp).')
|
|
|
|
@utils.arg('--from_port', metavar='<from_port>',
|
|
|
|
help='Port at start of range.')
|
|
|
|
@utils.arg('--to_port', metavar='<to_port>', 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")
|
2011-10-17 14:09:25 -07:00
|
|
|
|
|
|
|
|
2011-10-05 16:25:31 +04:00
|
|
|
@utils.arg('name', metavar='<name>', help='Name of key.')
|
2011-10-25 09:34:23 -07:00
|
|
|
@utils.arg('--pub_key', metavar='<pub_key>', help='Path to a public ssh key.',
|
|
|
|
default=None)
|
2011-10-05 16:25:31 +04:00
|
|
|
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:
|
2011-10-25 09:34:23 -07:00
|
|
|
raise exceptions.CommandError("Can't open or read '%s': %s" % \
|
|
|
|
(pub_key, e))
|
2011-10-19 10:54:27 -07:00
|
|
|
|
2011-10-05 16:25:31 +04:00
|
|
|
keypair = cs.keypairs.create(name, pub_key)
|
|
|
|
|
|
|
|
if not pub_key:
|
|
|
|
private_key = keypair.private_key
|
|
|
|
print private_key
|
|
|
|
|
|
|
|
|
|
|
|
@utils.arg('name', metavar='<name>', 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)
|
2011-12-06 12:11:50 -05:00
|
|
|
|
|
|
|
|
|
|
|
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)
|