diff options
author | Jenkins <jenkins@review.openstack.org> | 2014-09-19 00:29:03 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2014-09-19 00:29:03 +0000 |
commit | 0ecad55d846a5aae9196b6be2f417bff918956c0 (patch) | |
tree | 50506ee6e8040f3cdeb85bdbfe7948e7a4fd941f | |
parent | 1a8af2e03edfe9bfbfbfd7d65623813f6e149476 (diff) | |
parent | 69c86d4fe15c33a6d96550e11d4453d2c4839ef3 (diff) | |
download | nova-0ecad55d846a5aae9196b6be2f417bff918956c0.tar.gz |
Merge "Fix incorrect root partition size and compatible volume name" into stable/havana
-rw-r--r-- | nova/tests/virt/libvirt/fake_libvirt_utils.py | 6 | ||||
-rw-r--r-- | nova/tests/virt/libvirt/test_imagebackend.py | 19 | ||||
-rw-r--r-- | nova/tests/virt/libvirt/test_libvirt.py | 6 | ||||
-rw-r--r-- | nova/virt/libvirt/driver.py | 2 | ||||
-rw-r--r-- | nova/virt/libvirt/imagebackend.py | 84 |
5 files changed, 109 insertions, 8 deletions
diff --git a/nova/tests/virt/libvirt/fake_libvirt_utils.py b/nova/tests/virt/libvirt/fake_libvirt_utils.py index 1872922674..21ee7c47b9 100644 --- a/nova/tests/virt/libvirt/fake_libvirt_utils.py +++ b/nova/tests/virt/libvirt/fake_libvirt_utils.py @@ -203,8 +203,10 @@ def pick_disk_driver_name(hypervisor_version, is_block_dev=False): def list_rbd_volumes(pool): - fake_volumes = ['fakeinstancename.local', 'fakeinstancename.swap', - 'fakeinstancename', 'wronginstancename'] + fake_volumes = ['875a8070-d0b9-4949-8b31-104d125c9a64.local', + '875a8070-d0b9-4949-8b31-104d125c9a64.swap', + '875a8070-d0b9-4949-8b31-104d125c9a64', + 'wrong875a8070-d0b9-4949-8b31-104d125c9a64'] return fake_volumes diff --git a/nova/tests/virt/libvirt/test_imagebackend.py b/nova/tests/virt/libvirt/test_imagebackend.py index 5424f7b300..3935fe404e 100644 --- a/nova/tests/virt/libvirt/test_imagebackend.py +++ b/nova/tests/virt/libvirt/test_imagebackend.py @@ -20,6 +20,7 @@ import shutil import tempfile import fixtures +import mock from oslo.config import cfg from inspect import getargspec @@ -736,10 +737,12 @@ class RbdTestCase(_ImageTestCase, test.NoDBTestCase): self.libvirt_utils = imagebackend.libvirt_utils self.utils = imagebackend.utils self.rbd = self.mox.CreateMockAnything() + self.rados = self.mox.CreateMockAnything() def prepare_mocks(self): fn = self.mox.CreateMockAnything() self.mox.StubOutWithMock(imagebackend, 'rbd') + self.mox.StubOutWithMock(imagebackend, 'rados') return fn def test_cache(self): @@ -830,6 +833,9 @@ class RbdTestCase(_ImageTestCase, test.NoDBTestCase): self.rbd.RBD_FEATURE_LAYERING = 1 + self.mox.StubOutWithMock(imagebackend.disk, 'get_disk_size') + imagebackend.disk.get_disk_size(self.TEMPLATE_PATH + ).AndReturn(self.SIZE) rbd_name = "%s/%s" % (self.INSTANCE['name'], self.NAME) cmd = ('--pool', self.POOL, self.TEMPLATE_PATH, rbd_name, '--new-format', '--id', self.USER, @@ -848,11 +854,15 @@ class RbdTestCase(_ImageTestCase, test.NoDBTestCase): fake_processutils.fake_execute_clear_log() fake_processutils.stub_out_processutils_execute(self.stubs) self.mox.StubOutWithMock(imagebackend, 'rbd') + self.mox.StubOutWithMock(imagebackend, 'rados') image = self.image_class(self.INSTANCE, self.NAME) def fake_fetch(target, *args, **kwargs): return + def fake_resize(rbd_name, size): + return + self.stubs.Set(os.path, 'exists', lambda _: True) self.stubs.Set(image, 'check_image_exists', lambda: True) @@ -864,6 +874,15 @@ class RbdTestCase(_ImageTestCase, test.NoDBTestCase): self.assertEqual(getargspec(imagebackend.Image.libvirt_info), getargspec(self.image_class.libvirt_info)) + def test_resize(self): + image = self.image_class(self.INSTANCE, self.NAME) + with mock.patch.object(imagebackend, "RBDVolumeProxy") as mock_proxy: + volume_mock = mock.Mock() + mock_proxy.side_effect = [mock_proxy] + mock_proxy.__enter__.side_effect = [volume_mock] + image._resize(image.rbd_name, self.SIZE) + volume_mock.resize.assert_called_once_with(self.SIZE) + class BackendTestCase(test.NoDBTestCase): INSTANCE = {'name': 'fake-instance', diff --git a/nova/tests/virt/libvirt/test_libvirt.py b/nova/tests/virt/libvirt/test_libvirt.py index 3b426cf0bb..4725612377 100644 --- a/nova/tests/virt/libvirt/test_libvirt.py +++ b/nova/tests/virt/libvirt/test_libvirt.py @@ -4436,8 +4436,10 @@ class LibvirtConnTestCase(test.TestCase): def fake_get_info(instance_name): return {'state': power_state.SHUTDOWN, 'id': -1} - fake_volumes = ['fakeinstancename.local', 'fakeinstancename.swap', - 'fakeinstancename', 'wronginstancename'] + fake_volumes = ['875a8070-d0b9-4949-8b31-104d125c9a64.local', + '875a8070-d0b9-4949-8b31-104d125c9a64.swap', + '875a8070-d0b9-4949-8b31-104d125c9a64', + 'wrong875a8070-d0b9-4949-8b31-104d125c9a64'] fake_pool = 'fake_pool' fake_instance = {'name': 'fakeinstancename', 'id': 'instanceid', 'uuid': '875a8070-d0b9-4949-8b31-104d125c9a64'} diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index 150024e3be..0fc6974912 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -971,7 +971,7 @@ class LibvirtDriver(driver.ComputeDriver): def _cleanup_rbd(self, instance): pool = CONF.libvirt_images_rbd_pool volumes = libvirt_utils.list_rbd_volumes(pool) - pattern = instance['name'] + pattern = instance['uuid'] def belongs_to_instance(disk): return disk.startswith(pattern) diff --git a/nova/virt/libvirt/imagebackend.py b/nova/virt/libvirt/imagebackend.py index 3aee01067d..ca46add554 100644 --- a/nova/virt/libvirt/imagebackend.py +++ b/nova/virt/libvirt/imagebackend.py @@ -35,8 +35,10 @@ from nova.virt.libvirt import utils as libvirt_utils try: + import rados import rbd except ImportError: + rados = None rbd = None @@ -468,6 +470,51 @@ class Lvm(Image): run_as_root=True) +class RBDVolumeProxy(object): + """Context manager for dealing with an existing rbd volume. + + This handles connecting to rados and opening an ioctx automatically, and + otherwise acts like a librbd Image object. + + The underlying librados client and ioctx can be accessed as the attributes + 'client' and 'ioctx'. + """ + def __init__(self, driver, name, pool=None): + client, ioctx = driver._connect_to_rados(pool) + try: + self.volume = driver.rbd.Image(ioctx, str(name), snapshot=None) + except driver.rbd.Error: + LOG.exception(_("error opening rbd image %s"), name) + driver._disconnect_from_rados(client, ioctx) + raise + self.driver = driver + self.client = client + self.ioctx = ioctx + + def __enter__(self): + return self + + def __exit__(self, type_, value, traceback): + try: + self.volume.close() + finally: + self.driver._disconnect_from_rados(self.client, self.ioctx) + + def __getattr__(self, attrib): + return getattr(self.volume, attrib) + + +def ascii_str(s): + """Convert a string to ascii, or return None if the input is None. + + This is useful when a parameter is None by default, or a string. LibRBD + only accepts ascii, hence the need for conversion. + """ + if s is None: + return s + return str(s) + + class Rbd(Image): def __init__(self, instance=None, disk_name=None, path=None, **kwargs): super(Rbd, self).__init__("block", "rbd", is_block_dev=True) @@ -477,21 +524,41 @@ class Rbd(Image): except IndexError: raise exception.InvalidDevicePath(path=path) else: - self.rbd_name = '%s_%s' % (instance['name'], disk_name) + self.rbd_name = '%s_%s' % (instance['uuid'], disk_name) if not CONF.libvirt_images_rbd_pool: raise RuntimeError(_('You should specify' ' libvirt_images_rbd_pool' ' flag to use rbd images.')) self.pool = CONF.libvirt_images_rbd_pool - self.ceph_conf = CONF.libvirt_images_rbd_ceph_conf + self.ceph_conf = ascii_str(CONF.libvirt_images_rbd_ceph_conf) + self.rbd_user = ascii_str(CONF.rbd_user) self.rbd = kwargs.get('rbd', rbd) + self.rados = kwargs.get('rados', rados) + + def _connect_to_rados(self, pool=None): + client = self.rados.Rados(rados_id=self.rbd_user, + conffile=self.ceph_conf) + try: + client.connect() + pool_to_open = str(pool or self.pool) + ioctx = client.open_ioctx(pool_to_open) + return client, ioctx + except self.rados.Error: + # shutdown cannot raise an exception + client.shutdown() + raise + + def _disconnect_from_rados(self, client, ioctx): + # closing an ioctx cannot raise an exception + ioctx.close() + client.shutdown() def _supports_layering(self): return hasattr(self.rbd, 'RBD_FEATURE_LAYERING') def _ceph_args(self): args = [] - args.extend(['--id', CONF.rbd_user]) + args.extend(['--id', self.rbd_user]) args.extend(['--conf', self.ceph_conf]) return args @@ -557,6 +624,12 @@ class Rbd(Image): return False + def _resize(self, volume_name, size): + size = int(size) + + with RBDVolumeProxy(self, volume_name) as vol: + vol.resize(size) + def create_image(self, prepare_template, base, size, *args, **kwargs): if self.rbd is None: raise RuntimeError(_('rbd python libraries not found')) @@ -580,6 +653,11 @@ class Rbd(Image): args += self._ceph_args() libvirt_utils.import_rbd_image(*args) + base_size = disk.get_disk_size(base) + + if size and size > base_size: + self._resize(self.rbd_name, size) + def snapshot_extract(self, target, out_format): snap = 'rbd:%s/%s' % (self.pool, self.rbd_name) images.convert_image(snap, target, out_format) |