NetApp SolidFire: Add options for replication mode
This adds the option to specify the replication mode as: Synchronous, Asynchronous or SnapshotOnly. Depends-On: I920f958db1d48e52b548082d852c03f427a279ca Change-Id: I74d31e7a262f3a59f5e82c710f3ca5fd84e3ea60
This commit is contained in:
parent
33b32d9820
commit
ddc91052e4
@ -18,7 +18,10 @@ import datetime
|
|||||||
import re
|
import re
|
||||||
import six
|
import six
|
||||||
|
|
||||||
import ddt
|
from ddt import data
|
||||||
|
from ddt import ddt
|
||||||
|
from ddt import file_data
|
||||||
|
from ddt import unpack
|
||||||
import mock
|
import mock
|
||||||
from oslo_utils import timeutils
|
from oslo_utils import timeutils
|
||||||
from oslo_utils import units
|
from oslo_utils import units
|
||||||
@ -63,7 +66,7 @@ f_uuid = ['262b9ce2-a71a-4fbe-830c-c20c5596caea',
|
|||||||
'362b9ce2-a71a-4fbe-830c-c20c5596caea']
|
'362b9ce2-a71a-4fbe-830c-c20c5596caea']
|
||||||
|
|
||||||
|
|
||||||
@ddt.ddt
|
@ddt
|
||||||
class SolidFireVolumeTestCase(test.TestCase):
|
class SolidFireVolumeTestCase(test.TestCase):
|
||||||
|
|
||||||
EXPECTED_QOS = {'minIOPS': 110, 'burstIOPS': 1530, 'maxIOPS': 1020}
|
EXPECTED_QOS = {'minIOPS': 110, 'burstIOPS': 1530, 'maxIOPS': 1020}
|
||||||
@ -1237,8 +1240,8 @@ class SolidFireVolumeTestCase(test.TestCase):
|
|||||||
qos = sfv._set_qos_by_volume_type(self.ctxt, type_ref['id'], size)
|
qos = sfv._set_qos_by_volume_type(self.ctxt, type_ref['id'], size)
|
||||||
self.assertEqual(self.expected_qos_results, qos)
|
self.assertEqual(self.expected_qos_results, qos)
|
||||||
|
|
||||||
@ddt.file_data("scaled_iops_test_data.json")
|
@file_data("scaled_iops_test_data.json")
|
||||||
@ddt.unpack
|
@unpack
|
||||||
def test_scaled_qos_spec_by_type(self, argument):
|
def test_scaled_qos_spec_by_type(self, argument):
|
||||||
sfv = solidfire.SolidFireDriver(configuration=self.configuration)
|
sfv = solidfire.SolidFireDriver(configuration=self.configuration)
|
||||||
size = argument[0].pop('size')
|
size = argument[0].pop('size')
|
||||||
@ -1246,8 +1249,8 @@ class SolidFireVolumeTestCase(test.TestCase):
|
|||||||
qos = sfv._set_qos_by_volume_type(self.ctxt, type_ref['id'], size)
|
qos = sfv._set_qos_by_volume_type(self.ctxt, type_ref['id'], size)
|
||||||
self.assertEqual(argument[1], qos)
|
self.assertEqual(argument[1], qos)
|
||||||
|
|
||||||
@ddt.file_data("scaled_iops_invalid_data.json")
|
@file_data("scaled_iops_invalid_data.json")
|
||||||
@ddt.unpack
|
@unpack
|
||||||
def test_set_scaled_qos_by_type_invalid(self, inputs):
|
def test_set_scaled_qos_by_type_invalid(self, inputs):
|
||||||
sfv = solidfire.SolidFireDriver(configuration=self.configuration)
|
sfv = solidfire.SolidFireDriver(configuration=self.configuration)
|
||||||
size = inputs[0].pop('size')
|
size = inputs[0].pop('size')
|
||||||
@ -2684,22 +2687,31 @@ class SolidFireVolumeTestCase(test.TestCase):
|
|||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test_set_rep_by_volume_type(self):
|
@data('Async', 'Sync', 'SnapshotsOnly')
|
||||||
|
@mock.patch.object(volume_types, 'get_volume_type')
|
||||||
|
def test_set_rep_by_volume_type(self, mode, mock_get_volume_type):
|
||||||
|
mock_get_volume_type.return_value = {
|
||||||
|
'name': 'sf-1', 'deleted': False,
|
||||||
|
'created_at': '2014-02-06 04:58:11',
|
||||||
|
'updated_at': None, 'extra_specs':
|
||||||
|
{'replication_enabled': '<is> True',
|
||||||
|
'solidfire:replication_mode': mode},
|
||||||
|
'deleted_at': None,
|
||||||
|
'id': '290edb2a-f5ea-11e5-9ce9-5e5517507c66'}
|
||||||
|
rep_opts = {}
|
||||||
sfv = solidfire.SolidFireDriver(configuration=self.configuration)
|
sfv = solidfire.SolidFireDriver(configuration=self.configuration)
|
||||||
sfv.cluster_pairs = self.cluster_pairs
|
sfv.cluster_pairs = self.cluster_pairs
|
||||||
ctxt = None
|
ctxt = None
|
||||||
type_id = '290edb2a-f5ea-11e5-9ce9-5e5517507c66'
|
type_id = '290edb2a-f5ea-11e5-9ce9-5e5517507c66'
|
||||||
fake_type = {'extra_specs': {'replication_enabled': '<is> True'}}
|
rep_opts['rep_type'] = mode
|
||||||
with mock.patch.object(volume_types,
|
self.assertEqual(rep_opts, sfv._set_rep_by_volume_type(ctxt, type_id))
|
||||||
'get_volume_type',
|
mock_get_volume_type.assert_called()
|
||||||
return_value=fake_type):
|
|
||||||
self.assertEqual('Async', sfv._set_rep_by_volume_type(
|
|
||||||
ctxt, type_id))
|
|
||||||
|
|
||||||
def test_replicate_volume(self):
|
def test_replicate_volume(self):
|
||||||
replication_status = fields.ReplicationStatus.ENABLED
|
replication_status = fields.ReplicationStatus.ENABLED
|
||||||
fake_vol = {'project_id': 1, 'volumeID': 1, 'size': 1}
|
fake_vol = {'project_id': 1, 'volumeID': 1, 'size': 1}
|
||||||
params = {'attributes': {}}
|
params = {'attributes': {}}
|
||||||
|
rep_info = {'rep_type': 'Async'}
|
||||||
sf_account = {'initiatorSecret': 'shhh', 'targetSecret': 'dont-tell'}
|
sf_account = {'initiatorSecret': 'shhh', 'targetSecret': 'dont-tell'}
|
||||||
model_update = {'provider_id': '1 2 xxxx'}
|
model_update = {'provider_id': '1 2 xxxx'}
|
||||||
sfv = solidfire.SolidFireDriver(configuration=self.configuration)
|
sfv = solidfire.SolidFireDriver(configuration=self.configuration)
|
||||||
@ -2716,7 +2728,7 @@ class SolidFireVolumeTestCase(test.TestCase):
|
|||||||
return_value=model_update):
|
return_value=model_update):
|
||||||
self.assertEqual({'replication_status': replication_status},
|
self.assertEqual({'replication_status': replication_status},
|
||||||
sfv._replicate_volume(fake_vol, params,
|
sfv._replicate_volume(fake_vol, params,
|
||||||
sf_account, {}))
|
sf_account, rep_info))
|
||||||
|
|
||||||
def test_pythons_try_except(self):
|
def test_pythons_try_except(self):
|
||||||
def _fake_retrieve_rep(vol):
|
def _fake_retrieve_rep(vol):
|
||||||
|
@ -221,9 +221,11 @@ class SolidFireDriver(san.SanISCSIDriver):
|
|||||||
2.0.12 - Fix bug #1744005
|
2.0.12 - Fix bug #1744005
|
||||||
2.0.14 - Fix bug #1782588 qos settings on extend
|
2.0.14 - Fix bug #1782588 qos settings on extend
|
||||||
2.0.15 - Fix bug #1834013 NetApp SolidFire replication errors
|
2.0.15 - Fix bug #1834013 NetApp SolidFire replication errors
|
||||||
|
2.0.16 - Add options for replication mode (Async, Sync and
|
||||||
|
SnapshotsOnly)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
VERSION = '2.0.15'
|
VERSION = '2.0.16'
|
||||||
|
|
||||||
# ThirdPartySystems wiki page
|
# ThirdPartySystems wiki page
|
||||||
CI_WIKI_NAME = "NetApp_SolidFire_CI"
|
CI_WIKI_NAME = "NetApp_SolidFire_CI"
|
||||||
@ -323,6 +325,18 @@ class SolidFireDriver(san.SanISCSIDriver):
|
|||||||
def get_driver_options():
|
def get_driver_options():
|
||||||
return sf_opts
|
return sf_opts
|
||||||
|
|
||||||
|
def _init_vendor_properties(self):
|
||||||
|
properties = {}
|
||||||
|
self._set_property(
|
||||||
|
properties,
|
||||||
|
"solidfire:replication_mode",
|
||||||
|
"Replication mode",
|
||||||
|
_("Specifies replication mode."),
|
||||||
|
"string",
|
||||||
|
enum=["Async", "Sync", "SnapshotsOnly"])
|
||||||
|
|
||||||
|
return properties, 'solidfire'
|
||||||
|
|
||||||
def __getattr__(self, attr):
|
def __getattr__(self, attr):
|
||||||
if hasattr(self.target_driver, attr):
|
if hasattr(self.target_driver, attr):
|
||||||
return getattr(self.target_driver, attr)
|
return getattr(self.target_driver, attr)
|
||||||
@ -1412,15 +1426,17 @@ class SolidFireDriver(san.SanISCSIDriver):
|
|||||||
return rep_data
|
return rep_data
|
||||||
|
|
||||||
def _set_rep_by_volume_type(self, ctxt, type_id):
|
def _set_rep_by_volume_type(self, ctxt, type_id):
|
||||||
rep_type = None
|
rep_modes = ['Async', 'Sync', 'SnapshotsOnly']
|
||||||
|
rep_opts = {}
|
||||||
type_ref = volume_types.get_volume_type(ctxt, type_id)
|
type_ref = volume_types.get_volume_type(ctxt, type_id)
|
||||||
specs = type_ref.get('extra_specs')
|
specs = type_ref.get('extra_specs')
|
||||||
|
|
||||||
# TODO(erlon): Add support for sync/snapshot replication
|
|
||||||
if specs.get('replication_enabled', "") == "<is> True":
|
if specs.get('replication_enabled', "") == "<is> True":
|
||||||
rep_type = 'Async'
|
if specs.get('solidfire:replication_mode') in rep_modes:
|
||||||
|
rep_opts['rep_type'] = specs.get('solidfire:replication_mode')
|
||||||
|
else:
|
||||||
|
rep_opts['rep_type'] = 'Async'
|
||||||
|
|
||||||
return rep_type
|
return rep_opts
|
||||||
|
|
||||||
def _replicate_volume(self, volume, params,
|
def _replicate_volume(self, volume, params,
|
||||||
parent_sfaccount, rep_info):
|
parent_sfaccount, rep_info):
|
||||||
@ -1476,7 +1492,8 @@ class SolidFireDriver(san.SanISCSIDriver):
|
|||||||
volume['volumeID'])
|
volume['volumeID'])
|
||||||
|
|
||||||
# Make sure we split any pair the volume have
|
# Make sure we split any pair the volume have
|
||||||
params = {'volumeID': volume['volumeID'], 'mode': rep_info}
|
params = {'volumeID': volume['volumeID'],
|
||||||
|
'mode': rep_info['rep_type']}
|
||||||
self._issue_api_request('RemoveVolumePair', params, '8.0')
|
self._issue_api_request('RemoveVolumePair', params, '8.0')
|
||||||
|
|
||||||
rep_key = self._issue_api_request(
|
rep_key = self._issue_api_request(
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
upgrade:
|
||||||
|
- |
|
||||||
|
SolidFire supports Synchronous, Asynchronous and SnapshotsOnly replication
|
||||||
|
modes. This adds the config option `solidfire:replication_mode` to specify
|
||||||
|
the mode to be used by Cinder. Its value can be `Sync`, `Async` or
|
||||||
|
`SnapshotsOnly`.
|
Loading…
x
Reference in New Issue
Block a user