From 655eb8fbd21376e694f8134e42f10ddbc1aafb0e Mon Sep 17 00:00:00 2001 From: John Tran Date: Wed, 6 Apr 2011 18:22:03 -0700 Subject: ec2 api run_instances checks for image status must be 'available'. Overhauled test_run_instances for working set of test assertions --- nova/api/ec2/cloud.py | 10 +++++++- nova/tests/test_cloud.py | 62 +++++++++++++++++++++++++----------------------- 2 files changed, 41 insertions(+), 31 deletions(-) diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 58effd134..0ea0e3603 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -814,10 +814,18 @@ class CloudController(object): if kwargs.get('ramdisk_id'): ramdisk = self._get_image(context, kwargs['ramdisk_id']) kwargs['ramdisk_id'] = ramdisk['id'] + image = self._get_image(context, kwargs['image_id']) + if not image: + raise exception.NotFound(_('Image %s not found') % + kwargs['image_id']) + if not 'properties' in image or \ + (not 'image_state' in image['properties']) or \ + (image['properties']['image_state'] is not 'available'): + raise exception.ApiError(_('Image must be available')) instances = self.compute_api.create(context, instance_type=instance_types.get_by_type( kwargs.get('instance_type', None)), - image_id=self._get_image(context, kwargs['image_id'])['id'], + image_id = image['id'], min_count=int(kwargs.get('min_count', max_count)), max_count=max_count, kernel_id=kwargs.get('kernel_id'), diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py index 5cb969979..85f3a8e87 100644 --- a/nova/tests/test_cloud.py +++ b/nova/tests/test_cloud.py @@ -36,12 +36,12 @@ from nova import rpc from nova import service from nova import test from nova import utils +from nova import exception from nova.auth import manager from nova.compute import power_state from nova.api.ec2 import cloud from nova.api.ec2 import ec2utils from nova.image import local -from nova.exception import NotFound FLAGS = flags.FLAGS @@ -226,7 +226,7 @@ class CloudTestCase(test.TestCase): 'type': 'machine'}}] def fake_show_none(meh, context, id): - raise NotFound + raise exception.NotFound self.stubs.Set(local.LocalImageService, 'detail', fake_detail) # list all @@ -244,7 +244,7 @@ class CloudTestCase(test.TestCase): self.stubs.UnsetAll() self.stubs.Set(local.LocalImageService, 'show', fake_show_none) self.stubs.Set(local.LocalImageService, 'show_by_name', fake_show_none) - self.assertRaises(NotFound, describe_images, + self.assertRaises(exception.NotFound, describe_images, self.context, ['ami-fake']) def test_console_output(self): @@ -307,39 +307,41 @@ class CloudTestCase(test.TestCase): self.cloud.delete_key_pair(self.context, 'test') def test_run_instances(self): - if FLAGS.connection_type == 'fake': - LOG.debug(_("Can't test instances without a real virtual env.")) - return + allinst = db.instance_get_all(context.get_admin_context()) + self.assertEqual(0, len(allinst)) + def fake_show_decrypt(meh, context, id): + return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1, + 'type': 'machine', 'image_state': 'decrypting'}} + + def fake_show_avail(meh, context, id): + return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1, + 'type': 'machine', 'image_state': 'available'}} + image_id = FLAGS.default_image instance_type = FLAGS.default_instance_type max_count = 1 kwargs = {'image_id': image_id, 'instance_type': instance_type, 'max_count': max_count} - rv = self.cloud.run_instances(self.context, **kwargs) - # TODO: check for proper response - instance_id = rv['reservationSet'][0].keys()[0] - instance = rv['reservationSet'][0][instance_id][0] - LOG.debug(_("Need to watch instance %s until it's running..."), - instance['instance_id']) - while True: - greenthread.sleep(1) - info = self.cloud._get_instance(instance['instance_id']) - LOG.debug(info['state']) - if info['state'] == power_state.RUNNING: - break - self.assert_(rv) - - if FLAGS.connection_type != 'fake': - time.sleep(45) # Should use boto for polling here - for reservations in rv['reservationSet']: - # for res_id in reservations.keys(): - # LOG.debug(reservations[res_id]) - # for instance in reservations[res_id]: - for instance in reservations[reservations.keys()[0]]: - instance_id = instance['instance_id'] - LOG.debug(_("Terminating instance %s"), instance_id) - rv = self.compute.terminate_instance(instance_id) + run_instances = self.cloud.run_instances + # when image doesn't have 'image_state' attr at all + self.assertRaises(exception.ApiError, run_instances, + self.context, **kwargs) + # when image has 'image_state' yet not 'available' + self.stubs.UnsetAll() + self.stubs.Set(local.LocalImageService, 'show', fake_show_decrypt) + self.assertRaises(exception.ApiError, run_instances, + self.context, **kwargs) + # when image has valid image_state + self.stubs.UnsetAll() + self.stubs.Set(local.LocalImageService, 'show', fake_show_avail) + result = run_instances(self.context, **kwargs) + instance = result['instancesSet'][0] + self.assertEqual(instance['imageId'], 'ami-00000001') + self.assertEqual(instance['displayName'], 'Server 1') + self.assertEqual(instance['instanceId'], 'i-00000001') + self.assertEqual(instance['instanceState']['name'], 'scheduling') + self.assertEqual(instance['instanceType'], 'm1.small') def test_update_of_instance_display_fields(self): inst = db.instance_create(self.context, {}) -- cgit From 10db492376a8bb8409e3fb3c33707865ac0f3ee7 Mon Sep 17 00:00:00 2001 From: John Tran Date: Mon, 2 May 2011 14:25:21 -0700 Subject: implemented review suggestion EAFP style, and fixed test stub fake_show needs to have image_state = available or other tests will fail --- nova/api/ec2/cloud.py | 14 +++++++++----- nova/tests/test_cloud.py | 35 ++++++++++++++++++----------------- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 0ea0e3603..5dc608139 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -815,17 +815,21 @@ class CloudController(object): ramdisk = self._get_image(context, kwargs['ramdisk_id']) kwargs['ramdisk_id'] = ramdisk['id'] image = self._get_image(context, kwargs['image_id']) - if not image: + if not image: raise exception.NotFound(_('Image %s not found') % kwargs['image_id']) - if not 'properties' in image or \ - (not 'image_state' in image['properties']) or \ - (image['properties']['image_state'] is not 'available'): + try: + available = (image['properties']['image_state'] == 'available') + except KeyError: + available = False + + if not available: raise exception.ApiError(_('Image must be available')) + instances = self.compute_api.create(context, instance_type=instance_types.get_by_type( kwargs.get('instance_type', None)), - image_id = image['id'], + image_id=image['id'], min_count=int(kwargs.get('min_count', max_count)), max_count=max_count, kernel_id=kwargs.get('kernel_id'), diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py index 85f3a8e87..da2fce06b 100644 --- a/nova/tests/test_cloud.py +++ b/nova/tests/test_cloud.py @@ -30,13 +30,13 @@ from eventlet import greenthread from nova import context from nova import crypto from nova import db +from nova import exception from nova import flags from nova import log as logging from nova import rpc from nova import service from nova import test from nova import utils -from nova import exception from nova.auth import manager from nova.compute import power_state from nova.api.ec2 import cloud @@ -73,7 +73,7 @@ class CloudTestCase(test.TestCase): def fake_show(meh, context, id): return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1, - 'type': 'machine'}} + 'type': 'machine', 'image_state': 'available'}} self.stubs.Set(local.LocalImageService, 'show', fake_show) self.stubs.Set(local.LocalImageService, 'show_by_name', fake_show) @@ -307,15 +307,16 @@ class CloudTestCase(test.TestCase): self.cloud.delete_key_pair(self.context, 'test') def test_run_instances(self): - allinst = db.instance_get_all(context.get_admin_context()) - self.assertEqual(0, len(allinst)) - def fake_show_decrypt(meh, context, id): + all_instances = db.instance_get_all(context.get_admin_context()) + self.assertEqual(0, len(all_instances)) + + def fake_show_decrypt(self, context, id): return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1, 'type': 'machine', 'image_state': 'decrypting'}} - def fake_show_avail(meh, context, id): + def fake_show_no_state(self, context, id): return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1, - 'type': 'machine', 'image_state': 'available'}} + 'type': 'machine'}} image_id = FLAGS.default_image instance_type = FLAGS.default_instance_type @@ -324,17 +325,7 @@ class CloudTestCase(test.TestCase): 'instance_type': instance_type, 'max_count': max_count} run_instances = self.cloud.run_instances - # when image doesn't have 'image_state' attr at all - self.assertRaises(exception.ApiError, run_instances, - self.context, **kwargs) - # when image has 'image_state' yet not 'available' - self.stubs.UnsetAll() - self.stubs.Set(local.LocalImageService, 'show', fake_show_decrypt) - self.assertRaises(exception.ApiError, run_instances, - self.context, **kwargs) # when image has valid image_state - self.stubs.UnsetAll() - self.stubs.Set(local.LocalImageService, 'show', fake_show_avail) result = run_instances(self.context, **kwargs) instance = result['instancesSet'][0] self.assertEqual(instance['imageId'], 'ami-00000001') @@ -342,6 +333,16 @@ class CloudTestCase(test.TestCase): self.assertEqual(instance['instanceId'], 'i-00000001') self.assertEqual(instance['instanceState']['name'], 'scheduling') self.assertEqual(instance['instanceType'], 'm1.small') + # when image doesn't have 'image_state' attr at all + self.stubs.UnsetAll() + self.stubs.Set(local.LocalImageService, 'show', fake_show_no_state) + self.assertRaises(exception.ApiError, run_instances, + self.context, **kwargs) + # when image has 'image_state' yet not 'available' + self.stubs.UnsetAll() + self.stubs.Set(local.LocalImageService, 'show', fake_show_decrypt) + self.assertRaises(exception.ApiError, run_instances, + self.context, **kwargs) def test_update_of_instance_display_fields(self): inst = db.instance_create(self.context, {}) -- cgit From 0a3da155228228d3f0eeac1efdea1e29eef2f3a0 Mon Sep 17 00:00:00 2001 From: John Tran Date: Thu, 12 May 2011 12:04:39 -0700 Subject: changed NotFound exception to ImageNotFound --- nova/api/ec2/cloud.py | 3 +-- nova/tests/test_cloud.py | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 8a54d23f2..ad8c3fe90 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -823,8 +823,7 @@ class CloudController(object): kwargs['ramdisk_id'] = ramdisk['id'] image = self._get_image(context, kwargs['image_id']) if not image: - raise exception.NotFound(_('Image %s not found') % - kwargs['image_id']) + raise exception.ImageNotFound(kwargs['image_id']) try: available = (image['properties']['image_state'] == 'available') except KeyError: diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py index 202dc36bc..ebfb5ee44 100644 --- a/nova/tests/test_cloud.py +++ b/nova/tests/test_cloud.py @@ -227,7 +227,7 @@ class CloudTestCase(test.TestCase): 'type': 'machine'}}] def fake_show_none(meh, context, id): - raise exception.NotFound + raise exception.ImageNotFound self.stubs.Set(local.LocalImageService, 'detail', fake_detail) # list all @@ -245,7 +245,7 @@ class CloudTestCase(test.TestCase): self.stubs.UnsetAll() self.stubs.Set(local.LocalImageService, 'show', fake_show_none) self.stubs.Set(local.LocalImageService, 'show_by_name', fake_show_none) - self.assertRaises(exception.NotFound, describe_images, + self.assertRaises(exception.ImageNotFound, describe_images, self.context, ['ami-fake']) def test_describe_image_attribute(self): -- cgit From 7a521f49f6daf0a0a37a9ef98ff1ea8813f04a6f Mon Sep 17 00:00:00 2001 From: John Tran Date: Mon, 23 May 2011 14:54:11 -0700 Subject: merged from trunk --- nova/tests/test_cloud.py | 51 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py index ebfb5ee44..f3887b07b 100644 --- a/nova/tests/test_cloud.py +++ b/nova/tests/test_cloud.py @@ -37,7 +37,6 @@ from nova import rpc from nova import service from nova import test from nova import utils -from nova import exception from nova.auth import manager from nova.compute import power_state from nova.api.ec2 import cloud @@ -279,6 +278,26 @@ class CloudTestCase(test.TestCase): user_group=['all']) self.assertEqual(True, result['is_public']) + def test_deregister_image(self): + deregister_image = self.cloud.deregister_image + + def fake_delete(self, context, id): + return None + + self.stubs.Set(local.LocalImageService, 'delete', fake_delete) + # valid image + result = deregister_image(self.context, 'ami-00000001') + self.assertEqual(result['imageId'], 'ami-00000001') + # invalid image + self.stubs.UnsetAll() + + def fake_detail_empty(self, context): + return [] + + self.stubs.Set(local.LocalImageService, 'detail', fake_detail_empty) + self.assertRaises(exception.ImageNotFound, deregister_image, + self.context, 'ami-bad001') + def test_console_output(self): instance_type = FLAGS.default_instance_type max_count = 1 @@ -334,6 +353,36 @@ class CloudTestCase(test.TestCase): self.assertTrue(filter(lambda k: k['keyName'] == 'test1', keys)) self.assertTrue(filter(lambda k: k['keyName'] == 'test2', keys)) + def test_import_public_key(self): + # test when user provides all values + result1 = self.cloud.import_public_key(self.context, + 'testimportkey1', + 'mytestpubkey', + 'mytestfprint') + self.assertTrue(result1) + keydata = db.key_pair_get(self.context, + self.context.user.id, + 'testimportkey1') + self.assertEqual('mytestpubkey', keydata['public_key']) + self.assertEqual('mytestfprint', keydata['fingerprint']) + # test when user omits fingerprint + pubkey_path = os.path.join(os.path.dirname(__file__), 'public_key') + f = open(pubkey_path + '/dummy.pub', 'r') + dummypub = f.readline().rstrip() + f.close + f = open(pubkey_path + '/dummy.fingerprint', 'r') + dummyfprint = f.readline().rstrip() + f.close + result2 = self.cloud.import_public_key(self.context, + 'testimportkey2', + dummypub) + self.assertTrue(result2) + keydata = db.key_pair_get(self.context, + self.context.user.id, + 'testimportkey2') + self.assertEqual(dummypub, keydata['public_key']) + self.assertEqual(dummyfprint, keydata['fingerprint']) + def test_delete_key_pair(self): self._create_key('test') self.cloud.delete_key_pair(self.context, 'test') -- cgit From 8e7c3121fab4b5a87c2efe865f3c06b1bd267cbc Mon Sep 17 00:00:00 2001 From: John Tran Date: Tue, 24 May 2011 08:59:02 -0700 Subject: added imageid string to exception, per peer review --- nova/tests/test_cloud.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py index f3887b07b..e37aca4d6 100644 --- a/nova/tests/test_cloud.py +++ b/nova/tests/test_cloud.py @@ -226,7 +226,7 @@ class CloudTestCase(test.TestCase): 'type': 'machine'}}] def fake_show_none(meh, context, id): - raise exception.ImageNotFound + raise exception.ImageNotFound('bad_image_id') self.stubs.Set(local.LocalImageService, 'detail', fake_detail) # list all -- cgit From a0cffc4de8ba4b15958e320308477d42287858e7 Mon Sep 17 00:00:00 2001 From: John Tran Date: Tue, 24 May 2011 09:43:52 -0700 Subject: specified image_id keyword in exception arg --- nova/api/ec2/cloud.py | 2 +- nova/tests/test_cloud.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 59e00781e..80c61d62b 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -848,7 +848,7 @@ class CloudController(object): kwargs['ramdisk_id'] = ramdisk['id'] image = self._get_image(context, kwargs['image_id']) if not image: - raise exception.ImageNotFound(kwargs['image_id']) + raise exception.ImageNotFound(image_id=kwargs['image_id']) try: available = (image['properties']['image_state'] == 'available') except KeyError: diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py index e37aca4d6..1e583377b 100644 --- a/nova/tests/test_cloud.py +++ b/nova/tests/test_cloud.py @@ -226,7 +226,7 @@ class CloudTestCase(test.TestCase): 'type': 'machine'}}] def fake_show_none(meh, context, id): - raise exception.ImageNotFound('bad_image_id') + raise exception.ImageNotFound(image_id='bad_image_id') self.stubs.Set(local.LocalImageService, 'detail', fake_detail) # list all -- cgit From 5d89721f5fa3212146749236c666f0e584c8590f Mon Sep 17 00:00:00 2001 From: John Tran Date: Wed, 1 Jun 2011 16:27:51 -0700 Subject: merged, with trunk, fixed the test failure, and split the test into 3 as per peer review. --- nova/tests/test_cloud.py | 45 ++++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py index 04fd02ba3..02b7c8a38 100644 --- a/nova/tests/test_cloud.py +++ b/nova/tests/test_cloud.py @@ -445,38 +445,41 @@ class CloudTestCase(test.TestCase): self.cloud.delete_key_pair(self.context, 'test') def test_run_instances(self): - all_instances = db.instance_get_all(context.get_admin_context()) - self.assertEqual(0, len(all_instances)) - - def fake_show_decrypt(self, context, id): - return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1, - 'type': 'machine', 'image_state': 'decrypting'}} - - def fake_show_no_state(self, context, id): - return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1, - 'type': 'machine'}} - - image_id = FLAGS.default_image - instance_type = FLAGS.default_instance_type - max_count = 1 - kwargs = {'image_id': image_id, - 'instance_type': instance_type, - 'max_count': max_count} + kwargs = {'image_id': FLAGS.default_image, + 'instance_type': FLAGS.default_instance_type, + 'max_count': 1} run_instances = self.cloud.run_instances - # when image has valid image_state result = run_instances(self.context, **kwargs) instance = result['instancesSet'][0] self.assertEqual(instance['imageId'], 'ami-00000001') self.assertEqual(instance['displayName'], 'Server 1') self.assertEqual(instance['instanceId'], 'i-00000001') - self.assertEqual(instance['instanceState']['name'], 'scheduling') + self.assertEqual(instance['instanceState']['name'], 'networking') self.assertEqual(instance['instanceType'], 'm1.small') - # when image doesn't have 'image_state' attr at all + + def test_run_instances_image_state_none(self): + kwargs = {'image_id': FLAGS.default_image, + 'instance_type': FLAGS.default_instance_type, + 'max_count': 1} + run_instances = self.cloud.run_instances + def fake_show_no_state(self, context, id): + return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1, + 'type': 'machine'}} + self.stubs.UnsetAll() self.stubs.Set(local.LocalImageService, 'show', fake_show_no_state) self.assertRaises(exception.ApiError, run_instances, self.context, **kwargs) - # when image has 'image_state' yet not 'available' + + def test_run_instances_image_state_invalid(self): + kwargs = {'image_id': FLAGS.default_image, + 'instance_type': FLAGS.default_instance_type, + 'max_count': 1} + run_instances = self.cloud.run_instances + def fake_show_decrypt(self, context, id): + return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1, + 'type': 'machine', 'image_state': 'decrypting'}} + self.stubs.UnsetAll() self.stubs.Set(local.LocalImageService, 'show', fake_show_decrypt) self.assertRaises(exception.ApiError, run_instances, -- cgit From a9f21962a9e1e703730fbfae120129618b7a79ca Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Fri, 3 Jun 2011 09:24:46 -0400 Subject: Fixed pylint: no metadata member in models.py --- nova/db/sqlalchemy/models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py index edb7ffe4b..82b521e77 100644 --- a/nova/db/sqlalchemy/models.py +++ b/nova/db/sqlalchemy/models.py @@ -47,6 +47,7 @@ class NovaBase(object): updated_at = Column(DateTime, onupdate=datetime.datetime.utcnow) deleted_at = Column(DateTime) deleted = Column(Boolean, default=False) + metadata = None def save(self, session=None): """Save this object.""" -- cgit From b45d07ded9db7c92e03cea1427413d4dda95d869 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Fri, 3 Jun 2011 10:23:38 -0400 Subject: Make libvirt snapshotting work with images that don't have an 'architecture' property. --- nova/virt/libvirt/connection.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index c491418ae..98cdff311 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -403,8 +403,7 @@ class LibvirtConnection(driver.ComputeDriver): 'is_public': False, 'status': 'active', 'name': snapshot['name'], - 'properties': {'architecture': - base['properties']['architecture'], + 'properties': { 'kernel_id': instance['kernel_id'], 'image_location': 'snapshot', 'image_state': 'available', @@ -412,6 +411,9 @@ class LibvirtConnection(driver.ComputeDriver): 'ramdisk_id': instance['ramdisk_id'], } } + if 'architecture' in base['properties']: + arch = base['properties']['architecture'] + metadata['properties']['architecture'] = arch # Make the snapshot snapshot_name = uuid.uuid4().hex -- cgit From 5b00ca3ac874d0fff1eb2835cd4219f49d8a169f Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Fri, 3 Jun 2011 11:08:43 -0400 Subject: Set pylint to ignore correct lines that it could not determine were correct, due to the means by which eventlet.green imported subprocess Minimized the number of these lines to ignore --- nova/utils.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/nova/utils.py b/nova/utils.py index 361fc9873..4e1b7c26a 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -142,24 +142,26 @@ def execute(*cmd, **kwargs): env = os.environ.copy() if addl_env: env.update(addl_env) + _PIPE = subprocess.PIPE #pylint: disable=E1101 obj = subprocess.Popen(cmd, - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, + stdin=_PIPE, + stdout=_PIPE, + stderr=_PIPE, env=env) result = None if process_input is not None: result = obj.communicate(process_input) else: result = obj.communicate() - obj.stdin.close() - if obj.returncode: - LOG.debug(_('Result was %s') % obj.returncode) + obj.stdin.close() #pylint: disable=E1101 + _returncode = obj.returncode #pylint: disable=E1101 + if _returncode: + LOG.debug(_('Result was %s') % _returncode) if type(check_exit_code) == types.IntType \ - and obj.returncode != check_exit_code: + and _returncode != check_exit_code: (stdout, stderr) = result raise exception.ProcessExecutionError( - exit_code=obj.returncode, + exit_code=_returncode, stdout=stdout, stderr=stderr, cmd=' '.join(cmd)) -- cgit From 24a90512f20310007f4ca8ab01da8e19a6b5bf6f Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Fri, 3 Jun 2011 11:28:49 -0400 Subject: Removed unused and erroneous (yes, it was both) function --- nova/api/ec2/admin.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/nova/api/ec2/admin.py b/nova/api/ec2/admin.py index ea94d9c1f..4d981f70b 100644 --- a/nova/api/ec2/admin.py +++ b/nova/api/ec2/admin.py @@ -325,7 +325,3 @@ class AdminController(object): rv.append(host_dict(host, compute, instances, volume, volumes, now)) return {'hosts': rv} - - def describe_host(self, _context, name, **_kwargs): - """Returns status info for single node.""" - return host_dict(db.host_get(name)) -- cgit From 9c38da46d121e65707346473e6d51da3a2cf021f Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Mon, 6 Jun 2011 09:18:13 -0400 Subject: Fixed incorrect exception --- 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 cf1a84cd5..6970a2168 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -738,7 +738,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.NoFloatingIpsFoundForInstance(instance_id=instance_id) + raise exception.NoFixedIpsFoundForInstance(instance_id=instance_id) return rv -- cgit From ec5e5bcd3592dca44d1d71455ccd99e2c7f24d26 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Mon, 6 Jun 2011 10:49:29 -0400 Subject: Small pylint fixes --- nova/api/openstack/extensions.py | 6 ++++-- nova/api/openstack/views/limits.py | 9 --------- nova/tests/xenapi/stubs.py | 4 ++-- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/nova/api/openstack/extensions.py b/nova/api/openstack/extensions.py index 881b61733..9dad2f48d 100644 --- a/nova/api/openstack/extensions.py +++ b/nova/api/openstack/extensions.py @@ -137,7 +137,8 @@ class ActionExtensionResource(wsgi.Resource): def __init__(self, application): controller = ActionExtensionController(application) - super(ActionExtensionResource, self).__init__(controller) + #super(ActionExtensionResource, self).__init__(controller) + wsgi.Resource.__init__(self, controller) def add_action(self, action_name, handler): self.controller.add_action(action_name, handler) @@ -164,7 +165,8 @@ class RequestExtensionResource(wsgi.Resource): def __init__(self, application): controller = RequestExtensionController(application) - super(RequestExtensionResource, self).__init__(controller) + #super(RequestExtensionResource, self).__init__(controller) + wsgi.Resource.__init__(self, controller) def add_handler(self, handler): self.controller.add_handler(handler) diff --git a/nova/api/openstack/views/limits.py b/nova/api/openstack/views/limits.py index e21c9f2fd..934b4921a 100644 --- a/nova/api/openstack/views/limits.py +++ b/nova/api/openstack/views/limits.py @@ -29,9 +29,6 @@ class ViewBuilder(object): def _build_rate_limit(self, rate_limit): raise NotImplementedError() - def _build_absolute_limits(self, absolute_limit): - raise NotImplementedError() - def build(self, rate_limits, absolute_limits): rate_limits = self._build_rate_limits(rate_limits) absolute_limits = self._build_absolute_limits(absolute_limits) @@ -67,12 +64,6 @@ class ViewBuilder(object): limits[name] = value return limits - def _build_rate_limits(self, rate_limits): - raise NotImplementedError() - - def _build_rate_limit(self, rate_limit): - raise NotImplementedError() - class ViewBuilderV10(ViewBuilder): """Openstack API v1.0 limits view builder.""" diff --git a/nova/tests/xenapi/stubs.py b/nova/tests/xenapi/stubs.py index 35308d95f..5d2d1641a 100644 --- a/nova/tests/xenapi/stubs.py +++ b/nova/tests/xenapi/stubs.py @@ -251,10 +251,10 @@ class FakeSessionForMigrationTests(fake.SessionBase): def __init__(self, uri): super(FakeSessionForMigrationTests, self).__init__(uri) - def VDI_get_by_uuid(*args): + def VDI_get_by_uuid(self, *args): return 'hurr' - def VDI_resize_online(*args): + def VDI_resize_online(self, *args): pass def VM_start(self, _1, ref, _2, _3): -- cgit From 3fb0b8fd8e4ad5911c85fddcb6ef5127fa4cd384 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Mon, 6 Jun 2011 11:00:51 -0400 Subject: Removed extraneous code --- nova/tests/xenapi/stubs.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/nova/tests/xenapi/stubs.py b/nova/tests/xenapi/stubs.py index 5d2d1641a..151a3e909 100644 --- a/nova/tests/xenapi/stubs.py +++ b/nova/tests/xenapi/stubs.py @@ -42,20 +42,6 @@ def stubout_instance_snapshot(stubs): stubs.Set(vm_utils.VMHelper, 'fetch_image', fake_fetch_image) - def fake_wait_for_vhd_coalesce(session, instance_id, sr_ref, vdi_ref, - original_parent_uuid): - from nova.virt.xenapi.fake import create_vdi - name_label = "instance-%s" % instance_id - #TODO: create fake SR record - sr_ref = "fakesr" - vdi_ref = create_vdi(name_label=name_label, read_only=False, - sr_ref=sr_ref, sharable=False) - vdi_rec = session.get_xenapi().VDI.get_record(vdi_ref) - vdi_uuid = vdi_rec['uuid'] - return vdi_uuid - - stubs.Set(vm_utils.VMHelper, 'fetch_image', fake_fetch_image) - def fake_parse_xmlrpc_value(val): return val -- cgit From a2f74c2f706bdf45ec36348468b1ba5797fcde87 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Mon, 6 Jun 2011 11:20:25 -0400 Subject: Use super on an old style class --- nova/twistd.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nova/twistd.py b/nova/twistd.py index c07ed991f..15cf67825 100644 --- a/nova/twistd.py +++ b/nova/twistd.py @@ -78,7 +78,7 @@ def WrapTwistedOptions(wrapped): self._absorbParameters() self._absorbHandlers() - super(TwistedOptionsToFlags, self).__init__() + wrapped.__init__(self) def _absorbFlags(self): twistd_flags = [] @@ -163,12 +163,12 @@ def WrapTwistedOptions(wrapped): def parseArgs(self, *args): # TODO(termie): figure out a decent way of dealing with args #return - super(TwistedOptionsToFlags, self).parseArgs(*args) + wrapped.parseArgs(self, *args) def postOptions(self): self._doHandlers() - super(TwistedOptionsToFlags, self).postOptions() + wrapped.postOptions(self) def __getitem__(self, key): key = key.replace('-', '_') -- cgit From 0eb6db6f994963d519f9fe07e3dbc41e0c8079c6 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Mon, 6 Jun 2011 11:29:05 -0400 Subject: Removed Duplicate method --- nova/virt/xenapi/fake.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/nova/virt/xenapi/fake.py b/nova/virt/xenapi/fake.py index 76988b172..5d3b67417 100644 --- a/nova/virt/xenapi/fake.py +++ b/nova/virt/xenapi/fake.py @@ -340,10 +340,6 @@ class SessionBase(object): return db_ref['xenstore_data'][key] = None - def network_get_all_records_where(self, _1, _2): - # TODO (salvatore-orlando): filter table on _2 - return _db_content['network'] - def VM_add_to_xenstore_data(self, _1, vm_ref, key, value): db_ref = _db_content['VM'][vm_ref] if not 'xenstore_data' in db_ref: @@ -354,7 +350,7 @@ class SessionBase(object): #Always return 12GB available return 12 * 1024 * 1024 * 1024 - def host_call_plugin(*args): + def host_call_plugin(self, *args): return 'herp' def network_get_all_records_where(self, _1, filter): -- cgit From 3d481e551ac81a35cafcd79c2b17d2bd9c8a050f Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Mon, 6 Jun 2011 11:39:34 -0400 Subject: Ignore complaining about dynamic definition --- nova/api/direct.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/api/direct.py b/nova/api/direct.py index ea20042a7..ea7425e19 100644 --- a/nova/api/direct.py +++ b/nova/api/direct.py @@ -324,7 +324,7 @@ class Limited(object): def __init__(self, proxy): self._proxy = proxy - if not self.__doc__: + if not self.__doc__: #pylint: disable=E0203 self.__doc__ = proxy.__doc__ if not self._allowed: self._allowed = [] -- cgit From 9fca0b2156f1e7f3d007916ef18b2ed9fbc761df Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Mon, 6 Jun 2011 15:59:20 -0400 Subject: Added test case for snapshoting base image without architecture. --- nova/tests/test_libvirt.py | 92 +++++++++++++++++++++++++++++++++------------- 1 file changed, 66 insertions(+), 26 deletions(-) diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py index b6b36745a..d0bdaa738 100644 --- a/nova/tests/test_libvirt.py +++ b/nova/tests/test_libvirt.py @@ -14,6 +14,7 @@ # License for the specific language governing permissions and limitations # under the License. +import copy import eventlet import mox import os @@ -125,6 +126,7 @@ class CacheConcurrencyTestCase(test.TestCase): class LibvirtConnTestCase(test.TestCase): + def setUp(self): super(LibvirtConnTestCase, self).setUp() connection._late_load_cheetah() @@ -207,6 +209,31 @@ class LibvirtConnTestCase(test.TestCase): self.mox.StubOutWithMock(connection.LibvirtConnection, '_conn') connection.LibvirtConnection._conn = fake + def fake_lookup(self, instance_name): + class FakeVirtDomain(object): + + def __init__(self): + pass + + def snapshotCreateXML(self, *args): + return None + + def XMLDesc(self, *args): + return """ + + + + + + + + """ + + return FakeVirtDomain() + + def fake_execute(self, *args): + open(args[-1], "a").close() + def create_service(self, **kwargs): service_ref = {'host': kwargs.get('host', 'dummy'), 'binary': 'nova-compute', @@ -283,43 +310,56 @@ class LibvirtConnTestCase(test.TestCase): self._check_xml_and_container(instance_data) def test_snapshot(self): + if not self.lazy_load_library_exists(): + return + FLAGS.image_service = 'nova.image.fake.FakeImageService' - # Only file-based instance storages are supported at the moment - test_xml = """ - - - - - - - - """ + # Start test + image_service = utils.import_object(FLAGS.image_service) - class FakeVirtDomain(object): + # Assuming that base image already exists in image_service + instance_ref = db.instance_create(self.context, self.test_instance) + properties = {'instance_id': instance_ref['id'], + 'user_id': str(self.context.user_id)} + snapshot_name = 'test-snap' + sent_meta = {'name': snapshot_name, 'is_public': False, + 'status': 'creating', 'properties': properties} + # Create new image. It will be updated in snapshot method + # To work with it from snapshot, the single image_service is needed + recv_meta = image_service.create(context, sent_meta) - def __init__(self): - pass + self.mox.StubOutWithMock(connection.LibvirtConnection, '_conn') + connection.LibvirtConnection._conn.lookupByName = self.fake_lookup + self.mox.StubOutWithMock(connection.utils, 'execute') + connection.utils.execute = self.fake_execute - def snapshotCreateXML(self, *args): - return None + self.mox.ReplayAll() - def XMLDesc(self, *args): - return test_xml + conn = connection.LibvirtConnection(False) + conn.snapshot(instance_ref, recv_meta['id']) - def fake_lookup(instance_name): - if instance_name == instance_ref.name: - return FakeVirtDomain() + snapshot = image_service.show(context, recv_meta['id']) + self.assertEquals(snapshot['properties']['image_state'], 'available') + self.assertEquals(snapshot['status'], 'active') + self.assertEquals(snapshot['name'], snapshot_name) - def fake_execute(*args): - # Touch filename to pass 'with open(out_path)' - open(args[-1], "a").close() + def test_snapshot_no_image_architecture(self): + if not self.lazy_load_library_exists(): + return + + FLAGS.image_service = 'nova.image.fake.FakeImageService' # Start test image_service = utils.import_object(FLAGS.image_service) + # Assign image_ref = 2 from nova/images/fakes for testing different + # base image + test_instance = copy.deepcopy(self.test_instance) + test_instance["image_ref"] = "2" + # Assuming that base image already exists in image_service - instance_ref = db.instance_create(self.context, self.test_instance) + instance_ref = db.instance_create(self.context, test_instance) properties = {'instance_id': instance_ref['id'], 'user_id': str(self.context.user_id)} snapshot_name = 'test-snap' @@ -330,9 +370,9 @@ class LibvirtConnTestCase(test.TestCase): recv_meta = image_service.create(context, sent_meta) self.mox.StubOutWithMock(connection.LibvirtConnection, '_conn') - connection.LibvirtConnection._conn.lookupByName = fake_lookup + connection.LibvirtConnection._conn.lookupByName = self.fake_lookup self.mox.StubOutWithMock(connection.utils, 'execute') - connection.utils.execute = fake_execute + connection.utils.execute = self.fake_execute self.mox.ReplayAll() -- cgit From 57df676a3302f8d754ef54e415d2fd82a4291f49 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Mon, 6 Jun 2011 15:59:39 -0400 Subject: Removed commented code --- nova/api/openstack/extensions.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/nova/api/openstack/extensions.py b/nova/api/openstack/extensions.py index 9dad2f48d..54e17e23d 100644 --- a/nova/api/openstack/extensions.py +++ b/nova/api/openstack/extensions.py @@ -137,7 +137,6 @@ class ActionExtensionResource(wsgi.Resource): def __init__(self, application): controller = ActionExtensionController(application) - #super(ActionExtensionResource, self).__init__(controller) wsgi.Resource.__init__(self, controller) def add_action(self, action_name, handler): @@ -165,7 +164,6 @@ class RequestExtensionResource(wsgi.Resource): def __init__(self, application): controller = RequestExtensionController(application) - #super(RequestExtensionResource, self).__init__(controller) wsgi.Resource.__init__(self, controller) def add_handler(self, handler): -- cgit From e745c21724e5990874a12c4abff53127755185ea Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Mon, 6 Jun 2011 16:08:58 -0400 Subject: Use True/False instead of 1/0 when setting updating 'deleted' column attributes.Fixes casting issues when running nova with Postgres. --- nova/db/sqlalchemy/api.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 6dbf53a6c..103668b94 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -1127,7 +1127,7 @@ def key_pair_destroy_all_by_user(context, user_id): with session.begin(): session.query(models.KeyPair).\ filter_by(user_id=user_id).\ - update({'deleted': 1, + update({'deleted': True, 'deleted_at': utils.utcnow(), 'updated_at': literal_column('updated_at')}) @@ -1659,7 +1659,7 @@ def volume_destroy(context, volume_id): with session.begin(): session.query(models.Volume).\ filter_by(id=volume_id).\ - update({'deleted': 1, + update({'deleted': True, 'deleted_at': utils.utcnow(), 'updated_at': literal_column('updated_at')}) session.query(models.ExportDevice).\ @@ -1817,7 +1817,7 @@ def snapshot_destroy(context, snapshot_id): with session.begin(): session.query(models.Snapshot).\ filter_by(id=snapshot_id).\ - update({'deleted': 1, + update({'deleted': True, 'deleted_at': utils.utcnow(), 'updated_at': literal_column('updated_at')}) @@ -1972,17 +1972,17 @@ def security_group_destroy(context, security_group_id): with session.begin(): session.query(models.SecurityGroup).\ filter_by(id=security_group_id).\ - update({'deleted': 1, + update({'deleted': True, 'deleted_at': utils.utcnow(), 'updated_at': literal_column('updated_at')}) session.query(models.SecurityGroupInstanceAssociation).\ filter_by(security_group_id=security_group_id).\ - update({'deleted': 1, + update({'deleted': True, 'deleted_at': utils.utcnow(), 'updated_at': literal_column('updated_at')}) session.query(models.SecurityGroupIngressRule).\ filter_by(group_id=security_group_id).\ - update({'deleted': 1, + update({'deleted': True, 'deleted_at': utils.utcnow(), 'updated_at': literal_column('updated_at')}) @@ -1993,11 +1993,11 @@ def security_group_destroy_all(context, session=None): session = get_session() with session.begin(): session.query(models.SecurityGroup).\ - update({'deleted': 1, + update({'deleted': True, 'deleted_at': utils.utcnow(), 'updated_at': literal_column('updated_at')}) session.query(models.SecurityGroupIngressRule).\ - update({'deleted': 1, + update({'deleted': True, 'deleted_at': utils.utcnow(), 'updated_at': literal_column('updated_at')}) @@ -2678,7 +2678,7 @@ def instance_metadata_update_or_create(context, instance_id, metadata): meta_ref = models.InstanceMetadata() meta_ref.update({"key": key, "value": value, "instance_id": instance_id, - "deleted": 0}) + "deleted": False}) meta_ref.save(session=session) return metadata -- cgit From 8747611e4bd69b6da204b2c021fd5400c961db1d Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Tue, 7 Jun 2011 10:47:29 -0400 Subject: Removed empty init --- nova/tests/test_libvirt.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py index d0bdaa738..8b4183164 100644 --- a/nova/tests/test_libvirt.py +++ b/nova/tests/test_libvirt.py @@ -210,10 +210,8 @@ class LibvirtConnTestCase(test.TestCase): connection.LibvirtConnection._conn = fake def fake_lookup(self, instance_name): - class FakeVirtDomain(object): - def __init__(self): - pass + class FakeVirtDomain(object): def snapshotCreateXML(self, *args): return None -- cgit From 7bae412d230171baf1ba7bec7262705404d1ed7f Mon Sep 17 00:00:00 2001 From: Josh Kearney Date: Tue, 7 Jun 2011 10:47:14 -0500 Subject: Add the option to specify a default IPv6 gateway. --- bin/nova-manage | 13 +++++++++---- nova/network/manager.py | 11 +++++++++-- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/bin/nova-manage b/bin/nova-manage index b0cd343f5..7f024f9ca 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -96,6 +96,7 @@ flags.DECLARE('network_size', 'nova.network.manager') flags.DECLARE('vlan_start', 'nova.network.manager') flags.DECLARE('vpn_start', 'nova.network.manager') flags.DECLARE('fixed_range_v6', 'nova.network.manager') +flags.DECLARE('gateway_v6', 'nova.network.manager') flags.DECLARE('images_path', 'nova.image.local') flags.DECLARE('libvirt_type', 'nova.virt.libvirt.connection') flags.DEFINE_flag(flags.HelpFlag()) @@ -545,13 +546,14 @@ class FloatingIpCommands(object): class NetworkCommands(object): """Class for managing networks.""" - def create(self, fixed_range=None, num_networks=None, - network_size=None, vlan_start=None, - vpn_start=None, fixed_range_v6=None, label='public'): + def create(self, fixed_range=None, num_networks=None, network_size=None, + vlan_start=None, vpn_start=None, fixed_range_v6=None, + gateway_v6=None, label='public'): """Creates fixed ips for host by range arguments: fixed_range=FLAG, [num_networks=FLAG], [network_size=FLAG], [vlan_start=FLAG], - [vpn_start=FLAG], [fixed_range_v6=FLAG]""" + [vpn_start=FLAG], [fixed_range_v6=FLAG], + [gateway_v6=FLAG]""" if not fixed_range: msg = _('Fixed range in the form of 10.0.0.0/8 is ' 'required to create networks.') @@ -567,6 +569,8 @@ class NetworkCommands(object): vpn_start = FLAGS.vpn_start if not fixed_range_v6: fixed_range_v6 = FLAGS.fixed_range_v6 + if not gateway_v6: + gateway_v6 = FLAGS.gateway_v6 net_manager = utils.import_object(FLAGS.network_manager) try: net_manager.create_networks(context.get_admin_context(), @@ -576,6 +580,7 @@ class NetworkCommands(object): vlan_start=int(vlan_start), vpn_start=int(vpn_start), cidr_v6=fixed_range_v6, + gateway_v6=gateway_v6, label=label) except ValueError, e: print e diff --git a/nova/network/manager.py b/nova/network/manager.py index f726c4b26..b5352ca0f 100644 --- a/nova/network/manager.py +++ b/nova/network/manager.py @@ -86,6 +86,7 @@ flags.DEFINE_string('floating_range', '4.4.4.0/24', 'Floating IP address block') flags.DEFINE_string('fixed_range', '10.0.0.0/8', 'Fixed IP address block') flags.DEFINE_string('fixed_range_v6', 'fd00::/48', 'Fixed IPv6 address block') +flags.DEFINE_string('gateway_v6', None, 'Default IPv6 gateway') flags.DEFINE_integer('cnt_vpn_clients', 0, 'Number of addresses reserved for vpn clients') flags.DEFINE_string('network_driver', 'nova.network.linux_net', @@ -292,7 +293,7 @@ class NetworkManager(manager.SchedulerDependentManager): return host def create_networks(self, context, cidr, num_networks, network_size, - cidr_v6, label, *args, **kwargs): + cidr_v6, gateway_v6, label, *args, **kwargs): """Create networks based on parameters.""" fixed_net = IPy.IP(cidr) fixed_net_v6 = IPy.IP(cidr_v6) @@ -324,7 +325,13 @@ class NetworkManager(manager.SchedulerDependentManager): significant_bits_v6) net['cidr_v6'] = cidr_v6 project_net_v6 = IPy.IP(cidr_v6) - net['gateway_v6'] = str(project_net_v6[1]) + + if gateway_v6: + # use a pre-defined gateway if one is provided + net['gateway_v6'] = str(gateway_v6) + else: + net['gateway_v6'] = str(project_net_v6[1]) + net['netmask_v6'] = str(project_net_v6.prefixlen()) network_ref = self.db.network_create_safe(context, net) -- cgit From aa343c994c4738374bd91531ae2e260175690a56 Mon Sep 17 00:00:00 2001 From: Josh Kearney Date: Tue, 7 Jun 2011 11:45:25 -0500 Subject: Remove unnecessary docstrings. --- bin/nova-manage | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/bin/nova-manage b/bin/nova-manage index 7f024f9ca..0147ae21b 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -549,11 +549,7 @@ class NetworkCommands(object): def create(self, fixed_range=None, num_networks=None, network_size=None, vlan_start=None, vpn_start=None, fixed_range_v6=None, gateway_v6=None, label='public'): - """Creates fixed ips for host by range - arguments: fixed_range=FLAG, [num_networks=FLAG], - [network_size=FLAG], [vlan_start=FLAG], - [vpn_start=FLAG], [fixed_range_v6=FLAG], - [gateway_v6=FLAG]""" + """Creates fixed ips for host by range""" if not fixed_range: msg = _('Fixed range in the form of 10.0.0.0/8 is ' 'required to create networks.') -- cgit From e8d6740fefcac3734021edaf53a40ecb145ccaa3 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Tue, 7 Jun 2011 13:47:40 -0400 Subject: DRY up the image_state logic. Fix an issue where glance style images (which aren't required to have an 'image_state' property) couldn't be used to run instances on the EC2 controller. --- nova/api/ec2/cloud.py | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index ac73cd595..316298c39 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -136,6 +136,13 @@ class CloudController(object): return services[0]['availability_zone'] return 'unknown zone' + def _get_image_state(self, image): + # NOTE(vish): fallback status if image_state isn't set + state = image.get('status') + if state == 'active': + state = 'available' + return image['properties'].get('image_state', state) + def get_metadata(self, address): ctxt = context.get_admin_context() instance_ref = self.compute_api.get_all(ctxt, fixed_ip=address) @@ -896,14 +903,13 @@ class CloudController(object): ramdisk = self._get_image(context, kwargs['ramdisk_id']) kwargs['ramdisk_id'] = ramdisk['id'] image = self._get_image(context, kwargs['image_id']) - if not image: + + if image: + image_state = self._get_image_state(image) + else: raise exception.ImageNotFound(image_id=kwargs['image_id']) - try: - available = (image['properties']['image_state'] == 'available') - except KeyError: - available = False - if not available: + if image_state != 'available': raise exception.ApiError(_('Image must be available')) instances = self.compute_api.create(context, @@ -1021,11 +1027,8 @@ class CloudController(object): get('image_location'), name) else: i['imageLocation'] = image['properties'].get('image_location') - # NOTE(vish): fallback status if image_state isn't set - state = image.get('status') - if state == 'active': - state = 'available' - i['imageState'] = image['properties'].get('image_state', state) + + i['imageState'] = self._get_image_state(image) i['displayName'] = name i['description'] = image.get('description') display_mapping = {'aki': 'kernel', -- cgit From 641f16a5343ca5d95ea10ec5031a27a7f131c337 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Tue, 7 Jun 2011 15:17:34 -0400 Subject: pep8 --- nova/api/direct.py | 2 +- nova/utils.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/nova/api/direct.py b/nova/api/direct.py index ea7425e19..ec79151b1 100644 --- a/nova/api/direct.py +++ b/nova/api/direct.py @@ -324,7 +324,7 @@ class Limited(object): def __init__(self, proxy): self._proxy = proxy - if not self.__doc__: #pylint: disable=E0203 + if not self.__doc__: # pylint: disable=E0203 self.__doc__ = proxy.__doc__ if not self._allowed: self._allowed = [] diff --git a/nova/utils.py b/nova/utils.py index e77c80262..691134ada 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -142,7 +142,7 @@ def execute(*cmd, **kwargs): env = os.environ.copy() if addl_env: env.update(addl_env) - _PIPE = subprocess.PIPE #pylint: disable=E1101 + _PIPE = subprocess.PIPE # pylint: disable=E1101 obj = subprocess.Popen(cmd, stdin=_PIPE, stdout=_PIPE, @@ -153,8 +153,8 @@ def execute(*cmd, **kwargs): result = obj.communicate(process_input) else: result = obj.communicate() - obj.stdin.close() #pylint: disable=E1101 - _returncode = obj.returncode #pylint: disable=E1101 + obj.stdin.close() # pylint: disable=E1101 + _returncode = obj.returncode # pylint: disable=E1101 if _returncode: LOG.debug(_('Result was %s') % _returncode) if type(check_exit_code) == types.IntType \ -- cgit From 8f93aa59aca5440a4d9668942703bf235379ed59 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Tue, 7 Jun 2011 16:05:03 -0400 Subject: Added test_run_instances_image_status_active to test_cloud. --- nova/tests/test_cloud.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py index a58e8bc39..ba133c860 100644 --- a/nova/tests/test_cloud.py +++ b/nova/tests/test_cloud.py @@ -487,6 +487,21 @@ class CloudTestCase(test.TestCase): self.assertRaises(exception.ApiError, run_instances, self.context, **kwargs) + def test_run_instances_image_status_active(self): + kwargs = {'image_id': FLAGS.default_image, + 'instance_type': FLAGS.default_instance_type, + 'max_count': 1} + run_instances = self.cloud.run_instances + + def fake_show_stat_active(self, context, id): + return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1, + 'type': 'machine'}, 'status': 'active'} + + self.stubs.Set(local.LocalImageService, 'show', fake_show_stat_active) + + result = run_instances(self.context, **kwargs) + self.assertEqual(len(result['instancesSet']), 1) + def test_terminate_instances(self): inst1 = db.instance_create(self.context, {'reservation_id': 'a', 'image_ref': 1, -- cgit