diff options
| author | Jenkins <jenkins@review.openstack.org> | 2012-12-15 02:02:36 +0000 |
|---|---|---|
| committer | Gerrit Code Review <review@openstack.org> | 2012-12-15 02:02:36 +0000 |
| commit | 84472dd18da7900a30ba33ed97603069b5edfe76 (patch) | |
| tree | dd923e4595f21ed1d55701e077d4e98896ae1f78 | |
| parent | 083714206bb60b4673bf505eac9c1cc5cbd5279f (diff) | |
| parent | 6da1dbc8498b4c3143221fd4e1b9f59374134fd3 (diff) | |
| download | nova-84472dd18da7900a30ba33ed97603069b5edfe76.tar.gz nova-84472dd18da7900a30ba33ed97603069b5edfe76.tar.xz nova-84472dd18da7900a30ba33ed97603069b5edfe76.zip | |
Merge "Retry NBD device allocation."
| -rw-r--r-- | nova/tests/virt/disk/test_nbd.py | 110 | ||||
| -rw-r--r-- | nova/virt/disk/mount/nbd.py | 27 |
2 files changed, 101 insertions, 36 deletions
diff --git a/nova/tests/virt/disk/test_nbd.py b/nova/tests/virt/disk/test_nbd.py index 5e08215a5..17e149cbc 100644 --- a/nova/tests/virt/disk/test_nbd.py +++ b/nova/tests/virt/disk/test_nbd.py @@ -139,13 +139,13 @@ class NbdTestCase(test.TestCase): # re-added. I will fix this in a later patch. self.assertEquals('/dev/nbd1', n._allocate_nbd()) - def test_get_dev_no_devices(self): + def test_inner_get_dev_no_devices(self): tempdir = self.useFixture(fixtures.TempDir()).path n = nbd.NbdMount(None, tempdir) n.detect_nbd_device = _fake_detect_nbd_devices - self.assertFalse(n.get_dev()) + self.assertFalse(n._inner_get_dev()) - def test_get_dev_qemu_fails(self): + def test_inner_get_dev_qemu_fails(self): tempdir = self.useFixture(fixtures.TempDir()).path n = nbd.NbdMount(None, tempdir) self.useFixture(fixtures.MonkeyPatch('os.path.exists', @@ -157,10 +157,10 @@ class NbdTestCase(test.TestCase): self.useFixture(fixtures.MonkeyPatch('nova.utils.trycmd', fake_trycmd)) # Error logged, no device consumed - self.assertFalse(n.get_dev()) + self.assertFalse(n._inner_get_dev()) self.assertTrue(n.error.startswith('qemu-nbd error')) - def test_get_dev_qemu_timeout(self): + def test_inner_get_dev_qemu_timeout(self): tempdir = self.useFixture(fixtures.TempDir()).path n = nbd.NbdMount(None, tempdir) n.detect_nbd_device = _fake_detect_nbd_devices @@ -174,46 +174,46 @@ class NbdTestCase(test.TestCase): self.useFixture(fixtures.MonkeyPatch('time.sleep', _fake_noop)) # Error logged, no device consumed - self.assertFalse(n.get_dev()) + self.assertFalse(n._inner_get_dev()) self.assertTrue(n.error.endswith('did not show up')) - def test_get_dev_works(self): - tempdir = self.useFixture(fixtures.TempDir()).path - n = nbd.NbdMount(None, tempdir) - n.detect_nbd_device = _fake_detect_nbd_devices - self.useFixture(fixtures.MonkeyPatch('random.shuffle', _fake_noop)) - self.useFixture(fixtures.MonkeyPatch('nova.utils.execute', _fake_noop)) - + def fake_exists_one(self, path): # We need the pid file for the device which is allocated to exist, but # only once it is allocated to us - def fake_exists_one(path): + if path.startswith('/sys/block/nbd'): + if path == '/sys/block/nbd1/pid': + return False + if path.endswith('pid'): + return False + return True + return ORIG_EXISTS(path) + + def fake_trycmd_creates_pid(self, *args, **kwargs): + def fake_exists_two(path): if path.startswith('/sys/block/nbd'): - if path == '/sys/block/nbd1/pid': - return False + if path == '/sys/block/nbd0/pid': + return True if path.endswith('pid'): return False return True return ORIG_EXISTS(path) self.useFixture(fixtures.MonkeyPatch('os.path.exists', - fake_exists_one)) + fake_exists_two)) + return '', '' - # We have a trycmd that always passed - def fake_trycmd(*args, **kwargs): - def fake_exists_two(path): - if path.startswith('/sys/block/nbd'): - if path == '/sys/block/nbd0/pid': - return True - if path.endswith('pid'): - return False - return True - return ORIG_EXISTS(path) - self.useFixture(fixtures.MonkeyPatch('os.path.exists', - fake_exists_two)) - return '', '' - self.useFixture(fixtures.MonkeyPatch('nova.utils.trycmd', fake_trycmd)) + def test_inner_get_dev_works(self): + tempdir = self.useFixture(fixtures.TempDir()).path + n = nbd.NbdMount(None, tempdir) + n.detect_nbd_device = _fake_detect_nbd_devices + self.useFixture(fixtures.MonkeyPatch('random.shuffle', _fake_noop)) + self.useFixture(fixtures.MonkeyPatch('os.path.exists', + self.fake_exists_one)) + self.useFixture(fixtures.MonkeyPatch('nova.utils.trycmd', + self.fake_trycmd_creates_pid)) + self.useFixture(fixtures.MonkeyPatch('nova.utils.execute', _fake_noop)) # No error logged, device consumed - self.assertTrue(n.get_dev()) + self.assertTrue(n._inner_get_dev()) self.assertTrue(n.linked) self.assertEquals('', n.error) self.assertEquals('/dev/nbd0', n.device) @@ -229,4 +229,50 @@ class NbdTestCase(test.TestCase): # something we don't have tempdir = self.useFixture(fixtures.TempDir()).path n = nbd.NbdMount(None, tempdir) + self.useFixture(fixtures.MonkeyPatch('nova.utils.execute', _fake_noop)) n.unget_dev() + + def test_get_dev(self): + tempdir = self.useFixture(fixtures.TempDir()).path + n = nbd.NbdMount(None, tempdir) + n.detect_nbd_device = _fake_detect_nbd_devices + self.useFixture(fixtures.MonkeyPatch('random.shuffle', _fake_noop)) + self.useFixture(fixtures.MonkeyPatch('nova.utils.execute', _fake_noop)) + self.useFixture(fixtures.MonkeyPatch('os.path.exists', + self.fake_exists_one)) + self.useFixture(fixtures.MonkeyPatch('nova.utils.trycmd', + self.fake_trycmd_creates_pid)) + + # No error logged, device consumed + self.assertTrue(n.get_dev()) + self.assertTrue(n.linked) + self.assertEquals('', n.error) + self.assertEquals('/dev/nbd0', n.device) + + # Free + n.unget_dev() + self.assertFalse(n.linked) + self.assertEquals('', n.error) + self.assertEquals(None, n.device) + + def test_get_dev_timeout(self): + tempdir = self.useFixture(fixtures.TempDir()).path + n = nbd.NbdMount(None, tempdir) + n.detect_nbd_device = _fake_detect_nbd_devices + self.useFixture(fixtures.MonkeyPatch('random.shuffle', _fake_noop)) + self.useFixture(fixtures.MonkeyPatch('time.sleep', _fake_noop)) + self.useFixture(fixtures.MonkeyPatch('nova.utils.execute', _fake_noop)) + self.useFixture(fixtures.MonkeyPatch('os.path.exists', + self.fake_exists_one)) + self.useFixture(fixtures.MonkeyPatch('nova.utils.trycmd', + self.fake_trycmd_creates_pid)) + self.useFixture(fixtures.MonkeyPatch(('nova.virt.disk.mount.nbd.' + 'MAX_NBD_WAIT'), -10)) + + # Always fail to get a device + def fake_get_dev_fails(): + return False + n._inner_get_dev = fake_get_dev_fails + + # No error logged, device consumed + self.assertFalse(n.get_dev()) diff --git a/nova/virt/disk/mount/nbd.py b/nova/virt/disk/mount/nbd.py index 90d858a4b..1b6cc0778 100644 --- a/nova/virt/disk/mount/nbd.py +++ b/nova/virt/disk/mount/nbd.py @@ -37,15 +37,13 @@ CONF = cfg.CONF CONF.register_opts(nbd_opts) NBD_DEVICE_RE = re.compile('nbd[0-9]+') +MAX_NBD_WAIT = 30 class NbdMount(api.Mount): """qemu-nbd support disk images.""" mode = 'nbd' - # NOTE(padraig): The remaining issue with this code is that multiple - # workers on a system can race against each other. - def _detect_nbd_devices(self): """Detect nbd device files.""" return filter(NBD_DEVICE_RE.match, os.listdir('/sys/block/')) @@ -78,7 +76,7 @@ class NbdMount(api.Mount): pid = int(f.readline()) return pid - def get_dev(self): + def _inner_get_dev(self): device = self._allocate_nbd() if not device: return False @@ -102,12 +100,33 @@ class NbdMount(api.Mount): break time.sleep(1) else: + _out, err = utils.trycmd('qemu-nbd', '-d', device, + run_as_root=True) + if err: + LOG.warn(_('Detaching from erroneous nbd device returned ' + 'error: %s'), err) self.error = _('nbd device %s did not show up') % device return False + self.error = '' self.linked = True return True + def get_dev(self): + """Retry requests for NBD devices.""" + start_time = time.time() + device = self._inner_get_dev() + while not device: + LOG.info(_('nbd device allocation failed. Will retry in 2 ' + 'seconds.')) + time.sleep(2) + if time.time() - start_time > MAX_NBD_WAIT: + LOG.warn(_('nbd device allocation failed after repeated ' + 'retries.')) + return False + device = self._inner_get_dev() + return True + def unget_dev(self): if not self.linked: return |
