Make scheduler check online_extend_support capability
Since Pike release, Cinder supports volume online extending, and by default it assumes that every backend supports this feature. This assumption causes a bug on those backends that don't support it. On such backends, an online extending attempt leaves the volume in error_extending state. This patch allows a backend to report to the scheduler if it does not support online extending. This way, an online extending attempt will fail, without leaving the volume in error_extending state. Closes-bug: #1765182 Change-Id: I2c31b5c171574074a8fc7ba86f94f983fc9658f7 Co-Authored-By: Lucio Seki <luciomitsuru.seki@fit-tecnologia.org.br>
This commit is contained in:
parent
06817266df
commit
f33b234aa0
@ -132,6 +132,9 @@ class VolumeDriverCore(base.CinderInterface):
|
||||
* sparse_copy_volume (Boolean)
|
||||
Whether copies performed by the volume manager for operations such
|
||||
as migration should attempt to preserve sparseness.
|
||||
* online_extend_support (Boolean)
|
||||
Whether the backend supports in-use volume extend or not. Defaults
|
||||
to True.
|
||||
|
||||
The returned dict may also contain a list, "pools", which has a similar
|
||||
dict for each pool being used with the backend.
|
||||
@ -255,6 +258,9 @@ class VolumeDriverCore(base.CinderInterface):
|
||||
|
||||
:param volume: The volume to extend.
|
||||
:param new_size: The new desired size of the volume.
|
||||
|
||||
Note that if the volume backend doesn't support extending an in-use
|
||||
volume, the driver should report online_extend_support=False.
|
||||
"""
|
||||
|
||||
def create_snapshot(self, snapshot):
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
from cinder.objects.fields import VolumeAttachStatus
|
||||
from cinder.scheduler import filters
|
||||
from cinder.scheduler.filters import extra_specs_ops
|
||||
|
||||
@ -24,13 +25,27 @@ LOG = logging.getLogger(__name__)
|
||||
class CapabilitiesFilter(filters.BaseBackendFilter):
|
||||
"""BackendFilter to work with resource (instance & volume) type records."""
|
||||
|
||||
def _satisfies_extra_specs(self, capabilities, resource_type):
|
||||
def _satisfies_extra_specs(self, capabilities, filter_properties):
|
||||
"""Check if capabilities satisfy resource type requirements.
|
||||
|
||||
Check that the capabilities provided by the services satisfy
|
||||
the extra specs associated with the resource type.
|
||||
"""
|
||||
|
||||
req_spec = filter_properties.get('request_spec')
|
||||
if req_spec and req_spec.get('operation') == 'extend_volume':
|
||||
# NOTE(erlon): By default, cinder considers that every backend
|
||||
# supports volume online extending. Those backends that don't
|
||||
# support it should report online_extend_support=False.
|
||||
online_extends = capabilities.get('online_extend_support', True)
|
||||
if online_extends is False:
|
||||
vol_prop = req_spec.get('volume_properties')
|
||||
attach_status = vol_prop.get('attach_status')
|
||||
if attach_status != VolumeAttachStatus.DETACHED:
|
||||
LOG.debug("Backend doesn't support attached volume extend")
|
||||
return False
|
||||
|
||||
resource_type = filter_properties.get('resource_type')
|
||||
if not resource_type:
|
||||
return True
|
||||
|
||||
@ -80,9 +95,8 @@ class CapabilitiesFilter(filters.BaseBackendFilter):
|
||||
# Note(zhiteng) Currently only Cinder and Nova are using
|
||||
# this filter, so the resource type is either instance or
|
||||
# volume.
|
||||
resource_type = filter_properties.get('resource_type')
|
||||
if not self._satisfies_extra_specs(backend_state.capabilities,
|
||||
resource_type):
|
||||
filter_properties):
|
||||
LOG.debug("%(backend_state)s fails resource_type extra_specs "
|
||||
"requirements", {'backend_state': backend_state})
|
||||
return False
|
||||
|
@ -39,6 +39,7 @@ SERVICE_STATES = {
|
||||
'volume_backend_name': 'lvm1',
|
||||
'timestamp': UTC_NOW,
|
||||
'multiattach': True,
|
||||
'online_extend_support': True,
|
||||
'uuid': 'a3a593da-7f8d-4bb7-8b4c-f2bc1e0b4824'},
|
||||
'host2': {'total_capacity_gb': 2048,
|
||||
'free_capacity_gb': 300,
|
||||
@ -50,6 +51,7 @@ SERVICE_STATES = {
|
||||
'reserved_percentage': 10,
|
||||
'volume_backend_name': 'lvm2',
|
||||
'timestamp': UTC_NOW,
|
||||
'online_extend_support': False,
|
||||
'uuid': '4200b32b-0bf9-436c-86b2-0675f6ac218e'},
|
||||
'host3': {'total_capacity_gb': 512,
|
||||
'free_capacity_gb': 256,
|
||||
|
@ -426,6 +426,42 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
|
||||
ctx, 'host1#lvm1', request_spec, {})
|
||||
self.assertTrue(_mock_service_get_topic.called)
|
||||
|
||||
@mock.patch('cinder.db.service_get_all')
|
||||
def test_backend_passes_filters_online_extend_support_happy_day(
|
||||
self, _mock_service_get_topic):
|
||||
"""Do a successful online extend with backend_passes_filters()."""
|
||||
sched, ctx = self._backend_passes_filters_setup(
|
||||
_mock_service_get_topic)
|
||||
request_spec = {'volume_id': fake.VOLUME_ID,
|
||||
'volume_type': {'name': 'LVM_iSCSI'},
|
||||
'volume_properties': {'project_id': 1,
|
||||
'size': 1,
|
||||
'attach_status': 'attached'},
|
||||
'operation': 'extend_volume'}
|
||||
request_spec = objects.RequestSpec.from_primitives(request_spec)
|
||||
# host1#lvm1 has online_extend_support = True
|
||||
sched.backend_passes_filters(ctx, 'host1#lvm1', request_spec, {})
|
||||
self.assertTrue(_mock_service_get_topic.called)
|
||||
|
||||
@mock.patch('cinder.db.service_get_all')
|
||||
def test_backend_passes_filters_no_online_extend_support(
|
||||
self, _mock_service_get_topic):
|
||||
"""Fail the host due to lack of online extend support."""
|
||||
sched, ctx = self._backend_passes_filters_setup(
|
||||
_mock_service_get_topic)
|
||||
request_spec = {'volume_id': fake.VOLUME_ID,
|
||||
'volume_type': {'name': 'LVM_iSCSI'},
|
||||
'volume_properties': {'project_id': 1,
|
||||
'size': 1,
|
||||
'attach_status': 'attached'},
|
||||
'operation': 'extend_volume'}
|
||||
request_spec = objects.RequestSpec.from_primitives(request_spec)
|
||||
# host2#lvm2 has online_extend_support = False
|
||||
self.assertRaises(exception.NoValidBackend,
|
||||
sched.backend_passes_filters,
|
||||
ctx, 'host2#lvm2', request_spec, {})
|
||||
self.assertTrue(_mock_service_get_topic.called)
|
||||
|
||||
@mock.patch('cinder.db.service_get_all')
|
||||
def test_retype_policy_never_migrate_pass(self, _mock_service_get_topic):
|
||||
# Retype should pass if current host passes filters and
|
||||
|
@ -87,6 +87,11 @@ the backend cannot report the value or 'infinite' if the backend has no upper
|
||||
limit. But, it is recommended to report real values as the Cinder scheduler
|
||||
assigns lowest weight to any storage backend reporting 'unknown' or 'infinite'.
|
||||
|
||||
**NOTE:** By default, Cinder assumes that the driver supports attached volume
|
||||
extending. If it doesn't, it should report 'online_extend_support=False'.
|
||||
Otherwise the scheduler will attempt to perform the operation, and may leave
|
||||
the volume in 'error_extending' state.
|
||||
|
||||
Feature Enforcement
|
||||
-------------------
|
||||
|
||||
|
5
releasenotes/notes/bug-1765182-bcafd577f4b81eb6.yaml
Normal file
5
releasenotes/notes/bug-1765182-bcafd577f4b81eb6.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
fixes:
|
||||
- |
|
||||
Make Cinder scheduler check if backend reports `online_extend_support`
|
||||
before performing an online extend operation.
|
Loading…
Reference in New Issue
Block a user