summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2013-04-03 14:01:17 +0000
committerGerrit Code Review <review@openstack.org>2013-04-03 14:01:17 +0000
commitf7add7ea8cd2eb1c0cf1b148c53833fc4f85de33 (patch)
tree096f5787f1b8e7dfca9b4a946bf75220fa88acad
parent1d5b10ea7697f94e8eb72b61c599b12f9952a055 (diff)
parent24aacd2c91c73245d444a2460ded1c5c94382f5f (diff)
downloadnova-f7add7ea8cd2eb1c0cf1b148c53833fc4f85de33.tar.gz
nova-f7add7ea8cd2eb1c0cf1b148c53833fc4f85de33.tar.xz
nova-f7add7ea8cd2eb1c0cf1b148c53833fc4f85de33.zip
Merge "Limit the checks for block device becoming available."
-rwxr-xr-xnova/compute/manager.py33
-rw-r--r--nova/exception.py6
-rw-r--r--nova/tests/compute/test_compute.py35
3 files changed, 66 insertions, 8 deletions
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 775287192..0c038bf4c 100755
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -673,6 +673,30 @@ class ComputeManager(manager.SchedulerDependentManager):
network_info = network_info.legacy()
return network_info
+ def _await_block_device_map_created(self, context, vol_id, max_tries=30,
+ wait_between=1):
+ # TODO(yamahata): creating volume simultaneously
+ # reduces creation time?
+ # TODO(yamahata): eliminate dumb polling
+ # TODO(harlowja): make the max_tries configurable or dynamic?
+ attempts = 0
+ start = time.time()
+ while attempts < max_tries:
+ volume = self.volume_api.get(context, vol_id)
+ volume_status = volume['status']
+ if volume_status != 'creating':
+ if volume_status != 'available':
+ LOG.warn(_("Volume id: %s finished being created but was"
+ " not set as 'available'"), vol_id)
+ # NOTE(harlowja): return how many attempts were tried
+ return attempts + 1
+ greenthread.sleep(wait_between)
+ attempts += 1
+ # NOTE(harlowja): Should only happen if we ran out of attempts
+ raise exception.VolumeNotCreated(volume_id=vol_id,
+ seconds=int(time.time() - start),
+ attempts=attempts)
+
def _setup_block_device_mapping(self, context, instance, bdms):
"""setup volumes for block device mapping."""
block_device_mapping = []
@@ -705,14 +729,7 @@ class ComputeManager(manager.SchedulerDependentManager):
bdm['snapshot_id'])
vol = self.volume_api.create(context, bdm['volume_size'],
'', '', snapshot)
- # TODO(yamahata): creating volume simultaneously
- # reduces creation time?
- # TODO(yamahata): eliminate dumb polling
- while True:
- volume = self.volume_api.get(context, vol['id'])
- if volume['status'] != 'creating':
- break
- greenthread.sleep(1)
+ self._await_block_device_map_created(context, vol['id'])
self.conductor_api.block_device_mapping_update(
context, bdm['id'], {'volume_id': vol['id']})
bdm['volume_id'] = vol['id']
diff --git a/nova/exception.py b/nova/exception.py
index b3b3d1f1f..de922f50e 100644
--- a/nova/exception.py
+++ b/nova/exception.py
@@ -244,6 +244,12 @@ class VolumeUnattached(Invalid):
message = _("Volume %(volume_id)s is not attached to anything")
+class VolumeNotCreated(NovaException):
+ message = _("Volume %(volume_id)s did not finish being created"
+ " even after we waited %(seconds)s seconds or %(attempts)s"
+ " attempts.")
+
+
class InvalidKeypair(Invalid):
message = _("Keypair data is invalid")
diff --git a/nova/tests/compute/test_compute.py b/nova/tests/compute/test_compute.py
index 395a075c8..7e85ad0a7 100644
--- a/nova/tests/compute/test_compute.py
+++ b/nova/tests/compute/test_compute.py
@@ -248,6 +248,7 @@ class ComputeVolumeTestCase(BaseTestCase):
def setUp(self):
super(ComputeVolumeTestCase, self).setUp()
self.volume_id = 'fake'
+ self.fetched_attempts = 0
self.instance = {
'id': 'fake',
'uuid': 'fake',
@@ -283,6 +284,40 @@ class ComputeVolumeTestCase(BaseTestCase):
'/dev/vdb', self.instance)
self.assertEqual(self.cinfo.get('serial'), self.volume_id)
+ def test_await_block_device_created_to_slow(self):
+
+ def never_get(context, vol_id):
+ return {
+ 'status': 'creating',
+ 'id': 'blah',
+ }
+
+ self.stubs.Set(self.compute.volume_api, 'get', never_get)
+ self.assertRaises(exception.VolumeNotCreated,
+ self.compute._await_block_device_map_created,
+ self.context, '1', max_tries=2, wait_between=0.1)
+
+ def test_await_block_device_created_slow(self):
+ c = self.compute
+
+ def slow_get(context, vol_id):
+ while self.fetched_attempts < 2:
+ self.fetched_attempts += 1
+ return {
+ 'status': 'creating',
+ 'id': 'blah',
+ }
+ return {
+ 'status': 'available',
+ 'id': 'blah',
+ }
+
+ self.stubs.Set(c.volume_api, 'get', slow_get)
+ attempts = c._await_block_device_map_created(self.context, '1',
+ max_tries=4,
+ wait_between=0.1)
+ self.assertEqual(attempts, 3)
+
def test_boot_volume_serial(self):
block_device_mapping = [{
'id': 1,