Merge "Allow for eradicating Pure volumes on Cinder delete"
This commit is contained in:
commit
f2f241a440
|
@ -338,8 +338,8 @@ class PureDriverTestCase(test.TestCase):
|
|||
self.mock_config.pure_api_token = API_TOKEN
|
||||
self.mock_config.volume_backend_name = VOLUME_BACKEND_NAME
|
||||
self.mock_config.safe_get.return_value = None
|
||||
self.mock_config.pure_eradicate_on_delete = False
|
||||
self.array = mock.Mock()
|
||||
self.array
|
||||
self.array.get.return_value = GET_ARRAY_PRIMARY
|
||||
self.array.array_name = GET_ARRAY_PRIMARY["array_name"]
|
||||
self.array.array_id = GET_ARRAY_PRIMARY["id"]
|
||||
|
@ -650,6 +650,7 @@ class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase):
|
|||
)
|
||||
self.driver.delete_volume(VOLUME)
|
||||
self.assertFalse(self.array.destroy_volume.called)
|
||||
self.assertFalse(self.array.eradicate_volume.called)
|
||||
|
||||
# Testing case where array.destroy_volume returns an exception
|
||||
# because volume has already been deleted
|
||||
|
@ -662,6 +663,7 @@ class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase):
|
|||
)
|
||||
self.driver.delete_volume(VOLUME)
|
||||
self.assertTrue(self.array.destroy_volume.called)
|
||||
self.assertFalse(self.array.eradicate_volume.called)
|
||||
|
||||
def test_delete_volume(self):
|
||||
vol_name = VOLUME["name"] + "-cinder"
|
||||
|
@ -669,6 +671,7 @@ class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase):
|
|||
self.driver.delete_volume(VOLUME)
|
||||
expected = [mock.call.destroy_volume(vol_name)]
|
||||
self.array.assert_has_calls(expected)
|
||||
self.assertFalse(self.array.eradicate_volume.called)
|
||||
self.array.destroy_volume.side_effect = (
|
||||
self.purestorage_module.PureHTTPError(code=400, text="does not "
|
||||
"exist"))
|
||||
|
@ -677,6 +680,15 @@ class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase):
|
|||
self.assert_error_propagates([self.array.destroy_volume],
|
||||
self.driver.delete_volume, VOLUME)
|
||||
|
||||
def test_delete_volume_eradicate_now(self):
|
||||
vol_name = VOLUME["name"] + "-cinder"
|
||||
self.array.list_volume_private_connections.return_value = {}
|
||||
self.mock_config.pure_eradicate_on_delete = True
|
||||
self.driver.delete_volume(VOLUME)
|
||||
expected = [mock.call.destroy_volume(vol_name),
|
||||
mock.call.eradicate_volume(vol_name)]
|
||||
self.array.assert_has_calls(expected)
|
||||
|
||||
def test_delete_connected_volume(self):
|
||||
vol_name = VOLUME["name"] + "-cinder"
|
||||
host_name_a = "ha"
|
||||
|
@ -715,6 +727,7 @@ class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase):
|
|||
self.driver.delete_snapshot(SNAPSHOT)
|
||||
expected = [mock.call.destroy_volume(snap_name)]
|
||||
self.array.assert_has_calls(expected)
|
||||
self.assertFalse(self.array.eradicate_volume.called)
|
||||
self.array.destroy_volume.side_effect = (
|
||||
self.purestorage_module.PureHTTPError(code=400, text="does not "
|
||||
"exist"))
|
||||
|
@ -723,6 +736,14 @@ class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase):
|
|||
self.assert_error_propagates([self.array.destroy_volume],
|
||||
self.driver.delete_snapshot, SNAPSHOT)
|
||||
|
||||
def test_delete_snapshot_eradicate_now(self):
|
||||
snap_name = SNAPSHOT["volume_name"] + "-cinder." + SNAPSHOT["name"]
|
||||
self.mock_config.pure_eradicate_on_delete = True
|
||||
self.driver.delete_snapshot(SNAPSHOT)
|
||||
expected = [mock.call.destroy_volume(snap_name),
|
||||
mock.call.eradicate_volume(snap_name)]
|
||||
self.array.assert_has_calls(expected)
|
||||
|
||||
@mock.patch(BASE_DRIVER_OBJ + "._get_host", autospec=True)
|
||||
def test_terminate_connection(self, mock_host):
|
||||
vol_name = VOLUME["name"] + "-cinder"
|
||||
|
@ -967,6 +988,7 @@ class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase):
|
|||
|
||||
expected_name = self.driver._get_pgroup_name_from_id(mock_cgroup.id)
|
||||
self.array.destroy_pgroup.assert_called_with(expected_name)
|
||||
self.assertFalse(self.array.eradicate_pgroup.called)
|
||||
|
||||
expected_volume_updates = [{
|
||||
'id': mock_volume.id,
|
||||
|
@ -985,6 +1007,7 @@ class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase):
|
|||
mock_cgroup,
|
||||
[mock_volume])
|
||||
self.array.destroy_pgroup.assert_called_with(expected_name)
|
||||
self.assertFalse(self.array.eradicate_pgroup.called)
|
||||
mock_delete_volume.assert_called_with(self.driver, mock_volume)
|
||||
|
||||
self.array.destroy_pgroup.side_effect = \
|
||||
|
@ -996,6 +1019,7 @@ class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase):
|
|||
mock_cgroup,
|
||||
[mock_volume])
|
||||
self.array.destroy_pgroup.assert_called_with(expected_name)
|
||||
self.assertFalse(self.array.eradicate_pgroup.called)
|
||||
mock_delete_volume.assert_called_with(self.driver, mock_volume)
|
||||
|
||||
self.array.destroy_pgroup.side_effect = \
|
||||
|
@ -1146,6 +1170,7 @@ class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase):
|
|||
[mock_snap])
|
||||
|
||||
self.array.destroy_pgroup.assert_called_with(snap_name)
|
||||
self.assertFalse(self.array.eradicate_pgroup.called)
|
||||
self.assertEqual({'status': mock_cgsnap.status}, model_update)
|
||||
|
||||
expected_snapshot_update = [{
|
||||
|
@ -1161,6 +1186,7 @@ class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase):
|
|||
)
|
||||
self.driver.delete_cgsnapshot(mock_context, mock_cgsnap, [mock_snap])
|
||||
self.array.destroy_pgroup.assert_called_with(snap_name)
|
||||
self.assertFalse(self.array.eradicate_pgroup.called)
|
||||
|
||||
self.array.destroy_pgroup.side_effect = \
|
||||
self.purestorage_module.PureHTTPError(
|
||||
|
@ -1169,6 +1195,7 @@ class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase):
|
|||
)
|
||||
self.driver.delete_cgsnapshot(mock_context, mock_cgsnap, [mock_snap])
|
||||
self.array.destroy_pgroup.assert_called_with(snap_name)
|
||||
self.assertFalse(self.array.eradicate_pgroup.called)
|
||||
|
||||
self.array.destroy_pgroup.side_effect = \
|
||||
self.purestorage_module.PureHTTPError(
|
||||
|
@ -1202,6 +1229,20 @@ class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase):
|
|||
[mock_snap]
|
||||
)
|
||||
|
||||
@mock.patch(BASE_DRIVER_OBJ + "._get_pgroup_snap_name",
|
||||
spec=pure.PureBaseVolumeDriver._get_pgroup_snap_name)
|
||||
def test_delete_cgsnapshot_eradicate_now(self, mock_get_snap_name):
|
||||
snap_name = "consisgroup-4a2f7e3a-312a-40c5-96a8-536b8a0f" \
|
||||
"e074-cinder.4a2f7e3a-312a-40c5-96a8-536b8a0fe075"
|
||||
mock_get_snap_name.return_value = snap_name
|
||||
self.mock_config.pure_eradicate_on_delete = True
|
||||
model_update, snapshots = self.driver.delete_cgsnapshot(mock.Mock(),
|
||||
mock.Mock(),
|
||||
[mock.Mock()])
|
||||
|
||||
self.array.destroy_pgroup.assert_called_once_with(snap_name)
|
||||
self.array.eradicate_pgroup.assert_called_once_with(snap_name)
|
||||
|
||||
def test_manage_existing(self):
|
||||
ref_name = 'vol1'
|
||||
volume_ref = {'name': ref_name}
|
||||
|
|
|
@ -66,6 +66,15 @@ PURE_OPTS = [
|
|||
cfg.IntOpt("pure_replica_retention_long_term_default", default=7,
|
||||
help="Retain snapshots per day on target for this time "
|
||||
"(in days.)"),
|
||||
cfg.BoolOpt("pure_eradicate_on_delete",
|
||||
default=False,
|
||||
help="When enabled, all Pure volumes, snapshots, and "
|
||||
"protection groups will be eradicated at the time of "
|
||||
"deletion in Cinder. Data will NOT be recoverable after "
|
||||
"a delete with this set to True! When disabled, volumes "
|
||||
"and snapshots will go into pending eradication state "
|
||||
"and can be recovered."
|
||||
)
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
@ -348,6 +357,8 @@ class PureBaseVolumeDriver(san.SanDriver):
|
|||
host_name = host_info["host"]
|
||||
self._disconnect_host(current_array, host_name, vol_name)
|
||||
current_array.destroy_volume(vol_name)
|
||||
if self.configuration.pure_eradicate_on_delete:
|
||||
current_array.eradicate_volume(vol_name)
|
||||
except purestorage.PureHTTPError as err:
|
||||
with excutils.save_and_reraise_exception() as ctxt:
|
||||
if (err.code == 400 and
|
||||
|
@ -377,6 +388,8 @@ class PureBaseVolumeDriver(san.SanDriver):
|
|||
snap_name = self._get_snap_name(snapshot)
|
||||
try:
|
||||
current_array.destroy_volume(snap_name)
|
||||
if self.configuration.pure_eradicate_on_delete:
|
||||
current_array.eradicate_volume(snap_name)
|
||||
except purestorage.PureHTTPError as err:
|
||||
with excutils.save_and_reraise_exception() as ctxt:
|
||||
if err.code == 400 and (
|
||||
|
@ -654,7 +667,10 @@ class PureBaseVolumeDriver(san.SanDriver):
|
|||
"""Deletes a consistency group."""
|
||||
|
||||
try:
|
||||
self._array.destroy_pgroup(self._get_pgroup_name_from_id(group.id))
|
||||
pgroup_name = self._get_pgroup_name_from_id(group.id)
|
||||
self._array.destroy_pgroup(pgroup_name)
|
||||
if self.configuration.pure_eradicate_on_delete:
|
||||
self._array.eradicate_pgroup(pgroup_name)
|
||||
except purestorage.PureHTTPError as err:
|
||||
with excutils.save_and_reraise_exception() as ctxt:
|
||||
if (err.code == 400 and
|
||||
|
@ -724,6 +740,8 @@ class PureBaseVolumeDriver(san.SanDriver):
|
|||
# FlashArray.destroy_pgroup is also used for deleting
|
||||
# pgroup snapshots. The underlying REST API is identical.
|
||||
self._array.destroy_pgroup(pgsnap_name)
|
||||
if self.configuration.pure_eradicate_on_delete:
|
||||
self._array.eradicate_pgroup(pgsnap_name)
|
||||
except purestorage.PureHTTPError as err:
|
||||
with excutils.save_and_reraise_exception() as ctxt:
|
||||
if (err.code == 400 and
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
features:
|
||||
- New config option for Pure Storage volume drivers pure_eradicate_on_delete.
|
||||
When enabled will permanantly eradicate data instead of placing into
|
||||
pending eradication state.
|
||||
fixes:
|
||||
- Allow for eradicating Pure Storage volumes, snapshots, and pgroups when
|
||||
deleting their Cinder counterpart.
|
||||
|
Loading…
Reference in New Issue