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"]
)
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
)
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"
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"))
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"
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"))
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"
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,
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 = \
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 = \
[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 = [{
)
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(
)
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(
[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}
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
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
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 (
"""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
# 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