Merge "CG creation should be scheduled on backend level"
This commit is contained in:
commit
6a942ba647
@ -397,7 +397,10 @@ class FilterScheduler(driver.Scheduler):
|
|||||||
new_weighed_hosts = []
|
new_weighed_hosts = []
|
||||||
for host1 in weighed_hosts:
|
for host1 in weighed_hosts:
|
||||||
for host2 in temp_weighed_hosts:
|
for host2 in temp_weighed_hosts:
|
||||||
if host1.obj.host == host2.obj.host:
|
# Should schedule creation of CG on backend level,
|
||||||
|
# not pool level.
|
||||||
|
if (utils.extract_host(host1.obj.host) ==
|
||||||
|
utils.extract_host(host2.obj.host)):
|
||||||
new_weighed_hosts.append(host1)
|
new_weighed_hosts.append(host1)
|
||||||
weighed_hosts = new_weighed_hosts
|
weighed_hosts = new_weighed_hosts
|
||||||
if not weighed_hosts:
|
if not weighed_hosts:
|
||||||
@ -410,6 +413,16 @@ class FilterScheduler(driver.Scheduler):
|
|||||||
def _schedule(self, context, request_spec, filter_properties=None):
|
def _schedule(self, context, request_spec, filter_properties=None):
|
||||||
weighed_hosts = self._get_weighted_candidates(context, request_spec,
|
weighed_hosts = self._get_weighted_candidates(context, request_spec,
|
||||||
filter_properties)
|
filter_properties)
|
||||||
|
# When we get the weighed_hosts, we clear those hosts whose backend
|
||||||
|
# is not same as consistencygroup's backend.
|
||||||
|
CG_backend = request_spec.get('CG_backend')
|
||||||
|
if weighed_hosts and CG_backend:
|
||||||
|
# Get host name including host@backend#pool info from
|
||||||
|
# weighed_hosts.
|
||||||
|
for host in weighed_hosts[::-1]:
|
||||||
|
backend = utils.extract_host(host.obj.host)
|
||||||
|
if backend != CG_backend:
|
||||||
|
weighed_hosts.remove(host)
|
||||||
if not weighed_hosts:
|
if not weighed_hosts:
|
||||||
LOG.warning(_LW('No weighed hosts found for volume '
|
LOG.warning(_LW('No weighed hosts found for volume '
|
||||||
'with properties: %s'),
|
'with properties: %s'),
|
||||||
|
@ -192,6 +192,37 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
|
|||||||
self.assertIsNotNone(weighed_host.obj)
|
self.assertIsNotNone(weighed_host.obj)
|
||||||
self.assertTrue(_mock_service_get_all_by_topic.called)
|
self.assertTrue(_mock_service_get_all_by_topic.called)
|
||||||
|
|
||||||
|
@mock.patch('cinder.db.service_get_all_by_topic')
|
||||||
|
def test_create_volume_clear_host_different_with_cg(self,
|
||||||
|
_mock_service_get_all):
|
||||||
|
# Ensure we clear those hosts whose backend is not same as
|
||||||
|
# consistencygroup's backend.
|
||||||
|
sched = fakes.FakeFilterScheduler()
|
||||||
|
sched.host_manager = fakes.FakeHostManager()
|
||||||
|
fakes.mock_host_manager_db_calls(_mock_service_get_all)
|
||||||
|
fake_context = context.RequestContext('user', 'project')
|
||||||
|
request_spec = {'volume_properties': {'project_id': 1,
|
||||||
|
'size': 1},
|
||||||
|
'volume_type': {'name': 'LVM_iSCSI'},
|
||||||
|
'CG_backend': 'host@lvmdriver'}
|
||||||
|
weighed_host = sched._schedule(fake_context, request_spec, {})
|
||||||
|
self.assertIsNone(weighed_host)
|
||||||
|
|
||||||
|
@mock.patch('cinder.db.service_get_all_by_topic')
|
||||||
|
def test_create_volume_host_same_as_cg(self, _mock_service_get_all):
|
||||||
|
# Ensure we don't clear the host whose backend is same as
|
||||||
|
# consistencygroup's backend.
|
||||||
|
sched = fakes.FakeFilterScheduler()
|
||||||
|
sched.host_manager = fakes.FakeHostManager()
|
||||||
|
fakes.mock_host_manager_db_calls(_mock_service_get_all)
|
||||||
|
fake_context = context.RequestContext('user', 'project')
|
||||||
|
request_spec = {'volume_properties': {'project_id': 1,
|
||||||
|
'size': 1},
|
||||||
|
'volume_type': {'name': 'LVM_iSCSI'},
|
||||||
|
'CG_backend': 'host1'}
|
||||||
|
weighed_host = sched._schedule(fake_context, request_spec, {})
|
||||||
|
self.assertEqual('host1#lvm1', weighed_host.obj.host)
|
||||||
|
|
||||||
def test_max_attempts(self):
|
def test_max_attempts(self):
|
||||||
self.flags(scheduler_max_attempts=4)
|
self.flags(scheduler_max_attempts=4)
|
||||||
|
|
||||||
|
@ -50,14 +50,16 @@ class CreateVolumeFlowTestCase(test.TestCase):
|
|||||||
# called to avoid div by zero errors.
|
# called to avoid div by zero errors.
|
||||||
self.counter = float(0)
|
self.counter = float(0)
|
||||||
|
|
||||||
|
@mock.patch('cinder.volume.utils.extract_host')
|
||||||
@mock.patch('time.time', side_effect=time_inc)
|
@mock.patch('time.time', side_effect=time_inc)
|
||||||
@mock.patch('cinder.objects.ConsistencyGroup.get_by_id')
|
@mock.patch('cinder.objects.ConsistencyGroup.get_by_id')
|
||||||
def test_cast_create_volume(self, consistencygroup_get_by_id, mock_time):
|
def test_cast_create_volume(self, consistencygroup_get_by_id, mock_time,
|
||||||
|
mock_extract_host):
|
||||||
props = {}
|
props = {}
|
||||||
consistencygroup_obj = \
|
cg_obj = (fake_consistencygroup.
|
||||||
fake_consistencygroup.fake_consistencyobject_obj(
|
fake_consistencyobject_obj(self.ctxt, consistencygroup_id=1,
|
||||||
self.ctxt, consistencygroup_id=1, host=None)
|
host='host@backend#pool'))
|
||||||
consistencygroup_get_by_id.return_value = consistencygroup_obj
|
consistencygroup_get_by_id.return_value = cg_obj
|
||||||
spec = {'volume_id': None,
|
spec = {'volume_id': None,
|
||||||
'source_volid': None,
|
'source_volid': None,
|
||||||
'snapshot_id': None,
|
'snapshot_id': None,
|
||||||
@ -90,6 +92,7 @@ class CreateVolumeFlowTestCase(test.TestCase):
|
|||||||
|
|
||||||
task._cast_create_volume(self.ctxt, spec, props)
|
task._cast_create_volume(self.ctxt, spec, props)
|
||||||
consistencygroup_get_by_id.assert_called_once_with(self.ctxt, 5)
|
consistencygroup_get_by_id.assert_called_once_with(self.ctxt, 5)
|
||||||
|
mock_extract_host.assert_called_once_with('host@backend#pool')
|
||||||
|
|
||||||
@mock.patch('cinder.volume.volume_types.is_encrypted')
|
@mock.patch('cinder.volume.volume_types.is_encrypted')
|
||||||
@mock.patch('cinder.volume.flows.api.create_volume.'
|
@mock.patch('cinder.volume.flows.api.create_volume.'
|
||||||
|
@ -27,6 +27,7 @@ from cinder import policy
|
|||||||
from cinder import quota
|
from cinder import quota
|
||||||
from cinder import utils
|
from cinder import utils
|
||||||
from cinder.volume.flows import common
|
from cinder.volume.flows import common
|
||||||
|
from cinder.volume import utils as vol_utils
|
||||||
from cinder.volume import volume_types
|
from cinder.volume import volume_types
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
@ -697,8 +698,14 @@ class VolumeCastTask(flow_utils.CinderTask):
|
|||||||
cgsnapshot_id = request_spec['cgsnapshot_id']
|
cgsnapshot_id = request_spec['cgsnapshot_id']
|
||||||
|
|
||||||
if cgroup_id:
|
if cgroup_id:
|
||||||
|
# If cgroup_id existed, we should cast volume to the scheduler
|
||||||
|
# to choose a proper pool whose backend is same as CG's backend.
|
||||||
cgroup = objects.ConsistencyGroup.get_by_id(context, cgroup_id)
|
cgroup = objects.ConsistencyGroup.get_by_id(context, cgroup_id)
|
||||||
host = cgroup.host
|
# FIXME(wanghao): CG_backend got added before request_spec was
|
||||||
|
# converted to versioned objects. We should make sure that this
|
||||||
|
# will be handled by object version translations once we add
|
||||||
|
# RequestSpec object.
|
||||||
|
request_spec['CG_backend'] = vol_utils.extract_host(cgroup.host)
|
||||||
elif snapshot_id and CONF.snapshot_same_host:
|
elif snapshot_id and CONF.snapshot_same_host:
|
||||||
# NOTE(Rongze Zhu): A simple solution for bug 1008866.
|
# NOTE(Rongze Zhu): A simple solution for bug 1008866.
|
||||||
#
|
#
|
||||||
|
Loading…
x
Reference in New Issue
Block a user