self.assert_error_propagates(
[self.array.destroy_pgroup],
self.driver.delete_cgsnapshot, mock_context, mock_cgsnap)
+
+ def test_manage_existing(self):
+ ref_name = 'vol1'
+ volume_ref = {'name': ref_name}
+ self.array.list_volume_private_connections.return_value = []
+ vol_name = VOLUME['name'] + '-cinder'
+ self.driver.manage_existing(VOLUME, volume_ref)
+ self.array.list_volume_private_connections.assert_called_with(ref_name)
+ self.array.rename_volume.assert_called_with(ref_name, vol_name)
+
+ def test_manage_existing_error_propagates(self):
+ self.array.list_volume_private_connections.return_value = []
+ self.assert_error_propagates(
+ [self.array.list_volume_private_connections,
+ self.array.rename_volume],
+ self.driver.manage_existing,
+ VOLUME, {'name': 'vol1'}
+ )
+
+ def test_manage_existing_bad_ref(self):
+ self.assertRaises(exception.ManageExistingInvalidReference,
+ self.driver.manage_existing,
+ VOLUME, {'bad_key': 'bad_value'})
+
+ self.assertRaises(exception.ManageExistingInvalidReference,
+ self.driver.manage_existing,
+ VOLUME, {'name': ''})
+
+ self.assertRaises(exception.ManageExistingInvalidReference,
+ self.driver.manage_existing,
+ VOLUME, {'name': None})
+
+ self.array.get_volume.side_effect = \
+ self.purestorage_module.PureHTTPError(
+ text="Volume does not exist.",
+ code=400
+ )
+ self.assertRaises(exception.ManageExistingInvalidReference,
+ self.driver.manage_existing,
+ VOLUME, {'name': 'non-existing-volume'})
+
+ def test_manage_existing_with_connected_hosts(self):
+ ref_name = 'vol1'
+ self.array.list_volume_private_connections.return_value = \
+ ["host1", "host2"]
+
+ self.assertRaises(exception.ManageExistingInvalidReference,
+ self.driver.manage_existing,
+ VOLUME, {'name': ref_name})
+
+ self.array.list_volume_private_connections.assert_called_with(ref_name)
+ self.assertFalse(self.array.rename_volume.called)
+
+ def test_manage_existing_get_size(self):
+ ref_name = 'vol1'
+ volume_ref = {'name': ref_name}
+ expected_size = 5
+ self.array.get_volume.return_value = {"size": 5368709120}
+
+ size = self.driver.manage_existing_get_size(VOLUME, volume_ref)
+
+ self.assertEqual(expected_size, size)
+ self.array.get_volume.assert_called_with(ref_name)
+
+ def test_manage_existing_get_size_error_propagates(self):
+ self.array.get_volume.return_value = mock.MagicMock()
+ self.assert_error_propagates([self.array.get_volume],
+ self.driver.manage_existing_get_size,
+ VOLUME, {'name': 'vol1'})
+
+ def test_manage_existing_get_size_bad_ref(self):
+ self.assertRaises(exception.ManageExistingInvalidReference,
+ self.driver.manage_existing_get_size,
+ VOLUME, {'bad_key': 'bad_value'})
+
+ self.assertRaises(exception.ManageExistingInvalidReference,
+ self.driver.manage_existing_get_size,
+ VOLUME, {'name': ''})
+
+ self.assertRaises(exception.ManageExistingInvalidReference,
+ self.driver.manage_existing_get_size,
+ VOLUME, {'name': None})
+
+ def test_unmanage(self):
+ vol_name = VOLUME['name'] + "-cinder"
+ unmanaged_vol_name = vol_name + "-unmanaged"
+
+ self.driver.unmanage(VOLUME)
+
+ self.array.rename_volume.assert_called_with(vol_name,
+ unmanaged_vol_name)
+
+ def test_unmanage_error_propagates(self):
+ self.assert_error_propagates([self.array.rename_volume],
+ self.driver.unmanage,
+ VOLUME)
+
+ def test_unmanage_with_deleted_volume(self):
+ vol_name = VOLUME['name'] + "-cinder"
+ unmanaged_vol_name = vol_name + "-unmanaged"
+ self.array.rename_volume.side_effect = \
+ self.purestorage_module.PureHTTPError(
+ text="Volume does not exist.",
+ code=400
+ )
+
+ self.driver.unmanage(VOLUME)
+
+ self.array.rename_volume.assert_called_with(vol_name,
+ unmanaged_vol_name)
This driver requires Purity version 3.4.0 or later.
"""
+import math
import re
import uuid
LOG.debug("Leave PureISCSIDriver.delete_cgsnapshot")
return model_update, snapshots
+
+ def _validate_manage_existing_ref(self, existing_ref):
+ """Ensure that an existing_ref is valid and return volume info
+
+ If the ref is not valid throw a ManageExistingInvalidReference
+ exception with an appropriate error.
+ """
+ if "name" not in existing_ref or not existing_ref["name"]:
+ raise exception.ManageExistingInvalidReference(
+ existing_ref=existing_ref,
+ reason=_("PureISCSIDriver manage_existing requires a 'name'"
+ " key to identify an existing volume."))
+
+ ref_vol_name = existing_ref['name']
+
+ try:
+ volume_info = self._array.get_volume(ref_vol_name)
+ if volume_info:
+ return volume_info
+ except purestorage.PureHTTPError as err:
+ with excutils.save_and_reraise_exception() as ctxt:
+ if (err.code == 400 and
+ ERR_MSG_NOT_EXIST in err.text):
+ ctxt.reraise = False
+
+ # If volume information was unable to be retrieved we need
+ # to throw a Invalid Reference exception
+ raise exception.ManageExistingInvalidReference(
+ existing_ref=existing_ref,
+ reason=_("Unable to find volume with name=%s") % ref_vol_name)
+
+ def manage_existing(self, volume, existing_ref):
+ """Brings an existing backend storage object under Cinder management.
+
+ We expect a volume name in the existing_ref that matches one in Purity.
+ """
+ LOG.debug("Enter PureISCSIDriver.manage_existing.")
+
+ self._validate_manage_existing_ref(existing_ref)
+
+ ref_vol_name = existing_ref['name']
+
+ connected_hosts = \
+ self._array.list_volume_private_connections(ref_vol_name)
+ if len(connected_hosts) > 0:
+ raise exception.ManageExistingInvalidReference(
+ existing_ref=existing_ref,
+ reason=_("PureISCSIDriver manage_existing cannot manage a "
+ "volume connected to hosts. Please disconnect the "
+ "volume from existing hosts before importing."))
+
+ new_vol_name = _get_vol_name(volume)
+ LOG.info(_LI("Renaming existing volume %(ref_name)s to %(new_name)s"),
+ {"ref_name": ref_vol_name, "new_name": new_vol_name})
+ self._array.rename_volume(ref_vol_name, new_vol_name)
+ LOG.debug("Leave PureISCSIDriver.manage_existing.")
+ return None
+
+ def manage_existing_get_size(self, volume, existing_ref):
+ """Return size of volume to be managed by manage_existing.
+
+ We expect a volume name in the existing_ref that matches one in Purity.
+ """
+ LOG.debug("Enter PureISCSIDriver.manage_existing_get_size.")
+
+ volume_info = self._validate_manage_existing_ref(existing_ref)
+ size = math.ceil(float(volume_info["size"]) / units.Gi)
+
+ LOG.debug("Leave PureISCSIDriver.manage_existing_get_size.")
+ return size
+
+ def unmanage(self, volume):
+ """Removes the specified volume from Cinder management.
+
+ Does not delete the underlying backend storage object.
+
+ The volume will be renamed with "-unmanaged" as a suffix
+ """
+ vol_name = _get_vol_name(volume)
+ unmanaged_vol_name = vol_name + "-unmanaged"
+ LOG.info(_LI("Renaming existing volume %(ref_name)s to %(new_name)s"),
+ {"ref_name": vol_name, "new_name": unmanaged_vol_name})
+ try:
+ self._array.rename_volume(vol_name, unmanaged_vol_name)
+ except purestorage.PureHTTPError as err:
+ with excutils.save_and_reraise_exception() as ctxt:
+ if (err.code == 400 and
+ ERR_MSG_NOT_EXIST in err.text):
+ ctxt.reraise = False
+ LOG.warn(_LW("Volume unmanage was unable to rename "
+ "the volume, error message: %s"), err.text)