diff --git a/cinder/tests/unit/volume/drivers/test_pure.py b/cinder/tests/unit/volume/drivers/test_pure.py index 40fbc79f3c0..2ea70267862 100644 --- a/cinder/tests/unit/volume/drivers/test_pure.py +++ b/cinder/tests/unit/volume/drivers/test_pure.py @@ -4152,12 +4152,61 @@ class PureVolumeUpdateStatsTestCase(PureBaseSharedDriverTestCase): actual_ratio = self.driver._get_thin_provisioning(provisioned, used) self.assertEqual(expected_ratio, actual_ratio) + @ddt.data( + dict( + connections=[ + {'status': 'connected', 'type': 'sync-replication'}, + ], + expected='sync'), + dict( + connections=[ + {'status': 'connected', 'type': 'async-replication'} + ], + expected='async'), + dict( + connections=[ + {'status': 'connected', 'type': 'async-replication'}, + {'status': 'connected', 'type': 'sync-replication'}, + {'status': 'connected', 'type': 'async-replication'} + ], + expected='trisync'), + dict( + connections=[ + {'status': 'connected', 'type': 'async-replication'}, + {'status': 'connected', 'type': 'async-replication'} + ], + expected='async'), + dict( + connections=[ + {'status': 'connected', 'type': 'sync-replication'}, + {'status': 'connected', 'type': 'sync-replication'} + ], + expected='sync'), + dict( + connections=[ + {'status': 'connected', 'type': 'sync-replication'}, + {'status': 'connected', 'type': 'async-replication'} + ], + expected='trisync'), + dict( + connections=[ + {'status': 'connecting', 'type': 'sync-replication'} + ], + expected=None)) + @ddt.unpack + def test_get_replication_capability(self, connections, expected): + self.array.list_array_connections.return_value = connections + connection_status = self.driver._get_replication_capability() + self.assertEqual(expected, connection_status) + + @mock.patch(BASE_DRIVER_OBJ + '._get_replication_capability') @mock.patch(BASE_DRIVER_OBJ + '.get_goodness_function') @mock.patch(BASE_DRIVER_OBJ + '.get_filter_function') @mock.patch(BASE_DRIVER_OBJ + '._get_provisioned_space') @mock.patch(BASE_DRIVER_OBJ + '._get_thin_provisioning') def test_get_volume_stats(self, mock_get_thin_provisioning, mock_get_space, - mock_get_filter, mock_get_goodness): + mock_get_filter, mock_get_goodness, + mock_get_replication_capability): filter_function = 'capabilities.total_volumes < 10' goodness_function = '90' num_hosts = 20 @@ -4172,6 +4221,7 @@ class PureVolumeUpdateStatsTestCase(PureBaseSharedDriverTestCase): mock_get_space.return_value = (PROVISIONED_CAPACITY * units.Gi, 100) mock_get_filter.return_value = filter_function mock_get_goodness.return_value = goodness_function + mock_get_replication_capability.return_value = 'sync' mock_get_thin_provisioning.return_value = (PROVISIONED_CAPACITY / USED_SPACE) @@ -4203,6 +4253,7 @@ class PureVolumeUpdateStatsTestCase(PureBaseSharedDriverTestCase): 'usec_per_read_op': PERF_INFO['usec_per_read_op'], 'usec_per_write_op': PERF_INFO['usec_per_write_op'], 'queue_depth': PERF_INFO['queue_depth'], + 'replication_capability': 'sync', 'replication_enabled': False, 'replication_type': [], 'replication_count': 0, diff --git a/cinder/volume/drivers/pure.py b/cinder/volume/drivers/pure.py index fce1fdeae10..0002efeabf6 100644 --- a/cinder/volume/drivers/pure.py +++ b/cinder/volume/drivers/pure.py @@ -918,6 +918,7 @@ class PureBaseVolumeDriver(san.SanDriver): data['queue_depth'] = perf_info['queue_depth'] # Replication + data["replication_capability"] = self._get_replication_capability() data["replication_enabled"] = self._is_replication_enabled repl_types = [] if self._is_replication_enabled: @@ -930,6 +931,39 @@ class PureBaseVolumeDriver(san.SanDriver): in self._replication_target_arrays] self._stats = data + def _get_replication_capability(self): + """Discovered connected arrays status for replication""" + connections = self._get_current_array().list_array_connections() + is_sync, is_async, is_trisync = False, False, False + for conn in connections: + # If connection status is connected, we can have + # either sync or async replication + if conn["status"] == "connected": + # check for async replication + if conn["type"] == "async-replication": + is_async = True + # check for sync replication + elif conn["type"] == "sync-replication": + is_sync = True + # If we've connections for both sync and async + # replication, we can set trisync replication + # and exit the loop + if is_sync and is_async: + is_trisync = True + break + # Check if it is a trisync replication + if is_trisync: + replication_type = "trisync" + # If replication is not trisync, it will be either + # sync or async + elif is_sync: + replication_type = "sync" + elif is_async: + replication_type = "async" + else: + replication_type = None + return replication_type + def _get_provisioned_space(self): """Sum up provisioned size of all volumes on array""" volumes = self._get_current_array().list_volumes(pending=True) diff --git a/releasenotes/notes/pure_replication_capability-f9fa78aa96501a69.yaml b/releasenotes/notes/pure_replication_capability-f9fa78aa96501a69.yaml new file mode 100644 index 00000000000..67f674272be --- /dev/null +++ b/releasenotes/notes/pure_replication_capability-f9fa78aa96501a69.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + Pure Storage driver: Added replication capability to backend pool information. + Response will be ```async```, ```sync``` or```trisync```. ```sync``` implies + support for ```async``` and ```trisync``` implies support for ```sync``` and ```async```.