From b344877bdf24985dea5342060c989a9d06fe0964 Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Fri, 25 Feb 2011 13:01:32 -0800 Subject: add a caching layer to the has_role call to increase performance --- nova/api/ec2/__init__.py | 6 ++--- nova/auth/manager.py | 58 +++++++++++++++++++++++++++++++++++------------- nova/flags.py | 2 ++ 3 files changed, 47 insertions(+), 19 deletions(-) diff --git a/nova/api/ec2/__init__.py b/nova/api/ec2/__init__.py index 5adc2c075..7a9c4f957 100644 --- a/nova/api/ec2/__init__.py +++ b/nova/api/ec2/__init__.py @@ -46,8 +46,6 @@ flags.DEFINE_integer('lockout_minutes', 15, 'Number of minutes to lockout if triggered.') flags.DEFINE_integer('lockout_window', 15, 'Number of minutes for lockout window.') -flags.DEFINE_list('lockout_memcached_servers', None, - 'Memcached servers or None for in process cache.') class RequestLogging(wsgi.Middleware): @@ -104,11 +102,11 @@ class Lockout(wsgi.Middleware): def __init__(self, application): """middleware can use fake for testing.""" - if FLAGS.lockout_memcached_servers: + if FLAGS.memcached_servers: import memcache else: from nova import fakememcache as memcache - self.mc = memcache.Client(FLAGS.lockout_memcached_servers, + self.mc = memcache.Client(FLAGS.memcached_servers, debug=0) super(Lockout, self).__init__(application) diff --git a/nova/auth/manager.py b/nova/auth/manager.py index 450ab803a..906734799 100644 --- a/nova/auth/manager.py +++ b/nova/auth/manager.py @@ -214,6 +214,13 @@ class AuthManager(object): if driver or not getattr(self, 'driver', None): self.driver = utils.import_class(driver or FLAGS.auth_driver) + if FLAGS.memcached_servers: + import memcache + else: + from nova import fakememcache as memcache + self.mc = memcache.Client(FLAGS.memcached_servers, + debug=0) + def authenticate(self, access, signature, params, verb='GET', server_string='127.0.0.1:8773', path='/', check_type='ec2', headers=None): @@ -351,6 +358,25 @@ class AuthManager(object): if self.has_role(user, role): return True + def _build_mc_key(self, user, role, project=None): + return "rolecache-%s-%s-%s" % (User.safe_id(user), role, + (Project.safe_id(project) if project else 'None')) + + def _clear_mc_key(self, user, role, project=None): + # (anthony) it would be better to delete the key + self.mc.set(self._build_mc_key(user, role, project), None) + + def _has_role(self, user, role, project=None): + with self.driver() as drv: + mc_key = self._build_mc_key(user, role, project) + rslt = self.mc.get(mc_key) + if rslt == None: + rslt = drv.has_role(user, role, project) + self.mc.set(mc_key, rslt) + return rslt + else: + return rslt + def has_role(self, user, role, project=None): """Checks existence of role for user @@ -374,24 +400,24 @@ class AuthManager(object): @rtype: bool @return: True if the user has the role. """ - with self.driver() as drv: - if role == 'projectmanager': - if not project: - raise exception.Error(_("Must specify project")) - return self.is_project_manager(user, project) + if role == 'projectmanager': + if not project: + raise exception.Error(_("Must specify project")) + return self.is_project_manager(user, project) + + global_role = self._has_role(User.safe_id(user), + role, + None) - global_role = drv.has_role(User.safe_id(user), - role, - None) - if not global_role: - return global_role + if not global_role: + return global_role - if not project or role in FLAGS.global_roles: - return global_role + if not project or role in FLAGS.global_roles: + return global_role - return drv.has_role(User.safe_id(user), - role, - Project.safe_id(project)) + return self._has_role(User.safe_id(user), + role, + Project.safe_id(project)) def add_role(self, user, role, project=None): """Adds role for user @@ -423,6 +449,7 @@ class AuthManager(object): LOG.audit(_("Adding sitewide role %(role)s to user %(uid)s") % locals()) with self.driver() as drv: + self._clear_mc_key(uid, role, pid) drv.add_role(uid, role, pid) def remove_role(self, user, role, project=None): @@ -451,6 +478,7 @@ class AuthManager(object): LOG.audit(_("Removing sitewide role %(role)s" " from user %(uid)s") % locals()) with self.driver() as drv: + self._clear_mc_key(uid, role, pid) drv.remove_role(uid, role, pid) @staticmethod diff --git a/nova/flags.py b/nova/flags.py index 8cf199b2f..f885de293 100644 --- a/nova/flags.py +++ b/nova/flags.py @@ -354,3 +354,5 @@ DEFINE_string('host', socket.gethostname(), DEFINE_string('node_availability_zone', 'nova', 'availability zone of this node') +DEFINE_list('memcached_servers', None, + 'Memcached servers or None for in process cache.') -- cgit From 47c312bb659d0ad49a678c8213093827e6067f31 Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Fri, 25 Feb 2011 16:41:48 -0800 Subject: only create auth connection if cache misses --- nova/auth/manager.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/nova/auth/manager.py b/nova/auth/manager.py index 906734799..511bc3a64 100644 --- a/nova/auth/manager.py +++ b/nova/auth/manager.py @@ -367,15 +367,15 @@ class AuthManager(object): self.mc.set(self._build_mc_key(user, role, project), None) def _has_role(self, user, role, project=None): - with self.driver() as drv: - mc_key = self._build_mc_key(user, role, project) - rslt = self.mc.get(mc_key) - if rslt == None: + mc_key = self._build_mc_key(user, role, project) + rslt = self.mc.get(mc_key) + if rslt == None: + with self.driver() as drv: rslt = drv.has_role(user, role, project) self.mc.set(mc_key, rslt) return rslt - else: - return rslt + else: + return rslt def has_role(self, user, role, project=None): """Checks existence of role for user -- cgit From e0ba72946011b67a218e3c619b3105529bb43e53 Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Fri, 25 Feb 2011 17:18:41 -0800 Subject: force memcache key to be str --- nova/auth/manager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nova/auth/manager.py b/nova/auth/manager.py index 511bc3a64..84c8a6cb2 100644 --- a/nova/auth/manager.py +++ b/nova/auth/manager.py @@ -359,8 +359,8 @@ class AuthManager(object): return True def _build_mc_key(self, user, role, project=None): - return "rolecache-%s-%s-%s" % (User.safe_id(user), role, - (Project.safe_id(project) if project else 'None')) + return str("rolecache-%s-%s-%s" % (User.safe_id(user), role, + (Project.safe_id(project) if project else 'None'))) def _clear_mc_key(self, user, role, project=None): # (anthony) it would be better to delete the key -- cgit From 91458f29f8b04407471d9d94a5ad165817f72a43 Mon Sep 17 00:00:00 2001 From: Muneyuki Noguchi Date: Fri, 25 Mar 2011 11:47:17 +0900 Subject: Restore volume state on migration failure. --- nova/compute/manager.py | 19 +++++++++++++++++-- nova/virt/libvirt_conn.py | 2 +- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 468771f46..356d20285 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -1003,7 +1003,7 @@ class ComputeManager(manager.SchedulerDependentManager): "Domain not found: no domain with matching name.\" " "This error can be safely ignored.")) - def recover_live_migration(self, ctxt, instance_ref, host=None): + def recover_live_migration(self, ctxt, instance_ref, host=None, dest=None): """Recovers Instance/volume state from migrating -> running. :param ctxt: security context @@ -1011,6 +1011,7 @@ class ComputeManager(manager.SchedulerDependentManager): :param host: DB column value is updated by this hostname. if none, the host instance currently running is selected. + :param dest: destination host """ @@ -1024,7 +1025,21 @@ class ComputeManager(manager.SchedulerDependentManager): 'host': host}) for volume in instance_ref['volumes']: - self.db.volume_update(ctxt, volume['id'], {'status': 'in-use'}) + volume_id = volume['id'] + self.db.volume_update(ctxt, volume_id, {'status': 'in-use'}) + if dest: + topic = self.db.queue_get_for(ctxt, FLAGS.compute_topic, dest) + rpc.call(ctxt, topic, + {"method": "restore_volume_state", + "args": {'volume_id': volume_id}}) + + def restore_volume_state(self, context, volume_id): + """Restore volume state on migration failure. + + :param context: security context + :param volume_id: nova.db.sqlalchemy.models.Volume.id + """ + self.volume_manager.remove_compute_volume(context, volume_id) def periodic_tasks(self, context=None): """Tasks to be run at a periodic interval.""" diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 2cecb010d..5c6baa36e 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -1370,7 +1370,7 @@ class LibvirtConnection(driver.ComputeDriver): FLAGS.live_migration_bandwidth) except Exception: - recover_method(ctxt, instance_ref) + recover_method(ctxt, instance_ref, None, dest) raise # Waiting for completion of live_migration. -- cgit From e5b0f3921331b5c0acbe321b00e2a9fa8d27be4e Mon Sep 17 00:00:00 2001 From: Muneyuki Noguchi Date: Tue, 29 Mar 2011 10:40:48 +0900 Subject: Add remove_volume to compute API. --- nova/compute/api.py | 7 +++++++ nova/compute/manager.py | 26 ++++++++++++++------------ 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/nova/compute/api.py b/nova/compute/api.py index 266cbe677..0cdb8f4b7 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -668,6 +668,13 @@ class API(base.Base): "volume_id": volume_id}}) return instance + def remove_volume(self, context, volume_id, host): + """Remove volume on specified compute host.""" + rpc.call(context, + self.db.queue_get_for(context, FLAGS.compute_topic, host), + {"method": "remove_volume", + "args": {'volume_id': volume_id}}) + def associate_floating_ip(self, context, instance_id, address): instance = self.get(context, instance_id) self.network_api.associate_floating_ip(context, diff --git a/nova/compute/manager.py b/nova/compute/manager.py index aa612b137..bbd1fed1a 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -46,6 +46,7 @@ import functools from eventlet import greenthread +from nova import compute from nova import exception from nova import flags from nova import log as logging @@ -772,6 +773,14 @@ class ComputeManager(manager.SchedulerDependentManager): self.db.volume_detached(context, volume_id) return True + def remove_volume(self, context, volume_id): + """Remove volume on compute host. + + :param context: security context + :param volume_id: nova.db.sqlalchemy.models.Volume.id + """ + self.volume_manager.remove_compute_volume(context, volume_id) + @exception.wrap_exception def compare_cpu(self, context, cpu_info): """Checks the host cpu is compatible to a cpu given by xml. @@ -1018,22 +1027,15 @@ class ComputeManager(manager.SchedulerDependentManager): 'state': power_state.RUNNING, 'host': host}) + if dest: + # NOTE(noguchimn): We set image_service here + # not to import an image service object. + compute_api = compute.API(image_service=1) for volume in instance_ref['volumes']: volume_id = volume['id'] self.db.volume_update(ctxt, volume_id, {'status': 'in-use'}) if dest: - topic = self.db.queue_get_for(ctxt, FLAGS.compute_topic, dest) - rpc.call(ctxt, topic, - {"method": "restore_volume_state", - "args": {'volume_id': volume_id}}) - - def restore_volume_state(self, context, volume_id): - """Restore volume state on migration failure. - - :param context: security context - :param volume_id: nova.db.sqlalchemy.models.Volume.id - """ - self.volume_manager.remove_compute_volume(context, volume_id) + compute_api.remove_volume(ctxt, volume_id, dest) def periodic_tasks(self, context=None): """Tasks to be run at a periodic interval.""" -- cgit From b5f0d2c22ce48d06dc502f7790ed48fdf007d7f6 Mon Sep 17 00:00:00 2001 From: Muneyuki Noguchi Date: Thu, 31 Mar 2011 17:39:00 +0900 Subject: Add volume.API.remove_from_compute instead of compute.API.remove_volume. --- nova/compute/api.py | 7 ------- nova/compute/manager.py | 12 +++++------- nova/volume/api.py | 7 +++++++ 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/nova/compute/api.py b/nova/compute/api.py index 63983afd8..1dbd73f8f 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -687,13 +687,6 @@ class API(base.Base): "volume_id": volume_id}}) return instance - def remove_volume(self, context, volume_id, host): - """Remove volume on specified compute host.""" - rpc.call(context, - self.db.queue_get_for(context, FLAGS.compute_topic, host), - {"method": "remove_volume", - "args": {'volume_id': volume_id}}) - def associate_floating_ip(self, context, instance_id, address): instance = self.get(context, instance_id) self.network_api.associate_floating_ip(context, diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 8ce8a5d86..85bcd7590 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -46,13 +46,13 @@ import functools from eventlet import greenthread -from nova import compute from nova import exception from nova import flags from nova import log as logging from nova import manager from nova import rpc from nova import utils +from nova import volume from nova.compute import power_state from nova.virt import driver @@ -1037,14 +1037,12 @@ class ComputeManager(manager.SchedulerDependentManager): 'host': host}) if dest: - # NOTE(noguchimn): We set image_service here - # not to import an image service object. - compute_api = compute.API(image_service=1) - for volume in instance_ref['volumes']: - volume_id = volume['id'] + volume_api = volume.API() + for volume_ref in instance_ref['volumes']: + volume_id = volume_ref['id'] self.db.volume_update(ctxt, volume_id, {'status': 'in-use'}) if dest: - compute_api.remove_volume(ctxt, volume_id, dest) + volume_api.remove_from_compute(ctxt, volume_id, dest) def periodic_tasks(self, context=None): """Tasks to be run at a periodic interval.""" diff --git a/nova/volume/api.py b/nova/volume/api.py index 4b4bb9dc5..09befb647 100644 --- a/nova/volume/api.py +++ b/nova/volume/api.py @@ -103,3 +103,10 @@ class API(base.Base): # TODO(vish): abstract status checking? if volume['status'] == "available": raise exception.ApiError(_("Volume is already detached")) + + def remove_from_compute(self, context, volume_id, host): + """Remove volume from specified compute host.""" + rpc.call(context, + self.db.queue_get_for(context, FLAGS.compute_topic, host), + {"method": "remove_volume", + "args": {'volume_id': volume_id}}) -- cgit From a8d186d212ffbc628fc2b2672eca1e0557c57414 Mon Sep 17 00:00:00 2001 From: Eldar Nugaev Date: Sun, 3 Apr 2011 03:45:33 +0400 Subject: split up to_xml to creation xml_info and filling the template --- nova/tests/test_virt.py | 20 ++++++-------------- nova/virt/libvirt_conn.py | 12 +++++++----- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/nova/tests/test_virt.py b/nova/tests/test_virt.py index 958c8e3e2..62afcd1f1 100644 --- a/nova/tests/test_virt.py +++ b/nova/tests/test_virt.py @@ -31,9 +31,7 @@ from nova import test from nova import utils from nova.api.ec2 import cloud from nova.auth import manager -from nova.compute import manager as compute_manager from nova.compute import power_state -from nova.db.sqlalchemy import models from nova.virt import libvirt_conn libvirt = None @@ -269,7 +267,7 @@ class LibvirtConnTestCase(test.TestCase): self.assertTrue(len(target) > 0) def _check_xml_and_uri(self, instance, expect_ramdisk, expect_kernel, - rescue=False): + rescue=False, network_info=None): user_context = context.RequestContext(project=self.project, user=self.user) instance_ref = db.instance_create(user_context, instance) @@ -327,19 +325,13 @@ class LibvirtConnTestCase(test.TestCase): check = (lambda t: t.find('./os/initrd'), None) check_list.append(check) + parameter = './devices/interface/filterref/parameter' common_checks = [ (lambda t: t.find('.').tag, 'domain'), - (lambda t: t.find( - './devices/interface/filterref/parameter').get('name'), 'IP'), - (lambda t: t.find( - './devices/interface/filterref/parameter').get( - 'value'), '10.11.12.13'), - (lambda t: t.findall( - './devices/interface/filterref/parameter')[1].get( - 'name'), 'DHCPSERVER'), - (lambda t: t.findall( - './devices/interface/filterref/parameter')[1].get( - 'value'), '10.0.0.1'), + (lambda t: t.find(parameter).get('name'), 'IP'), + (lambda t: t.find(parameter).get('value'), '10.11.12.13'), + (lambda t: t.findall(parameter)[1].get('name'), 'DHCPSERVER'), + (lambda t: t.findall(parameter)[1].get('value'), '10.0.0.1'), (lambda t: t.find('./devices/serial/source').get( 'path').split('/')[1], 'console.log'), (lambda t: t.find('./memory').text, '2097152')] diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index f34ea7225..910d8a634 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -936,7 +936,7 @@ class LibvirtConnection(driver.ComputeDriver): return result - def to_xml(self, instance, rescue=False, network_info=None): + def _prepare_xml_info(self, instance, rescue=False, network_info=None): # TODO(termie): cache? LOG.debug(_('instance %s: starting toXML method'), instance['name']) @@ -947,8 +947,7 @@ class LibvirtConnection(driver.ComputeDriver): nics = [] for (network, mapping) in network_info: - nics.append(self._get_nic_for_xml(network, - mapping)) + nics.append(self._get_nic_for_xml(network, mapping)) # FIXME(vish): stick this in db instance_type_name = instance['instance_type'] instance_type = instance_types.get_instance_type(instance_type_name) @@ -979,10 +978,13 @@ class LibvirtConnection(driver.ComputeDriver): xml_info['ramdisk'] = xml_info['basepath'] + "/ramdisk" xml_info['disk'] = xml_info['basepath'] + "/disk" + + return xml_info + def to_xml(self, instance, rescue=False, network_info=None): + xml_info = self._prepare_xml_info(instance, rescue, network_info) xml = str(Template(self.libvirt_xml, searchList=[xml_info])) - LOG.debug(_('instance %s: finished toXML method'), - instance['name']) + LOG.debug(_('instance %s: finished toXML method'), instance['name']) return xml def get_info(self, instance_name): -- cgit From 74d9a325a452fb927e5edddca3f1b7edd35d1496 Mon Sep 17 00:00:00 2001 From: Eldar Nugaev Date: Sun, 3 Apr 2011 21:18:35 +0400 Subject: added preparing_xml test --- nova/tests/test_virt.py | 41 +++++++++++++++++++++++++++++++++++++++++ nova/virt/libvirt_conn.py | 24 +++++++----------------- 2 files changed, 48 insertions(+), 17 deletions(-) diff --git a/nova/tests/test_virt.py b/nova/tests/test_virt.py index 62afcd1f1..319544099 100644 --- a/nova/tests/test_virt.py +++ b/nova/tests/test_virt.py @@ -192,6 +192,47 @@ class LibvirtConnTestCase(test.TestCase): return db.service_create(context.get_admin_context(), service_ref) + + def _create_network_info(self, count=1): + fake = 'fake' + fake_ip = '0.0.0.0/0' + network = {'gateway': fake, + 'gateway_v6': fake, + 'bridge': fake, + 'cidr': fake_ip, + 'cidr_v6': fake_ip} + mapping = {'mac': fake, + 'ips': [{'ip': fake_ip}]} + + return [(network, mapping) for x in xrange(0, count)] + + def test_preparing_xml_info(self): + conn = libvirt_conn.LibvirtConnection(True) + instance_ref = db.instance_create(self.context, self.test_instance) + + result = conn._prepare_xml_info(instance_ref, False) + self.assertFalse(result['nics']) + + result = conn._prepare_xml_info(instance_ref, False, + self._create_network_info()) + self.assertTrue(len(result['nics']) == 1) + + result = conn._prepare_xml_info(instance_ref, False, + self._create_network_info(2)) + self.assertTrue(len(result['nics']) == 2) + + def test_get_nic_for_xml(self): + conn = libvirt_conn.LibvirtConnection(True) + network, mapping = self._create_network_info()[0] + FLAGS.use_ipv6 = False + params_1 = conn._get_nic_for_xml(network, mapping)['extra_params'] + FLAGS.use_ipv6 = True + params_2 = conn._get_nic_for_xml(network, mapping)['extra_params'] + self.assertTrue(params_1.find('PROJNETV6') == -1) + self.assertTrue(params_1.find('PROJMASKV6') == -1) + self.assertTrue(params_2.find('PROJNETV6') > -1) + self.assertTrue(params_2.find('PROJMASKV6') > -1) + def test_xml_and_uri_no_ramdisk_no_kernel(self): instance_data = dict(self.test_instance) self._check_xml_and_uri(instance_data, diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 910d8a634..8af5eb025 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -899,26 +899,16 @@ class LibvirtConnection(driver.ComputeDriver): mac_id = mapping['mac'].replace(':', '') if FLAGS.allow_project_net_traffic: + template = "\n" + net, mask = _get_net_and_mask(network['cidr']) + values = [("PROJNET", net), ("PROJMASK", mask)] if FLAGS.use_ipv6: - net, mask = _get_net_and_mask(network['cidr']) net_v6, prefixlen_v6 = _get_net_and_prefixlen( network['cidr_v6']) - extra_params = ("\n" - "\n" - "\n" - "\n") % \ - (net, mask, net_v6, prefixlen_v6) - else: - net, mask = _get_net_and_mask(network['cidr']) - extra_params = ("\n" - "\n") % \ - (net, mask) + values.extend([("PROJNETV6", net_v6), + ("PROJMASKV6", prefixlen_v6)]) + + extra_params = "".join([template % value for value in values]) else: extra_params = "\n" -- cgit From 8969cb1f22a7760dc7e17c578a686f088b1a8d89 Mon Sep 17 00:00:00 2001 From: Eldar Nugaev Date: Sun, 3 Apr 2011 22:50:38 +0400 Subject: add multi_nic_test --- nova/tests/test_virt.py | 14 ++++++++++++-- nova/virt/libvirt_conn.py | 3 +-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/nova/tests/test_virt.py b/nova/tests/test_virt.py index 319544099..b6482503e 100644 --- a/nova/tests/test_virt.py +++ b/nova/tests/test_virt.py @@ -192,7 +192,6 @@ class LibvirtConnTestCase(test.TestCase): return db.service_create(context.get_admin_context(), service_ref) - def _create_network_info(self, count=1): fake = 'fake' fake_ip = '0.0.0.0/0' @@ -224,6 +223,7 @@ class LibvirtConnTestCase(test.TestCase): def test_get_nic_for_xml(self): conn = libvirt_conn.LibvirtConnection(True) network, mapping = self._create_network_info()[0] + backup = FLAGS.use_ipv6 FLAGS.use_ipv6 = False params_1 = conn._get_nic_for_xml(network, mapping)['extra_params'] FLAGS.use_ipv6 = True @@ -232,6 +232,7 @@ class LibvirtConnTestCase(test.TestCase): self.assertTrue(params_1.find('PROJMASKV6') == -1) self.assertTrue(params_2.find('PROJNETV6') > -1) self.assertTrue(params_2.find('PROJMASKV6') > -1) + FLAGS.use_ipv6 = backup def test_xml_and_uri_no_ramdisk_no_kernel(self): instance_data = dict(self.test_instance) @@ -268,6 +269,15 @@ class LibvirtConnTestCase(test.TestCase): instance_data = dict(self.test_instance) self._check_xml_and_container(instance_data) + def test_multi_nic(self): + instance_data = dict(self.test_instance) + network_info = self._create_network_info(2) + conn = libvirt_conn.LibvirtConnection(True) + instance_ref = db.instance_create(self.context, instance_data) + xml = conn.to_xml(instance_ref, False, network_info) + tree = xml_to_tree(xml) + self.assertEquals(len(tree.findall("./devices/interface")), 2) + def _check_xml_and_container(self, instance): user_context = context.RequestContext(project=self.project, user=self.user) @@ -308,7 +318,7 @@ class LibvirtConnTestCase(test.TestCase): self.assertTrue(len(target) > 0) def _check_xml_and_uri(self, instance, expect_ramdisk, expect_kernel, - rescue=False, network_info=None): + rescue=False): user_context = context.RequestContext(project=self.project, user=self.user) instance_ref = db.instance_create(user_context, instance) diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 8af5eb025..5c7540927 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -908,7 +908,7 @@ class LibvirtConnection(driver.ComputeDriver): values.extend([("PROJNETV6", net_v6), ("PROJMASKV6", prefixlen_v6)]) - extra_params = "".join([template % value for value in values]) + extra_params = "".join([template % value for value in values]) else: extra_params = "\n" @@ -968,7 +968,6 @@ class LibvirtConnection(driver.ComputeDriver): xml_info['ramdisk'] = xml_info['basepath'] + "/ramdisk" xml_info['disk'] = xml_info['basepath'] + "/disk" - return xml_info def to_xml(self, instance, rescue=False, network_info=None): -- cgit From c1120caaa8c8ed8902b5634da56b2bd5478662e1 Mon Sep 17 00:00:00 2001 From: Muneyuki Noguchi Date: Mon, 4 Apr 2011 10:25:58 +0900 Subject: Use keyword arguments. --- nova/virt/libvirt_conn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index c5a71d244..c03c2ae1d 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -1475,7 +1475,7 @@ class LibvirtConnection(driver.ComputeDriver): FLAGS.live_migration_bandwidth) except Exception: - recover_method(ctxt, instance_ref, None, dest) + recover_method(ctxt, instance_ref, dest=dest) raise # Waiting for completion of live_migration. -- cgit From 80549a0085e7c3a90b117b4c9df5a77b4ecd0843 Mon Sep 17 00:00:00 2001 From: Eldar Nugaev Date: Mon, 4 Apr 2011 18:33:50 +0400 Subject: improving tests --- nova/tests/test_virt.py | 76 +++++++++++++++++++++++++++++++++-------------- nova/virt/libvirt_conn.py | 44 +++++++++++++-------------- 2 files changed, 75 insertions(+), 45 deletions(-) diff --git a/nova/tests/test_virt.py b/nova/tests/test_virt.py index b6482503e..ae813cb80 100644 --- a/nova/tests/test_virt.py +++ b/nova/tests/test_virt.py @@ -44,6 +44,22 @@ def _concurrency(wait, done, target): done.send() +def _create_network_info(count=1): + fake = 'fake' + fake_ip = '0.0.0.0/0' + fake_ip_2 = '0.0.0.1/0' + fake_ip_3 = '0.0.0.1/0' + network = {'gateway': fake, + 'gateway_v6': fake, + 'bridge': fake, + 'cidr': fake_ip, + 'cidr_v6': fake_ip} + mapping = {'mac': fake, + 'ips': [{'ip': fake_ip}, {'ip': fake_ip}], + 'ip6s': [{'ip': fake_ip}, {'ip': fake_ip_2}, {'ip': fake_ip_3}]} + return [(network, mapping) for x in xrange(0, count)] + + class CacheConcurrencyTestCase(test.TestCase): def setUp(self): super(CacheConcurrencyTestCase, self).setUp() @@ -192,19 +208,6 @@ class LibvirtConnTestCase(test.TestCase): return db.service_create(context.get_admin_context(), service_ref) - def _create_network_info(self, count=1): - fake = 'fake' - fake_ip = '0.0.0.0/0' - network = {'gateway': fake, - 'gateway_v6': fake, - 'bridge': fake, - 'cidr': fake_ip, - 'cidr_v6': fake_ip} - mapping = {'mac': fake, - 'ips': [{'ip': fake_ip}]} - - return [(network, mapping) for x in xrange(0, count)] - def test_preparing_xml_info(self): conn = libvirt_conn.LibvirtConnection(True) instance_ref = db.instance_create(self.context, self.test_instance) @@ -213,16 +216,16 @@ class LibvirtConnTestCase(test.TestCase): self.assertFalse(result['nics']) result = conn._prepare_xml_info(instance_ref, False, - self._create_network_info()) + _create_network_info()) self.assertTrue(len(result['nics']) == 1) result = conn._prepare_xml_info(instance_ref, False, - self._create_network_info(2)) + _create_network_info(2)) self.assertTrue(len(result['nics']) == 2) def test_get_nic_for_xml(self): conn = libvirt_conn.LibvirtConnection(True) - network, mapping = self._create_network_info()[0] + network, mapping = _create_network_info()[0] backup = FLAGS.use_ipv6 FLAGS.use_ipv6 = False params_1 = conn._get_nic_for_xml(network, mapping)['extra_params'] @@ -271,12 +274,19 @@ class LibvirtConnTestCase(test.TestCase): def test_multi_nic(self): instance_data = dict(self.test_instance) - network_info = self._create_network_info(2) + network_info = _create_network_info(2) conn = libvirt_conn.LibvirtConnection(True) instance_ref = db.instance_create(self.context, instance_data) xml = conn.to_xml(instance_ref, False, network_info) tree = xml_to_tree(xml) - self.assertEquals(len(tree.findall("./devices/interface")), 2) + interfaces = tree.findall("./devices/interface") + self.assertEquals(len(interfaces), 2) + parameters = interfaces[0].findall('./filterref/parameter') + self.assertEquals(interfaces[0].get('type'), 'bridge') + self.assertEquals(parameters[0].get('name'), 'IP') + self.assertEquals(parameters[0].get('value'), '0.0.0.0/0') + self.assertEquals(parameters[1].get('name'), 'DHCPSERVER') + self.assertEquals(parameters[1].get('value'), 'fake') def _check_xml_and_container(self, instance): user_context = context.RequestContext(project=self.project, @@ -656,11 +666,14 @@ class IptablesFirewallTestCase(test.TestCase): '# Completed on Tue Jan 18 23:47:56 2011', ] + def _create_instance_ref(self): + return db.instance_create(self.context, + {'user_id': 'fake', + 'project_id': 'fake', + 'mac_address': '56:12:12:12:12:12'}) + def test_static_filters(self): - instance_ref = db.instance_create(self.context, - {'user_id': 'fake', - 'project_id': 'fake', - 'mac_address': '56:12:12:12:12:12'}) + instance_ref = self._create_instance_ref() ip = '10.11.12.13' network_ref = db.project_get_network(self.context, @@ -771,6 +784,25 @@ class IptablesFirewallTestCase(test.TestCase): "TCP port 80/81 acceptance rule wasn't added") db.instance_destroy(admin_ctxt, instance_ref['id']) + def test_filters_for_instance(self): + network_info = _create_network_info() + rulesv4, rulesv6 = self.fw._filters_for_instance("fake", network_info) + self.assertEquals(len(rulesv4), 2) + self.assertEquals(len(rulesv6), 3) + + def multinic_iptables_test(self): + instance_ref = self._create_instance_ref() + network_info = _create_network_info() + ipv4_len = len(self.fw.iptables.ipv4['filter'].rules) + ipv6_len = len(self.fw.iptables.ipv6['filter'].rules) + inst_ipv4, inst_ipv6 = self.fw.instance_rules(instance_ref, + network_info) + self.fw.add_filters_for_instance(instance_ref, network_info) + ipv4 = self.fw.iptables.ipv4['filter'].rules + ipv6 = self.fw.iptables.ipv6['filter'].rules + self.assertEquals(len(ipv4) - len(inst_ipv4) - ipv4_len, 2) + self.assertEquals(len(ipv6) - len(inst_ipv6) - ipv6_len, 3) + class NWFilterTestCase(test.TestCase): def setUp(self): diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 5c7540927..92519da65 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -1877,34 +1877,21 @@ class IptablesFirewallDriver(FirewallDriver): self.add_filters_for_instance(instance, network_info) self.iptables.apply() - def add_filters_for_instance(self, instance, network_info=None): - if not network_info: - network_info = _get_network_info(instance) - chain_name = self._instance_chain_name(instance) - - self.iptables.ipv4['filter'].add_chain(chain_name) + def _create_filter(self, ips, chain_name): + return ['-d %s -j $%s' % (ip, chain_name) for ip in ips] + def _filters_for_instance(self, chain_name, network_info): ips_v4 = [ip['ip'] for (_, mapping) in network_info - for ip in mapping['ips']] - - for ipv4_address in ips_v4: - self.iptables.ipv4['filter'].add_rule('local', - '-d %s -j $%s' % - (ipv4_address, chain_name)) - - if FLAGS.use_ipv6: - self.iptables.ipv6['filter'].add_chain(chain_name) - ips_v6 = [ip['ip'] for (_, mapping) in network_info - for ip in mapping['ip6s']] + for ip in mapping['ips']] + ipv4_rules = self._create_filter(ips_v4, chain_name) - for ipv6_address in ips_v6: - self.iptables.ipv6['filter'].add_rule('local', - '-d %s -j $%s' % - (ipv6_address, - chain_name)) + ips_v6 = [ip['ip'] for (_, mapping) in network_info + for ip in mapping['ip6s']] - ipv4_rules, ipv6_rules = self.instance_rules(instance, network_info) + ipv6_rules = self._create_filter(ips_v6, chain_name) + return ipv4_rules, ipv6_rules + def _add_filters(self, chain_name, ipv4_rules, ipv6_rules): for rule in ipv4_rules: self.iptables.ipv4['filter'].add_rule(chain_name, rule) @@ -1912,6 +1899,17 @@ class IptablesFirewallDriver(FirewallDriver): for rule in ipv6_rules: self.iptables.ipv6['filter'].add_rule(chain_name, rule) + def add_filters_for_instance(self, instance, network_info=None): + chain_name = self._instance_chain_name(instance) + if FLAGS.use_ipv6: + self.iptables.ipv6['filter'].add_chain(chain_name) + self.iptables.ipv4['filter'].add_chain(chain_name) + ipv4_rules, ipv6_rules = self._filters_for_instance(chain_name, + network_info) + self._add_filters('local', ipv4_rules, ipv6_rules) + ipv4_rules, ipv6_rules = self.instance_rules(instance, network_info) + self._add_filters(chain_name, ipv4_rules, ipv6_rules) + def remove_filters_for_instance(self, instance): chain_name = self._instance_chain_name(instance) -- cgit From d7053efa810aa3d20ef7cd089429c6d96f451a7d Mon Sep 17 00:00:00 2001 From: Ilya Alekseyev Date: Mon, 4 Apr 2011 21:05:38 +0400 Subject: Fixed network_info creating. --- nova/tests/test_virt.py | 6 ++++-- nova/virt/libvirt_conn.py | 5 +++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/nova/tests/test_virt.py b/nova/tests/test_virt.py index 958c8e3e2..5a010d347 100644 --- a/nova/tests/test_virt.py +++ b/nova/tests/test_virt.py @@ -617,7 +617,8 @@ class IptablesFirewallTestCase(test.TestCase): instance_ref = db.instance_create(self.context, {'user_id': 'fake', 'project_id': 'fake', - 'mac_address': '56:12:12:12:12:12'}) + 'mac_address': '56:12:12:12:12:12', + 'instance_type': 'm1.small'}) ip = '10.11.12.13' network_ref = db.project_get_network(self.context, @@ -840,7 +841,8 @@ class NWFilterTestCase(test.TestCase): instance_ref = db.instance_create(self.context, {'user_id': 'fake', 'project_id': 'fake', - 'mac_address': '00:A0:C9:14:C8:29'}) + 'mac_address': '00:A0:C9:14:C8:29', + 'instance_type': 'm1.small'}) inst_id = instance_ref['id'] ip = '10.11.12.13' diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index f34ea7225..93a250502 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -167,6 +167,9 @@ def _get_network_info(instance): networks = db.network_get_all_by_instance(admin_context, instance['id']) + + flavor = db.instance_type_get_by_name(admin_context, + instance['instance_type']) network_info = [] def ip_dict(ip): @@ -191,7 +194,9 @@ def _get_network_info(instance): mapping = { 'label': network['label'], 'gateway': network['gateway'], + 'broadcast': network['broadcast'], 'mac': instance.mac_address, + 'rxtx_cap': flavor['rxtx_cap'], 'dns': [network['dns']], 'ips': [ip_dict(ip) for ip in network_ips]} -- cgit From 917f7aafbfa0a797687d10a600a218517f9b75e0 Mon Sep 17 00:00:00 2001 From: Eldar Nugaev Date: Mon, 4 Apr 2011 22:22:27 +0400 Subject: add test for NWFilterFirewall --- nova/tests/test_virt.py | 19 +++++++++++---- nova/virt/libvirt_conn.py | 60 ++++++++++++++++++++++++++++++----------------- 2 files changed, 53 insertions(+), 26 deletions(-) diff --git a/nova/tests/test_virt.py b/nova/tests/test_virt.py index ae813cb80..b3d701efe 100644 --- a/nova/tests/test_virt.py +++ b/nova/tests/test_virt.py @@ -884,6 +884,12 @@ class NWFilterTestCase(test.TestCase): return db.security_group_get_by_name(self.context, 'fake', 'testgroup') + def _create_instance(self): + return db.instance_create(self.context, + {'user_id': 'fake', + 'project_id': 'fake', + 'mac_address': '00:A0:C9:14:C8:29'}) + def test_creates_base_rule_first(self): # These come pre-defined by libvirt self.defined_filters = ['no-mac-spoofing', @@ -912,10 +918,7 @@ class NWFilterTestCase(test.TestCase): self.fake_libvirt_connection.nwfilterDefineXML = _filterDefineXMLMock - instance_ref = db.instance_create(self.context, - {'user_id': 'fake', - 'project_id': 'fake', - 'mac_address': '00:A0:C9:14:C8:29'}) + instance_ref = self._create_instance() inst_id = instance_ref['id'] ip = '10.11.12.13' @@ -955,3 +958,11 @@ class NWFilterTestCase(test.TestCase): _ensure_all_called() self.teardown_security_group() db.instance_destroy(admin_ctxt, instance_ref['id']) + + + def test_create_network_filters(self): + instance_ref = self._create_instance() + network_info = _create_network_info(3) + result = \ + self.fw._create_network_filters(instance_ref, network_info, "fake") + self.assertEquals(len(result), 3) diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 6c99e5448..57d0f4355 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -1740,10 +1740,7 @@ class NWFilterFirewall(FirewallDriver): """ if not network_info: network_info = _get_network_info(instance) - if instance['image_id'] == FLAGS.vpn_image_id: - base_filter = 'nova-vpn' - else: - base_filter = 'nova-base' + ctxt = context.get_admin_context() @@ -1755,41 +1752,60 @@ class NWFilterFirewall(FirewallDriver): 'nova-base-ipv6', 'nova-allow-dhcp-server'] + if FLAGS.use_ipv6: + networks = [network for (network, _) in network_info if + network['gateway_v6']] + + if networks: + instance_secgroup_filter_children.\ + append('nova-allow-ra-server') + for security_group in \ db.security_group_get_by_instance(ctxt, instance['id']): self.refresh_security_group_rules(security_group['id']) - instance_secgroup_filter_children += [('nova-secgroup-%s' % - security_group['id'])] + instance_secgroup_filter_children.append('nova-secgroup-%s' % + security_group['id']) self._define_filter( self._filter_container(instance_secgroup_filter_name, instance_secgroup_filter_children)) - for (network, mapping) in network_info: - nic_id = mapping['mac'].replace(':', '') - instance_filter_name = self._instance_filter_name(instance, nic_id) - instance_filter_children = \ - [base_filter, instance_secgroup_filter_name] + network_filters = self.\ + _create_network_filters(instance, network_info, + instance_secgroup_filter_name) - if FLAGS.use_ipv6: - gateway_v6 = network['gateway_v6'] + for (name, children) in network_filters: + self._define_filters(name, children) - if gateway_v6: - instance_secgroup_filter_children += \ - ['nova-allow-ra-server'] + + def _create_network_filters(self, instance, network_info, + instance_secgroup_filter_name): + if instance['image_id'] == FLAGS.vpn_image_id: + base_filter = 'nova-vpn' + else: + base_filter = 'nova-base' + + result = [] + for (_, mapping) in network_info: + nic_id = mapping['mac'].replace(':', '') + instance_filter_name = self._instance_filter_name(instance, nic_id) + instance_filter_children = [base_filter, + instance_secgroup_filter_name] if FLAGS.allow_project_net_traffic: - instance_filter_children += ['nova-project'] + instance_filter_children.append('nova-project') if FLAGS.use_ipv6: - instance_filter_children += ['nova-project-v6'] + instance_filter_children.append('nova-project-v6') - self._define_filter( - self._filter_container(instance_filter_name, - instance_filter_children)) + result.append((instance_filter_name, instance_filter_children)) - return + return result + + def _define_filters(self, filter_name, filter_children): + self._define_filter(self._filter_container(filter_name, + filter_children)) def refresh_security_group_rules(self, security_group_id): return self._define_filter( -- cgit From 5e74b5a5f121c9f0be2c529b76878615812d9483 Mon Sep 17 00:00:00 2001 From: Eldar Nugaev Date: Mon, 4 Apr 2011 23:43:26 +0400 Subject: splitting test_get_nic_for_xml into two functions --- nova/tests/test_virt.py | 23 ++++++++++++----------- nova/virt/libvirt_conn.py | 2 -- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/nova/tests/test_virt.py b/nova/tests/test_virt.py index b3d701efe..061797b04 100644 --- a/nova/tests/test_virt.py +++ b/nova/tests/test_virt.py @@ -226,16 +226,18 @@ class LibvirtConnTestCase(test.TestCase): def test_get_nic_for_xml(self): conn = libvirt_conn.LibvirtConnection(True) network, mapping = _create_network_info()[0] - backup = FLAGS.use_ipv6 - FLAGS.use_ipv6 = False - params_1 = conn._get_nic_for_xml(network, mapping)['extra_params'] - FLAGS.use_ipv6 = True - params_2 = conn._get_nic_for_xml(network, mapping)['extra_params'] - self.assertTrue(params_1.find('PROJNETV6') == -1) - self.assertTrue(params_1.find('PROJMASKV6') == -1) - self.assertTrue(params_2.find('PROJNETV6') > -1) - self.assertTrue(params_2.find('PROJMASKV6') > -1) - FLAGS.use_ipv6 = backup + self.flags(use_ipv6=False) + params = conn._get_nic_for_xml(network, mapping)['extra_params'] + self.assertTrue(params.find('PROJNETV6') == -1) + self.assertTrue(params.find('PROJMASKV6') == -1) + + def test_get_nic_for_xml_v6(self): + conn = libvirt_conn.LibvirtConnection(True) + network, mapping = _create_network_info()[0] + self.flags(use_ipv6=True) + params = conn._get_nic_for_xml(network, mapping)['extra_params'] + self.assertTrue(params.find('PROJNETV6') > -1) + self.assertTrue(params.find('PROJMASKV6') > -1) def test_xml_and_uri_no_ramdisk_no_kernel(self): instance_data = dict(self.test_instance) @@ -959,7 +961,6 @@ class NWFilterTestCase(test.TestCase): self.teardown_security_group() db.instance_destroy(admin_ctxt, instance_ref['id']) - def test_create_network_filters(self): instance_ref = self._create_instance() network_info = _create_network_info(3) diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 57d0f4355..0ca2cce9a 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -1741,7 +1741,6 @@ class NWFilterFirewall(FirewallDriver): if not network_info: network_info = _get_network_info(instance) - ctxt = context.get_admin_context() instance_secgroup_filter_name = \ @@ -1779,7 +1778,6 @@ class NWFilterFirewall(FirewallDriver): for (name, children) in network_filters: self._define_filters(name, children) - def _create_network_filters(self, instance, network_info, instance_secgroup_filter_name): if instance['image_id'] == FLAGS.vpn_image_id: -- cgit From 519c885a4e3622417cd78655a211a2f23033d610 Mon Sep 17 00:00:00 2001 From: Ilya Alekseyev Date: Tue, 5 Apr 2011 19:42:09 +0400 Subject: pep8 fixed --- nova/virt/libvirt_conn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 93a250502..1eec55e5f 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -167,7 +167,7 @@ def _get_network_info(instance): networks = db.network_get_all_by_instance(admin_context, instance['id']) - + flavor = db.instance_type_get_by_name(admin_context, instance['instance_type']) network_info = [] -- cgit From 28568e51ab4eb84e66e7d15adc9648220684ab84 Mon Sep 17 00:00:00 2001 From: Ilya Alekseyev Date: Tue, 5 Apr 2011 20:40:52 +0400 Subject: removed blank lines for pep8 fix --- nova/virt/libvirt_conn.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 1eec55e5f..d6f51a644 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -164,10 +164,8 @@ def _get_network_info(instance): ip_addresses = db.fixed_ip_get_all_by_instance(admin_context, instance['id']) - networks = db.network_get_all_by_instance(admin_context, instance['id']) - flavor = db.instance_type_get_by_name(admin_context, instance['instance_type']) network_info = [] -- cgit From 4a8a08790803d574ecd1dce4b3765cbce7e1043a Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 5 Apr 2011 12:56:25 -0700 Subject: fixed comment --- nova/auth/manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/auth/manager.py b/nova/auth/manager.py index 12ded1207..f2451702c 100644 --- a/nova/auth/manager.py +++ b/nova/auth/manager.py @@ -372,7 +372,7 @@ class AuthManager(object): (Project.safe_id(project) if project else 'None'))) def _clear_mc_key(self, user, role, project=None): - # (anthony) it would be better to delete the key + # NOTE(anthony): it would be better to delete the key self.mc.set(self._build_mc_key(user, role, project), None) def _has_role(self, user, role, project=None): -- cgit From 36857e5091234940e3ac68d154c019fbd5d28af5 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 5 Apr 2011 15:58:19 -0700 Subject: remove -None for user roles --- nova/auth/manager.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nova/auth/manager.py b/nova/auth/manager.py index f2451702c..3de2ceffe 100644 --- a/nova/auth/manager.py +++ b/nova/auth/manager.py @@ -368,8 +368,10 @@ class AuthManager(object): return True def _build_mc_key(self, user, role, project=None): - return str("rolecache-%s-%s-%s" % (User.safe_id(user), role, - (Project.safe_id(project) if project else 'None'))) + role_key = str("rolecache-%s-%s" % (User.safe_id(user), role)) + if project: + return "%s-%s" % (role_key, Project.safe_id(project)) + return role_key def _clear_mc_key(self, user, role, project=None): # NOTE(anthony): it would be better to delete the key -- cgit From 14833117f19a3a1789c99a519b12bf9c61faec07 Mon Sep 17 00:00:00 2001 From: Naveed Massjouni Date: Wed, 6 Apr 2011 18:17:43 -0400 Subject: Added an option to run_tests.sh so you can run just pep8. So now you can: ./run_tests.sh --just-pep8 or ./run_tests.sh -p --- run_tests.sh | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/run_tests.sh b/run_tests.sh index 8f4d37cd4..9773071c7 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -7,6 +7,7 @@ function usage { echo " -V, --virtual-env Always use virtualenv. Install automatically if not present" echo " -N, --no-virtual-env Don't use virtualenv. Run tests in local environment" echo " -f, --force Force a clean re-build of the virtual environment. Useful when dependencies have been added." + echo " -p, --just-pep8 Just run pep8" echo " -h, --help Print this usage message" echo "" echo "Note: with no options specified, the script will try to run the tests in a virtual environment," @@ -21,6 +22,7 @@ function process_option { -V|--virtual-env) let always_venv=1; let never_venv=0;; -N|--no-virtual-env) let always_venv=0; let never_venv=1;; -f|--force) let force=1;; + -p|--just-pep8) let just_pep8=1;; *) noseargs="$noseargs $1" esac } @@ -32,6 +34,7 @@ never_venv=0 force=0 noseargs= wrapper="" +just_pep8=0 for arg in "$@"; do process_option $arg @@ -53,6 +56,18 @@ function run_tests { return $RESULT } +function run_pep8 { + echo "Running pep8 ..." + srcfiles=`find bin -type f ! -name "nova.conf*"` + srcfiles+=" nova setup.py plugins/xenserver/xenapi/etc/xapi.d/plugins/glance" + pep8 --repeat --show-pep8 --show-source --exclude=vcsversion.py ${srcfiles} +} + +if [ $just_pep8 -eq 1 ]; then + run_pep8 + exit +fi + NOSETESTS="python run_tests.py $noseargs" if [ $never_venv -eq 0 ] @@ -81,11 +96,9 @@ then fi fi -if [ -z "$noseargs" ]; -then - srcfiles=`find bin -type f ! -name "nova.conf*"` - srcfiles+=" nova setup.py plugins/xenserver/xenapi/etc/xapi.d/plugins/glance" - run_tests && pep8 --repeat --show-pep8 --show-source --exclude=vcsversion.py ${srcfiles} || exit 1 -else - run_tests +run_tests + +# Also run pep8 if no options were provided. +if [ -z "$noseargs" ]; then + run_pep8 fi -- cgit From 1ee150c449e630c6409798399eccb577c8273c70 Mon Sep 17 00:00:00 2001 From: Muneyuki Noguchi Date: Thu, 7 Apr 2011 12:35:45 +0900 Subject: Make description of volume_id more generic. --- nova/compute/manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 85bcd7590..383eda0dc 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -786,7 +786,7 @@ class ComputeManager(manager.SchedulerDependentManager): """Remove volume on compute host. :param context: security context - :param volume_id: nova.db.sqlalchemy.models.Volume.id + :param volume_id: volume ID """ self.volume_manager.remove_compute_volume(context, volume_id) -- cgit From a1572a4f234bdeda1d25250de62b5892d8f47891 Mon Sep 17 00:00:00 2001 From: Ken Pepple Date: Thu, 7 Apr 2011 15:00:35 -0700 Subject: clarified nova-manage instance_type create error output on duplicate flavorid --- bin/nova-manage | 10 +++++++--- nova/compute/instance_types.py | 4 +++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/bin/nova-manage b/bin/nova-manage index 25695482f..a999571b2 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -819,6 +819,7 @@ class InstanceTypeCommands(object): """Class for managing instance types / flavors.""" def _print_instance_types(self, n, val): + """helper method to print out instance_types values""" deleted = ('', ', inactive')[val["deleted"] == 1] print ("%s: Memory: %sMB, VCPUS: %s, Storage: %sGB, FlavorID: %s, " "Swap: %sGB, RXTX Quota: %sGB, RXTX Cap: %sMB%s") % ( @@ -836,11 +837,14 @@ class InstanceTypeCommands(object): instance_types.create(name, memory, vcpus, local_gb, flavorid, swap, rxtx_quota, rxtx_cap) except exception.InvalidInputException: - print "Must supply valid parameters to create instance type" + print "Must supply valid parameters to create instance_type" print e sys.exit(1) - except exception.DBError, e: - print "DB Error: %s" % e + except exception.ApiError, e: + print e + print "Please ensure instance_type name and flavor id are unique" + print "Here are the already defined instance_type names and flavorids:" + self.list("--all") sys.exit(2) except: print "Unknown error" diff --git a/nova/compute/instance_types.py b/nova/compute/instance_types.py index fa02a5dfa..bfa120675 100644 --- a/nova/compute/instance_types.py +++ b/nova/compute/instance_types.py @@ -60,7 +60,9 @@ def create(name, memory, vcpus, local_gb, flavorid, swap=0, rxtx_cap=rxtx_cap)) except exception.DBError, e: LOG.exception(_('DB error: %s' % e)) - raise exception.ApiError(_("Cannot create instance type: %s" % name)) + raise exception.ApiError( + _("Cannot create instance_type with name %s and flavorid %s"\ + % (name, flavorid))) def destroy(name): -- cgit From 59b460e98c5b8f718a654539c5788e8775126dfd Mon Sep 17 00:00:00 2001 From: Ken Pepple Date: Thu, 7 Apr 2011 15:08:29 -0700 Subject: slight typo --- bin/nova-manage | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/nova-manage b/bin/nova-manage index a999571b2..5369a98b3 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -841,7 +841,6 @@ class InstanceTypeCommands(object): print e sys.exit(1) except exception.ApiError, e: - print e print "Please ensure instance_type name and flavor id are unique" print "Here are the already defined instance_type names and flavorids:" self.list("--all") -- cgit From 86ffed4e988025023b570b9e6e87f89b6075c7b0 Mon Sep 17 00:00:00 2001 From: Ken Pepple Date: Thu, 7 Apr 2011 17:38:24 -0700 Subject: reminde admins of --purge option --- bin/nova-manage | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bin/nova-manage b/bin/nova-manage index e63898979..73da83767 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -841,8 +841,10 @@ class InstanceTypeCommands(object): print e sys.exit(1) except exception.ApiError, e: - print "Please ensure instance_type name and flavor id are unique" - print "Here are the already defined instance_type names and flavorids:" + print "\n\nPlease ensure instance_type name and flavor id are unique." + print "To complete remove a instance_type, use the --purge flag:" + print "\n # nova-manage instance_type delete --purge\n" + print "Currently defined instance_type names and flavorids:" self.list("--all") sys.exit(2) except: -- cgit From c47c545b293d5b73f46ff18ace2f4b9db61a771f Mon Sep 17 00:00:00 2001 From: Masanori Itoh Date: Sun, 10 Apr 2011 02:49:38 +0900 Subject: debug tree status checkpoint. --- nova/virt/libvirt_conn.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 2be190256..300672ae5 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -471,6 +471,9 @@ class LibvirtConnection(driver.ComputeDriver): @exception.wrap_exception def reboot(self, instance): + # NOTE(itoumsn): self.shutdown() and wait instead of destroy would be + # better because we cannot ensure flushing dirty buffers + # in the guest OS. But, in case of KVM, shutdown often fails... self.destroy(instance, False) xml = self.to_xml(instance) self.firewall_driver.setup_basic_filtering(instance) @@ -496,7 +499,26 @@ class LibvirtConnection(driver.ComputeDriver): timer.stop() timer.f = _wait_for_reboot - return timer.start(interval=0.5, now=True) + timer_result=timer.start(interval=0.5, now=True) + + # Fix lp747922 + instance_id = instance['id'] + for vol in db.volume_get_all_by_instance(context.get_admin_context(), + instance_id): +# LOG.debug(_("re-attaching: %s") % vol['ec2_id']) +# instance-id : instance-00000001 +# device_path : /dev/etherd/e0.1, /dev/mapper/nova--volumes-volume--00000001 +# mountpoint : sdh +# BTW, is iSCSI working? + LOG.debug(_("instance_id: %s, volume_id: %s, mountpoint: %s") % + (instance_id, vol['id'], vol['mountpoint'])) +# self.attach_volume(instance['name'], vol['id'], vol['mountpoint']) + + self.attach_volume(instance['name'], + '/dev/mapper/nova--volumes-volume--00000001', + 'vdb') + + return timer_result @exception.wrap_exception def pause(self, instance, callback): -- cgit From 92df1dc754126895a052bb648c1613201455f714 Mon Sep 17 00:00:00 2001 From: Masanori Itoh Date: Tue, 12 Apr 2011 02:09:29 +0900 Subject: debug tree status checkpoint 2. --- nova/virt/libvirt_conn.py | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 567e17a91..0b1ed2a93 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -487,6 +487,28 @@ class LibvirtConnection(driver.ComputeDriver): instance['id'], state) if state == power_state.RUNNING: LOG.debug(_('instance %s: rebooted'), instance['name']) + + # Fix lp747922 + instance_id = instance['id'] + for vol in db.volume_get_all_by_instance( + context.get_admin_context(), instance_id): + # LOG.debug(_("re-attaching: %s") % vol['ec2_id']) + # instance-id : instance-00000001 + # device_path : /dev/etherd/e0.1, etc + # mountpoint : /dev/sdh + # dev_path is not stored anywhere, and it has driver + # specific format. Therefore, noway other than calling + # discover_driver here. + dev_path = nova.volume.driver.discover_volume(self, + context, + vol) + LOG.debug(_("instance_id: %s, volume_id: %s, mountpoint: %s") % + (instance_id, dev_path, vol['mountpoint'])) + self.attach_volume(instance['name'], + dev_path, + vol['mountpoint']); + # Fix lp747922 + timer.stop() except Exception, exn: LOG.exception(_('_wait_for_reboot failed: %s'), exn) @@ -497,24 +519,6 @@ class LibvirtConnection(driver.ComputeDriver): timer.f = _wait_for_reboot timer_result=timer.start(interval=0.5, now=True) - - # Fix lp747922 - instance_id = instance['id'] - for vol in db.volume_get_all_by_instance(context.get_admin_context(), - instance_id): -# LOG.debug(_("re-attaching: %s") % vol['ec2_id']) -# instance-id : instance-00000001 -# device_path : /dev/etherd/e0.1, /dev/mapper/nova--volumes-volume--00000001 -# mountpoint : sdh -# BTW, is iSCSI working? - LOG.debug(_("instance_id: %s, volume_id: %s, mountpoint: %s") % - (instance_id, vol['id'], vol['mountpoint'])) -# self.attach_volume(instance['name'], vol['id'], vol['mountpoint']) - - self.attach_volume(instance['name'], - '/dev/mapper/nova--volumes-volume--00000001', - 'vdb') - return timer_result @exception.wrap_exception -- cgit From 2295e47b1f85fb199c7e4bf514f6781d7033dd77 Mon Sep 17 00:00:00 2001 From: Masanori Itoh Date: Tue, 12 Apr 2011 02:30:31 +0900 Subject: A minor blush up. --- nova/virt/libvirt_conn.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index b9f6c482e..d47e8f422 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -566,8 +566,7 @@ class LibvirtConnection(driver.ComputeDriver): timer.stop() timer.f = _wait_for_reboot - timer_result=timer.start(interval=0.5, now=True) - return timer_result + return timer.start(interval=0.5, now=True) @exception.wrap_exception def pause(self, instance, callback): -- cgit From 7a2f3d6007a1da365a008cca163cf493668a71de Mon Sep 17 00:00:00 2001 From: Masanori Itoh Date: Tue, 12 Apr 2011 02:32:19 +0900 Subject: A minor blush up. --- nova/virt/libvirt_conn.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index d47e8f422..7670d3989 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -535,12 +535,10 @@ class LibvirtConnection(driver.ComputeDriver): instance['id'], state) if state == power_state.RUNNING: LOG.debug(_('instance %s: rebooted'), instance['name']) - # Fix lp747922 instance_id = instance['id'] for vol in db.volume_get_all_by_instance( context.get_admin_context(), instance_id): - # LOG.debug(_("re-attaching: %s") % vol['ec2_id']) # instance-id : instance-00000001 # device_path : /dev/etherd/e0.1, etc # mountpoint : /dev/sdh -- cgit From b6975a79e91a531ea7501aeb0dbf6c7c07a6722b Mon Sep 17 00:00:00 2001 From: Masanori Itoh Date: Tue, 12 Apr 2011 03:13:58 +0900 Subject: Minor blush ups. --- nova/virt/libvirt_conn.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 7670d3989..0a9ee688a 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -536,7 +536,7 @@ class LibvirtConnection(driver.ComputeDriver): if state == power_state.RUNNING: LOG.debug(_('instance %s: rebooted'), instance['name']) # Fix lp747922 - instance_id = instance['id'] + instance_id = instance['id'] for vol in db.volume_get_all_by_instance( context.get_admin_context(), instance_id): # instance-id : instance-00000001 @@ -548,11 +548,11 @@ class LibvirtConnection(driver.ComputeDriver): dev_path = nova.volume.driver.discover_volume(self, context, vol) - LOG.debug(_("instance_id: %s, volume_id: %s, mountpoint: %s") % - (instance_id, dev_path, vol['mountpoint'])) + LOG.debug( + _("Re-attaching %(dev_path)s to %(mountpoint)s") % + (dev_path, vol['mountpoint'])) self.attach_volume(instance['name'], - dev_path, - vol['mountpoint']); + dev_path, vol['mountpoint']) # Fix lp747922 timer.stop() -- cgit From 9ce66a4a09094d2b0403deea77416149aa789f3c Mon Sep 17 00:00:00 2001 From: Ilya Alekseyev Date: Mon, 11 Apr 2011 22:35:09 +0400 Subject: Floating ips auto assignment --- nova/compute/manager.py | 21 +++++++++++++++++++++ nova/db/api.py | 3 +++ nova/db/sqlalchemy/api.py | 12 ++++++++++++ 3 files changed, 36 insertions(+) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 68b163355..86273b6b4 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -73,6 +73,8 @@ flags.DEFINE_integer('live_migration_retry_count', 30, flags.DEFINE_integer("rescue_timeout", 0, "Automatically unrescue an instance after N seconds." " Set to 0 to disable.") +flags.DEFINE_bool('auto_assign_floating_ip',False, 'Autoassigning floating' + ' ip to VM') LOG = logging.getLogger('nova.compute.manager') @@ -224,6 +226,16 @@ class ComputeManager(manager.SchedulerDependentManager): self.network_manager.setup_compute_network(context, instance_id) + if FLAGS.auto_assign_floating_ip: + public_ip = rpc.call(context, + FLAGS.network_topic, + {"method": "allocate_floating_ip", + "args": {"project_id": context.project_id}}) + self.network_manager.associate_floating_ip(context, + instance_id=instance_id, + address=public_ip) + + # TODO(vish) check to make sure the availability zone matches self.db.instance_set_state(context, instance_id, @@ -271,6 +283,15 @@ class ComputeManager(manager.SchedulerDependentManager): network_topic, {"method": "disassociate_floating_ip", "args": {"floating_address": address}}) + + if FLAGS.auto_assign_floating_ip: + LOG.debug(_("Deallocating floating ip %s"), + floating_ip['address'], context=context) + rpc.cast(context, + FLAGS.network_topic, + {"method": "deallocate_floating_ip", + "args": {"floating_address": + floating_ip['address']}}) address = fixed_ip['address'] if address: diff --git a/nova/db/api.py b/nova/db/api.py index 63901e94d..859acc146 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -290,6 +290,9 @@ def floating_ip_update(context, address, values): """Update a floating ip by address or raise if it doesn't exist.""" return IMPL.floating_ip_update(context, address, values) +def floating_ip_set_auto_assigned(context, address): + """Set auto_assigned flag to floating ip""" + return IMPL.floating_ip_set_auto_assigned(context, address) #################### diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index e675022e9..28126a517 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -489,6 +489,7 @@ def floating_ip_deallocate(context, address): address, session=session) floating_ip_ref['project_id'] = None + floating_ip_ref['auto_assigned'] = False floating_ip_ref.save(session=session) @@ -522,6 +523,17 @@ def floating_ip_disassociate(context, address): return fixed_ip_address +@require_context +def floating_ip_set_auto_assigned(context, address): + session = get_session() + with session.begin(): + floating_ip_ref = floating_ip_get_by_address(context, + address, + session=session) + floating_ip_ref.auto_assigned = True + floating_ip_ref.save(session=session) + + @require_admin_context def floating_ip_get_all(context): session = get_session() -- cgit From 4a2c973fe5c7cf68ff7f45a4927dc6d2e0a3986b Mon Sep 17 00:00:00 2001 From: Ilya Alekseyev Date: Tue, 12 Apr 2011 02:44:44 +0400 Subject: migaration and pep8 fixes --- nova/api/openstack/contrib/volumes.py | 3 +- nova/compute/manager.py | 4 +-- nova/db/api.py | 2 ++ .../015_add_auto_assign_to_floating_ips.py | 38 ++++++++++++++++++++++ 4 files changed, 42 insertions(+), 5 deletions(-) create mode 100644 nova/db/sqlalchemy/migrate_repo/versions/015_add_auto_assign_to_floating_ips.py diff --git a/nova/api/openstack/contrib/volumes.py b/nova/api/openstack/contrib/volumes.py index 6efacce52..18de2ec71 100644 --- a/nova/api/openstack/contrib/volumes.py +++ b/nova/api/openstack/contrib/volumes.py @@ -322,8 +322,7 @@ class Volumes(extensions.ExtensionDescriptor): # Does this matter? res = extensions.ResourceExtension('volumes', VolumeController(), - collection_actions={'detail': 'GET'} - ) + collection_actions={'detail': 'GET'}) resources.append(res) res = extensions.ResourceExtension('volume_attachments', diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 86273b6b4..af3551708 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -73,7 +73,7 @@ flags.DEFINE_integer('live_migration_retry_count', 30, flags.DEFINE_integer("rescue_timeout", 0, "Automatically unrescue an instance after N seconds." " Set to 0 to disable.") -flags.DEFINE_bool('auto_assign_floating_ip',False, 'Autoassigning floating' +flags.DEFINE_bool('auto_assign_floating_ip', False, 'Autoassigning floating' ' ip to VM') LOG = logging.getLogger('nova.compute.manager') @@ -235,7 +235,6 @@ class ComputeManager(manager.SchedulerDependentManager): instance_id=instance_id, address=public_ip) - # TODO(vish) check to make sure the availability zone matches self.db.instance_set_state(context, instance_id, @@ -283,7 +282,6 @@ class ComputeManager(manager.SchedulerDependentManager): network_topic, {"method": "disassociate_floating_ip", "args": {"floating_address": address}}) - if FLAGS.auto_assign_floating_ip: LOG.debug(_("Deallocating floating ip %s"), floating_ip['address'], context=context) diff --git a/nova/db/api.py b/nova/db/api.py index 859acc146..6b465c021 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -290,12 +290,14 @@ def floating_ip_update(context, address, values): """Update a floating ip by address or raise if it doesn't exist.""" return IMPL.floating_ip_update(context, address, values) + def floating_ip_set_auto_assigned(context, address): """Set auto_assigned flag to floating ip""" return IMPL.floating_ip_set_auto_assigned(context, address) #################### + def migration_update(context, id, values): """Update a migration instance""" return IMPL.migration_update(context, id, values) diff --git a/nova/db/sqlalchemy/migrate_repo/versions/015_add_auto_assign_to_floating_ips.py b/nova/db/sqlalchemy/migrate_repo/versions/015_add_auto_assign_to_floating_ips.py new file mode 100644 index 000000000..b7e480e67 --- /dev/null +++ b/nova/db/sqlalchemy/migrate_repo/versions/015_add_auto_assign_to_floating_ips.py @@ -0,0 +1,38 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack LLC. +# Copyright 2011 Grid Dynamics +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from sqlalchemy import * +from sqlalchemy.sql import text +from migrate import * + + +meta = MetaData() + +c_auto_assigned = Column('auto_assigned',Boolean, default=False) + + +def upgrade(migrate_engine): + # Upgrade operations go here. Don't create your own engine; + # bind migrate_engine to your metadata + meta.bind = migrate_engine + + floating_ips = Table('floating_ips', meta, autoload=True, + autoload_with=migrate_engine) + + floating_ips.create_column(c_auto_assigned) + + \ No newline at end of file -- cgit From fa4aeb9af8d00ecff6620646c142e5ff68e1cd5e Mon Sep 17 00:00:00 2001 From: Ilya Alekseyev Date: Tue, 12 Apr 2011 03:07:22 +0400 Subject: pep8 fixes --- .../migrate_repo/versions/015_add_auto_assign_to_floating_ips.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/nova/db/sqlalchemy/migrate_repo/versions/015_add_auto_assign_to_floating_ips.py b/nova/db/sqlalchemy/migrate_repo/versions/015_add_auto_assign_to_floating_ips.py index b7e480e67..6829b5d6e 100644 --- a/nova/db/sqlalchemy/migrate_repo/versions/015_add_auto_assign_to_floating_ips.py +++ b/nova/db/sqlalchemy/migrate_repo/versions/015_add_auto_assign_to_floating_ips.py @@ -22,7 +22,7 @@ from migrate import * meta = MetaData() -c_auto_assigned = Column('auto_assigned',Boolean, default=False) +c_auto_assigned = Column('auto_assigned', Boolean, default=False) def upgrade(migrate_engine): @@ -33,6 +33,4 @@ def upgrade(migrate_engine): floating_ips = Table('floating_ips', meta, autoload=True, autoload_with=migrate_engine) - floating_ips.create_column(c_auto_assigned) - - \ No newline at end of file + floating_ips.create_column(c_auto_assigned) \ No newline at end of file -- cgit From a4791a2d2b4f44c636b7f7694e92bed615309070 Mon Sep 17 00:00:00 2001 From: Masanori Itoh Date: Wed, 13 Apr 2011 02:41:33 +0900 Subject: Rework importing volume_manager. --- nova/virt/libvirt_conn.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 0a9ee688a..990779d47 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -33,7 +33,8 @@ Supports KVM, LXC, QEMU, UML, and XEN. :rescue_ramdisk_id: Rescue ari image (default: ari-rescue). :injected_network_template: Template file for injected network :allow_project_net_traffic: Whether to allow in project network traffic - +:volume_manager: Name of class that handles persistent storage, loaded by + :func:`nova.utils.import_object` """ import multiprocessing @@ -218,6 +219,8 @@ class LibvirtConnection(driver.ComputeDriver): fw_class = utils.import_class(FLAGS.firewall_driver) self.firewall_driver = fw_class(get_connection=self._get_connection) + # NOTE(itoumsn): This is an ugly hack to re-attach volumes on reboot. + self.volume_manager = utils.import_object(FLAGS.volume_manager) def init_host(self, host): # Adopt existing VM's running here @@ -539,15 +542,12 @@ class LibvirtConnection(driver.ComputeDriver): instance_id = instance['id'] for vol in db.volume_get_all_by_instance( context.get_admin_context(), instance_id): - # instance-id : instance-00000001 - # device_path : /dev/etherd/e0.1, etc - # mountpoint : /dev/sdh # dev_path is not stored anywhere, and it has driver - # specific format. Therefore, noway other than calling - # discover_driver here. - dev_path = nova.volume.driver.discover_volume(self, - context, - vol) + # specific format. Furthermore, compute node specific. + # Therefore, noway other than calling discover_driver + # here. + dev_path = self.volume_manager.driver.discover_volume( + context, vol) LOG.debug( _("Re-attaching %(dev_path)s to %(mountpoint)s") % (dev_path, vol['mountpoint'])) -- cgit From 1ca1e83040cb2899c108415c899eee54c760afe3 Mon Sep 17 00:00:00 2001 From: Masanori Itoh Date: Wed, 13 Apr 2011 14:51:26 +0900 Subject: iSCSI/KVM test completed. --- nova/virt/libvirt_conn.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 990779d47..fae48ba4a 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -538,23 +538,23 @@ class LibvirtConnection(driver.ComputeDriver): instance['id'], state) if state == power_state.RUNNING: LOG.debug(_('instance %s: rebooted'), instance['name']) - # Fix lp747922 + # Re-attach volumes instance_id = instance['id'] for vol in db.volume_get_all_by_instance( context.get_admin_context(), instance_id): - # dev_path is not stored anywhere, and it has driver - # specific format. Furthermore, compute node specific. - # Therefore, noway other than calling discover_driver - # here. + # NOTE(itoumsn): dev_path is not stored anywhere, + # and it has driver specific format. Furthermore, it's + # also compute node specific in general. + # Therefore, no way other than calling + # undiscover/discover_driver here at this moment. + self.volume_manager.driver.undiscover_volume(vol) dev_path = self.volume_manager.driver.discover_volume( context, vol) LOG.debug( - _("Re-attaching %(dev_path)s to %(mountpoint)s") % + _("Re-attaching %s to %s") % (dev_path, vol['mountpoint'])) self.attach_volume(instance['name'], dev_path, vol['mountpoint']) - # Fix lp747922 - timer.stop() except Exception, exn: LOG.exception(_('_wait_for_reboot failed: %s'), exn) -- cgit From 33ca304f4cd7156c6a183293521ba29bb9e2833e Mon Sep 17 00:00:00 2001 From: Naveed Massjouni Date: Wed, 13 Apr 2011 12:46:51 -0400 Subject: Changed pep8 command line option from --just-pep8 to --pep8. --- run_tests.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/run_tests.sh b/run_tests.sh index 9773071c7..4f85dfe6d 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -7,7 +7,7 @@ function usage { echo " -V, --virtual-env Always use virtualenv. Install automatically if not present" echo " -N, --no-virtual-env Don't use virtualenv. Run tests in local environment" echo " -f, --force Force a clean re-build of the virtual environment. Useful when dependencies have been added." - echo " -p, --just-pep8 Just run pep8" + echo " -p, --pep8 Just run pep8" echo " -h, --help Print this usage message" echo "" echo "Note: with no options specified, the script will try to run the tests in a virtual environment," @@ -22,7 +22,7 @@ function process_option { -V|--virtual-env) let always_venv=1; let never_venv=0;; -N|--no-virtual-env) let always_venv=0; let never_venv=1;; -f|--force) let force=1;; - -p|--just-pep8) let just_pep8=1;; + -p|--pep8) let just_pep8=1;; *) noseargs="$noseargs $1" esac } -- cgit From ea07b74b8b0fd912555b4193f6e29a2dcd86f4b0 Mon Sep 17 00:00:00 2001 From: Masanori Itoh Date: Thu, 14 Apr 2011 02:22:41 +0900 Subject: An ultimate workaround workd... :( --- nova/virt/libvirt_conn.py | 93 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 77 insertions(+), 16 deletions(-) diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index fae48ba4a..870deae31 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -33,8 +33,6 @@ Supports KVM, LXC, QEMU, UML, and XEN. :rescue_ramdisk_id: Rescue ari image (default: ari-rescue). :injected_network_template: Template file for injected network :allow_project_net_traffic: Whether to allow in project network traffic -:volume_manager: Name of class that handles persistent storage, loaded by - :func:`nova.utils.import_object` """ import multiprocessing @@ -219,8 +217,6 @@ class LibvirtConnection(driver.ComputeDriver): fw_class = utils.import_class(FLAGS.firewall_driver) self.firewall_driver = fw_class(get_connection=self._get_connection) - # NOTE(itoumsn): This is an ugly hack to re-attach volumes on reboot. - self.volume_manager = utils.import_object(FLAGS.volume_manager) def init_host(self, host): # Adopt existing VM's running here @@ -522,8 +518,66 @@ class LibvirtConnection(driver.ComputeDriver): # NOTE(itoumsn): self.shutdown() and wait instead of destroy would be # better because we cannot ensure flushing dirty buffers # in the guest OS. But, in case of KVM, shutdown often fails... +# instance_id = instance['id'] +# volume_list = [] +# dev_path_list = {} +# vols = db.volume_get_all_by_instance(context.get_admin_context(), +# instance_id) +# LOG.debug(_("DEBUG: vols %s") % vols) +# for vol in vols: +# LOG.debug(_("DEBUG: reboot: %s %s") % (vol['mountpoint'], +# vol['mountpoint'].rpartition("/")[2])) +# volume_list.append(vol['mountpoint'].partition("/")[2]) +# +# if len(volume_list) != 0: +# LOG.debug(_("DEBUG: volume_list is not empty")) +# virt_dom = self._conn.lookupByName(instance['name']) +# xml = virt_dom.XMLDesc(0) +# try: +# doc = libxml2.parseDoc(xml) +# except: +# LOG.exception(_('Failed to get xml description %s'), +# instance_id) +# ctx = doc.xpathNewContext() +# try: +# ret = ctx.xpathEval('/domain/devices/disk') +# for node in ret: +# LOG.debug(_("DEBUG: node.name %s") % node.name) +# target_dev = '' +# source_dev = '' +# for child in node.children: +# LOG.debug( +# _("child.name: %s prop.dev %s") % +# (child.name, child.prop('dev'))) +# +# if child.name == 'source': +# source_dev = child.prop('dev') +# elif child.name == 'target': +# target_dev = child.prop('dev') +# LOG.debug( +# _("source: %s target %s") % +# (source_dev, target_dev)) +# +# if target_dev in volume_list: +# dev_path_list[target_dev] = source_dev +# LOG.debug( +# _("append to dev_path_list source: %s target: %s") % +# (source_dev, target_dev)) +# else: +# LOG.debug(_("DEBUG: %s not found in volume_list") % +# (target_dev)) +# finally: +# LOG.debug(_("DEBUG: finally block")) +# if ctx != None: +# ctx.xpathFreeContext() +# if doc != None: +# doc.freeDoc() + + virt_dom = self._conn.lookupByName(instance['name']) + xml = virt_dom.XMLDesc(0) + self.destroy(instance, False) - xml = self.to_xml(instance) +# xml = self.to_xml(instance) self.firewall_driver.setup_basic_filtering(instance) self.firewall_driver.prepare_instance_filter(instance) self._create_new_domain(xml) @@ -539,22 +593,29 @@ class LibvirtConnection(driver.ComputeDriver): if state == power_state.RUNNING: LOG.debug(_('instance %s: rebooted'), instance['name']) # Re-attach volumes - instance_id = instance['id'] - for vol in db.volume_get_all_by_instance( - context.get_admin_context(), instance_id): +# for mp in dev_path_list.iterkeys(): +# LOG.debug( +# _("Re-attaching %s to %s") % +# (dev_path_list[mp], mp)) +# self.attach_volume(instance['name'], +# dev_path_list[mp], mp) +# +# instance_id = instance['id'] +# for vol in db.volume_get_all_by_instance( +# context.get_admin_context(), instance_id): # NOTE(itoumsn): dev_path is not stored anywhere, # and it has driver specific format. Furthermore, it's # also compute node specific in general. # Therefore, no way other than calling # undiscover/discover_driver here at this moment. - self.volume_manager.driver.undiscover_volume(vol) - dev_path = self.volume_manager.driver.discover_volume( - context, vol) - LOG.debug( - _("Re-attaching %s to %s") % - (dev_path, vol['mountpoint'])) - self.attach_volume(instance['name'], - dev_path, vol['mountpoint']) +# self.volume_manager.driver.undiscover_volume(vol) +# dev_path = self.volume_manager.driver.discover_volume( +# context, vol) +# LOG.debug( +# _("Re-attaching %s to %s") % +# (dev_path, vol['mountpoint'])) +# self.attach_volume(instance['name'], +# dev_path, vol['mountpoint']) timer.stop() except Exception, exn: LOG.exception(_('_wait_for_reboot failed: %s'), exn) -- cgit From 2d1235ea404d55f1cdf764798d7a071b3b60dc7e Mon Sep 17 00:00:00 2001 From: Masanori Itoh Date: Thu, 14 Apr 2011 02:38:14 +0900 Subject: Debug code clean up. --- nova/virt/libvirt_conn.py | 91 ++++------------------------------------------- 1 file changed, 7 insertions(+), 84 deletions(-) diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 870deae31..f273d47ce 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -33,6 +33,7 @@ Supports KVM, LXC, QEMU, UML, and XEN. :rescue_ramdisk_id: Rescue ari image (default: ari-rescue). :injected_network_template: Template file for injected network :allow_project_net_traffic: Whether to allow in project network traffic + """ import multiprocessing @@ -515,69 +516,15 @@ class LibvirtConnection(driver.ComputeDriver): @exception.wrap_exception def reboot(self, instance): - # NOTE(itoumsn): self.shutdown() and wait instead of destroy would be - # better because we cannot ensure flushing dirty buffers - # in the guest OS. But, in case of KVM, shutdown often fails... -# instance_id = instance['id'] -# volume_list = [] -# dev_path_list = {} -# vols = db.volume_get_all_by_instance(context.get_admin_context(), -# instance_id) -# LOG.debug(_("DEBUG: vols %s") % vols) -# for vol in vols: -# LOG.debug(_("DEBUG: reboot: %s %s") % (vol['mountpoint'], -# vol['mountpoint'].rpartition("/")[2])) -# volume_list.append(vol['mountpoint'].partition("/")[2]) -# -# if len(volume_list) != 0: -# LOG.debug(_("DEBUG: volume_list is not empty")) -# virt_dom = self._conn.lookupByName(instance['name']) -# xml = virt_dom.XMLDesc(0) -# try: -# doc = libxml2.parseDoc(xml) -# except: -# LOG.exception(_('Failed to get xml description %s'), -# instance_id) -# ctx = doc.xpathNewContext() -# try: -# ret = ctx.xpathEval('/domain/devices/disk') -# for node in ret: -# LOG.debug(_("DEBUG: node.name %s") % node.name) -# target_dev = '' -# source_dev = '' -# for child in node.children: -# LOG.debug( -# _("child.name: %s prop.dev %s") % -# (child.name, child.prop('dev'))) -# -# if child.name == 'source': -# source_dev = child.prop('dev') -# elif child.name == 'target': -# target_dev = child.prop('dev') -# LOG.debug( -# _("source: %s target %s") % -# (source_dev, target_dev)) -# -# if target_dev in volume_list: -# dev_path_list[target_dev] = source_dev -# LOG.debug( -# _("append to dev_path_list source: %s target: %s") % -# (source_dev, target_dev)) -# else: -# LOG.debug(_("DEBUG: %s not found in volume_list") % -# (target_dev)) -# finally: -# LOG.debug(_("DEBUG: finally block")) -# if ctx != None: -# ctx.xpathFreeContext() -# if doc != None: -# doc.freeDoc() - virt_dom = self._conn.lookupByName(instance['name']) + # NOTE(itoumsn): Use XML delived from the running instance + # instead of using to_xml(instance). This is almost the ultimate + # stupid workaround. xml = virt_dom.XMLDesc(0) - + # NOTE(itoumsn): self.shutdown() and wait instead of self.destroy() is + # better because we cannot ensure flushing dirty buffers + # in the guest OS. But, in case of KVM, shutdown() does not work... self.destroy(instance, False) -# xml = self.to_xml(instance) self.firewall_driver.setup_basic_filtering(instance) self.firewall_driver.prepare_instance_filter(instance) self._create_new_domain(xml) @@ -592,30 +539,6 @@ class LibvirtConnection(driver.ComputeDriver): instance['id'], state) if state == power_state.RUNNING: LOG.debug(_('instance %s: rebooted'), instance['name']) - # Re-attach volumes -# for mp in dev_path_list.iterkeys(): -# LOG.debug( -# _("Re-attaching %s to %s") % -# (dev_path_list[mp], mp)) -# self.attach_volume(instance['name'], -# dev_path_list[mp], mp) -# -# instance_id = instance['id'] -# for vol in db.volume_get_all_by_instance( -# context.get_admin_context(), instance_id): - # NOTE(itoumsn): dev_path is not stored anywhere, - # and it has driver specific format. Furthermore, it's - # also compute node specific in general. - # Therefore, no way other than calling - # undiscover/discover_driver here at this moment. -# self.volume_manager.driver.undiscover_volume(vol) -# dev_path = self.volume_manager.driver.discover_volume( -# context, vol) -# LOG.debug( -# _("Re-attaching %s to %s") % -# (dev_path, vol['mountpoint'])) -# self.attach_volume(instance['name'], -# dev_path, vol['mountpoint']) timer.stop() except Exception, exn: LOG.exception(_('_wait_for_reboot failed: %s'), exn) -- cgit From 3d72f59530b1c974dca498fbca44e5720547fc61 Mon Sep 17 00:00:00 2001 From: Ken Pepple Date: Wed, 13 Apr 2011 11:51:03 -0700 Subject: fixed error message i18n-ization. added test. --- nova/compute/instance_types.py | 8 ++++---- nova/tests/test_instance_types.py | 10 ++++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/nova/compute/instance_types.py b/nova/compute/instance_types.py index 70b43540f..158cf1e9d 100644 --- a/nova/compute/instance_types.py +++ b/nova/compute/instance_types.py @@ -59,10 +59,10 @@ def create(name, memory, vcpus, local_gb, flavorid, swap=0, rxtx_quota=rxtx_quota, rxtx_cap=rxtx_cap)) except exception.DBError, e: - LOG.exception(_('DB error: %s' % e)) - raise exception.ApiError( - _("Cannot create instance_type with name %s and flavorid %s"\ - % (name, flavorid))) + LOG.exception(_('DB error: %s') % e) + raise exception.ApiError(_("Cannot create instance_type with\ + name %(name)s and flavorid %(flavorid)s") % + locals()) def destroy(name): diff --git a/nova/tests/test_instance_types.py b/nova/tests/test_instance_types.py index 5d6d5e1f4..ec3bc5bbf 100644 --- a/nova/tests/test_instance_types.py +++ b/nova/tests/test_instance_types.py @@ -88,3 +88,13 @@ class InstanceTypeTestCase(test.TestCase): """Ensures that instance type creation fails with invalid args""" self.assertRaises(exception.ApiError, instance_types.destroy, "sfsfsdfdfs") + + def test_repeated_inst_types_should_raise_api_error(self): + """Ensures that instance duplicates raises ApiError""" + new_name = self.name + "dup" + instance_types.create(new_name, 256, 1, 120, self.flavorid + 1) + instance_types.destroy(new_name) + self.assertRaises( + exception.ApiError, + instance_types.create, new_name, 256, 1, 120, self.flavorid) + \ No newline at end of file -- cgit From 6a20cba0ea3c1e9945897ec27646d74d597492d7 Mon Sep 17 00:00:00 2001 From: Ken Pepple Date: Wed, 13 Apr 2011 12:01:59 -0700 Subject: pep8 --- bin/nova-manage | 3 ++- nova/tests/test_instance_types.py | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/nova-manage b/bin/nova-manage index 750cd2596..8ec3a1e64 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -832,7 +832,8 @@ class InstanceTypeCommands(object): print e sys.exit(1) except exception.ApiError, e: - print "\n\nPlease ensure instance_type name and flavor id are unique." + print "\n\n" + print "Please ensure instance_type name and flavorid are unique." print "To complete remove a instance_type, use the --purge flag:" print "\n # nova-manage instance_type delete --purge\n" print "Currently defined instance_type names and flavorids:" diff --git a/nova/tests/test_instance_types.py b/nova/tests/test_instance_types.py index ec3bc5bbf..dd7d0737e 100644 --- a/nova/tests/test_instance_types.py +++ b/nova/tests/test_instance_types.py @@ -97,4 +97,3 @@ class InstanceTypeTestCase(test.TestCase): self.assertRaises( exception.ApiError, instance_types.create, new_name, 256, 1, 120, self.flavorid) - \ No newline at end of file -- cgit From 1b460de2f881d3cda0fd58bacedc3886020e4ca7 Mon Sep 17 00:00:00 2001 From: Ilya Alekseyev Date: Thu, 14 Apr 2011 17:12:54 +0400 Subject: bugfix --- nova/compute/manager.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index af3551708..63d374326 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -226,15 +226,6 @@ class ComputeManager(manager.SchedulerDependentManager): self.network_manager.setup_compute_network(context, instance_id) - if FLAGS.auto_assign_floating_ip: - public_ip = rpc.call(context, - FLAGS.network_topic, - {"method": "allocate_floating_ip", - "args": {"project_id": context.project_id}}) - self.network_manager.associate_floating_ip(context, - instance_id=instance_id, - address=public_ip) - # TODO(vish) check to make sure the availability zone matches self.db.instance_set_state(context, instance_id, @@ -255,6 +246,16 @@ class ComputeManager(manager.SchedulerDependentManager): instance_id, power_state.SHUTDOWN) + if not FLAGS.stub_network: + if FLAGS.auto_assign_floating_ip: + public_ip = rpc.call(context, + FLAGS.network_topic, + {"method": "allocate_floating_ip", + "args": {"project_id": context.project_id}}) + self.network_manager.associate_floating_ip(context, + floating_address=public_ip, + fixed_address=address) + self._update_state(context, instance_id) @exception.wrap_exception -- cgit From 76e643dc0b6b8b6e2ad499034f4d4491380e91ba Mon Sep 17 00:00:00 2001 From: Ilya Alekseyev Date: Thu, 14 Apr 2011 21:23:40 +0400 Subject: bugfix --- nova/compute/manager.py | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 63d374326..94fee36a5 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -252,9 +252,34 @@ class ComputeManager(manager.SchedulerDependentManager): FLAGS.network_topic, {"method": "allocate_floating_ip", "args": {"project_id": context.project_id}}) - self.network_manager.associate_floating_ip(context, - floating_address=public_ip, - fixed_address=address) + + fixed_ip = self.db.fixed_ip_get_by_address(context, address) + floating_ip = self.db.floating_ip_get_by_address(context, + public_ip) + # Check if the floating ip address is allocated + if floating_ip['project_id'] is None: + raise exception.Error(_("Address (%s) is not allocated") % + floating_ip['address']) + # Check if the floating ip address is allocated + # to the same project + if floating_ip['project_id'] != context.project_id: + LOG.warn(_("Address (%(address)s) is not allocated to your" + " project (%(project)s)"), + {'address': floating_ip['address'], + 'project': context.project_id}) + raise exception.Error(_("Address (%(address)s) is not " + "allocated to your project" + "(%(project)s)") % + {'address': floating_ip['address'], + 'project': context.project_id}) + + host = fixed_ip['network']['host'] + rpc.cast(context, + self.db.queue_get_for(context, + FLAGS.network_topic, host), + {"method": "associate_floating_ip", + "args": {"floating_address": floating_ip['address'], + "fixed_address": fixed_ip['address']}}) self._update_state(context, instance_id) -- cgit From 4b0785632ba626d34a8a9fae5e0a5c742660e2dc Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Thu, 14 Apr 2011 17:34:09 -0400 Subject: initial roundup of all 'exception.Invalid' cases --- nova/api/openstack/servers.py | 4 +- nova/exception.py | 90 +++++++++++++++++++++++++++++++++++++++++-- nova/network/vmwareapi_net.py | 16 +++----- nova/scheduler/driver.py | 27 ++++--------- nova/virt/libvirt_conn.py | 19 ++++----- nova/virt/vmwareapi/vmops.py | 13 ++++--- 6 files changed, 116 insertions(+), 53 deletions(-) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 43e0c7963..2332b1af7 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -561,9 +561,7 @@ class Controller(common.OpenstackController): """ image_id = image_meta['id'] if image_meta['status'] != 'active': - raise exception.Invalid( - _("Cannot build from image %(image_id)s, status not active") % - locals()) + raise exception.InstanceNotRunning(image_id=image_id) if image_meta.get('container_format') != 'ami': return None, None diff --git a/nova/exception.py b/nova/exception.py index 4e2bbdbaf..cbfbb2920 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -80,10 +80,6 @@ class NotEmpty(Error): pass -class Invalid(Error): - pass - - class InvalidInputException(Error): pass @@ -127,3 +123,89 @@ def wrap_exception(f): raise _wrap.func_name = f.func_name return _wrap + + +class NovaException(Exception): + message = "" + + def __init__(self, **kwargs): + self._error_string = _(self.message) % kwargs + + def __str__(self): + return self._error_string + + +#TODO: EOL this exception! +class Invalid(NovaException): + pass + + +class InstanceNotRunning(Invalid): + message = "Instance is not 'running'." + + +class InstanceNotSuspended(Invalid): + message = "Instance is not 'suspended'." + + +class InstanceSuspendFailure(Invalid): + message = "Failed to suspend instance: %(reason)s." + + +class InstanceResumeFailure(Invalid): + message = "Failed to resume server: %(reson)s." + + +class InstanceRebootFailure(Invalid): + message = "Failed to reboot instance: %(reason)s." + + +class ServiceUnavailable(Invalid): + message = "Service is unavailable at this time." + + +class VolumeServiceUnavailable(ServiceUnavailable): + message = "Volume service is unavailable at this time." + + +class ComputeServiceUnavailable(ServiceUnavailable): + message = "Compute service on %(host)s is unavailable at this time." + + +class UnableToMigrateToSelf(Invalid): + message = "Unable to migrate instance (%(instance_id)s) " \ + "to current host (%(host)s." + + +class SourceHostUnavailable(Invalid): + message = "Original compute host is unavailable at this time." + + +class InvalidHypervisorType(Invalid): + message = "The supplied hypervisor type of %(type)s is invalid." + + +class DestinationHypervisorTooOld(Invalid): + message = "The instance requires a newer hypervisor version than " \ + "has been provided." + + +class InvalidDevicePath(Invalid): + message = "The supplied device path (%(path)s) is invalid." + + +class InvalidCPUInfo(Invalid): + message = "Unacceptable CPU info: %(reason)s." + + +class InvalidVLANTag(Invalid): + message = "VLAN tag is not appropriate for the port group " \ + "%(bridge)s. Expected VLAN tag is %(tag)s, " \ + "but the one associated with the port group is %(pgroup)s." + + +class InvalidVLANPortGroup(Invalid): + message = "vSwitch which contains the port group %(bridge)s is " \ + "not associated with the desired physical adapter. " \ + "Expected vSwitch is %(expected)s, but the one associated " \ + "is %(actual)s." diff --git a/nova/network/vmwareapi_net.py b/nova/network/vmwareapi_net.py index 93e6584f0..6e1ed480b 100644 --- a/nova/network/vmwareapi_net.py +++ b/nova/network/vmwareapi_net.py @@ -75,17 +75,13 @@ def ensure_vlan_bridge(vlan_num, bridge, net_attrs=None): pg_vlanid, pg_vswitch = \ network_utils.get_vlanid_and_vswitch_for_portgroup(session, bridge) - # Check if the vsiwtch associated is proper + # Check if the vswitch associated is proper if pg_vswitch != vswitch_associated: - raise exception.Invalid(_("vSwitch which contains the port group " - "%(bridge)s is not associated with the desired " - "physical adapter. Expected vSwitch is " - "%(vswitch_associated)s, but the one associated" - " is %(pg_vswitch)s") % locals()) + raise exception.InvalidVLANPortGroup(bridge=bridge, + expected=vswitch_associated, + actual=pg_vswitch) # Check if the vlan id is proper for the port group if pg_vlanid != vlan_num: - raise exception.Invalid(_("VLAN tag is not appropriate for the " - "port group %(bridge)s. Expected VLAN tag is " - "%(vlan_num)s, but the one associated with the " - "port group is %(pg_vlanid)s") % locals()) + raise exception.InvalidVLANTag(bridge=bridge, tag=vlan_num, + pgroup=pg_vlanid) diff --git a/nova/scheduler/driver.py b/nova/scheduler/driver.py index ce05d9f6a..02e65357c 100644 --- a/nova/scheduler/driver.py +++ b/nova/scheduler/driver.py @@ -129,15 +129,14 @@ class Scheduler(object): if (power_state.RUNNING != instance_ref['state'] or \ 'running' != instance_ref['state_description']): ec2_id = instance_ref['hostname'] - raise exception.Invalid(_('Instance(%s) is not running') % ec2_id) + raise exception.InstanceNotRunning(instance_id=ec2_id) # Checing volume node is running when any volumes are mounted # to the instance. if len(instance_ref['volumes']) != 0: services = db.service_get_all_by_topic(context, 'volume') if len(services) < 1 or not self.service_is_up(services[0]): - raise exception.Invalid(_("volume node is not alive" - "(time synchronize problem?)")) + raise exception.VolumeServiceUnavailable() # Checking src host exists and compute node src = instance_ref['host'] @@ -145,8 +144,7 @@ class Scheduler(object): # Checking src host is alive. if not self.service_is_up(services[0]): - raise exception.Invalid(_("%s is not alive(time " - "synchronize problem?)") % src) + raise exception.ComputeServiceUnavailable(host=src) def _live_migration_dest_check(self, context, instance_ref, dest): """Live migration check routine (for destination host). @@ -163,17 +161,14 @@ class Scheduler(object): # Checking dest host is alive. if not self.service_is_up(dservice_ref): - raise exception.Invalid(_("%s is not alive(time " - "synchronize problem?)") % dest) + raise exception.ComputeServiceUnavailable(host=dest) # Checking whether The host where instance is running # and dest is not same. src = instance_ref['host'] if dest == src: ec2_id = instance_ref['hostname'] - raise exception.Invalid(_("%(dest)s is where %(ec2_id)s is " - "running now. choose other host.") - % locals()) + raise exception.UnableToMigrateToSelf(instance_id=ec2_id, host=dest) # Checking dst host still has enough capacities. self.assert_compute_node_has_enough_resources(context, @@ -204,26 +199,20 @@ class Scheduler(object): oservice_refs = db.service_get_all_compute_by_host(context, instance_ref['launched_on']) except exception.NotFound: - raise exception.Invalid(_("host %s where instance was launched " - "does not exist.") - % instance_ref['launched_on']) + raise exception.SourceHostUnavailable() oservice_ref = oservice_refs[0]['compute_node'][0] # Checking hypervisor is same. orig_hypervisor = oservice_ref['hypervisor_type'] dest_hypervisor = dservice_ref['hypervisor_type'] if orig_hypervisor != dest_hypervisor: - raise exception.Invalid(_("Different hypervisor type" - "(%(orig_hypervisor)s->" - "%(dest_hypervisor)s)')" % locals())) + raise exception.InvalidHypervisorType() # Checkng hypervisor version. orig_hypervisor = oservice_ref['hypervisor_version'] dest_hypervisor = dservice_ref['hypervisor_version'] if orig_hypervisor > dest_hypervisor: - raise exception.Invalid(_("Older hypervisor version" - "(%(orig_hypervisor)s->" - "%(dest_hypervisor)s)") % locals()) + raise exception.DestinationHypervisorTooOld() # Checking cpuinfo. try: diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 94410003e..78190cb6d 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -421,7 +421,7 @@ class LibvirtConnection(driver.ComputeDriver): name, mount_device) else: - raise exception.Invalid(_("Invalid device path %s") % device_path) + raise exception.InvalidDevicePath(path=device_path) virt_dom.attachDevice(xml) @@ -1302,9 +1302,9 @@ class LibvirtConnection(driver.ComputeDriver): xml = libxml2.parseDoc(xml) nodes = xml.xpathEval('//host/cpu') if len(nodes) != 1: - raise exception.Invalid(_("Invalid xml. '' must be 1," - "but %d\n") % len(nodes) - + xml.serialize()) + reason = _("'' must be 1, but %d\n") % len(nodes) + reason += xml.serialize() + raise exception.InvalidCPUInfo(reason=reason) cpu_info = dict() @@ -1333,9 +1333,8 @@ class LibvirtConnection(driver.ComputeDriver): tkeys = topology.keys() if set(tkeys) != set(keys): ks = ', '.join(keys) - raise exception.Invalid(_("Invalid xml: topology" - "(%(topology)s) must have " - "%(ks)s") % locals()) + reason = _("topology (%(topology)s) must have %(ks)s") + raise exception.InvalidCPUInfo(reason=reason % locals()) feature_nodes = xml.xpathEval('//host/cpu/feature') features = list() @@ -1390,9 +1389,7 @@ class LibvirtConnection(driver.ComputeDriver): try: service_ref = db.service_get_all_compute_by_host(ctxt, host)[0] except exception.NotFound: - raise exception.Invalid(_("Cannot update compute manager " - "specific info, because no service " - "record was found.")) + raise exception.ComputeServiceUnavailable() # Updating host information dic = {'vcpus': self.get_vcpu_total(), @@ -1445,7 +1442,7 @@ class LibvirtConnection(driver.ComputeDriver): raise if ret <= 0: - raise exception.Invalid(m % locals()) + raise exception.InvalidCPUInfo(reason=m % locals()) return diff --git a/nova/virt/vmwareapi/vmops.py b/nova/virt/vmwareapi/vmops.py index cf6c88bbd..f2f68ec22 100644 --- a/nova/virt/vmwareapi/vmops.py +++ b/nova/virt/vmwareapi/vmops.py @@ -501,8 +501,8 @@ class VMWareVMOps(object): # Raise an exception if the VM is not powered On. if pwr_state not in ["poweredOn"]: - raise exception.Invalid(_("instance - %s not poweredOn. So can't " - "be rebooted.") % instance.name) + reason = _("instance is not powered on") + raise exception.InstanceRebootFailure(reason=reason) # If latest vmware tools are installed in the VM, and that the tools # are running, then only do a guest reboot. Otherwise do a hard reset. @@ -620,8 +620,9 @@ class VMWareVMOps(object): LOG.debug(_("Suspended the VM %s ") % instance.name) # Raise Exception if VM is poweredOff elif pwr_state == "poweredOff": - raise exception.Invalid(_("instance - %s is poweredOff and hence " - " can't be suspended.") % instance.name) + reason = _("instance is poweredOff and can not be suspended.") + raise exception.InstanceSuspendFailure(reason=reason) + LOG.debug(_("VM %s was already in suspended state. So returning " "without doing anything") % instance.name) @@ -643,8 +644,8 @@ class VMWareVMOps(object): self._wait_with_callback(instance.id, suspend_task, callback) LOG.debug(_("Resumed the VM %s ") % instance.name) else: - raise exception.Invalid(_("instance - %s not in Suspended state " - "and hence can't be Resumed.") % instance.name) + reason = _("instance is not in a suspended state") + raise exception.InstanceResumeFailure(reason=reason) def get_info(self, instance_name): """Return data about the VM instance.""" -- cgit From ad138a5a50868531f34ba358600f1270588ce80b Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Fri, 15 Apr 2011 14:24:17 -0400 Subject: correcting tests; pep8 --- nova/api/openstack/servers.py | 3 +- nova/exception.py | 20 ++++++++----- nova/scheduler/driver.py | 3 +- nova/tests/test_scheduler.py | 69 +++++++++++++------------------------------ nova/tests/test_virt.py | 2 +- nova/virt/libvirt_conn.py | 2 +- 6 files changed, 39 insertions(+), 60 deletions(-) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 2332b1af7..1cb42355a 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -561,7 +561,8 @@ class Controller(common.OpenstackController): """ image_id = image_meta['id'] if image_meta['status'] != 'active': - raise exception.InstanceNotRunning(image_id=image_id) + raise exception.ImageUnacceptable(image_id=image_id, + reason=_("status is not active")) if image_meta.get('container_format') != 'ami': return None, None diff --git a/nova/exception.py b/nova/exception.py index cbfbb2920..29d6b13e5 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -141,23 +141,23 @@ class Invalid(NovaException): class InstanceNotRunning(Invalid): - message = "Instance is not 'running'." + message = "Instance %(instance_id)s is not running." class InstanceNotSuspended(Invalid): - message = "Instance is not 'suspended'." + message = "Instance %(instance_id)s is not suspended." class InstanceSuspendFailure(Invalid): - message = "Failed to suspend instance: %(reason)s." + message = "Failed to suspend instance: %(reason)s" class InstanceResumeFailure(Invalid): - message = "Failed to resume server: %(reson)s." + message = "Failed to resume server: %(reason)s." class InstanceRebootFailure(Invalid): - message = "Failed to reboot instance: %(reason)s." + message = "Failed to reboot instance: %(reason)s" class ServiceUnavailable(Invalid): @@ -169,7 +169,7 @@ class VolumeServiceUnavailable(ServiceUnavailable): class ComputeServiceUnavailable(ServiceUnavailable): - message = "Compute service on %(host)s is unavailable at this time." + message = "Compute service is unavailable at this time." class UnableToMigrateToSelf(Invalid): @@ -182,7 +182,7 @@ class SourceHostUnavailable(Invalid): class InvalidHypervisorType(Invalid): - message = "The supplied hypervisor type of %(type)s is invalid." + message = "The supplied hypervisor type of is invalid." class DestinationHypervisorTooOld(Invalid): @@ -195,7 +195,7 @@ class InvalidDevicePath(Invalid): class InvalidCPUInfo(Invalid): - message = "Unacceptable CPU info: %(reason)s." + message = "Unacceptable CPU info: %(reason)s" class InvalidVLANTag(Invalid): @@ -209,3 +209,7 @@ class InvalidVLANPortGroup(Invalid): "not associated with the desired physical adapter. " \ "Expected vSwitch is %(expected)s, but the one associated " \ "is %(actual)s." + + +class ImageUnacceptable(Invalid): + message = "Image %(image_id)s is unacceptable: %(reason)s" diff --git a/nova/scheduler/driver.py b/nova/scheduler/driver.py index 02e65357c..87b10e940 100644 --- a/nova/scheduler/driver.py +++ b/nova/scheduler/driver.py @@ -168,7 +168,8 @@ class Scheduler(object): src = instance_ref['host'] if dest == src: ec2_id = instance_ref['hostname'] - raise exception.UnableToMigrateToSelf(instance_id=ec2_id, host=dest) + raise exception.UnableToMigrateToSelf(instance_id=ec2_id, + host=dest) # Checking dst host still has enough capacities. self.assert_compute_node_has_enough_resources(context, diff --git a/nova/tests/test_scheduler.py b/nova/tests/test_scheduler.py index ae56a1a16..4a2b15f56 100644 --- a/nova/tests/test_scheduler.py +++ b/nova/tests/test_scheduler.py @@ -698,14 +698,10 @@ class SimpleDriverTestCase(test.TestCase): 'topic': 'volume', 'report_count': 0} s_ref = db.service_create(self.context, dic) - try: - self.scheduler.driver.schedule_live_migration(self.context, - instance_id, - i_ref['host']) - except exception.Invalid, e: - c = (e.message.find('volume node is not alive') >= 0) + self.assertRaises(exception.VolumeServiceUnavailable, + self.scheduler.driver.schedule_live_migration, + self.context, instance_id, i_ref['host']) - self.assertTrue(c) db.instance_destroy(self.context, instance_id) db.service_destroy(self.context, s_ref['id']) db.volume_destroy(self.context, v_ref['id']) @@ -718,13 +714,10 @@ class SimpleDriverTestCase(test.TestCase): s_ref = self._create_compute_service(created_at=t, updated_at=t, host=i_ref['host']) - try: - self.scheduler.driver._live_migration_src_check(self.context, - i_ref) - except exception.Invalid, e: - c = (e.message.find('is not alive') >= 0) + self.assertRaises(exception.ComputeServiceUnavailable, + self.scheduler.driver._live_migration_src_check, + self.context, i_ref) - self.assertTrue(c) db.instance_destroy(self.context, instance_id) db.service_destroy(self.context, s_ref['id']) @@ -749,14 +742,10 @@ class SimpleDriverTestCase(test.TestCase): s_ref = self._create_compute_service(created_at=t, updated_at=t, host=i_ref['host']) - try: - self.scheduler.driver._live_migration_dest_check(self.context, - i_ref, - i_ref['host']) - except exception.Invalid, e: - c = (e.message.find('is not alive') >= 0) + self.assertRaises(exception.ComputeServiceUnavailable, + self.scheduler.driver._live_migration_dest_check, + self.context, i_ref, i_ref['host']) - self.assertTrue(c) db.instance_destroy(self.context, instance_id) db.service_destroy(self.context, s_ref['id']) @@ -766,14 +755,10 @@ class SimpleDriverTestCase(test.TestCase): i_ref = db.instance_get(self.context, instance_id) s_ref = self._create_compute_service(host=i_ref['host']) - try: - self.scheduler.driver._live_migration_dest_check(self.context, - i_ref, - i_ref['host']) - except exception.Invalid, e: - c = (e.message.find('choose other host') >= 0) + self.assertRaises(exception.UnableToMigrateToSelf, + self.scheduler.driver._live_migration_dest_check, + self.context, i_ref, i_ref['host']) - self.assertTrue(c) db.instance_destroy(self.context, instance_id) db.service_destroy(self.context, s_ref['id']) @@ -837,14 +822,10 @@ class SimpleDriverTestCase(test.TestCase): "args": {'filename': fpath}}) self.mox.ReplayAll() - try: - self.scheduler.driver._live_migration_common_check(self.context, - i_ref, - dest) - except exception.Invalid, e: - c = (e.message.find('does not exist') >= 0) + self.assertRaises(exception.SourceHostUnavailable, + self.scheduler.driver._live_migration_common_check, + self.context, i_ref, dest) - self.assertTrue(c) db.instance_destroy(self.context, instance_id) db.service_destroy(self.context, s_ref['id']) @@ -865,14 +846,10 @@ class SimpleDriverTestCase(test.TestCase): driver.mounted_on_same_shared_storage(mox.IgnoreArg(), i_ref, dest) self.mox.ReplayAll() - try: - self.scheduler.driver._live_migration_common_check(self.context, - i_ref, - dest) - except exception.Invalid, e: - c = (e.message.find(_('Different hypervisor type')) >= 0) + self.assertRaises(exception.InvalidHypervisorType, + self.scheduler.driver._live_migration_common_check, + self.context, i_ref, dest) - self.assertTrue(c) db.instance_destroy(self.context, instance_id) db.service_destroy(self.context, s_ref['id']) db.service_destroy(self.context, s_ref2['id']) @@ -895,14 +872,10 @@ class SimpleDriverTestCase(test.TestCase): driver.mounted_on_same_shared_storage(mox.IgnoreArg(), i_ref, dest) self.mox.ReplayAll() - try: - self.scheduler.driver._live_migration_common_check(self.context, - i_ref, - dest) - except exception.Invalid, e: - c = (e.message.find(_('Older hypervisor version')) >= 0) + self.assertRaises(exception.DestinationHypervisorTooOld, + self.scheduler.driver._live_migration_common_check, + self.context, i_ref, dest) - self.assertTrue(c) db.instance_destroy(self.context, instance_id) db.service_destroy(self.context, s_ref['id']) db.service_destroy(self.context, s_ref2['id']) diff --git a/nova/tests/test_virt.py b/nova/tests/test_virt.py index aeaea91c7..fe0ea5d6e 100644 --- a/nova/tests/test_virt.py +++ b/nova/tests/test_virt.py @@ -451,7 +451,7 @@ class LibvirtConnTestCase(test.TestCase): self.mox.ReplayAll() conn = libvirt_conn.LibvirtConnection(False) - self.assertRaises(exception.Invalid, + self.assertRaises(exception.ComputeServiceUnavailable, conn.update_available_resource, self.context, 'dummy') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 78190cb6d..2b78dceb2 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -1389,7 +1389,7 @@ class LibvirtConnection(driver.ComputeDriver): try: service_ref = db.service_get_all_compute_by_host(ctxt, host)[0] except exception.NotFound: - raise exception.ComputeServiceUnavailable() + raise exception.ComputeServiceUnavailable(host=host) # Updating host information dic = {'vcpus': self.get_vcpu_total(), -- cgit From 876216838843044adba401c1f44f18dd97b0e01d Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Fri, 15 Apr 2011 14:33:24 -0400 Subject: adding documentation & error handling --- nova/exception.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/nova/exception.py b/nova/exception.py index 29d6b13e5..7d1b44c35 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -126,16 +126,28 @@ def wrap_exception(f): class NovaException(Exception): - message = "" + """Base Nova Exception + + To correctly use this class, inherit from it and define + a 'message' property. That message will get printf'd + with the keyword arguments provided to the constructor. + + """ + message = "An unknown exception occurred." def __init__(self, **kwargs): - self._error_string = _(self.message) % kwargs + try: + self._error_string = _(self.message) % kwargs + + except Exception: + # at least get the core message out if something happened + self._error_string = _(self.message) def __str__(self): return self._error_string -#TODO: EOL this exception! +#TODO(bcwaldon): EOL this exception! class Invalid(NovaException): pass -- cgit From 9a0d079cfe28d6d8d4e909f68541efda5ad3a3c5 Mon Sep 17 00:00:00 2001 From: Ilya Alekseyev Date: Mon, 18 Apr 2011 21:06:29 +0400 Subject: not performing floating ip operation with auto allocated ips --- nova/compute/manager.py | 3 ++- nova/db/sqlalchemy/api.py | 2 ++ nova/db/sqlalchemy/models.py | 1 + nova/network/api.py | 6 ++++++ 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 94fee36a5..829d59170 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -308,7 +308,8 @@ class ComputeManager(manager.SchedulerDependentManager): network_topic, {"method": "disassociate_floating_ip", "args": {"floating_address": address}}) - if FLAGS.auto_assign_floating_ip: + if FLAGS.auto_assign_floating_ip \ + and floating_ip.get('auto_assigned'): LOG.debug(_("Deallocating floating ip %s"), floating_ip['address'], context=context) rpc.cast(context, diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 28126a517..6b2caf46c 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -461,6 +461,7 @@ def floating_ip_count_by_project(context, project_id): session = get_session() return session.query(models.FloatingIp).\ filter_by(project_id=project_id).\ + filter_by(auto_assigned=False).\ filter_by(deleted=False).\ count() @@ -560,6 +561,7 @@ def floating_ip_get_all_by_project(context, project_id): return session.query(models.FloatingIp).\ options(joinedload_all('fixed_ip.instance')).\ filter_by(project_id=project_id).\ + filter_by(auto_assigned=False).\ filter_by(deleted=False).\ all() diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py index f79d0f16c..36a084a1d 100644 --- a/nova/db/sqlalchemy/models.py +++ b/nova/db/sqlalchemy/models.py @@ -592,6 +592,7 @@ class FloatingIp(BASE, NovaBase): 'FloatingIp.deleted == False)') project_id = Column(String(255)) host = Column(String(255)) # , ForeignKey('hosts.id')) + auto_assigned = Column(Boolean, default=False, nullable=False) class ConsolePool(BASE, NovaBase): diff --git a/nova/network/api.py b/nova/network/api.py index c56e3062b..c5f76a14e 100644 --- a/nova/network/api.py +++ b/nova/network/api.py @@ -53,6 +53,8 @@ class API(base.Base): def release_floating_ip(self, context, address): floating_ip = self.db.floating_ip_get_by_address(context, address) + if floating_ip.get('auto_assigned'): + return # NOTE(vish): We don't know which network host should get the ip # when we deallocate, so just send it to any one. This # will probably need to move into a network supervisor @@ -66,6 +68,8 @@ class API(base.Base): if isinstance(fixed_ip, str) or isinstance(fixed_ip, unicode): fixed_ip = self.db.fixed_ip_get_by_address(context, fixed_ip) floating_ip = self.db.floating_ip_get_by_address(context, floating_ip) + if floating_ip.get('auto_assigned'): + return # Check if the floating ip address is allocated if floating_ip['project_id'] is None: raise exception.ApiError(_("Address (%s) is not allocated") % @@ -92,6 +96,8 @@ class API(base.Base): def disassociate_floating_ip(self, context, address): floating_ip = self.db.floating_ip_get_by_address(context, address) + if floating_ip.get('auto_assigned'): + return if not floating_ip.get('fixed_ip'): raise exception.ApiError('Address is not associated.') # NOTE(vish): Get the topic from the host name of the network of -- cgit From 841d25c1c9ab840ed39261a3bb234b981d9c337a Mon Sep 17 00:00:00 2001 From: Ilya Alekseyev Date: Mon, 18 Apr 2011 22:02:12 +0400 Subject: pep8 fixed --- .../migrate_repo/versions/015_add_auto_assign_to_floating_ips.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/db/sqlalchemy/migrate_repo/versions/015_add_auto_assign_to_floating_ips.py b/nova/db/sqlalchemy/migrate_repo/versions/015_add_auto_assign_to_floating_ips.py index 6829b5d6e..f3767b29f 100644 --- a/nova/db/sqlalchemy/migrate_repo/versions/015_add_auto_assign_to_floating_ips.py +++ b/nova/db/sqlalchemy/migrate_repo/versions/015_add_auto_assign_to_floating_ips.py @@ -33,4 +33,4 @@ def upgrade(migrate_engine): floating_ips = Table('floating_ips', meta, autoload=True, autoload_with=migrate_engine) - floating_ips.create_column(c_auto_assigned) \ No newline at end of file + floating_ips.create_column(c_auto_assigned) -- cgit From 50bd39e0413c2231ebdf9f4c9fb7e58d27624250 Mon Sep 17 00:00:00 2001 From: Ilya Alekseyev Date: Tue, 19 Apr 2011 16:57:17 +0400 Subject: refractoring --- nova/compute/manager.py | 50 ++++++++++--------------------------------------- nova/network/api.py | 15 +++++++++------ 2 files changed, 19 insertions(+), 46 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index db97ae690..313b9e0e1 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -54,6 +54,7 @@ from nova import rpc from nova import utils from nova.compute import power_state from nova.virt import driver +from nova.network import api as network_api FLAGS = flags.FLAGS flags.DEFINE_string('instances_path', '$state_path/instances', @@ -134,6 +135,7 @@ class ComputeManager(manager.SchedulerDependentManager): self.network_manager = utils.import_object(FLAGS.network_manager) self.volume_manager = utils.import_object(FLAGS.volume_manager) + self.network_api = network_api.API() super(ComputeManager, self).__init__(service_name="compute", *args, **kwargs) @@ -248,39 +250,15 @@ class ComputeManager(manager.SchedulerDependentManager): if not FLAGS.stub_network: if FLAGS.auto_assign_floating_ip: - public_ip = rpc.call(context, - FLAGS.network_topic, - {"method": "allocate_floating_ip", - "args": {"project_id": context.project_id}}) + public_ip = self.network_api.allocate_floating_ip(context) fixed_ip = self.db.fixed_ip_get_by_address(context, address) floating_ip = self.db.floating_ip_get_by_address(context, public_ip) - # Check if the floating ip address is allocated - if floating_ip['project_id'] is None: - raise exception.Error(_("Address (%s) is not allocated") % - floating_ip['address']) - # Check if the floating ip address is allocated - # to the same project - if floating_ip['project_id'] != context.project_id: - LOG.warn(_("Address (%(address)s) is not allocated to your" - " project (%(project)s)"), - {'address': floating_ip['address'], - 'project': context.project_id}) - raise exception.Error(_("Address (%(address)s) is not " - "allocated to your project" - "(%(project)s)") % - {'address': floating_ip['address'], - 'project': context.project_id}) - - host = fixed_ip['network']['host'] - rpc.cast(context, - self.db.queue_get_for(context, - FLAGS.network_topic, host), - {"method": "associate_floating_ip", - "args": {"floating_address": floating_ip['address'], - "fixed_address": fixed_ip['address']}}) + self.network_api.associate_floating_ip(context, floating_ip, + fixed_ip, + affect_auto_assigned=True) self._update_state(context, instance_id) @exception.wrap_exception @@ -301,22 +279,14 @@ class ComputeManager(manager.SchedulerDependentManager): # NOTE(vish): Right now we don't really care if the ip is # disassociated. We may need to worry about # checking this later. - network_topic = self.db.queue_get_for(context, - FLAGS.network_topic, - floating_ip['host']) - rpc.cast(context, - network_topic, - {"method": "disassociate_floating_ip", - "args": {"floating_address": address}}) + self.network_api.disassociate_floating_ip(context, address, + affect_auto_assigned=True) if FLAGS.auto_assign_floating_ip \ and floating_ip.get('auto_assigned'): LOG.debug(_("Deallocating floating ip %s"), floating_ip['address'], context=context) - rpc.cast(context, - FLAGS.network_topic, - {"method": "deallocate_floating_ip", - "args": {"floating_address": - floating_ip['address']}}) + self.network_api.release_floating_ip(context, address, + affect_auto_assigned=True) address = fixed_ip['address'] if address: diff --git a/nova/network/api.py b/nova/network/api.py index c5f76a14e..61db646ae 100644 --- a/nova/network/api.py +++ b/nova/network/api.py @@ -51,9 +51,10 @@ class API(base.Base): {"method": "allocate_floating_ip", "args": {"project_id": context.project_id}}) - def release_floating_ip(self, context, address): + def release_floating_ip(self, context, address, + affect_auto_assigned = False): floating_ip = self.db.floating_ip_get_by_address(context, address) - if floating_ip.get('auto_assigned'): + if not affect_auto_assigned and floating_ip.get('auto_assigned'): return # NOTE(vish): We don't know which network host should get the ip # when we deallocate, so just send it to any one. This @@ -64,11 +65,12 @@ class API(base.Base): {"method": "deallocate_floating_ip", "args": {"floating_address": floating_ip['address']}}) - def associate_floating_ip(self, context, floating_ip, fixed_ip): + def associate_floating_ip(self, context, floating_ip, fixed_ip, + affect_auto_assigned = False): if isinstance(fixed_ip, str) or isinstance(fixed_ip, unicode): fixed_ip = self.db.fixed_ip_get_by_address(context, fixed_ip) floating_ip = self.db.floating_ip_get_by_address(context, floating_ip) - if floating_ip.get('auto_assigned'): + if not affect_auto_assigned and floating_ip.get('auto_assigned'): return # Check if the floating ip address is allocated if floating_ip['project_id'] is None: @@ -94,9 +96,10 @@ class API(base.Base): "args": {"floating_address": floating_ip['address'], "fixed_address": fixed_ip['address']}}) - def disassociate_floating_ip(self, context, address): + def disassociate_floating_ip(self, context, address, + affect_auto_assigned = False): floating_ip = self.db.floating_ip_get_by_address(context, address) - if floating_ip.get('auto_assigned'): + if not affect_auto_assigned and floating_ip.get('auto_assigned'): return if not floating_ip.get('fixed_ip'): raise exception.ApiError('Address is not associated.') -- cgit From 9c6cbd448088f5096bba9866d8057300256c6d34 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 19 Apr 2011 09:48:07 -0400 Subject: moving dynamic i18n to static --- nova/exception.py | 52 ++++++++++++++++++++--------------------- nova/tests/test_localization.py | 1 + nova/virt/vmwareapi/vmops.py | 2 +- 3 files changed, 28 insertions(+), 27 deletions(-) diff --git a/nova/exception.py b/nova/exception.py index 7d1b44c35..50d7984dc 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -137,11 +137,11 @@ class NovaException(Exception): def __init__(self, **kwargs): try: - self._error_string = _(self.message) % kwargs + self._error_string = self.message % kwargs except Exception: # at least get the core message out if something happened - self._error_string = _(self.message) + self._error_string = self.message def __str__(self): return self._error_string @@ -153,75 +153,75 @@ class Invalid(NovaException): class InstanceNotRunning(Invalid): - message = "Instance %(instance_id)s is not running." + message = _("Instance %(instance_id)s is not running.") class InstanceNotSuspended(Invalid): - message = "Instance %(instance_id)s is not suspended." + message = _("Instance %(instance_id)s is not suspended.") class InstanceSuspendFailure(Invalid): - message = "Failed to suspend instance: %(reason)s" + message = _("Failed to suspend instance") + ": %(reason)s" class InstanceResumeFailure(Invalid): - message = "Failed to resume server: %(reason)s." + message = _("Failed to resume server") + ": %(reason)s." class InstanceRebootFailure(Invalid): - message = "Failed to reboot instance: %(reason)s" + message = _("Failed to reboot instance") + ": %(reason)s" class ServiceUnavailable(Invalid): - message = "Service is unavailable at this time." + message = _("Service is unavailable at this time.") class VolumeServiceUnavailable(ServiceUnavailable): - message = "Volume service is unavailable at this time." + message = _("Volume service is unavailable at this time.") class ComputeServiceUnavailable(ServiceUnavailable): - message = "Compute service is unavailable at this time." + message = _("Compute service is unavailable at this time.") class UnableToMigrateToSelf(Invalid): - message = "Unable to migrate instance (%(instance_id)s) " \ - "to current host (%(host)s." + message = _("Unable to migrate instance (%(instance_id)s) " + "to current host (%(host)s).") class SourceHostUnavailable(Invalid): - message = "Original compute host is unavailable at this time." + message = _("Original compute host is unavailable at this time.") class InvalidHypervisorType(Invalid): - message = "The supplied hypervisor type of is invalid." + message = _("The supplied hypervisor type of is invalid.") class DestinationHypervisorTooOld(Invalid): - message = "The instance requires a newer hypervisor version than " \ - "has been provided." + message = _("The instance requires a newer hypervisor version than " + "has been provided.") class InvalidDevicePath(Invalid): - message = "The supplied device path (%(path)s) is invalid." + message = _("The supplied device path (%(path)s) is invalid.") class InvalidCPUInfo(Invalid): - message = "Unacceptable CPU info: %(reason)s" + message = _("Unacceptable CPU info") + ": %(reason)s" class InvalidVLANTag(Invalid): - message = "VLAN tag is not appropriate for the port group " \ - "%(bridge)s. Expected VLAN tag is %(tag)s, " \ - "but the one associated with the port group is %(pgroup)s." + message = _("VLAN tag is not appropriate for the port group " + "%(bridge)s. Expected VLAN tag is %(tag)s, " + "but the one associated with the port group is %(pgroup)s.") class InvalidVLANPortGroup(Invalid): - message = "vSwitch which contains the port group %(bridge)s is " \ - "not associated with the desired physical adapter. " \ - "Expected vSwitch is %(expected)s, but the one associated " \ - "is %(actual)s." + message = _("vSwitch which contains the port group %(bridge)s is " + "not associated with the desired physical adapter. " + "Expected vSwitch is %(expected)s, but the one associated " + "is %(actual)s.") class ImageUnacceptable(Invalid): - message = "Image %(image_id)s is unacceptable: %(reason)s" + message = _("Image %(image_id)s is unacceptable") + ": %(reason)s" diff --git a/nova/tests/test_localization.py b/nova/tests/test_localization.py index a25809a79..37cc22b1d 100644 --- a/nova/tests/test_localization.py +++ b/nova/tests/test_localization.py @@ -59,6 +59,7 @@ class LocalizationTestCase(test.TestCase): pos = 0 while parenCount > 0: char = txt[pos] + print char if char == "(": parenCount += 1 elif char == ")": diff --git a/nova/virt/vmwareapi/vmops.py b/nova/virt/vmwareapi/vmops.py index f2f68ec22..b700c438f 100644 --- a/nova/virt/vmwareapi/vmops.py +++ b/nova/virt/vmwareapi/vmops.py @@ -620,7 +620,7 @@ class VMWareVMOps(object): LOG.debug(_("Suspended the VM %s ") % instance.name) # Raise Exception if VM is poweredOff elif pwr_state == "poweredOff": - reason = _("instance is poweredOff and can not be suspended.") + reason = _("instance is powered off and can not be suspended.") raise exception.InstanceSuspendFailure(reason=reason) LOG.debug(_("VM %s was already in suspended state. So returning " -- cgit From 4466f775a70162f8a140afbe19a56d7290b014d3 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 19 Apr 2011 09:48:44 -0400 Subject: removing rogue print --- nova/tests/test_localization.py | 1 - 1 file changed, 1 deletion(-) diff --git a/nova/tests/test_localization.py b/nova/tests/test_localization.py index 37cc22b1d..a25809a79 100644 --- a/nova/tests/test_localization.py +++ b/nova/tests/test_localization.py @@ -59,7 +59,6 @@ class LocalizationTestCase(test.TestCase): pos = 0 while parenCount > 0: char = txt[pos] - print char if char == "(": parenCount += 1 elif char == ")": -- cgit From 7b5cf70cc9339028b1be9569e5754b997c7dae83 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 19 Apr 2011 09:50:53 -0400 Subject: multi-line string spacing --- nova/exception.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/nova/exception.py b/nova/exception.py index 50d7984dc..80c8dedfe 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -186,7 +186,7 @@ class ComputeServiceUnavailable(ServiceUnavailable): class UnableToMigrateToSelf(Invalid): message = _("Unable to migrate instance (%(instance_id)s) " - "to current host (%(host)s).") + "to current host (%(host)s).") class SourceHostUnavailable(Invalid): @@ -199,7 +199,7 @@ class InvalidHypervisorType(Invalid): class DestinationHypervisorTooOld(Invalid): message = _("The instance requires a newer hypervisor version than " - "has been provided.") + "has been provided.") class InvalidDevicePath(Invalid): @@ -212,15 +212,15 @@ class InvalidCPUInfo(Invalid): class InvalidVLANTag(Invalid): message = _("VLAN tag is not appropriate for the port group " - "%(bridge)s. Expected VLAN tag is %(tag)s, " - "but the one associated with the port group is %(pgroup)s.") + "%(bridge)s. Expected VLAN tag is %(tag)s, " + "but the one associated with the port group is %(pgroup)s.") class InvalidVLANPortGroup(Invalid): message = _("vSwitch which contains the port group %(bridge)s is " - "not associated with the desired physical adapter. " - "Expected vSwitch is %(expected)s, but the one associated " - "is %(actual)s.") + "not associated with the desired physical adapter. " + "Expected vSwitch is %(expected)s, but the one associated " + "is %(actual)s.") class ImageUnacceptable(Invalid): -- cgit From f5ef0e4bf39e01b46db241f5766db60059d52df3 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 19 Apr 2011 10:55:47 -0400 Subject: one last i18n string --- nova/exception.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/exception.py b/nova/exception.py index 80c8dedfe..6948a93c1 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -133,7 +133,7 @@ class NovaException(Exception): with the keyword arguments provided to the constructor. """ - message = "An unknown exception occurred." + message = _("An unknown exception occurred.") def __init__(self, **kwargs): try: -- cgit From 9812ae8d3c113475f8ef5d609874317d0b330425 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Tue, 19 Apr 2011 11:05:37 -0400 Subject: Removed extra calls in exception handling and standardized the way LoopingCalls are done. --- nova/virt/libvirt_conn.py | 186 ++++++++++++++++++++++++---------------------- 1 file changed, 98 insertions(+), 88 deletions(-) diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index d212be3c9..4e96b4e97 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -154,8 +154,8 @@ def _get_net_and_prefixlen(cidr): def _get_ip_version(cidr): - net = IPy.IP(cidr) - return int(net.version()) + net = IPy.IP(cidr) + return int(net.version()) def _get_network_info(instance): @@ -359,28 +359,24 @@ class LibvirtConnection(driver.ComputeDriver): locals()) raise - # We'll save this for when we do shutdown, - # instead of destroy - but destroy returns immediately - timer = utils.LoopingCall(f=None) + def _wait_for_destroy(): + """Called at an interval until the VM is running again.""" + instance_name = insatnce['name'] - while True: try: - state = self.get_info(instance['name'])['state'] - db.instance_set_state(context.get_admin_context(), - instance['id'], state) - if state == power_state.SHUTOFF: - break - - # Let's not hammer on the DB - time.sleep(1) - except Exception as ex: - msg = _("Error encountered when destroying instance '%(id)s': " - "%(ex)s") % {"id": instance["id"], "ex": ex} - LOG.debug(msg) - db.instance_set_state(context.get_admin_context(), - instance['id'], - power_state.SHUTOFF) - break + state = self.get_info(instance_name)['state'] + except exception.NotFound: + msg = _("During destroy, %s disappeared.") % instance_name + LOG.error(msg) + raise utils.LoopingCallDone + + if state == power_state.SHUTOFF: + msg = _("Instance %s destroyed successfully.") % instance_name + LOG.debug(instance_name) + raise utils.LoopingCallDone + + timer = utils.LoopingCall(_wait_for_destroy) + timer.start(interval=0.5, now=True) self.firewall_driver.unfilter_instance(instance) @@ -522,6 +518,12 @@ class LibvirtConnection(driver.ComputeDriver): @exception.wrap_exception def reboot(self, instance): + """Reboot a virtual machine, given an instance reference. + + This method actually destroys and re-creates the domain to ensure the + reboot happens, as the guest OS cannot ignore this action. + + """ self.destroy(instance, False) xml = self.to_xml(instance) self.firewall_driver.setup_basic_filtering(instance) @@ -529,24 +531,23 @@ class LibvirtConnection(driver.ComputeDriver): self._create_new_domain(xml) self.firewall_driver.apply_instance_filter(instance) - timer = utils.LoopingCall(f=None) - def _wait_for_reboot(): + """Called at an interval until the VM is running again.""" + instance_name = insatnce['name'] + try: - state = self.get_info(instance['name'])['state'] - db.instance_set_state(context.get_admin_context(), - instance['id'], state) - if state == power_state.RUNNING: - LOG.debug(_('instance %s: rebooted'), instance['name']) - timer.stop() - except Exception, exn: - LOG.exception(_('_wait_for_reboot failed: %s'), exn) - db.instance_set_state(context.get_admin_context(), - instance['id'], - power_state.SHUTDOWN) - timer.stop() + state = self.get_info(instance_name)['state'] + except exception.NotFound: + msg = _("During reboot, %s disappeared.") % instance_name + LOG.error(msg) + raise utils.LoopingCallDone + + if state == power_state.RUNNING: + msg = _("Instance %s rebooted successfully.") % instance_name + LOG.debug(instance_name) + raise utils.LoopingCallDone - timer.f = _wait_for_reboot + timer = utils.LoopingCall(_wait_for_reboot) return timer.start(interval=0.5, now=True) @exception.wrap_exception @@ -566,7 +567,15 @@ class LibvirtConnection(driver.ComputeDriver): raise exception.ApiError("resume not supported for libvirt") @exception.wrap_exception - def rescue(self, instance, callback=None): + def rescue(self, instance): + """Loads a VM using rescue images. + + A rescue is normally performed when something goes wrong with the + primary images and data needs to be corrected/recovered. Rescuing + should not edit or over-ride the original image, only allow for + data recovery. + + """ self.destroy(instance, False) xml = self.to_xml(instance, rescue=True) @@ -576,29 +585,33 @@ class LibvirtConnection(driver.ComputeDriver): self._create_image(instance, xml, '.rescue', rescue_images) self._create_new_domain(xml) - timer = utils.LoopingCall(f=None) - def _wait_for_rescue(): + """Called at an interval until the VM is running again.""" + instance_name = instance['name'] + try: - state = self.get_info(instance['name'])['state'] - db.instance_set_state(None, instance['id'], state) - if state == power_state.RUNNING: - LOG.debug(_('instance %s: rescued'), instance['name']) - timer.stop() - except Exception, exn: - LOG.exception(_('_wait_for_rescue failed: %s'), exn) - db.instance_set_state(None, - instance['id'], - power_state.SHUTDOWN) - timer.stop() + state = self.get_info(instance_name)['state'] + except exception.NotFound: + msg = _("During reboot, %s disappeared.") % instance_name + LOG.error(msg) + raise utils.LoopingCallDone + + if state == power_state.RUNNING: + msg = _("Instance %s rescued successfully.") % instance_name + LOG.debug(instance_name) + raise utils.LoopingCallDone - timer.f = _wait_for_rescue + timer = utils.LoopingCall(_wait_for_rescue) return timer.start(interval=0.5, now=True) @exception.wrap_exception - def unrescue(self, instance, callback=None): - # NOTE(vish): Because reboot destroys and recreates an instance using - # the normal xml file, we can just call reboot here + def unrescue(self, instance): + """Reboot the VM which is being rescued back into primary images. + + Because reboot destroys and re-creates instances, unresue should + simply call reboot. + + """ self.reboot(instance) @exception.wrap_exception @@ -610,10 +623,6 @@ class LibvirtConnection(driver.ComputeDriver): @exception.wrap_exception def spawn(self, instance, network_info=None): xml = self.to_xml(instance, False, network_info) - db.instance_set_state(context.get_admin_context(), - instance['id'], - power_state.NOSTATE, - 'launching') self.firewall_driver.setup_basic_filtering(instance, network_info) self.firewall_driver.prepare_instance_filter(instance, network_info) self._create_image(instance, xml, network_info) @@ -626,25 +635,23 @@ class LibvirtConnection(driver.ComputeDriver): instance['name']) domain.setAutostart(1) - timer = utils.LoopingCall(f=None) - def _wait_for_boot(): + """Called at an interval until the VM is running.""" + instance_name = insatnce['name'] + try: - state = self.get_info(instance['name'])['state'] - db.instance_set_state(context.get_admin_context(), - instance['id'], state) - if state == power_state.RUNNING: - LOG.debug(_('instance %s: booted'), instance['name']) - timer.stop() - except: - LOG.exception(_('instance %s: failed to boot'), - instance['name']) - db.instance_set_state(context.get_admin_context(), - instance['id'], - power_state.SHUTDOWN) - timer.stop() + state = self.get_info(instance_name)['state'] + except exception.NotFound: + msg = _("During reboot, %s disappeared.") % instance_name + LOG.error(msg) + raise utils.LoopingCallDone - timer.f = _wait_for_boot + if state == power_state.RUNNING: + msg = _("Instance %s spawned successfully.") % instance_name + LOG.debug(instance_name) + raise utils.LoopingCallDone + + timer = utils.LoopingCall(_wait_for_boot) return timer.start(interval=0.5, now=True) def _flush_xen_console(self, virsh_output): @@ -1045,21 +1052,24 @@ class LibvirtConnection(driver.ComputeDriver): return xml def get_info(self, instance_name): - # NOTE(justinsb): When libvirt isn't running / can't connect, we get: - # libvir: Remote error : unable to connect to - # '/var/run/libvirt/libvirt-sock', libvirtd may need to be started: - # No such file or directory + """Retrieve information from libvirt for a specific instance name. + + If a libvirt error is encountered during lookup, we might raise a + NotFound exception or Error exception depending on how severe the + libvirt error is. + + """ try: virt_dom = self._conn.lookupByName(instance_name) - except libvirt.libvirtError as e: - errcode = e.get_error_code() - if errcode == libvirt.VIR_ERR_NO_DOMAIN: - raise exception.NotFound(_("Instance %s not found") - % instance_name) - LOG.warning(_("Error from libvirt during lookup. " - "Code=%(errcode)s Error=%(e)s") % - locals()) - raise + except libvirt.libvirtError as ex: + error_code = ex.get_error_code() + if error_code == libvirt.VIR_ERR_NO_DOMAIN: + msg = _("Instance %s not found") % instance_name + raise exception.NotFound(msg) + + msg = _("Error from libvirt while looking up %(instance_name)s: " + "[Error Code %(error_code)s] %(ex)s") % locals() + raise exception.Error(msg) (state, max_mem, mem, num_cpu, cpu_time) = virt_dom.info() return {'state': state, -- cgit From 8e98888323d4308640ab5061cdae5ccd4e3ebabf Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Tue, 19 Apr 2011 11:09:07 -0400 Subject: Pretty critical spelling error. --- nova/virt/libvirt_conn.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 4e96b4e97..fad8dd52a 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -361,7 +361,7 @@ class LibvirtConnection(driver.ComputeDriver): def _wait_for_destroy(): """Called at an interval until the VM is running again.""" - instance_name = insatnce['name'] + instance_name = instance['name'] try: state = self.get_info(instance_name)['state'] @@ -533,7 +533,7 @@ class LibvirtConnection(driver.ComputeDriver): def _wait_for_reboot(): """Called at an interval until the VM is running again.""" - instance_name = insatnce['name'] + instance_name = instance['name'] try: state = self.get_info(instance_name)['state'] @@ -637,7 +637,7 @@ class LibvirtConnection(driver.ComputeDriver): def _wait_for_boot(): """Called at an interval until the VM is running.""" - instance_name = insatnce['name'] + instance_name = instance['name'] try: state = self.get_info(instance_name)['state'] -- cgit From 3e31785d86c59dbda62e3a3ba3a1e23452e52562 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Tue, 19 Apr 2011 11:16:46 -0400 Subject: Tweak to destroy loop logic. --- nova/virt/libvirt_conn.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index fad8dd52a..53137395e 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -366,11 +366,6 @@ class LibvirtConnection(driver.ComputeDriver): try: state = self.get_info(instance_name)['state'] except exception.NotFound: - msg = _("During destroy, %s disappeared.") % instance_name - LOG.error(msg) - raise utils.LoopingCallDone - - if state == power_state.SHUTOFF: msg = _("Instance %s destroyed successfully.") % instance_name LOG.debug(instance_name) raise utils.LoopingCallDone -- cgit From ad2d97972d63f50500ec8215c7f8f04d87468060 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Tue, 19 Apr 2011 11:29:26 -0400 Subject: Fixed info messages. --- nova/virt/libvirt_conn.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 53137395e..13378bbd2 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -367,7 +367,7 @@ class LibvirtConnection(driver.ComputeDriver): state = self.get_info(instance_name)['state'] except exception.NotFound: msg = _("Instance %s destroyed successfully.") % instance_name - LOG.debug(instance_name) + LOG.info(msg) raise utils.LoopingCallDone timer = utils.LoopingCall(_wait_for_destroy) @@ -539,7 +539,7 @@ class LibvirtConnection(driver.ComputeDriver): if state == power_state.RUNNING: msg = _("Instance %s rebooted successfully.") % instance_name - LOG.debug(instance_name) + LOG.info(msg) raise utils.LoopingCallDone timer = utils.LoopingCall(_wait_for_reboot) @@ -593,7 +593,7 @@ class LibvirtConnection(driver.ComputeDriver): if state == power_state.RUNNING: msg = _("Instance %s rescued successfully.") % instance_name - LOG.debug(instance_name) + LOG.info(msg) raise utils.LoopingCallDone timer = utils.LoopingCall(_wait_for_rescue) @@ -643,7 +643,7 @@ class LibvirtConnection(driver.ComputeDriver): if state == power_state.RUNNING: msg = _("Instance %s spawned successfully.") % instance_name - LOG.debug(instance_name) + LOG.info(msg) raise utils.LoopingCallDone timer = utils.LoopingCall(_wait_for_boot) -- cgit From 25e1e2d64ad43638ad4231e6e6edd84d96e14bdb Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Tue, 19 Apr 2011 11:33:51 -0400 Subject: Merged trunk and fixed small comment. --- nova/virt/libvirt_conn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 13378bbd2..2582b9730 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -360,7 +360,7 @@ class LibvirtConnection(driver.ComputeDriver): raise def _wait_for_destroy(): - """Called at an interval until the VM is running again.""" + """Called at an interval until the VM is gone.""" instance_name = instance['name'] try: -- cgit From da99e8e6b143cd2051c23f14d4d46602f16f7ba3 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 19 Apr 2011 09:16:25 -0700 Subject: add instructions for setting up interfaces --- doc/source/devref/cloudpipe.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/source/devref/cloudpipe.rst b/doc/source/devref/cloudpipe.rst index 95570aa1b..a1f6c6450 100644 --- a/doc/source/devref/cloudpipe.rst +++ b/doc/source/devref/cloudpipe.rst @@ -68,6 +68,12 @@ Making a cloudpipe image is relatively easy. :language: bash :linenos: +# setup network interfaces. + +.. literalinclude:: interfaces + :language: bash + :linenos: + # register the image and set the image id in your flagfile:: --vpn_image_id=ami-xxxxxxxx -- cgit From 8b21dd6634cc32c43d0bebf3dede40b4b28c0a78 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 19 Apr 2011 09:16:45 -0700 Subject: add include file for doc interfaces --- doc/source/devref/interfaces | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 doc/source/devref/interfaces diff --git a/doc/source/devref/interfaces b/doc/source/devref/interfaces new file mode 100644 index 000000000..2aae39558 --- /dev/null +++ b/doc/source/devref/interfaces @@ -0,0 +1,18 @@ +# The loopback network interface +auto lo +iface lo inet loopback + +# The primary network interface +auto br0 +iface br0 inet dhcp + bridge_ports eth0 + bridge_fd 9 ## from the libvirt docs (forward delay time) + bridge_hello 2 ## from the libvirt docs (hello time) + bridge_maxage 12 ## from the libvirt docs (maximum message age) + bridge_stp off ## from the libvirt docs (spanning tree protocol) + +iface eth0 inet manual + up ifconfig $IFACE 0.0.0.0 up + up ip link set $IFACE promisc on + down ip link set $IFACE promisc off + down ifconfig $IFACE down -- cgit From 745351d1e2a98a98de0a5f955385a92c01110684 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 19 Apr 2011 09:19:52 -0700 Subject: Fixes cloudpipe to get the proper ip address. * Changes FLAGS.vpn_image_id to integer * Converts to str when comparing because instance['image_id'] is a str * Removes unused method from db * Converts integer_id to ami when launching * Adds docs for setting up interface in cloudpipe image --- nova/api/ec2/admin.py | 2 +- nova/api/ec2/cloud.py | 4 ++-- nova/cloudpipe/pipelib.py | 2 ++ nova/compute/manager.py | 2 +- nova/db/api.py | 5 ----- nova/db/sqlalchemy/api.py | 9 +-------- nova/flags.py | 2 +- nova/virt/libvirt_conn.py | 2 +- 8 files changed, 9 insertions(+), 19 deletions(-) diff --git a/nova/api/ec2/admin.py b/nova/api/ec2/admin.py index 6a5609d4a..ea94d9c1f 100644 --- a/nova/api/ec2/admin.py +++ b/nova/api/ec2/admin.py @@ -266,7 +266,7 @@ class AdminController(object): def _vpn_for(self, context, project_id): """Get the VPN instance for a project ID.""" for instance in db.instance_get_all_by_project(context, project_id): - if (instance['image_id'] == FLAGS.vpn_image_id + if (instance['image_id'] == str(FLAGS.vpn_image_id) and not instance['state_description'] in ['shutting_down', 'shutdown']): return instance diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 10b1d0ac5..d9c1af072 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -703,7 +703,7 @@ class CloudController(object): instances = self.compute_api.get_all(context, **kwargs) for instance in instances: if not context.is_admin: - if instance['image_id'] == FLAGS.vpn_image_id: + if instance['image_id'] == str(FLAGS.vpn_image_id): continue i = {} instance_id = instance['id'] @@ -898,7 +898,7 @@ class CloudController(object): return image_type @staticmethod - def _image_ec2_id(image_id, image_type='ami'): + def image_ec2_id(image_id, image_type='ami'): """Returns image ec2_id using id and three letter type.""" template = image_type + '-%08x' return ec2utils.id_to_ec2_id(int(image_id), template=template) diff --git a/nova/cloudpipe/pipelib.py b/nova/cloudpipe/pipelib.py index dc6f55af2..2c8912422 100644 --- a/nova/cloudpipe/pipelib.py +++ b/nova/cloudpipe/pipelib.py @@ -37,6 +37,7 @@ from nova import utils from nova.auth import manager # TODO(eday): Eventually changes these to something not ec2-specific from nova.api.ec2 import cloud +from nova.api FLAGS = flags.FLAGS @@ -101,6 +102,7 @@ class CloudPipe(object): key_name = self.setup_key_pair(ctxt) group_name = self.setup_security_group(ctxt) + ec2_id = self.controller.image_ec2_id(FLAGS.vpn_image_id) reservation = self.controller.run_instances(ctxt, user_data=self.get_encoded_zip(project_id), max_count=1, diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 39d7af9c1..05b168e13 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -209,7 +209,7 @@ class ComputeManager(manager.SchedulerDependentManager): power_state.NOSTATE, 'networking') - is_vpn = instance_ref['image_id'] == FLAGS.vpn_image_id + is_vpn = instance_ref['image_id'] == str(FLAGS.vpn_image_id) # NOTE(vish): This could be a cast because we don't do anything # with the address currently, but I'm leaving it as # a call to ensure that network setup completes. We diff --git a/nova/db/api.py b/nova/db/api.py index 63901e94d..030d2f434 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -455,11 +455,6 @@ def instance_get_project_vpn(context, project_id): return IMPL.instance_get_project_vpn(context, project_id) -def instance_is_vpn(context, instance_id): - """True if instance is a vpn.""" - return IMPL.instance_is_vpn(context, instance_id) - - def instance_set_state(context, instance_id, state, description=None): """Set the state of an instance.""" return IMPL.instance_set_state(context, instance_id, state, description) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index e675022e9..e9450e392 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -940,7 +940,7 @@ def instance_get_project_vpn(context, project_id): options(joinedload('security_groups')).\ options(joinedload('instance_type')).\ filter_by(project_id=project_id).\ - filter_by(image_id=FLAGS.vpn_image_id).\ + filter_by(image_id=str(FLAGS.vpn_image_id)).\ filter_by(deleted=can_read_deleted(context)).\ first() @@ -979,13 +979,6 @@ def instance_get_floating_address(context, instance_id): return instance_ref.fixed_ip.floating_ips[0]['address'] -@require_admin_context -def instance_is_vpn(context, instance_id): - # TODO(vish): Move this into image code somewhere - instance_ref = instance_get(context, instance_id) - return instance_ref['image_id'] == FLAGS.vpn_image_id - - @require_admin_context def instance_set_state(context, instance_id, state, description=None): # TODO(devcamcar): Move this out of models and into driver diff --git a/nova/flags.py b/nova/flags.py index f011ab383..760bcc37d 100644 --- a/nova/flags.py +++ b/nova/flags.py @@ -316,7 +316,7 @@ DEFINE_string('null_kernel', 'nokernel', 'kernel image that indicates not to use a kernel,' ' but to use a raw disk image instead') -DEFINE_string('vpn_image_id', 'ami-cloudpipe', 'AMI for cloudpipe vpn server') +DEFINE_integer('vpn_image_id', 0, 'integer id for cloudpipe vpn server') DEFINE_string('vpn_key_suffix', '-vpn', 'Suffix to add to project name for vpn key and secgroups') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 5da091920..9c8d64446 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -1837,7 +1837,7 @@ class NWFilterFirewall(FirewallDriver): """ if not network_info: network_info = _get_network_info(instance) - if instance['image_id'] == FLAGS.vpn_image_id: + if instance['image_id'] == str(FLAGS.vpn_image_id): base_filter = 'nova-vpn' else: base_filter = 'nova-base' -- cgit From 7554ab7da290565ee457b2d42730a2bff2fd7861 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 19 Apr 2011 09:31:18 -0700 Subject: remove typo --- nova/cloudpipe/pipelib.py | 1 - 1 file changed, 1 deletion(-) diff --git a/nova/cloudpipe/pipelib.py b/nova/cloudpipe/pipelib.py index 2c8912422..f4cb53da0 100644 --- a/nova/cloudpipe/pipelib.py +++ b/nova/cloudpipe/pipelib.py @@ -37,7 +37,6 @@ from nova import utils from nova.auth import manager # TODO(eday): Eventually changes these to something not ec2-specific from nova.api.ec2 import cloud -from nova.api FLAGS = flags.FLAGS -- cgit From 2d649fa8928e9682064613f2c984f53f492efbec Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 19 Apr 2011 09:32:33 -0700 Subject: actually use the ec2_id --- nova/cloudpipe/pipelib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/cloudpipe/pipelib.py b/nova/cloudpipe/pipelib.py index f4cb53da0..7844d31e1 100644 --- a/nova/cloudpipe/pipelib.py +++ b/nova/cloudpipe/pipelib.py @@ -107,7 +107,7 @@ class CloudPipe(object): max_count=1, min_count=1, instance_type='m1.tiny', - image_id=FLAGS.vpn_image_id, + image_id=ec2_id, key_name=key_name, security_group=[group_name]) -- cgit From 3e3f8e1f09d0615e66cc1be0b656d0d8e1d69671 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Tue, 19 Apr 2011 12:36:07 -0400 Subject: Abstracted lookupByName calls to _lookup_by_name for centralized error handling. --- nova/virt/libvirt_conn.py | 53 +++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 2582b9730..c1f62c391 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -309,19 +309,10 @@ class LibvirtConnection(driver.ComputeDriver): def destroy(self, instance, cleanup=True): instance_name = instance['name'] - # TODO(justinsb): Refactor all lookupByName calls for error-handling try: - virt_dom = self._conn.lookupByName(instance_name) - except libvirt.libvirtError as e: - errcode = e.get_error_code() - if errcode == libvirt.VIR_ERR_NO_DOMAIN: - virt_dom = None - else: - LOG.warning(_("Error from libvirt during lookup of " - "%(instance_name)s. Code=%(errcode)s " - "Error=%(e)s") % - locals()) - raise + virt_dom = self._lookup_by_name(instance_name) + except exception.NotFound: + virt_dom = None # If the instance is already terminated, we're still happy # Otherwise, destroy it @@ -392,7 +383,7 @@ class LibvirtConnection(driver.ComputeDriver): @exception.wrap_exception def attach_volume(self, instance_name, device_path, mountpoint): - virt_dom = self._conn.lookupByName(instance_name) + virt_dom = self._lookup_by_name(instance_name) mount_device = mountpoint.rpartition("/")[2] if device_path.startswith('/dev/'): xml = """ @@ -436,7 +427,7 @@ class LibvirtConnection(driver.ComputeDriver): @exception.wrap_exception def detach_volume(self, instance_name, mountpoint): - virt_dom = self._conn.lookupByName(instance_name) + virt_dom = self._lookup_by_name(instance_name) mount_device = mountpoint.rpartition("/")[2] xml = self._get_disk_xml(virt_dom.XMLDesc(0), mount_device) if not xml: @@ -453,7 +444,7 @@ class LibvirtConnection(driver.ComputeDriver): """ image_service = utils.import_object(FLAGS.image_service) - virt_dom = self._conn.lookupByName(instance['name']) + virt_dom = self._lookup_by_name(instance['name']) elevated = context.get_admin_context() base = image_service.show(elevated, instance['image_id']) @@ -712,7 +703,7 @@ class LibvirtConnection(driver.ComputeDriver): raise Exception(_('Unable to find an open port')) def get_pty_for_instance(instance_name): - virt_dom = self._conn.lookupByName(instance_name) + virt_dom = self._lookup_by_name(instance_name) xml = virt_dom.XMLDesc(0) dom = minidom.parseString(xml) @@ -737,7 +728,7 @@ class LibvirtConnection(driver.ComputeDriver): @exception.wrap_exception def get_vnc_console(self, instance): def get_vnc_port_for_instance(instance_name): - virt_dom = self._conn.lookupByName(instance_name) + virt_dom = self._lookup_by_name(instance_name) xml = virt_dom.XMLDesc(0) # TODO: use etree instead of minidom dom = minidom.parseString(xml) @@ -1046,16 +1037,15 @@ class LibvirtConnection(driver.ComputeDriver): instance['name']) return xml - def get_info(self, instance_name): - """Retrieve information from libvirt for a specific instance name. + def _lookup_by_name(self, instance_name): + """Retrieve libvirt domain object given an instance name. - If a libvirt error is encountered during lookup, we might raise a - NotFound exception or Error exception depending on how severe the - libvirt error is. + All libvirt error handling should be handled in this method and + relevant nova exceptions should be raised in response. """ try: - virt_dom = self._conn.lookupByName(instance_name) + return self._conn.lookupByName(instance_name) except libvirt.libvirtError as ex: error_code = ex.get_error_code() if error_code == libvirt.VIR_ERR_NO_DOMAIN: @@ -1066,6 +1056,15 @@ class LibvirtConnection(driver.ComputeDriver): "[Error Code %(error_code)s] %(ex)s") % locals() raise exception.Error(msg) + def get_info(self, instance_name): + """Retrieve information from libvirt for a specific instance name. + + If a libvirt error is encountered during lookup, we might raise a + NotFound exception or Error exception depending on how severe the + libvirt error is. + + """ + virt_dom = self._lookup_by_name(instance_name) (state, max_mem, mem, num_cpu, cpu_time) = virt_dom.info() return {'state': state, 'max_mem': max_mem, @@ -1102,7 +1101,7 @@ class LibvirtConnection(driver.ComputeDriver): Returns a list of all block devices for this domain. """ - domain = self._conn.lookupByName(instance_name) + domain = self._lookup_by_name(instance_name) # TODO(devcamcar): Replace libxml2 with etree. xml = domain.XMLDesc(0) doc = None @@ -1144,7 +1143,7 @@ class LibvirtConnection(driver.ComputeDriver): Returns a list of all network interfaces for this instance. """ - domain = self._conn.lookupByName(instance_name) + domain = self._lookup_by_name(instance_name) # TODO(devcamcar): Replace libxml2 with etree. xml = domain.XMLDesc(0) doc = None @@ -1359,7 +1358,7 @@ class LibvirtConnection(driver.ComputeDriver): Note that this function takes an instance name, not an Instance, so that it can be called by monitor. """ - domain = self._conn.lookupByName(instance_name) + domain = self._lookup_by_name(instance_name) return domain.blockStats(disk) def interface_stats(self, instance_name, interface): @@ -1367,7 +1366,7 @@ class LibvirtConnection(driver.ComputeDriver): Note that this function takes an instance name, not an Instance, so that it can be called by monitor. """ - domain = self._conn.lookupByName(instance_name) + domain = self._lookup_by_name(instance_name) return domain.interfaceStats(interface) def get_console_pool_info(self, console_type): -- cgit From c3a45962a322086e4d7339f980bcf61ee8bd3167 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 19 Apr 2011 09:38:01 -0700 Subject: rename all versions of image_ec2_id --- nova/api/ec2/cloud.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index d9c1af072..c48ec9004 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -159,7 +159,7 @@ class CloudController(object): floating_ip = db.instance_get_floating_address(ctxt, instance_ref['id']) ec2_id = ec2utils.id_to_ec2_id(instance_ref['id']) - image_ec2_id = self._image_ec2_id(instance_ref['image_id'], 'ami') + image_ec2_id = self.image_ec2_id(instance_ref['image_id']) data = { 'user-data': base64.b64decode(instance_ref['user_data']), 'meta-data': { @@ -188,8 +188,8 @@ class CloudController(object): for image_type in ['kernel', 'ramdisk']: if '%s_id' % image_type in instance_ref: - ec2_id = self._image_ec2_id(instance_ref['%s_id' % image_type], - self._image_type(image_type)) + ec2_id = self.image_ec2_id(instance_ref['%s_id' % image_type], + self._image_type(image_type)) data['meta-data']['%s-id' % image_type] = ec2_id if False: # TODO(vish): store ancestor ids @@ -709,7 +709,7 @@ class CloudController(object): instance_id = instance['id'] ec2_id = ec2utils.id_to_ec2_id(instance_id) i['instanceId'] = ec2_id - i['imageId'] = self._image_ec2_id(instance['image_id']) + i['imageId'] = self.image_ec2_id(instance['image_id']) i['instanceState'] = { 'code': instance['state'], 'name': instance['state_description']} @@ -917,15 +917,15 @@ class CloudController(object): """Convert from format defined by BaseImageService to S3 format.""" i = {} image_type = self._image_type(image.get('container_format')) - ec2_id = self._image_ec2_id(image.get('id'), image_type) + ec2_id = self.image_ec2_id(image.get('id'), image_type) name = image.get('name') i['imageId'] = ec2_id kernel_id = image['properties'].get('kernel_id') if kernel_id: - i['kernelId'] = self._image_ec2_id(kernel_id, 'aki') + i['kernelId'] = self.image_ec2_id(kernel_id, 'aki') ramdisk_id = image['properties'].get('ramdisk_id') if ramdisk_id: - i['ramdiskId'] = self._image_ec2_id(ramdisk_id, 'ari') + i['ramdiskId'] = self.image_ec2_id(ramdisk_id, 'ari') i['imageOwnerId'] = image['properties'].get('owner_id') if name: i['imageLocation'] = "%s (%s)" % (image['properties']. @@ -976,8 +976,8 @@ class CloudController(object): metadata = {'properties': {'image_location': image_location}} image = self.image_service.create(context, metadata) image_type = self._image_type(image.get('container_format')) - image_id = self._image_ec2_id(image['id'], - image_type) + image_id = self.image_ec2_id(image['id'], + image_type) msg = _("Registered image %(image_location)s with" " id %(image_id)s") % locals() LOG.audit(msg, context=context) -- cgit From 1378b117b7ea2bb05219b5a0e48f4b1ae8cac9ae Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 19 Apr 2011 13:17:21 -0400 Subject: refactoring usage of exception.Duplicate errors --- nova/api/ec2/cloud.py | 3 +-- nova/auth/dbdriver.py | 5 ++--- nova/auth/ldapdriver.py | 11 ++++------- nova/exception.py | 39 +++++++++++++++++++++++++++++++++++---- nova/virt/hyperv.py | 3 +-- nova/virt/vmwareapi/vmops.py | 3 +-- nova/virt/xenapi/vm_utils.py | 3 +-- nova/virt/xenapi/vmops.py | 3 +-- 8 files changed, 46 insertions(+), 24 deletions(-) diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index bd4c9dcd4..0bbfa0ea6 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -61,8 +61,7 @@ def _gen_key(context, user_id, key_name): # creation before creating key_pair try: db.key_pair_get(context, user_id, key_name) - raise exception.Duplicate(_("The key_pair %s already exists") - % key_name) + raise exception.KeyPairExists(key_name=key_name) except exception.NotFound: pass private_key, public_key, fingerprint = crypto.generate_key_pair() diff --git a/nova/auth/dbdriver.py b/nova/auth/dbdriver.py index b2c580d83..4f5022b9a 100644 --- a/nova/auth/dbdriver.py +++ b/nova/auth/dbdriver.py @@ -81,7 +81,7 @@ class DbDriver(object): user_ref = db.user_create(context.get_admin_context(), values) return self._db_user_to_auth_user(user_ref) except exception.Duplicate, e: - raise exception.Duplicate(_('User %s already exists') % name) + raise exception.UserExists(user=name) def _db_user_to_auth_user(self, user_ref): return {'id': user_ref['id'], @@ -132,8 +132,7 @@ class DbDriver(object): try: project = db.project_create(context.get_admin_context(), values) except exception.Duplicate: - raise exception.Duplicate(_("Project can't be created because " - "project %s already exists") % name) + raise exception.ProjectExists(project=name) for member in members: db.project_add_member(context.get_admin_context(), diff --git a/nova/auth/ldapdriver.py b/nova/auth/ldapdriver.py index fcac55510..1feb77625 100644 --- a/nova/auth/ldapdriver.py +++ b/nova/auth/ldapdriver.py @@ -171,7 +171,7 @@ class LdapDriver(object): def create_user(self, name, access_key, secret_key, is_admin): """Create a user""" if self.__user_exists(name): - raise exception.Duplicate(_("LDAP user %s already exists") % name) + raise exception.LDAPUserExists(user=name) if FLAGS.ldap_user_modify_only: if self.__ldap_user_exists(name): # Retrieve user by name @@ -226,8 +226,7 @@ class LdapDriver(object): description=None, member_uids=None): """Create a project""" if self.__project_exists(name): - raise exception.Duplicate(_("Project can't be created because " - "project %s already exists") % name) + raise exception.ProjectExists(project=name) if not self.__user_exists(manager_uid): raise exception.NotFound(_("Project can't be created because " "manager %s doesn't exist") @@ -471,8 +470,7 @@ class LdapDriver(object): description, member_uids=None): """Create a group""" if self.__group_exists(group_dn): - raise exception.Duplicate(_("Group can't be created because " - "group %s already exists") % name) + raise exception.LDAPGroupExists(group=name) members = [] if member_uids is not None: for member_uid in member_uids: @@ -512,8 +510,7 @@ class LdapDriver(object): raise exception.NotFound(_("The group at dn %s doesn't exist") % group_dn) if self.__is_in_group(uid, group_dn): - raise exception.Duplicate(_("User %(uid)s is already a member of " - "the group %(group_dn)s") % locals()) + raise exception.LDAPMembershipExists(uid=uid, group_dn=group_dn) attr = [(self.ldap.MOD_ADD, 'member', self.__uid_to_dn(uid))] self.conn.modify_s(group_dn, attr) diff --git a/nova/exception.py b/nova/exception.py index 6948a93c1..6d3bcd67e 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -68,10 +68,6 @@ class VolumeNotFound(NotFound): super(VolumeNotFound, self).__init__(message) -class Duplicate(Error): - pass - - class NotAuthorized(Error): pass @@ -225,3 +221,38 @@ class InvalidVLANPortGroup(Invalid): class ImageUnacceptable(Invalid): message = _("Image %(image_id)s is unacceptable") + ": %(reason)s" + + +#TODO(bcwaldon): EOL this exception! +class Duplicate(NovaException): + pass + + +class KeyPairExists(Duplicate): + message = _("Key pair %(key_name)s already exists.") + + +class UserExists(Duplicate): + message = _("User %(user)s already exists.") + + +class LDAPUserExists(UserExists): + message = _("LDAP user %(user)s already exists.") + + +class LDAPGroupExists(Duplicate): + message = _("LDAP group %(group)s already exists.") + + +class LDAPMembershipExists(Duplicate): + message = _("User %(uid)s is already a member of " + "the group %(group_dn)s") + + +class ProjectExists(Duplicate): + message = _("Project %(project)s already exists.") + + +class InstanceExists(Duplicate): + message = _("Instance %(name)s already exists.") + diff --git a/nova/virt/hyperv.py b/nova/virt/hyperv.py index 13f403a66..85d5190fb 100644 --- a/nova/virt/hyperv.py +++ b/nova/virt/hyperv.py @@ -143,8 +143,7 @@ class HyperVConnection(driver.ComputeDriver): """ Create a new VM and start it.""" vm = self._lookup(instance.name) if vm is not None: - raise exception.Duplicate(_('Attempt to create duplicate vm %s') % - instance.name) + raise exception.InstanceExists(name=instance.name) user = manager.AuthManager().get_user(instance['user_id']) project = manager.AuthManager().get_project(instance['project_id']) diff --git a/nova/virt/vmwareapi/vmops.py b/nova/virt/vmwareapi/vmops.py index b700c438f..d77f9f8cb 100644 --- a/nova/virt/vmwareapi/vmops.py +++ b/nova/virt/vmwareapi/vmops.py @@ -100,8 +100,7 @@ class VMWareVMOps(object): """ vm_ref = self._get_vm_ref_from_the_name(instance.name) if vm_ref: - raise exception.Duplicate(_("Attempted to create a VM with a name" - " %s, but that already exists on the host") % instance.name) + raise exception.InstanceExists(name=instance.name) client_factory = self._session._get_vim().client.factory service_content = self._session._get_vim().get_service_content() diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index d2045a557..4b00b45ca 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -647,8 +647,7 @@ class VMHelper(HelperBase): if n == 0: return None elif n > 1: - raise exception.Duplicate(_('duplicate name found: %s') % - name_label) + raise exception.InstanceExists(name=name_label) else: return vm_refs[0] diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 7c7aa8e98..6f2870501 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -127,8 +127,7 @@ class VMOps(object): instance_name = instance.name vm_ref = VMHelper.lookup(self._session, instance_name) if vm_ref is not None: - raise exception.Duplicate(_('Attempted to create' - ' non-unique name %s') % instance_name) + raise exception.InstanceExists(name=instance_name) #ensure enough free memory is available if not VMHelper.ensure_free_mem(self._session, instance): -- cgit From 2ed46e198933de00059e8436b970efa0a0de8318 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 19 Apr 2011 13:18:15 -0400 Subject: pep8 fix --- nova/exception.py | 1 - 1 file changed, 1 deletion(-) diff --git a/nova/exception.py b/nova/exception.py index 6d3bcd67e..ba16c4796 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -255,4 +255,3 @@ class ProjectExists(Duplicate): class InstanceExists(Duplicate): message = _("Instance %(name)s already exists.") - -- cgit From 4442d8f7017868f64eacc6d8ad94620263b9a9c9 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 19 Apr 2011 10:20:56 -0700 Subject: make geninter.sh use the right tmpl file --- nova/CA/geninter.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/CA/geninter.sh b/nova/CA/geninter.sh index 4b7f5a55c..9b3ea3b76 100755 --- a/nova/CA/geninter.sh +++ b/nova/CA/geninter.sh @@ -21,7 +21,7 @@ NAME=$1 SUBJ=$2 mkdir -p projects/$NAME cd projects/$NAME -cp ../../openssl.cnf.tmpl openssl.cnf +cp "$(dirname $0)/openssl.cnf.tmpl" openssl.cnf sed -i -e s/%USERNAME%/$NAME/g openssl.cnf mkdir -p certs crl newcerts private openssl req -new -x509 -extensions v3_ca -keyout private/cakey.pem -out cacert.pem -days 365 -config ./openssl.cnf -batch -nodes -- cgit From ccf9b2ccb41b1e7f946f2b2c21e6f8fbc9bd04e8 Mon Sep 17 00:00:00 2001 From: Eldar Nugaev Date: Tue, 19 Apr 2011 21:25:53 +0400 Subject: fix logging in reboot OpenStack API --- nova/api/openstack/servers.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index f221229f0..e9f570213 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -40,7 +40,7 @@ import nova.api.openstack from nova.scheduler import api as scheduler_api -LOG = logging.getLogger('server') +LOG = logging.getLogger('nova.api.openstack.servers') FLAGS = flags.FLAGS @@ -331,6 +331,7 @@ class Controller(common.OpenstackController): return exc.HTTPAccepted() def _action_rebuild(self, input_dict, req, id): + LOG.debug(_("Rebuild server action is not implemented")) return faults.Fault(exc.HTTPNotImplemented()) def _action_resize(self, input_dict, req, id): @@ -346,18 +347,20 @@ class Controller(common.OpenstackController): except Exception, e: LOG.exception(_("Error in resize %s"), e) return faults.Fault(exc.HTTPBadRequest()) - return faults.Fault(exc.HTTPAccepted()) + return exc.HTTPAccepted() def _action_reboot(self, input_dict, req, id): - try: + if 'reboot' in input_dict and 'type' in input_dict['reboot']: reboot_type = input_dict['reboot']['type'] - except Exception: - raise faults.Fault(exc.HTTPNotImplemented()) + else: + LOG.exception(_("Missing argument 'type' for reboot")) + return faults.Fault(exc.HTTPUnprocessableEntity()) try: # TODO(gundlach): pass reboot_type, support soft reboot in # virt driver self.compute_api.reboot(req.environ['nova.context'], id) - except: + except Exception, e: + LOG.exception(_("Error in reboot %s"), e) return faults.Fault(exc.HTTPUnprocessableEntity()) return exc.HTTPAccepted() -- cgit From 66a15373a14e9acc30808d2cf21bd800c64cc012 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 19 Apr 2011 10:31:35 -0700 Subject: fix doc typo --- doc/source/devref/cloudpipe.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/source/devref/cloudpipe.rst b/doc/source/devref/cloudpipe.rst index a1f6c6450..15d3160b7 100644 --- a/doc/source/devref/cloudpipe.rst +++ b/doc/source/devref/cloudpipe.rst @@ -62,13 +62,13 @@ Making a cloudpipe image is relatively easy. :language: bash :linenos: -# download and run the payload on boot from /etc/rc.local. +# download and run the payload on boot from /etc/rc.local .. literalinclude:: rc.local :language: bash :linenos: -# setup network interfaces. +# setup /etc/network/interfaces .. literalinclude:: interfaces :language: bash -- cgit From a474310be8ed4d7a9840412779567abef71406f1 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Tue, 19 Apr 2011 17:24:01 -0400 Subject: Create a dictionary of instance_types before executing SQL updates in the instance_type_id migration (014). This should resolve a "cannot commit transaction - SQL statements in progress" error with some versions of sqlite. --- .../migrate_repo/versions/014_add_instance_type_id_to_instances.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nova/db/sqlalchemy/migrate_repo/versions/014_add_instance_type_id_to_instances.py b/nova/db/sqlalchemy/migrate_repo/versions/014_add_instance_type_id_to_instances.py index b12a0a801..334d1f255 100644 --- a/nova/db/sqlalchemy/migrate_repo/versions/014_add_instance_type_id_to_instances.py +++ b/nova/db/sqlalchemy/migrate_repo/versions/014_add_instance_type_id_to_instances.py @@ -54,10 +54,12 @@ def upgrade(migrate_engine): instances.create_column(c_instance_type_id) + type_names = {} recs = migrate_engine.execute(instance_types.select()) for row in recs: - type_id = row[0] - type_name = row[1] + type_names[row[0]] = row[1] + + for type_id, type_name in type_names.iteritems(): migrate_engine.execute(instances.update()\ .where(instances.c.instance_type == type_name)\ .values(instance_type_id=type_id)) -- cgit From 63f5aa5484aa9d61f2ed79caae1c665230a56f35 Mon Sep 17 00:00:00 2001 From: Ken Pepple Date: Tue, 19 Apr 2011 15:25:39 -0700 Subject: revamped spacing per Rick Harris suggestion. Added exact error to nova-manage output. --- bin/nova-manage | 1 + nova/compute/instance_types.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/bin/nova-manage b/bin/nova-manage index 8ec3a1e64..6b47cc4f5 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -833,6 +833,7 @@ class InstanceTypeCommands(object): sys.exit(1) except exception.ApiError, e: print "\n\n" + print "\n%s" % e print "Please ensure instance_type name and flavorid are unique." print "To complete remove a instance_type, use the --purge flag:" print "\n # nova-manage instance_type delete --purge\n" diff --git a/nova/compute/instance_types.py b/nova/compute/instance_types.py index a92e5d3bc..6accf82bb 100644 --- a/nova/compute/instance_types.py +++ b/nova/compute/instance_types.py @@ -56,8 +56,8 @@ def create(name, memory, vcpus, local_gb, flavorid, swap=0, rxtx_cap=rxtx_cap)) except exception.DBError, e: LOG.exception(_('DB error: %s') % e) - raise exception.ApiError(_("Cannot create instance_type with\ - name %(name)s and flavorid %(flavorid)s") % + raise exception.ApiError(_("Cannot create instance_type with " + "name %(name)s and flavorid %(flavorid)s") % locals()) -- cgit From d992fbbde7c8e5274d80e2fce9c840e7209c78c6 Mon Sep 17 00:00:00 2001 From: Jimmy Bergman Date: Wed, 20 Apr 2011 14:06:23 +0200 Subject: Change response format of CreateVolume to match EC2 --- nova/api/ec2/cloud.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index bd4c9dcd4..2bbe4c368 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -613,7 +613,7 @@ class CloudController(object): # TODO(vish): Instance should be None at db layer instead of # trying to lazy load, but for now we turn it into # a dict to avoid an error. - return {'volumeSet': [self._format_volume(context, dict(volume))]} + return self._format_volume(context, dict(volume)) def delete_volume(self, context, volume_id, **kwargs): volume_id = ec2utils.ec2_id_to_id(volume_id) -- cgit From 19aaf2523b1f157b5f9cad0d625857e98c19002b Mon Sep 17 00:00:00 2001 From: Jimmy Bergman Date: Wed, 20 Apr 2011 14:12:47 +0200 Subject: Add to Authors --- Authors | 1 + 1 file changed, 1 insertion(+) diff --git a/Authors b/Authors index ce280749d..c440d3c11 100644 --- a/Authors +++ b/Authors @@ -30,6 +30,7 @@ Ilya Alekseyev Jason Koelker Jay Pipes Jesse Andrews +Jimmy Bergman Joe Heck Joel Moore Johannes Erdfelt -- cgit From 45178fd6da58ff37617e35b5cddaf416ae5cee65 Mon Sep 17 00:00:00 2001 From: Ilya Alekseyev Date: Wed, 20 Apr 2011 17:44:25 +0400 Subject: fix: mark floating ip as auto assigned --- nova/compute/manager.py | 1 + 1 file changed, 1 insertion(+) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 313b9e0e1..c1dc06557 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -252,6 +252,7 @@ class ComputeManager(manager.SchedulerDependentManager): if FLAGS.auto_assign_floating_ip: public_ip = self.network_api.allocate_floating_ip(context) + self.db.floating_ip_set_auto_assigned(context, public_ip) fixed_ip = self.db.fixed_ip_get_by_address(context, address) floating_ip = self.db.floating_ip_get_by_address(context, public_ip) -- cgit From 803d246c35256e0578837226b1a91003e451ab6f Mon Sep 17 00:00:00 2001 From: Ilya Alekseyev Date: Wed, 20 Apr 2011 18:35:07 +0400 Subject: instance type get approach changed. tests fixed --- nova/tests/test_virt.py | 4 ++-- nova/virt/libvirt_conn.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/nova/tests/test_virt.py b/nova/tests/test_virt.py index 5c8705a1c..0a0c7a958 100644 --- a/nova/tests/test_virt.py +++ b/nova/tests/test_virt.py @@ -619,7 +619,7 @@ class IptablesFirewallTestCase(test.TestCase): {'user_id': 'fake', 'project_id': 'fake', 'mac_address': '56:12:12:12:12:12', - 'instance_type': 'm1.small'}) + 'instance_type_id': 1}) ip = '10.11.12.13' network_ref = db.project_get_network(self.context, @@ -843,7 +843,7 @@ class NWFilterTestCase(test.TestCase): {'user_id': 'fake', 'project_id': 'fake', 'mac_address': '00:A0:C9:14:C8:29', - 'instance_type': 'm1.small'}) + 'instance_type_id': 1}) inst_id = instance_ref['id'] ip = '10.11.12.13' diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index c12b6e91e..d5a88ebed 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -167,8 +167,8 @@ def _get_network_info(instance): instance['id']) networks = db.network_get_all_by_instance(admin_context, instance['id']) - flavor = db.instance_type_get_by_name(admin_context, - instance['instance_type']) + flavor = db.instance_type_get_by_id(admin_context, + instance['instance_type_id']) network_info = [] for network in networks: -- cgit From 48936f6b8f063cf71fa42b4586d8ba524ed39cc4 Mon Sep 17 00:00:00 2001 From: Eldar Nugaev Date: Wed, 20 Apr 2011 20:37:51 +0400 Subject: fix Request.get_content_type --- nova/api/openstack/servers.py | 67 +++++++++++------------------ nova/tests/api/openstack/test_extensions.py | 1 + nova/tests/api/openstack/test_servers.py | 4 ++ nova/tests/api/test_wsgi.py | 7 +++ nova/wsgi.py | 20 ++++++--- 5 files changed, 52 insertions(+), 47 deletions(-) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 22a9c632c..e0681e597 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -294,61 +294,47 @@ class Controller(common.OpenstackController): 'revertResize': self._action_revert_resize, 'rebuild': self._action_rebuild, } - input_dict = self._deserialize(req.body, req.get_content_type()) for key in actions.keys(): if key in input_dict: - return actions[key](input_dict, req, id) + try: + context = req.environ['nova.context'] + return actions[key](context, input_dict, id) + except Exception, e: + LOG.exception(_("Error in action %(key)s: %(e)s") % + locals()) + return faults.Fault(exc.HTTPBadRequest()) return faults.Fault(exc.HTTPNotImplemented()) - def _action_change_password(self, input_dict, req, id): + def _action_change_password(self, context, input_dict, id): return exc.HTTPNotImplemented() - def _action_confirm_resize(self, input_dict, req, id): - try: - self.compute_api.confirm_resize(req.environ['nova.context'], id) - except Exception, e: - LOG.exception(_("Error in confirm-resize %s"), e) - return faults.Fault(exc.HTTPBadRequest()) + def _action_confirm_resize(self, context, input_dict, id): + self.compute_api.confirm_resize(context, id) return exc.HTTPNoContent() - def _action_revert_resize(self, input_dict, req, id): - try: - self.compute_api.revert_resize(req.environ['nova.context'], id) - except Exception, e: - LOG.exception(_("Error in revert-resize %s"), e) - return faults.Fault(exc.HTTPBadRequest()) + def _action_revert_resize(self, context, input_dict, id): + self.compute_api.revert_resize(context, id) return exc.HTTPAccepted() - def _action_rebuild(self, input_dict, req, id): + def _action_rebuild(self, context, input_dict, id): return faults.Fault(exc.HTTPNotImplemented()) - def _action_resize(self, input_dict, req, id): + def _action_resize(self, context, input_dict, id): """ Resizes a given instance to the flavor size requested """ - try: - if 'resize' in input_dict and 'flavorId' in input_dict['resize']: - flavor_id = input_dict['resize']['flavorId'] - self.compute_api.resize(req.environ['nova.context'], id, - flavor_id) - else: - LOG.exception(_("Missing arguments for resize")) - return faults.Fault(exc.HTTPUnprocessableEntity()) - except Exception, e: - LOG.exception(_("Error in resize %s"), e) - return faults.Fault(exc.HTTPBadRequest()) + if 'resize' in input_dict and 'flavorId' in input_dict['resize']: + flavor_id = input_dict['resize']['flavorId'] + self.compute_api.resize(context, id, flavor_id) + else: + LOG.exception(_("Missing arguments for resize")) + return faults.Fault(exc.HTTPUnprocessableEntity()) return faults.Fault(exc.HTTPAccepted()) - def _action_reboot(self, input_dict, req, id): - try: - reboot_type = input_dict['reboot']['type'] - except Exception: - raise faults.Fault(exc.HTTPNotImplemented()) - try: - # TODO(gundlach): pass reboot_type, support soft reboot in - # virt driver - self.compute_api.reboot(req.environ['nova.context'], id) - except: - return faults.Fault(exc.HTTPUnprocessableEntity()) + def _action_reboot(self, context, input_dict, id): + reboot_type = input_dict['reboot']['type'] + # TODO(gundlach): pass reboot_type, support soft reboot in + # virt driver + self.compute_api.reboot(context, id) return exc.HTTPAccepted() @scheduler_api.redirect_handler @@ -632,8 +618,7 @@ class ControllerV11(Controller): def _get_addresses_view_builder(self, req): return nova.api.openstack.views.addresses.ViewBuilderV11(req) - def _action_change_password(self, input_dict, req, id): - context = req.environ['nova.context'] + def _action_change_password(self, context, input_dict, id): if (not 'changePassword' in input_dict or not 'adminPass' in input_dict['changePassword']): msg = _("No adminPass was specified") diff --git a/nova/tests/api/openstack/test_extensions.py b/nova/tests/api/openstack/test_extensions.py index 481d34ed1..6453e96c9 100644 --- a/nova/tests/api/openstack/test_extensions.py +++ b/nova/tests/api/openstack/test_extensions.py @@ -158,6 +158,7 @@ class ActionExtensionTest(unittest.TestCase): request.method = 'POST' request.content_type = 'application/json' request.body = json.dumps(body) + request.environ = {'nova.context': 'context'} response = request.get_response(ext_midware) return response diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 556046e9d..a92da52b1 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -952,6 +952,7 @@ class ServersTest(test.TestCase): req.method = 'POST' req.content_type = 'application/json' req.body = json.dumps(body) + req.environ = {"nova.context": "context"} res = req.get_response(fakes.wsgi_app()) self.assertEqual(res.status_int, 501) @@ -973,6 +974,7 @@ class ServersTest(test.TestCase): req.method = 'POST' req.content_type = 'application/json' req.body = json.dumps(body) + req.environ = {"nova.context": "context"} res = req.get_response(fakes.wsgi_app()) self.assertEqual(res.status_int, 202) self.assertEqual(mock_method.instance_id, '1') @@ -993,6 +995,7 @@ class ServersTest(test.TestCase): req.method = 'POST' req.content_type = 'application/json' req.body = json.dumps(body) + req.environ = {"nova.context": "context"} res = req.get_response(fakes.wsgi_app()) self.assertEqual(res.status_int, 400) @@ -1002,6 +1005,7 @@ class ServersTest(test.TestCase): req.method = 'POST' req.content_type = 'application/json' req.body = json.dumps(body) + req.environ = {"nova.context": "context"} res = req.get_response(fakes.wsgi_app()) self.assertEqual(res.status_int, 400) diff --git a/nova/tests/api/test_wsgi.py b/nova/tests/api/test_wsgi.py index 1ecdd1cfb..ed96aac5e 100644 --- a/nova/tests/api/test_wsgi.py +++ b/nova/tests/api/test_wsgi.py @@ -136,6 +136,13 @@ class RequestTest(test.TestCase): request.body = "asdf
" self.assertRaises(webob.exc.HTTPBadRequest, request.get_content_type) + def test_request_content_type_with_charset(self): + request = wsgi.Request.blank('/tests/123') + request.headers["Content-Type"] = "application/json; charset=UTF-8" + request.body = "" + result = request.get_content_type() + self.assertEqual(result, "application/json") + def test_content_type_from_accept_xml(self): request = wsgi.Request.blank('/tests/123') request.headers["Accept"] = "application/xml" diff --git a/nova/wsgi.py b/nova/wsgi.py index de2e0749f..617830c22 100644 --- a/nova/wsgi.py +++ b/nova/wsgi.py @@ -28,6 +28,7 @@ from xml.dom import minidom import eventlet import eventlet.wsgi eventlet.patcher.monkey_patch(all=False, socket=True, time=True) +import re import routes import routes.middleware import webob @@ -105,12 +106,19 @@ class Request(webob.Request): return bm or "application/json" def get_content_type(self): - try: - ct = self.headers["Content-Type"] - assert ct in ("application/xml", "application/json") - return ct - except Exception: - raise webob.exc.HTTPBadRequest("Invalid content type") + allowed_types = ("application/xml", "application/json") + if not "Content-Type" in self.headers: + msg = _("Missing Content-Type") + LOG.debug(msg) + raise webob.exc.HTTPBadRequest(msg) + content_type = self.headers["Content-Type"] + match = re.search("([\w/]+)", content_type) + if match: + type = match.group(0) + if type in allowed_types: + return type + LOG.debug(_("Wrong Content-Type: %s") % content_type) + raise webob.exc.HTTPBadRequest("Invalid content type") class Application(object): -- cgit From a4b78306d31e1ef84d5dc9550ef2dcb1ed030fa2 Mon Sep 17 00:00:00 2001 From: Eldar Nugaev Date: Wed, 20 Apr 2011 21:34:55 +0400 Subject: fix after review: style, improving tests, replacing underscore --- nova/tests/test_virt.py | 20 ++++++++++++++------ nova/virt/libvirt_conn.py | 14 +++++++------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/nova/tests/test_virt.py b/nova/tests/test_virt.py index 19e4d5428..2e6fae6c7 100644 --- a/nova/tests/test_virt.py +++ b/nova/tests/test_virt.py @@ -223,7 +223,7 @@ class LibvirtConnTestCase(test.TestCase): _create_network_info(2)) self.assertTrue(len(result['nics']) == 2) - def test_get_nic_for_xml(self): + def test_get_nic_for_xml_v4(self): conn = libvirt_conn.LibvirtConnection(True) network, mapping = _create_network_info()[0] self.flags(use_ipv6=False) @@ -794,8 +794,11 @@ class IptablesFirewallTestCase(test.TestCase): self.assertEquals(len(rulesv6), 3) def multinic_iptables_test(self): + ipv4_rules_per_network = 2 + ipv6_rules_per_network = 3 + networks_count = 5 instance_ref = self._create_instance_ref() - network_info = _create_network_info() + network_info = _create_network_info(networks_count) ipv4_len = len(self.fw.iptables.ipv4['filter'].rules) ipv6_len = len(self.fw.iptables.ipv6['filter'].rules) inst_ipv4, inst_ipv6 = self.fw.instance_rules(instance_ref, @@ -803,8 +806,12 @@ class IptablesFirewallTestCase(test.TestCase): self.fw.add_filters_for_instance(instance_ref, network_info) ipv4 = self.fw.iptables.ipv4['filter'].rules ipv6 = self.fw.iptables.ipv6['filter'].rules - self.assertEquals(len(ipv4) - len(inst_ipv4) - ipv4_len, 2) - self.assertEquals(len(ipv6) - len(inst_ipv6) - ipv6_len, 3) + ipv4_network_rules = len(ipv4) - len(inst_ipv4) - ipv4_len + ipv6_network_rules = len(ipv6) - len(inst_ipv6) - ipv6_len + self.assertEquals(ipv4_network_rules, + ipv4_rules_per_network * networks_count) + self.assertEquals(ipv6_network_rules, + ipv6_rules_per_network * networks_count) class NWFilterTestCase(test.TestCase): @@ -965,6 +972,7 @@ class NWFilterTestCase(test.TestCase): def test_create_network_filters(self): instance_ref = self._create_instance() network_info = _create_network_info(3) - result = \ - self.fw._create_network_filters(instance_ref, network_info, "fake") + result = self.fw._create_network_filters(instance_ref, + network_info, + "fake") self.assertEquals(len(result), 3) diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 73a804014..7e8ff409a 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -1839,12 +1839,12 @@ class NWFilterFirewall(FirewallDriver): 'nova-allow-dhcp-server'] if FLAGS.use_ipv6: - networks = [network for (network, _) in network_info if + networks = [network for (network, _m) in network_info if network['gateway_v6']] if networks: instance_secgroup_filter_children.\ - append('nova-allow-ra-server') + append('nova-allow-ra-server') for security_group in \ db.security_group_get_by_instance(ctxt, instance['id']): @@ -1859,8 +1859,8 @@ class NWFilterFirewall(FirewallDriver): instance_secgroup_filter_children)) network_filters = self.\ - _create_network_filters(instance, network_info, - instance_secgroup_filter_name) + _create_network_filters(instance, network_info, + instance_secgroup_filter_name) for (name, children) in network_filters: self._define_filters(name, children) @@ -1873,7 +1873,7 @@ class NWFilterFirewall(FirewallDriver): base_filter = 'nova-base' result = [] - for (_, mapping) in network_info: + for (_n, mapping) in network_info: nic_id = mapping['mac'].replace(':', '') instance_filter_name = self._instance_filter_name(instance, nic_id) instance_filter_children = [base_filter, @@ -1996,11 +1996,11 @@ class IptablesFirewallDriver(FirewallDriver): return ['-d %s -j $%s' % (ip, chain_name) for ip in ips] def _filters_for_instance(self, chain_name, network_info): - ips_v4 = [ip['ip'] for (_, mapping) in network_info + ips_v4 = [ip['ip'] for (_n, mapping) in network_info for ip in mapping['ips']] ipv4_rules = self._create_filter(ips_v4, chain_name) - ips_v6 = [ip['ip'] for (_, mapping) in network_info + ips_v6 = [ip['ip'] for (_n, mapping) in network_info for ip in mapping['ip6s']] ipv6_rules = self._create_filter(ips_v6, chain_name) -- cgit From 155635faf20d4a1996639baf5d2c10b05734c3df Mon Sep 17 00:00:00 2001 From: Eldar Nugaev Date: Wed, 20 Apr 2011 21:50:03 +0400 Subject: replaced regex to webob.Request.content_type --- nova/wsgi.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/nova/wsgi.py b/nova/wsgi.py index 617830c22..9e0f80565 100644 --- a/nova/wsgi.py +++ b/nova/wsgi.py @@ -28,7 +28,6 @@ from xml.dom import minidom import eventlet import eventlet.wsgi eventlet.patcher.monkey_patch(all=False, socket=True, time=True) -import re import routes import routes.middleware import webob @@ -111,13 +110,10 @@ class Request(webob.Request): msg = _("Missing Content-Type") LOG.debug(msg) raise webob.exc.HTTPBadRequest(msg) - content_type = self.headers["Content-Type"] - match = re.search("([\w/]+)", content_type) - if match: - type = match.group(0) - if type in allowed_types: - return type - LOG.debug(_("Wrong Content-Type: %s") % content_type) + type = self.content_type + if type in allowed_types: + return type + LOG.debug(_("Wrong Content-Type: %s") % type) raise webob.exc.HTTPBadRequest("Invalid content type") -- cgit From 584cde68aa36c35c03c29eb4bb09ede5f8c4074e Mon Sep 17 00:00:00 2001 From: Josh Kearney Date: Wed, 20 Apr 2011 12:50:23 -0500 Subject: Pylinted nova-manage --- bin/nova-manage | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/bin/nova-manage b/bin/nova-manage index b2308bc03..2c06767f1 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -58,7 +58,6 @@ import gettext import glob import json import os -import re import sys import time @@ -66,11 +65,11 @@ import IPy # If ../nova/__init__.py exists, add ../ to Python search path, so that # it will override what happens to be installed in /usr/(local/)lib/python... -possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]), +POSSIBLE_TOPDIR = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]), os.pardir, os.pardir)) -if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')): - sys.path.insert(0, possible_topdir) +if os.path.exists(os.path.join(POSSIBLE_TOPDIR, 'nova', '__init__.py')): + sys.path.insert(0, POSSIBLE_TOPDIR) gettext.install('nova', unicode=1) @@ -809,11 +808,11 @@ class VolumeCommands(object): class InstanceTypeCommands(object): """Class for managing instance types / flavors.""" - def _print_instance_types(self, n, val): + def _print_instance_types(self, name, val): deleted = ('', ', inactive')[val["deleted"] == 1] print ("%s: Memory: %sMB, VCPUS: %s, Storage: %sGB, FlavorID: %s, " "Swap: %sGB, RXTX Quota: %sGB, RXTX Cap: %sMB%s") % ( - n, val["memory_mb"], val["vcpus"], val["local_gb"], + name, val["memory_mb"], val["vcpus"], val["local_gb"], val["flavorid"], val["swap"], val["rxtx_quota"], val["rxtx_cap"], deleted) @@ -1021,7 +1020,7 @@ class ImageCommands(object): machine_images[image_path] = image_metadata else: other_images[image_path] = image_metadata - except Exception as exc: + except Exception: print _("Failed to load %(fn)s.") % locals() # NOTE(vish): do kernels and ramdisks first so images self._convert_images(other_images) -- cgit From 8b2ac745211a567b7c05e31343ada3ef4be85eb4 Mon Sep 17 00:00:00 2001 From: Josh Kearney Date: Wed, 20 Apr 2011 12:56:44 -0500 Subject: Pylinted nova-compute. --- bin/nova-compute | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/nova-compute b/bin/nova-compute index 95fa393b1..cd7c78def 100755 --- a/bin/nova-compute +++ b/bin/nova-compute @@ -28,11 +28,11 @@ import sys # If ../nova/__init__.py exists, add ../ to Python search path, so that # it will override what happens to be installed in /usr/(local/)lib/python... -possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]), +POSSIBLE_TOPDIR = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]), os.pardir, os.pardir)) -if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')): - sys.path.insert(0, possible_topdir) +if os.path.exists(os.path.join(POSSIBLE_TOPDIR, 'nova', '__init__.py')): + sys.path.insert(0, POSSIBLE_TOPDIR) gettext.install('nova', unicode=1) -- cgit From fe23f71687e09248feb7542ea97001a496697742 Mon Sep 17 00:00:00 2001 From: Eldar Nugaev Date: Wed, 20 Apr 2011 22:01:14 +0400 Subject: remove ambiguity in test --- nova/tests/api/test_wsgi.py | 1 - 1 file changed, 1 deletion(-) diff --git a/nova/tests/api/test_wsgi.py b/nova/tests/api/test_wsgi.py index ed96aac5e..5820ecdc2 100644 --- a/nova/tests/api/test_wsgi.py +++ b/nova/tests/api/test_wsgi.py @@ -139,7 +139,6 @@ class RequestTest(test.TestCase): def test_request_content_type_with_charset(self): request = wsgi.Request.blank('/tests/123') request.headers["Content-Type"] = "application/json; charset=UTF-8" - request.body = "" result = request.get_content_type() self.assertEqual(result, "application/json") -- cgit From f4cfb9f0e654f26664345a041a62fd93613ef83b Mon Sep 17 00:00:00 2001 From: termie Date: Wed, 20 Apr 2011 11:52:17 -0700 Subject: docstring cleanup compute manager --- nova/compute/manager.py | 236 +++++++++++++++++++++--------------------------- 1 file changed, 105 insertions(+), 131 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index c795d72ad..8103ed61e 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -17,8 +17,7 @@ # License for the specific language governing permissions and limitations # under the License. -""" -Handles all processes relating to instances (guest vms). +"""Handles all processes relating to instances (guest vms). The :py:class:`ComputeManager` class is a :py:class:`nova.manager.Manager` that handles RPC calls relating to creating instances. It is responsible for @@ -33,6 +32,7 @@ terminating it. by :func:`nova.utils.import_object` :volume_manager: Name of class that handles persistent storage, loaded by :func:`nova.utils.import_object` + """ import datetime @@ -55,6 +55,7 @@ from nova import utils from nova.compute import power_state from nova.virt import driver + FLAGS = flags.FLAGS flags.DEFINE_string('instances_path', '$state_path/instances', 'where instances are stored on disk') @@ -74,19 +75,14 @@ flags.DEFINE_integer("rescue_timeout", 0, "Automatically unrescue an instance after N seconds." " Set to 0 to disable.") + LOG = logging.getLogger('nova.compute.manager') def checks_instance_lock(function): - """ - decorator used for preventing action against locked instances - unless, of course, you happen to be admin - - """ - + """Decorator to prevent action against locked instances for non-admins.""" @functools.wraps(function) def decorated_function(self, context, instance_id, *args, **kwargs): - LOG.info(_("check_instance_lock: decorating: |%s|"), function, context=context) LOG.info(_("check_instance_lock: arguments: |%(self)s| |%(context)s|" @@ -112,7 +108,6 @@ def checks_instance_lock(function): class ComputeManager(manager.SchedulerDependentManager): - """Manages the running instances from creation to destruction.""" def __init__(self, compute_driver=None, *args, **kwargs): @@ -136,9 +131,7 @@ class ComputeManager(manager.SchedulerDependentManager): *args, **kwargs) def init_host(self): - """Do any initialization that needs to be run if this is a - standalone service. - """ + """Initialization for a standalone compute service.""" self.driver.init_host(host=self.host) def _update_state(self, context, instance_id): @@ -153,16 +146,18 @@ class ComputeManager(manager.SchedulerDependentManager): self.db.instance_set_state(context, instance_id, state) def get_console_topic(self, context, **kwargs): - """Retrieves the console host for a project on this host - Currently this is just set in the flags for each compute - host.""" + """Retrieves the console host for a project on this host. + + Currently this is just set in the flags for each compute host. + + """ #TODO(mdragon): perhaps make this variable by console_type? return self.db.queue_get_for(context, FLAGS.console_topic, FLAGS.console_host) def get_network_topic(self, context, **kwargs): - """Retrieves the network host for a project on this host""" + """Retrieves the network host for a project on this host.""" # TODO(vish): This method should be memoized. This will make # the call to get_network_host cheaper, so that # it can pas messages instead of checking the db @@ -179,15 +174,23 @@ class ComputeManager(manager.SchedulerDependentManager): return self.driver.get_console_pool_info(console_type) @exception.wrap_exception - def refresh_security_group_rules(self, context, - security_group_id, **kwargs): - """This call passes straight through to the virtualization driver.""" + def refresh_security_group_rules(self, context, security_group_id, + **kwargs): + """Tell the virtualization driver to refresh security group rules. + + Passes straight through to the virtualization driver. + + """ return self.driver.refresh_security_group_rules(security_group_id) @exception.wrap_exception def refresh_security_group_members(self, context, security_group_id, **kwargs): - """This call passes straight through to the virtualization driver.""" + """Tell the virtualization driver to refresh security group members. + + Passes straight through to the virtualization driver. + + """ return self.driver.refresh_security_group_members(security_group_id) @exception.wrap_exception @@ -249,7 +252,7 @@ class ComputeManager(manager.SchedulerDependentManager): @exception.wrap_exception @checks_instance_lock def terminate_instance(self, context, instance_id): - """Terminate an instance on this machine.""" + """Terminate an instance on this host.""" context = context.elevated() instance_ref = self.db.instance_get(context, instance_id) LOG.audit(_("Terminating instance %s"), instance_id, context=context) @@ -297,7 +300,7 @@ class ComputeManager(manager.SchedulerDependentManager): @exception.wrap_exception @checks_instance_lock def reboot_instance(self, context, instance_id): - """Reboot an instance on this server.""" + """Reboot an instance on this host.""" context = context.elevated() self._update_state(context, instance_id) instance_ref = self.db.instance_get(context, instance_id) @@ -321,7 +324,7 @@ class ComputeManager(manager.SchedulerDependentManager): @exception.wrap_exception def snapshot_instance(self, context, instance_id, image_id): - """Snapshot an instance on this server.""" + """Snapshot an instance on this host.""" context = context.elevated() instance_ref = self.db.instance_get(context, instance_id) @@ -344,7 +347,7 @@ class ComputeManager(manager.SchedulerDependentManager): @exception.wrap_exception @checks_instance_lock def set_admin_password(self, context, instance_id, new_pass=None): - """Set the root/admin password for an instance on this server.""" + """Set the root/admin password for an instance on this host.""" context = context.elevated() instance_ref = self.db.instance_get(context, instance_id) instance_id = instance_ref['id'] @@ -365,7 +368,7 @@ class ComputeManager(manager.SchedulerDependentManager): @exception.wrap_exception @checks_instance_lock def inject_file(self, context, instance_id, path, file_contents): - """Write a file to the specified path on an instance on this server""" + """Write a file to the specified path in an instance on this host.""" context = context.elevated() instance_ref = self.db.instance_get(context, instance_id) instance_id = instance_ref['id'] @@ -383,44 +386,34 @@ class ComputeManager(manager.SchedulerDependentManager): @exception.wrap_exception @checks_instance_lock def rescue_instance(self, context, instance_id): - """Rescue an instance on this server.""" + """Rescue an instance on this host.""" context = context.elevated() instance_ref = self.db.instance_get(context, instance_id) LOG.audit(_('instance %s: rescuing'), instance_id, context=context) - self.db.instance_set_state( - context, - instance_id, - power_state.NOSTATE, - 'rescuing') + self.db.instance_set_state(context, + instance_id, + power_state.NOSTATE, + 'rescuing') self.network_manager.setup_compute_network(context, instance_id) - self.driver.rescue( - instance_ref, - lambda result: self._update_state_callback( - self, - context, - instance_id, - result)) + _update_state = lambda result: self._update_state_callback( + self, context, instance_id, result)) + self.driver.rescue(instance_ref, _update_state) self._update_state(context, instance_id) @exception.wrap_exception @checks_instance_lock def unrescue_instance(self, context, instance_id): - """Rescue an instance on this server.""" + """Rescue an instance on this host.""" context = context.elevated() instance_ref = self.db.instance_get(context, instance_id) LOG.audit(_('instance %s: unrescuing'), instance_id, context=context) - self.db.instance_set_state( - context, - instance_id, - power_state.NOSTATE, - 'unrescuing') - self.driver.unrescue( - instance_ref, - lambda result: self._update_state_callback( - self, - context, - instance_id, - result)) + self.db.instance_set_state(context, + instance_id, + power_state.NOSTATE, + 'unrescuing') + _update_state = lambda result: self._update_state_callback( + self, context, instance_id, result)) + self.driver.unrescue(instance_ref, _update_state) self._update_state(context, instance_id) @staticmethod @@ -431,7 +424,7 @@ class ComputeManager(manager.SchedulerDependentManager): @exception.wrap_exception @checks_instance_lock def confirm_resize(self, context, instance_id, migration_id): - """Destroys the source instance""" + """Destroys the source instance.""" context = context.elevated() instance_ref = self.db.instance_get(context, instance_id) self.driver.destroy(instance_ref) @@ -439,9 +432,12 @@ class ComputeManager(manager.SchedulerDependentManager): @exception.wrap_exception @checks_instance_lock def revert_resize(self, context, instance_id, migration_id): - """Destroys the new instance on the destination machine, - reverts the model changes, and powers on the old - instance on the source machine""" + """Destroys the new instance on the destination machine. + + Reverts the model changes, and powers on the old instance on the + source machine. + + """ instance_ref = self.db.instance_get(context, instance_id) migration_ref = self.db.migration_get(context, migration_id) @@ -458,9 +454,12 @@ class ComputeManager(manager.SchedulerDependentManager): @exception.wrap_exception @checks_instance_lock def finish_revert_resize(self, context, instance_id, migration_id): - """Finishes the second half of reverting a resize, powering back on - the source instance and reverting the resized attributes in the - database""" + """Finishes the second half of reverting a resize. + + Power back on the source instance and revert the resized attributes + in the database. + + """ instance_ref = self.db.instance_get(context, instance_id) migration_ref = self.db.migration_get(context, migration_id) instance_type = self.db.instance_type_get_by_flavor_id(context, @@ -480,8 +479,11 @@ class ComputeManager(manager.SchedulerDependentManager): @exception.wrap_exception @checks_instance_lock def prep_resize(self, context, instance_id, flavor_id): - """Initiates the process of moving a running instance to another - host, possibly changing the RAM and disk size in the process""" + """Initiates the process of moving a running instance to another host. + + Possibly changes the RAM and disk size in the process. + + """ context = context.elevated() instance_ref = self.db.instance_get(context, instance_id) if instance_ref['host'] == FLAGS.host: @@ -513,35 +515,38 @@ class ComputeManager(manager.SchedulerDependentManager): @exception.wrap_exception @checks_instance_lock def resize_instance(self, context, instance_id, migration_id): - """Starts the migration of a running instance to another host""" + """Starts the migration of a running instance to another host.""" migration_ref = self.db.migration_get(context, migration_id) instance_ref = self.db.instance_get(context, instance_id) - self.db.migration_update(context, migration_id, - {'status': 'migrating', }) - - disk_info = self.driver.migrate_disk_and_power_off(instance_ref, - migration_ref['dest_host']) - self.db.migration_update(context, migration_id, - {'status': 'post-migrating', }) - - # Make sure the service exists before sending a message. - _service = self.db.service_get_by_host_and_topic(context, - migration_ref['dest_compute'], FLAGS.compute_topic) - topic = self.db.queue_get_for(context, FLAGS.compute_topic, - migration_ref['dest_compute']) - rpc.cast(context, topic, - {'method': 'finish_resize', - 'args': { - 'migration_id': migration_id, - 'instance_id': instance_id, - 'disk_info': disk_info, }, - }) + self.db.migration_update(context, + migration_id, + {'status': 'migrating'}) + + disk_info = self.driver.migrate_disk_and_power_off( + instance_ref, migration_ref['dest_host']) + self.db.migration_update(context, + migration_id, + {'status': 'post-migrating'}) + + service = self.db.service_get_by_host_and_topic( + context, migration_ref['dest_compute'], FLAGS.compute_topic) + topic = self.db.queue_get_for(context, + FLAGS.compute_topic, + migration_ref['dest_compute']) + rpc.cast(context, topic, {'method': 'finish_resize', + 'args': {'migration_id': migration_id, + 'instance_id': instance_id, + 'disk_info': disk_info}}) @exception.wrap_exception @checks_instance_lock def finish_resize(self, context, instance_id, migration_id, disk_info): - """Completes the migration process by setting up the newly transferred - disk and turning on the instance on its new host machine""" + """Completes the migration process. + + Sets up the newly transferred disk and turns on the instance at its + new host machine. + + """ migration_ref = self.db.migration_get(context, migration_id) instance_ref = self.db.instance_get(context, migration_ref['instance_id']) @@ -566,7 +571,7 @@ class ComputeManager(manager.SchedulerDependentManager): @exception.wrap_exception @checks_instance_lock def pause_instance(self, context, instance_id): - """Pause an instance on this server.""" + """Pause an instance on this host.""" context = context.elevated() instance_ref = self.db.instance_get(context, instance_id) LOG.audit(_('instance %s: pausing'), instance_id, context=context) @@ -583,7 +588,7 @@ class ComputeManager(manager.SchedulerDependentManager): @exception.wrap_exception @checks_instance_lock def unpause_instance(self, context, instance_id): - """Unpause a paused instance on this server.""" + """Unpause a paused instance on this host.""" context = context.elevated() instance_ref = self.db.instance_get(context, instance_id) LOG.audit(_('instance %s: unpausing'), instance_id, context=context) @@ -599,7 +604,7 @@ class ComputeManager(manager.SchedulerDependentManager): @exception.wrap_exception def get_diagnostics(self, context, instance_id): - """Retrieve diagnostics for an instance on this server.""" + """Retrieve diagnostics for an instance on this host.""" instance_ref = self.db.instance_get(context, instance_id) if instance_ref["state"] == power_state.RUNNING: @@ -610,10 +615,7 @@ class ComputeManager(manager.SchedulerDependentManager): @exception.wrap_exception @checks_instance_lock def suspend_instance(self, context, instance_id): - """ - suspend the instance with instance_id - - """ + """Suspend the given instance.""" context = context.elevated() instance_ref = self.db.instance_get(context, instance_id) LOG.audit(_('instance %s: suspending'), instance_id, context=context) @@ -629,10 +631,7 @@ class ComputeManager(manager.SchedulerDependentManager): @exception.wrap_exception @checks_instance_lock def resume_instance(self, context, instance_id): - """ - resume the suspended instance with instance_id - - """ + """Resume the given suspended instance.""" context = context.elevated() instance_ref = self.db.instance_get(context, instance_id) LOG.audit(_('instance %s: resuming'), instance_id, context=context) @@ -647,10 +646,7 @@ class ComputeManager(manager.SchedulerDependentManager): @exception.wrap_exception def lock_instance(self, context, instance_id): - """ - lock the instance with instance_id - - """ + """Lock the given instance.""" context = context.elevated() LOG.debug(_('instance %s: locking'), instance_id, context=context) @@ -658,10 +654,7 @@ class ComputeManager(manager.SchedulerDependentManager): @exception.wrap_exception def unlock_instance(self, context, instance_id): - """ - unlock the instance with instance_id - - """ + """Unlock the given instance.""" context = context.elevated() LOG.debug(_('instance %s: unlocking'), instance_id, context=context) @@ -669,10 +662,7 @@ class ComputeManager(manager.SchedulerDependentManager): @exception.wrap_exception def get_lock(self, context, instance_id): - """ - return the boolean state of (instance with instance_id)'s lock - - """ + """Return the boolean state of the given instance's lock.""" context = context.elevated() LOG.debug(_('instance %s: getting locked state'), instance_id, context=context) @@ -681,10 +671,7 @@ class ComputeManager(manager.SchedulerDependentManager): @checks_instance_lock def reset_network(self, context, instance_id): - """ - Reset networking on the instance. - - """ + """Reset networking on the given instance.""" context = context.elevated() instance_ref = self.db.instance_get(context, instance_id) LOG.debug(_('instance %s: reset network'), instance_id, @@ -693,10 +680,7 @@ class ComputeManager(manager.SchedulerDependentManager): @checks_instance_lock def inject_network_info(self, context, instance_id): - """ - Inject network info for the instance. - - """ + """Inject network info for the given instance.""" context = context.elevated() instance_ref = self.db.instance_get(context, instance_id) LOG.debug(_('instance %s: inject network info'), instance_id, @@ -705,7 +689,7 @@ class ComputeManager(manager.SchedulerDependentManager): @exception.wrap_exception def get_console_output(self, context, instance_id): - """Send the console output for an instance.""" + """Send the console output for the given instance.""" context = context.elevated() instance_ref = self.db.instance_get(context, instance_id) LOG.audit(_("Get console output for instance %s"), instance_id, @@ -714,20 +698,18 @@ class ComputeManager(manager.SchedulerDependentManager): @exception.wrap_exception def get_ajax_console(self, context, instance_id): - """Return connection information for an ajax console""" + """Return connection information for an ajax console.""" context = context.elevated() LOG.debug(_("instance %s: getting ajax console"), instance_id) instance_ref = self.db.instance_get(context, instance_id) - return self.driver.get_ajax_console(instance_ref) @exception.wrap_exception def get_vnc_console(self, context, instance_id): - """Return connection information for an vnc console.""" + """Return connection information for a vnc console.""" context = context.elevated() LOG.debug(_("instance %s: getting vnc console"), instance_id) instance_ref = self.db.instance_get(context, instance_id) - return self.driver.get_vnc_console(instance_ref) @checks_instance_lock @@ -781,7 +763,7 @@ class ComputeManager(manager.SchedulerDependentManager): @exception.wrap_exception def compare_cpu(self, context, cpu_info): - """Checks the host cpu is compatible to a cpu given by xml. + """Checks that the host cpu is compatible with a cpu given by xml. :param context: security context :param cpu_info: json string obtained from virConnect.getCapabilities @@ -802,7 +784,6 @@ class ComputeManager(manager.SchedulerDependentManager): :returns: tmpfile name(basename) """ - dirpath = FLAGS.instances_path fd, tmp_file = tempfile.mkstemp(dir=dirpath) LOG.debug(_("Creating tmpfile %s to notify to other " @@ -819,7 +800,6 @@ class ComputeManager(manager.SchedulerDependentManager): :param filename: confirm existence of FLAGS.instances_path/thisfile """ - tmp_file = os.path.join(FLAGS.instances_path, filename) if not os.path.exists(tmp_file): raise exception.NotFound(_('%s not found') % tmp_file) @@ -832,7 +812,6 @@ class ComputeManager(manager.SchedulerDependentManager): :param filename: remove existence of FLAGS.instances_path/thisfile """ - tmp_file = os.path.join(FLAGS.instances_path, filename) os.remove(tmp_file) @@ -844,7 +823,6 @@ class ComputeManager(manager.SchedulerDependentManager): :returns: See driver.update_available_resource() """ - return self.driver.update_available_resource(context, self.host) def pre_live_migration(self, context, instance_id, time=None): @@ -854,7 +832,6 @@ class ComputeManager(manager.SchedulerDependentManager): :param instance_id: nova.db.sqlalchemy.models.Instance.Id """ - if not time: time = greenthread @@ -913,7 +890,6 @@ class ComputeManager(manager.SchedulerDependentManager): :param dest: destination host """ - # Get instance for error handling. instance_ref = self.db.instance_get(context, instance_id) i_name = instance_ref.name @@ -1009,12 +985,10 @@ class ComputeManager(manager.SchedulerDependentManager): :param ctxt: security context :param instance_id: nova.db.sqlalchemy.models.Instance.Id - :param host: - DB column value is updated by this hostname. - if none, the host instance currently running is selected. + :param host: DB column value is updated by this hostname. + If none, the host instance currently running is selected. """ - if not host: host = instance_ref['host'] -- cgit From b26f3166554cf5de29fcedee7463bc523786cf72 Mon Sep 17 00:00:00 2001 From: termie Date: Wed, 20 Apr 2011 11:52:19 -0700 Subject: fix typo --- nova/compute/manager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 8103ed61e..fac00e45e 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -396,7 +396,7 @@ class ComputeManager(manager.SchedulerDependentManager): 'rescuing') self.network_manager.setup_compute_network(context, instance_id) _update_state = lambda result: self._update_state_callback( - self, context, instance_id, result)) + self, context, instance_id, result) self.driver.rescue(instance_ref, _update_state) self._update_state(context, instance_id) @@ -412,7 +412,7 @@ class ComputeManager(manager.SchedulerDependentManager): power_state.NOSTATE, 'unrescuing') _update_state = lambda result: self._update_state_callback( - self, context, instance_id, result)) + self, context, instance_id, result) self.driver.unrescue(instance_ref, _update_state) self._update_state(context, instance_id) -- cgit From 98b8a800b16a1e6699b1d4c7ce0e4ab61319be6e Mon Sep 17 00:00:00 2001 From: termie Date: Wed, 20 Apr 2011 12:00:21 -0700 Subject: docstring cleanup, nova/db dir --- nova/db/api.py | 61 +++++++++++++++++++++++++++------------------------- nova/db/base.py | 8 +++---- nova/db/migration.py | 2 ++ 3 files changed, 38 insertions(+), 33 deletions(-) diff --git a/nova/db/api.py b/nova/db/api.py index 63901e94d..1b33d8932 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -15,8 +15,8 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. -""" -Defines interface for DB access. + +"""Defines interface for DB access. The underlying driver is loaded as a :class:`LazyPluggable`. @@ -30,6 +30,7 @@ The underlying driver is loaded as a :class:`LazyPluggable`. :enable_new_services: when adding a new service to the database, is it in the pool of available hardware (Default: True) + """ from nova import exception @@ -86,7 +87,7 @@ def service_get(context, service_id): def service_get_by_host_and_topic(context, host, topic): - """Get a service by host it's on and topic it listens to""" + """Get a service by host it's on and topic it listens to.""" return IMPL.service_get_by_host_and_topic(context, host, topic) @@ -113,7 +114,7 @@ def service_get_all_compute_by_host(context, host): def service_get_all_compute_sorted(context): """Get all compute services sorted by instance count. - Returns a list of (Service, instance_count) tuples. + :returns: a list of (Service, instance_count) tuples. """ return IMPL.service_get_all_compute_sorted(context) @@ -122,7 +123,7 @@ def service_get_all_compute_sorted(context): def service_get_all_network_sorted(context): """Get all network services sorted by network count. - Returns a list of (Service, network_count) tuples. + :returns: a list of (Service, network_count) tuples. """ return IMPL.service_get_all_network_sorted(context) @@ -131,7 +132,7 @@ def service_get_all_network_sorted(context): def service_get_all_volume_sorted(context): """Get all volume services sorted by volume count. - Returns a list of (Service, volume_count) tuples. + :returns: a list of (Service, volume_count) tuples. """ return IMPL.service_get_all_volume_sorted(context) @@ -241,7 +242,7 @@ def floating_ip_count_by_project(context, project_id): def floating_ip_deallocate(context, address): - """Deallocate an floating ip by address""" + """Deallocate an floating ip by address.""" return IMPL.floating_ip_deallocate(context, address) @@ -253,7 +254,7 @@ def floating_ip_destroy(context, address): def floating_ip_disassociate(context, address): """Disassociate an floating ip from a fixed ip by address. - Returns the address of the existing fixed ip. + :returns: the address of the existing fixed ip. """ return IMPL.floating_ip_disassociate(context, address) @@ -294,22 +295,22 @@ def floating_ip_update(context, address, values): #################### def migration_update(context, id, values): - """Update a migration instance""" + """Update a migration instance.""" return IMPL.migration_update(context, id, values) def migration_create(context, values): - """Create a migration record""" + """Create a migration record.""" return IMPL.migration_create(context, values) def migration_get(context, migration_id): - """Finds a migration by the id""" + """Finds a migration by the id.""" return IMPL.migration_get(context, migration_id) def migration_get_by_instance_and_status(context, instance_id, status): - """Finds a migration by the instance id its migrating""" + """Finds a migration by the instance id its migrating.""" return IMPL.migration_get_by_instance_and_status(context, instance_id, status) @@ -579,7 +580,9 @@ def network_create_safe(context, values): def network_delete_safe(context, network_id): """Delete network with key network_id. + This method assumes that the network is not associated with any project + """ return IMPL.network_delete_safe(context, network_id) @@ -674,7 +677,6 @@ def project_get_network(context, project_id, associate=True): network if one is not found, otherwise it returns None. """ - return IMPL.project_get_network(context, project_id, associate) @@ -722,7 +724,9 @@ def iscsi_target_create_safe(context, values): The device is not returned. If the create violates the unique constraints because the iscsi_target and host already exist, - no exception is raised.""" + no exception is raised. + + """ return IMPL.iscsi_target_create_safe(context, values) @@ -1050,10 +1054,7 @@ def project_delete(context, project_id): def host_get_networks(context, host): - """Return all networks for which the given host is the designated - network host. - - """ + """All networks for which the given host is the network host.""" return IMPL.host_get_networks(context, host) @@ -1115,38 +1116,40 @@ def console_get(context, console_id, instance_id=None): def instance_type_create(context, values): - """Create a new instance type""" + """Create a new instance type.""" return IMPL.instance_type_create(context, values) def instance_type_get_all(context, inactive=False): - """Get all instance types""" + """Get all instance types.""" return IMPL.instance_type_get_all(context, inactive) def instance_type_get_by_id(context, id): - """Get instance type by id""" + """Get instance type by id.""" return IMPL.instance_type_get_by_id(context, id) def instance_type_get_by_name(context, name): - """Get instance type by name""" + """Get instance type by name.""" return IMPL.instance_type_get_by_name(context, name) def instance_type_get_by_flavor_id(context, id): - """Get instance type by name""" + """Get instance type by name.""" return IMPL.instance_type_get_by_flavor_id(context, id) def instance_type_destroy(context, name): - """Delete a instance type""" + """Delete a instance type.""" return IMPL.instance_type_destroy(context, name) def instance_type_purge(context, name): - """Purges (removes) an instance type from DB - Use instance_type_destroy for most cases + """Purges (removes) an instance type from DB. + + Use instance_type_destroy for most cases + """ return IMPL.instance_type_purge(context, name) @@ -1183,15 +1186,15 @@ def zone_get_all(context): def instance_metadata_get(context, instance_id): - """Get all metadata for an instance""" + """Get all metadata for an instance.""" return IMPL.instance_metadata_get(context, instance_id) def instance_metadata_delete(context, instance_id, key): - """Delete the given metadata item""" + """Delete the given metadata item.""" IMPL.instance_metadata_delete(context, instance_id, key) def instance_metadata_update_or_create(context, instance_id, metadata): - """Create or update instance metadata""" + """Create or update instance metadata.""" IMPL.instance_metadata_update_or_create(context, instance_id, metadata) diff --git a/nova/db/base.py b/nova/db/base.py index a0f2180c6..a0d055d5b 100644 --- a/nova/db/base.py +++ b/nova/db/base.py @@ -16,20 +16,20 @@ # License for the specific language governing permissions and limitations # under the License. -""" -Base class for classes that need modular database access. -""" +"""Base class for classes that need modular database access.""" from nova import utils from nova import flags + FLAGS = flags.FLAGS flags.DEFINE_string('db_driver', 'nova.db.api', 'driver to use for database access') class Base(object): - """DB driver is injected in the init method""" + """DB driver is injected in the init method.""" + def __init__(self, db_driver=None): if not db_driver: db_driver = FLAGS.db_driver diff --git a/nova/db/migration.py b/nova/db/migration.py index e54b90cd8..ccd06cffe 100644 --- a/nova/db/migration.py +++ b/nova/db/migration.py @@ -15,11 +15,13 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. + """Database setup and migration commands.""" from nova import flags from nova import utils + FLAGS = flags.FLAGS flags.DECLARE('db_backend', 'nova.db.api') -- cgit From 04fd29085c6ed5fe72378b061b1d7659f110c924 Mon Sep 17 00:00:00 2001 From: termie Date: Wed, 20 Apr 2011 12:06:10 -0700 Subject: docstring cleanup, console --- nova/console/api.py | 23 ++++++-------- nova/console/fake.py | 22 ++++++-------- nova/console/manager.py | 17 ++++++----- nova/console/vmrc.py | 48 ++++++++++++++--------------- nova/console/vmrc_manager.py | 72 ++++++++++++++++++++------------------------ nova/console/xvp.py | 48 +++++++++++++++-------------- 6 files changed, 108 insertions(+), 122 deletions(-) diff --git a/nova/console/api.py b/nova/console/api.py index 3850d2c44..137ddcaac 100644 --- a/nova/console/api.py +++ b/nova/console/api.py @@ -15,23 +15,19 @@ # License for the specific language governing permissions and limitations # under the License. -""" -Handles ConsoleProxy API requests -""" +"""Handles ConsoleProxy API requests.""" from nova import exception -from nova.db import base - - from nova import flags from nova import rpc +from nova.db import base FLAGS = flags.FLAGS class API(base.Base): - """API for spining up or down console proxy connections""" + """API for spinning up or down console proxy connections.""" def __init__(self, **kwargs): super(API, self).__init__(**kwargs) @@ -51,8 +47,8 @@ class API(base.Base): self.db.queue_get_for(context, FLAGS.console_topic, pool['host']), - {"method": "remove_console", - "args": {"console_id": console['id']}}) + {'method': 'remove_console', + 'args': {'console_id': console['id']}}) def create_console(self, context, instance_id): instance = self.db.instance_get(context, instance_id) @@ -63,13 +59,12 @@ class API(base.Base): # here. rpc.cast(context, self._get_console_topic(context, instance['host']), - {"method": "add_console", - "args": {"instance_id": instance_id}}) + {'method': 'add_console', + 'args': {'instance_id': instance_id}}) def _get_console_topic(self, context, instance_host): topic = self.db.queue_get_for(context, FLAGS.compute_topic, instance_host) - return rpc.call(context, - topic, - {"method": "get_console_topic", "args": {'fake': 1}}) + return rpc.call(context, topic, {'method': 'get_console_topic', + 'args': {'fake': 1}}) diff --git a/nova/console/fake.py b/nova/console/fake.py index 7a90d5221..e2eb886f8 100644 --- a/nova/console/fake.py +++ b/nova/console/fake.py @@ -15,9 +15,7 @@ # License for the specific language governing permissions and limitations # under the License. -""" -Fake ConsoleProxy driver for tests. -""" +"""Fake ConsoleProxy driver for tests.""" from nova import exception @@ -27,32 +25,32 @@ class FakeConsoleProxy(object): @property def console_type(self): - return "fake" + return 'fake' def setup_console(self, context, console): - """Sets up actual proxies""" + """Sets up actual proxies.""" pass def teardown_console(self, context, console): - """Tears down actual proxies""" + """Tears down actual proxies.""" pass def init_host(self): - """Start up any config'ed consoles on start""" + """Start up any config'ed consoles on start.""" pass def generate_password(self, length=8): - """Returns random console password""" - return "fakepass" + """Returns random console password.""" + return 'fakepass' def get_port(self, context): - """get available port for consoles that need one""" + """Get available port for consoles that need one.""" return 5999 def fix_pool_password(self, password): - """Trim password to length, and any other massaging""" + """Trim password to length, and any other massaging.""" return password def fix_console_password(self, password): - """Trim password to length, and any other massaging""" + """Trim password to length, and any other massaging.""" return password diff --git a/nova/console/manager.py b/nova/console/manager.py index bfa571ea9..e0db21666 100644 --- a/nova/console/manager.py +++ b/nova/console/manager.py @@ -15,9 +15,7 @@ # License for the specific language governing permissions and limitations # under the License. -""" -Console Proxy Service -""" +"""Console Proxy Service.""" import functools import socket @@ -29,6 +27,7 @@ from nova import manager from nova import rpc from nova import utils + FLAGS = flags.FLAGS flags.DEFINE_string('console_driver', 'nova.console.xvp.XVPConsoleProxy', @@ -41,9 +40,11 @@ flags.DEFINE_string('console_public_hostname', class ConsoleProxyManager(manager.Manager): + """Sets up and tears down any console proxy connections. + + Needed for accessing instance consoles securely. - """ Sets up and tears down any proxy connections needed for accessing - instance consoles securely""" + """ def __init__(self, console_driver=None, *args, **kwargs): if not console_driver: @@ -67,7 +68,7 @@ class ConsoleProxyManager(manager.Manager): pool['id'], instance_id) except exception.NotFound: - logging.debug(_("Adding console")) + logging.debug(_('Adding console')) if not password: password = utils.generate_password(8) if not port: @@ -115,8 +116,8 @@ class ConsoleProxyManager(manager.Manager): self.db.queue_get_for(context, FLAGS.compute_topic, instance_host), - {"method": "get_console_pool_info", - "args": {"console_type": console_type}}) + {'method': 'get_console_pool_info', + 'args': {'console_type': console_type}}) pool_info['password'] = self.driver.fix_pool_password( pool_info['password']) pool_info['host'] = self.host diff --git a/nova/console/vmrc.py b/nova/console/vmrc.py index 521da289f..127d31121 100644 --- a/nova/console/vmrc.py +++ b/nova/console/vmrc.py @@ -15,9 +15,7 @@ # License for the specific language governing permissions and limitations # under the License. -""" -VMRC console drivers. -""" +"""VMRC console drivers.""" import base64 import json @@ -27,6 +25,8 @@ from nova import flags from nova import log as logging from nova.virt.vmwareapi import vim_util + +FLAGS = flags.FLAGS flags.DEFINE_integer('console_vmrc_port', 443, "port for VMware VMRC connections") @@ -34,8 +34,6 @@ flags.DEFINE_integer('console_vmrc_error_retries', 10, "number of retries for retrieving VMRC information") -FLAGS = flags.FLAGS - class VMRCConsole(object): """VMRC console driver with ESX credentials.""" @@ -69,34 +67,34 @@ class VMRCConsole(object): return password def generate_password(self, vim_session, pool, instance_name): - """ - Returns VMRC Connection credentials. + """Returns VMRC Connection credentials. Return string is of the form ':@'. + """ username, password = pool['username'], pool['password'] - vms = vim_session._call_method(vim_util, "get_objects", - "VirtualMachine", ["name", "config.files.vmPathName"]) + vms = vim_session._call_method(vim_util, 'get_objects', + 'VirtualMachine', ['name', 'config.files.vmPathName']) vm_ds_path_name = None vm_ref = None for vm in vms: vm_name = None ds_path_name = None for prop in vm.propSet: - if prop.name == "name": + if prop.name == 'name': vm_name = prop.val - elif prop.name == "config.files.vmPathName": + elif prop.name == 'config.files.vmPathName': ds_path_name = prop.val if vm_name == instance_name: vm_ref = vm.obj vm_ds_path_name = ds_path_name break if vm_ref is None: - raise exception.NotFound(_("instance - %s not present") % + raise exception.NotFound(_('instance - %s not present') % instance_name) - json_data = json.dumps({"vm_id": vm_ds_path_name, - "username": username, - "password": password}) + json_data = json.dumps({'vm_id': vm_ds_path_name, + 'username': username, + 'password': password}) return base64.b64encode(json_data) def is_otp(self): @@ -115,28 +113,28 @@ class VMRCSessionConsole(VMRCConsole): return 'vmrc+session' def generate_password(self, vim_session, pool, instance_name): - """ - Returns a VMRC Session. + """Returns a VMRC Session. Return string is of the form ':'. + """ - vms = vim_session._call_method(vim_util, "get_objects", - "VirtualMachine", ["name"]) - vm_ref = None + vms = vim_session._call_method(vim_util, 'get_objects', + 'VirtualMachine', ['name']) + vm_ref = NoneV for vm in vms: if vm.propSet[0].val == instance_name: vm_ref = vm.obj if vm_ref is None: - raise exception.NotFound(_("instance - %s not present") % + raise exception.NotFound(_('instance - %s not present') % instance_name) virtual_machine_ticket = \ vim_session._call_method( vim_session._get_vim(), - "AcquireCloneTicket", + 'AcquireCloneTicket', vim_session._get_vim().get_service_content().sessionManager) - json_data = json.dumps({"vm_id": str(vm_ref.value), - "username": virtual_machine_ticket, - "password": virtual_machine_ticket}) + json_data = json.dumps({'vm_id': str(vm_ref.value), + 'username': virtual_machine_ticket, + 'password': virtual_machine_ticket}) return base64.b64encode(json_data) def is_otp(self): diff --git a/nova/console/vmrc_manager.py b/nova/console/vmrc_manager.py index 09beac7a0..3c6b77782 100644 --- a/nova/console/vmrc_manager.py +++ b/nova/console/vmrc_manager.py @@ -15,9 +15,7 @@ # License for the specific language governing permissions and limitations # under the License. -""" -VMRC Console Manager. -""" +"""VMRC Console Manager.""" from nova import exception from nova import flags @@ -25,24 +23,21 @@ from nova import log as logging from nova import manager from nova import rpc from nova import utils -from nova.virt.vmwareapi_conn import VMWareAPISession +from nova.virt import vmwareapi_conn + LOG = logging.getLogger("nova.console.vmrc_manager") + FLAGS = flags.FLAGS -flags.DEFINE_string('console_public_hostname', - '', +flags.DEFINE_string('console_public_hostname', '', 'Publicly visible name for this console host') -flags.DEFINE_string('console_driver', - 'nova.console.vmrc.VMRCConsole', +flags.DEFINE_string('console_driver', 'nova.console.vmrc.VMRCConsole', 'Driver to use for the console') class ConsoleVMRCManager(manager.Manager): - - """ - Manager to handle VMRC connections needed for accessing instance consoles. - """ + """Manager to handle VMRC connections for accessing instance consoles.""" def __init__(self, console_driver=None, *args, **kwargs): self.driver = utils.import_object(FLAGS.console_driver) @@ -56,7 +51,7 @@ class ConsoleVMRCManager(manager.Manager): """Get VIM session for the pool specified.""" vim_session = None if pool['id'] not in self.sessions.keys(): - vim_session = VMWareAPISession(pool['address'], + vim_session = vmwareapi_conn.VMWareAPISession(pool['address'], pool['username'], pool['password'], FLAGS.console_vmrc_error_retries) @@ -65,7 +60,7 @@ class ConsoleVMRCManager(manager.Manager): def _generate_console(self, context, pool, name, instance_id, instance): """Sets up console for the instance.""" - LOG.debug(_("Adding console")) + LOG.debug(_('Adding console')) password = self.driver.generate_password( self._get_vim_session(pool), @@ -84,9 +79,10 @@ class ConsoleVMRCManager(manager.Manager): @exception.wrap_exception def add_console(self, context, instance_id, password=None, port=None, **kwargs): - """ - Adds a console for the instance. If it is one time password, then we - generate new console credentials. + """Adds a console for the instance. + + If it is one time password, then we generate new console credentials. + """ instance = self.db.instance_get(context, instance_id) host = instance['host'] @@ -97,19 +93,17 @@ class ConsoleVMRCManager(manager.Manager): pool['id'], instance_id) if self.driver.is_otp(): - console = self._generate_console( - context, - pool, - name, - instance_id, - instance) + console = self._generate_console(context, + pool, + name, + instance_id, + instance) except exception.NotFound: - console = self._generate_console( - context, - pool, - name, - instance_id, - instance) + console = self._generate_console(context, + pool, + name, + instance_id, + instance) return console['id'] @exception.wrap_exception @@ -118,13 +112,11 @@ class ConsoleVMRCManager(manager.Manager): try: console = self.db.console_get(context, console_id) except exception.NotFound: - LOG.debug(_("Tried to remove non-existent console " - "%(console_id)s.") % - {'console_id': console_id}) + LOG.debug(_('Tried to remove non-existent console ' + '%(console_id)s.') % {'console_id': console_id}) return - LOG.debug(_("Removing console " - "%(console_id)s.") % - {'console_id': console_id}) + LOG.debug(_('Removing console ' + '%(console_id)s.') % {'console_id': console_id}) self.db.console_delete(context, console_id) self.driver.teardown_console(context, console) @@ -139,11 +131,11 @@ class ConsoleVMRCManager(manager.Manager): console_type) except exception.NotFound: pool_info = rpc.call(context, - self.db.queue_get_for(context, - FLAGS.compute_topic, - instance_host), - {"method": "get_console_pool_info", - "args": {"console_type": console_type}}) + self.db.queue_get_for(context, + FLAGS.compute_topic, + instance_host), + {'method': 'get_console_pool_info', + 'args': {'console_type': console_type}}) pool_info['password'] = self.driver.fix_pool_password( pool_info['password']) pool_info['host'] = self.host diff --git a/nova/console/xvp.py b/nova/console/xvp.py index 0cedfbb13..3cd287183 100644 --- a/nova/console/xvp.py +++ b/nova/console/xvp.py @@ -15,16 +15,14 @@ # License for the specific language governing permissions and limitations # under the License. -""" -XVP (Xenserver VNC Proxy) driver. -""" +"""XVP (Xenserver VNC Proxy) driver.""" import fcntl import os import signal import subprocess -from Cheetah.Template import Template +from Cheetah import Template from nova import context from nova import db @@ -33,6 +31,8 @@ from nova import flags from nova import log as logging from nova import utils + +FLAGS = flags.FLAGS flags.DEFINE_string('console_xvp_conf_template', utils.abspath('console/xvp.conf.template'), 'XVP conf template') @@ -47,12 +47,11 @@ flags.DEFINE_string('console_xvp_log', 'XVP log file') flags.DEFINE_integer('console_xvp_multiplex_port', 5900, - "port for XVP to multiplex VNC connections on") -FLAGS = flags.FLAGS + 'port for XVP to multiplex VNC connections on') class XVPConsoleProxy(object): - """Sets up XVP config, and manages xvp daemon""" + """Sets up XVP config, and manages XVP daemon.""" def __init__(self): self.xvpconf_template = open(FLAGS.console_xvp_conf_template).read() @@ -61,50 +60,51 @@ class XVPConsoleProxy(object): @property def console_type(self): - return "vnc+xvp" + return 'vnc+xvp' def get_port(self, context): - """get available port for consoles that need one""" + """Get available port for consoles that need one.""" #TODO(mdragon): implement port selection for non multiplex ports, # we are not using that, but someone else may want # it. return FLAGS.console_xvp_multiplex_port def setup_console(self, context, console): - """Sets up actual proxies""" + """Sets up actual proxies.""" self._rebuild_xvp_conf(context.elevated()) def teardown_console(self, context, console): - """Tears down actual proxies""" + """Tears down actual proxies.""" self._rebuild_xvp_conf(context.elevated()) def init_host(self): - """Start up any config'ed consoles on start""" + """Start up any config'ed consoles on start.""" ctxt = context.get_admin_context() self._rebuild_xvp_conf(ctxt) def fix_pool_password(self, password): - """Trim password to length, and encode""" + """Trim password to length, and encode.""" return self._xvp_encrypt(password, is_pool_password=True) def fix_console_password(self, password): - """Trim password to length, and encode""" + """Trim password to length, and encode.""" return self._xvp_encrypt(password) def _rebuild_xvp_conf(self, context): - logging.debug(_("Rebuilding xvp conf")) + logging.debug(_('Rebuilding xvp conf')) pools = [pool for pool in db.console_pool_get_all_by_host_type(context, self.host, self.console_type) if pool['consoles']] if not pools: - logging.debug("No console pools!") + logging.debug('No console pools!') self._xvp_stop() return conf_data = {'multiplex_port': FLAGS.console_xvp_multiplex_port, 'pools': pools, 'pass_encode': self.fix_console_password} - config = str(Template(self.xvpconf_template, searchList=[conf_data])) + config = str(Template.Template(self.xvpconf_template, + searchList=[conf_data])) self._write_conf(config) self._xvp_restart() @@ -114,7 +114,7 @@ class XVPConsoleProxy(object): cfile.write(config) def _xvp_stop(self): - logging.debug(_("Stopping xvp")) + logging.debug(_('Stopping xvp')) pid = self._xvp_pid() if not pid: return @@ -127,19 +127,19 @@ class XVPConsoleProxy(object): def _xvp_start(self): if self._xvp_check_running(): return - logging.debug(_("Starting xvp")) + logging.debug(_('Starting xvp')) try: utils.execute('xvp', '-p', FLAGS.console_xvp_pid, '-c', FLAGS.console_xvp_conf, '-l', FLAGS.console_xvp_log) except exception.ProcessExecutionError, err: - logging.error(_("Error starting xvp: %s") % err) + logging.error(_('Error starting xvp: %s') % err) def _xvp_restart(self): - logging.debug(_("Restarting xvp")) + logging.debug(_('Restarting xvp')) if not self._xvp_check_running(): - logging.debug(_("xvp not running...")) + logging.debug(_('xvp not running...')) self._xvp_start() else: pid = self._xvp_pid() @@ -178,7 +178,9 @@ class XVPConsoleProxy(object): Note that xvp's obfuscation should not be considered 'real' encryption. It simply DES encrypts the passwords with static keys plainly viewable - in the xvp source code.""" + in the xvp source code. + + """ maxlen = 8 flag = '-e' if is_pool_password: -- cgit From 740547fcb1aa02c31a362d1be2d4a27b3799e36a Mon Sep 17 00:00:00 2001 From: termie Date: Wed, 20 Apr 2011 12:06:10 -0700 Subject: fixed indentation --- nova/console/vmrc_manager.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/nova/console/vmrc_manager.py b/nova/console/vmrc_manager.py index 3c6b77782..acecc1075 100644 --- a/nova/console/vmrc_manager.py +++ b/nova/console/vmrc_manager.py @@ -51,10 +51,11 @@ class ConsoleVMRCManager(manager.Manager): """Get VIM session for the pool specified.""" vim_session = None if pool['id'] not in self.sessions.keys(): - vim_session = vmwareapi_conn.VMWareAPISession(pool['address'], - pool['username'], - pool['password'], - FLAGS.console_vmrc_error_retries) + vim_session = vmwareapi_conn.VMWareAPISession( + pool['address'], + pool['username'], + pool['password'], + FLAGS.console_vmrc_error_retries) self.sessions[pool['id']] = vim_session return self.sessions[pool['id']] -- cgit From f69600e1844898bd48dc8f615c6684044d9aebe0 Mon Sep 17 00:00:00 2001 From: termie Date: Wed, 20 Apr 2011 12:08:22 -0700 Subject: docstring cleanup, nova dir --- nova/context.py | 10 +++- nova/crypto.py | 61 +++++++++++---------- nova/exception.py | 25 +++++---- nova/fakememcache.py | 4 +- nova/flags.py | 16 ++++-- nova/log.py | 49 ++++++++--------- nova/manager.py | 34 ++++++++---- nova/quota.py | 23 ++++---- nova/rpc.py | 152 +++++++++++++++++++++++++++++---------------------- nova/service.py | 83 +++++++++++++--------------- nova/test.py | 50 +++++++++-------- nova/utils.py | 147 ++++++++++++++++++++++++------------------------- nova/version.py | 6 +- nova/wsgi.py | 144 ++++++++++++++++++++++++------------------------ 14 files changed, 422 insertions(+), 382 deletions(-) diff --git a/nova/context.py b/nova/context.py index 0256bf448..c113f7ea7 100644 --- a/nova/context.py +++ b/nova/context.py @@ -16,9 +16,7 @@ # License for the specific language governing permissions and limitations # under the License. -""" -RequestContext: context for requests that persist through all of nova. -""" +"""RequestContext: context for requests that persist through all of nova.""" import datetime import random @@ -28,6 +26,12 @@ from nova import utils class RequestContext(object): + """Security context and request information. + + Represents the user taking a given action within the system. + + """ + def __init__(self, user, project, is_admin=None, read_deleted=False, remote_address=None, timestamp=None, request_id=None): if hasattr(user, 'id'): diff --git a/nova/crypto.py b/nova/crypto.py index 605be2a32..14b9cbef6 100644 --- a/nova/crypto.py +++ b/nova/crypto.py @@ -15,10 +15,11 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. -""" -Wrappers around standard crypto data elements. + +"""Wrappers around standard crypto data elements. Includes root and intermediate CAs, SSH key_pairs and x509 certificates. + """ import base64 @@ -43,6 +44,8 @@ from nova import log as logging LOG = logging.getLogger("nova.crypto") + + FLAGS = flags.FLAGS flags.DEFINE_string('ca_file', 'cacert.pem', _('Filename of root CA')) flags.DEFINE_string('key_file', @@ -90,13 +93,13 @@ def key_path(project_id=None): def fetch_ca(project_id=None, chain=True): if not FLAGS.use_project_ca: project_id = None - buffer = "" + buffer = '' if project_id: - with open(ca_path(project_id), "r") as cafile: + with open(ca_path(project_id), 'r') as cafile: buffer += cafile.read() if not chain: return buffer - with open(ca_path(None), "r") as cafile: + with open(ca_path(None), 'r') as cafile: buffer += cafile.read() return buffer @@ -143,7 +146,7 @@ def ssl_pub_to_ssh_pub(ssl_public_key, name='root', suffix='nova'): def revoke_cert(project_id, file_name): - """Revoke a cert by file name""" + """Revoke a cert by file name.""" start = os.getcwd() os.chdir(ca_folder(project_id)) # NOTE(vish): potential race condition here @@ -155,14 +158,14 @@ def revoke_cert(project_id, file_name): def revoke_certs_by_user(user_id): - """Revoke all user certs""" + """Revoke all user certs.""" admin = context.get_admin_context() for cert in db.certificate_get_all_by_user(admin, user_id): revoke_cert(cert['project_id'], cert['file_name']) def revoke_certs_by_project(project_id): - """Revoke all project certs""" + """Revoke all project certs.""" # NOTE(vish): This is somewhat useless because we can just shut down # the vpn. admin = context.get_admin_context() @@ -171,29 +174,29 @@ def revoke_certs_by_project(project_id): def revoke_certs_by_user_and_project(user_id, project_id): - """Revoke certs for user in project""" + """Revoke certs for user in project.""" admin = context.get_admin_context() for cert in db.certificate_get_all_by_user(admin, user_id, project_id): revoke_cert(cert['project_id'], cert['file_name']) def _project_cert_subject(project_id): - """Helper to generate user cert subject""" + """Helper to generate user cert subject.""" return FLAGS.project_cert_subject % (project_id, utils.isotime()) def _vpn_cert_subject(project_id): - """Helper to generate user cert subject""" + """Helper to generate user cert subject.""" return FLAGS.vpn_cert_subject % (project_id, utils.isotime()) def _user_cert_subject(user_id, project_id): - """Helper to generate user cert subject""" + """Helper to generate user cert subject.""" return FLAGS.user_cert_subject % (project_id, user_id, utils.isotime()) def generate_x509_cert(user_id, project_id, bits=1024): - """Generate and sign a cert for user in project""" + """Generate and sign a cert for user in project.""" subject = _user_cert_subject(user_id, project_id) tmpdir = tempfile.mkdtemp() keyfile = os.path.abspath(os.path.join(tmpdir, 'temp.key')) @@ -205,7 +208,7 @@ def generate_x509_cert(user_id, project_id, bits=1024): csr = open(csrfile).read() shutil.rmtree(tmpdir) (serial, signed_csr) = sign_csr(csr, project_id) - fname = os.path.join(ca_folder(project_id), "newcerts/%s.pem" % serial) + fname = os.path.join(ca_folder(project_id), 'newcerts/%s.pem' % serial) cert = {'user_id': user_id, 'project_id': project_id, 'file_name': fname} @@ -227,8 +230,8 @@ def _ensure_project_folder(project_id): def generate_vpn_files(project_id): project_folder = ca_folder(project_id) - csr_fn = os.path.join(project_folder, "server.csr") - crt_fn = os.path.join(project_folder, "server.crt") + csr_fn = os.path.join(project_folder, 'server.csr') + crt_fn = os.path.join(project_folder, 'server.crt') genvpn_sh_path = os.path.join(os.path.dirname(__file__), 'CA', @@ -241,10 +244,10 @@ def generate_vpn_files(project_id): # TODO(vish): the shell scripts could all be done in python utils.execute('sh', genvpn_sh_path, project_id, _vpn_cert_subject(project_id)) - with open(csr_fn, "r") as csrfile: + with open(csr_fn, 'r') as csrfile: csr_text = csrfile.read() (serial, signed_csr) = sign_csr(csr_text, project_id) - with open(crt_fn, "w") as crtfile: + with open(crt_fn, 'w') as crtfile: crtfile.write(signed_csr) os.chdir(start) @@ -261,12 +264,12 @@ def sign_csr(csr_text, project_id=None): def _sign_csr(csr_text, ca_folder): tmpfolder = tempfile.mkdtemp() - inbound = os.path.join(tmpfolder, "inbound.csr") - outbound = os.path.join(tmpfolder, "outbound.csr") - csrfile = open(inbound, "w") + inbound = os.path.join(tmpfolder, 'inbound.csr') + outbound = os.path.join(tmpfolder, 'outbound.csr') + csrfile = open(inbound, 'w') csrfile.write(csr_text) csrfile.close() - LOG.debug(_("Flags path: %s"), ca_folder) + LOG.debug(_('Flags path: %s'), ca_folder) start = os.getcwd() # Change working dir to CA if not os.path.exists(ca_folder): @@ -276,13 +279,13 @@ def _sign_csr(csr_text, ca_folder): './openssl.cnf', '-infiles', inbound) out, _err = utils.execute('openssl', 'x509', '-in', outbound, '-serial', '-noout') - serial = string.strip(out.rpartition("=")[2]) + serial = string.strip(out.rpartition('=')[2]) os.chdir(start) - with open(outbound, "r") as crtfile: + with open(outbound, 'r') as crtfile: return (serial, crtfile.read()) -def mkreq(bits, subject="foo", ca=0): +def mkreq(bits, subject='foo', ca=0): pk = M2Crypto.EVP.PKey() req = M2Crypto.X509.Request() rsa = M2Crypto.RSA.gen_key(bits, 65537, callback=lambda: None) @@ -314,7 +317,7 @@ def mkcacert(subject='nova', years=1): cert.set_not_before(now) cert.set_not_after(nowPlusYear) issuer = M2Crypto.X509.X509_Name() - issuer.C = "US" + issuer.C = 'US' issuer.CN = subject cert.set_issuer(issuer) cert.set_pubkey(pkey) @@ -352,13 +355,15 @@ def mkcacert(subject='nova', years=1): # http://code.google.com/p/boto def compute_md5(fp): - """ + """Compute an md5 hash. + :type fp: file :param fp: File pointer to the file to MD5 hash. The file pointer will be reset to the beginning of the file before the method returns. :rtype: tuple - :return: the hex digest version of the MD5 hash + :returns: the hex digest version of the MD5 hash + """ m = hashlib.md5() fp.seek(0) diff --git a/nova/exception.py b/nova/exception.py index 4e2bbdbaf..3123b2f1f 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -16,31 +16,34 @@ # License for the specific language governing permissions and limitations # under the License. -""" -Nova base exception handling, including decorator for re-raising -Nova-type exceptions. SHOULD include dedicated exception logging. +"""Nova base exception handling. + +Includes decorator for re-raising Nova-type exceptions. + +SHOULD include dedicated exception logging. + """ from nova import log as logging + + LOG = logging.getLogger('nova.exception') class ProcessExecutionError(IOError): - def __init__(self, stdout=None, stderr=None, exit_code=None, cmd=None, description=None): if description is None: - description = _("Unexpected error while running command.") + description = _('Unexpected error while running command.') if exit_code is None: exit_code = '-' - message = _("%(description)s\nCommand: %(cmd)s\n" - "Exit code: %(exit_code)s\nStdout: %(stdout)r\n" - "Stderr: %(stderr)r") % locals() + message = _('%(description)s\nCommand: %(cmd)s\n' + 'Exit code: %(exit_code)s\nStdout: %(stdout)r\n' + 'Stderr: %(stderr)r') % locals() IOError.__init__(self, message) class Error(Exception): - def __init__(self, message=None): super(Error, self).__init__(message) @@ -97,7 +100,7 @@ class TimeoutException(Error): class DBError(Error): - """Wraps an implementation specific exception""" + """Wraps an implementation specific exception.""" def __init__(self, inner_exception): self.inner_exception = inner_exception super(DBError, self).__init__(str(inner_exception)) @@ -108,7 +111,7 @@ def wrap_db_error(f): try: return f(*args, **kwargs) except Exception, e: - LOG.exception(_('DB exception wrapped')) + LOG.exception(_('DB exception wrapped.')) raise DBError(e) return _wrap _wrap.func_name = f.func_name diff --git a/nova/fakememcache.py b/nova/fakememcache.py index 67f46dbdc..e4f238aa9 100644 --- a/nova/fakememcache.py +++ b/nova/fakememcache.py @@ -18,14 +18,14 @@ """Super simple fake memcache client.""" -import utils +from nova import utils class Client(object): """Replicates a tiny subset of memcached client interface.""" def __init__(self, *args, **kwargs): - """Ignores the passed in args""" + """Ignores the passed in args.""" self.cache = {} def get(self, key): diff --git a/nova/flags.py b/nova/flags.py index f011ab383..d1b93f0a8 100644 --- a/nova/flags.py +++ b/nova/flags.py @@ -16,9 +16,13 @@ # License for the specific language governing permissions and limitations # under the License. -""" +"""Command-line flag library. + +Wraps gflags. + Package-level global flags are defined here, the rest are defined where they're used. + """ import getopt @@ -145,10 +149,12 @@ class FlagValues(gflags.FlagValues): class StrWrapper(object): - """Wrapper around FlagValues objects + """Wrapper around FlagValues objects. Wraps FlagValues objects for string.Template so that we're - sure to return strings.""" + sure to return strings. + + """ def __init__(self, context_objs): self.context_objs = context_objs @@ -169,6 +175,7 @@ def _GetCallingModule(): We generally use this function to get the name of the module calling a DEFINE_foo... function. + """ # Walk down the stack to find the first globals dict that's not ours. for depth in range(1, sys.getrecursionlimit()): @@ -192,6 +199,7 @@ def __GetModuleName(globals_dict): Returns: A string (the name of the module) or None (if the module could not be identified. + """ for name, module in sys.modules.iteritems(): if getattr(module, '__dict__', None) is globals_dict: @@ -326,7 +334,7 @@ DEFINE_integer('auth_token_ttl', 3600, 'Seconds for auth tokens to linger') DEFINE_string('state_path', os.path.join(os.path.dirname(__file__), '../'), "Top-level directory for maintaining nova's state") DEFINE_string('lock_path', os.path.join(os.path.dirname(__file__), '../'), - "Directory for lock files") + 'Directory for lock files') DEFINE_string('logdir', None, 'output to a per-service log file in named ' 'directory') diff --git a/nova/log.py b/nova/log.py index ea94be194..096279f7c 100644 --- a/nova/log.py +++ b/nova/log.py @@ -16,16 +16,15 @@ # License for the specific language governing permissions and limitations # under the License. -""" -Nova logging handler. +"""Nova logging handler. This module adds to logging functionality by adding the option to specify a context object when calling the various log methods. If the context object is not specified, default formatting is used. It also allows setting of formatting information through flags. -""" +""" import cStringIO import inspect @@ -41,34 +40,28 @@ from nova import version FLAGS = flags.FLAGS - flags.DEFINE_string('logging_context_format_string', '%(asctime)s %(levelname)s %(name)s ' '[%(request_id)s %(user)s ' '%(project)s] %(message)s', 'format string to use for log messages with context') - flags.DEFINE_string('logging_default_format_string', '%(asctime)s %(levelname)s %(name)s [-] ' '%(message)s', 'format string to use for log messages without context') - flags.DEFINE_string('logging_debug_format_suffix', 'from (pid=%(process)d) %(funcName)s' ' %(pathname)s:%(lineno)d', 'data to append to log format when level is DEBUG') - flags.DEFINE_string('logging_exception_prefix', '(%(name)s): TRACE: ', 'prefix each line of exception output with this format') - flags.DEFINE_list('default_log_levels', ['amqplib=WARN', 'sqlalchemy=WARN', 'boto=WARN', 'eventlet.wsgi.server=WARN'], 'list of logger=LEVEL pairs') - flags.DEFINE_bool('use_syslog', False, 'output to syslog') flags.DEFINE_string('logfile', None, 'output to named file') @@ -83,6 +76,8 @@ WARN = logging.WARN INFO = logging.INFO DEBUG = logging.DEBUG NOTSET = logging.NOTSET + + # methods getLogger = logging.getLogger debug = logging.debug @@ -93,6 +88,8 @@ error = logging.error exception = logging.exception critical = logging.critical log = logging.log + + # handlers StreamHandler = logging.StreamHandler WatchedFileHandler = logging.handlers.WatchedFileHandler @@ -127,17 +124,18 @@ def _get_log_file_path(binary=None): class NovaLogger(logging.Logger): - """ - NovaLogger manages request context and formatting. + """NovaLogger manages request context and formatting. This becomes the class that is instanciated by logging.getLogger. + """ + def __init__(self, name, level=NOTSET): logging.Logger.__init__(self, name, level) self.setup_from_flags() def setup_from_flags(self): - """Setup logger from flags""" + """Setup logger from flags.""" level = NOTSET for pair in FLAGS.default_log_levels: logger, _sep, level_name = pair.partition('=') @@ -148,7 +146,7 @@ class NovaLogger(logging.Logger): self.setLevel(level) def _log(self, level, msg, args, exc_info=None, extra=None, context=None): - """Extract context from any log call""" + """Extract context from any log call.""" if not extra: extra = {} if context: @@ -157,17 +155,17 @@ class NovaLogger(logging.Logger): return logging.Logger._log(self, level, msg, args, exc_info, extra) def addHandler(self, handler): - """Each handler gets our custom formatter""" + """Each handler gets our custom formatter.""" handler.setFormatter(_formatter) return logging.Logger.addHandler(self, handler) def audit(self, msg, *args, **kwargs): - """Shortcut for our AUDIT level""" + """Shortcut for our AUDIT level.""" if self.isEnabledFor(AUDIT): self._log(AUDIT, msg, args, **kwargs) def exception(self, msg, *args, **kwargs): - """Logging.exception doesn't handle kwargs, so breaks context""" + """Logging.exception doesn't handle kwargs, so breaks context.""" if not kwargs.get('exc_info'): kwargs['exc_info'] = 1 self.error(msg, *args, **kwargs) @@ -181,14 +179,13 @@ class NovaLogger(logging.Logger): for k in env.keys(): if not isinstance(env[k], str): env.pop(k) - message = "Environment: %s" % json.dumps(env) + message = 'Environment: %s' % json.dumps(env) kwargs.pop('exc_info') self.error(message, **kwargs) class NovaFormatter(logging.Formatter): - """ - A nova.context.RequestContext aware formatter configured through flags. + """A nova.context.RequestContext aware formatter configured through flags. The flags used to set format strings are: logging_context_foramt_string and logging_default_format_string. You can also specify @@ -197,10 +194,11 @@ class NovaFormatter(logging.Formatter): For information about what variables are available for the formatter see: http://docs.python.org/library/logging.html#formatter + """ def format(self, record): - """Uses contextstring if request_id is set, otherwise default""" + """Uses contextstring if request_id is set, otherwise default.""" if record.__dict__.get('request_id', None): self._fmt = FLAGS.logging_context_format_string else: @@ -214,20 +212,21 @@ class NovaFormatter(logging.Formatter): return logging.Formatter.format(self, record) def formatException(self, exc_info, record=None): - """Format exception output with FLAGS.logging_exception_prefix""" + """Format exception output with FLAGS.logging_exception_prefix.""" if not record: return logging.Formatter.formatException(self, exc_info) stringbuffer = cStringIO.StringIO() traceback.print_exception(exc_info[0], exc_info[1], exc_info[2], None, stringbuffer) - lines = stringbuffer.getvalue().split("\n") + lines = stringbuffer.getvalue().split('\n') stringbuffer.close() formatted_lines = [] for line in lines: pl = FLAGS.logging_exception_prefix % record.__dict__ - fl = "%s%s" % (pl, line) + fl = '%s%s' % (pl, line) formatted_lines.append(fl) - return "\n".join(formatted_lines) + return '\n'.join(formatted_lines) + _formatter = NovaFormatter() @@ -241,7 +240,7 @@ class NovaRootLogger(NovaLogger): NovaLogger.__init__(self, name, level) def setup_from_flags(self): - """Setup logger from flags""" + """Setup logger from flags.""" global _filelog if FLAGS.use_syslog: self.syslog = SysLogHandler(address='/dev/log') diff --git a/nova/manager.py b/nova/manager.py index 804a50479..34338ac04 100644 --- a/nova/manager.py +++ b/nova/manager.py @@ -16,7 +16,8 @@ # License for the specific language governing permissions and limitations # under the License. -""" +"""Base Manager class. + Managers are responsible for a certain aspect of the sytem. It is a logical grouping of code relating to a portion of the system. In general other components should be using the manager to make changes to the components that @@ -49,16 +50,19 @@ Managers will often provide methods for initial setup of a host or periodic tasksto a wrapping service. This module provides Manager, a base class for managers. + """ -from nova import utils from nova import flags from nova import log as logging +from nova import utils from nova.db import base from nova.scheduler import api + FLAGS = flags.FLAGS + LOG = logging.getLogger('nova.manager') @@ -70,23 +74,29 @@ class Manager(base.Base): super(Manager, self).__init__(db_driver) def periodic_tasks(self, context=None): - """Tasks to be run at a periodic interval""" + """Tasks to be run at a periodic interval.""" pass def init_host(self): - """Do any initialization that needs to be run if this is a standalone - service. Child classes should override this method.""" + """Handle initialization if this is a standalone service. + + Child classes should override this method. + + """ pass class SchedulerDependentManager(Manager): """Periodically send capability updates to the Scheduler services. - Services that need to update the Scheduler of their capabilities - should derive from this class. Otherwise they can derive from - manager.Manager directly. Updates are only sent after - update_service_capabilities is called with non-None values.""" - def __init__(self, host=None, db_driver=None, service_name="undefined"): + Services that need to update the Scheduler of their capabilities + should derive from this class. Otherwise they can derive from + manager.Manager directly. Updates are only sent after + update_service_capabilities is called with non-None values. + + """ + + def __init__(self, host=None, db_driver=None, service_name='undefined'): self.last_capabilities = None self.service_name = service_name super(SchedulerDependentManager, self).__init__(host, db_driver) @@ -96,9 +106,9 @@ class SchedulerDependentManager(Manager): self.last_capabilities = capabilities def periodic_tasks(self, context=None): - """Pass data back to the scheduler at a periodic interval""" + """Pass data back to the scheduler at a periodic interval.""" if self.last_capabilities: - LOG.debug(_("Notifying Schedulers of capabilities ...")) + LOG.debug(_('Notifying Schedulers of capabilities ...')) api.update_service_capabilities(context, self.service_name, self.host, self.last_capabilities) diff --git a/nova/quota.py b/nova/quota.py index 2b24c0b5b..d8b5d9a93 100644 --- a/nova/quota.py +++ b/nova/quota.py @@ -15,16 +15,15 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. -""" -Quotas for instances, volumes, and floating ips -""" + +"""Quotas for instances, volumes, and floating ips.""" from nova import db from nova import exception from nova import flags -FLAGS = flags.FLAGS +FLAGS = flags.FLAGS flags.DEFINE_integer('quota_instances', 10, 'number of instances allowed per project') flags.DEFINE_integer('quota_cores', 20, @@ -64,7 +63,7 @@ def get_quota(context, project_id): def allowed_instances(context, num_instances, instance_type): - """Check quota and return min(num_instances, allowed_instances)""" + """Check quota and return min(num_instances, allowed_instances).""" project_id = context.project_id context = context.elevated() used_instances, used_cores = db.instance_data_get_for_project(context, @@ -79,7 +78,7 @@ def allowed_instances(context, num_instances, instance_type): def allowed_volumes(context, num_volumes, size): - """Check quota and return min(num_volumes, allowed_volumes)""" + """Check quota and return min(num_volumes, allowed_volumes).""" project_id = context.project_id context = context.elevated() used_volumes, used_gigabytes = db.volume_data_get_for_project(context, @@ -95,7 +94,7 @@ def allowed_volumes(context, num_volumes, size): def allowed_floating_ips(context, num_floating_ips): - """Check quota and return min(num_floating_ips, allowed_floating_ips)""" + """Check quota and return min(num_floating_ips, allowed_floating_ips).""" project_id = context.project_id context = context.elevated() used_floating_ips = db.floating_ip_count_by_project(context, project_id) @@ -105,7 +104,7 @@ def allowed_floating_ips(context, num_floating_ips): def allowed_metadata_items(context, num_metadata_items): - """Check quota; return min(num_metadata_items,allowed_metadata_items)""" + """Check quota; return min(num_metadata_items,allowed_metadata_items).""" project_id = context.project_id context = context.elevated() quota = get_quota(context, project_id) @@ -114,20 +113,20 @@ def allowed_metadata_items(context, num_metadata_items): def allowed_injected_files(context): - """Return the number of injected files allowed""" + """Return the number of injected files allowed.""" return FLAGS.quota_max_injected_files def allowed_injected_file_content_bytes(context): - """Return the number of bytes allowed per injected file content""" + """Return the number of bytes allowed per injected file content.""" return FLAGS.quota_max_injected_file_content_bytes def allowed_injected_file_path_bytes(context): - """Return the number of bytes allowed in an injected file path""" + """Return the number of bytes allowed in an injected file path.""" return FLAGS.quota_max_injected_file_path_bytes class QuotaError(exception.ApiError): - """Quota Exceeeded""" + """Quota Exceeeded.""" pass diff --git a/nova/rpc.py b/nova/rpc.py index b610cdf9b..2116f22c3 100644 --- a/nova/rpc.py +++ b/nova/rpc.py @@ -16,9 +16,12 @@ # License for the specific language governing permissions and limitations # under the License. -""" -AMQP-based RPC. Queues have consumers and publishers. +"""AMQP-based RPC. + +Queues have consumers and publishers. + No fan-out support yet. + """ import json @@ -40,17 +43,19 @@ from nova import log as logging from nova import utils -FLAGS = flags.FLAGS LOG = logging.getLogger('nova.rpc') + +FLAGS = flags.FLAGS flags.DEFINE_integer('rpc_thread_pool_size', 1024, 'Size of RPC thread pool') class Connection(carrot_connection.BrokerConnection): - """Connection instance object""" + """Connection instance object.""" + @classmethod def instance(cls, new=True): - """Returns the instance""" + """Returns the instance.""" if new or not hasattr(cls, '_instance'): params = dict(hostname=FLAGS.rabbit_host, port=FLAGS.rabbit_port, @@ -71,9 +76,11 @@ class Connection(carrot_connection.BrokerConnection): @classmethod def recreate(cls): - """Recreates the connection instance + """Recreates the connection instance. + + This is necessary to recover from some network errors/disconnects. - This is necessary to recover from some network errors/disconnects""" + """ try: del cls._instance except AttributeError, e: @@ -84,10 +91,12 @@ class Connection(carrot_connection.BrokerConnection): class Consumer(messaging.Consumer): - """Consumer base class + """Consumer base class. + + Contains methods for connecting the fetch method to async loops. - Contains methods for connecting the fetch method to async loops """ + def __init__(self, *args, **kwargs): for i in xrange(FLAGS.rabbit_max_retries): if i > 0: @@ -100,19 +109,18 @@ class Consumer(messaging.Consumer): fl_host = FLAGS.rabbit_host fl_port = FLAGS.rabbit_port fl_intv = FLAGS.rabbit_retry_interval - LOG.error(_("AMQP server on %(fl_host)s:%(fl_port)d is" - " unreachable: %(e)s. Trying again in %(fl_intv)d" - " seconds.") - % locals()) + LOG.error(_('AMQP server on %(fl_host)s:%(fl_port)d is' + ' unreachable: %(e)s. Trying again in %(fl_intv)d' + ' seconds.') % locals()) self.failed_connection = True if self.failed_connection: - LOG.error(_("Unable to connect to AMQP server " - "after %d tries. Shutting down."), + LOG.error(_('Unable to connect to AMQP server ' + 'after %d tries. Shutting down.'), FLAGS.rabbit_max_retries) sys.exit(1) def fetch(self, no_ack=None, auto_ack=None, enable_callbacks=False): - """Wraps the parent fetch with some logic for failed connections""" + """Wraps the parent fetch with some logic for failed connection.""" # TODO(vish): the logic for failed connections and logging should be # refactored into some sort of connection manager object try: @@ -125,14 +133,14 @@ class Consumer(messaging.Consumer): self.declare() super(Consumer, self).fetch(no_ack, auto_ack, enable_callbacks) if self.failed_connection: - LOG.error(_("Reconnected to queue")) + LOG.error(_('Reconnected to queue')) self.failed_connection = False # NOTE(vish): This is catching all errors because we really don't # want exceptions to be logged 10 times a second if some # persistent failure occurs. except Exception, e: # pylint: disable=W0703 if not self.failed_connection: - LOG.exception(_("Failed to fetch message from queue: %s" % e)) + LOG.exception(_('Failed to fetch message from queue: %s' % e)) self.failed_connection = True def attach_to_eventlet(self): @@ -143,8 +151,9 @@ class Consumer(messaging.Consumer): class AdapterConsumer(Consumer): - """Calls methods on a proxy object based on method and args""" - def __init__(self, connection=None, topic="broadcast", proxy=None): + """Calls methods on a proxy object based on method and args.""" + + def __init__(self, connection=None, topic='broadcast', proxy=None): LOG.debug(_('Initing the Adapter Consumer for %s') % topic) self.proxy = proxy self.pool = greenpool.GreenPool(FLAGS.rpc_thread_pool_size) @@ -156,13 +165,14 @@ class AdapterConsumer(Consumer): @exception.wrap_exception def _receive(self, message_data, message): - """Magically looks for a method on the proxy object and calls it + """Magically looks for a method on the proxy object and calls it. Message data should be a dictionary with two keys: method: string representing the method to call args: dictionary of arg: value Example: {'method': 'echo', 'args': {'value': 42}} + """ LOG.debug(_('received %s') % message_data) msg_id = message_data.pop('_msg_id', None) @@ -189,22 +199,23 @@ class AdapterConsumer(Consumer): if msg_id: msg_reply(msg_id, rval, None) except Exception as e: - logging.exception("Exception during message handling") + logging.exception('Exception during message handling') if msg_id: msg_reply(msg_id, None, sys.exc_info()) return class Publisher(messaging.Publisher): - """Publisher base class""" + """Publisher base class.""" pass class TopicAdapterConsumer(AdapterConsumer): - """Consumes messages on a specific topic""" - exchange_type = "topic" + """Consumes messages on a specific topic.""" + + exchange_type = 'topic' - def __init__(self, connection=None, topic="broadcast", proxy=None): + def __init__(self, connection=None, topic='broadcast', proxy=None): self.queue = topic self.routing_key = topic self.exchange = FLAGS.control_exchange @@ -214,27 +225,29 @@ class TopicAdapterConsumer(AdapterConsumer): class FanoutAdapterConsumer(AdapterConsumer): - """Consumes messages from a fanout exchange""" - exchange_type = "fanout" + """Consumes messages from a fanout exchange.""" - def __init__(self, connection=None, topic="broadcast", proxy=None): - self.exchange = "%s_fanout" % topic + exchange_type = 'fanout' + + def __init__(self, connection=None, topic='broadcast', proxy=None): + self.exchange = '%s_fanout' % topic self.routing_key = topic unique = uuid.uuid4().hex - self.queue = "%s_fanout_%s" % (topic, unique) + self.queue = '%s_fanout_%s' % (topic, unique) self.durable = False - LOG.info(_("Created '%(exchange)s' fanout exchange " - "with '%(key)s' routing key"), - dict(exchange=self.exchange, key=self.routing_key)) + LOG.info(_('Created "%(exchange)s" fanout exchange ' + 'with "%(key)s" routing key'), + dict(exchange=self.exchange, key=self.routing_key)) super(FanoutAdapterConsumer, self).__init__(connection=connection, topic=topic, proxy=proxy) class TopicPublisher(Publisher): - """Publishes messages on a specific topic""" - exchange_type = "topic" + """Publishes messages on a specific topic.""" + + exchange_type = 'topic' - def __init__(self, connection=None, topic="broadcast"): + def __init__(self, connection=None, topic='broadcast'): self.routing_key = topic self.exchange = FLAGS.control_exchange self.durable = False @@ -243,20 +256,22 @@ class TopicPublisher(Publisher): class FanoutPublisher(Publisher): """Publishes messages to a fanout exchange.""" - exchange_type = "fanout" + + exchange_type = 'fanout' def __init__(self, topic, connection=None): - self.exchange = "%s_fanout" % topic - self.queue = "%s_fanout" % topic + self.exchange = '%s_fanout' % topic + self.queue = '%s_fanout' % topic self.durable = False - LOG.info(_("Creating '%(exchange)s' fanout exchange"), - dict(exchange=self.exchange)) + LOG.info(_('Creating "%(exchange)s" fanout exchange'), + dict(exchange=self.exchange)) super(FanoutPublisher, self).__init__(connection=connection) class DirectConsumer(Consumer): - """Consumes messages directly on a channel specified by msg_id""" - exchange_type = "direct" + """Consumes messages directly on a channel specified by msg_id.""" + + exchange_type = 'direct' def __init__(self, connection=None, msg_id=None): self.queue = msg_id @@ -268,8 +283,9 @@ class DirectConsumer(Consumer): class DirectPublisher(Publisher): - """Publishes messages directly on a channel specified by msg_id""" - exchange_type = "direct" + """Publishes messages directly on a channel specified by msg_id.""" + + exchange_type = 'direct' def __init__(self, connection=None, msg_id=None): self.routing_key = msg_id @@ -279,9 +295,9 @@ class DirectPublisher(Publisher): def msg_reply(msg_id, reply=None, failure=None): - """Sends a reply or an error on the channel signified by msg_id + """Sends a reply or an error on the channel signified by msg_id. - failure should be a sys.exc_info() tuple. + Failure should be a sys.exc_info() tuple. """ if failure: @@ -303,17 +319,20 @@ def msg_reply(msg_id, reply=None, failure=None): class RemoteError(exception.Error): - """Signifies that a remote class has raised an exception + """Signifies that a remote class has raised an exception. Containes a string representation of the type of the original exception, the value of the original exception, and the traceback. These are sent to the parent as a joined string so printing the exception - contains all of the relevent info.""" + contains all of the relevent info. + + """ + def __init__(self, exc_type, value, traceback): self.exc_type = exc_type self.value = value self.traceback = traceback - super(RemoteError, self).__init__("%s %s\n%s" % (exc_type, + super(RemoteError, self).__init__('%s %s\n%s' % (exc_type, value, traceback)) @@ -339,6 +358,7 @@ def _pack_context(msg, context): context out into a bunch of separate keys. If we want to support more arguments in rabbit messages, we may want to do the same for args at some point. + """ context = dict([('_context_%s' % key, value) for (key, value) in context.to_dict().iteritems()]) @@ -346,11 +366,11 @@ def _pack_context(msg, context): def call(context, topic, msg): - """Sends a message on a topic and wait for a response""" - LOG.debug(_("Making asynchronous call on %s ..."), topic) + """Sends a message on a topic and wait for a response.""" + LOG.debug(_('Making asynchronous call on %s ...'), topic) msg_id = uuid.uuid4().hex msg.update({'_msg_id': msg_id}) - LOG.debug(_("MSG_ID is %s") % (msg_id)) + LOG.debug(_('MSG_ID is %s') % (msg_id)) _pack_context(msg, context) class WaitMessage(object): @@ -387,8 +407,8 @@ def call(context, topic, msg): def cast(context, topic, msg): - """Sends a message on a topic without waiting for a response""" - LOG.debug(_("Making asynchronous cast on %s..."), topic) + """Sends a message on a topic without waiting for a response.""" + LOG.debug(_('Making asynchronous cast on %s...'), topic) _pack_context(msg, context) conn = Connection.instance() publisher = TopicPublisher(connection=conn, topic=topic) @@ -397,8 +417,8 @@ def cast(context, topic, msg): def fanout_cast(context, topic, msg): - """Sends a message on a fanout exchange without waiting for a response""" - LOG.debug(_("Making asynchronous fanout cast...")) + """Sends a message on a fanout exchange without waiting for a response.""" + LOG.debug(_('Making asynchronous fanout cast...')) _pack_context(msg, context) conn = Connection.instance() publisher = FanoutPublisher(topic, connection=conn) @@ -407,14 +427,14 @@ def fanout_cast(context, topic, msg): def generic_response(message_data, message): - """Logs a result and exits""" + """Logs a result and exits.""" LOG.debug(_('response %s'), message_data) message.ack() sys.exit(0) def send_message(topic, message, wait=True): - """Sends a message for testing""" + """Sends a message for testing.""" msg_id = uuid.uuid4().hex message.update({'_msg_id': msg_id}) LOG.debug(_('topic is %s'), topic) @@ -425,14 +445,14 @@ def send_message(topic, message, wait=True): queue=msg_id, exchange=msg_id, auto_delete=True, - exchange_type="direct", + exchange_type='direct', routing_key=msg_id) consumer.register_callback(generic_response) publisher = messaging.Publisher(connection=Connection.instance(), exchange=FLAGS.control_exchange, durable=False, - exchange_type="topic", + exchange_type='topic', routing_key=topic) publisher.send(message) publisher.close() @@ -441,8 +461,8 @@ def send_message(topic, message, wait=True): consumer.wait() -if __name__ == "__main__": - # NOTE(vish): you can send messages from the command line using - # topic and a json sting representing a dictionary - # for the method +if __name__ == '__main__': + # You can send messages from the command line using + # topic and a json string representing a dictionary + # for the method send_message(sys.argv[1], json.loads(sys.argv[2])) diff --git a/nova/service.py b/nova/service.py index 47c0b96c0..2532b9df2 100644 --- a/nova/service.py +++ b/nova/service.py @@ -17,9 +17,7 @@ # License for the specific language governing permissions and limitations # under the License. -""" -Generic Node baseclass for all workers that run on hosts -""" +"""Generic Node baseclass for all workers that run on hosts.""" import inspect import os @@ -30,13 +28,11 @@ from eventlet import event from eventlet import greenthread from eventlet import greenpool -from sqlalchemy.exc import OperationalError - from nova import context from nova import db from nova import exception -from nova import log as logging from nova import flags +from nova import log as logging from nova import rpc from nova import utils from nova import version @@ -79,7 +75,7 @@ class Service(object): def start(self): vcs_string = version.version_string_with_vcs() - logging.audit(_("Starting %(topic)s node (version %(vcs_string)s)"), + logging.audit(_('Starting %(topic)s node (version %(vcs_string)s)'), {'topic': self.topic, 'vcs_string': vcs_string}) self.manager.init_host() self.model_disconnected = False @@ -140,29 +136,24 @@ class Service(object): return getattr(manager, key) @classmethod - def create(cls, - host=None, - binary=None, - topic=None, - manager=None, - report_interval=None, - periodic_interval=None): + def create(cls, host=None, binary=None, topic=None, manager=None, + report_interval=None, periodic_interval=None): """Instantiates class and passes back application object. - Args: - host, defaults to FLAGS.host - binary, defaults to basename of executable - topic, defaults to bin_name - "nova-" part - manager, defaults to FLAGS._manager - report_interval, defaults to FLAGS.report_interval - periodic_interval, defaults to FLAGS.periodic_interval + :param host: defaults to FLAGS.host + :param binary: defaults to basename of executable + :param topic: defaults to bin_name - 'nova-' part + :param manager: defaults to FLAGS._manager + :param report_interval: defaults to FLAGS.report_interval + :param periodic_interval: defaults to FLAGS.periodic_interval + """ if not host: host = FLAGS.host if not binary: binary = os.path.basename(inspect.stack()[-1][1]) if not topic: - topic = binary.rpartition("nova-")[2] + topic = binary.rpartition('nova-')[2] if not manager: manager = FLAGS.get('%s_manager' % topic, None) if not report_interval: @@ -175,12 +166,12 @@ class Service(object): return service_obj def kill(self): - """Destroy the service object in the datastore""" + """Destroy the service object in the datastore.""" self.stop() try: db.service_destroy(context.get_admin_context(), self.service_id) except exception.NotFound: - logging.warn(_("Service killed that has no database entry")) + logging.warn(_('Service killed that has no database entry')) def stop(self): for x in self.timers: @@ -198,7 +189,7 @@ class Service(object): pass def periodic_tasks(self): - """Tasks to be run at a periodic interval""" + """Tasks to be run at a periodic interval.""" self.manager.periodic_tasks(context.get_admin_context()) def report_state(self): @@ -208,8 +199,8 @@ class Service(object): try: service_ref = db.service_get(ctxt, self.service_id) except exception.NotFound: - logging.debug(_("The service database object disappeared, " - "Recreating it.")) + logging.debug(_('The service database object disappeared, ' + 'Recreating it.')) self._create_service_ref(ctxt) service_ref = db.service_get(ctxt, self.service_id) @@ -218,23 +209,24 @@ class Service(object): {'report_count': service_ref['report_count'] + 1}) # TODO(termie): make this pattern be more elegant. - if getattr(self, "model_disconnected", False): + if getattr(self, 'model_disconnected', False): self.model_disconnected = False - logging.error(_("Recovered model server connection!")) + logging.error(_('Recovered model server connection!')) # TODO(vish): this should probably only catch connection errors except Exception: # pylint: disable=W0702 - if not getattr(self, "model_disconnected", False): + if not getattr(self, 'model_disconnected', False): self.model_disconnected = True - logging.exception(_("model server went away")) + logging.exception(_('model server went away')) class WsgiService(object): """Base class for WSGI based services. For each api you define, you must also define these flags: - :_listen: The address on which to listen - :_listen_port: The port on which to listen + :_listen: The address on which to listen + :_listen_port: The port on which to listen + """ def __init__(self, conf, apis): @@ -250,13 +242,14 @@ class WsgiService(object): class ApiService(WsgiService): - """Class for our nova-api service""" + """Class for our nova-api service.""" + @classmethod def create(cls, conf=None): if not conf: conf = wsgi.paste_config_file(FLAGS.api_paste_config) if not conf: - message = (_("No paste configuration found for: %s"), + message = (_('No paste configuration found for: %s'), FLAGS.api_paste_config) raise exception.Error(message) api_endpoints = ['ec2', 'osapi'] @@ -280,11 +273,11 @@ def serve(*services): FLAGS.ParseNewFlags() name = '_'.join(x.binary for x in services) - logging.debug(_("Serving %s"), name) - logging.debug(_("Full set of FLAGS:")) + logging.debug(_('Serving %s'), name) + logging.debug(_('Full set of FLAGS:')) for flag in FLAGS: flag_get = FLAGS.get(flag, None) - logging.debug("%(flag)s : %(flag_get)s" % locals()) + logging.debug('%(flag)s : %(flag_get)s' % locals()) for x in services: x.start() @@ -315,20 +308,20 @@ def serve_wsgi(cls, conf=None): def _run_wsgi(paste_config_file, apis): - logging.debug(_("Using paste.deploy config at: %s"), paste_config_file) + logging.debug(_('Using paste.deploy config at: %s'), paste_config_file) apps = [] for api in apis: config = wsgi.load_paste_configuration(paste_config_file, api) if config is None: - logging.debug(_("No paste configuration for app: %s"), api) + logging.debug(_('No paste configuration for app: %s'), api) continue - logging.debug(_("App Config: %(api)s\n%(config)r") % locals()) - logging.info(_("Running %s API"), api) + logging.debug(_('App Config: %(api)s\n%(config)r') % locals()) + logging.info(_('Running %s API'), api) app = wsgi.load_paste_app(paste_config_file, api) - apps.append((app, getattr(FLAGS, "%s_listen_port" % api), - getattr(FLAGS, "%s_listen" % api))) + apps.append((app, getattr(FLAGS, '%s_listen_port' % api), + getattr(FLAGS, '%s_listen' % api))) if len(apps) == 0: - logging.error(_("No known API applications configured in %s."), + logging.error(_('No known API applications configured in %s.'), paste_config_file) return diff --git a/nova/test.py b/nova/test.py index 3b608520a..4deb2a175 100644 --- a/nova/test.py +++ b/nova/test.py @@ -16,12 +16,12 @@ # License for the specific language governing permissions and limitations # under the License. -""" -Base classes for our unit tests. -Allows overriding of flags for use of fakes, -and some black magic for inline callbacks. -""" +"""Base classes for our unit tests. +Allows overriding of flags for use of fakes, and some black magic for +inline callbacks. + +""" import datetime import functools @@ -52,9 +52,9 @@ flags.DEFINE_bool('fake_tests', True, def skip_if_fake(func): - """Decorator that skips a test if running in fake mode""" + """Decorator that skips a test if running in fake mode.""" def _skipper(*args, **kw): - """Wrapped skipper function""" + """Wrapped skipper function.""" if FLAGS.fake_tests: raise unittest.SkipTest('Test cannot be run in fake mode') else: @@ -63,9 +63,10 @@ def skip_if_fake(func): class TestCase(unittest.TestCase): - """Test case base class for all unit tests""" + """Test case base class for all unit tests.""" + def setUp(self): - """Run before each test method to initialize test environment""" + """Run before each test method to initialize test environment.""" super(TestCase, self).setUp() # NOTE(vish): We need a better method for creating fixtures for tests # now that we have some required db setup for the system @@ -86,8 +87,7 @@ class TestCase(unittest.TestCase): self._original_flags = FLAGS.FlagValuesDict() def tearDown(self): - """Runs after each test method to finalize/tear down test - environment.""" + """Runs after each test method to tear down test environment.""" try: self.mox.UnsetStubs() self.stubs.UnsetAll() @@ -121,7 +121,7 @@ class TestCase(unittest.TestCase): pass def flags(self, **kw): - """Override flag variables for a test""" + """Override flag variables for a test.""" for k, v in kw.iteritems(): if k in self.flag_overrides: self.reset_flags() @@ -131,7 +131,11 @@ class TestCase(unittest.TestCase): setattr(FLAGS, k, v) def reset_flags(self): - """Resets all flag variables for the test. Runs after each test""" + """Resets all flag variables for the test. + + Runs after each test. + + """ FLAGS.Reset() for k, v in self._original_flags.iteritems(): setattr(FLAGS, k, v) @@ -158,7 +162,6 @@ class TestCase(unittest.TestCase): def _monkey_patch_wsgi(self): """Allow us to kill servers spawned by wsgi.Server.""" - # TODO(termie): change these patterns to use functools self.original_start = wsgi.Server.start @functools.wraps(self.original_start) @@ -189,12 +192,13 @@ class TestCase(unittest.TestCase): If you don't care (or don't know) a given value, you can specify the string DONTCARE as the value. This will cause that dict-item to be skipped. + """ def raise_assertion(msg): d1str = str(d1) d2str = str(d2) - base_msg = ("Dictionaries do not match. %(msg)s d1: %(d1str)s " - "d2: %(d2str)s" % locals()) + base_msg = ('Dictionaries do not match. %(msg)s d1: %(d1str)s ' + 'd2: %(d2str)s' % locals()) raise AssertionError(base_msg) d1keys = set(d1.keys()) @@ -202,8 +206,8 @@ class TestCase(unittest.TestCase): if d1keys != d2keys: d1only = d1keys - d2keys d2only = d2keys - d1keys - raise_assertion("Keys in d1 and not d2: %(d1only)s. " - "Keys in d2 and not d1: %(d2only)s" % locals()) + raise_assertion('Keys in d1 and not d2: %(d1only)s. ' + 'Keys in d2 and not d1: %(d2only)s' % locals()) for key in d1keys: d1value = d1[key] @@ -217,19 +221,19 @@ class TestCase(unittest.TestCase): "d2['%(key)s']=%(d2value)s" % locals()) def assertDictListMatch(self, L1, L2): - """Assert a list of dicts are equivalent""" + """Assert a list of dicts are equivalent.""" def raise_assertion(msg): L1str = str(L1) L2str = str(L2) - base_msg = ("List of dictionaries do not match: %(msg)s " - "L1: %(L1str)s L2: %(L2str)s" % locals()) + base_msg = ('List of dictionaries do not match: %(msg)s ' + 'L1: %(L1str)s L2: %(L2str)s' % locals()) raise AssertionError(base_msg) L1count = len(L1) L2count = len(L2) if L1count != L2count: - raise_assertion("Length mismatch: len(L1)=%(L1count)d != " - "len(L2)=%(L2count)d" % locals()) + raise_assertion('Length mismatch: len(L1)=%(L1count)d != ' + 'len(L2)=%(L2count)d' % locals()) for d1, d2 in zip(L1, L2): self.assertDictMatch(d1, d2) diff --git a/nova/utils.py b/nova/utils.py index 76cba1a08..59f694196 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -17,9 +17,7 @@ # License for the specific language governing permissions and limitations # under the License. -""" -System-level utilities and helper functions. -""" +"""Utilities and helper functions.""" import base64 import datetime @@ -43,9 +41,8 @@ from eventlet import event from eventlet import greenthread from eventlet import semaphore from eventlet.green import subprocess -None + from nova import exception -from nova.exception import ProcessExecutionError from nova import flags from nova import log as logging @@ -56,7 +53,7 @@ FLAGS = flags.FLAGS def import_class(import_str): - """Returns a class from a string including module and class""" + """Returns a class from a string including module and class.""" mod_str, _sep, class_str = import_str.rpartition('.') try: __import__(mod_str) @@ -67,7 +64,7 @@ def import_class(import_str): def import_object(import_str): - """Returns an object including a module or module and class""" + """Returns an object including a module or module and class.""" try: __import__(import_str) return sys.modules[import_str] @@ -99,11 +96,12 @@ def vpn_ping(address, port, timeout=0.05, session_id=None): cli_id = 64 bit identifier ? = unknown, probably flags/padding bit 9 was 1 and the rest were 0 in testing + """ if session_id is None: session_id = random.randint(0, 0xffffffffffffffff) sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - data = struct.pack("!BQxxxxxx", 0x38, session_id) + data = struct.pack('!BQxxxxxx', 0x38, session_id) sock.sendto(data, (address, port)) sock.settimeout(timeout) try: @@ -112,7 +110,7 @@ def vpn_ping(address, port, timeout=0.05, session_id=None): return False finally: sock.close() - fmt = "!BQxxxxxQxxxx" + fmt = '!BQxxxxxQxxxx' if len(received) != struct.calcsize(fmt): print struct.calcsize(fmt) return False @@ -122,15 +120,8 @@ def vpn_ping(address, port, timeout=0.05, session_id=None): def fetchfile(url, target): - LOG.debug(_("Fetching %s") % url) -# c = pycurl.Curl() -# fp = open(target, "wb") -# c.setopt(c.URL, url) -# c.setopt(c.WRITEDATA, fp) -# c.perform() -# c.close() -# fp.close() - execute("curl", "--fail", url, "-o", target) + LOG.debug(_('Fetching %s') % url) + execute('curl', '--fail', url, '-o', target) def execute(*cmd, **kwargs): @@ -147,7 +138,7 @@ def execute(*cmd, **kwargs): while attempts > 0: attempts -= 1 try: - LOG.debug(_("Running cmd (subprocess): %s"), ' '.join(cmd)) + LOG.debug(_('Running cmd (subprocess): %s'), ' '.join(cmd)) env = os.environ.copy() if addl_env: env.update(addl_env) @@ -163,20 +154,21 @@ def execute(*cmd, **kwargs): result = obj.communicate() obj.stdin.close() if obj.returncode: - LOG.debug(_("Result was %s") % obj.returncode) + LOG.debug(_('Result was %s') % obj.returncode) if type(check_exit_code) == types.IntType \ and obj.returncode != check_exit_code: (stdout, stderr) = result - raise ProcessExecutionError(exit_code=obj.returncode, - stdout=stdout, - stderr=stderr, - cmd=' '.join(cmd)) + raise exception.ProcessExecutionError( + exit_code=obj.returncode, + stdout=stdout, + stderr=stderr, + cmd=' '.join(cmd)) return result - except ProcessExecutionError: + except exception.ProcessExecutionError: if not attempts: raise else: - LOG.debug(_("%r failed. Retrying."), cmd) + LOG.debug(_('%r failed. Retrying.'), cmd) if delay_on_retry: greenthread.sleep(random.randint(20, 200) / 100.0) finally: @@ -188,13 +180,13 @@ def execute(*cmd, **kwargs): def ssh_execute(ssh, cmd, process_input=None, addl_env=None, check_exit_code=True): - LOG.debug(_("Running cmd (SSH): %s"), ' '.join(cmd)) + LOG.debug(_('Running cmd (SSH): %s'), ' '.join(cmd)) if addl_env: - raise exception.Error("Environment not supported over SSH") + raise exception.Error('Environment not supported over SSH') if process_input: # This is (probably) fixable if we need it... - raise exception.Error("process_input not supported over SSH") + raise exception.Error('process_input not supported over SSH') stdin_stream, stdout_stream, stderr_stream = ssh.exec_command(cmd) channel = stdout_stream.channel @@ -212,7 +204,7 @@ def ssh_execute(ssh, cmd, process_input=None, # exit_status == -1 if no exit code was returned if exit_status != -1: - LOG.debug(_("Result was %s") % exit_status) + LOG.debug(_('Result was %s') % exit_status) if check_exit_code and exit_status != 0: raise exception.ProcessExecutionError(exit_code=exit_status, stdout=stdout, @@ -251,7 +243,7 @@ def debug(arg): def runthis(prompt, *cmd, **kwargs): - LOG.debug(_("Running %s"), (" ".join(cmd))) + LOG.debug(_('Running %s'), (' '.join(cmd))) rv, err = execute(*cmd, **kwargs) @@ -266,48 +258,49 @@ def generate_mac(): random.randint(0x00, 0x7f), random.randint(0x00, 0xff), random.randint(0x00, 0xff)] - return ':'.join(map(lambda x: "%02x" % x, mac)) + return ':'.join(map(lambda x: '%02x' % x, mac)) # Default symbols to use for passwords. Avoids visually confusing characters. # ~6 bits per symbol -DEFAULT_PASSWORD_SYMBOLS = ("23456789" # Removed: 0,1 - "ABCDEFGHJKLMNPQRSTUVWXYZ" # Removed: I, O - "abcdefghijkmnopqrstuvwxyz") # Removed: l +DEFAULT_PASSWORD_SYMBOLS = ('23456789' # Removed: 0,1 + 'ABCDEFGHJKLMNPQRSTUVWXYZ' # Removed: I, O + 'abcdefghijkmnopqrstuvwxyz') # Removed: l # ~5 bits per symbol -EASIER_PASSWORD_SYMBOLS = ("23456789" # Removed: 0, 1 - "ABCDEFGHJKLMNPQRSTUVWXYZ") # Removed: I, O +EASIER_PASSWORD_SYMBOLS = ('23456789' # Removed: 0, 1 + 'ABCDEFGHJKLMNPQRSTUVWXYZ') # Removed: I, O def generate_password(length=20, symbols=DEFAULT_PASSWORD_SYMBOLS): """Generate a random password from the supplied symbols. Believed to be reasonably secure (with a reasonable password length!) + """ r = random.SystemRandom() - return "".join([r.choice(symbols) for _i in xrange(length)]) + return ''.join([r.choice(symbols) for _i in xrange(length)]) def last_octet(address): - return int(address.split(".")[-1]) + return int(address.split('.')[-1]) def get_my_linklocal(interface): try: - if_str = execute("ip", "-f", "inet6", "-o", "addr", "show", interface) - condition = "\s+inet6\s+([0-9a-f:]+)/\d+\s+scope\s+link" + if_str = execute('ip', '-f', 'inet6', '-o', 'addr', 'show', interface) + condition = '\s+inet6\s+([0-9a-f:]+)/\d+\s+scope\s+link' links = [re.search(condition, x) for x in if_str[0].split('\n')] address = [w.group(1) for w in links if w is not None] if address[0] is not None: return address[0] else: - raise exception.Error(_("Link Local address is not found.:%s") + raise exception.Error(_('Link Local address is not found.:%s') % if_str) except Exception as ex: raise exception.Error(_("Couldn't get Link Local IP of %(interface)s" - " :%(ex)s") % locals()) + " :%(ex)s") % locals()) def to_global_ipv6(prefix, mac): @@ -319,15 +312,15 @@ def to_global_ipv6(prefix, mac): return (mac64_addr ^ netaddr.IPAddress('::0200:0:0:0') | maskIP).\ format() except TypeError: - raise TypeError(_("Bad mac for to_global_ipv6: %s") % mac) + raise TypeError(_('Bad mac for to_global_ipv6: %s') % mac) def to_mac(ipv6_address): address = netaddr.IPAddress(ipv6_address) - mask1 = netaddr.IPAddress("::ffff:ffff:ffff:ffff") - mask2 = netaddr.IPAddress("::0200:0:0:0") + mask1 = netaddr.IPAddress('::ffff:ffff:ffff:ffff') + mask2 = netaddr.IPAddress('::0200:0:0:0') mac64 = netaddr.EUI(int(address & mask1 ^ mask2)).words - return ":".join(["%02x" % i for i in mac64[0:3] + mac64[5:8]]) + return ':'.join(['%02x' % i for i in mac64[0:3] + mac64[5:8]]) def utcnow(): @@ -341,7 +334,7 @@ utcnow.override_time = None def is_older_than(before, seconds): - """Return True if before is older than seconds""" + """Return True if before is older than seconds.""" return utcnow() - before > datetime.timedelta(seconds=seconds) @@ -379,7 +372,7 @@ def isotime(at=None): def parse_isotime(timestr): - """Turn an iso formatted time back into a datetime""" + """Turn an iso formatted time back into a datetime.""" return datetime.datetime.strptime(timestr, TIME_FORMAT) @@ -433,16 +426,19 @@ class LazyPluggable(object): class LoopingCallDone(Exception): - """The poll-function passed to LoopingCall can raise this exception to + """Exception to break out and stop a LoopingCall. + + The poll-function passed to LoopingCall can raise this exception to break out of the loop normally. This is somewhat analogous to StopIteration. An optional return-value can be included as the argument to the exception; this return-value will be returned by LoopingCall.wait() + """ def __init__(self, retvalue=True): - """:param retvalue: Value that LoopingCall.wait() should return""" + """:param retvalue: Value that LoopingCall.wait() should return.""" self.retvalue = retvalue @@ -493,7 +489,7 @@ def xhtml_escape(value): http://github.com/facebook/tornado/blob/master/tornado/escape.py """ - return saxutils.escape(value, {'"': """}) + return saxutils.escape(value, {'"': '"'}) def utf8(value): @@ -504,7 +500,7 @@ def utf8(value): """ if isinstance(value, unicode): - return value.encode("utf-8") + return value.encode('utf-8') assert isinstance(value, str) return value @@ -554,7 +550,7 @@ class _NoopContextManager(object): def synchronized(name, external=False): - """Synchronization decorator + """Synchronization decorator. Decorating a method like so: @synchronized('mylock') @@ -578,6 +574,7 @@ def synchronized(name, external=False): multiple processes. This means that if two different workers both run a a method decorated with @synchronized('mylock', external=True), only one of them will execute at a time. + """ def wrap(f): @@ -590,13 +587,13 @@ def synchronized(name, external=False): _semaphores[name] = semaphore.Semaphore() sem = _semaphores[name] LOG.debug(_('Attempting to grab semaphore "%(lock)s" for method ' - '"%(method)s"...' % {"lock": name, - "method": f.__name__})) + '"%(method)s"...' % {'lock': name, + 'method': f.__name__})) with sem: if external: LOG.debug(_('Attempting to grab file lock "%(lock)s" for ' 'method "%(method)s"...' % - {"lock": name, "method": f.__name__})) + {'lock': name, 'method': f.__name__})) lock_file_path = os.path.join(FLAGS.lock_path, 'nova-%s.lock' % name) lock = lockfile.FileLock(lock_file_path) @@ -617,21 +614,23 @@ def synchronized(name, external=False): def get_from_path(items, path): - """ Returns a list of items matching the specified path. Takes an - XPath-like expression e.g. prop1/prop2/prop3, and for each item in items, - looks up items[prop1][prop2][prop3]. Like XPath, if any of the + """Returns a list of items matching the specified path. + + Takes an XPath-like expression e.g. prop1/prop2/prop3, and for each item + in items, looks up items[prop1][prop2][prop3]. Like XPath, if any of the intermediate results are lists it will treat each list item individually. A 'None' in items or any child expressions will be ignored, this function will not throw because of None (anywhere) in items. The returned list - will contain no None values.""" + will contain no None values. + """ if path is None: - raise exception.Error("Invalid mini_xpath") + raise exception.Error('Invalid mini_xpath') - (first_token, sep, remainder) = path.partition("/") + (first_token, sep, remainder) = path.partition('/') - if first_token == "": - raise exception.Error("Invalid mini_xpath") + if first_token == '': + raise exception.Error('Invalid mini_xpath') results = [] @@ -645,7 +644,7 @@ def get_from_path(items, path): for item in items: if item is None: continue - get_method = getattr(item, "get", None) + get_method = getattr(item, 'get', None) if get_method is None: continue child = get_method(first_token) @@ -666,7 +665,7 @@ def get_from_path(items, path): def flatten_dict(dict_, flattened=None): - """Recursively flatten a nested dictionary""" + """Recursively flatten a nested dictionary.""" flattened = flattened or {} for key, value in dict_.iteritems(): if hasattr(value, 'iteritems'): @@ -677,9 +676,7 @@ def flatten_dict(dict_, flattened=None): def partition_dict(dict_, keys): - """Return two dicts, one containing only `keys` the other containing - everything but `keys` - """ + """Return two dicts, one with `keys` the other with everything else.""" intersection = {} difference = {} for key, value in dict_.iteritems(): @@ -691,9 +688,7 @@ def partition_dict(dict_, keys): def map_dict_keys(dict_, key_map): - """Return a dictionary in which the dictionaries keys are mapped to - new keys. - """ + """Return a dict in which the dictionaries keys are mapped to new keys.""" mapped = {} for key, value in dict_.iteritems(): mapped_key = key_map[key] if key in key_map else key @@ -702,15 +697,15 @@ def map_dict_keys(dict_, key_map): def subset_dict(dict_, keys): - """Return a dict that only contains a subset of keys""" + """Return a dict that only contains a subset of keys.""" subset = partition_dict(dict_, keys)[0] return subset def check_isinstance(obj, cls): - """Checks that obj is of type cls, and lets PyLint infer types""" + """Checks that obj is of type cls, and lets PyLint infer types.""" if isinstance(obj, cls): return obj - raise Exception(_("Expected object of type: %s") % (str(cls))) + raise Exception(_('Expected object of type: %s') % (str(cls))) # TODO(justinsb): Can we make this better?? return cls() # Ugly PyLint hack diff --git a/nova/version.py b/nova/version.py index c43d12cf8..1f8d08e8c 100644 --- a/nova/version.py +++ b/nova/version.py @@ -21,9 +21,9 @@ except ImportError: 'revision_id': 'LOCALREVISION', 'revno': 0} + NOVA_VERSION = ['2011', '3'] YEAR, COUNT = NOVA_VERSION - FINAL = False # This becomes true at Release Candidate time @@ -39,8 +39,8 @@ def version_string(): def vcs_version_string(): - return "%s:%s" % (version_info['branch_nick'], version_info['revision_id']) + return '%s:%s' % (version_info['branch_nick'], version_info['revision_id']) def version_string_with_vcs(): - return "%s-%s" % (canonical_version_string(), vcs_version_string()) + return '%s-%s' % (canonical_version_string(), vcs_version_string()) diff --git a/nova/wsgi.py b/nova/wsgi.py index de2e0749f..119fcbe4c 100644 --- a/nova/wsgi.py +++ b/nova/wsgi.py @@ -17,9 +17,7 @@ # License for the specific language governing permissions and limitations # under the License. -""" -Utility methods for working with WSGI servers -""" +"""Utility methods for working with WSGI servers.""" import os import sys @@ -33,7 +31,6 @@ import routes.middleware import webob import webob.dec import webob.exc - from paste import deploy from nova import exception @@ -66,7 +63,7 @@ class Server(object): def start(self, application, port, host='0.0.0.0', backlog=128): """Run a WSGI server with the given application.""" arg0 = sys.argv[0] - logging.audit(_("Starting %(arg0)s on %(host)s:%(port)s") % locals()) + logging.audit(_('Starting %(arg0)s on %(host)s:%(port)s') % locals()) socket = eventlet.listen((host, port), backlog=backlog) self.pool.spawn_n(self._run, application, socket) @@ -87,30 +84,31 @@ class Server(object): class Request(webob.Request): def best_match_content_type(self): - """ - Determine the most acceptable content-type based on the - query extension then the Accept header + """Determine the most acceptable content-type. + + Based on the query extension then the Accept header. + """ - parts = self.path.rsplit(".", 1) + parts = self.path.rsplit('.', 1) if len(parts) > 1: format = parts[1] - if format in ["json", "xml"]: - return "application/{0}".format(parts[1]) + if format in ['json', 'xml']: + return 'application/{0}'.format(parts[1]) - ctypes = ["application/json", "application/xml"] + ctypes = ['application/json', 'application/xml'] bm = self.accept.best_match(ctypes) - return bm or "application/json" + return bm or 'application/json' def get_content_type(self): try: - ct = self.headers["Content-Type"] - assert ct in ("application/xml", "application/json") + ct = self.headers['Content-Type'] + assert ct in ('application/xml', 'application/json') return ct except Exception: - raise webob.exc.HTTPBadRequest("Invalid content type") + raise webob.exc.HTTPBadRequest('Invalid content type') class Application(object): @@ -118,7 +116,7 @@ class Application(object): @classmethod def factory(cls, global_config, **local_config): - """Used for paste app factories in paste.deploy config fles. + """Used for paste app factories in paste.deploy config files. Any local configuration (that is, values under the [app:APPNAME] section of the paste config) will be passed into the `__init__` method @@ -173,8 +171,9 @@ class Application(object): See the end of http://pythonpaste.org/webob/modules/dec.html for more info. + """ - raise NotImplementedError(_("You must implement __call__")) + raise NotImplementedError(_('You must implement __call__')) class Middleware(Application): @@ -184,11 +183,12 @@ class Middleware(Application): initialized that will be called next. By default the middleware will simply call its wrapped app, or you can override __call__ to customize its behavior. + """ @classmethod def factory(cls, global_config, **local_config): - """Used for paste app factories in paste.deploy config fles. + """Used for paste app factories in paste.deploy config files. Any local configuration (that is, values under the [filter:APPNAME] section of the paste config) will be passed into the `__init__` method @@ -240,20 +240,24 @@ class Middleware(Application): class Debug(Middleware): - """Helper class that can be inserted into any WSGI application chain - to get information about the request and response.""" + """Helper class for debugging a WSGI application. + + Can be inserted into any WSGI application chain to get information + about the request and response. + + """ @webob.dec.wsgify(RequestClass=Request) def __call__(self, req): - print ("*" * 40) + " REQUEST ENVIRON" + print ('*' * 40) + ' REQUEST ENVIRON' for key, value in req.environ.items(): - print key, "=", value + print key, '=', value print resp = req.get_response(self.application) - print ("*" * 40) + " RESPONSE HEADERS" + print ('*' * 40) + ' RESPONSE HEADERS' for (key, value) in resp.headers.iteritems(): - print key, "=", value + print key, '=', value print resp.app_iter = self.print_generator(resp.app_iter) @@ -262,11 +266,8 @@ class Debug(Middleware): @staticmethod def print_generator(app_iter): - """ - Iterator that prints the contents of a wrapper string iterator - when iterated. - """ - print ("*" * 40) + " BODY" + """Iterator that prints the contents of a wrapper string.""" + print ('*' * 40) + ' BODY' for part in app_iter: sys.stdout.write(part) sys.stdout.flush() @@ -275,13 +276,10 @@ class Debug(Middleware): class Router(object): - """ - WSGI middleware that maps incoming requests to WSGI apps. - """ + """WSGI middleware that maps incoming requests to WSGI apps.""" def __init__(self, mapper): - """ - Create a router for the given routes.Mapper. + """Create a router for the given routes.Mapper. Each route in `mapper` must specify a 'controller', which is a WSGI app to call. You'll probably want to specify an 'action' as @@ -293,15 +291,16 @@ class Router(object): sc = ServerController() # Explicit mapping of one route to a controller+action - mapper.connect(None, "/svrlist", controller=sc, action="list") + mapper.connect(None, '/svrlist', controller=sc, action='list') # Actions are all implicitly defined - mapper.resource("server", "servers", controller=sc) + mapper.resource('server', 'servers', controller=sc) # Pointing to an arbitrary WSGI app. You can specify the # {path_info:.*} parameter so the target app can be handed just that # section of the URL. - mapper.connect(None, "/v1.0/{path_info:.*}", controller=BlogApp()) + mapper.connect(None, '/v1.0/{path_info:.*}', controller=BlogApp()) + """ self.map = mapper self._router = routes.middleware.RoutesMiddleware(self._dispatch, @@ -309,19 +308,22 @@ class Router(object): @webob.dec.wsgify(RequestClass=Request) def __call__(self, req): - """ - Route the incoming request to a controller based on self.map. + """Route the incoming request to a controller based on self.map. + If no match, return a 404. + """ return self._router @staticmethod @webob.dec.wsgify(RequestClass=Request) def _dispatch(req): - """ + """Dispatch the request to the appropriate controller. + Called by self._router after matching the incoming request to a route and putting the information into req.environ. Either returns 404 or the routed WSGI app's response. + """ match = req.environ['wsgiorg.routing_args'][1] if not match: @@ -331,19 +333,19 @@ class Router(object): class Controller(object): - """ + """WSGI app that dispatched to methods. + WSGI app that reads routing information supplied by RoutesMiddleware and calls the requested action method upon itself. All action methods must, in addition to their normal parameters, accept a 'req' argument which is the incoming wsgi.Request. They raise a webob.exc exception, or return a dict which will be serialized by requested content type. + """ @webob.dec.wsgify(RequestClass=Request) def __call__(self, req): - """ - Call the method specified in req.environ by RoutesMiddleware. - """ + """Call the method specified in req.environ by RoutesMiddleware.""" arg_dict = req.environ['wsgiorg.routing_args'][1] action = arg_dict['action'] method = getattr(self, action) @@ -361,7 +363,7 @@ class Controller(object): body = self._serialize(result, content_type, default_xmlns) response = webob.Response() - response.headers["Content-Type"] = content_type + response.headers['Content-Type'] = content_type response.body = body msg_dict = dict(url=req.url, status=response.status_int) msg = _("%(url)s returned with HTTP %(status)d") % msg_dict @@ -371,12 +373,13 @@ class Controller(object): return result def _serialize(self, data, content_type, default_xmlns): - """ - Serialize the given dict to the provided content_type. + """Serialize the given dict to the provided content_type. + Uses self._serialization_metadata if it exists, which is a dict mapping MIME types to information needed to serialize to that type. + """ - _metadata = getattr(type(self), "_serialization_metadata", {}) + _metadata = getattr(type(self), '_serialization_metadata', {}) serializer = Serializer(_metadata, default_xmlns) try: @@ -385,12 +388,13 @@ class Controller(object): raise webob.exc.HTTPNotAcceptable() def _deserialize(self, data, content_type): - """ - Deserialize the request body to the specefied content type. + """Deserialize the request body to the specefied content type. + Uses self._serialization_metadata if it exists, which is a dict mapping MIME types to information needed to serialize to that type. + """ - _metadata = getattr(type(self), "_serialization_metadata", {}) + _metadata = getattr(type(self), '_serialization_metadata', {}) serializer = Serializer(_metadata) return serializer.deserialize(data, content_type) @@ -400,23 +404,22 @@ class Controller(object): class Serializer(object): - """ - Serializes and deserializes dictionaries to certain MIME types. - """ + """Serializes and deserializes dictionaries to certain MIME types.""" def __init__(self, metadata=None, default_xmlns=None): - """ - Create a serializer based on the given WSGI environment. + """Create a serializer based on the given WSGI environment. + 'metadata' is an optional dict mapping MIME types to information needed to serialize a dictionary to that type. + """ self.metadata = metadata or {} self.default_xmlns = default_xmlns def _get_serialize_handler(self, content_type): handlers = { - "application/json": self._to_json, - "application/xml": self._to_xml, + 'application/json': self._to_json, + 'application/xml': self._to_xml, } try: @@ -425,29 +428,27 @@ class Serializer(object): raise exception.InvalidContentType() def serialize(self, data, content_type): - """ - Serialize a dictionary into a string of the specified content type. - """ + """Serialize a dictionary into the specified content type.""" return self._get_serialize_handler(content_type)(data) def deserialize(self, datastring, content_type): - """ - Deserialize a string to a dictionary. + """Deserialize a string to a dictionary. The string must be in the format of a supported MIME type. + """ return self.get_deserialize_handler(content_type)(datastring) def get_deserialize_handler(self, content_type): handlers = { - "application/json": self._from_json, - "application/xml": self._from_xml, + 'application/json': self._from_json, + 'application/xml': self._from_xml, } try: return handlers[content_type] except Exception: - raise exception.InvalidContentType(_("Invalid content type %s" + raise exception.InvalidContentType(_('Invalid content type %s' % content_type)) def _from_json(self, datastring): @@ -460,11 +461,11 @@ class Serializer(object): return {node.nodeName: self._from_xml_node(node, plurals)} def _from_xml_node(self, node, listnames): - """ - Convert a minidom node to a simple Python type. + """Convert a minidom node to a simple Python type. listnames is a collection of names of XML nodes whose subnodes should be considered list items. + """ if len(node.childNodes) == 1 and node.childNodes[0].nodeType == 3: return node.childNodes[0].nodeValue @@ -571,7 +572,6 @@ def paste_config_file(basename): * /etc/nova, which may not be diffrerent from state_path on your distro """ - configfiles = [basename, os.path.join(FLAGS.state_path, 'etc', 'nova', basename), os.path.join(FLAGS.state_path, 'etc', basename), @@ -587,7 +587,7 @@ def load_paste_configuration(filename, appname): filename = os.path.abspath(filename) config = None try: - config = deploy.appconfig("config:%s" % filename, name=appname) + config = deploy.appconfig('config:%s' % filename, name=appname) except LookupError: pass return config @@ -598,7 +598,7 @@ def load_paste_app(filename, appname): filename = os.path.abspath(filename) app = None try: - app = deploy.loadapp("config:%s" % filename, name=appname) + app = deploy.loadapp('config:%s' % filename, name=appname) except LookupError: pass return app -- cgit From 6eacc130af49ced7a1e5ce511c7096dd7563b4b2 Mon Sep 17 00:00:00 2001 From: termie Date: Wed, 20 Apr 2011 12:08:24 -0700 Subject: cleanups per code review --- nova/utils.py | 4 ++-- nova/wsgi.py | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/nova/utils.py b/nova/utils.py index 59f694196..b783f6c14 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -182,11 +182,11 @@ def ssh_execute(ssh, cmd, process_input=None, addl_env=None, check_exit_code=True): LOG.debug(_('Running cmd (SSH): %s'), ' '.join(cmd)) if addl_env: - raise exception.Error('Environment not supported over SSH') + raise exception.Error(_('Environment not supported over SSH')) if process_input: # This is (probably) fixable if we need it... - raise exception.Error('process_input not supported over SSH') + raise exception.Error(_('process_input not supported over SSH')) stdin_stream, stdout_stream, stderr_stream = ssh.exec_command(cmd) channel = stdout_stream.channel diff --git a/nova/wsgi.py b/nova/wsgi.py index 119fcbe4c..418087641 100644 --- a/nova/wsgi.py +++ b/nova/wsgi.py @@ -89,7 +89,6 @@ class Request(webob.Request): Based on the query extension then the Accept header. """ - parts = self.path.rsplit('.', 1) if len(parts) > 1: -- cgit From 8bf11973b0de6a57f18ac48452e3f8b36adac565 Mon Sep 17 00:00:00 2001 From: termie Date: Wed, 20 Apr 2011 12:26:15 -0700 Subject: docstring cleanup, nova/image dir --- nova/image/fake.py | 9 ++++--- nova/image/glance.py | 70 +++++++++++++++++++++------------------------------ nova/image/local.py | 8 +++--- nova/image/s3.py | 43 +++++++++++++++---------------- nova/image/service.py | 63 +++++++++++++++++++++++----------------------- 5 files changed, 92 insertions(+), 101 deletions(-) diff --git a/nova/image/fake.py b/nova/image/fake.py index e02b4127e..3bc2a8287 100644 --- a/nova/image/fake.py +++ b/nova/image/fake.py @@ -14,6 +14,7 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. + """Implementation of an fake image service""" import copy @@ -69,14 +70,14 @@ class FakeImageService(service.BaseImageService): image = self.images.get(image_id) if image: return copy.deepcopy(image) - LOG.warn("Unable to find image id %s. Have images: %s", + LOG.warn('Unable to find image id %s. Have images: %s', image_id, self.images) raise exception.NotFound def create(self, context, data): """Store the image data and return the new image id. - :raises Duplicate if the image already exist. + :raises: Duplicate if the image already exist. """ image_id = int(data['id']) @@ -88,7 +89,7 @@ class FakeImageService(service.BaseImageService): def update(self, context, image_id, data): """Replace the contents of the given image with the new data. - :raises NotFound if the image does not exist. + :raises: NotFound if the image does not exist. """ image_id = int(image_id) @@ -99,7 +100,7 @@ class FakeImageService(service.BaseImageService): def delete(self, context, image_id): """Delete the given image. - :raises NotFound if the image does not exist. + :raises: NotFound if the image does not exist. """ image_id = int(image_id) diff --git a/nova/image/glance.py b/nova/image/glance.py index 1a80bb2af..81661b3b0 100644 --- a/nova/image/glance.py +++ b/nova/image/glance.py @@ -14,6 +14,7 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. + """Implementation of an image service that uses Glance as the backend""" from __future__ import absolute_import @@ -31,16 +32,18 @@ from nova.image import service LOG = logging.getLogger('nova.image.glance') + FLAGS = flags.FLAGS + GlanceClient = utils.import_class('glance.client.Client') class GlanceImageService(service.BaseImageService): """Provides storage and retrieval of disk image objects within Glance.""" - GLANCE_ONLY_ATTRS = ["size", "location", "disk_format", - "container_format"] + GLANCE_ONLY_ATTRS = ['size', 'location', 'disk_format', + 'container_format'] # NOTE(sirp): Overriding to use _translate_to_service provided by # BaseImageService @@ -56,9 +59,7 @@ class GlanceImageService(service.BaseImageService): self.client = client def index(self, context): - """ - Calls out to Glance for a list of images available - """ + """Calls out to Glance for a list of images available.""" # NOTE(sirp): We need to use `get_images_detailed` and not # `get_images` here because we need `is_public` and `properties` # included so we can filter by user @@ -71,9 +72,7 @@ class GlanceImageService(service.BaseImageService): return filtered def detail(self, context): - """ - Calls out to Glance for a list of detailed image information - """ + """Calls out to Glance for a list of detailed image information.""" filtered = [] image_metas = self.client.get_images_detailed() for image_meta in image_metas: @@ -83,9 +82,7 @@ class GlanceImageService(service.BaseImageService): return filtered def show(self, context, image_id): - """ - Returns a dict containing image data for the given opaque image id. - """ + """Returns a dict with image data for the given opaque image id.""" try: image_meta = self.client.get_image_meta(image_id) except glance_exception.NotFound: @@ -98,9 +95,7 @@ class GlanceImageService(service.BaseImageService): return base_image_meta def show_by_name(self, context, name): - """ - Returns a dict containing image data for the given name. - """ + """Returns a dict containing image data for the given name.""" # TODO(vish): replace this with more efficient call when glance # supports it. image_metas = self.detail(context) @@ -110,9 +105,7 @@ class GlanceImageService(service.BaseImageService): raise exception.NotFound def get(self, context, image_id, data): - """ - Calls out to Glance for metadata and data and writes data. - """ + """Calls out to Glance for metadata and data and writes data.""" try: image_meta, image_chunks = self.client.get_image(image_id) except glance_exception.NotFound: @@ -125,16 +118,16 @@ class GlanceImageService(service.BaseImageService): return base_image_meta def create(self, context, image_meta, data=None): - """ - Store the image data and return the new image id. + """Store the image data and return the new image id. + + :raises: AlreadyExists if the image already exist. - :raises AlreadyExists if the image already exist. """ # Translate Base -> Service - LOG.debug(_("Creating image in Glance. Metadata passed in %s"), + LOG.debug(_('Creating image in Glance. Metadata passed in %s'), image_meta) sent_service_image_meta = self._translate_to_service(image_meta) - LOG.debug(_("Metadata after formatting for Glance %s"), + LOG.debug(_('Metadata after formatting for Glance %s'), sent_service_image_meta) recv_service_image_meta = self.client.add_image( @@ -142,14 +135,15 @@ class GlanceImageService(service.BaseImageService): # Translate Service -> Base base_image_meta = self._translate_to_base(recv_service_image_meta) - LOG.debug(_("Metadata returned from Glance formatted for Base %s"), + LOG.debug(_('Metadata returned from Glance formatted for Base %s'), base_image_meta) return base_image_meta def update(self, context, image_id, image_meta, data=None): """Replace the contents of the given image with the new data. - :raises NotFound if the image does not exist. + :raises: NotFound if the image does not exist. + """ # NOTE(vish): show is to check if image is available self.show(context, image_id) @@ -162,10 +156,10 @@ class GlanceImageService(service.BaseImageService): return base_image_meta def delete(self, context, image_id): - """ - Delete the given image. + """Delete the given image. + + :raises: NotFound if the image does not exist. - :raises NotFound if the image does not exist. """ # NOTE(vish): show is to check if image is available self.show(context, image_id) @@ -176,16 +170,12 @@ class GlanceImageService(service.BaseImageService): return result def delete_all(self): - """ - Clears out all images - """ + """Clears out all images.""" pass @classmethod def _translate_to_base(cls, image_meta): - """Overriding the base translation to handle conversion to datetime - objects - """ + """Override translation to handle conversion to datetime objects.""" image_meta = service.BaseImageService._propertify_metadata( image_meta, cls.SERVICE_IMAGE_ATTRS) image_meta = _convert_timestamps_to_datetimes(image_meta) @@ -194,9 +184,7 @@ class GlanceImageService(service.BaseImageService): # utility functions def _convert_timestamps_to_datetimes(image_meta): - """ - Returns image with known timestamp fields converted to datetime objects - """ + """Returns image with timestamp fields converted to datetime objects.""" for attr in ['created_at', 'updated_at', 'deleted_at']: if image_meta.get(attr): image_meta[attr] = _parse_glance_iso8601_timestamp( @@ -205,10 +193,8 @@ def _convert_timestamps_to_datetimes(image_meta): def _parse_glance_iso8601_timestamp(timestamp): - """ - Parse a subset of iso8601 timestamps into datetime objects - """ - iso_formats = ["%Y-%m-%dT%H:%M:%S.%f", "%Y-%m-%dT%H:%M:%S"] + """Parse a subset of iso8601 timestamps into datetime objects.""" + iso_formats = ['%Y-%m-%dT%H:%M:%S.%f', '%Y-%m-%dT%H:%M:%S'] for iso_format in iso_formats: try: @@ -216,5 +202,5 @@ def _parse_glance_iso8601_timestamp(timestamp): except ValueError: pass - raise ValueError(_("%(timestamp)s does not follow any of the " - "signatures: %(ISO_FORMATS)s") % locals()) + raise ValueError(_('%(timestamp)s does not follow any of the ' + 'signatures: %(ISO_FORMATS)s') % locals()) diff --git a/nova/image/local.py b/nova/image/local.py index fa5e93346..d59c3970f 100644 --- a/nova/image/local.py +++ b/nova/image/local.py @@ -23,14 +23,15 @@ import shutil from nova import exception from nova import flags from nova import log as logging -from nova.image import service from nova import utils +from nova.image import service FLAGS = flags.FLAGS flags.DEFINE_string('images_path', '$state_path/images', 'path to decrypted images') + LOG = logging.getLogger('nova.image.local') @@ -57,7 +58,7 @@ class LocalImageService(service.BaseImageService): unhexed_image_id = int(image_dir, 16) except ValueError: LOG.error( - _("%s is not in correct directory naming format"\ + _('%s is not in correct directory naming format'\ % image_dir)) else: images.append(unhexed_image_id) @@ -148,7 +149,8 @@ class LocalImageService(service.BaseImageService): def delete(self, context, image_id): """Delete the given image. - Raises NotFound if the image does not exist. + + :raises: NotFound if the image does not exist. """ # NOTE(vish): show is to check if image is available diff --git a/nova/image/s3.py b/nova/image/s3.py index 2a02d4674..4a4ee44d8 100644 --- a/nova/image/s3.py +++ b/nova/image/s3.py @@ -16,19 +16,16 @@ # License for the specific language governing permissions and limitations # under the License. -""" -Proxy AMI-related calls from the cloud controller, to the running -objectstore service. -""" +"""Proxy AMI-related calls from cloud controller to objectstore service.""" import binascii -import eventlet import os import shutil import tarfile import tempfile from xml.etree import ElementTree +import eventlet import boto.s3.connection from nova import crypto @@ -46,7 +43,7 @@ flags.DEFINE_string('image_decryption_dir', '/tmp', class S3ImageService(service.BaseImageService): - """Wraps an existing image service to support s3 based register""" + """Wraps an existing image service to support s3 based register.""" def __init__(self, service=None, *args, **kwargs): if service is None: service = utils.import_object(FLAGS.image_service) @@ -54,7 +51,11 @@ class S3ImageService(service.BaseImageService): self.service.__init__(*args, **kwargs) def create(self, context, metadata, data=None): - """metadata['properties'] should contain image_location""" + """Create an image. + + metadata['properties'] should contain image_location. + + """ image = self._s3_create(context, metadata) return image @@ -100,12 +101,12 @@ class S3ImageService(service.BaseImageService): return local_filename def _s3_create(self, context, metadata): - """Gets a manifext from s3 and makes an image""" + """Gets a manifext from s3 and makes an image.""" image_path = tempfile.mkdtemp(dir=FLAGS.image_decryption_dir) image_location = metadata['properties']['image_location'] - bucket_name = image_location.split("/")[0] + bucket_name = image_location.split('/')[0] manifest_path = image_location[len(bucket_name) + 1:] bucket = self._conn(context).get_bucket(bucket_name) key = bucket.get_key(manifest_path) @@ -116,7 +117,7 @@ class S3ImageService(service.BaseImageService): image_type = 'machine' try: - kernel_id = manifest.find("machine_configuration/kernel_id").text + kernel_id = manifest.find('machine_configuration/kernel_id').text if kernel_id == 'true': image_format = 'aki' image_type = 'kernel' @@ -125,7 +126,7 @@ class S3ImageService(service.BaseImageService): kernel_id = None try: - ramdisk_id = manifest.find("machine_configuration/ramdisk_id").text + ramdisk_id = manifest.find('machine_configuration/ramdisk_id').text if ramdisk_id == 'true': image_format = 'ari' image_type = 'ramdisk' @@ -134,7 +135,7 @@ class S3ImageService(service.BaseImageService): ramdisk_id = None try: - arch = manifest.find("machine_configuration/architecture").text + arch = manifest.find('machine_configuration/architecture').text except Exception: arch = 'x86_64' @@ -160,7 +161,7 @@ class S3ImageService(service.BaseImageService): def delayed_create(): """This handles the fetching and decrypting of the part files.""" parts = [] - for fn_element in manifest.find("image").getiterator("filename"): + for fn_element in manifest.find('image').getiterator('filename'): part = self._download_file(bucket, fn_element.text, image_path) parts.append(part) @@ -174,9 +175,9 @@ class S3ImageService(service.BaseImageService): metadata['properties']['image_state'] = 'decrypting' self.service.update(context, image_id, metadata) - hex_key = manifest.find("image/ec2_encrypted_key").text + hex_key = manifest.find('image/ec2_encrypted_key').text encrypted_key = binascii.a2b_hex(hex_key) - hex_iv = manifest.find("image/ec2_encrypted_iv").text + hex_iv = manifest.find('image/ec2_encrypted_iv').text encrypted_iv = binascii.a2b_hex(hex_iv) # FIXME(vish): grab key from common service so this can run on @@ -214,7 +215,7 @@ class S3ImageService(service.BaseImageService): process_input=encrypted_key, check_exit_code=False) if err: - raise exception.Error(_("Failed to decrypt private key: %s") + raise exception.Error(_('Failed to decrypt private key: %s') % err) iv, err = utils.execute('openssl', 'rsautl', @@ -223,8 +224,8 @@ class S3ImageService(service.BaseImageService): process_input=encrypted_iv, check_exit_code=False) if err: - raise exception.Error(_("Failed to decrypt initialization " - "vector: %s") % err) + raise exception.Error(_('Failed to decrypt initialization ' + 'vector: %s') % err) _out, err = utils.execute('openssl', 'enc', '-d', '-aes-128-cbc', @@ -234,14 +235,14 @@ class S3ImageService(service.BaseImageService): '-out', '%s' % (decrypted_filename,), check_exit_code=False) if err: - raise exception.Error(_("Failed to decrypt image file " - "%(image_file)s: %(err)s") % + raise exception.Error(_('Failed to decrypt image file ' + '%(image_file)s: %(err)s') % {'image_file': encrypted_filename, 'err': err}) @staticmethod def _untarzip_image(path, filename): - tar_file = tarfile.open(filename, "r|gz") + tar_file = tarfile.open(filename, 'r|gz') tar_file.extractall(path) image_file = tar_file.getnames()[0] tar_file.close() diff --git a/nova/image/service.py b/nova/image/service.py index fddc72409..3e2357df8 100644 --- a/nova/image/service.py +++ b/nova/image/service.py @@ -20,7 +20,7 @@ from nova import utils class BaseImageService(object): - """Base class for providing image search and retrieval services + """Base class for providing image search and retrieval services. ImageService exposes two concepts of metadata: @@ -35,7 +35,9 @@ class BaseImageService(object): This means that ImageServices will return BASE_IMAGE_ATTRS as keys in the metadata dict, all other attributes will be returned as keys in the nested 'properties' dict. + """ + BASE_IMAGE_ATTRS = ['id', 'name', 'created_at', 'updated_at', 'deleted_at', 'deleted', 'status', 'is_public'] @@ -45,23 +47,18 @@ class BaseImageService(object): SERVICE_IMAGE_ATTRS = [] def index(self, context): - """ - Returns a sequence of mappings of id and name information about - images. + """List images. - :rtype: array - :retval: a sequence of mappings with the following signature + :returnsl: a sequence of mappings with the following signature {'id': opaque id of image, 'name': name of image} """ raise NotImplementedError def detail(self, context): - """ - Returns a sequence of mappings of detailed information about images. + """Detailed information about an images. - :rtype: array - :retval: a sequence of mappings with the following signature + :returns: a sequence of mappings with the following signature {'id': opaque id of image, 'name': name of image, 'created_at': creation datetime object, @@ -77,15 +74,14 @@ class BaseImageService(object): NotImplementedError, in which case Nova will emulate this method with repeated calls to show() for each image received from the index() method. + """ raise NotImplementedError def show(self, context, image_id): - """ - Returns a dict containing image metadata for the given opaque image id. - - :retval a mapping with the following signature: + """Detailed information about an image. + :returns: a mapping with the following signature: {'id': opaque id of image, 'name': name of image, 'created_at': creation datetime object, @@ -96,31 +92,32 @@ class BaseImageService(object): 'is_public': boolean indicating if image is public }, ... - :raises NotFound if the image does not exist + :raises: NotFound if the image does not exist + """ raise NotImplementedError def get(self, context, data): - """ - Returns a dict containing image metadata and writes image data to data. + """Get an image. :param data: a file-like object to hold binary image data - + :returns: a dict containing image metadata, writes image data to data. :raises NotFound if the image does not exist + """ raise NotImplementedError def create(self, context, metadata, data=None): - """ - Store the image metadata and data and return the new image metadata. + """Store the image metadata and data. - :raises AlreadyExists if the image already exist. + :returns: the new image metadata. + :raises: AlreadyExists if the image already exist. """ raise NotImplementedError def update(self, context, image_id, metadata, data=None): - """Update the given image metadata and data and return the metadata + """Update the given image metadata and data and return the metadata. :raises NotFound if the image does not exist. @@ -128,8 +125,7 @@ class BaseImageService(object): raise NotImplementedError def delete(self, context, image_id): - """ - Delete the given image. + """Delete the given image. :raises NotFound if the image does not exist. @@ -138,12 +134,14 @@ class BaseImageService(object): @staticmethod def _is_image_available(context, image_meta): - """ + """Check image availability. + Images are always available if they are public or if the user is an admin. Otherwise, we filter by project_id (if present) and then fall-back to images owned by user. + """ # FIXME(sirp): We should be filtering by user_id on the Glance side # for security; however, we can't do that until we get authn/authz @@ -169,29 +167,32 @@ class BaseImageService(object): This is used by subclasses to expose only a metadata dictionary that is the same across ImageService implementations. + """ return cls._propertify_metadata(metadata, cls.BASE_IMAGE_ATTRS) @classmethod def _translate_to_service(cls, metadata): - """Return a metadata dictionary that is usable by the ImageService - subclass. + """Return a metadata dict that is usable by the ImageService subclass. As an example, Glance has additional attributes (like 'location'); the BaseImageService considers these properties, but we need to translate these back to first-class attrs for sending to Glance. This method handles this by allowing you to specify the attributes an ImageService considers first-class. + """ if not cls.SERVICE_IMAGE_ATTRS: - raise NotImplementedError(_("Cannot use this without specifying " - "SERVICE_IMAGE_ATTRS for subclass")) + raise NotImplementedError(_('Cannot use this without specifying ' + 'SERVICE_IMAGE_ATTRS for subclass')) return cls._propertify_metadata(metadata, cls.SERVICE_IMAGE_ATTRS) @staticmethod def _propertify_metadata(metadata, keys): - """Return a dict with any unrecognized keys placed in the nested - 'properties' dict. + """Move unknown keys to a nested 'properties' dict. + + :returns: a new dict with the keys moved. + """ flattened = utils.flatten_dict(metadata) attributes, properties = utils.partition_dict(flattened, keys) -- cgit From 42b139f740c08cce04d898c4ce7c85030733927f Mon Sep 17 00:00:00 2001 From: termie Date: Wed, 20 Apr 2011 12:26:17 -0700 Subject: fixes per review --- nova/image/s3.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nova/image/s3.py b/nova/image/s3.py index 4a4ee44d8..c38c58d95 100644 --- a/nova/image/s3.py +++ b/nova/image/s3.py @@ -25,8 +25,8 @@ import tarfile import tempfile from xml.etree import ElementTree -import eventlet import boto.s3.connection +import eventlet from nova import crypto from nova import exception @@ -44,6 +44,7 @@ flags.DEFINE_string('image_decryption_dir', '/tmp', class S3ImageService(service.BaseImageService): """Wraps an existing image service to support s3 based register.""" + def __init__(self, service=None, *args, **kwargs): if service is None: service = utils.import_object(FLAGS.image_service) -- cgit From ce8fd6b5e3ef0c757c76bbe9db37c696a1d2c11c Mon Sep 17 00:00:00 2001 From: termie Date: Wed, 20 Apr 2011 12:26:17 -0700 Subject: more changes per review --- nova/image/local.py | 5 ++--- nova/image/service.py | 10 +++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/nova/image/local.py b/nova/image/local.py index d59c3970f..50f00bee1 100644 --- a/nova/image/local.py +++ b/nova/image/local.py @@ -57,9 +57,8 @@ class LocalImageService(service.BaseImageService): try: unhexed_image_id = int(image_dir, 16) except ValueError: - LOG.error( - _('%s is not in correct directory naming format'\ - % image_dir)) + LOG.error(_('%s is not in correct directory naming format') + % image_dir) else: images.append(unhexed_image_id) return images diff --git a/nova/image/service.py b/nova/image/service.py index 3e2357df8..ab6749049 100644 --- a/nova/image/service.py +++ b/nova/image/service.py @@ -49,8 +49,8 @@ class BaseImageService(object): def index(self, context): """List images. - :returnsl: a sequence of mappings with the following signature - {'id': opaque id of image, 'name': name of image} + :returns: a sequence of mappings with the following signature + {'id': opaque id of image, 'name': name of image} """ raise NotImplementedError @@ -102,7 +102,7 @@ class BaseImageService(object): :param data: a file-like object to hold binary image data :returns: a dict containing image metadata, writes image data to data. - :raises NotFound if the image does not exist + :raises: NotFound if the image does not exist """ raise NotImplementedError @@ -119,7 +119,7 @@ class BaseImageService(object): def update(self, context, image_id, metadata, data=None): """Update the given image metadata and data and return the metadata. - :raises NotFound if the image does not exist. + :raises: NotFound if the image does not exist. """ raise NotImplementedError @@ -127,7 +127,7 @@ class BaseImageService(object): def delete(self, context, image_id): """Delete the given image. - :raises NotFound if the image does not exist. + :raises: NotFound if the image does not exist. """ raise NotImplementedError -- cgit From 2ea651dad0265807119716046767b85cf769ca05 Mon Sep 17 00:00:00 2001 From: Naveed Massjouni Date: Wed, 20 Apr 2011 16:27:33 -0400 Subject: Exit early if tests fail, before pep8 is run. --- run_tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run_tests.sh b/run_tests.sh index 4f85dfe6d..610cf1f27 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -96,7 +96,7 @@ then fi fi -run_tests +run_tests || exit # Also run pep8 if no options were provided. if [ -z "$noseargs" ]; then -- cgit From 7d8698ad551b756a9dfc7058e6d836de65a64945 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Wed, 20 Apr 2011 16:21:37 -0700 Subject: in doesn't work properly on instance_ref --- nova/api/ec2/cloud.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index bd4c9dcd4..4785d812a 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -187,7 +187,7 @@ class CloudController(object): 'mpi': mpi}} for image_type in ['kernel', 'ramdisk']: - if '%s_id' % image_type in instance_ref: + if instance_ref.get('%s_id' % image_type): ec2_id = self._image_ec2_id(instance_ref['%s_id' % image_type], self._image_type(image_type)) data['meta-data']['%s-id' % image_type] = ec2_id -- cgit From 783cea4dc4497176b57b7a718a29bde102fb92bc Mon Sep 17 00:00:00 2001 From: Eldar Nugaev Date: Thu, 21 Apr 2011 04:31:17 +0400 Subject: style fix --- nova/virt/libvirt_conn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index d5a88ebed..a42433fed 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -168,7 +168,7 @@ def _get_network_info(instance): networks = db.network_get_all_by_instance(admin_context, instance['id']) flavor = db.instance_type_get_by_id(admin_context, - instance['instance_type_id']) + instance['instance_type_id']) network_info = [] for network in networks: -- cgit From 2217872ff5e8e5b53af0b38064a3cdbc2c783ebb Mon Sep 17 00:00:00 2001 From: Eldar Nugaev Date: Thu, 21 Apr 2011 05:22:09 +0400 Subject: pep8 cleaning --- nova/compute/manager.py | 47 +++++++++++----------- .../015_add_auto_assign_to_floating_ips.py | 1 + nova/network/api.py | 6 +-- 3 files changed, 28 insertions(+), 26 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index c1dc06557..13a082b44 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -37,8 +37,6 @@ terminating it. import datetime import os -import random -import string import socket import sys import tempfile @@ -54,7 +52,7 @@ from nova import rpc from nova import utils from nova.compute import power_state from nova.virt import driver -from nova.network import api as network_api +from nova import network FLAGS = flags.FLAGS flags.DEFINE_string('instances_path', '$state_path/instances', @@ -74,8 +72,8 @@ flags.DEFINE_integer('live_migration_retry_count', 30, flags.DEFINE_integer("rescue_timeout", 0, "Automatically unrescue an instance after N seconds." " Set to 0 to disable.") -flags.DEFINE_bool('auto_assign_floating_ip', False, 'Autoassigning floating' - ' ip to VM') +flags.DEFINE_bool('auto_assign_floating_ip', False, + 'Autoassigning floating ip to VM') LOG = logging.getLogger('nova.compute.manager') @@ -135,7 +133,7 @@ class ComputeManager(manager.SchedulerDependentManager): self.network_manager = utils.import_object(FLAGS.network_manager) self.volume_manager = utils.import_object(FLAGS.volume_manager) - self.network_api = network_api.API() + self.network_api = network.API() super(ComputeManager, self).__init__(service_name="compute", *args, **kwargs) @@ -248,18 +246,18 @@ class ComputeManager(manager.SchedulerDependentManager): instance_id, power_state.SHUTDOWN) - if not FLAGS.stub_network: - if FLAGS.auto_assign_floating_ip: - public_ip = self.network_api.allocate_floating_ip(context) + if not FLAGS.stub_network and FLAGS.auto_assign_floating_ip: + public_ip = self.network_api.allocate_floating_ip(context) - self.db.floating_ip_set_auto_assigned(context, public_ip) - fixed_ip = self.db.fixed_ip_get_by_address(context, address) - floating_ip = self.db.floating_ip_get_by_address(context, - public_ip) + self.db.floating_ip_set_auto_assigned(context, public_ip) + fixed_ip = self.db.fixed_ip_get_by_address(context, address) + floating_ip = self.db.floating_ip_get_by_address(context, + public_ip) - self.network_api.associate_floating_ip(context, floating_ip, - fixed_ip, - affect_auto_assigned=True) + self.network_api.associate_floating_ip(context, + floating_ip, + fixed_ip, + affect_auto_assigned=True) self._update_state(context, instance_id) @exception.wrap_exception @@ -280,14 +278,17 @@ class ComputeManager(manager.SchedulerDependentManager): # NOTE(vish): Right now we don't really care if the ip is # disassociated. We may need to worry about # checking this later. - self.network_api.disassociate_floating_ip(context, address, - affect_auto_assigned=True) - if FLAGS.auto_assign_floating_ip \ - and floating_ip.get('auto_assigned'): + self.network_api.disassociate_floating_ip(context, + address, + True) + if (FLAGS.auto_assign_floating_ip + and floating_ip.get('auto_assigned')): LOG.debug(_("Deallocating floating ip %s"), - floating_ip['address'], context=context) - self.network_api.release_floating_ip(context, address, - affect_auto_assigned=True) + floating_ip['address'], + context=context) + self.network_api.release_floating_ip(context, + address, + True) address = fixed_ip['address'] if address: diff --git a/nova/db/sqlalchemy/migrate_repo/versions/015_add_auto_assign_to_floating_ips.py b/nova/db/sqlalchemy/migrate_repo/versions/015_add_auto_assign_to_floating_ips.py index f3767b29f..64d6df77f 100644 --- a/nova/db/sqlalchemy/migrate_repo/versions/015_add_auto_assign_to_floating_ips.py +++ b/nova/db/sqlalchemy/migrate_repo/versions/015_add_auto_assign_to_floating_ips.py @@ -22,6 +22,7 @@ from migrate import * meta = MetaData() + c_auto_assigned = Column('auto_assigned', Boolean, default=False) diff --git a/nova/network/api.py b/nova/network/api.py index 61db646ae..1d8193b28 100644 --- a/nova/network/api.py +++ b/nova/network/api.py @@ -52,7 +52,7 @@ class API(base.Base): "args": {"project_id": context.project_id}}) def release_floating_ip(self, context, address, - affect_auto_assigned = False): + affect_auto_assigned=False): floating_ip = self.db.floating_ip_get_by_address(context, address) if not affect_auto_assigned and floating_ip.get('auto_assigned'): return @@ -66,7 +66,7 @@ class API(base.Base): "args": {"floating_address": floating_ip['address']}}) def associate_floating_ip(self, context, floating_ip, fixed_ip, - affect_auto_assigned = False): + affect_auto_assigned=False): if isinstance(fixed_ip, str) or isinstance(fixed_ip, unicode): fixed_ip = self.db.fixed_ip_get_by_address(context, fixed_ip) floating_ip = self.db.floating_ip_get_by_address(context, floating_ip) @@ -97,7 +97,7 @@ class API(base.Base): "fixed_address": fixed_ip['address']}}) def disassociate_floating_ip(self, context, address, - affect_auto_assigned = False): + affect_auto_assigned=False): floating_ip = self.db.floating_ip_get_by_address(context, address) if not affect_auto_assigned and floating_ip.get('auto_assigned'): return -- cgit From ba9edf8d6d93290d1f1e85bb3a51e3a69e3f0822 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Wed, 20 Apr 2011 21:06:56 -0700 Subject: put up and down in the right dir --- doc/source/devref/down.sh | 7 +++++++ doc/source/devref/up.sh | 7 +++++++ doc/source/down.sh | 7 ------- doc/source/up.sh | 7 ------- 4 files changed, 14 insertions(+), 14 deletions(-) create mode 100644 doc/source/devref/down.sh create mode 100644 doc/source/devref/up.sh delete mode 100644 doc/source/down.sh delete mode 100644 doc/source/up.sh diff --git a/doc/source/devref/down.sh b/doc/source/devref/down.sh new file mode 100644 index 000000000..5c1888870 --- /dev/null +++ b/doc/source/devref/down.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +BR=$1 +DEV=$2 + +/usr/sbin/brctl delif $BR $DEV +/sbin/ifconfig $DEV down diff --git a/doc/source/devref/up.sh b/doc/source/devref/up.sh new file mode 100644 index 000000000..073a58e15 --- /dev/null +++ b/doc/source/devref/up.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +BR=$1 +DEV=$2 +MTU=$3 +/sbin/ifconfig $DEV mtu $MTU promisc up +/usr/sbin/brctl addif $BR $DEV diff --git a/doc/source/down.sh b/doc/source/down.sh deleted file mode 100644 index 5c1888870..000000000 --- a/doc/source/down.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -BR=$1 -DEV=$2 - -/usr/sbin/brctl delif $BR $DEV -/sbin/ifconfig $DEV down diff --git a/doc/source/up.sh b/doc/source/up.sh deleted file mode 100644 index 073a58e15..000000000 --- a/doc/source/up.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -BR=$1 -DEV=$2 -MTU=$3 -/sbin/ifconfig $DEV mtu $MTU promisc up -/usr/sbin/brctl addif $BR $DEV -- cgit From db1f6a3f2a8d85c82eb3530194e61276e7f54c6a Mon Sep 17 00:00:00 2001 From: Yoshiaki Tamura Date: Thu, 21 Apr 2011 16:54:37 +0900 Subject: Add a test checking spawn() works when network_info is set, which currently doesn't. The following patch would fix it. --- nova/tests/test_virt.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/nova/tests/test_virt.py b/nova/tests/test_virt.py index aeaea91c7..fdde6ed97 100644 --- a/nova/tests/test_virt.py +++ b/nova/tests/test_virt.py @@ -549,6 +549,43 @@ class LibvirtConnTestCase(test.TestCase): db.volume_destroy(self.context, volume_ref['id']) db.instance_destroy(self.context, instance_ref['id']) + def test_spawn_with_network_info(self): + # Skip if non-libvirt environment + if not self.lazy_load_library_exists(): + return + + # Preparing mocks + def fake_none(self, instance): + return + + self.create_fake_libvirt_mock() + instance = db.instance_create(self.context, self.test_instance) + + # Start test + self.mox.ReplayAll() + conn = libvirt_conn.LibvirtConnection(False) + conn.firewall_driver.setattr('setup_basic_filtering', fake_none) + conn.firewall_driver.setattr('prepare_instance_filter', fake_none) + + network = db.project_get_network(context.get_admin_context(), + self.project.id) + ip_dict = {'ip': self.test_ip, + 'netmask': network['netmask'], + 'enabled': '1'} + mapping = {'label': network['label'], + 'gateway': network['gateway'], + 'mac': instance['mac_address'], + 'dns': [network['dns']], + 'ips': [ip_dict]} + network_info = [(network, mapping)] + + try: + conn.spawn(instance, network_info) + except Exception, e: + count = (0 <= e.message.find('Unexpected method call')) + + self.assertTrue(count) + def tearDown(self): self.manager.delete_project(self.project) self.manager.delete_user(self.user) -- cgit From ba00a83490d6f442688d42f7f58c5f6cc566e1ee Mon Sep 17 00:00:00 2001 From: Yoshiaki Tamura Date: Thu, 21 Apr 2011 16:54:59 +0900 Subject: Fix parameter mismatch calling _create_image() from spawn() in libvirt_conn.py --- nova/virt/libvirt_conn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 9e815799f..a8de7147b 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -612,7 +612,7 @@ class LibvirtConnection(driver.ComputeDriver): 'launching') self.firewall_driver.setup_basic_filtering(instance, network_info) self.firewall_driver.prepare_instance_filter(instance, network_info) - self._create_image(instance, xml, network_info) + self._create_image(instance, xml, network_info=network_info) domain = self._create_new_domain(xml) LOG.debug(_("instance %s: is running"), instance['name']) self.firewall_driver.apply_instance_filter(instance) -- cgit From e1f37b81e805c087947c87a9bc341dd60e7e481c Mon Sep 17 00:00:00 2001 From: Eldar Nugaev Date: Thu, 21 Apr 2011 15:49:47 +0400 Subject: style fixing --- nova/compute/manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 13a082b44..864b3a816 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -48,11 +48,11 @@ from nova import exception from nova import flags from nova import log as logging from nova import manager +from nova import network from nova import rpc from nova import utils from nova.compute import power_state from nova.virt import driver -from nova import network FLAGS = flags.FLAGS flags.DEFINE_string('instances_path', '$state_path/instances', -- cgit From ea11033935192ee26ea6d0d0dad47a0a624b17a0 Mon Sep 17 00:00:00 2001 From: Jimmy Bergman Date: Thu, 21 Apr 2011 15:23:36 +0200 Subject: Add privateIpAddress and ipAddress to EC2 API DescribeInstances response. --- nova/api/ec2/cloud.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 4785d812a..4aa973290 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -726,7 +726,9 @@ class CloudController(object): instance['mac_address']) i['privateDnsName'] = fixed_addr + i['privateIpAddress'] = fixed_addr i['publicDnsName'] = floating_addr + i['ipAddress'] = floating_addr or fixed_addr i['dnsName'] = i['publicDnsName'] or i['privateDnsName'] i['keyName'] = instance['key_name'] -- cgit From e6b76ce6886a1404739a972d106248a67df4f02a Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Thu, 21 Apr 2011 07:35:30 -0700 Subject: use simpler interfaces --- doc/source/devref/interfaces | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/doc/source/devref/interfaces b/doc/source/devref/interfaces index 2aae39558..b7116aeb7 100644 --- a/doc/source/devref/interfaces +++ b/doc/source/devref/interfaces @@ -1,18 +1,17 @@ +# This file describes the network interfaces available on your system +# and how to activate them. For more information, see interfaces(5). + # The loopback network interface auto lo iface lo inet loopback # The primary network interface +auto eth0 +iface eth0 inet manual + up ifconfig $IFACE 0.0.0.0 up + down ifconfig $IFACE down + auto br0 iface br0 inet dhcp bridge_ports eth0 - bridge_fd 9 ## from the libvirt docs (forward delay time) - bridge_hello 2 ## from the libvirt docs (hello time) - bridge_maxage 12 ## from the libvirt docs (maximum message age) - bridge_stp off ## from the libvirt docs (spanning tree protocol) -iface eth0 inet manual - up ifconfig $IFACE 0.0.0.0 up - up ip link set $IFACE promisc on - down ip link set $IFACE promisc off - down ifconfig $IFACE down -- cgit From 2d82195d59240ea53d4726879d2a28a5872e58f7 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Thu, 21 Apr 2011 07:39:49 -0700 Subject: use vpn filter in basic filtering so cloudpipe works with iptables driver --- nova/virt/libvirt_conn.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 9c8d64446..3dcb8ae42 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -1734,11 +1734,16 @@ class NWFilterFirewall(FirewallDriver): logging.info('ensuring static filters') self._ensure_static_filters() + if instance['image_id'] == str(FLAGS.vpn_image_id): + base_filter = 'nova-vpn' + else: + base_filter = 'nova-base' + for (network, mapping) in network_info: nic_id = mapping['mac'].replace(':', '') instance_filter_name = self._instance_filter_name(instance, nic_id) self._define_filter(self._filter_container(instance_filter_name, - ['nova-base'])) + [base_filter])) def _ensure_static_filters(self): if self.static_filters_configured: @@ -1749,11 +1754,12 @@ class NWFilterFirewall(FirewallDriver): 'no-ip-spoofing', 'no-arp-spoofing', 'allow-dhcp-server'])) + self._define_filter(self._filter_container('nova-vpn', + ['allow-dhcp-server'])) self._define_filter(self.nova_base_ipv4_filter) self._define_filter(self.nova_base_ipv6_filter) self._define_filter(self.nova_dhcp_filter) self._define_filter(self.nova_ra_filter) - self._define_filter(self.nova_vpn_filter) if FLAGS.allow_project_net_traffic: self._define_filter(self.nova_project_filter) if FLAGS.use_ipv6: @@ -1767,14 +1773,6 @@ class NWFilterFirewall(FirewallDriver): ''.join(["" % (f,) for f in filters])) return xml - nova_vpn_filter = ''' - 2086015e-cf03-11df-8c5d-080027c27973 - - - - - ''' - def nova_base_ipv4_filter(self): retval = "" for protocol in ['tcp', 'udp', 'icmp']: -- cgit From 5904cba617038600f3d8e7f65c71485abb163927 Mon Sep 17 00:00:00 2001 From: Eldar Nugaev Date: Thu, 21 Apr 2011 22:23:40 +0400 Subject: style cleaning --- .../migrate_repo/versions/015_add_auto_assign_to_floating_ips.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nova/db/sqlalchemy/migrate_repo/versions/015_add_auto_assign_to_floating_ips.py b/nova/db/sqlalchemy/migrate_repo/versions/015_add_auto_assign_to_floating_ips.py index 64d6df77f..29b26b3dd 100644 --- a/nova/db/sqlalchemy/migrate_repo/versions/015_add_auto_assign_to_floating_ips.py +++ b/nova/db/sqlalchemy/migrate_repo/versions/015_add_auto_assign_to_floating_ips.py @@ -31,7 +31,9 @@ def upgrade(migrate_engine): # bind migrate_engine to your metadata meta.bind = migrate_engine - floating_ips = Table('floating_ips', meta, autoload=True, - autoload_with=migrate_engine) + floating_ips = Table('floating_ips', + meta, + autoload=True, + autoload_with=migrate_engine) floating_ips.create_column(c_auto_assigned) -- cgit From 8681db3aa9104f97a84a3323b102ed10af269888 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Thu, 21 Apr 2011 15:50:04 -0400 Subject: Addressing exception.NotFound across the project --- nova/api/ec2/__init__.py | 4 +- nova/api/ec2/cloud.py | 11 +- nova/api/ec2/ec2utils.py | 5 +- nova/api/openstack/common.py | 2 +- nova/api/openstack/servers.py | 6 +- nova/auth/dbdriver.py | 16 +- nova/auth/ldapdriver.py | 48 ++--- nova/auth/manager.py | 14 +- nova/compute/api.py | 8 +- nova/compute/manager.py | 5 +- nova/console/vmrc.py | 6 +- nova/db/sqlalchemy/api.py | 131 +++++++------- nova/exception.py | 291 +++++++++++++++++++++++++++++-- nova/image/fake.py | 10 +- nova/image/glance.py | 16 +- nova/image/local.py | 14 +- nova/network/vmwareapi_net.py | 7 +- nova/tests/api/openstack/test_flavors.py | 4 +- nova/tests/test_scheduler.py | 20 +-- nova/tests/test_volume.py | 2 +- nova/utils.py | 2 +- nova/virt/fake.py | 3 +- nova/virt/hyperv.py | 10 +- nova/virt/libvirt_conn.py | 5 +- nova/virt/vmwareapi/fake.py | 9 +- nova/virt/vmwareapi/vmops.py | 27 +-- nova/virt/xenapi/vm_utils.py | 6 +- nova/virt/xenapi/vmops.py | 11 +- nova/virt/xenapi/volumeops.py | 6 +- 29 files changed, 441 insertions(+), 258 deletions(-) diff --git a/nova/api/ec2/__init__.py b/nova/api/ec2/__init__.py index a3c3b25a1..e18e7f05e 100644 --- a/nova/api/ec2/__init__.py +++ b/nova/api/ec2/__init__.py @@ -322,9 +322,7 @@ class Executor(wsgi.Application): except exception.InstanceNotFound as ex: LOG.info(_('InstanceNotFound raised: %s'), unicode(ex), context=context) - ec2_id = ec2utils.id_to_ec2_id(ex.instance_id) - message = _('Instance %s not found') % ec2_id - return self._error(req, context, type(ex).__name__, message) + return self._error(req, context, type(ex).__name__, ex.message) except exception.VolumeNotFound as ex: LOG.info(_('VolumeNotFound raised: %s'), unicode(ex), context=context) diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index bd4c9dcd4..abd668ca4 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -907,11 +907,11 @@ class CloudController(object): try: internal_id = ec2utils.ec2_id_to_id(ec2_id) return self.image_service.show(context, internal_id) - except exception.NotFound: + except ValueError: try: return self.image_service.show_by_name(context, ec2_id) except exception.NotFound: - raise exception.NotFound(_('Image %s not found') % ec2_id) + raise exception.ImageNotFound(image_id=ec2_id) def _format_image(self, image): """Convert from format defined by BaseImageService to S3 format.""" @@ -955,8 +955,7 @@ class CloudController(object): try: image = self._get_image(context, ec2_id) except exception.NotFound: - raise exception.NotFound(_('Image %s not found') % - ec2_id) + raise exception.ImageNotFound(image_id=ec2_id) images.append(image) else: images = self.image_service.detail(context) @@ -990,7 +989,7 @@ class CloudController(object): try: image = self._get_image(context, image_id) except exception.NotFound: - raise exception.NotFound(_('Image %s not found') % image_id) + raise exception.ImageNotFound(image_id=image_id) result = {'imageId': image_id, 'launchPermission': []} if image['is_public']: result['launchPermission'].append({'group': 'all'}) @@ -1013,7 +1012,7 @@ class CloudController(object): try: image = self._get_image(context, image_id) except exception.NotFound: - raise exception.NotFound(_('Image %s not found') % image_id) + raise exception.ImageNotFound(image_id=image_id) internal_id = image['id'] del(image['id']) diff --git a/nova/api/ec2/ec2utils.py b/nova/api/ec2/ec2utils.py index 3b34f6ea5..1ac48163c 100644 --- a/nova/api/ec2/ec2utils.py +++ b/nova/api/ec2/ec2utils.py @@ -21,10 +21,7 @@ from nova import exception def ec2_id_to_id(ec2_id): """Convert an ec2 ID (i-[base 16 number]) to an instance id (int)""" - try: - return int(ec2_id.split('-')[-1], 16) - except ValueError: - raise exception.NotFound(_("Id %s Not Found") % ec2_id) + return int(ec2_id.split('-')[-1], 16) def id_to_ec2_id(instance_id, template='i-%08x'): diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py index 0b6dc944a..65ed1e143 100644 --- a/nova/api/openstack/common.py +++ b/nova/api/openstack/common.py @@ -124,7 +124,7 @@ def get_image_id_from_image_hash(image_service, context, image_hash): "should have numerical format") % image_id LOG.error(msg) raise Exception(msg) - raise exception.NotFound(image_hash) + raise exception.ImageNotFound(image_id=image_hash) def get_id_from_href(href): diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 2ccc6d1db..763b021a8 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -570,14 +570,12 @@ class Controller(common.OpenstackController): try: kernel_id = image_meta['properties']['kernel_id'] except KeyError: - raise exception.NotFound( - _("Kernel not found for image %(image_id)s") % locals()) + raise exception.KernelNotFoundForImage(image_id=image_id) try: ramdisk_id = image_meta['properties']['ramdisk_id'] except KeyError: - raise exception.NotFound( - _("Ramdisk not found for image %(image_id)s") % locals()) + raise exception.RamdiskNotFoundForImage(image_id=image_id) return kernel_id, ramdisk_id diff --git a/nova/auth/dbdriver.py b/nova/auth/dbdriver.py index b2c580d83..813cba36d 100644 --- a/nova/auth/dbdriver.py +++ b/nova/auth/dbdriver.py @@ -103,9 +103,7 @@ class DbDriver(object): """Create a project""" manager = db.user_get(context.get_admin_context(), manager_uid) if not manager: - raise exception.NotFound(_("Project can't be created because " - "manager %s doesn't exist") - % manager_uid) + raise exception.UserNotFound(user_id=manager_uid) # description is a required attribute if description is None: @@ -119,9 +117,7 @@ class DbDriver(object): for member_uid in member_uids: member = db.user_get(context.get_admin_context(), member_uid) if not member: - raise exception.NotFound(_("Project can't be created " - "because user %s doesn't exist") - % member_uid) + raise exception.UserNotFound(user_id=member_uid) members.add(member) values = {'id': name, @@ -154,9 +150,7 @@ class DbDriver(object): if manager_uid: manager = db.user_get(context.get_admin_context(), manager_uid) if not manager: - raise exception.NotFound(_("Project can't be modified because " - "manager %s doesn't exist") % - manager_uid) + raise exception.UserNotFound(user_id=manager_uid) values['project_manager'] = manager['id'] if description: values['description'] = description @@ -244,8 +238,8 @@ class DbDriver(object): def _validate_user_and_project(self, user_id, project_id): user = db.user_get(context.get_admin_context(), user_id) if not user: - raise exception.NotFound(_('User "%s" not found') % user_id) + raise exception.UserNotFound(user_id=user_id) project = db.project_get(context.get_admin_context(), project_id) if not project: - raise exception.NotFound(_('Project "%s" not found') % project_id) + raise exception.ProjectNotFound(project_id=project_id) return user, project diff --git a/nova/auth/ldapdriver.py b/nova/auth/ldapdriver.py index fcac55510..093462b93 100644 --- a/nova/auth/ldapdriver.py +++ b/nova/auth/ldapdriver.py @@ -202,8 +202,7 @@ class LdapDriver(object): self.conn.modify_s(self.__uid_to_dn(name), attr) return self.get_user(name) else: - raise exception.NotFound(_("LDAP object for %s doesn't exist") - % name) + raise exception.LDAPUserNotFound(user_id=name) else: attr = [ ('objectclass', ['person', @@ -229,9 +228,7 @@ class LdapDriver(object): raise exception.Duplicate(_("Project can't be created because " "project %s already exists") % name) if not self.__user_exists(manager_uid): - raise exception.NotFound(_("Project can't be created because " - "manager %s doesn't exist") - % manager_uid) + raise exception.LDAPUserNotFound(user_id=manager_uid) manager_dn = self.__uid_to_dn(manager_uid) # description is a required attribute if description is None: @@ -240,9 +237,7 @@ class LdapDriver(object): if member_uids is not None: for member_uid in member_uids: if not self.__user_exists(member_uid): - raise exception.NotFound(_("Project can't be created " - "because user %s doesn't exist") - % member_uid) + raise exception.LDAPUserNotFound(user_id=member_uid) members.append(self.__uid_to_dn(member_uid)) # always add the manager as a member because members is required if not manager_dn in members: @@ -265,9 +260,7 @@ class LdapDriver(object): attr = [] if manager_uid: if not self.__user_exists(manager_uid): - raise exception.NotFound(_("Project can't be modified because " - "manager %s doesn't exist") - % manager_uid) + raise exception.LDAPUserNotFound(user_id=manager_uid) manager_dn = self.__uid_to_dn(manager_uid) attr.append((self.ldap.MOD_REPLACE, LdapDriver.project_attribute, manager_dn)) @@ -347,7 +340,7 @@ class LdapDriver(object): def delete_user(self, uid): """Delete a user""" if not self.__user_exists(uid): - raise exception.NotFound(_("User %s doesn't exist") % uid) + raise exception.LDAPUserNotFound(user_id=uid) self.__remove_from_all(uid) if FLAGS.ldap_user_modify_only: # Delete attributes @@ -477,9 +470,7 @@ class LdapDriver(object): if member_uids is not None: for member_uid in member_uids: if not self.__user_exists(member_uid): - raise exception.NotFound(_("Group can't be created " - "because user %s doesn't exist") - % member_uid) + raise exception.LDAPUserNotFound(user_id=member_uid) members.append(self.__uid_to_dn(member_uid)) dn = self.__uid_to_dn(uid) if not dn in members: @@ -494,8 +485,7 @@ class LdapDriver(object): def __is_in_group(self, uid, group_dn): """Check if user is in group""" if not self.__user_exists(uid): - raise exception.NotFound(_("User %s can't be searched in group " - "because the user doesn't exist") % uid) + raise exception.LDAPUserNotFound(user_id=uid) if not self.__group_exists(group_dn): return False res = self.__find_object(group_dn, @@ -506,11 +496,9 @@ class LdapDriver(object): def __add_to_group(self, uid, group_dn): """Add user to group""" if not self.__user_exists(uid): - raise exception.NotFound(_("User %s can't be added to the group " - "because the user doesn't exist") % uid) + raise exception.LDAPUserNotFound(user_id=uid) if not self.__group_exists(group_dn): - raise exception.NotFound(_("The group at dn %s doesn't exist") % - group_dn) + raise exception.LDAPGroupNotFound(group_id=group_dn) if self.__is_in_group(uid, group_dn): raise exception.Duplicate(_("User %(uid)s is already a member of " "the group %(group_dn)s") % locals()) @@ -520,15 +508,12 @@ class LdapDriver(object): def __remove_from_group(self, uid, group_dn): """Remove user from group""" if not self.__group_exists(group_dn): - raise exception.NotFound(_("The group at dn %s doesn't exist") - % group_dn) + raise exception.LDAPGroupNotFound(group_id=group_dn) if not self.__user_exists(uid): - raise exception.NotFound(_("User %s can't be removed from the " - "group because the user doesn't exist") - % uid) + raise exception.LDAPUserNotFound(user_id=uid) if not self.__is_in_group(uid, group_dn): - raise exception.NotFound(_("User %s is not a member of the group") - % uid) + raise exception.LDAPGroupMembershipNotFound(user_id=uid, + group_id=group_dn) # NOTE(vish): remove user from group and any sub_groups sub_dns = self.__find_group_dns_with_member(group_dn, uid) for sub_dn in sub_dns: @@ -548,9 +533,7 @@ class LdapDriver(object): def __remove_from_all(self, uid): """Remove user from all roles and projects""" if not self.__user_exists(uid): - raise exception.NotFound(_("User %s can't be removed from all " - "because the user doesn't exist") - % uid) + raise exception.LDAPUserNotFound(user_id=uid) role_dns = self.__find_group_dns_with_member( FLAGS.role_project_subtree, uid) for role_dn in role_dns: @@ -563,8 +546,7 @@ class LdapDriver(object): def __delete_group(self, group_dn): """Delete Group""" if not self.__group_exists(group_dn): - raise exception.NotFound(_("Group at dn %s doesn't exist") - % group_dn) + raise exception.LDAPGroupNotFound(group_id=group_dn) self.conn.delete_s(group_dn) def __delete_roles(self, project_dn): diff --git a/nova/auth/manager.py b/nova/auth/manager.py index 8479c95a4..b719a0dbd 100644 --- a/nova/auth/manager.py +++ b/nova/auth/manager.py @@ -270,8 +270,7 @@ class AuthManager(object): LOG.debug('user: %r', user) if user is None: LOG.audit(_("Failed authorization for access key %s"), access_key) - raise exception.NotFound(_('No user found for access key %s') - % access_key) + raise exception.AccessKeyNotFound(access_key=access_key) # NOTE(vish): if we stop using project name as id we need better # logic to find a default project for user @@ -285,8 +284,7 @@ class AuthManager(object): uname = user.name LOG.audit(_("failed authorization: no project named %(pjid)s" " (user=%(uname)s)") % locals()) - raise exception.NotFound(_('No project called %s could be found') - % project_id) + raise exception.ProjectNotFound(project_id=project_id) if not self.is_admin(user) and not self.is_project_member(user, project): uname = user.name @@ -295,8 +293,8 @@ class AuthManager(object): pjid = project.id LOG.audit(_("Failed authorization: user %(uname)s not admin" " and not member of project %(pjname)s") % locals()) - raise exception.NotFound(_('User %(uid)s is not a member of' - ' project %(pjid)s') % locals()) + raise exception.ProjectMembershipNotFound(project_id=pjid, + user_id=uid) if check_type == 's3': sign = signer.Signer(user.secret.encode()) expected_signature = sign.s3_authorization(headers, verb, path) @@ -420,9 +418,9 @@ class AuthManager(object): @param project: Project in which to add local role. """ if role not in FLAGS.allowed_roles: - raise exception.NotFound(_("The %s role can not be found") % role) + raise exception.UserRoleNotFound(role_id=role) if project is not None and role in FLAGS.global_roles: - raise exception.NotFound(_("The %s role is global only") % role) + raise exception.GlobalRoleNotAllowed(role_id=role) uid = User.safe_id(user) pid = Project.safe_id(project) if project: diff --git a/nova/compute/api.py b/nova/compute/api.py index 264961fe3..c85f0f53a 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -507,8 +507,8 @@ class API(base.Base): migration_ref = self.db.migration_get_by_instance_and_status(context, instance_id, 'finished') if not migration_ref: - raise exception.NotFound(_("No finished migrations found for " - "instance")) + raise exception.MigrationNotFoundByStatus(instance_id=instance_id, + status='finished') params = {'migration_id': migration_ref['id']} self._cast_compute_message('revert_resize', context, instance_id, @@ -522,8 +522,8 @@ class API(base.Base): migration_ref = self.db.migration_get_by_instance_and_status(context, instance_id, 'finished') if not migration_ref: - raise exception.NotFound(_("No finished migrations found for " - "instance")) + raise exception.MigrationNotFoundByStatus(instance_id=instance_id, + status='finished') instance_ref = self.db.instance_get(context, instance_id) params = {'migration_id': migration_ref['id']} self._cast_compute_message('confirm_resize', context, instance_id, diff --git a/nova/compute/manager.py b/nova/compute/manager.py index c795d72ad..9272df3da 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -822,7 +822,7 @@ class ComputeManager(manager.SchedulerDependentManager): tmp_file = os.path.join(FLAGS.instances_path, filename) if not os.path.exists(tmp_file): - raise exception.NotFound(_('%s not found') % tmp_file) + raise exception.FileNotFound(file_path=tmp_file) @exception.wrap_exception def cleanup_shared_storage_test_file(self, context, filename): @@ -865,8 +865,7 @@ class ComputeManager(manager.SchedulerDependentManager): # Getting fixed ips fixed_ip = self.db.instance_get_fixed_address(context, instance_id) if not fixed_ip: - msg = _("%(instance_id)s(%(ec2_id)s) does not have fixed_ip.") - raise exception.NotFound(msg % locals()) + raise exception.NoFixedIpsFoundForInstance(instance_id=instance_id) # If any volume is mounted, prepare here. if not instance_ref['volumes']: diff --git a/nova/console/vmrc.py b/nova/console/vmrc.py index 521da289f..b62de347d 100644 --- a/nova/console/vmrc.py +++ b/nova/console/vmrc.py @@ -92,8 +92,7 @@ class VMRCConsole(object): vm_ds_path_name = ds_path_name break if vm_ref is None: - raise exception.NotFound(_("instance - %s not present") % - instance_name) + raise exception.InstanceNotFound(instance_id=instance_name) json_data = json.dumps({"vm_id": vm_ds_path_name, "username": username, "password": password}) @@ -127,8 +126,7 @@ class VMRCSessionConsole(VMRCConsole): if vm.propSet[0].val == instance_name: vm_ref = vm.obj if vm_ref is None: - raise exception.NotFound(_("instance - %s not present") % - instance_name) + raise exception.InstanceNotFound(instance_id=instance_name) virtual_machine_ticket = \ vim_session._call_method( vim_session._get_vim(), diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index cd6052506..0e5433490 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -137,7 +137,7 @@ def service_get(context, service_id, session=None): first() if not result: - raise exception.NotFound(_('No service for id %s') % service_id) + raise exception.ServiceNotFound(service_id=service_id) return result @@ -196,8 +196,7 @@ def service_get_all_compute_by_host(context, host): all() if not result: - raise exception.NotFound(_("%s does not exist or is not " - "a compute node.") % host) + raise exception.ComputeHostNotFound(host=host) return result @@ -284,8 +283,7 @@ def service_get_by_args(context, host, binary): filter_by(deleted=can_read_deleted(context)).\ first() if not result: - raise exception.NotFound(_('No service for %(host)s, %(binary)s') - % locals()) + raise exception.HostBinaryNotFound(host=host, binary=binary) return result @@ -323,7 +321,7 @@ def compute_node_get(context, compute_id, session=None): first() if not result: - raise exception.NotFound(_('No computeNode for id %s') % compute_id) + raise exception.ComputeHostNotFound(host=compute_id) return result @@ -359,7 +357,7 @@ def certificate_get(context, certificate_id, session=None): first() if not result: - raise exception.NotFound('No certificate for id %s' % certificate_id) + raise exception.CertificateNotFound(certificate_id=certificate_id) return result @@ -564,7 +562,7 @@ def floating_ip_get_by_address(context, address, session=None): filter_by(deleted=can_read_deleted(context)).\ first() if not result: - raise exception.NotFound('No floating ip for address %s' % address) + raise exception.FloatingIpNotFound(fixed_ip=address) return result @@ -672,7 +670,7 @@ def fixed_ip_get_all(context, session=None): session = get_session() result = session.query(models.FixedIp).all() if not result: - raise exception.NotFound(_('No fixed ips defined')) + raise exception.NoFloatingIpsDefined() return result @@ -688,7 +686,7 @@ def fixed_ip_get_all_by_host(context, host=None): all() if not result: - raise exception.NotFound(_('No fixed ips for this host defined')) + raise exception.NoFloatingIpsDefinedForHost(host=host) return result @@ -704,7 +702,7 @@ def fixed_ip_get_by_address(context, address, session=None): options(joinedload('instance')).\ first() if not result: - raise exception.NotFound(_('No floating ip for address %s') % address) + raise exception.FloatingIpNotFound(fixed_ip=address) if is_user_context(context): authorize_project_context(context, result.instance.project_id) @@ -725,7 +723,7 @@ def fixed_ip_get_all_by_instance(context, instance_id): filter_by(instance_id=instance_id).\ filter_by(deleted=False) if not rv: - raise exception.NotFound(_('No address for instance %s') % instance_id) + raise exception.NoFloatingIpsFoundForInstance(instance_id=instance_id) return rv @@ -848,9 +846,7 @@ def instance_get(context, instance_id, session=None): filter_by(deleted=False).\ first() if not result: - raise exception.InstanceNotFound(_('Instance %s not found') - % instance_id, - instance_id) + raise exception.InstanceNotFound(instance_id=instance_id) return result @@ -1126,8 +1122,7 @@ def key_pair_get(context, user_id, name, session=None): filter_by(deleted=can_read_deleted(context)).\ first() if not result: - raise exception.NotFound(_('no keypair for user %(user_id)s,' - ' name %(name)s') % locals()) + raise exception.KeypairNotFound(user_id=user_id, name=name) return result @@ -1253,7 +1248,7 @@ def network_get(context, network_id, session=None): filter_by(deleted=False).\ first() if not result: - raise exception.NotFound(_('No network for id %s') % network_id) + raise exception.NetworkNotFound(network_id=network_id) return result @@ -1263,7 +1258,7 @@ def network_get_all(context): session = get_session() result = session.query(models.Network) if not result: - raise exception.NotFound(_('No networks defined')) + raise exception.NoNetworksFound() return result @@ -1292,7 +1287,7 @@ def network_get_by_bridge(context, bridge): first() if not result: - raise exception.NotFound(_('No network for bridge %s') % bridge) + raise exception.NetworkNotFoundForBridge(bridge=bridge) return result @@ -1303,8 +1298,7 @@ def network_get_by_cidr(context, cidr): filter_by(cidr=cidr).first() if not result: - raise exception.NotFound(_('Network with cidr %s does not exist') % - cidr) + raise exception.NetworkNotFoundForCidr(cidr=cidr) return result @@ -1318,7 +1312,7 @@ def network_get_by_instance(_context, instance_id): filter_by(deleted=False).\ first() if not rv: - raise exception.NotFound(_('No network for instance %s') % instance_id) + raise exception.NetworkNotFoundForInstance(instance_id=instance_id) return rv @@ -1331,7 +1325,7 @@ def network_get_all_by_instance(_context, instance_id): filter_by(instance_id=instance_id).\ filter_by(deleted=False) if not rv: - raise exception.NotFound(_('No network for instance %s') % instance_id) + raise exception.NetworkNotFoundForInstance(instance_id=instance_id) return rv @@ -1345,7 +1339,7 @@ def network_set_host(context, network_id, host_id): with_lockmode('update').\ first() if not network_ref: - raise exception.NotFound(_('No network for id %s') % network_id) + raise exception.NetworkNotFound(network_id=network_id) # NOTE(vish): if with_lockmode isn't supported, as in sqlite, # then this has concurrency issues @@ -1470,7 +1464,7 @@ def auth_token_get(context, token_hash, session=None): filter_by(deleted=can_read_deleted(context)).\ first() if not tk: - raise exception.NotFound(_('Token %s does not exist') % token_hash) + raise exception.AuthTokenNotFound(token=token_hash) return tk @@ -1504,7 +1498,7 @@ def quota_get(context, project_id, session=None): filter_by(deleted=can_read_deleted(context)).\ first() if not result: - raise exception.NotFound(_('No quota for project_id %s') % project_id) + raise exception.ProjectQuotaNotFound(project_id=project_id) return result @@ -1659,8 +1653,7 @@ def volume_get(context, volume_id, session=None): filter_by(deleted=False).\ first() if not result: - raise exception.VolumeNotFound(_('Volume %s not found') % volume_id, - volume_id) + raise exception.VolumeNotFound(volume_id=volume_id) return result @@ -1692,7 +1685,7 @@ def volume_get_all_by_instance(context, instance_id): filter_by(deleted=False).\ all() if not result: - raise exception.NotFound(_('No volume for instance %s') % instance_id) + raise exception.VolumeNotFoundForInstance(instance_id=instance_id) return result @@ -1717,8 +1710,7 @@ def volume_get_instance(context, volume_id): options(joinedload('instance')).\ first() if not result: - raise exception.VolumeNotFound(_('Volume %s not found') % volume_id, - volume_id) + raise exception.VolumeNotFound(volume_id=volume_id) return result.instance @@ -1730,8 +1722,7 @@ def volume_get_shelf_and_blade(context, volume_id): filter_by(volume_id=volume_id).\ first() if not result: - raise exception.NotFound(_('No export device found for volume %s') % - volume_id) + raise exception.ExportDeviceNotFoundForVolume(volume_id=volume_id) return (result.shelf_id, result.blade_id) @@ -1743,8 +1734,7 @@ def volume_get_iscsi_target_num(context, volume_id): filter_by(volume_id=volume_id).\ first() if not result: - raise exception.NotFound(_('No target id found for volume %s') % - volume_id) + raise exception.ISCSITargetNotFoundForVolume(volume_id=volume_id) return result.target_num @@ -1788,8 +1778,8 @@ def security_group_get(context, security_group_id, session=None): options(joinedload_all('rules')).\ first() if not result: - raise exception.NotFound(_("No security group with id %s") % - security_group_id) + raise exception.SecurityGroupNotFound( + security_group_id=security_group_id) return result @@ -1804,9 +1794,8 @@ def security_group_get_by_name(context, project_id, group_name): options(joinedload_all('instances')).\ first() if not result: - raise exception.NotFound( - _('No security group named %(group_name)s' - ' for project: %(project_id)s') % locals()) + raise exception.SecurityGroupNotFoundForProject(project_id=project_id, + security_group_id=group_name) return result @@ -1907,8 +1896,8 @@ def security_group_rule_get(context, security_group_rule_id, session=None): filter_by(id=security_group_rule_id).\ first() if not result: - raise exception.NotFound(_("No secuity group rule with id %s") % - security_group_rule_id) + raise exception.SecurityGroupNotFoundForRule( + rule_id=security_group_rule_id) return result @@ -1981,7 +1970,7 @@ def user_get(context, id, session=None): first() if not result: - raise exception.NotFound(_('No user for id %s') % id) + raise exception.UserNotFound(user_id=id) return result @@ -1997,7 +1986,7 @@ def user_get_by_access_key(context, access_key, session=None): first() if not result: - raise exception.NotFound(_('No user for access key %s') % access_key) + raise exception.AccessKeyNotFound(access_key=access_key) return result @@ -2062,7 +2051,7 @@ def project_get(context, id, session=None): first() if not result: - raise exception.NotFound(_("No project with id %s") % id) + raise exception.ProjectNotFound(project_id=id) return result @@ -2083,7 +2072,7 @@ def project_get_by_user(context, user_id): options(joinedload_all('projects')).\ first() if not user: - raise exception.NotFound(_('Invalid user_id %s') % user_id) + raise exception.UserNotFound(user_id=user_id) return user.projects @@ -2223,8 +2212,7 @@ def migration_get(context, id, session=None): result = session.query(models.Migration).\ filter_by(id=id).first() if not result: - raise exception.NotFound(_("No migration found with id %s") - % id) + raise exception.MigrationNotFound(migration_id=id) return result @@ -2235,8 +2223,8 @@ def migration_get_by_instance_and_status(context, instance_id, status): filter_by(instance_id=instance_id).\ filter_by(status=status).first() if not result: - raise exception.NotFound(_("No migration found for instance " - "%(instance_id)s with status %(status)s") % locals()) + raise exception.MigrationNotFoundByStatus(instance_id=instance_id, + status=status) return result @@ -2257,8 +2245,7 @@ def console_pool_get(context, pool_id): filter_by(id=pool_id).\ first() if not result: - raise exception.NotFound(_("No console pool with id %(pool_id)s") - % locals()) + raise exception.ConsolePoolNotFound(pool_id=pool_id) return result @@ -2274,9 +2261,9 @@ def console_pool_get_by_host_type(context, compute_host, host, options(joinedload('consoles')).\ first() if not result: - raise exception.NotFound(_('No console pool of type %(console_type)s ' - 'for compute host %(compute_host)s ' - 'on proxy host %(host)s') % locals()) + raise exception.ConsolePoolNotFoundForHostType(host=host, + console_type=console_type, + compute_host=compute_host ) return result @@ -2314,8 +2301,8 @@ def console_get_by_pool_instance(context, pool_id, instance_id): options(joinedload('pool')).\ first() if not result: - raise exception.NotFound(_('No console for instance %(instance_id)s ' - 'in pool %(pool_id)s') % locals()) + raise exception.ConsoleNotFoundInPoolForInstance(pool_id=pool_id, + instance_id=instance_id) return result @@ -2336,9 +2323,11 @@ def console_get(context, console_id, instance_id=None): query = query.filter_by(instance_id=instance_id) result = query.options(joinedload('pool')).first() if not result: - idesc = (_("on instance %s") % instance_id) if instance_id else "" - raise exception.NotFound(_("No console with id %(console_id)s" - " %(idesc)s") % locals()) + if instance_id: + raise exception.ConsoleNotFoundForInstance(console_id=console_id, + instance_id=instance_id) + else: + raise exception.ConsoleNotFound(console_id=console_id) return result @@ -2377,7 +2366,7 @@ def instance_type_get_all(context, inactive=False): inst_dict[i['name']] = dict(i) return inst_dict else: - raise exception.NotFound + raise exception.NoInstanceTypesFound() @require_context @@ -2388,7 +2377,7 @@ def instance_type_get_by_id(context, id): filter_by(id=id).\ first() if not inst_type: - raise exception.NotFound(_("No instance type with id %s") % id) + raise exception.InstanceTypeNotFound(instance_type=id) else: return dict(inst_type) @@ -2401,7 +2390,7 @@ def instance_type_get_by_name(context, name): filter_by(name=name).\ first() if not inst_type: - raise exception.NotFound(_("No instance type with name %s") % name) + raise exception.InstanceTypeNotFoundByName(instance_type_name=name) else: return dict(inst_type) @@ -2414,7 +2403,7 @@ def instance_type_get_by_flavor_id(context, id): filter_by(flavorid=int(id)).\ first() if not inst_type: - raise exception.NotFound(_("No flavor with flavorid %s") % id) + raise exception.FlavorNotFound(flavor_id=id) else: return dict(inst_type) @@ -2427,7 +2416,7 @@ def instance_type_destroy(context, name): filter_by(name=name) records = instance_type_ref.update(dict(deleted=True)) if records == 0: - raise exception.NotFound + raise exception.InstanceTypeNotFoundByName(instance_type_name=name) else: return instance_type_ref @@ -2442,7 +2431,7 @@ def instance_type_purge(context, name): filter_by(name=name) records = instance_type_ref.delete() if records == 0: - raise exception.NotFound + raise exception.InstanceTypeNotFoundByName(instance_type_name=name) else: return instance_type_ref @@ -2463,7 +2452,7 @@ def zone_update(context, zone_id, values): session = get_session() zone = session.query(models.Zone).filter_by(id=zone_id).first() if not zone: - raise exception.NotFound(_("No zone with id %(zone_id)s") % locals()) + raise exception.ZoneNotFound(zone_id=zone_id) zone.update(values) zone.save() return zone @@ -2483,7 +2472,7 @@ def zone_get(context, zone_id): session = get_session() result = session.query(models.Zone).filter_by(id=zone_id).first() if not result: - raise exception.NotFound(_("No zone with id %(zone_id)s") % locals()) + raise exception.ZoneNotFound(zone_id=zone_id) return result @@ -2533,8 +2522,8 @@ def instance_metadata_get_item(context, instance_id, key): first() if not meta_result: - raise exception.NotFound(_('Invalid metadata key for instance %s') % - instance_id) + raise exception.InstanceMetadataNotFound(metadata_key=key, + instance_id=instance_id) return meta_result diff --git a/nova/exception.py b/nova/exception.py index 6948a93c1..88f6bfcce 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -52,22 +52,6 @@ class ApiError(Error): super(ApiError, self).__init__('%s: %s' % (code, message)) -class NotFound(Error): - pass - - -class InstanceNotFound(NotFound): - def __init__(self, message, instance_id): - self.instance_id = instance_id - super(InstanceNotFound, self).__init__(message) - - -class VolumeNotFound(NotFound): - def __init__(self, message, volume_id): - self.volume_id = volume_id - super(VolumeNotFound, self).__init__(message) - - class Duplicate(Error): pass @@ -160,6 +144,10 @@ class InstanceNotSuspended(Invalid): message = _("Instance %(instance_id)s is not suspended.") +class InstanceNotInRescueMode(Invalid): + message = _("Instance %(instance_id)s is not in rescue mode") + + class InstanceSuspendFailure(Invalid): message = _("Failed to suspend instance") + ": %(reason)s" @@ -223,5 +211,276 @@ class InvalidVLANPortGroup(Invalid): "is %(actual)s.") +class InvalidDiskFormat(Invalid): + message = _("Disk format %(disk_format)s is not acceptable") + + class ImageUnacceptable(Invalid): message = _("Image %(image_id)s is unacceptable") + ": %(reason)s" + + +class InstanceUnacceptable(Invalid): + message = _("Instance %(instance_id)s is unacceptable") + ": %(reason)s" + + +class NotFound(NovaException): + message = _("Resource could not be found.") + + def __init__(self, *args, **kwargs): + super(NotFound, self).__init__(**kwargs) + + +class InstanceNotFound(NotFound): + message = _("Instance %(instance_id)s could not be found.") + + +class VolumeNotFound(NotFound): + message = _("Volume %(volume_id)s could not be found.") + + +class VolumeNotFoundForInstance(VolumeNotFound): + message = _("Volume not found for instance %(instance_id)s.") + + +class ExportDeviceNotFoundForVolume(NotFound): + message = _("No export device found for volume %(volume_id)s.") + + +class ISCSITargetNotFoundForVolume(NotFound): + message = _("No target id found for volume %(volume_id)s.") + + +class DiskNotFound(NotFound): + message = _("No disk at %(location)s") + + +class ImageNotFound(NotFound): + message = _("Image %(image_id)s could not be found.") + + +class KernelNotFoundForImage(ImageNotFound): + message = _("Kernel not found for image %(image_id)s.") + + +class RamdiskNotFoundForImage(ImageNotFound): + message = _("Ramdisk not found for image %(image_id)s.") + + +class UserNotFound(NotFound): + message = _("User %(user_id)s could not be found.") + + +class ProjectNotFound(NotFound): + message = _("Project %(project_id)s could not be found.") + + +class ProjectMembershipNotFound(NotFound): + message = _("User %(user_id)s is not a member of project %(project_id)s.") + + +class UserRoleNotFound(NotFound): + message = _("Role %(role_id)s could not be found.") + + +class StorageRepositoryNotFound(NotFound): + message = _("Cannot find SR to read/write VDI.") + + +class NetworkNotFound(NotFound): + message = _("Network %(network_id)s could not be found.") + + +class NetworkNotFoundForBridge(NetworkNotFound): + message = _("Network could not be found for bridge %(bridge)s") + + +class NetworkNotFoundForCidr(NetworkNotFound): + message = _("Network could not be found with cidr %(cidr)s.") + + +class NetworkNotFoundForInstance(NetworkNotFound): + message = _("Network could not be found for instance %(instance_id)s.") + + +class NoNetworksFound(NotFound): + message = _("No networks defined.") + + +class DatastoreNotFound(NotFound): + message = _("Could not find the datastore reference(s) which the VM uses.") + + +class NoFixedIpsFoundForInstance(NotFound): + message = _("Instance %(instance_id)s has zero fixed ips.") + + +class FloatingIpNotFound(NotFound): + message = _("Floating ip not found for fixed address %(fixed_ip)s.") + + +class NoFloatingIpsDefined(NotFound): + message = _("Zero floating ips could be found.") + + +class NoFloatingIpsDefinedForHost(NoFloatingIpsDefined): + message = _("Zero floating ips defined for host %(host)s.") + + +class NoFloatingIpsDefinedForInstance(NoFloatingIpsDefined): + message = _("Zero floating ips defined for instance %(instance_id)s.") + + +class KeypairNotFound(NotFound): + message = _("Keypair %(keypair_name)s not found for user %(user_id)s") + + +class CertificateNotFound(NotFound): + message = _("Certificate %(certificate_id)s not found.") + + +class ServiceNotFound(NotFound): + message = _("Service %(service_id)s could not be found.") + + +class HostNotFound(NotFound): + message = _("Host %(host)s could not be found.") + + +class ComputeHostNotFound(HostNotFound): + message = _("Compute host %(host)s could not be found.") + + +class HostBinaryNotFound(NotFound): + message = _("Could not find binary %(binary)s on host %(host)s.") + + +class AuthTokenNotFound(NotFound): + message = _("Auth token %(token)s could not be found.") + + +class AccessKeyNotFound(NotFound): + message = _("Access Key %(access_key)s could not be found.") + + +class QuotaNotFound(NotFound): + message = _("Quota could not be found") + + +class ProjectQuotaNotFound(QuotaNotFound): + message = _("Quota for project %(project_id)s could not be found.") + + +class SecurityGroupNotFound(NotFound): + message = _("Security group %(security_group_id)s not found.") + + +class SecurityGroupNotFoundForProject(SecurityGroupNotFound): + message = _("Security group %(security_group_id)s not found " + "for project %(project_id)s.") + + +class SecurityGroupNotFoundForRule(SecurityGroupNotFound): + message = _("Security group with rule %(rule_id)s not found.") + + +class MigrationNotFound(NotFound): + message = _("Migration %(migration_id)s could not be found.") + + +class MigrationNotFoundByStatus(MigrationNotFound): + message = _("Migration not found for instance %(instance_id)s " + "with status %(status)s.") + + +class ConsolePoolNotFound(NotFound): + message = _("Console pool %(pool_id)s could not be found.") + + +class ConsolePoolNotFoundForHostType(NotFound): + message = _("Console pool of type %(console_type)s " + "for compute host %(compute_host)s " + "on proxy host %(host)s not found.") + + +class ConsoleNotFound(NotFound): + message = _("Console %(console_id)s could not be found.") + + +class ConsoleNotFoundForInstance(ConsoleNotFound): + message = _("Console for instance %(instance_id)s could not be found.") + + +class ConsoleNotFoundInPoolForInstance(ConsoleNotFound): + message = _("Console for instance %(instance_id)s " + "in pool %(pool_id)s could not be found.") + + +class NoInstanceTypesFound(NotFound): + message = _("Zero instance types found.") + + +class InstanceTypeNotFound(NotFound): + message = _("Instance type %(instance_type_id)s could not be found.") + + +class InstanceTypeNotFoundByName(InstanceTypeNotFound): + message = _("Instance type with name %(instance_type_name)s " + "could not be found.") + + +class FlavorNotFound(NotFound): + message = _("Flavor %(flavor_id)s could not be found.") + + +class ZoneNotFound(NotFound): + message = _("Zone %(zone_id)s could not be found.") + + +class InstanceMetadataNotFound(NotFound): + message = _("Instance %(instance_id)s has no metadata with " + "key %(metadata_key)s.") + + +class LDAPObjectNotFound(NotFound): + message = _("LDAP object could not be found") + + +class LDAPUserNotFound(LDAPObjectNotFound): + message = _("LDAP user %(user_id)s could not be found.") + + +class LDAPGroupNotFound(LDAPObjectNotFound): + message = _("LDAP group %(group_id)s could not be found.") + + +class LDAPGroupMembershipNotFound(NotFound): + message = _("LDAP user %(user_id)s is not a member of group %(group_id)s.") + + +class FileNotFound(NotFound): + message = _("File %(file_path)s could not be found.") + + +class NoFilesFound(NotFound): + message = _("Zero files could be found.") + + +class SwitchNotFoundForNetworkAdapter(NotFound): + message = _("Virtual switch associated with the " + "network adapter %(adapter)s not found.") + + +class NetworkAdapterNotFound(NotFound): + message = _("Network adapter %(adapter)s could not be found.") + + +class ClassNotFound(NotFound): + message = _("Class %(class_name)s could not be found") + + +class NotAllowed(NovaException): + message = _("Action not allowed.") + + +class GlobalRoleNotAllowed(NotAllowed): + message = _("Unable to use global role %(role_id)s") diff --git a/nova/image/fake.py b/nova/image/fake.py index e02b4127e..c0b98d68f 100644 --- a/nova/image/fake.py +++ b/nova/image/fake.py @@ -71,7 +71,7 @@ class FakeImageService(service.BaseImageService): return copy.deepcopy(image) LOG.warn("Unable to find image id %s. Have images: %s", image_id, self.images) - raise exception.NotFound + raise exception.ImageNotFound(image_id=image_id) def create(self, context, data): """Store the image data and return the new image id. @@ -88,24 +88,24 @@ class FakeImageService(service.BaseImageService): def update(self, context, image_id, data): """Replace the contents of the given image with the new data. - :raises NotFound if the image does not exist. + :raises ImageNotFound if the image does not exist. """ image_id = int(image_id) if not self.images.get(image_id): - raise exception.NotFound + raise exception.ImageNotFound(image_id=image_id) self.images[image_id] = copy.deepcopy(data) def delete(self, context, image_id): """Delete the given image. - :raises NotFound if the image does not exist. + :raises ImageNotFound if the image does not exist. """ image_id = int(image_id) removed = self.images.pop(image_id, None) if not removed: - raise exception.NotFound + raise exception.ImageNotFound(image_id=image_id) def delete_all(self): """Clears out all images.""" diff --git a/nova/image/glance.py b/nova/image/glance.py index 1a80bb2af..2f1716239 100644 --- a/nova/image/glance.py +++ b/nova/image/glance.py @@ -89,10 +89,10 @@ class GlanceImageService(service.BaseImageService): try: image_meta = self.client.get_image_meta(image_id) except glance_exception.NotFound: - raise exception.NotFound + raise exception.ImageNotFound(image_id=image_id) if not self._is_image_available(context, image_meta): - raise exception.NotFound + raise exception.ImageNotFound(image_id=image_id) base_image_meta = self._translate_to_base(image_meta) return base_image_meta @@ -107,7 +107,7 @@ class GlanceImageService(service.BaseImageService): for image_meta in image_metas: if name == image_meta.get('name'): return image_meta - raise exception.NotFound + raise exception.ImageNotFound(image_id=name) def get(self, context, image_id, data): """ @@ -116,7 +116,7 @@ class GlanceImageService(service.BaseImageService): try: image_meta, image_chunks = self.client.get_image(image_id) except glance_exception.NotFound: - raise exception.NotFound + raise exception.ImageNotFound(image_id=image_id) for chunk in image_chunks: data.write(chunk) @@ -149,14 +149,14 @@ class GlanceImageService(service.BaseImageService): def update(self, context, image_id, image_meta, data=None): """Replace the contents of the given image with the new data. - :raises NotFound if the image does not exist. + :raises ImageNotFound if the image does not exist. """ # NOTE(vish): show is to check if image is available self.show(context, image_id) try: image_meta = self.client.update_image(image_id, image_meta, data) except glance_exception.NotFound: - raise exception.NotFound + raise exception.ImageNotFound(image_id=image_id) base_image_meta = self._translate_to_base(image_meta) return base_image_meta @@ -165,14 +165,14 @@ class GlanceImageService(service.BaseImageService): """ Delete the given image. - :raises NotFound if the image does not exist. + :raises ImageNotFound if the image does not exist. """ # NOTE(vish): show is to check if image is available self.show(context, image_id) try: result = self.client.delete_image(image_id) except glance_exception.NotFound: - raise exception.NotFound + raise exception.ImageNotFound(image_id=image_id) return result def delete_all(self): diff --git a/nova/image/local.py b/nova/image/local.py index fa5e93346..5d1ff6b3e 100644 --- a/nova/image/local.py +++ b/nova/image/local.py @@ -86,10 +86,10 @@ class LocalImageService(service.BaseImageService): with open(self._path_to(image_id)) as metadata_file: image_meta = json.load(metadata_file) if not self._is_image_available(context, image_meta): - raise exception.NotFound + raise exception.ImageNotFound(image_id=image_id) return image_meta except (IOError, ValueError): - raise exception.NotFound + raise exception.ImageNotFound(image_id=image_id) def show_by_name(self, context, name): """Returns a dict containing image data for the given name.""" @@ -102,7 +102,7 @@ class LocalImageService(service.BaseImageService): image = cantidate break if image is None: - raise exception.NotFound + raise exception.ImageNotFound(image_id=image_id) return image def get(self, context, image_id, data): @@ -113,7 +113,7 @@ class LocalImageService(service.BaseImageService): with open(self._path_to(image_id, 'image')) as image_file: shutil.copyfileobj(image_file, data) except (IOError, ValueError): - raise exception.NotFound + raise exception.ImageNotFound(image_id=image_id) return metadata def create(self, context, metadata, data=None): @@ -143,12 +143,12 @@ class LocalImageService(service.BaseImageService): with open(self._path_to(image_id), 'w') as metadata_file: json.dump(metadata, metadata_file) except (IOError, ValueError): - raise exception.NotFound + raise exception.ImageNotFound(image_id=image_id) return metadata def delete(self, context, image_id): """Delete the given image. - Raises NotFound if the image does not exist. + Raises ImageNotFound if the image does not exist. """ # NOTE(vish): show is to check if image is available @@ -156,7 +156,7 @@ class LocalImageService(service.BaseImageService): try: shutil.rmtree(self._path_to(image_id, None)) except (IOError, ValueError): - raise exception.NotFound + raise exception.ImageNotFound(image_id=image_id) def delete_all(self): """Clears out all images in local directory.""" diff --git a/nova/network/vmwareapi_net.py b/nova/network/vmwareapi_net.py index 6e1ed480b..9b2db7b8f 100644 --- a/nova/network/vmwareapi_net.py +++ b/nova/network/vmwareapi_net.py @@ -52,16 +52,13 @@ def ensure_vlan_bridge(vlan_num, bridge, net_attrs=None): # Check if the vlan_interface physical network adapter exists on the host if not network_utils.check_if_vlan_interface_exists(session, vlan_interface): - raise exception.NotFound(_("There is no physical network adapter with " - "the name %s on the ESX host") % vlan_interface) + raise exception.NetworkAdapterNotFound(adapter=vlan_interface) # Get the vSwitch associated with the Physical Adapter vswitch_associated = network_utils.get_vswitch_for_vlan_interface( session, vlan_interface) if vswitch_associated is None: - raise exception.NotFound(_("There is no virtual switch associated " - "with the physical network adapter with name %s") % - vlan_interface) + raise exception.SwicthNotFoundForNetworkAdapter(adapter=vlan_interface) # Check whether bridge already exists and retrieve the the ref of the # network whose name_label is "bridge" network_ref = network_utils.get_network_with_the_name(session, bridge) diff --git a/nova/tests/api/openstack/test_flavors.py b/nova/tests/api/openstack/test_flavors.py index 954d72adf..d1c62e454 100644 --- a/nova/tests/api/openstack/test_flavors.py +++ b/nova/tests/api/openstack/test_flavors.py @@ -47,8 +47,8 @@ def return_instance_types(context, num=2): return instance_types -def return_instance_type_not_found(context, flavorid): - raise exception.NotFound() +def return_instance_type_not_found(context, flavor_id): + raise exception.InstanceTypeNotFound(flavor_id=flavor_id) class FlavorsTest(test.TestCase): diff --git a/nova/tests/test_scheduler.py b/nova/tests/test_scheduler.py index 42ea19d6e..efd12f930 100644 --- a/nova/tests/test_scheduler.py +++ b/nova/tests/test_scheduler.py @@ -120,12 +120,11 @@ class SchedulerTestCase(test.TestCase): dest = 'dummydest' ctxt = context.get_admin_context() - try: - scheduler.show_host_resources(ctxt, dest) - except exception.NotFound, e: - c1 = (e.message.find(_("does not exist or is not a " - "compute node.")) >= 0) - self.assertTrue(c1) + self.assertRaises(exception.NotFound, scheduler.show_host_resources, + ctxt, dest) + #TODO(bcwaldon): reimplement this functionality + #c1 = (e.message.find(_("does not exist or is not a " + # "compute node.")) >= 0) def _dic_is_equal(self, dic1, dic2, keys=None): """Compares 2 dictionary contents(Helper method)""" @@ -941,7 +940,7 @@ class FakeRerouteCompute(api.reroute_compute): def go_boom(self, context, instance): - raise exception.InstanceNotFound("boom message", instance) + raise exception.InstanceNotFound(instance_id=instance) def found_instance(self, context, instance): @@ -990,11 +989,8 @@ class ZoneRedirectTest(test.TestCase): def test_routing_flags(self): FLAGS.enable_zone_routing = False decorator = FakeRerouteCompute("foo") - try: - result = decorator(go_boom)(None, None, 1) - self.assertFail(_("Should have thrown exception.")) - except exception.InstanceNotFound, e: - self.assertEquals(e.message, 'boom message') + self.assertRaises(exception.InstanceNotFound, decorator(go_boom), + None, None, 1) def test_get_collection_context_and_id(self): decorator = api.reroute_compute("foo") diff --git a/nova/tests/test_volume.py b/nova/tests/test_volume.py index e9d8289aa..236d12434 100644 --- a/nova/tests/test_volume.py +++ b/nova/tests/test_volume.py @@ -142,7 +142,7 @@ class VolumeTestCase(test.TestCase): self.assertEqual(vol['status'], "available") self.volume.delete_volume(self.context, volume_id) - self.assertRaises(exception.Error, + self.assertRaises(exception.VolumeNotFound, db.volume_get, self.context, volume_id) diff --git a/nova/utils.py b/nova/utils.py index 76cba1a08..372b1df38 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -63,7 +63,7 @@ def import_class(import_str): return getattr(sys.modules[mod_str], class_str) except (ImportError, ValueError, AttributeError), exc: LOG.debug(_('Inner Exception: %s'), exc) - raise exception.NotFound(_('Class %s cannot be found') % class_str) + raise exception.ClassNotFound(class_name=class_str) def import_object(import_str): diff --git a/nova/virt/fake.py b/nova/virt/fake.py index c3d5230df..33f37b512 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -288,8 +288,7 @@ class FakeConnection(driver.ComputeDriver): knowledge of the instance """ if instance_name not in self.instances: - raise exception.NotFound(_("Instance %s Not Found") - % instance_name) + raise exception.InstanceNotFound(instance_id=instance_name) i = self.instances[instance_name] return {'state': i.state, 'max_mem': 0, diff --git a/nova/virt/hyperv.py b/nova/virt/hyperv.py index 13f403a66..507ea5457 100644 --- a/nova/virt/hyperv.py +++ b/nova/virt/hyperv.py @@ -368,7 +368,7 @@ class HyperVConnection(driver.ComputeDriver): """Reboot the specified instance.""" vm = self._lookup(instance.name) if vm is None: - raise exception.NotFound('instance not present %s' % instance.name) + raise exception.InstanceNotFound(instance_id=instance.id) self._set_vm_state(instance.name, 'Reboot') def destroy(self, instance): @@ -412,7 +412,7 @@ class HyperVConnection(driver.ComputeDriver): """Get information about the VM""" vm = self._lookup(instance_id) if vm is None: - raise exception.NotFound('instance not present %s' % instance_id) + raise exception.InstanceNotFound(instance_id=instance_id) vm = self._conn.Msvm_ComputerSystem(ElementName=instance_id)[0] vs_man_svc = self._conn.Msvm_VirtualSystemManagementService()[0] vmsettings = vm.associators( @@ -474,14 +474,12 @@ class HyperVConnection(driver.ComputeDriver): def attach_volume(self, instance_name, device_path, mountpoint): vm = self._lookup(instance_name) if vm is None: - raise exception.NotFound('Cannot attach volume to missing %s vm' - % instance_name) + raise exception.InstanceNotFound(instance_id=instance_name) def detach_volume(self, instance_name, mountpoint): vm = self._lookup(instance_name) if vm is None: - raise exception.NotFound('Cannot detach volume from missing %s ' - % instance_name) + raise exception.InstanceNotFound(instance_id=instance_name) def poll_rescued_instances(self, timeout): pass diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 55e1d4295..705b6380c 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -449,7 +449,7 @@ class LibvirtConnection(driver.ComputeDriver): mount_device = mountpoint.rpartition("/")[2] xml = self._get_disk_xml(virt_dom.XMLDesc(0), mount_device) if not xml: - raise exception.NotFound(_("No disk at %s") % mount_device) + raise exception.DiskNotFound(location=mount_device) virt_dom.detachDevice(xml) @exception.wrap_exception @@ -1054,8 +1054,7 @@ class LibvirtConnection(driver.ComputeDriver): except libvirt.libvirtError as e: errcode = e.get_error_code() if errcode == libvirt.VIR_ERR_NO_DOMAIN: - raise exception.NotFound(_("Instance %s not found") - % instance_name) + raise exception.InstanceNotFound(instance_id=instance_name) LOG.warning(_("Error from libvirt during lookup. " "Code=%(errcode)s Error=%(e)s") % locals()) diff --git a/nova/virt/vmwareapi/fake.py b/nova/virt/vmwareapi/fake.py index 4bb467fa9..7370684bd 100644 --- a/nova/virt/vmwareapi/fake.py +++ b/nova/virt/vmwareapi/fake.py @@ -387,12 +387,11 @@ def _add_file(file_path): def _remove_file(file_path): """Removes a file reference from the db.""" if _db_content.get("files") is None: - raise exception.NotFound(_("No files have been added yet")) + raise exception.NoFilesFound() # Check if the remove is for a single file object or for a folder if file_path.find(".vmdk") != -1: if file_path not in _db_content.get("files"): - raise exception.NotFound(_("File- '%s' is not there in the " - "datastore") % file_path) + raise exception.FileNotFound(file_path=file_path) _db_content.get("files").remove(file_path) else: # Removes the files in the folder and the folder too from the db @@ -579,7 +578,7 @@ class FakeVim(object): """Searches the datastore for a file.""" ds_path = kwargs.get("datastorePath") if _db_content.get("files", None) is None: - raise exception.NotFound(_("No files have been added yet")) + raise exception.NoFilesFound() for file in _db_content.get("files"): if file.find(ds_path) != -1: task_mdo = create_task(method, "success") @@ -591,7 +590,7 @@ class FakeVim(object): """Creates a directory in the datastore.""" ds_path = kwargs.get("name") if _db_content.get("files", None) is None: - raise exception.NotFound(_("No files have been added yet")) + raise exception.NoFilesFound() _db_content["files"].append(ds_path) def _set_power_state(self, method, vm_ref, pwr_state="poweredOn"): diff --git a/nova/virt/vmwareapi/vmops.py b/nova/virt/vmwareapi/vmops.py index b700c438f..033a511f8 100644 --- a/nova/virt/vmwareapi/vmops.py +++ b/nova/virt/vmwareapi/vmops.py @@ -116,8 +116,7 @@ class VMWareVMOps(object): network_utils.get_network_with_the_name(self._session, net_name) if network_ref is None: - raise exception.NotFound(_("Network with the name '%s' doesn't" - " exist on the ESX host") % net_name) + raise exception.NetworkNotFoundForBridge(bridge=net_name) _check_if_network_bridge_exists() @@ -337,8 +336,7 @@ class VMWareVMOps(object): """ vm_ref = self._get_vm_ref_from_the_name(instance.name) if vm_ref is None: - raise exception.NotFound(_("instance - %s not present") % - instance.name) + raise exception.InstanceNotFound(instance_id=instance.id) client_factory = self._session._get_vim().client.factory service_content = self._session._get_vim().get_service_content() @@ -388,8 +386,7 @@ class VMWareVMOps(object): "VirtualMachine", "datastore") if not ds_ref_ret: - raise exception.NotFound(_("Failed to get the datastore " - "reference(s) which the VM uses")) + raise exception.DatastoreNotFound() ds_ref = ds_ref_ret.ManagedObjectReference[0] ds_browser = vim_util.get_dynamic_property( self._session._get_vim(), @@ -480,8 +477,7 @@ class VMWareVMOps(object): """Reboot a VM instance.""" vm_ref = self._get_vm_ref_from_the_name(instance.name) if vm_ref is None: - raise exception.NotFound(_("instance - %s not present") % - instance.name) + raise exception.InstanceNotFound(instance_id=instance.id) lst_properties = ["summary.guest.toolsStatus", "runtime.powerState", "summary.guest.toolsRunningStatus"] props = self._session._call_method(vim_util, "get_object_properties", @@ -605,8 +601,7 @@ class VMWareVMOps(object): """Suspend the specified instance.""" vm_ref = self._get_vm_ref_from_the_name(instance.name) if vm_ref is None: - raise exception.NotFound(_("instance - %s not present") % - instance.name) + raise exception.InstanceNotFound(instance_id=instance.id) pwr_state = self._session._call_method(vim_util, "get_dynamic_property", vm_ref, @@ -630,8 +625,7 @@ class VMWareVMOps(object): """Resume the specified instance.""" vm_ref = self._get_vm_ref_from_the_name(instance.name) if vm_ref is None: - raise exception.NotFound(_("instance - %s not present") % - instance.name) + raise exception.InstanceNotFound(instance_id=instance.id) pwr_state = self._session._call_method(vim_util, "get_dynamic_property", vm_ref, @@ -651,8 +645,7 @@ class VMWareVMOps(object): """Return data about the VM instance.""" vm_ref = self._get_vm_ref_from_the_name(instance_name) if vm_ref is None: - raise exception.NotFound(_("instance - %s not present") % - instance_name) + raise exception.InstanceNotFound(instance_id=instance_name) lst_properties = ["summary.config.numCpu", "summary.config.memorySizeMB", @@ -688,8 +681,7 @@ class VMWareVMOps(object): """Return snapshot of console.""" vm_ref = self._get_vm_ref_from_the_name(instance.name) if vm_ref is None: - raise exception.NotFound(_("instance - %s not present") % - instance.name) + raise exception.InstanceNotFound(instance_id=instance.id) param_list = {"id": str(vm_ref)} base_url = "%s://%s/screen?%s" % (self._session._scheme, self._session._host_ip, @@ -717,8 +709,7 @@ class VMWareVMOps(object): """ vm_ref = self._get_vm_ref_from_the_name(instance.name) if vm_ref is None: - raise exception.NotFound(_("instance - %s not present") % - instance.name) + raise exception.InstanceNotFound(instance_id=instance.id) network = db.network_get_by_instance(context.get_admin_context(), instance['id']) mac_addr = instance.mac_address diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index 1927500ad..8f30a6d7c 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -506,9 +506,7 @@ class VMHelper(HelperBase): try: return glance_disk_format2nova_type[disk_format] except KeyError: - raise exception.NotFound( - _("Unrecognized disk_format '%(disk_format)s'") - % locals()) + raise exception.InvalidDiskFormat(disk_format=disk_format) def determine_from_instance(): if instance.kernel_id: @@ -853,7 +851,7 @@ def safe_find_sr(session): """ sr_ref = find_sr(session) if sr_ref is None: - raise exception.NotFound(_('Cannot find SR to read/write VDI')) + raise exception.StorageRepositoryNotFound() return sr_ref diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 8b6a35f74..69b1a163d 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -260,8 +260,7 @@ class VMOps(object): instance_name = instance_or_vm.name vm_ref = VMHelper.lookup(self._session, instance_name) if vm_ref is None: - raise exception.NotFound( - _('Instance not present %s') % instance_name) + raise exception.InstanceNotFound(instance_id=instance_obj.id) return vm_ref def _acquire_bootlock(self, vm): @@ -578,9 +577,8 @@ class VMOps(object): if not (instance.kernel_id and instance.ramdisk_id): # 2. We only have kernel xor ramdisk - raise exception.NotFound( - _("Instance %(instance_id)s has a kernel or ramdisk but not " - "both" % locals())) + raise exception.InstanceUnacceptable(instance_id=instance_id, + reason=_("instance has a kernel or ramdisk but not both")) # 3. We have both kernel and ramdisk (kernel, ramdisk) = VMHelper.lookup_kernel_ramdisk(self._session, @@ -721,8 +719,7 @@ class VMOps(object): "%s-rescue" % instance.name) if not rescue_vm_ref: - raise exception.NotFound(_( - "Instance is not in Rescue Mode: %s" % instance.name)) + raise exception.InstanceNotInRescueMode(instance_id=instance.id) original_vm_ref = VMHelper.lookup(self._session, instance.name) instance._rescue = False diff --git a/nova/virt/xenapi/volumeops.py b/nova/virt/xenapi/volumeops.py index 757ecf5ad..afcb8cf47 100644 --- a/nova/virt/xenapi/volumeops.py +++ b/nova/virt/xenapi/volumeops.py @@ -45,8 +45,7 @@ class VolumeOps(object): # Before we start, check that the VM exists vm_ref = VMHelper.lookup(self._session, instance_name) if vm_ref is None: - raise exception.NotFound(_('Instance %s not found') - % instance_name) + raise exception.InstanceNotFound(instance_id=instance_name) # NOTE: No Resource Pool concept so far LOG.debug(_("Attach_volume: %(instance_name)s, %(device_path)s," " %(mountpoint)s") % locals()) @@ -98,8 +97,7 @@ class VolumeOps(object): # Before we start, check that the VM exists vm_ref = VMHelper.lookup(self._session, instance_name) if vm_ref is None: - raise exception.NotFound(_('Instance %s not found') - % instance_name) + raise exception.InstanceNotFound(instance_id=instance_name) # Detach VBD from VM LOG.debug(_("Detach_volume: %(instance_name)s, %(mountpoint)s") % locals()) -- cgit From dc4beede6bda3b7db5ca5963cc6c48052d2b7c62 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Thu, 21 Apr 2011 23:45:02 -0700 Subject: Fixes per review --- nova/auth/manager.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nova/auth/manager.py b/nova/auth/manager.py index 3de2ceffe..4d4bdbce9 100644 --- a/nova/auth/manager.py +++ b/nova/auth/manager.py @@ -368,10 +368,10 @@ class AuthManager(object): return True def _build_mc_key(self, user, role, project=None): - role_key = str("rolecache-%s-%s" % (User.safe_id(user), role)) + key_parts = ['rolecache', User.safe_id(user), str(role)] if project: - return "%s-%s" % (role_key, Project.safe_id(project)) - return role_key + key_parts.append(Project.safe_id(project)) + return '-'.join(key_parts) def _clear_mc_key(self, user, role, project=None): # NOTE(anthony): it would be better to delete the key @@ -380,7 +380,7 @@ class AuthManager(object): def _has_role(self, user, role, project=None): mc_key = self._build_mc_key(user, role, project) rslt = self.mc.get(mc_key) - if rslt == None: + if rslt is None: with self.driver() as drv: rslt = drv.has_role(user, role, project) self.mc.set(mc_key, rslt) -- cgit From f710ad1e3fff16de696f608986f24bdc8ffc3f6b Mon Sep 17 00:00:00 2001 From: Ken Pepple Date: Fri, 22 Apr 2011 00:22:23 -0700 Subject: pep8 --- nova/compute/instance_types.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nova/compute/instance_types.py b/nova/compute/instance_types.py index 4e250bb83..7e7198b96 100644 --- a/nova/compute/instance_types.py +++ b/nova/compute/instance_types.py @@ -57,8 +57,8 @@ def create(name, memory, vcpus, local_gb, flavorid, swap=0, except exception.DBError, e: LOG.exception(_('DB error: %s') % e) raise exception.ApiError(_("Cannot create instance_type with " - "name %(name)s and flavorid %(flavorid)s") % - locals()) + "name %(name)s and flavorid %(flavorid)s") + % locals()) def destroy(name): -- cgit From 7168812fdf56280f24dc977c5dd9c7a73959c2a2 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Fri, 22 Apr 2011 13:30:13 -0400 Subject: adding gettext to setup.py --- setup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.py b/setup.py index 6c45109bc..194b55183 100644 --- a/setup.py +++ b/setup.py @@ -16,6 +16,7 @@ # License for the specific language governing permissions and limitations # under the License. +import gettext import glob import os import subprocess @@ -33,6 +34,7 @@ except ImportError: assert DistUtilsExtra.auto.__version__ >= '2.18',\ 'needs DistUtilsExtra.auto >= 2.18' +gettext.install('nova', unicode=1) from nova.utils import parse_mailmap, str_dict_replace from nova import version -- cgit From c2ec2054a6b42b086580c6647ae0d5d808b4d2c7 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Fri, 22 Apr 2011 15:14:36 -0400 Subject: fixing bad merge --- nova/virt/libvirt_conn.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index ee0b7ab98..7a78ce9e2 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -619,10 +619,6 @@ class LibvirtConnection(driver.ComputeDriver): @exception.wrap_exception def spawn(self, instance, network_info=None): xml = self.to_xml(instance, False, network_info) - db.instance_set_state(context.get_admin_context(), - instance['id'], - power_state.NOSTATE, - 'launching') self.firewall_driver.setup_basic_filtering(instance, network_info) self.firewall_driver.prepare_instance_filter(instance, network_info) self._create_image(instance, xml, network_info) -- cgit From a3f16d7efbdc51c75c1a729d9194ee3a66841bab Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Fri, 22 Apr 2011 15:49:37 -0400 Subject: pep8 --- nova/db/sqlalchemy/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index edfd3ce77..0d4fe61bf 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -2270,7 +2270,7 @@ def console_pool_get_by_host_type(context, compute_host, host, if not result: raise exception.ConsolePoolNotFoundForHostType(host=host, console_type=console_type, - compute_host=compute_host ) + compute_host=compute_host) return result -- cgit From c95aaaaefe11048990021d376dbca6460f19248c Mon Sep 17 00:00:00 2001 From: "jaypipes@gmail.com" <> Date: Tue, 26 Apr 2011 14:17:09 -0700 Subject: Make the import of distutils.extra non-mandatory in setup.py. Just print a warning that i18n commands are not available... --- setup.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/setup.py b/setup.py index 194b55183..c165f40d7 100644 --- a/setup.py +++ b/setup.py @@ -25,14 +25,18 @@ import sys from setuptools import find_packages from setuptools.command.sdist import sdist +# In order to run the i18n commands for compiling and +# installing message catalogs, we use DistUtilsExtra. +# Don't make this a hard requirement, but warn that +# i18n commands won't be available if DistUtilsExtra is +# not installed... try: - import DistUtilsExtra.auto + from DistUtilsExtra.auto import setup except ImportError: - print >> sys.stderr, 'To build nova you need '\ - 'https://launchpad.net/python-distutils-extra' - sys.exit(1) -assert DistUtilsExtra.auto.__version__ >= '2.18',\ - 'needs DistUtilsExtra.auto >= 2.18' + from setuptools import setup + print "Warning: DistUtilsExtra required to use i18n builders. " + print "To build nova with support for message catalogs, you need " + print " https://launchpad.net/python-distutils-extra >= 2.18" gettext.install('nova', unicode=1) @@ -102,7 +106,7 @@ def find_data_files(destdir, srcdir): package_data += [(destdir, files)] return package_data -DistUtilsExtra.auto.setup(name='nova', +setup(name='nova', version=version.canonical_version_string(), description='cloud computing fabric controller', author='OpenStack', -- cgit From 475453e9981d4d71a0639afc176629163abfc818 Mon Sep 17 00:00:00 2001 From: Todd Willey Date: Tue, 26 Apr 2011 18:55:13 -0400 Subject: Let nova-mange limit project list by user. --- bin/nova-manage | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/nova-manage b/bin/nova-manage index c8230670a..820b10e26 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -385,10 +385,10 @@ class ProjectCommands(object): with open(filename, 'w') as f: f.write(rc) - def list(self): + def list(self, username=None): """Lists all projects - arguments: """ - for project in self.manager.get_projects(): + arguments: [username]""" + for project in self.manager.get_projects(username): print project.name def quota(self, project_id, key=None, value=None): -- cgit From 8e6875e8c9b45a03396d5e4312c4f9136b1dc552 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Wed, 27 Apr 2011 14:03:05 -0700 Subject: further cleanup of nova/exceptions.py --- nova/api/ec2/cloud.py | 8 ++-- nova/api/openstack/accounts.py | 2 +- nova/api/openstack/users.py | 2 +- nova/auth/manager.py | 6 ++- nova/compute/instance_types.py | 12 +++--- nova/db/sqlalchemy/api.py | 4 +- nova/exception.py | 78 ++++++++++++++++++++------------------- nova/scheduler/driver.py | 8 ++-- nova/tests/test_instance_types.py | 6 +-- nova/tests/test_scheduler.py | 10 ++--- nova/virt/libvirt_conn.py | 3 +- nova/wsgi.py | 5 +-- 12 files changed, 69 insertions(+), 75 deletions(-) diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 94fbf19ff..092b80fa2 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -49,8 +49,6 @@ flags.DECLARE('service_down_time', 'nova.scheduler.driver') LOG = logging.getLogger("nova.api.cloud") -InvalidInputException = exception.InvalidInputException - def _gen_key(context, user_id, key_name): """Generate a key @@ -398,11 +396,11 @@ class CloudController(object): ip_protocol = str(ip_protocol) if ip_protocol.upper() not in ['TCP', 'UDP', 'ICMP']: - raise InvalidInputException(_('%s is not a valid ipProtocol') % - (ip_protocol,)) + raise exception.InvalidIpProtocol(protocol=ip_protocol) if ((min(from_port, to_port) < -1) or (max(from_port, to_port) > 65535)): - raise InvalidInputException(_('Invalid port range')) + raise exception.InvalidPortRange(from_port=from_port, + to_port=to_port) values['protocol'] = ip_protocol values['from_port'] = from_port diff --git a/nova/api/openstack/accounts.py b/nova/api/openstack/accounts.py index 6e3763e47..00fdd4540 100644 --- a/nova/api/openstack/accounts.py +++ b/nova/api/openstack/accounts.py @@ -48,7 +48,7 @@ class Controller(common.OpenstackController): """We cannot depend on the db layer to check for admin access for the auth manager, so we do it here""" if not context.is_admin: - raise exception.NotAuthorized(_("Not admin user.")) + raise exception.AdminRequired() def index(self, req): raise faults.Fault(webob.exc.HTTPNotImplemented()) diff --git a/nova/api/openstack/users.py b/nova/api/openstack/users.py index 077ccfc79..7ae4c3232 100644 --- a/nova/api/openstack/users.py +++ b/nova/api/openstack/users.py @@ -48,7 +48,7 @@ class Controller(common.OpenstackController): """We cannot depend on the db layer to check for admin access for the auth manager, so we do it here""" if not context.is_admin: - raise exception.NotAuthorized(_("Not admin user")) + raise exception.AdminRequired() def index(self, req): """Return all users in brief""" diff --git a/nova/auth/manager.py b/nova/auth/manager.py index b719a0dbd..72566717e 100644 --- a/nova/auth/manager.py +++ b/nova/auth/manager.py @@ -303,7 +303,8 @@ class AuthManager(object): LOG.debug('signature: %s', signature) if signature != expected_signature: LOG.audit(_("Invalid signature for user %s"), user.name) - raise exception.NotAuthorized(_('Signature does not match')) + raise exception.InvalidSignature(signature=signature, + user=user) elif check_type == 'ec2': # NOTE(vish): hmac can't handle unicode, so encode ensures that # secret isn't unicode @@ -314,7 +315,8 @@ class AuthManager(object): LOG.debug('signature: %s', signature) if signature != expected_signature: LOG.audit(_("Invalid signature for user %s"), user.name) - raise exception.NotAuthorized(_('Signature does not match')) + raise exception.InvalidSignature(signature=signature, + user=user) return (user, project) def get_access_key(self, user, project): diff --git a/nova/compute/instance_types.py b/nova/compute/instance_types.py index 7e7198b96..8cfa2f8da 100644 --- a/nova/compute/instance_types.py +++ b/nova/compute/instance_types.py @@ -37,11 +37,11 @@ def create(name, memory, vcpus, local_gb, flavorid, swap=0, try: int(option) except ValueError: - raise exception.InvalidInputException( - _("create arguments must be positive integers")) + raise exception.InvalidInput(reason=_("create arguments must " + "be positive integers")) if (int(memory) <= 0) or (int(vcpus) <= 0) or (int(local_gb) < 0): - raise exception.InvalidInputException( - _("create arguments must be positive integers")) + raise exception.InvalidInput(reason=_("create arguments must " + "be positive integers")) try: db.instance_type_create( @@ -64,7 +64,7 @@ def create(name, memory, vcpus, local_gb, flavorid, swap=0, def destroy(name): """Marks instance types as deleted.""" if name is None: - raise exception.InvalidInputException(_("No instance type specified")) + raise exception.InstanceNotFound(instance_id=instance_name) else: try: db.instance_type_destroy(context.get_admin_context(), name) @@ -76,7 +76,7 @@ def destroy(name): def purge(name): """Removes instance types from database.""" if name is None: - raise exception.InvalidInputException(_("No instance type specified")) + raise exception.InnstanceNotFound(instance_id=name) else: try: db.instance_type_purge(context.get_admin_context(), name) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 0d4fe61bf..31daa1f43 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -94,7 +94,7 @@ def require_admin_context(f): """ def wrapper(*args, **kwargs): if not is_admin_context(args[0]): - raise exception.NotAuthorized() + raise exception.AdminRequired() return f(*args, **kwargs) return wrapper @@ -105,7 +105,7 @@ def require_context(f): """ def wrapper(*args, **kwargs): if not is_admin_context(args[0]) and not is_user_context(args[0]): - raise exception.NotAuthorized() + raise exception.AdminRequired() return f(*args, **kwargs) return wrapper diff --git a/nova/exception.py b/nova/exception.py index 67b9d95ef..e8444cb14 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -55,42 +55,6 @@ class ApiError(Error): super(ApiError, self).__init__('%s: %s' % (code, message)) -class NotFound(Error): - pass - - -class InstanceNotFound(NotFound): - def __init__(self, message, instance_id): - self.instance_id = instance_id - super(InstanceNotFound, self).__init__(message) - - -class VolumeNotFound(NotFound): - def __init__(self, message, volume_id): - self.volume_id = volume_id - super(VolumeNotFound, self).__init__(message) - - -class NotAuthorized(Error): - pass - - -class NotEmpty(Error): - pass - - -class InvalidInputException(Error): - pass - - -class InvalidContentType(Error): - pass - - -class TimeoutException(Error): - pass - - class DBError(Error): """Wraps an implementation specific exception.""" def __init__(self, inner_exception): @@ -146,9 +110,43 @@ class NovaException(Exception): return self._error_string -#TODO(bcwaldon): EOL this exception! +class NotAuthorized(NovaException): + message = _("Not authorized.") + + def __init__(self, *args, **kwargs): + super(NotFound, self).__init__(**kwargs) + + +class AdminRequired(NotAuthorized): + message = _("User does not have admin privileges") + + class Invalid(NovaException): - pass + message = _("Unacceptable parameters.") + + +class InvalidSignature(Invalid): + message = _("Invalid signature %(signature)s for user %(user)s.") + + +class InvalidInput(Invalid): + message = _("Invalid input received") + ": %(reason)s" + + +class InvalidInstanceType(Invalid): + message = _("Invalid instance type %(instance_type)s.") + + +class InvalidPortRange(Invalid): + message = _("Invalid port range %(from_port)s:%(to_port)s.") + + +class InvalidIpProtocol(Invalid): + message = _("Invalid IP protocol %(protocol)s.") + + +class InvalidContentType(Invalid): + message = _("Invalid content type %(content_type)s.") class InstanceNotRunning(Invalid): @@ -533,3 +531,7 @@ class ProjectExists(Duplicate): class InstanceExists(Duplicate): message = _("Instance %(name)s already exists.") + + +class MigrationError(NovaException): + message = _("Migration error") + ": %(reason)s" diff --git a/nova/scheduler/driver.py b/nova/scheduler/driver.py index 87b10e940..2094e3565 100644 --- a/nova/scheduler/driver.py +++ b/nova/scheduler/driver.py @@ -255,11 +255,9 @@ class Scheduler(object): mem_avail = mem_total - mem_used mem_inst = instance_ref['memory_mb'] if mem_avail <= mem_inst: - raise exception.NotEmpty(_("Unable to migrate %(ec2_id)s " - "to destination: %(dest)s " - "(host:%(mem_avail)s " - "<= instance:%(mem_inst)s)") - % locals()) + reason = _("Unable to migrate %(ec2_id)s to destination: %(dest)s " + "(host:%(mem_avail)s <= instance:%(mem_inst)s)") + raise exception.MigrationError(reason=reason % locals()) def mounted_on_same_shared_storage(self, context, instance_ref, dest): """Check if the src and dest host mount same shared storage. diff --git a/nova/tests/test_instance_types.py b/nova/tests/test_instance_types.py index dd7d0737e..ef271518c 100644 --- a/nova/tests/test_instance_types.py +++ b/nova/tests/test_instance_types.py @@ -75,13 +75,13 @@ class InstanceTypeTestCase(test.TestCase): def test_invalid_create_args_should_fail(self): """Ensures that instance type creation fails with invalid args""" self.assertRaises( - exception.InvalidInputException, + exception.InvalidInput, instance_types.create, self.name, 0, 1, 120, self.flavorid) self.assertRaises( - exception.InvalidInputException, + exception.InvalidInput, instance_types.create, self.name, 256, -1, 120, self.flavorid) self.assertRaises( - exception.InvalidInputException, + exception.InvalidInput, instance_types.create, self.name, 256, 1, "aa", self.flavorid) def test_non_existant_inst_type_shouldnt_delete(self): diff --git a/nova/tests/test_scheduler.py b/nova/tests/test_scheduler.py index efd12f930..968ef9d6c 100644 --- a/nova/tests/test_scheduler.py +++ b/nova/tests/test_scheduler.py @@ -768,14 +768,10 @@ class SimpleDriverTestCase(test.TestCase): s_ref = self._create_compute_service(host='somewhere', memory_mb_used=12) - try: - self.scheduler.driver._live_migration_dest_check(self.context, - i_ref, - 'somewhere') - except exception.NotEmpty, e: - c = (e.message.find('Unable to migrate') >= 0) + self.assertRaises(exception.MigrationError, + self.scheduler.driver._live_migration_dest_check, + self.context, i_ref, 'somewhere') - self.assertTrue(c) db.instance_destroy(self.context, instance_id) db.service_destroy(self.context, s_ref['id']) diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 15adcccee..8cb971d95 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -1059,8 +1059,7 @@ class LibvirtConnection(driver.ComputeDriver): except libvirt.libvirtError as ex: error_code = ex.get_error_code() if error_code == libvirt.VIR_ERR_NO_DOMAIN: - msg = _("Instance %s not found") % instance_name - raise exception.NotFound(msg) + raise exception.InstanceNotFound(instance_id=instance_name) msg = _("Error from libvirt while looking up %(instance_name)s: " "[Error Code %(error_code)s] %(ex)s") % locals() diff --git a/nova/wsgi.py b/nova/wsgi.py index f3f82b36a..e60a8820d 100644 --- a/nova/wsgi.py +++ b/nova/wsgi.py @@ -428,7 +428,7 @@ class Serializer(object): try: return handlers[content_type] except Exception: - raise exception.InvalidContentType() + raise exception.InvalidContentType(content_type=content_type) def serialize(self, data, content_type): """Serialize a dictionary into the specified content type.""" @@ -451,8 +451,7 @@ class Serializer(object): try: return handlers[content_type] except Exception: - raise exception.InvalidContentType(_('Invalid content type %s' - % content_type)) + raise exception.InvalidContentType(content_type=content_type) def _from_json(self, datastring): return utils.loads(datastring) -- cgit From 0fe36c8ba3e524e490c66011c0787ea8a26dcfee Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Wed, 27 Apr 2011 14:23:21 -0700 Subject: Correcting exception case --- nova/compute/instance_types.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nova/compute/instance_types.py b/nova/compute/instance_types.py index 8cfa2f8da..1275a6fdd 100644 --- a/nova/compute/instance_types.py +++ b/nova/compute/instance_types.py @@ -64,7 +64,7 @@ def create(name, memory, vcpus, local_gb, flavorid, swap=0, def destroy(name): """Marks instance types as deleted.""" if name is None: - raise exception.InstanceNotFound(instance_id=instance_name) + raise exception.InvalidInstanceType(instance_type=name) else: try: db.instance_type_destroy(context.get_admin_context(), name) @@ -76,7 +76,7 @@ def destroy(name): def purge(name): """Removes instance types from database.""" if name is None: - raise exception.InnstanceNotFound(instance_id=name) + raise exception.InvalidInstanceType(instance_type=name) else: try: db.instance_type_purge(context.get_admin_context(), name) -- cgit From 95ee288d3498c478248afdea649eef1aa58fe2f2 Mon Sep 17 00:00:00 2001 From: Ken Pepple Date: Wed, 27 Apr 2011 20:33:55 -0700 Subject: added nova version output to usage printout for nova-manage --- bin/nova-manage | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bin/nova-manage b/bin/nova-manage index c8230670a..898255fb9 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -82,6 +82,7 @@ from nova import log as logging from nova import quota from nova import rpc from nova import utils +from nova import version from nova.api.ec2 import ec2utils from nova.auth import manager from nova.cloudpipe import pipelib @@ -1091,6 +1092,8 @@ def main(): script_name = argv.pop(0) if len(argv) < 1: + print _("\nOpenStack Nova version: %s (%s)\n") %\ + (version.version_string(), version.version_string_with_vcs()) print script_name + " category action []" print _("Available categories:") for k, _v in CATEGORIES: -- cgit From 0ab13f16af693fc7eee200aadc951c99241f86fa Mon Sep 17 00:00:00 2001 From: Ken Pepple Date: Thu, 28 Apr 2011 10:26:43 -0700 Subject: added version list command to nova-manage --- bin/nova-manage | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/bin/nova-manage b/bin/nova-manage index 898255fb9..ad2960d14 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -759,6 +759,16 @@ class DbCommands(object): print migration.db_version() +class VersionCommands(object): + """Class for managing the database.""" + + def __init__(self): + pass + + def list(self): + print _("%s (%s)") %\ + (version.version_string(), version.version_string_with_vcs()) + class VolumeCommands(object): """Methods for dealing with a cloud in an odd state""" @@ -1050,7 +1060,8 @@ CATEGORIES = [ ('volume', VolumeCommands), ('instance_type', InstanceTypeCommands), ('image', ImageCommands), - ('flavor', InstanceTypeCommands)] + ('flavor', InstanceTypeCommands), + ('version', VersionCommands)] def lazy_match(name, key_value_tuples): -- cgit From ae50200f9a5a72cab7d976e5dd7fda287c54341f Mon Sep 17 00:00:00 2001 From: Ken Pepple Date: Thu, 28 Apr 2011 12:49:07 -0700 Subject: fixed docstring per jsb --- bin/nova-manage | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/nova-manage b/bin/nova-manage index ad2960d14..d2d81e5af 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -760,7 +760,7 @@ class DbCommands(object): class VersionCommands(object): - """Class for managing the database.""" + """Class for exposing the codebase version.""" def __init__(self): pass -- cgit From ad077fc137cc6a1dfdcd60349560abb94f4cc8eb Mon Sep 17 00:00:00 2001 From: Ken Pepple Date: Thu, 28 Apr 2011 12:49:48 -0700 Subject: pep8 --- bin/nova-manage | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/nova-manage b/bin/nova-manage index d2d81e5af..8122e6745 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -769,6 +769,7 @@ class VersionCommands(object): print _("%s (%s)") %\ (version.version_string(), version.version_string_with_vcs()) + class VolumeCommands(object): """Methods for dealing with a cloud in an odd state""" -- cgit From ba43fe874a959e677c2d02583d261d8136c9ff8e Mon Sep 17 00:00:00 2001 From: Ken Pepple Date: Thu, 28 Apr 2011 13:37:30 -0700 Subject: converted 1/0 comparison to True/False for Postgres compatibility --- nova/db/sqlalchemy/api.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 0d4fe61bf..aa341949d 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -816,17 +816,17 @@ def instance_destroy(context, instance_id): with session.begin(): session.query(models.Instance).\ filter_by(id=instance_id).\ - update({'deleted': 1, + update({'deleted': True, 'deleted_at': datetime.datetime.utcnow(), 'updated_at': literal_column('updated_at')}) session.query(models.SecurityGroupInstanceAssociation).\ filter_by(instance_id=instance_id).\ - update({'deleted': 1, + update({'deleted': True, 'deleted_at': datetime.datetime.utcnow(), 'updated_at': literal_column('updated_at')}) session.query(models.InstanceMetadata).\ filter_by(instance_id=instance_id).\ - update({'deleted': 1, + update({'deleted': True, 'deleted_at': datetime.datetime.utcnow(), 'updated_at': literal_column('updated_at')}) @@ -2513,7 +2513,7 @@ def instance_metadata_delete(context, instance_id, key): filter_by(instance_id=instance_id).\ filter_by(key=key).\ filter_by(deleted=False).\ - update({'deleted': 1, + update({'deleted': True, 'deleted_at': datetime.datetime.utcnow(), 'updated_at': literal_column('updated_at')}) -- cgit