1103
class VsaCommands(object):
1104
"""Methods for dealing with VSAs"""
1106
def __init__(self, *args, **kwargs):
1107
self.manager = manager.AuthManager()
1108
self.vsa_api = vsa.API()
1109
self.context = context.get_admin_context()
1111
self._format_str_vsa = "%(id)-5s %(vsa_id)-15s %(name)-25s "\
1112
"%(type)-10s %(vcs)-6s %(drives)-9s %(stat)-10s "\
1113
"%(az)-10s %(time)-10s"
1114
self._format_str_volume = "\t%(id)-4s %(name)-15s %(size)-5s "\
1115
"%(stat)-10s %(att)-20s %(time)s"
1116
self._format_str_drive = "\t%(id)-4s %(name)-15s %(size)-5s "\
1117
"%(stat)-10s %(host)-20s %(type)-4s %(tname)-10s %(time)s"
1118
self._format_str_instance = "\t%(id)-4s %(name)-10s %(dname)-20s "\
1119
"%(image)-12s %(type)-10s %(fl_ip)-15s %(fx_ip)-15s "\
1120
"%(stat)-10s %(host)-15s %(time)s"
1122
def _print_vsa_header(self):
1123
print self._format_str_vsa %\
1126
name=_('displayName'),
1129
drives=_('drive_cnt'),
1132
time=_('createTime'))
1134
def _print_vsa(self, vsa):
1135
print self._format_str_vsa %\
1138
name=vsa['display_name'],
1139
type=vsa['vsa_instance_type'].get('name', None),
1140
vcs=vsa['vc_count'],
1141
drives=vsa['vol_count'],
1143
az=vsa['availability_zone'],
1144
time=str(vsa['created_at']))
1146
def _print_volume_header(self):
1147
print _(' === Volumes ===')
1148
print self._format_str_volume %\
1153
att=_('attachment'),
1154
time=_('createTime'))
1156
def _print_volume(self, vol):
1157
print self._format_str_volume %\
1159
name=vol['display_name'] or vol['name'],
1162
att=vol['attach_status'],
1163
time=str(vol['created_at']))
1165
def _print_drive_header(self):
1166
print _(' === Drives ===')
1167
print self._format_str_drive %\
1174
tname=_('typeName'),
1175
time=_('createTime'))
1177
def _print_drive(self, drive):
1178
if drive['volume_type_id'] is not None and drive.get('volume_type'):
1179
drive_type_name = drive['volume_type'].get('name')
1181
drive_type_name = ''
1183
print self._format_str_drive %\
1184
dict(id=drive['id'],
1185
name=drive['display_name'],
1187
stat=drive['status'],
1189
type=drive['volume_type_id'],
1190
tname=drive_type_name,
1191
time=str(drive['created_at']))
1193
def _print_instance_header(self):
1194
print _(' === Instances ===')
1195
print self._format_str_instance %\
1198
dname=_('disp_name'),
1201
fl_ip=_('floating_IP'),
1202
fx_ip=_('fixed_IP'),
1205
time=_('createTime'))
1207
def _print_instance(self, vc):
1210
floating_addr = None
1212
fixed = vc['fixed_ips'][0]
1213
fixed_addr = fixed['address']
1214
if fixed['floating_ips']:
1215
floating_addr = fixed['floating_ips'][0]['address']
1216
floating_addr = floating_addr or fixed_addr
1218
print self._format_str_instance %\
1220
name=ec2utils.id_to_ec2_id(vc['id']),
1221
dname=vc['display_name'],
1222
image=('ami-%08x' % int(vc['image_ref'])),
1223
type=vc['instance_type']['name'],
1224
fl_ip=floating_addr,
1226
stat=vc['state_description'],
1228
time=str(vc['created_at']))
1230
def _list(self, context, vsas, print_drives=False,
1231
print_volumes=False, print_instances=False):
1233
self._print_vsa_header()
1236
self._print_vsa(vsa)
1237
vsa_id = vsa.get('id')
1240
instances = self.vsa_api.get_all_vsa_instances(context, vsa_id)
1243
self._print_instance_header()
1244
for instance in instances:
1245
self._print_instance(instance)
1249
drives = self.vsa_api.get_all_vsa_drives(context, vsa_id)
1251
self._print_drive_header()
1252
for drive in drives:
1253
self._print_drive(drive)
1257
volumes = self.vsa_api.get_all_vsa_volumes(context, vsa_id)
1259
self._print_volume_header()
1260
for volume in volumes:
1261
self._print_volume(volume)
1264
@args('--storage', dest='storage',
1265
metavar="[{'drive_name': 'type', 'num_drives': N, 'size': M},..]",
1266
help='Initial storage allocation for VSA')
1267
@args('--name', dest='name', metavar="<name>", help='VSA name')
1268
@args('--description', dest='description', metavar="<description>",
1269
help='VSA description')
1270
@args('--vc', dest='vc_count', metavar="<number>", help='Number of VCs')
1271
@args('--instance_type', dest='instance_type_name', metavar="<name>",
1272
help='Instance type name')
1273
@args('--image', dest='image_name', metavar="<name>", help='Image name')
1274
@args('--shared', dest='shared', action="store_true", default=False,
1275
help='Use shared drives')
1276
@args('--az', dest='az', metavar="<zone:host>", help='Availability zone')
1277
@args('--user', dest="user_id", metavar='<User name>',
1279
@args('--project', dest="project_id", metavar='<Project name>',
1280
help='Project name')
1281
def create(self, storage='[]', name=None, description=None, vc_count=1,
1282
instance_type_name=None, image_name=None, shared=None,
1283
az=None, user_id=None, project_id=None):
1286
if project_id is None:
1288
project_id = os.getenv("EC2_ACCESS_KEY").split(':')[1]
1289
except Exception as exc:
1290
print _("Failed to retrieve project id: %(exc)s") % exc
1295
project = self.manager.get_project(project_id)
1296
user_id = project.project_manager_id
1297
except Exception as exc:
1298
print _("Failed to retrieve user info: %(exc)s") % exc
1301
is_admin = self.manager.is_admin(user_id)
1302
ctxt = context.RequestContext(user_id, project_id, is_admin)
1303
if not is_admin and \
1304
not self.manager.is_project_member(user_id, project_id):
1305
msg = _("%(user_id)s must be an admin or a "
1306
"member of %(project_id)s")
1307
LOG.warn(msg % locals())
1308
raise ValueError(msg % locals())
1310
# Sanity check for storage string
1312
if storage is not None:
1314
storage_list = ast.literal_eval(storage)
1316
print _("Invalid string format %s") % storage
1319
for node in storage_list:
1320
if ('drive_name' not in node) or ('num_drives' not in node):
1321
print (_("Invalid string format for element %s. " \
1322
"Expecting keys 'drive_name' & 'num_drives'"),
1326
if instance_type_name == '':
1327
instance_type_name = None
1328
instance_type = instance_types.get_instance_type_by_name(
1331
if image_name == '':
1334
if shared in [None, False, "--full_drives"]:
1336
elif shared in [True, "--shared"]:
1339
raise ValueError(_('Shared parameter should be set either to "\
1340
"--shared or --full_drives'))
1343
'display_name': name,
1344
'display_description': description,
1345
'vc_count': int(vc_count),
1346
'instance_type': instance_type,
1347
'image_name': image_name,
1348
'availability_zone': az,
1349
'storage': storage_list,
1353
result = self.vsa_api.create(ctxt, **values)
1354
self._list(ctxt, [result])
1356
@args('--id', dest='vsa_id', metavar="<vsa_id>", help='VSA ID')
1357
@args('--name', dest='name', metavar="<name>", help='VSA name')
1358
@args('--description', dest='description', metavar="<description>",
1359
help='VSA description')
1360
@args('--vc', dest='vc_count', metavar="<number>", help='Number of VCs')
1361
def update(self, vsa_id, name=None, description=None, vc_count=None):
1362
"""Updates name/description of vsa and number of VCs."""
1365
if name is not None:
1366
values['display_name'] = name
1367
if description is not None:
1368
values['display_description'] = description
1369
if vc_count is not None:
1370
values['vc_count'] = int(vc_count)
1372
vsa_id = ec2utils.ec2_id_to_id(vsa_id)
1373
result = self.vsa_api.update(self.context, vsa_id=vsa_id, **values)
1374
self._list(self.context, [result])
1376
@args('--id', dest='vsa_id', metavar="<vsa_id>", help='VSA ID')
1377
def delete(self, vsa_id):
1379
vsa_id = ec2utils.ec2_id_to_id(vsa_id)
1380
self.vsa_api.delete(self.context, vsa_id)
1382
@args('--id', dest='vsa_id', metavar="<vsa_id>",
1383
help='VSA ID (optional)')
1384
@args('--all', dest='all', action="store_true", default=False,
1385
help='Show all available details')
1386
@args('--drives', dest='drives', action="store_true",
1387
help='Include drive-level details')
1388
@args('--volumes', dest='volumes', action="store_true",
1389
help='Include volume-level details')
1390
@args('--instances', dest='instances', action="store_true",
1391
help='Include instance-level details')
1392
def list(self, vsa_id=None, all=False,
1393
drives=False, volumes=False, instances=False):
1394
"""Describe all available VSAs (or particular one)."""
1397
if vsa_id is not None:
1398
internal_id = ec2utils.ec2_id_to_id(vsa_id)
1399
vsa = self.vsa_api.get(self.context, internal_id)
1402
vsas = self.vsa_api.get_all(self.context)
1405
drives = volumes = instances = True
1407
self._list(self.context, vsas, drives, volumes, instances)
1409
def update_capabilities(self):
1410
"""Forces updates capabilities on all nova-volume nodes."""
1412
rpc.fanout_cast(context.get_admin_context(),
1414
{"method": "notification",
1415
"args": {"event": "startup"}})
1418
class VsaDriveTypeCommands(object):
1419
"""Methods for dealing with VSA drive types"""
1421
def __init__(self, *args, **kwargs):
1422
super(VsaDriveTypeCommands, self).__init__(*args, **kwargs)
1423
self.context = context.get_admin_context()
1424
self._drive_type_template = '%s_%sGB_%sRPM'
1426
def _list(self, drives):
1427
format_str = "%-5s %-30s %-10s %-10s %-10s %-20s %-10s %s"
1439
for name, vol_type in drives.iteritems():
1440
drive = vol_type.get('extra_specs')
1442
(str(vol_type['id']),
1443
drive['drive_name'],
1444
drive['drive_type'],
1445
drive['drive_size'],
1447
drive.get('capabilities', ''),
1448
str(drive.get('visible', '')),
1449
str(vol_type['created_at']))
1451
@args('--type', dest='type', metavar="<type>",
1452
help='Drive type (SATA, SAS, SSD, etc.)')
1453
@args('--size', dest='size_gb', metavar="<gb>", help='Drive size in GB')
1454
@args('--rpm', dest='rpm', metavar="<rpm>", help='RPM')
1455
@args('--capabilities', dest='capabilities', default=None,
1456
metavar="<string>", help='Different capabilities')
1457
@args('--hide', dest='hide', action="store_true", default=False,
1458
help='Show or hide drive')
1459
@args('--name', dest='name', metavar="<name>", help='Drive name')
1460
def create(self, type, size_gb, rpm, capabilities=None,
1461
hide=False, name=None):
1462
"""Create drive type."""
1464
hide = True if hide in [True, "True", "--hide", "hide"] else False
1467
name = self._drive_type_template % (type, size_gb, rpm)
1469
extra_specs = {'type': 'vsa_drive',
1472
'drive_size': size_gb,
1477
extra_specs['visible'] = False
1479
if capabilities is not None and capabilities != '':
1480
extra_specs['capabilities'] = capabilities
1482
volume_types.create(self.context, name, extra_specs)
1483
result = volume_types.get_volume_type_by_name(self.context, name)
1484
self._list({name: result})
1486
@args('--name', dest='name', metavar="<name>", help='Drive name')
1487
@args('--purge', action="store_true", dest='purge', default=False,
1488
help='purge record from database')
1489
def delete(self, name, purge):
1490
"""Marks instance types / flavors as deleted"""
1493
volume_types.purge(self.context, name)
1496
volume_types.destroy(self.context, name)
1498
except exception.ApiError:
1499
print "Valid volume type name is required"
1501
except exception.DBError, e:
1502
print "DB Error: %s" % e
1507
print "%s %s" % (name, verb)
1509
@args('--all', dest='all', action="store_true", default=False,
1510
help='Show all drives (including invisible)')
1511
@args('--name', dest='name', metavar="<name>",
1512
help='Show only specified drive')
1513
def list(self, all=False, name=None):
1514
"""Describe all available VSA drive types (or particular one)."""
1516
all = False if all in ["--all", False, "False"] else True
1518
search_opts = {'extra_specs': {'type': 'vsa_drive'}}
1519
if name is not None:
1520
search_opts['extra_specs']['name'] = name
1523
search_opts['extra_specs']['visible'] = '1'
1525
drives = volume_types.get_all_types(self.context,
1526
search_opts=search_opts)
1529
@args('--name', dest='name', metavar="<name>", help='Drive name')
1530
@args('--type', dest='type', metavar="<type>",
1531
help='Drive type (SATA, SAS, SSD, etc.)')
1532
@args('--size', dest='size_gb', metavar="<gb>", help='Drive size in GB')
1533
@args('--rpm', dest='rpm', metavar="<rpm>", help='RPM')
1534
@args('--capabilities', dest='capabilities', default=None,
1535
metavar="<string>", help='Different capabilities')
1536
@args('--visible', dest='visible',
1537
metavar="<show|hide>", help='Show or hide drive')
1538
def update(self, name, type=None, size_gb=None, rpm=None,
1539
capabilities=None, visible=None):
1540
"""Update drive type."""
1542
volume_type = volume_types.get_volume_type_by_name(self.context, name)
1544
extra_specs = {'type': 'vsa_drive'}
1547
extra_specs['drive_type'] = type
1550
extra_specs['drive_size'] = size_gb
1553
extra_specs['drive_rpm'] = rpm
1556
extra_specs['capabilities'] = capabilities
1558
if visible is not None:
1559
if visible in ["show", True, "True"]:
1560
extra_specs['visible'] = True
1561
elif visible in ["hide", False, "False"]:
1562
extra_specs['visible'] = False
1564
raise ValueError(_('visible parameter should be set to '\
1567
db.api.volume_type_extra_specs_update_or_create(self.context,
1570
result = volume_types.get_volume_type_by_name(self.context, name)
1571
self._list({name: result})
1100
1574
class VolumeCommands(object):
1101
1575
"""Methods for dealing with a cloud in an odd state"""