Add IOPS limits that scale per-GB
This allows new values in QoS specs: - read_iops_sec_per_gb - write_iops_sec_per_gb - total_iops_sec_per_gb The IOPS value specifed in the QoS spec is multiplied by the size of the volume in initialize_connection, and the result is passed along like a standard <x>_iops_sec QoS value. Implements: blueprint capacity-based-qos Change-Id: Ic10880c264f4ecaae4f9f49ecc4aabb1a4b56163
This commit is contained in:
parent
5072a2c0f9
commit
aa563283f3
|
@ -31,6 +31,8 @@ from cinder.tests.unit import fake_volume
|
|||
from cinder.tests.unit import utils as tests_utils
|
||||
from cinder.tests.unit import volume as base
|
||||
import cinder.volume
|
||||
import cinder.volume.targets
|
||||
import cinder.volume.targets.iscsi
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
|
@ -162,6 +164,63 @@ class VolumeConnectionTestCase(base.BaseVolumeTestCase):
|
|||
self.context, fake_volume_obj, connector)
|
||||
self.assertIsNone(conn_info['data']['qos_specs'])
|
||||
|
||||
@mock.patch.object(cinder.volume.targets.iscsi.ISCSITarget,
|
||||
'_get_target_chap_auth')
|
||||
@mock.patch.object(db, 'volume_admin_metadata_get')
|
||||
@mock.patch.object(db.sqlalchemy.api, 'volume_get')
|
||||
@mock.patch.object(db, 'volume_update')
|
||||
def test_initialize_connection_qos_per_gb(self,
|
||||
_mock_volume_update,
|
||||
_mock_volume_get,
|
||||
_mock_volume_admin_metadata_get,
|
||||
mock_get_target):
|
||||
"""Make sure initialize_connection returns correct information."""
|
||||
_fake_admin_meta = [{'key': 'fake-key', 'value': 'fake-value'}]
|
||||
_fake_volume = {'size': 3,
|
||||
'volume_type_id': fake.VOLUME_TYPE_ID,
|
||||
'name': 'fake_name',
|
||||
'host': 'fake_host',
|
||||
'id': fake.VOLUME_ID,
|
||||
'volume_admin_metadata': _fake_admin_meta}
|
||||
fake_volume_obj = fake_volume.fake_volume_obj(self.context,
|
||||
**_fake_volume)
|
||||
|
||||
_mock_volume_get.return_value = _fake_volume
|
||||
_mock_volume_update.return_value = _fake_volume
|
||||
_mock_volume_admin_metadata_get.return_value = {
|
||||
'fake-key': 'fake-value'}
|
||||
|
||||
connector = {'ip': 'IP', 'initiator': 'INITIATOR'}
|
||||
qos_values = {'consumer': 'front-end',
|
||||
'specs': {
|
||||
'write_iops_sec_per_gb': 5,
|
||||
'read_iops_sec_per_gb': 7700,
|
||||
'total_iops_sec_per_gb': 300000}
|
||||
}
|
||||
|
||||
with mock.patch.object(cinder.volume.volume_types,
|
||||
'get_volume_type_qos_specs') as type_qos, \
|
||||
mock.patch.object(cinder.tests.fake_driver.FakeLoggingVolumeDriver,
|
||||
'initialize_connection') as driver_init:
|
||||
type_qos.return_value = dict(qos_specs=qos_values)
|
||||
driver_init.return_value = {'data': {}}
|
||||
mock_get_target.return_value = None
|
||||
qos_specs_expected = {'write_iops_sec': 15,
|
||||
'read_iops_sec': 23100,
|
||||
'total_iops_sec': 900000}
|
||||
# initialize_connection() passes qos_specs that is designated to
|
||||
# be consumed by front-end or both front-end and back-end
|
||||
conn_info = self.volume.initialize_connection(
|
||||
self.context, fake_volume_obj, connector,)
|
||||
self.assertDictEqual(qos_specs_expected,
|
||||
conn_info['data']['qos_specs'])
|
||||
|
||||
qos_values.update({'consumer': 'both'})
|
||||
conn_info = self.volume.initialize_connection(
|
||||
self.context, fake_volume_obj, connector)
|
||||
self.assertDictEqual(qos_specs_expected,
|
||||
conn_info['data']['qos_specs'])
|
||||
|
||||
@mock.patch.object(fake_driver.FakeLoggingVolumeDriver, 'create_export')
|
||||
def test_initialize_connection_export_failure(self,
|
||||
_mock_create_export):
|
||||
|
|
|
@ -1408,6 +1408,23 @@ class VolumeManager(manager.CleanableManager,
|
|||
if qos and qos.get('consumer') in ['front-end', 'both']:
|
||||
specs = qos.get('specs')
|
||||
|
||||
if specs is not None:
|
||||
# Compute fixed IOPS values for per-GB keys
|
||||
if 'write_iops_sec_per_gb' in specs:
|
||||
specs['write_iops_sec'] = (
|
||||
int(specs['write_iops_sec_per_gb']) * int(volume.size))
|
||||
specs.pop('write_iops_sec_per_gb')
|
||||
|
||||
if 'read_iops_sec_per_gb' in specs:
|
||||
specs['read_iops_sec'] = (
|
||||
int(specs['read_iops_sec_per_gb']) * int(volume.size))
|
||||
specs.pop('read_iops_sec_per_gb')
|
||||
|
||||
if 'total_iops_sec_per_gb' in specs:
|
||||
specs['total_iops_sec'] = (
|
||||
int(specs['total_iops_sec_per_gb']) * int(volume.size))
|
||||
specs.pop('total_iops_sec_per_gb')
|
||||
|
||||
qos_spec = dict(qos_specs=specs)
|
||||
conn_info['data'].update(qos_spec)
|
||||
|
||||
|
|
Loading…
Reference in New Issue