diff --git a/doc/source/devref/share_back_ends_feature_support_mapping.rst b/doc/source/devref/share_back_ends_feature_support_mapping.rst index 3110fcdb94..ae944961b4 100644 --- a/doc/source/devref/share_back_ends_feature_support_mapping.rst +++ b/doc/source/devref/share_back_ends_feature_support_mapping.rst @@ -47,7 +47,7 @@ Mapping of share drivers and share features support +----------------------------------------+-----------------------------+-----------------------+--------------+--------------+------------------------+----------------------------+ | HDFS | DHSS = False (K) | \- | M | \- | K | K | +----------------------------------------+-----------------------------+-----------------------+--------------+--------------+------------------------+----------------------------+ -| Hitachi HNAS | DHSS = False (L) | L | L | \- | L | L | +| Hitachi HNAS | DHSS = False (L) | L | L | M | L | L | +----------------------------------------+-----------------------------+-----------------------+--------------+--------------+------------------------+----------------------------+ | HPE 3PAR | DHSS = True (L) & False (K) | \- | \- | \- | K | K | +----------------------------------------+-----------------------------+-----------------------+--------------+--------------+------------------------+----------------------------+ diff --git a/manila/share/drivers/hitachi/hds_hnas.py b/manila/share/drivers/hitachi/hds_hnas.py index 1da62c40dd..06194bf247 100644 --- a/manila/share/drivers/hitachi/hds_hnas.py +++ b/manila/share/drivers/hitachi/hds_hnas.py @@ -424,6 +424,25 @@ class HDSHNASDriver(driver.ShareDriver): {'shr_path': share['export_locations'][0]['path'], 'shr_id': share['id']}) + def shrink_share(self, share, new_size, share_server=None): + """Shrinks a share to new size. + + :param share: Share that will be shrunk. + :param new_size: New size of share. + :param share_server: Data structure with share server information. + Not used by this driver. + """ + share_id = self._get_hnas_share_id(share['id']) + + LOG.debug("Shrinking share in HNAS: %(shr_id)s.", + {'shr_id': share['id']}) + + self._shrink_share(share_id, share['size'], new_size) + LOG.info(_LI("Share %(shr_id)s successfully shrunk to " + "%(shr_size)sG."), + {'shr_id': share['id'], + 'shr_size': six.text_type(new_size)}) + def _get_hnas_share_id(self, share_id): hnas_id = self.private_storage.get(share_id, 'hnas_id') @@ -549,6 +568,25 @@ class HDSHNASDriver(driver.ShareDriver): self.hnas.check_export(share_id) return path + def _shrink_share(self, share_id, old_size, new_size): + """Shrinks a share to new size. + + :param share_id: ID of share that will be shrunk. + :param old_size: Current size of share that will be shrunk. + :param new_size: New size of share after shrink operation. + """ + self._ensure_share(share_id) + + usage = self.hnas.get_share_usage(share_id) + + LOG.debug("Usage space in share %(share)s: %(usage)sG", + {'share': share_id, 'usage': usage}) + + if new_size > usage: + self.hnas.modify_quota(share_id, new_size) + else: + raise exception.ShareShrinkingPossibleDataLoss(share_id=share_id) + def _extend_share(self, share_id, old_size, new_size): """Extends a share to new size. diff --git a/manila/share/drivers/hitachi/ssh.py b/manila/share/drivers/hitachi/ssh.py index b810680ff1..4e290d9352 100644 --- a/manila/share/drivers/hitachi/ssh.py +++ b/manila/share/drivers/hitachi/ssh.py @@ -15,6 +15,7 @@ from oslo_concurrency import processutils from oslo_log import log +from oslo_utils import strutils from oslo_utils import units import paramiko import six @@ -297,6 +298,20 @@ class HNASSSHBackend(object): "below 1G.") % share_id) raise exception.HNASBackendException(msg=msg) + def get_share_usage(self, share_id): + command = ['quota', 'list', self.fs_name, share_id] + output, err = self._execute(command) + + quota = Quota(output) + + if quota.usage is None: + msg = (_("Virtual volume %s does not have any quota.") % share_id) + raise exception.HNASItemNotFoundException(msg=msg) + else: + bytes_usage = strutils.string_to_bytes(six.text_type(quota.usage) + + quota.usage_unit) + return bytes_usage / units.Gi + def _get_share_export(self, share_id): share_id = '/shares/' + share_id command = ['nfs-export', 'list ', share_id] diff --git a/manila/tests/share/drivers/hitachi/test_hds_hnas.py b/manila/tests/share/drivers/hitachi/test_hds_hnas.py index 3fa980ff24..88b6c1ee82 100644 --- a/manila/tests/share/drivers/hitachi/test_hds_hnas.py +++ b/manila/tests/share/drivers/hitachi/test_hds_hnas.py @@ -379,6 +379,31 @@ class HDSHNASTestCase(test.TestCase): ssh.HNASSSHBackend.check_quota.assert_called_once_with(share['id']) ssh.HNASSSHBackend.check_export.assert_called_once_with(share['id']) + def test_shrink_share(self): + self.mock_object(hds_hnas.HDSHNASDriver, "_get_hnas_share_id", + mock.Mock(return_value=share['id'])) + self.mock_object(hds_hnas.HDSHNASDriver, "_ensure_share", mock.Mock()) + self.mock_object(ssh.HNASSSHBackend, "get_share_usage", mock.Mock( + return_value=10)) + self.mock_object(ssh.HNASSSHBackend, "modify_quota", mock.Mock()) + + self._driver.shrink_share(share, 11) + + ssh.HNASSSHBackend.get_share_usage.assert_called_once_with(share['id']) + ssh.HNASSSHBackend.modify_quota.assert_called_once_with(share['id'], + 11) + + def test_shrink_share_new_size_lower_than_usage(self): + self.mock_object(hds_hnas.HDSHNASDriver, "_get_hnas_share_id", + mock.Mock(return_value=share['id'])) + self.mock_object(hds_hnas.HDSHNASDriver, "_ensure_share", mock.Mock()) + self.mock_object(ssh.HNASSSHBackend, "get_share_usage", mock.Mock( + return_value=10)) + + self.assertRaises(exception.ShareShrinkingPossibleDataLoss, + self._driver.shrink_share, share, 9) + ssh.HNASSSHBackend.get_share_usage.assert_called_once_with(share['id']) + def test_extend_share(self): self.mock_object(hds_hnas.HDSHNASDriver, "_get_hnas_share_id", mock.Mock(return_value=share['id'])) diff --git a/manila/tests/share/drivers/hitachi/test_ssh.py b/manila/tests/share/drivers/hitachi/test_ssh.py index 3a9c04166b..1f616830bd 100644 --- a/manila/tests/share/drivers/hitachi/test_ssh.py +++ b/manila/tests/share/drivers/hitachi/test_ssh.py @@ -96,7 +96,7 @@ File system fake_fs successfully mounted.""" HNAS_RESULT_quota = """Type : Explicit Target : ViVol: vvol_test -Usage : 0 B +Usage : 1 GB Limit : 5 GB (Hard) Warning : Unset Critical : Unset @@ -112,7 +112,7 @@ Last modified : 2015-06-23 22:37:17.363660800+00:00 """ HNAS_RESULT_quota_tb = """Type : Explicit Target : ViVol: vvol_test -Usage : 0 B +Usage : 1 TB Limit : 1 TB (Hard) Warning : Unset Critical : Unset @@ -128,7 +128,7 @@ Last modified : 2015-06-23 22:37:17.363660800+00:00 """ HNAS_RESULT_quota_mb = """Type : Explicit Target : ViVol: vvol_test -Usage : 0 B +Usage : 20 MB Limit : 500 MB (Hard) Warning : Unset Critical : Unset @@ -797,6 +797,32 @@ class HNASSSHTestCase(test.TestCase): self.assertRaises(exception.HNASBackendException, self._driver_ssh.get_share_quota, "vvol_test") + def test_get_share_usage(self): + self.mock_object(ssh.HNASSSHBackend, "_execute", mock.Mock( + return_value=(HNAS_RESULT_quota, ''))) + + self.assertEqual(1, self._driver_ssh.get_share_usage("vvol_test")) + + def test_get_share_usage_error(self): + self.mock_object(ssh.HNASSSHBackend, "_execute", mock.Mock( + return_value=(HNAS_RESULT_quota_err, ''))) + + self.assertRaises(exception.HNASItemNotFoundException, + self._driver_ssh.get_share_usage, "vvol_test") + + def test_get_share_usage_mb(self): + self.mock_object(ssh.HNASSSHBackend, "_execute", mock.Mock( + return_value=(HNAS_RESULT_quota_mb, ''))) + + self.assertEqual(0.01953125, self._driver_ssh.get_share_usage( + "vvol_test")) + + def test_get_share_usage_tb(self): + self.mock_object(ssh.HNASSSHBackend, "_execute", mock.Mock( + return_value=(HNAS_RESULT_quota_tb, ''))) + + self.assertEqual(1024, self._driver_ssh.get_share_usage("vvol_test")) + def test__get_share_export(self): self.mock_object(ssh.HNASSSHBackend, '_execute', mock.Mock(return_value=[HNAS_RESULT_export_ip, '']))