171
409
def __init__(self):
172
410
self.manager = manager.AuthManager()
174
def add(self, project, user):
175
"""Adds user to project
176
arguments: project user"""
177
self.manager.add_to_project(user, project)
412
@args('--project', dest="project_id", metavar='<Project name>',
414
@args('--user', dest="user_id", metavar='<name>', help='User name')
415
def add(self, project_id, user_id):
416
"""Adds user to project"""
418
self.manager.add_to_project(user_id, project_id)
419
except exception.UserNotFound as ex:
423
@args('--project', dest="name", metavar='<Project name>',
425
@args('--user', dest="project_manager", metavar='<user>',
426
help='Project manager')
427
@args('--desc', dest="description", metavar='<description>',
179
429
def create(self, name, project_manager, description=None):
180
"""Creates a new project
181
arguments: name project_manager [description]"""
182
self.manager.create_project(name, project_manager, description)
430
"""Creates a new project"""
432
self.manager.create_project(name, project_manager, description)
433
except exception.UserNotFound as ex:
437
@args('--project', dest="name", metavar='<Project name>',
439
@args('--user', dest="project_manager", metavar='<user>',
440
help='Project manager')
441
@args('--desc', dest="description", metavar='<description>',
443
def modify(self, name, project_manager, description=None):
444
"""Modifies a project"""
446
self.manager.modify_project(name, project_manager, description)
447
except exception.UserNotFound as ex:
451
@args('--project', dest="name", metavar='<Project name>',
184
453
def delete(self, name):
185
"""Deletes an existing project
187
self.manager.delete_project(name)
454
"""Deletes an existing project"""
456
self.manager.delete_project(name)
457
except exception.ProjectNotFound as ex:
461
@args('--project', dest="project_id", metavar='<Project name>',
463
@args('--user', dest="user_id", metavar='<name>', help='User name')
464
@args('--file', dest="filename", metavar='<filename>',
465
help='File name(Default: novarc)')
189
466
def environment(self, project_id, user_id, filename='novarc'):
190
"""Exports environment variables to an sourcable file
191
arguments: project_id user_id [filename='novarc]"""
192
rc = self.manager.get_environment_rc(project_id, user_id)
193
with open(filename, 'w') as f:
467
"""Exports environment variables to an sourcable file"""
469
rc = self.manager.get_environment_rc(user_id, project_id)
470
except (exception.UserNotFound, exception.ProjectNotFound) as ex:
476
with open(filename, 'w') as f:
197
"""Lists all projects
199
for project in self.manager.get_projects():
479
@args('--user', dest="username", metavar='<username>', help='User name')
480
def list(self, username=None):
481
"""Lists all projects"""
482
for project in self.manager.get_projects(username):
200
483
print project.name
202
def remove(self, project, user):
203
"""Removes user from project
204
arguments: project user"""
205
self.manager.remove_from_project(user, project)
485
@args('--project', dest="project_id", metavar='<Project name>',
487
@args('--key', dest="key", metavar='<key>', help='Key')
488
@args('--value', dest="value", metavar='<value>', help='Value')
489
def quota(self, project_id, key=None, value=None):
490
"""Set or display quotas for project"""
491
ctxt = context.get_admin_context()
493
if value.lower() == 'unlimited':
496
db.quota_update(ctxt, project_id, key, value)
497
except exception.ProjectQuotaNotFound:
498
db.quota_create(ctxt, project_id, key, value)
499
project_quota = quota.get_project_quotas(ctxt, project_id)
500
for key, value in project_quota.iteritems():
503
print '%s: %s' % (key, value)
505
@args('--project', dest="project_id", metavar='<Project name>',
507
@args('--user', dest="user_id", metavar='<name>', help='User name')
508
def remove(self, project_id, user_id):
509
"""Removes user from project"""
511
self.manager.remove_from_project(user_id, project_id)
512
except (exception.UserNotFound, exception.ProjectNotFound) as ex:
516
@args('--project', dest="project_id", metavar='<Project name>',
518
def scrub(self, project_id):
519
"""Deletes data associated with project"""
520
admin_context = context.get_admin_context()
521
networks = db.project_get_networks(admin_context, project_id)
522
for network in networks:
523
db.network_disassociate(admin_context, network['id'])
524
groups = db.security_group_get_by_project(admin_context, project_id)
526
db.security_group_destroy(admin_context, group['id'])
528
@args('--project', dest="project_id", metavar='<Project name>',
530
@args('--user', dest="user_id", metavar='<name>', help='User name')
531
@args('--file', dest="filename", metavar='<filename>',
532
help='File name(Default: nova.zip)')
207
533
def zipfile(self, project_id, user_id, filename='nova.zip'):
208
"""Exports credentials for project to a zip file
209
arguments: project_id user_id [filename='nova.zip]"""
210
zip_file = self.manager.get_credentials(user_id, project_id)
211
with open(filename, 'w') as f:
534
"""Exports credentials for project to a zip file"""
536
zip_file = self.manager.get_credentials(user_id, project_id)
538
sys.stdout.write(zip_file)
540
with open(filename, 'w') as f:
542
except (exception.UserNotFound, exception.ProjectNotFound) as ex:
545
except db.api.NoMoreNetworks:
546
print _('No more networks available. If this is a new '
547
'installation, you need\nto call something like this:\n\n'
548
' nova-manage network create pvt 10.0.0.0/8 10 64\n\n')
549
except exception.ProcessExecutionError, e:
551
print _("The above error may show that the certificate db has "
552
"not been created.\nPlease create a database by running "
553
"a nova-api server on this host.")
555
AccountCommands = ProjectCommands
558
class FixedIpCommands(object):
559
"""Class for managing fixed ip."""
561
@args('--host', dest="host", metavar='<host>', help='Host')
562
def list(self, host=None):
563
"""Lists all fixed ips (optionally by host)"""
564
ctxt = context.get_admin_context()
568
fixed_ips = db.fixed_ip_get_all(ctxt)
570
fixed_ips = db.fixed_ip_get_all_by_instance_host(ctxt, host)
571
except exception.NotFound as ex:
572
print "error: %s" % ex
575
print "%-18s\t%-15s\t%-17s\t%-15s\t%s" % (_('network'),
580
for fixed_ip in fixed_ips:
584
if fixed_ip['instance']:
585
instance = fixed_ip['instance']
586
hostname = instance['hostname']
587
host = instance['host']
588
mac_address = fixed_ip['virtual_interface']['address']
589
print "%-18s\t%-15s\t%-17s\t%-15s\t%s" % (
590
fixed_ip['network']['cidr'],
592
mac_address, hostname, host)
595
class FloatingIpCommands(object):
596
"""Class for managing floating ip."""
598
@args('--ip_range', dest="range", metavar='<range>', help='IP range')
599
def create(self, range):
600
"""Creates floating ips for zone by range"""
601
for address in netaddr.IPNetwork(range):
602
db.floating_ip_create(context.get_admin_context(),
603
{'address': str(address)})
605
@args('--ip_range', dest="ip_range", metavar='<range>', help='IP range')
606
def delete(self, ip_range):
607
"""Deletes floating ips by range"""
608
for address in netaddr.IPNetwork(ip_range):
609
db.floating_ip_destroy(context.get_admin_context(),
612
@args('--host', dest="host", metavar='<host>', help='Host')
613
def list(self, host=None):
614
"""Lists all floating ips (optionally by host)
615
Note: if host is given, only active floating IPs are returned"""
616
ctxt = context.get_admin_context()
618
floating_ips = db.floating_ip_get_all(ctxt)
620
floating_ips = db.floating_ip_get_all_by_host(ctxt, host)
621
for floating_ip in floating_ips:
623
if floating_ip['fixed_ip']:
624
instance = floating_ip['fixed_ip']['instance']['hostname']
625
print "%s\t%s\t%s" % (floating_ip['host'],
626
floating_ip['address'],
630
class NetworkCommands(object):
631
"""Class for managing networks."""
633
@args('--label', dest="label", metavar='<label>',
634
help='Label for network (ex: public)')
635
@args('--fixed_range_v4', dest="fixed_range_v4", metavar='<x.x.x.x/yy>',
636
help='IPv4 subnet (ex: 10.0.0.0/8)')
637
@args('--num_networks', dest="num_networks", metavar='<number>',
638
help='Number of networks to create')
639
@args('--network_size', dest="network_size", metavar='<number>',
640
help='Number of IPs per network')
641
@args('--vlan', dest="vlan_start", metavar='<vlan id>', help='vlan id')
642
@args('--vpn', dest="vpn_start", help='vpn start')
643
@args('--fixed_range_v6', dest="fixed_range_v6",
644
help='IPv6 subnet (ex: fe80::/64')
645
@args('--gateway_v6', dest="gateway_v6", help='ipv6 gateway')
646
@args('--bridge', dest="bridge",
648
help='VIFs on this network are connected to this bridge')
649
@args('--bridge_interface', dest="bridge_interface",
650
metavar='<bridge interface>',
651
help='the bridge is connected to this interface')
652
@args('--multi_host', dest="multi_host", metavar="<'T'|'F'>",
654
@args('--dns1', dest="dns1", metavar="<DNS Address>", help='First DNS')
655
@args('--dns2', dest="dns2", metavar="<DNS Address>", help='Second DNS')
656
def create(self, label=None, fixed_range_v4=None, num_networks=None,
657
network_size=None, multi_host=None, vlan_start=None,
658
vpn_start=None, fixed_range_v6=None, gateway_v6=None,
659
bridge=None, bridge_interface=None, dns1=None, dns2=None):
660
"""Creates fixed ips for host by range"""
662
# check for certain required inputs
664
raise exception.NetworkNotCreated(req='--label')
665
if not fixed_range_v4:
666
raise exception.NetworkNotCreated(req='--fixed_range_v4')
668
bridge = bridge or FLAGS.flat_network_bridge
670
bridge_required = ['nova.network.manager.FlatManager',
671
'nova.network.manager.FlatDHCPManager']
672
if FLAGS.network_manager in bridge_required:
673
# TODO(tr3buchet) - swap print statement and following line for
674
# raise statement in diablo 4
675
print _('--bridge parameter required or FLAG '
676
'flat_network_bridge must be set to create networks\n'
677
'WARNING! ACHTUNG! Setting the bridge to br100 '
678
'automatically is deprecated and will be removed in '
679
'Diablo milestone 4. Prepare yourself accordingly.')
682
#raise exception.NetworkNotCreated(req='--bridge')
684
bridge_interface = bridge_interface or FLAGS.flat_interface or \
686
if not bridge_interface:
687
interface_required = ['nova.network.manager.FlatDHCPManager',
688
'nova.network.manager.VlanManager']
689
if FLAGS.network_manager in interface_required:
690
raise exception.NetworkNotCreated(req='--bridge_interface')
693
fixed_range_v6 = fixed_range_v6 or FLAGS.fixed_range_v6
694
if not fixed_range_v6:
695
raise exception.NetworkNotCreated(req='with use_ipv6, '
697
gateway_v6 = gateway_v6 or FLAGS.gateway_v6
699
raise exception.NetworkNotCreated(req='with use_ipv6, '
702
# sanitize other input using FLAGS if necessary
704
num_networks = FLAGS.num_networks
706
network_size = FLAGS.network_size
708
multi_host = FLAGS.multi_host
710
multi_host = multi_host == 'T'
712
vlan_start = FLAGS.vlan_start
714
vpn_start = FLAGS.vpn_start
715
if not dns1 and FLAGS.flat_network_dns:
716
dns1 = FLAGS.flat_network_dns
719
net_manager = utils.import_object(FLAGS.network_manager)
720
net_manager.create_networks(context.get_admin_context(),
723
multi_host=multi_host,
724
num_networks=int(num_networks),
725
network_size=int(network_size),
726
vlan_start=int(vlan_start),
727
vpn_start=int(vpn_start),
728
cidr_v6=fixed_range_v6,
729
gateway_v6=gateway_v6,
731
bridge_interface=bridge_interface,
736
"""List all created networks"""
737
print "%-18s\t%-15s\t%-15s\t%-15s\t%-15s\t%-15s\t%-15s" % (
745
for network in db.network_get_all(context.get_admin_context()):
746
print "%-18s\t%-15s\t%-15s\t%-15s\t%-15s\t%-15s\t%-15s" % (
755
@args('--network', dest="fixed_range", metavar='<x.x.x.x/yy>',
756
help='Network to delete')
757
def delete(self, fixed_range):
758
"""Deletes a network"""
759
network = db.network_get_by_cidr(context.get_admin_context(), \
761
if network.project_id is not None:
762
raise ValueError(_('Network must be disassociated from project %s'
763
' before delete' % network.project_id))
764
db.network_delete_safe(context.get_admin_context(), network.id)
767
class VmCommands(object):
768
"""Class for mangaging VM instances."""
770
@args('--host', dest="host", metavar='<host>', help='Host')
771
def list(self, host=None):
772
"""Show a list of all instances"""
774
print "%-10s %-15s %-10s %-10s %-26s %-9s %-9s %-9s" \
775
" %-10s %-10s %-10s %-5s" % (
790
instances = db.instance_get_all(context.get_admin_context())
792
instances = db.instance_get_all_by_host(
793
context.get_admin_context(), host)
795
for instance in instances:
796
print "%-10s %-15s %-10s %-10s %-26s %-9s %-9s %-9s" \
797
" %-10s %-10s %-10s %-5d" % (
798
instance['hostname'],
800
instance['instance_type'].name,
801
instance['state_description'],
802
instance['launched_at'],
803
instance['image_ref'],
804
instance['kernel_id'],
805
instance['ramdisk_id'],
806
instance['project_id'],
808
instance['availability_zone'],
809
instance['launch_index'])
811
@args('--ec2_id', dest='ec2_id', metavar='<ec2 id>', help='EC2 ID')
812
@args('--dest', dest='dest', metavar='<Destanation>',
813
help='destanation node')
814
def live_migration(self, ec2_id, dest):
815
"""Migrates a running instance to a new machine."""
817
ctxt = context.get_admin_context()
818
instance_id = ec2utils.ec2_id_to_id(ec2_id)
820
if (FLAGS.connection_type != 'libvirt' or
821
(FLAGS.connection_type == 'libvirt' and
822
FLAGS.libvirt_type not in ['kvm', 'qemu'])):
823
msg = _('Only KVM and QEmu are supported for now. Sorry!')
824
raise exception.Error(msg)
826
if (FLAGS.volume_driver != 'nova.volume.driver.AOEDriver' and \
827
FLAGS.volume_driver != 'nova.volume.driver.ISCSIDriver'):
828
msg = _("Support only AOEDriver and ISCSIDriver. Sorry!")
829
raise exception.Error(msg)
832
FLAGS.scheduler_topic,
833
{"method": "live_migration",
834
"args": {"instance_id": instance_id,
836
"topic": FLAGS.compute_topic}})
838
print _('Migration of %s initiated.'
839
'Check its progress using euca-describe-instances.') % ec2_id
842
class ServiceCommands(object):
843
"""Enable and disable running services"""
845
@args('--host', dest='host', metavar='<host>', help='Host')
846
@args('--service', dest='service', metavar='<service>',
848
def list(self, host=None, service=None):
850
Show a list of all running services. Filter by host & service name.
852
ctxt = context.get_admin_context()
854
services = db.service_get_all(ctxt)
856
services = [s for s in services if s['host'] == host]
858
services = [s for s in services if s['binary'] == service]
860
delta = now - (svc['updated_at'] or svc['created_at'])
861
alive = (delta.seconds <= 15)
862
art = (alive and ":-)") or "XXX"
866
print "%-10s %-10s %-8s %s %s" % (svc['host'], svc['binary'],
870
@args('--host', dest='host', metavar='<host>', help='Host')
871
@args('--service', dest='service', metavar='<service>',
873
def enable(self, host, service):
874
"""Enable scheduling for a service"""
875
ctxt = context.get_admin_context()
876
svc = db.service_get_by_args(ctxt, host, service)
878
print "Unable to find service"
880
db.service_update(ctxt, svc['id'], {'disabled': False})
882
@args('--host', dest='host', metavar='<host>', help='Host')
883
@args('--service', dest='service', metavar='<service>',
885
def disable(self, host, service):
886
"""Disable scheduling for a service"""
887
ctxt = context.get_admin_context()
888
svc = db.service_get_by_args(ctxt, host, service)
890
print "Unable to find service"
892
db.service_update(ctxt, svc['id'], {'disabled': True})
894
@args('--host', dest='host', metavar='<host>', help='Host')
895
def describe_resource(self, host):
896
"""Describes cpu/memory/hdd info for host."""
898
result = rpc.call(context.get_admin_context(),
899
FLAGS.scheduler_topic,
900
{"method": "show_host_resources",
901
"args": {"host": host}})
903
if type(result) != dict:
904
print _('An unexpected error has occurred.')
905
print _('[Result]'), result
907
cpu = result['resource']['vcpus']
908
mem = result['resource']['memory_mb']
909
hdd = result['resource']['local_gb']
910
cpu_u = result['resource']['vcpus_used']
911
mem_u = result['resource']['memory_mb_used']
912
hdd_u = result['resource']['local_gb_used']
914
print 'HOST\t\t\tPROJECT\t\tcpu\tmem(mb)\tdisk(gb)'
915
print '%s(total)\t\t\t%s\t%s\t%s' % (host, cpu, mem, hdd)
916
print '%s(used)\t\t\t%s\t%s\t%s' % (host, cpu_u, mem_u, hdd_u)
917
for p_id, val in result['usage'].items():
918
print '%s\t\t%s\t\t%s\t%s\t%s' % (host,
924
@args('--host', dest='host', metavar='<host>', help='Host')
925
def update_resource(self, host):
926
"""Updates available vcpu/memory/disk info for host."""
928
ctxt = context.get_admin_context()
929
service_refs = db.service_get_all_by_host(ctxt, host)
930
if len(service_refs) <= 0:
931
raise exception.Invalid(_('%s does not exist.') % host)
933
service_refs = [s for s in service_refs if s['topic'] == 'compute']
934
if len(service_refs) <= 0:
935
raise exception.Invalid(_('%s is not compute node.') % host)
938
db.queue_get_for(ctxt, FLAGS.compute_topic, host),
939
{"method": "update_available_resource"})
942
class HostCommands(object):
945
def list(self, zone=None):
946
"""Show a list of all physical hosts. Filter by zone.
948
print "%-25s\t%-15s" % (_('host'),
950
ctxt = context.get_admin_context()
952
services = db.service_get_all(ctxt)
954
services = [s for s in services if s['availability_zone'] == zone]
957
if not [h for h in hosts if h['host'] == srv['host']]:
961
print "%-25s\t%-15s" % (h['host'], h['availability_zone'])
964
class DbCommands(object):
965
"""Class for managing the database."""
970
@args('--version', dest='version', metavar='<version>',
971
help='Database version')
972
def sync(self, version=None):
973
"""Sync the database up to the most recent version."""
974
return migration.db_sync(version)
977
"""Print the current database version."""
978
print migration.db_version()
981
class VersionCommands(object):
982
"""Class for exposing the codebase version."""
988
print _("%s (%s)") %\
989
(version.version_string(), version.version_string_with_vcs())
995
class VolumeCommands(object):
996
"""Methods for dealing with a cloud in an odd state"""
998
@args('--volume', dest='volume_id', metavar='<volume id>',
1000
def delete(self, volume_id):
1001
"""Delete a volume, bypassing the check that it
1002
must be available."""
1003
ctxt = context.get_admin_context()
1004
volume = db.volume_get(ctxt, param2id(volume_id))
1005
host = volume['host']
1008
print "Volume not yet assigned to host."
1009
print "Deleting volume from database and skipping rpc."
1010
db.volume_destroy(ctxt, param2id(volume_id))
1013
if volume['status'] == 'in-use':
1014
print "Volume is in-use."
1015
print "Detach volume from instance and then try again."
1019
db.queue_get_for(ctxt, FLAGS.volume_topic, host),
1020
{"method": "delete_volume",
1021
"args": {"volume_id": volume['id']}})
1023
@args('--volume', dest='volume_id', metavar='<volume id>',
1025
def reattach(self, volume_id):
1026
"""Re-attach a volume that has previously been attached
1027
to an instance. Typically called after a compute host
1028
has been rebooted."""
1029
ctxt = context.get_admin_context()
1030
volume = db.volume_get(ctxt, param2id(volume_id))
1031
if not volume['instance_id']:
1032
print "volume is not attached to an instance"
1034
instance = db.instance_get(ctxt, volume['instance_id'])
1035
host = instance['host']
1037
db.queue_get_for(ctxt, FLAGS.compute_topic, host),
1038
{"method": "attach_volume",
1039
"args": {"instance_id": instance['id'],
1040
"volume_id": volume['id'],
1041
"mountpoint": volume['mountpoint']}})
1044
class InstanceTypeCommands(object):
1045
"""Class for managing instance types / flavors."""
1047
def _print_instance_types(self, name, val):
1048
deleted = ('', ', inactive')[val["deleted"] == 1]
1049
print ("%s: Memory: %sMB, VCPUS: %s, Storage: %sGB, FlavorID: %s, "
1050
"Swap: %sGB, RXTX Quota: %sGB, RXTX Cap: %sMB%s") % (
1051
name, val["memory_mb"], val["vcpus"], val["local_gb"],
1052
val["flavorid"], val["swap"], val["rxtx_quota"],
1053
val["rxtx_cap"], deleted)
1055
@args('--name', dest='name', metavar='<name>',
1056
help='Name of instance type/flavor')
1057
@args('--memory', dest='memory', metavar='<memory size>',
1059
@args('--cpu', dest='vcpus', metavar='<num cores>', help='Number cpus')
1060
@args('--local_gb', dest='local_gb', metavar='<local_gb>',
1062
@args('--flavor', dest='flavorid', metavar='<flavor id>',
1064
@args('--swap', dest='swap', metavar='<swap>', help='Swap')
1065
@args('--rxtx_quota', dest='rxtx_quota', metavar='<rxtx_quota>',
1067
@args('--rxtx_cap', dest='rxtx_cap', metavar='<rxtx_cap>',
1069
def create(self, name, memory, vcpus, local_gb, flavorid,
1070
swap=0, rxtx_quota=0, rxtx_cap=0):
1071
"""Creates instance types / flavors"""
1073
instance_types.create(name, memory, vcpus, local_gb,
1074
flavorid, swap, rxtx_quota, rxtx_cap)
1075
except exception.InvalidInput, e:
1076
print "Must supply valid parameters to create instance_type"
1079
except exception.ApiError, e:
1082
print "Please ensure instance_type name and flavorid are unique."
1083
print "To complete remove a instance_type, use the --purge flag:"
1084
print "\n # nova-manage instance_type delete <name> --purge\n"
1085
print "Currently defined instance_type names and flavorids:"
1089
print "Unknown error"
1092
print "%s created" % name
1094
@args('--name', dest='name', metavar='<name>',
1095
help='Name of instance type/flavor')
1096
def delete(self, name, purge=None):
1097
"""Marks instance types / flavors as deleted"""
1099
if purge == "--purge":
1100
instance_types.purge(name)
1103
instance_types.destroy(name)
1105
except exception.ApiError:
1106
print "Valid instance type name is required"
1108
except exception.DBError, e:
1109
print "DB Error: %s" % e
1114
print "%s %s" % (name, verb)
1116
@args('--name', dest='name', metavar='<name>',
1117
help='Name of instance type/flavor')
1118
def list(self, name=None):
1119
"""Lists all active or specific instance types / flavors"""
1122
inst_types = instance_types.get_all_types()
1123
elif name == "--all":
1124
inst_types = instance_types.get_all_types(True)
1126
inst_types = instance_types.get_instance_type_by_name(name)
1127
except exception.DBError, e:
1129
if isinstance(inst_types.values()[0], dict):
1130
for k, v in inst_types.iteritems():
1131
self._print_instance_types(k, v)
1133
self._print_instance_types(name, inst_types)
1136
class ImageCommands(object):
1137
"""Methods for dealing with a cloud in an odd state"""
1139
def __init__(self, *args, **kwargs):
1140
self.image_service = image.get_default_image_service()
1142
def _register(self, container_format, disk_format,
1143
path, owner, name=None, is_public='T',
1144
architecture='x86_64', kernel_id=None, ramdisk_id=None):
1145
meta = {'is_public': (is_public == 'T'),
1147
'container_format': container_format,
1148
'disk_format': disk_format,
1149
'properties': {'image_state': 'available',
1150
'project_id': owner,
1151
'architecture': architecture,
1152
'image_location': 'local'}}
1154
meta['properties']['kernel_id'] = int(kernel_id)
1156
meta['properties']['ramdisk_id'] = int(ramdisk_id)
1157
elevated = context.get_admin_context()
1159
with open(path) as ifile:
1160
image = self.image_service.create(elevated, meta, ifile)
1162
print _("Image registered to %(new)s (%(new)08x).") % locals()
1164
except Exception as exc:
1165
print _("Failed to register %(path)s: %(exc)s") % locals()
1167
@args('--image', dest='image', metavar='<image>', help='Image')
1168
@args('--kernel', dest='kernel', metavar='<kernel>', help='Kernel')
1169
@args('--ram', dest='ramdisk', metavar='<ramdisk>', help='RAM disk')
1170
@args('--owner', dest='owner', metavar='<owner>', help='Image owner')
1171
@args('--name', dest='name', metavar='<name>', help='Image name')
1172
@args('--public', dest='is_public', metavar="<'T'|'F'>",
1173
help='Image public or not')
1174
@args('--arch', dest='architecture', metavar='<arch>',
1175
help='Architecture')
1176
def all_register(self, image, kernel, ramdisk, owner, name=None,
1177
is_public='T', architecture='x86_64'):
1178
"""Uploads an image, kernel, and ramdisk into the image_service"""
1179
kernel_id = self.kernel_register(kernel, owner, None,
1180
is_public, architecture)
1181
ramdisk_id = self.ramdisk_register(ramdisk, owner, None,
1182
is_public, architecture)
1183
self.image_register(image, owner, name, is_public,
1184
architecture, 'ami', 'ami',
1185
kernel_id, ramdisk_id)
1187
@args('--path', dest='path', metavar='<path>', help='Image path')
1188
@args('--owner', dest='owner', metavar='<owner>', help='Image owner')
1189
@args('--name', dest='name', metavar='<name>', help='Image name')
1190
@args('--public', dest='is_public', metavar="<'T'|'F'>",
1191
help='Image public or not')
1192
@args('--arch', dest='architecture', metavar='<arch>',
1193
help='Architecture')
1194
@args('--cont_format', dest='container_format',
1195
metavar='<container format>',
1196
help='Container format(default bare)')
1197
@args('--disk_format', dest='disk_format', metavar='<disk format>',
1198
help='Disk format(default: raw)')
1199
@args('--kernel', dest='kernel_id', metavar='<kernel>', help='Kernel')
1200
@args('--ram', dest='ramdisk_id', metavar='<ramdisk>', help='RAM disk')
1201
def image_register(self, path, owner, name=None, is_public='T',
1202
architecture='x86_64', container_format='bare',
1203
disk_format='raw', kernel_id=None, ramdisk_id=None):
1204
"""Uploads an image into the image_service"""
1205
return self._register(container_format, disk_format, path,
1206
owner, name, is_public, architecture,
1207
kernel_id, ramdisk_id)
1209
@args('--path', dest='path', metavar='<path>', help='Image path')
1210
@args('--owner', dest='owner', metavar='<owner>', help='Image owner')
1211
@args('--name', dest='name', metavar='<name>', help='Image name')
1212
@args('--public', dest='is_public', metavar="<'T'|'F'>",
1213
help='Image public or not')
1214
@args('--arch', dest='architecture', metavar='<arch>',
1215
help='Architecture')
1216
def kernel_register(self, path, owner, name=None, is_public='T',
1217
architecture='x86_64'):
1218
"""Uploads a kernel into the image_service"""
1219
return self._register('aki', 'aki', path, owner, name,
1220
is_public, architecture)
1222
@args('--path', dest='path', metavar='<path>', help='Image path')
1223
@args('--owner', dest='owner', metavar='<owner>', help='Image owner')
1224
@args('--name', dest='name', metavar='<name>', help='Image name')
1225
@args('--public', dest='is_public', metavar="<'T'|'F'>",
1226
help='Image public or not')
1227
@args('--arch', dest='architecture', metavar='<arch>',
1228
help='Architecture')
1229
def ramdisk_register(self, path, owner, name=None, is_public='T',
1230
architecture='x86_64'):
1231
"""Uploads a ramdisk into the image_service"""
1232
return self._register('ari', 'ari', path, owner, name,
1233
is_public, architecture)
1235
def _lookup(self, old_image_id):
1237
internal_id = ec2utils.ec2_id_to_id(old_image_id)
1238
image = self.image_service.show(context, internal_id)
1239
except (exception.InvalidEc2Id, exception.ImageNotFound):
1240
image = self.image_service.show_by_name(context, old_image_id)
1243
def _old_to_new(self, old):
1244
mapping = {'machine': 'ami',
1247
container_format = mapping[old['type']]
1248
disk_format = container_format
1249
if container_format == 'ami' and not old.get('kernelId'):
1250
container_format = 'bare'
1252
new = {'disk_format': disk_format,
1253
'container_format': container_format,
1254
'is_public': old['isPublic'],
1255
'name': old['imageId'],
1256
'properties': {'image_state': old['imageState'],
1257
'project_id': old['imageOwnerId'],
1258
'architecture': old['architecture'],
1259
'image_location': old['imageLocation']}}
1260
if old.get('kernelId'):
1261
new['properties']['kernel_id'] = self._lookup(old['kernelId'])
1262
if old.get('ramdiskId'):
1263
new['properties']['ramdisk_id'] = self._lookup(old['ramdiskId'])
1266
def _convert_images(self, images):
1267
elevated = context.get_admin_context()
1268
for image_path, image_metadata in images.iteritems():
1269
meta = self._old_to_new(image_metadata)
1272
with open(image_path) as ifile:
1273
image = self.image_service.create(elevated, meta, ifile)
1275
print _("Image %(old)s converted to " \
1276
"%(new)s (%(new)08x).") % locals()
1277
except Exception as exc:
1278
print _("Failed to convert %(old)s: %(exc)s") % locals()
1280
@args('--dir', dest='directory', metavar='<path>',
1281
help='Images directory')
1282
def convert(self, directory):
1283
"""Uploads old objectstore images in directory to new service"""
1286
directory = os.path.abspath(directory)
1287
for fn in glob.glob("%s/*/info.json" % directory):
1289
image_path = os.path.join(fn.rpartition('/')[0], 'image')
1290
with open(fn) as metadata_file:
1291
image_metadata = json.load(metadata_file)
1292
if image_metadata['type'] == 'machine':
1293
machine_images[image_path] = image_metadata
1295
other_images[image_path] = image_metadata
1297
print _("Failed to load %(fn)s.") % locals()
1298
# NOTE(vish): do kernels and ramdisks first so images
1299
self._convert_images(other_images)
1300
self._convert_images(machine_images)
1303
class AgentBuildCommands(object):
1304
"""Class for managing agent builds."""
1306
def create(self, os, architecture, version, url, md5hash,
1308
"""Creates a new agent build."""
1309
ctxt = context.get_admin_context()
1310
agent_build = db.agent_build_create(ctxt,
1311
{'hypervisor': hypervisor,
1313
'architecture': architecture,
1316
'md5hash': md5hash})
1318
def delete(self, os, architecture, hypervisor='xen'):
1319
"""Deletes an existing agent build."""
1320
ctxt = context.get_admin_context()
1321
agent_build_ref = db.agent_build_get_by_triple(ctxt,
1322
hypervisor, os, architecture)
1323
db.agent_build_destroy(ctxt, agent_build_ref['id'])
1325
def list(self, hypervisor=None):
1326
"""Lists all agent builds.
1327
arguments: <none>"""
1328
fmt = "%-10s %-8s %12s %s"
1329
ctxt = context.get_admin_context()
1331
for agent_build in db.agent_build_get_all(ctxt):
1332
buildlist = by_hypervisor.get(agent_build.hypervisor)
1334
buildlist = by_hypervisor[agent_build.hypervisor] = []
1336
buildlist.append(agent_build)
1338
for key, buildlist in by_hypervisor.iteritems():
1339
if hypervisor and key != hypervisor:
1342
print "Hypervisor: %s" % key
1343
print fmt % ('-' * 10, '-' * 8, '-' * 12, '-' * 32)
1344
for agent_build in buildlist:
1345
print fmt % (agent_build.os, agent_build.architecture,
1346
agent_build.version, agent_build.md5hash)
1347
print ' %s' % agent_build.url
1351
def modify(self, os, architecture, version, url, md5hash,
1353
"""Update an existing agent build."""
1354
ctxt = context.get_admin_context()
1355
agent_build_ref = db.agent_build_get_by_triple(ctxt,
1356
hypervisor, os, architecture)
1357
db.agent_build_update(ctxt, agent_build_ref['id'],
1358
{'version': version,
1360
'md5hash': md5hash})
1363
class ConfigCommands(object):
1364
"""Class for exposing the flags defined by flag_file(s)."""
1370
print FLAGS.FlagsIntoString()
216
('user', UserCommands),
1374
('account', AccountCommands),
1375
('agent', AgentBuildCommands),
1376
('config', ConfigCommands),
1378
('fixed', FixedIpCommands),
1379
('flavor', InstanceTypeCommands),
1380
('floating', FloatingIpCommands),
1381
('host', HostCommands),
1382
('instance_type', InstanceTypeCommands),
1383
('image', ImageCommands),
1384
('network', NetworkCommands),
217
1385
('project', ProjectCommands),
218
1386
('role', RoleCommands),
219
('vpn', VpnCommands),
1387
('service', ServiceCommands),
1388
('shell', ShellCommands),
1389
('user', UserCommands),
1390
('version', VersionCommands),
1392
('volume', VolumeCommands),
1393
('vpn', VpnCommands)]
223
1396
def lazy_match(name, key_value_tuples):