414
302
def __init__(self):
415
303
self.manager = manager.AuthManager()
417
@args('--project', dest="project_id", metavar='<Project name>',
419
@args('--user', dest="user_id", metavar='<name>', help='User name')
420
305
def add(self, project_id, user_id):
421
"""Adds user to project"""
423
self.manager.add_to_project(user_id, project_id)
424
except exception.UserNotFound as ex:
306
"""Adds user to project
307
arguments: project_id user_id"""
308
self.manager.add_to_project(user_id, project_id)
428
@args('--project', dest="name", metavar='<Project name>',
430
@args('--user', dest="project_manager", metavar='<user>',
431
help='Project manager')
432
@args('--desc', dest="description", metavar='<description>',
434
310
def create(self, name, project_manager, description=None):
435
"""Creates a new project"""
437
self.manager.create_project(name, project_manager, description)
438
except exception.UserNotFound as ex:
442
@args('--project', dest="name", metavar='<Project name>',
444
@args('--user', dest="project_manager", metavar='<user>',
445
help='Project manager')
446
@args('--desc', dest="description", metavar='<description>',
448
def modify(self, name, project_manager, description=None):
449
"""Modifies a project"""
451
self.manager.modify_project(name, project_manager, description)
452
except exception.UserNotFound as ex:
456
@args('--project', dest="name", metavar='<Project name>',
311
"""Creates a new project
312
arguments: name project_manager [description]"""
313
self.manager.create_project(name, project_manager, description)
458
315
def delete(self, name):
459
"""Deletes an existing project"""
461
self.manager.delete_project(name)
462
except exception.ProjectNotFound as ex:
316
"""Deletes an existing project
318
self.manager.delete_project(name)
466
@args('--project', dest="project_id", metavar='<Project name>',
468
@args('--user', dest="user_id", metavar='<name>', help='User name')
469
@args('--file', dest="filename", metavar='<filename>',
470
help='File name(Default: novarc)')
471
320
def environment(self, project_id, user_id, filename='novarc'):
472
"""Exports environment variables to an sourcable file"""
474
rc = self.manager.get_environment_rc(user_id, project_id)
475
except (exception.UserNotFound, exception.ProjectNotFound) as ex:
481
with open(filename, 'w') as f:
321
"""Exports environment variables to an sourcable file
322
arguments: project_id user_id [filename='novarc]"""
323
rc = self.manager.get_environment_rc(user_id, project_id)
324
with open(filename, 'w') as f:
484
@args('--user', dest="username", metavar='<username>', help='User name')
485
def list(self, username=None):
486
"""Lists all projects"""
487
for project in self.manager.get_projects(username):
328
"""Lists all projects
330
for project in self.manager.get_projects():
488
331
print project.name
490
@args('--project', dest="project_id", metavar='<Project name>',
492
@args('--key', dest="key", metavar='<key>', help='Key')
493
@args('--value', dest="value", metavar='<value>', help='Value')
494
333
def quota(self, project_id, key=None, value=None):
495
"""Set or display quotas for project"""
334
"""Set or display quotas for project
335
arguments: project_id [key] [value]"""
496
336
ctxt = context.get_admin_context()
498
if value.lower() == 'unlimited':
338
quo = {'project_id': project_id, key: value}
501
db.quota_update(ctxt, project_id, key, value)
502
except exception.ProjectQuotaNotFound:
503
db.quota_create(ctxt, project_id, key, value)
504
project_quota = quota.get_project_quotas(ctxt, project_id)
340
db.quota_update(ctxt, project_id, quo)
341
except exception.NotFound:
342
db.quota_create(ctxt, quo)
343
project_quota = quota.get_quota(ctxt, project_id)
505
344
for key, value in project_quota.iteritems():
508
345
print '%s: %s' % (key, value)
510
@args('--project', dest="project_id", metavar='<Project name>',
512
@args('--user', dest="user_id", metavar='<name>', help='User name')
513
347
def remove(self, project_id, user_id):
514
"""Removes user from project"""
516
self.manager.remove_from_project(user_id, project_id)
517
except (exception.UserNotFound, exception.ProjectNotFound) as ex:
348
"""Removes user from project
349
arguments: project_id user_id"""
350
self.manager.remove_from_project(user_id, project_id)
521
@args('--project', dest="project_id", metavar='<Project name>',
523
352
def scrub(self, project_id):
524
"""Deletes data associated with project"""
525
admin_context = context.get_admin_context()
526
networks = db.project_get_networks(admin_context, project_id)
527
for network in networks:
528
db.network_disassociate(admin_context, network['id'])
529
groups = db.security_group_get_by_project(admin_context, project_id)
353
"""Deletes data associated with project
354
arguments: project_id"""
355
ctxt = context.get_admin_context()
356
network_ref = db.project_get_network(ctxt, project_id)
357
db.network_disassociate(ctxt, network_ref['id'])
358
groups = db.security_group_get_by_project(ctxt, project_id)
530
359
for group in groups:
531
db.security_group_destroy(admin_context, group['id'])
360
db.security_group_destroy(ctxt, group['id'])
533
@args('--project', dest="project_id", metavar='<Project name>',
535
@args('--user', dest="user_id", metavar='<name>', help='User name')
536
@args('--file', dest="filename", metavar='<filename>',
537
help='File name(Default: nova.zip)')
538
362
def zipfile(self, project_id, user_id, filename='nova.zip'):
539
"""Exports credentials for project to a zip file"""
363
"""Exports credentials for project to a zip file
364
arguments: project_id user_id [filename='nova.zip]"""
541
366
zip_file = self.manager.get_credentials(user_id, project_id)
543
sys.stdout.write(zip_file)
545
with open(filename, 'w') as f:
547
except (exception.UserNotFound, exception.ProjectNotFound) as ex:
367
with open(filename, 'w') as f:
550
369
except db.api.NoMoreNetworks:
551
print _('No more networks available. If this is a new '
552
'installation, you need\nto call something like this:\n\n'
553
' nova-manage network create pvt 10.0.0.0/8 10 64\n\n')
554
except exception.ProcessExecutionError, e:
556
print _("The above error may show that the certificate db has "
557
"not been created.\nPlease create a database by running "
558
"a nova-api server on this host.")
560
AccountCommands = ProjectCommands
563
class FixedIpCommands(object):
564
"""Class for managing fixed ip."""
566
@args('--host', dest="host", metavar='<host>', help='Host')
567
def list(self, host=None):
568
"""Lists all fixed ips (optionally by host)"""
569
ctxt = context.get_admin_context()
573
fixed_ips = db.fixed_ip_get_all(ctxt)
575
fixed_ips = db.fixed_ip_get_all_by_instance_host(ctxt, host)
576
except exception.NotFound as ex:
577
print "error: %s" % ex
580
print "%-18s\t%-15s\t%-17s\t%-15s\t%s" % (_('network'),
585
for fixed_ip in fixed_ips:
589
if fixed_ip['instance']:
590
instance = fixed_ip['instance']
591
hostname = instance['hostname']
592
host = instance['host']
593
mac_address = fixed_ip['virtual_interface']['address']
594
print "%-18s\t%-15s\t%-17s\t%-15s\t%s" % (
595
fixed_ip['network']['cidr'],
597
mac_address, hostname, host)
599
@args('--address', dest="address", metavar='<ip address>',
601
def reserve(self, address):
602
"""Mark fixed ip as reserved
603
arguments: address"""
604
self._set_reserved(address, True)
606
@args('--address', dest="address", metavar='<ip address>',
608
def unreserve(self, address):
609
"""Mark fixed ip as free to use
610
arguments: address"""
611
self._set_reserved(address, False)
613
def _set_reserved(self, address, reserved):
614
ctxt = context.get_admin_context()
617
fixed_ip = db.fixed_ip_get_by_address(ctxt, address)
619
raise exception.NotFound('Could not find address')
620
db.fixed_ip_update(ctxt, fixed_ip['address'],
621
{'reserved': reserved})
622
except exception.NotFound as ex:
623
print "error: %s" % ex
370
print ('No more networks available. If this is a new '
371
'installation, you need\nto call something like this:\n\n'
372
' nova-manage network create 10.0.0.0/8 10 64\n\n')
627
375
class FloatingIpCommands(object):
628
376
"""Class for managing floating ip."""
630
@args('--ip_range', dest="range", metavar='<range>', help='IP range')
631
def create(self, range):
632
"""Creates floating ips for zone by range"""
633
for address in netaddr.IPNetwork(range):
378
def create(self, host, range):
379
"""Creates floating ips for host by range
380
arguments: host ip_range"""
381
for address in IPy.IP(range):
634
382
db.floating_ip_create(context.get_admin_context(),
635
{'address': str(address)})
383
{'address': str(address),
637
@args('--ip_range', dest="ip_range", metavar='<range>', help='IP range')
638
386
def delete(self, ip_range):
639
"""Deletes floating ips by range"""
640
for address in netaddr.IPNetwork(ip_range):
387
"""Deletes floating ips by range
389
for address in IPy.IP(ip_range):
641
390
db.floating_ip_destroy(context.get_admin_context(),
644
@args('--host', dest="host", metavar='<host>', help='Host')
645
393
def list(self, host=None):
646
394
"""Lists all floating ips (optionally by host)
647
Note: if host is given, only active floating IPs are returned"""
648
396
ctxt = context.get_admin_context()
650
398
floating_ips = db.floating_ip_get_all(ctxt)
652
400
floating_ips = db.floating_ip_get_all_by_host(ctxt, host)
653
401
for floating_ip in floating_ips:
655
403
if floating_ip['fixed_ip']:
656
instance = floating_ip['fixed_ip']['instance']['hostname']
404
instance = floating_ip['fixed_ip']['instance']['ec2_id']
657
405
print "%s\t%s\t%s" % (floating_ip['host'],
658
406
floating_ip['address'],
662
410
class NetworkCommands(object):
663
411
"""Class for managing networks."""
665
@args('--label', dest="label", metavar='<label>',
666
help='Label for network (ex: public)')
667
@args('--fixed_range_v4', dest="fixed_range_v4", metavar='<x.x.x.x/yy>',
668
help='IPv4 subnet (ex: 10.0.0.0/8)')
669
@args('--num_networks', dest="num_networks", metavar='<number>',
670
help='Number of networks to create')
671
@args('--network_size', dest="network_size", metavar='<number>',
672
help='Number of IPs per network')
673
@args('--vlan', dest="vlan_start", metavar='<vlan id>', help='vlan id')
674
@args('--vpn', dest="vpn_start", help='vpn start')
675
@args('--fixed_range_v6', dest="fixed_range_v6",
676
help='IPv6 subnet (ex: fe80::/64')
677
@args('--gateway_v6', dest="gateway_v6", help='ipv6 gateway')
678
@args('--bridge', dest="bridge",
680
help='VIFs on this network are connected to this bridge')
681
@args('--bridge_interface', dest="bridge_interface",
682
metavar='<bridge interface>',
683
help='the bridge is connected to this interface')
684
@args('--multi_host', dest="multi_host", metavar="<'T'|'F'>",
686
@args('--dns1', dest="dns1", metavar="<DNS Address>", help='First DNS')
687
@args('--dns2', dest="dns2", metavar="<DNS Address>", help='Second DNS')
688
@args('--uuid', dest="net_uuid", metavar="<network uuid>",
690
@args('--project_id', dest="project_id", metavar="<project id>",
692
@args('--priority', dest="priority", metavar="<number>",
693
help='Network interface priority')
694
def create(self, label=None, fixed_range_v4=None, num_networks=None,
695
network_size=None, multi_host=None, vlan_start=None,
696
vpn_start=None, fixed_range_v6=None, gateway_v6=None,
697
bridge=None, bridge_interface=None, dns1=None, dns2=None,
698
project_id=None, priority=None, uuid=None):
699
"""Creates fixed ips for host by range"""
701
# check for certain required inputs
703
raise exception.NetworkNotCreated(req='--label')
704
if not (fixed_range_v4 or fixed_range_v6):
705
req = '--fixed_range_v4 or --fixed_range_v6'
706
raise exception.NetworkNotCreated(req=req)
708
bridge = bridge or FLAGS.flat_network_bridge
710
bridge_required = ['nova.network.manager.FlatManager',
711
'nova.network.manager.FlatDHCPManager']
712
if FLAGS.network_manager in bridge_required:
713
# TODO(tr3buchet) - swap print statement and following line for
714
# raise statement in diablo 4
715
print _('--bridge parameter required or FLAG '
716
'flat_network_bridge must be set to create networks\n'
717
'WARNING! ACHTUNG! Setting the bridge to br100 '
718
'automatically is deprecated and will be removed in '
719
'Diablo milestone 4. Prepare yourself accordingly.')
722
#raise exception.NetworkNotCreated(req='--bridge')
724
bridge_interface = bridge_interface or FLAGS.flat_interface or \
726
if not bridge_interface:
727
interface_required = ['nova.network.manager.VlanManager']
728
if FLAGS.network_manager in interface_required:
729
raise exception.NetworkNotCreated(req='--bridge_interface')
731
# sanitize other input using FLAGS if necessary
413
def create(self, fixed_range=None, num_networks=None,
414
network_size=None, vlan_start=None, vpn_start=None,fixed_range_v6=None):
415
"""Creates fixed ips for host by range
416
arguments: [fixed_range=FLAG], [num_networks=FLAG],
417
[network_size=FLAG], [vlan_start=FLAG],
418
[vpn_start=FLAG],[fixed_range_v6=FLAG]"""
420
fixed_range = FLAGS.fixed_range
732
421
if not num_networks:
733
422
num_networks = FLAGS.num_networks
734
if not network_size and fixed_range_v4:
735
fixnet = netaddr.IPNetwork(fixed_range_v4)
736
each_subnet_size = fixnet.size / int(num_networks)
737
if each_subnet_size > FLAGS.network_size:
738
network_size = FLAGS.network_size
739
subnet = 32 - int(math.log(network_size, 2))
740
oversize_msg = _('Subnet(s) too large, defaulting to /%s.'
741
' To override, specify network_size flag.') % subnet
744
network_size = fixnet.size
746
multi_host = FLAGS.multi_host
748
multi_host = multi_host == 'T'
424
network_size = FLAGS.network_size
749
425
if not vlan_start:
750
426
vlan_start = FLAGS.vlan_start
751
427
if not vpn_start:
752
428
vpn_start = FLAGS.vpn_start
753
if not dns1 and FLAGS.flat_network_dns:
754
dns1 = FLAGS.flat_network_dns
757
network_size = FLAGS.network_size
429
if not fixed_range_v6:
430
fixed_range_v6 = FLAGS.fixed_range_v6
760
431
net_manager = utils.import_object(FLAGS.network_manager)
761
432
net_manager.create_networks(context.get_admin_context(),
764
multi_host=multi_host,
765
num_networks=int(num_networks),
766
network_size=int(network_size),
767
vlan_start=int(vlan_start),
768
vpn_start=int(vpn_start),
769
cidr_v6=fixed_range_v6,
770
gateway_v6=gateway_v6,
772
bridge_interface=bridge_interface,
775
project_id=project_id,
780
"""List all created networks"""
781
_fmt = "%-5s\t%-18s\t%-15s\t%-15s\t%-15s\t%-15s\t%-15s\t%-15s\t%-15s"
782
print _fmt % (_('id'),
791
for network in db.network_get_all(context.get_admin_context()):
792
print _fmt % (network.id,
802
def quantum_list(self):
803
"""List all created networks with Quantum-relevant fields"""
804
_fmt = "%-32s\t%-10s\t%-10s\t%s , %s"
805
print _fmt % (_('uuid'),
810
for network in db.network_get_all(context.get_admin_context()):
811
print _fmt % (network.uuid,
817
@args('--network', dest="fixed_range", metavar='<x.x.x.x/yy>',
818
help='Network to delete')
819
def delete(self, fixed_range):
820
"""Deletes a network"""
823
net_manager = utils.import_object(FLAGS.network_manager)
824
net_manager.delete_network(context.get_admin_context(), fixed_range)
826
@args('--network', dest="fixed_range", metavar='<x.x.x.x/yy>',
827
help='Network to modify')
828
@args('--project', dest="project", metavar='<project name>',
829
help='Project name to associate')
830
@args('--host', dest="host", metavar='<host>',
831
help='Host to associate')
832
@args('--disassociate-project', action="store_true", dest='dis_project',
833
default=False, help='Disassociate Network from Project')
834
@args('--disassociate-host', action="store_true", dest='dis_host',
835
default=False, help='Disassociate Host from Project')
836
def modify(self, fixed_range, project=None, host=None,
837
dis_project=None, dis_host=None):
838
"""Associate/Disassociate Network with Project and/or Host
839
arguments: network project host
840
leave any field blank to ignore it
842
admin_context = context.get_admin_context()
843
network = db.network_get_by_cidr(admin_context, fixed_range)
845
#User can choose the following actions each for project and host.
846
#1) Associate (set not None value given by project/host parameter)
847
#2) Disassociate (set None by disassociate parameter)
848
#3) Keep unchanged (project/host key is not added to 'net')
850
net['project_id'] = project
852
net['project_id'] = None
857
db.network_update(admin_context, network['id'], net)
860
class VmCommands(object):
861
"""Class for mangaging VM instances."""
863
@args('--host', dest="host", metavar='<host>', help='Host')
864
def list(self, host=None):
865
"""Show a list of all instances"""
867
print "%-10s %-15s %-10s %-10s %-26s %-9s %-9s %-9s" \
868
" %-10s %-10s %-10s %-5s" % (
883
instances = db.instance_get_all(context.get_admin_context())
885
instances = db.instance_get_all_by_host(
886
context.get_admin_context(), host)
888
for instance in instances:
889
print "%-10s %-15s %-10s %-10s %-26s %-9s %-9s %-9s" \
890
" %-10s %-10s %-10s %-5d" % (
891
instance['hostname'],
893
instance['instance_type'].name,
894
instance['vm_state'],
895
instance['launched_at'],
896
instance['image_ref'],
897
instance['kernel_id'],
898
instance['ramdisk_id'],
899
instance['project_id'],
901
instance['availability_zone'],
902
instance['launch_index'])
904
def _migration(self, ec2_id, dest, block_migration=False):
905
"""Migrates a running instance to a new machine.
906
:param ec2_id: instance id which comes from euca-describe-instance.
907
:param dest: destination host name.
908
:param block_migration: if True, do block_migration.
912
ctxt = context.get_admin_context()
913
instance_id = ec2utils.ec2_id_to_id(ec2_id)
915
if (FLAGS.connection_type != 'libvirt' or
916
(FLAGS.connection_type == 'libvirt' and
917
FLAGS.libvirt_type not in ['kvm', 'qemu'])):
918
msg = _('Only KVM and QEmu are supported for now. Sorry!')
919
raise exception.Error(msg)
921
if (FLAGS.volume_driver != 'nova.volume.driver.AOEDriver' and \
922
FLAGS.volume_driver != 'nova.volume.driver.ISCSIDriver'):
923
msg = _("Support only AOEDriver and ISCSIDriver. Sorry!")
924
raise exception.Error(msg)
927
FLAGS.scheduler_topic,
928
{"method": "live_migration",
929
"args": {"instance_id": instance_id,
931
"topic": FLAGS.compute_topic,
932
"block_migration": block_migration}})
934
print _('Migration of %s initiated.'
935
'Check its progress using euca-describe-instances.') % ec2_id
937
@args('--ec2_id', dest='ec2_id', metavar='<ec2 id>', help='EC2 ID')
938
@args('--dest', dest='dest', metavar='<Destanation>',
939
help='destanation node')
940
def live_migration(self, ec2_id, dest):
941
"""Migrates a running instance to a new machine."""
943
self._migration(ec2_id, dest)
945
@args('--ec2_id', dest='ec2_id', metavar='<ec2 id>', help='EC2 ID')
946
@args('--dest', dest='dest', metavar='<Destanation>',
947
help='destanation node')
948
def block_migration(self, ec2_id, dest):
949
"""Migrates a running instance to a new machine with storage data."""
951
self._migration(ec2_id, dest, True)
954
class ServiceCommands(object):
955
"""Enable and disable running services"""
957
@args('--host', dest='host', metavar='<host>', help='Host')
958
@args('--service', dest='service', metavar='<service>',
960
def list(self, host=None, service=None):
962
Show a list of all running services. Filter by host & service name.
964
ctxt = context.get_admin_context()
966
services = db.service_get_all(ctxt)
968
services = [s for s in services if s['host'] == host]
970
services = [s for s in services if s['binary'] == service]
971
print_format = "%-16s %-36s %-16s %-10s %-5s %-10s"
972
print print_format % (
980
delta = now - (svc['updated_at'] or svc['created_at'])
981
alive = (delta.seconds <= 15)
982
art = (alive and ":-)") or "XXX"
986
print print_format % (svc['binary'], svc['host'],
987
svc['availability_zone'], active, art,
990
@args('--host', dest='host', metavar='<host>', help='Host')
991
@args('--service', dest='service', metavar='<service>',
993
def enable(self, host, service):
994
"""Enable scheduling for a service"""
995
ctxt = context.get_admin_context()
996
svc = db.service_get_by_args(ctxt, host, service)
998
print "Unable to find service"
1000
db.service_update(ctxt, svc['id'], {'disabled': False})
1002
@args('--host', dest='host', metavar='<host>', help='Host')
1003
@args('--service', dest='service', metavar='<service>',
1004
help='Nova service')
1005
def disable(self, host, service):
1006
"""Disable scheduling for a service"""
1007
ctxt = context.get_admin_context()
1008
svc = db.service_get_by_args(ctxt, host, service)
1010
print "Unable to find service"
1012
db.service_update(ctxt, svc['id'], {'disabled': True})
1014
@args('--host', dest='host', metavar='<host>', help='Host')
1015
def describe_resource(self, host):
1016
"""Describes cpu/memory/hdd info for host."""
1018
result = rpc.call(context.get_admin_context(),
1019
FLAGS.scheduler_topic,
1020
{"method": "show_host_resources",
1021
"args": {"host": host}})
1023
if type(result) != dict:
1024
print _('An unexpected error has occurred.')
1025
print _('[Result]'), result
1027
cpu = result['resource']['vcpus']
1028
mem = result['resource']['memory_mb']
1029
hdd = result['resource']['local_gb']
1030
cpu_u = result['resource']['vcpus_used']
1031
mem_u = result['resource']['memory_mb_used']
1032
hdd_u = result['resource']['local_gb_used']
1037
print 'HOST\t\t\tPROJECT\t\tcpu\tmem(mb)\tdisk(gb)'
1038
print '%s(total)\t\t\t%s\t%s\t%s' % (host, cpu, mem, hdd)
1039
print '%s(used_now)\t\t\t%s\t%s\t%s' % (host, cpu_u, mem_u, hdd_u)
1040
for p_id, val in result['usage'].items():
1041
cpu_sum += val['vcpus']
1042
mem_sum += val['memory_mb']
1043
hdd_sum += val['local_gb']
1044
print '%s(used_max)\t\t\t%s\t%s\t%s' % (host, cpu_sum,
1047
for p_id, val in result['usage'].items():
1048
print '%s\t\t%s\t\t%s\t%s\t%s' % (host,
1054
@args('--host', dest='host', metavar='<host>', help='Host')
1055
def update_resource(self, host):
1056
"""Updates available vcpu/memory/disk info for host."""
1058
ctxt = context.get_admin_context()
1059
service_refs = db.service_get_all_by_host(ctxt, host)
1060
if len(service_refs) <= 0:
1061
raise exception.Invalid(_('%s does not exist.') % host)
1063
service_refs = [s for s in service_refs if s['topic'] == 'compute']
1064
if len(service_refs) <= 0:
1065
raise exception.Invalid(_('%s is not compute node.') % host)
1068
db.queue_get_for(ctxt, FLAGS.compute_topic, host),
1069
{"method": "update_available_resource"})
1072
class HostCommands(object):
1075
def list(self, zone=None):
1076
"""Show a list of all physical hosts. Filter by zone.
1078
print "%-25s\t%-15s" % (_('host'),
1080
ctxt = context.get_admin_context()
1081
now = utils.utcnow()
1082
services = db.service_get_all(ctxt)
1084
services = [s for s in services if s['availability_zone'] == zone]
1086
for srv in services:
1087
if not [h for h in hosts if h['host'] == srv['host']]:
1091
print "%-25s\t%-15s" % (h['host'], h['availability_zone'])
1094
class DbCommands(object):
1095
"""Class for managing the database."""
1100
@args('--version', dest='version', metavar='<version>',
1101
help='Database version')
1102
def sync(self, version=None):
1103
"""Sync the database up to the most recent version."""
1104
return migration.db_sync(version)
1107
"""Print the current database version."""
1108
print migration.db_version()
1111
class VersionCommands(object):
1112
"""Class for exposing the codebase version."""
1118
print _("%s (%s)") %\
1119
(version.version_string(), version.version_string_with_vcs())
1125
class VsaCommands(object):
1126
"""Methods for dealing with VSAs"""
1128
def __init__(self, *args, **kwargs):
1129
self.manager = manager.AuthManager()
1130
self.vsa_api = vsa.API()
1131
self.context = context.get_admin_context()
1133
self._format_str_vsa = "%(id)-5s %(vsa_id)-15s %(name)-25s "\
1134
"%(type)-10s %(vcs)-6s %(drives)-9s %(stat)-10s "\
1135
"%(az)-10s %(time)-10s"
1136
self._format_str_volume = "\t%(id)-4s %(name)-15s %(size)-5s "\
1137
"%(stat)-10s %(att)-20s %(time)s"
1138
self._format_str_drive = "\t%(id)-4s %(name)-15s %(size)-5s "\
1139
"%(stat)-10s %(host)-20s %(type)-4s %(tname)-10s %(time)s"
1140
self._format_str_instance = "\t%(id)-4s %(name)-10s %(dname)-20s "\
1141
"%(image)-12s %(type)-10s %(fl_ip)-15s %(fx_ip)-15s "\
1142
"%(stat)-10s %(host)-15s %(time)s"
1144
def _print_vsa_header(self):
1145
print self._format_str_vsa %\
1148
name=_('displayName'),
1151
drives=_('drive_cnt'),
1154
time=_('createTime'))
1156
def _print_vsa(self, vsa):
1157
print self._format_str_vsa %\
1160
name=vsa['display_name'],
1161
type=vsa['vsa_instance_type'].get('name', None),
1162
vcs=vsa['vc_count'],
1163
drives=vsa['vol_count'],
1165
az=vsa['availability_zone'],
1166
time=str(vsa['created_at']))
1168
def _print_volume_header(self):
1169
print _(' === Volumes ===')
1170
print self._format_str_volume %\
1175
att=_('attachment'),
1176
time=_('createTime'))
1178
def _print_volume(self, vol):
1179
print self._format_str_volume %\
1181
name=vol['display_name'] or vol['name'],
1184
att=vol['attach_status'],
1185
time=str(vol['created_at']))
1187
def _print_drive_header(self):
1188
print _(' === Drives ===')
1189
print self._format_str_drive %\
1196
tname=_('typeName'),
1197
time=_('createTime'))
1199
def _print_drive(self, drive):
1200
if drive['volume_type_id'] is not None and drive.get('volume_type'):
1201
drive_type_name = drive['volume_type'].get('name')
1203
drive_type_name = ''
1205
print self._format_str_drive %\
1206
dict(id=drive['id'],
1207
name=drive['display_name'],
1209
stat=drive['status'],
1211
type=drive['volume_type_id'],
1212
tname=drive_type_name,
1213
time=str(drive['created_at']))
1215
def _print_instance_header(self):
1216
print _(' === Instances ===')
1217
print self._format_str_instance %\
1220
dname=_('disp_name'),
1223
fl_ip=_('floating_IP'),
1224
fx_ip=_('fixed_IP'),
1227
time=_('createTime'))
1229
def _print_instance(self, vc):
1232
floating_addr = None
1234
fixed = vc['fixed_ips'][0]
1235
fixed_addr = fixed['address']
1236
if fixed['floating_ips']:
1237
floating_addr = fixed['floating_ips'][0]['address']
1238
floating_addr = floating_addr or fixed_addr
1240
print self._format_str_instance %\
1242
name=ec2utils.id_to_ec2_id(vc['id']),
1243
dname=vc['display_name'],
1244
image=('ami-%08x' % int(vc['image_ref'])),
1245
type=vc['instance_type']['name'],
1246
fl_ip=floating_addr,
1248
stat=vc['vm_state'],
1250
time=str(vc['created_at']))
1252
def _list(self, context, vsas, print_drives=False,
1253
print_volumes=False, print_instances=False):
1255
self._print_vsa_header()
1258
self._print_vsa(vsa)
1259
vsa_id = vsa.get('id')
1262
instances = self.vsa_api.get_all_vsa_instances(context, vsa_id)
1265
self._print_instance_header()
1266
for instance in instances:
1267
self._print_instance(instance)
1271
drives = self.vsa_api.get_all_vsa_drives(context, vsa_id)
1273
self._print_drive_header()
1274
for drive in drives:
1275
self._print_drive(drive)
1279
volumes = self.vsa_api.get_all_vsa_volumes(context, vsa_id)
1281
self._print_volume_header()
1282
for volume in volumes:
1283
self._print_volume(volume)
1286
@args('--storage', dest='storage',
1287
metavar="[{'drive_name': 'type', 'num_drives': N, 'size': M},..]",
1288
help='Initial storage allocation for VSA')
1289
@args('--name', dest='name', metavar="<name>", help='VSA name')
1290
@args('--description', dest='description', metavar="<description>",
1291
help='VSA description')
1292
@args('--vc', dest='vc_count', metavar="<number>", help='Number of VCs')
1293
@args('--instance_type', dest='instance_type_name', metavar="<name>",
1294
help='Instance type name')
1295
@args('--image', dest='image_name', metavar="<name>", help='Image name')
1296
@args('--shared', dest='shared', action="store_true", default=False,
1297
help='Use shared drives')
1298
@args('--az', dest='az', metavar="<zone:host>", help='Availability zone')
1299
@args('--user', dest="user_id", metavar='<User name>',
1301
@args('--project', dest="project_id", metavar='<Project name>',
1302
help='Project name')
1303
def create(self, storage='[]', name=None, description=None, vc_count=1,
1304
instance_type_name=None, image_name=None, shared=None,
1305
az=None, user_id=None, project_id=None):
1308
if project_id is None:
1310
project_id = os.getenv("EC2_ACCESS_KEY").split(':')[1]
1311
except Exception as exc:
1312
print _("Failed to retrieve project id: %(exc)s") % exc
1317
project = self.manager.get_project(project_id)
1318
user_id = project.project_manager_id
1319
except Exception as exc:
1320
print _("Failed to retrieve user info: %(exc)s") % exc
1323
is_admin = self.manager.is_admin(user_id)
1324
ctxt = context.RequestContext(user_id, project_id, is_admin)
1325
if not is_admin and \
1326
not self.manager.is_project_member(user_id, project_id):
1327
msg = _("%(user_id)s must be an admin or a "
1328
"member of %(project_id)s")
1329
LOG.warn(msg % locals())
1330
raise ValueError(msg % locals())
1332
# Sanity check for storage string
1334
if storage is not None:
1336
storage_list = ast.literal_eval(storage)
1338
print _("Invalid string format %s") % storage
1341
for node in storage_list:
1342
if ('drive_name' not in node) or ('num_drives' not in node):
1343
print (_("Invalid string format for element %s. " \
1344
"Expecting keys 'drive_name' & 'num_drives'"),
1348
if instance_type_name == '':
1349
instance_type_name = None
1350
instance_type = instance_types.get_instance_type_by_name(
1353
if image_name == '':
1356
if shared in [None, False, "--full_drives"]:
1358
elif shared in [True, "--shared"]:
1361
raise ValueError(_('Shared parameter should be set either to "\
1362
"--shared or --full_drives'))
1365
'display_name': name,
1366
'display_description': description,
1367
'vc_count': int(vc_count),
1368
'instance_type': instance_type,
1369
'image_name': image_name,
1370
'availability_zone': az,
1371
'storage': storage_list,
1375
result = self.vsa_api.create(ctxt, **values)
1376
self._list(ctxt, [result])
1378
@args('--id', dest='vsa_id', metavar="<vsa_id>", help='VSA ID')
1379
@args('--name', dest='name', metavar="<name>", help='VSA name')
1380
@args('--description', dest='description', metavar="<description>",
1381
help='VSA description')
1382
@args('--vc', dest='vc_count', metavar="<number>", help='Number of VCs')
1383
def update(self, vsa_id, name=None, description=None, vc_count=None):
1384
"""Updates name/description of vsa and number of VCs."""
1387
if name is not None:
1388
values['display_name'] = name
1389
if description is not None:
1390
values['display_description'] = description
1391
if vc_count is not None:
1392
values['vc_count'] = int(vc_count)
1394
vsa_id = ec2utils.ec2_id_to_id(vsa_id)
1395
result = self.vsa_api.update(self.context, vsa_id=vsa_id, **values)
1396
self._list(self.context, [result])
1398
@args('--id', dest='vsa_id', metavar="<vsa_id>", help='VSA ID')
1399
def delete(self, vsa_id):
1401
vsa_id = ec2utils.ec2_id_to_id(vsa_id)
1402
self.vsa_api.delete(self.context, vsa_id)
1404
@args('--id', dest='vsa_id', metavar="<vsa_id>",
1405
help='VSA ID (optional)')
1406
@args('--all', dest='all', action="store_true", default=False,
1407
help='Show all available details')
1408
@args('--drives', dest='drives', action="store_true",
1409
help='Include drive-level details')
1410
@args('--volumes', dest='volumes', action="store_true",
1411
help='Include volume-level details')
1412
@args('--instances', dest='instances', action="store_true",
1413
help='Include instance-level details')
1414
def list(self, vsa_id=None, all=False,
1415
drives=False, volumes=False, instances=False):
1416
"""Describe all available VSAs (or particular one)."""
1419
if vsa_id is not None:
1420
internal_id = ec2utils.ec2_id_to_id(vsa_id)
1421
vsa = self.vsa_api.get(self.context, internal_id)
1424
vsas = self.vsa_api.get_all(self.context)
1427
drives = volumes = instances = True
1429
self._list(self.context, vsas, drives, volumes, instances)
1431
def update_capabilities(self):
1432
"""Forces updates capabilities on all nova-volume nodes."""
1434
rpc.fanout_cast(context.get_admin_context(),
1436
{"method": "notification",
1437
"args": {"event": "startup"}})
1440
class VsaDriveTypeCommands(object):
1441
"""Methods for dealing with VSA drive types"""
1443
def __init__(self, *args, **kwargs):
1444
super(VsaDriveTypeCommands, self).__init__(*args, **kwargs)
1445
self.context = context.get_admin_context()
1446
self._drive_type_template = '%s_%sGB_%sRPM'
1448
def _list(self, drives):
1449
format_str = "%-5s %-30s %-10s %-10s %-10s %-20s %-10s %s"
1461
for name, vol_type in drives.iteritems():
1462
drive = vol_type.get('extra_specs')
1464
(str(vol_type['id']),
1465
drive['drive_name'],
1466
drive['drive_type'],
1467
drive['drive_size'],
1469
drive.get('capabilities', ''),
1470
str(drive.get('visible', '')),
1471
str(vol_type['created_at']))
1473
@args('--type', dest='type', metavar="<type>",
1474
help='Drive type (SATA, SAS, SSD, etc.)')
1475
@args('--size', dest='size_gb', metavar="<gb>", help='Drive size in GB')
1476
@args('--rpm', dest='rpm', metavar="<rpm>", help='RPM')
1477
@args('--capabilities', dest='capabilities', default=None,
1478
metavar="<string>", help='Different capabilities')
1479
@args('--hide', dest='hide', action="store_true", default=False,
1480
help='Show or hide drive')
1481
@args('--name', dest='name', metavar="<name>", help='Drive name')
1482
def create(self, type, size_gb, rpm, capabilities=None,
1483
hide=False, name=None):
1484
"""Create drive type."""
1486
hide = True if hide in [True, "True", "--hide", "hide"] else False
1489
name = self._drive_type_template % (type, size_gb, rpm)
1491
extra_specs = {'type': 'vsa_drive',
1494
'drive_size': size_gb,
1499
extra_specs['visible'] = False
1501
if capabilities is not None and capabilities != '':
1502
extra_specs['capabilities'] = capabilities
1504
volume_types.create(self.context, name, extra_specs)
1505
result = volume_types.get_volume_type_by_name(self.context, name)
1506
self._list({name: result})
1508
@args('--name', dest='name', metavar="<name>", help='Drive name')
1509
@args('--purge', action="store_true", dest='purge', default=False,
1510
help='purge record from database')
1511
def delete(self, name, purge):
1512
"""Marks instance types / flavors as deleted"""
1515
volume_types.purge(self.context, name)
1518
volume_types.destroy(self.context, name)
1520
except exception.ApiError:
1521
print "Valid volume type name is required"
1523
except exception.DBError, e:
1524
print "DB Error: %s" % e
1529
print "%s %s" % (name, verb)
1531
@args('--all', dest='all', action="store_true", default=False,
1532
help='Show all drives (including invisible)')
1533
@args('--name', dest='name', metavar="<name>",
1534
help='Show only specified drive')
1535
def list(self, all=False, name=None):
1536
"""Describe all available VSA drive types (or particular one)."""
1538
all = False if all in ["--all", False, "False"] else True
1540
search_opts = {'extra_specs': {'type': 'vsa_drive'}}
1541
if name is not None:
1542
search_opts['extra_specs']['name'] = name
1545
search_opts['extra_specs']['visible'] = '1'
1547
drives = volume_types.get_all_types(self.context,
1548
search_opts=search_opts)
1551
@args('--name', dest='name', metavar="<name>", help='Drive name')
1552
@args('--type', dest='type', metavar="<type>",
1553
help='Drive type (SATA, SAS, SSD, etc.)')
1554
@args('--size', dest='size_gb', metavar="<gb>", help='Drive size in GB')
1555
@args('--rpm', dest='rpm', metavar="<rpm>", help='RPM')
1556
@args('--capabilities', dest='capabilities', default=None,
1557
metavar="<string>", help='Different capabilities')
1558
@args('--visible', dest='visible',
1559
metavar="<show|hide>", help='Show or hide drive')
1560
def update(self, name, type=None, size_gb=None, rpm=None,
1561
capabilities=None, visible=None):
1562
"""Update drive type."""
1564
volume_type = volume_types.get_volume_type_by_name(self.context, name)
1566
extra_specs = {'type': 'vsa_drive'}
1569
extra_specs['drive_type'] = type
1572
extra_specs['drive_size'] = size_gb
1575
extra_specs['drive_rpm'] = rpm
1578
extra_specs['capabilities'] = capabilities
1580
if visible is not None:
1581
if visible in ["show", True, "True"]:
1582
extra_specs['visible'] = True
1583
elif visible in ["hide", False, "False"]:
1584
extra_specs['visible'] = False
1586
raise ValueError(_('visible parameter should be set to '\
1589
db.api.volume_type_extra_specs_update_or_create(self.context,
1592
result = volume_types.get_volume_type_by_name(self.context, name)
1593
self._list({name: result})
1596
class VolumeCommands(object):
1597
"""Methods for dealing with a cloud in an odd state"""
1599
@args('--volume', dest='volume_id', metavar='<volume id>',
1601
def delete(self, volume_id):
1602
"""Delete a volume, bypassing the check that it
1603
must be available."""
1604
ctxt = context.get_admin_context()
1605
volume = db.volume_get(ctxt, param2id(volume_id))
1606
host = volume['host']
1609
print "Volume not yet assigned to host."
1610
print "Deleting volume from database and skipping rpc."
1611
db.volume_destroy(ctxt, param2id(volume_id))
1614
if volume['status'] == 'in-use':
1615
print "Volume is in-use."
1616
print "Detach volume from instance and then try again."
1620
db.queue_get_for(ctxt, FLAGS.volume_topic, host),
1621
{"method": "delete_volume",
1622
"args": {"volume_id": volume['id']}})
1624
@args('--volume', dest='volume_id', metavar='<volume id>',
1626
def reattach(self, volume_id):
1627
"""Re-attach a volume that has previously been attached
1628
to an instance. Typically called after a compute host
1629
has been rebooted."""
1630
ctxt = context.get_admin_context()
1631
volume = db.volume_get(ctxt, param2id(volume_id))
1632
if not volume['instance_id']:
1633
print "volume is not attached to an instance"
1635
instance = db.instance_get(ctxt, volume['instance_id'])
1636
host = instance['host']
1638
db.queue_get_for(ctxt, FLAGS.compute_topic, host),
1639
{"method": "attach_volume",
1640
"args": {"instance_id": instance['id'],
1641
"volume_id": volume['id'],
1642
"mountpoint": volume['mountpoint']}})
1645
class InstanceTypeCommands(object):
1646
"""Class for managing instance types / flavors."""
1648
def _print_instance_types(self, name, val):
1649
deleted = ('', ', inactive')[val["deleted"] == 1]
1650
print ("%s: Memory: %sMB, VCPUS: %s, Storage: %sGB, FlavorID: %s, "
1651
"Swap: %sGB, RXTX Quota: %sGB, RXTX Cap: %sMB%s") % (
1652
name, val["memory_mb"], val["vcpus"], val["local_gb"],
1653
val["flavorid"], val["swap"], val["rxtx_quota"],
1654
val["rxtx_cap"], deleted)
1656
@args('--name', dest='name', metavar='<name>',
1657
help='Name of instance type/flavor')
1658
@args('--memory', dest='memory', metavar='<memory size>',
1660
@args('--cpu', dest='vcpus', metavar='<num cores>', help='Number cpus')
1661
@args('--local_gb', dest='local_gb', metavar='<local_gb>',
1663
@args('--flavor', dest='flavorid', metavar='<flavor id>',
1665
@args('--swap', dest='swap', metavar='<swap>', help='Swap')
1666
@args('--rxtx_quota', dest='rxtx_quota', metavar='<rxtx_quota>',
1668
@args('--rxtx_cap', dest='rxtx_cap', metavar='<rxtx_cap>',
1670
def create(self, name, memory, vcpus, local_gb, flavorid,
1671
swap=0, rxtx_quota=0, rxtx_cap=0):
1672
"""Creates instance types / flavors"""
1674
instance_types.create(name, memory, vcpus, local_gb,
1675
flavorid, swap, rxtx_quota, rxtx_cap)
1676
except exception.InvalidInput, e:
1677
print "Must supply valid parameters to create instance_type"
1680
except exception.ApiError, e:
1683
print "Please ensure instance_type name and flavorid are unique."
1684
print "To complete remove a instance_type, use the --purge flag:"
1685
print "\n # nova-manage instance_type delete <name> --purge\n"
1686
print "Currently defined instance_type names and flavorids:"
1690
print "Unknown error"
1693
print "%s created" % name
1695
@args('--name', dest='name', metavar='<name>',
1696
help='Name of instance type/flavor')
1697
@args('--purge', action="store_true", dest='purge', default=False,
1698
help='purge record from database')
1699
def delete(self, name, purge):
1700
"""Marks instance types / flavors as deleted"""
1703
instance_types.purge(name)
1706
instance_types.destroy(name)
1708
except exception.ApiError:
1709
print "Valid instance type name is required"
1711
except exception.DBError, e:
1712
print "DB Error: %s" % e
1717
print "%s %s" % (name, verb)
1719
@args('--name', dest='name', metavar='<name>',
1720
help='Name of instance type/flavor')
1721
def list(self, name=None):
1722
"""Lists all active or specific instance types / flavors"""
1725
inst_types = instance_types.get_all_types()
1726
elif name == "--all":
1727
inst_types = instance_types.get_all_types(True)
1729
inst_types = instance_types.get_instance_type_by_name(name)
1730
except exception.DBError, e:
1732
if isinstance(inst_types.values()[0], dict):
1733
for k, v in inst_types.iteritems():
1734
self._print_instance_types(k, v)
1736
self._print_instance_types(name, inst_types)
1739
class ImageCommands(object):
1740
"""Methods for dealing with a cloud in an odd state"""
1742
def __init__(self, *args, **kwargs):
1743
self.image_service = image.get_default_image_service()
1745
def _register(self, container_format, disk_format,
1746
path, owner, name=None, is_public='T',
1747
architecture='x86_64', kernel_id=None, ramdisk_id=None):
1748
meta = {'is_public': (is_public == 'T'),
1750
'container_format': container_format,
1751
'disk_format': disk_format,
1752
'properties': {'image_state': 'available',
1753
'project_id': owner,
1754
'architecture': architecture,
1755
'image_location': 'local'}}
1757
meta['properties']['kernel_id'] = int(kernel_id)
1759
meta['properties']['ramdisk_id'] = int(ramdisk_id)
1760
elevated = context.get_admin_context()
1762
with open(path) as ifile:
1763
image = self.image_service.create(elevated, meta, ifile)
1765
print _("Image registered to %(new)s (%(new)08x).") % locals()
1767
except Exception as exc:
1768
print _("Failed to register %(path)s: %(exc)s") % locals()
1770
@args('--image', dest='image', metavar='<image>', help='Image')
1771
@args('--kernel', dest='kernel', metavar='<kernel>', help='Kernel')
1772
@args('--ram', dest='ramdisk', metavar='<ramdisk>', help='RAM disk')
1773
@args('--owner', dest='owner', metavar='<owner>', help='Image owner')
1774
@args('--name', dest='name', metavar='<name>', help='Image name')
1775
@args('--public', dest='is_public', metavar="<'T'|'F'>",
1776
help='Image public or not')
1777
@args('--arch', dest='architecture', metavar='<arch>',
1778
help='Architecture')
1779
def all_register(self, image, kernel, ramdisk, owner, name=None,
1780
is_public='T', architecture='x86_64'):
1781
"""Uploads an image, kernel, and ramdisk into the image_service"""
1782
kernel_id = self.kernel_register(kernel, owner, None,
1783
is_public, architecture)
1784
ramdisk_id = self.ramdisk_register(ramdisk, owner, None,
1785
is_public, architecture)
1786
self.image_register(image, owner, name, is_public,
1787
architecture, 'ami', 'ami',
1788
kernel_id, ramdisk_id)
1790
@args('--path', dest='path', metavar='<path>', help='Image path')
1791
@args('--owner', dest='owner', metavar='<owner>', help='Image owner')
1792
@args('--name', dest='name', metavar='<name>', help='Image name')
1793
@args('--public', dest='is_public', metavar="<'T'|'F'>",
1794
help='Image public or not')
1795
@args('--arch', dest='architecture', metavar='<arch>',
1796
help='Architecture')
1797
@args('--cont_format', dest='container_format',
1798
metavar='<container format>',
1799
help='Container format(default bare)')
1800
@args('--disk_format', dest='disk_format', metavar='<disk format>',
1801
help='Disk format(default: raw)')
1802
@args('--kernel', dest='kernel_id', metavar='<kernel>', help='Kernel')
1803
@args('--ram', dest='ramdisk_id', metavar='<ramdisk>', help='RAM disk')
1804
def image_register(self, path, owner, name=None, is_public='T',
1805
architecture='x86_64', container_format='bare',
1806
disk_format='raw', kernel_id=None, ramdisk_id=None):
1807
"""Uploads an image into the image_service"""
1808
return self._register(container_format, disk_format, path,
1809
owner, name, is_public, architecture,
1810
kernel_id, ramdisk_id)
1812
@args('--path', dest='path', metavar='<path>', help='Image path')
1813
@args('--owner', dest='owner', metavar='<owner>', help='Image owner')
1814
@args('--name', dest='name', metavar='<name>', help='Image name')
1815
@args('--public', dest='is_public', metavar="<'T'|'F'>",
1816
help='Image public or not')
1817
@args('--arch', dest='architecture', metavar='<arch>',
1818
help='Architecture')
1819
def kernel_register(self, path, owner, name=None, is_public='T',
1820
architecture='x86_64'):
1821
"""Uploads a kernel into the image_service"""
1822
return self._register('aki', 'aki', path, owner, name,
1823
is_public, architecture)
1825
@args('--path', dest='path', metavar='<path>', help='Image path')
1826
@args('--owner', dest='owner', metavar='<owner>', help='Image owner')
1827
@args('--name', dest='name', metavar='<name>', help='Image name')
1828
@args('--public', dest='is_public', metavar="<'T'|'F'>",
1829
help='Image public or not')
1830
@args('--arch', dest='architecture', metavar='<arch>',
1831
help='Architecture')
1832
def ramdisk_register(self, path, owner, name=None, is_public='T',
1833
architecture='x86_64'):
1834
"""Uploads a ramdisk into the image_service"""
1835
return self._register('ari', 'ari', path, owner, name,
1836
is_public, architecture)
1838
def _lookup(self, old_image_id):
1839
elevated = context.get_admin_context()
1841
internal_id = ec2utils.ec2_id_to_id(old_image_id)
1842
image = self.image_service.show(elevated, internal_id)
1843
except (exception.InvalidEc2Id, exception.ImageNotFound):
1844
image = self.image_service.show_by_name(elevated, old_image_id)
1847
def _old_to_new(self, old):
1848
mapping = {'machine': 'ami',
1851
container_format = mapping[old['type']]
1852
disk_format = container_format
1853
if container_format == 'ami' and not old.get('kernelId'):
1854
container_format = 'bare'
1856
new = {'disk_format': disk_format,
1857
'container_format': container_format,
1858
'is_public': old['isPublic'],
1859
'name': old['imageId'],
1860
'properties': {'image_state': old['imageState'],
1861
'project_id': old['imageOwnerId'],
1862
'architecture': old['architecture'],
1863
'image_location': old['imageLocation']}}
1864
if old.get('kernelId'):
1865
new['properties']['kernel_id'] = self._lookup(old['kernelId'])
1866
if old.get('ramdiskId'):
1867
new['properties']['ramdisk_id'] = self._lookup(old['ramdiskId'])
1870
def _convert_images(self, images):
1871
elevated = context.get_admin_context()
1872
for image_path, image_metadata in images.iteritems():
1873
meta = self._old_to_new(image_metadata)
1876
with open(image_path) as ifile:
1877
image = self.image_service.create(elevated, meta, ifile)
1879
print _("Image %(old)s converted to " \
1880
"%(new)s (%(new)08x).") % locals()
1881
except Exception as exc:
1882
print _("Failed to convert %(old)s: %(exc)s") % locals()
1884
@args('--dir', dest='directory', metavar='<path>',
1885
help='Images directory')
1886
def convert(self, directory):
1887
"""Uploads old objectstore images in directory to new service"""
1890
directory = os.path.abspath(directory)
1891
for fn in glob.glob("%s/*/info.json" % directory):
1893
image_path = os.path.join(fn.rpartition('/')[0], 'image')
1894
with open(fn) as metadata_file:
1895
image_metadata = json.load(metadata_file)
1896
if image_metadata['type'] == 'machine':
1897
machine_images[image_path] = image_metadata
1899
other_images[image_path] = image_metadata
1901
print _("Failed to load %(fn)s.") % locals()
1902
# NOTE(vish): do kernels and ramdisks first so images
1903
self._convert_images(other_images)
1904
self._convert_images(machine_images)
1907
class AgentBuildCommands(object):
1908
"""Class for managing agent builds."""
1910
def create(self, os, architecture, version, url, md5hash,
1912
"""Creates a new agent build."""
1913
ctxt = context.get_admin_context()
1914
agent_build = db.agent_build_create(ctxt,
1915
{'hypervisor': hypervisor,
1917
'architecture': architecture,
1920
'md5hash': md5hash})
1922
def delete(self, os, architecture, hypervisor='xen'):
1923
"""Deletes an existing agent build."""
1924
ctxt = context.get_admin_context()
1925
agent_build_ref = db.agent_build_get_by_triple(ctxt,
1926
hypervisor, os, architecture)
1927
db.agent_build_destroy(ctxt, agent_build_ref['id'])
1929
def list(self, hypervisor=None):
1930
"""Lists all agent builds.
1931
arguments: <none>"""
1932
fmt = "%-10s %-8s %12s %s"
1933
ctxt = context.get_admin_context()
1935
for agent_build in db.agent_build_get_all(ctxt):
1936
buildlist = by_hypervisor.get(agent_build.hypervisor)
1938
buildlist = by_hypervisor[agent_build.hypervisor] = []
1940
buildlist.append(agent_build)
1942
for key, buildlist in by_hypervisor.iteritems():
1943
if hypervisor and key != hypervisor:
1946
print "Hypervisor: %s" % key
1947
print fmt % ('-' * 10, '-' * 8, '-' * 12, '-' * 32)
1948
for agent_build in buildlist:
1949
print fmt % (agent_build.os, agent_build.architecture,
1950
agent_build.version, agent_build.md5hash)
1951
print ' %s' % agent_build.url
1955
def modify(self, os, architecture, version, url, md5hash,
1957
"""Update an existing agent build."""
1958
ctxt = context.get_admin_context()
1959
agent_build_ref = db.agent_build_get_by_triple(ctxt,
1960
hypervisor, os, architecture)
1961
db.agent_build_update(ctxt, agent_build_ref['id'],
1962
{'version': version,
1964
'md5hash': md5hash})
1967
class ConfigCommands(object):
1968
"""Class for exposing the flags defined by flag_file(s)."""
1974
print FLAGS.FlagsIntoString()
433
fixed_range, int(num_networks),
434
int(network_size), int(vlan_start),
435
int(vpn_start),fixed_range_v6)
1978
('account', AccountCommands),
1979
('agent', AgentBuildCommands),
1980
('config', ConfigCommands),
1982
('drive', VsaDriveTypeCommands),
1983
('fixed', FixedIpCommands),
1984
('flavor', InstanceTypeCommands),
1985
('floating', FloatingIpCommands),
1986
('host', HostCommands),
1987
('instance_type', InstanceTypeCommands),
1988
('image', ImageCommands),
1989
('network', NetworkCommands),
440
('user', UserCommands),
1990
441
('project', ProjectCommands),
1991
442
('role', RoleCommands),
1992
('service', ServiceCommands),
1993
443
('shell', ShellCommands),
1994
('user', UserCommands),
1995
('version', VersionCommands),
1997
('volume', VolumeCommands),
1998
444
('vpn', VpnCommands),
1999
('vsa', VsaCommands)]
445
('floating', FloatingIpCommands),
446
('network', NetworkCommands)]
2002
449
def lazy_match(name, key_value_tuples):