summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2014-09-19 00:29:03 +0000
committerGerrit Code Review <review@openstack.org>2014-09-19 00:29:03 +0000
commit0ecad55d846a5aae9196b6be2f417bff918956c0 (patch)
tree50506ee6e8040f3cdeb85bdbfe7948e7a4fd941f
parent1a8af2e03edfe9bfbfbfd7d65623813f6e149476 (diff)
parent69c86d4fe15c33a6d96550e11d4453d2c4839ef3 (diff)
downloadnova-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.py6
-rw-r--r--nova/tests/virt/libvirt/test_imagebackend.py19
-rw-r--r--nova/tests/virt/libvirt/test_libvirt.py6
-rw-r--r--nova/virt/libvirt/driver.py2
-rw-r--r--nova/virt/libvirt/imagebackend.py84
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)