Improve DB volume check in LVM manage volume

LVM driver makes a call to volume.utils.check_alredy_managed_volume when
managing a new volume in method manage_existing, and this check method
is trying to retrieve the volume for the check, which means getting all
the volume information with joined tables and then converting it to an
ORM object.

This patch improves this check_already_managed_volume by using a simpler
EXISTS DB query.

Change-Id: I132b6bdd05524c955fcd404ed45624e1b1e98320
This commit is contained in:
Gorka Eguileor 2016-05-20 16:02:12 +02:00
parent d669449cd2
commit a85d95084b
6 changed files with 49 additions and 47 deletions

View File

@ -1204,6 +1204,10 @@ def message_destroy(context, message_id):
################### ###################
def resource_exists(context, model, resource_id):
return IMPL.resource_exists(context, model, resource_id)
def get_model_for_versioned_object(versioned_object): def get_model_for_versioned_object(versioned_object):
return IMPL.get_model_for_versioned_object(versioned_object) return IMPL.get_model_for_versioned_object(versioned_object)

View File

@ -416,6 +416,11 @@ class CinderPersistentObject(object):
setattr(self, field, current_field) setattr(self, field, current_field)
self.obj_reset_changes() self.obj_reset_changes()
@classmethod
def exists(cls, context, id_):
model = db.get_model_for_versioned_object(cls)
return db.resource_exists(context, model, id_)
class CinderComparableObject(base.ComparableVersionedObject): class CinderComparableObject(base.ComparableVersionedObject):
def __eq__(self, obj): def __eq__(self, obj):

View File

@ -660,11 +660,10 @@ class LVMVolumeDriverTestCase(DriverTestCase):
model_update = self.volume.driver.manage_existing(vol, ref) model_update = self.volume.driver.manage_existing(vol, ref)
self.assertIsNone(model_update) self.assertIsNone(model_update)
@mock.patch.object(db.sqlalchemy.api, 'volume_get') @mock.patch('cinder.db.sqlalchemy.api.resource_exists', return_value=True)
def test_lvm_manage_existing_already_managed(self, mock_conf): def test_lvm_manage_existing_already_managed(self, exists_mock):
self._setup_stubs_for_manage_existing() self._setup_stubs_for_manage_existing()
mock_conf.volume_name_template = 'volume-%s'
vol_name = 'volume-d8cd1feb-2dcc-404d-9b15-b86fe3bec0a1' vol_name = 'volume-d8cd1feb-2dcc-404d-9b15-b86fe3bec0a1'
ref = {'source-name': vol_name} ref = {'source-name': vol_name}
vol = {'name': 'test', 'id': 1, 'size': 0} vol = {'name': 'test', 'id': 1, 'size': 0}

View File

@ -25,6 +25,7 @@ from oslo_concurrency import processutils
from oslo_config import cfg from oslo_config import cfg
from cinder import context from cinder import context
from cinder.db.sqlalchemy import models
from cinder import exception from cinder import exception
from cinder.objects import fields from cinder.objects import fields
from cinder import test from cinder import test
@ -757,56 +758,51 @@ class VolumeUtilsTestCase(test.TestCase):
host_2 = 'fake_host2@backend1' host_2 = 'fake_host2@backend1'
self.assertFalse(volume_utils.hosts_are_equivalent(host_1, host_2)) self.assertFalse(volume_utils.hosts_are_equivalent(host_1, host_2))
def test_check_managed_volume_already_managed(self): @mock.patch('cinder.db.sqlalchemy.api.resource_exists', return_value=True)
mock_db = mock.Mock() def test_check_managed_volume_already_managed(self, exists_mock):
id_ = 'd8cd1feb-2dcc-404d-9b15-b86fe3bec0a1'
result = volume_utils.check_already_managed_volume( vol_id = 'volume-' + id_
mock_db, 'volume-d8cd1feb-2dcc-404d-9b15-b86fe3bec0a1') result = volume_utils.check_already_managed_volume(vol_id)
self.assertTrue(result) self.assertTrue(result)
exists_mock.assert_called_once_with(mock.ANY, models.Volume, id_)
@mock.patch('cinder.volume.utils.CONF') @mock.patch('cinder.db.sqlalchemy.api.resource_exists', return_value=True)
def test_check_already_managed_with_vol_id_vol_pattern(self, conf_mock): def test_check_already_managed_with_vol_id_vol_pattern(self, exists_mock):
mock_db = mock.Mock() template = 'volume-%s-volume'
conf_mock.volume_name_template = 'volume-%s-volume' self.override_config('volume_name_template', template)
id_ = 'd8cd1feb-2dcc-404d-9b15-b86fe3bec0a1'
vol_id = template % id_
result = volume_utils.check_already_managed_volume( result = volume_utils.check_already_managed_volume(vol_id)
mock_db, 'volume-d8cd1feb-2dcc-404d-9b15-b86fe3bec0a1-volume')
self.assertTrue(result) self.assertTrue(result)
exists_mock.assert_called_once_with(mock.ANY, models.Volume, id_)
@mock.patch('cinder.volume.utils.CONF') @mock.patch('cinder.db.sqlalchemy.api.resource_exists', return_value=True)
def test_check_already_managed_with_id_vol_pattern(self, conf_mock): def test_check_already_managed_with_id_vol_pattern(self, exists_mock):
mock_db = mock.Mock() template = '%s-volume'
conf_mock.volume_name_template = '%s-volume' self.override_config('volume_name_template', template)
id_ = 'd8cd1feb-2dcc-404d-9b15-b86fe3bec0a1'
vol_id = template % id_
result = volume_utils.check_already_managed_volume( result = volume_utils.check_already_managed_volume(vol_id)
mock_db, 'd8cd1feb-2dcc-404d-9b15-b86fe3bec0a1-volume')
self.assertTrue(result) self.assertTrue(result)
exists_mock.assert_called_once_with(mock.ANY, models.Volume, id_)
def test_check_managed_volume_not_managed_cinder_like_name(self): @mock.patch('cinder.db.sqlalchemy.api.resource_exists', return_value=False)
mock_db = mock.Mock() def test_check_managed_volume_not_managed_cinder_like_name(self,
mock_db.volume_get = mock.Mock( exists_mock):
side_effect=exception.VolumeNotFound( id_ = 'd8cd1feb-2dcc-404d-9b15-b86fe3bec0a1'
'volume-d8cd1feb-2dcc-404d-9b15-b86fe3bec0a1')) vol_id = 'volume-' + id_
result = volume_utils.check_already_managed_volume(vol_id)
result = volume_utils.check_already_managed_volume(
mock_db, 'volume-d8cd1feb-2dcc-404d-9b15-b86fe3bec0a1')
self.assertFalse(result) self.assertFalse(result)
exists_mock.assert_called_once_with(mock.ANY, models.Volume, id_)
def test_check_managed_volume_not_managed(self): def test_check_managed_volume_not_managed(self):
mock_db = mock.Mock() result = volume_utils.check_already_managed_volume('test-volume')
result = volume_utils.check_already_managed_volume(
mock_db, 'test-volume')
self.assertFalse(result) self.assertFalse(result)
def test_check_managed_volume_not_managed_id_like_uuid(self): def test_check_managed_volume_not_managed_id_like_uuid(self):
mock_db = mock.Mock() result = volume_utils.check_already_managed_volume('volume-d8cd1fe')
result = volume_utils.check_already_managed_volume(
mock_db, 'volume-d8cd1fe')
self.assertFalse(result) self.assertFalse(result)
def test_convert_config_string_to_dict(self): def test_convert_config_string_to_dict(self):

View File

@ -586,7 +586,7 @@ class LVMVolumeDriver(driver.VolumeDriver):
lv_name = existing_ref['source-name'] lv_name = existing_ref['source-name']
self.vg.get_volume(lv_name) self.vg.get_volume(lv_name)
if volutils.check_already_managed_volume(self.db, lv_name): if volutils.check_already_managed_volume(lv_name):
raise exception.ManageExistingAlreadyManaged(volume_ref=lv_name) raise exception.ManageExistingAlreadyManaged(volume_ref=lv_name)
# Attempt to rename the LV to match the OpenStack internal name. # Attempt to rename the LV to match the OpenStack internal name.

View File

@ -38,6 +38,7 @@ from cinder import context
from cinder import db from cinder import db
from cinder import exception from cinder import exception
from cinder.i18n import _, _LI, _LW, _LE from cinder.i18n import _, _LI, _LW, _LE
from cinder import objects
from cinder import rpc from cinder import rpc
from cinder import utils from cinder import utils
from cinder.volume import throttling from cinder.volume import throttling
@ -670,22 +671,19 @@ def _extract_id(vol_name):
return match.group('uuid') if match else None return match.group('uuid') if match else None
def check_already_managed_volume(db, vol_name): def check_already_managed_volume(vol_name):
"""Check cinder db for already managed volume. """Check cinder db for already managed volume.
:param db: database api parameter
:param vol_name: volume name parameter :param vol_name: volume name parameter
:returns: bool -- return True, if db entry with specified :returns: bool -- return True, if db entry with specified
volume name exist, otherwise return False volume name exist, otherwise return False
""" """
vol_id = _extract_id(vol_name) vol_id = _extract_id(vol_name)
try: try:
if vol_id and uuid.UUID(vol_id, version=4): return (vol_id and uuid.UUID(vol_id, version=4) and
db.volume_get(context.get_admin_context(), vol_id) objects.Volume.exists(context.get_admin_context(), vol_id))
return True except ValueError:
except (exception.VolumeNotFound, ValueError):
return False return False
return False
def convert_config_string_to_dict(config_string): def convert_config_string_to_dict(config_string):