]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Configure space reservation on NetApp Data ONTAP
authorGoutham Pacha Ravi <gouthamr@netapp.com>
Thu, 23 Jul 2015 21:37:44 +0000 (17:37 -0400)
committerGoutham Pacha Ravi <gouthamr@netapp.com>
Tue, 18 Aug 2015 16:02:38 +0000 (16:02 +0000)
This patchset allows configuring Cinder volumes on NetApp Data ONTAP
backends to be thick or thin provisioned.

DocImpact
Implements: blueprint netapp-thin-provisioned-luns

Change-Id: I1a2679c72ca0fb56edd0c9e39d361408022380e3

cinder/tests/unit/volume/drivers/netapp/dataontap/fakes.py
cinder/tests/unit/volume/drivers/netapp/dataontap/test_block_7mode.py
cinder/tests/unit/volume/drivers/netapp/dataontap/test_block_base.py
cinder/tests/unit/volume/drivers/netapp/dataontap/test_block_cmode.py
cinder/volume/drivers/netapp/dataontap/block_7mode.py
cinder/volume/drivers/netapp/dataontap/block_base.py
cinder/volume/drivers/netapp/dataontap/block_cmode.py
cinder/volume/drivers/netapp/options.py

index 4f0f710e96ed0c61865da0fae147ac733ce92534..e340f31046f6b7c016ccfd235d3fc8b51762b9d0 100644 (file)
@@ -13,6 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from cinder.volume.drivers.netapp.dataontap.client import api as netapp_api
+
 VOLUME_ID = 'f10d1a84-9b7b-427e-8fec-63c48b509a56'
 LUN_ID = 'ee6b4cc7-477b-4016-aa0c-7127b4e3af86'
 LUN_HANDLE = 'fake_lun_handle'
@@ -209,3 +211,28 @@ SNAPSHOT = {
 VOLUME_REF = {'name': 'fake_vref_name', 'size': 42}
 
 FILE_LIST = ['file1', 'file2', 'file3']
+
+FAKE_LUN = netapp_api.NaElement.create_node_with_children(
+    'lun-info',
+    **{'alignment': 'indeterminate',
+       'block-size': '512',
+       'comment': '',
+       'creation-timestamp': '1354536362',
+       'is-space-alloc-enabled': 'false',
+       'is-space-reservation-enabled': 'true',
+       'mapped': 'false',
+       'multiprotocol-type': 'linux',
+       'online': 'true',
+       'path': '/vol/fakeLUN/fakeLUN',
+       'prefix-size': '0',
+       'qtree': '',
+       'read-only': 'false',
+       'serial-number': '2FfGI$APyN68',
+       'share-state': 'none',
+       'size': '20971520',
+       'size-used': '0',
+       'staging': 'false',
+       'suffix-size': '0',
+       'uuid': 'cec1f3d7-3d41-11e2-9cf4-123478563412',
+       'volume': 'fakeLUN',
+       'vserver': 'fake_vserver'})
index a4f4a612656b4e8d955c20ccc73ab1559b74ee0c..ac7b21b59e628ae716cd93abc23856a5d1156999 100644 (file)
@@ -269,42 +269,32 @@ class NetAppBlockStorage7modeLibraryTestCase(test.TestCase):
 
     def test_clone_lun_zero_block_count(self):
         """Test for when clone lun is not passed a block count."""
+        self.library._get_lun_attr = mock.Mock(return_value={
+            'Volume': 'fakeLUN', 'Path': '/vol/fake/fakeLUN'})
+        self.library.zapi_client = mock.Mock()
+        self.library.zapi_client.get_lun_by_args.return_value = [fake.FAKE_LUN]
+        self.library._add_lun_to_table = mock.Mock()
+
+        self.library._clone_lun('fakeLUN', 'newFakeLUN', 'false')
+
+        self.library.zapi_client.clone_lun.assert_called_once_with(
+            '/vol/fake/fakeLUN', '/vol/fake/newFakeLUN', 'fakeLUN',
+            'newFakeLUN', 'false', block_count=0, dest_block=0, src_block=0)
 
-        lun = netapp_api.NaElement.create_node_with_children(
-            'lun-info',
-            **{'alignment': 'indeterminate',
-               'block-size': '512',
-               'comment': '',
-               'creation-timestamp': '1354536362',
-               'is-space-alloc-enabled': 'false',
-               'is-space-reservation-enabled': 'true',
-               'mapped': 'false',
-               'multiprotocol-type': 'linux',
-               'online': 'true',
-               'path': '/vol/fakeLUN/fakeLUN',
-               'prefix-size': '0',
-               'qtree': '',
-               'read-only': 'false',
-               'serial-number': '2FfGI$APyN68',
-               'share-state': 'none',
-               'size': '20971520',
-               'size-used': '0',
-               'staging': 'false',
-               'suffix-size': '0',
-               'uuid': 'cec1f3d7-3d41-11e2-9cf4-123478563412',
-               'volume': 'fakeLUN',
-               'vserver': 'fake_vserver'})
+    def test_clone_lun_no_space_reservation(self):
+        """Test for when space_reservation is not passed."""
         self.library._get_lun_attr = mock.Mock(return_value={
             'Volume': 'fakeLUN', 'Path': '/vol/fake/fakeLUN'})
+        self.library.lun_space_reservation = 'false'
         self.library.zapi_client = mock.Mock()
-        self.library.zapi_client.get_lun_by_args.return_value = [lun]
+        self.library.zapi_client.get_lun_by_args.return_value = [fake.FAKE_LUN]
         self.library._add_lun_to_table = mock.Mock()
 
         self.library._clone_lun('fakeLUN', 'newFakeLUN')
 
         self.library.zapi_client.clone_lun.assert_called_once_with(
             '/vol/fake/fakeLUN', '/vol/fake/newFakeLUN', 'fakeLUN',
-            'newFakeLUN', 'true', block_count=0, dest_block=0, src_block=0)
+            'newFakeLUN', 'false', block_count=0, dest_block=0, src_block=0)
 
     def test_clone_lun_qos_supplied(self):
         """Test for qos supplied in clone lun invocation."""
index 626e0cd90440da29504543fa54542965114fea9f..f2d4fcadcebb8e344ff638413206564e8bf15fd2 100644 (file)
@@ -382,6 +382,7 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase):
     def test_do_setup_san_configured(self, mock_check_flags):
         self.library.configuration.netapp_lun_ostype = 'windows'
         self.library.configuration.netapp_host_type = 'solaris'
+        self.library.configuration.netapp_lun_space_reservation = 'disabled'
         self.library.do_setup(mock.Mock())
         self.assertTrue(mock_check_flags.called)
         self.assertEqual('windows', self.library.lun_ostype)
@@ -391,11 +392,32 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase):
     def test_do_setup_san_unconfigured(self, mock_check_flags):
         self.library.configuration.netapp_lun_ostype = None
         self.library.configuration.netapp_host_type = None
+        self.library.configuration.netapp_lun_space_reservation = 'enabled'
         self.library.do_setup(mock.Mock())
         self.assertTrue(mock_check_flags.called)
         self.assertEqual('linux', self.library.lun_ostype)
         self.assertEqual('linux', self.library.host_type)
 
+    def test_do_setup_space_reservation_disabled(self):
+        self.mock_object(na_utils, 'check_flags')
+        self.library.configuration.netapp_lun_ostype = None
+        self.library.configuration.netapp_host_type = None
+        self.library.configuration.netapp_lun_space_reservation = 'disabled'
+
+        self.library.do_setup(mock.Mock())
+
+        self.assertEqual('false', self.library.lun_space_reservation)
+
+    def test_do_setup_space_reservation_enabled(self):
+        self.mock_object(na_utils, 'check_flags')
+        self.library.configuration.netapp_lun_ostype = None
+        self.library.configuration.netapp_host_type = None
+        self.library.configuration.netapp_lun_space_reservation = 'enabled'
+
+        self.library.do_setup(mock.Mock())
+
+        self.assertEqual('true', self.library.lun_space_reservation)
+
     def test_get_existing_vol_manage_missing_id_path(self):
         self.assertRaises(exception.ManageExistingInvalidReference,
                           self.library._get_existing_vol_with_manage_ref,
@@ -675,6 +697,7 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase):
         self.mock_object(self.library, 'extend_volume')
         self.mock_object(self.library, 'delete_volume')
         self.mock_object(self.library, '_mark_qos_policy_group_for_deletion')
+        self.library.lun_space_reservation = 'false'
 
         self.library._clone_source_to_destination(fake.CLONE_SOURCE,
                                                   fake.CLONE_DESTINATION)
@@ -685,7 +708,7 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase):
             fake.CLONE_DESTINATION, fake.EXTRA_SPECS)
         self.library._clone_lun.assert_called_once_with(
             fake.CLONE_SOURCE_NAME, fake.CLONE_DESTINATION_NAME,
-            space_reserved='true',
+            space_reserved='false',
             qos_policy_group_name=fake.QOS_POLICY_GROUP_NAME)
         self.library.extend_volume.assert_called_once_with(
             fake.CLONE_DESTINATION, fake.CLONE_DESTINATION_SIZE,
@@ -704,6 +727,7 @@ class NetAppBlockStorageLibraryTestCase(test.TestCase):
             side_effect=Exception))
         self.mock_object(self.library, 'delete_volume')
         self.mock_object(self.library, '_mark_qos_policy_group_for_deletion')
+        self.library.lun_space_reservation = 'true'
 
         self.assertRaises(exception.VolumeBackendAPIException,
                           self.library._clone_source_to_destination,
index 12568ad9331f54928da708db57163e1d6ae8019f..c610e6a70139dee721c7ddd425a532ba2b54c220 100644 (file)
@@ -164,30 +164,27 @@ class NetAppBlockStorageCmodeLibraryTestCase(test.TestCase):
         self.library.zapi_client = mock.Mock()
         self.library.zapi_client.get_lun_by_args.return_value = [
             mock.Mock(spec=netapp_api.NaElement)]
-        lun = netapp_api.NaElement.create_node_with_children(
-            'lun-info',
-            **{'alignment': 'indeterminate',
-               'block-size': '512',
-               'comment': '',
-               'creation-timestamp': '1354536362',
-               'is-space-alloc-enabled': 'false',
-               'is-space-reservation-enabled': 'true',
-               'mapped': 'false',
-               'multiprotocol-type': 'linux',
-               'online': 'true',
-               'path': '/vol/fakeLUN/lun1',
-               'prefix-size': '0',
-               'qtree': '',
-               'read-only': 'false',
-               'serial-number': '2FfGI$APyN68',
-               'share-state': 'none',
-               'size': '20971520',
-               'size-used': '0',
-               'staging': 'false',
-               'suffix-size': '0',
-               'uuid': 'cec1f3d7-3d41-11e2-9cf4-123478563412',
-               'volume': 'fakeLUN',
-               'vserver': 'fake_vserver'})
+        lun = fake.FAKE_LUN
+        self.library._get_lun_by_args = mock.Mock(return_value=[lun])
+        self.library._add_lun_to_table = mock.Mock()
+        self.library._update_stale_vols = mock.Mock()
+
+        self.library._clone_lun('fakeLUN', 'newFakeLUN', 'false')
+
+        self.library.zapi_client.clone_lun.assert_called_once_with(
+            'fakeLUN', 'fakeLUN', 'newFakeLUN', 'false', block_count=0,
+            dest_block=0, src_block=0, qos_policy_group_name=None)
+
+    def test_clone_lun_no_space_reservation(self):
+        """Test for when space_reservation is not passed."""
+
+        self.library._get_lun_attr = mock.Mock(return_value={'Volume':
+                                                             'fakeLUN'})
+        self.library.zapi_client = mock.Mock()
+        self.library.lun_space_reservation = 'false'
+        self.library.zapi_client.get_lun_by_args.return_value = [
+            mock.Mock(spec=netapp_api.NaElement)]
+        lun = fake.FAKE_LUN
         self.library._get_lun_by_args = mock.Mock(return_value=[lun])
         self.library._add_lun_to_table = mock.Mock()
         self.library._update_stale_vols = mock.Mock()
@@ -195,7 +192,7 @@ class NetAppBlockStorageCmodeLibraryTestCase(test.TestCase):
         self.library._clone_lun('fakeLUN', 'newFakeLUN')
 
         self.library.zapi_client.clone_lun.assert_called_once_with(
-            'fakeLUN', 'fakeLUN', 'newFakeLUN', 'true', block_count=0,
+            'fakeLUN', 'fakeLUN', 'newFakeLUN', 'false', block_count=0,
             dest_block=0, src_block=0, qos_policy_group_name=None)
 
     def test_get_fc_target_wwpns(self):
index ef7a229040ac6db4d5ca0fabfbeadd90c281896e..03ac32363d2b8a49660da4652b443b7ae6ef0796 100644 (file)
@@ -181,10 +181,12 @@ class NetAppBlockStorage7modeLibrary(block_base.NetAppBlockStorageLibrary):
             return True
         return False
 
-    def _clone_lun(self, name, new_name, space_reserved='true',
+    def _clone_lun(self, name, new_name, space_reserved=None,
                    qos_policy_group_name=None, src_block=0, dest_block=0,
                    block_count=0):
         """Clone LUN with the given handle to the new name."""
+        if not space_reserved:
+            space_reserved = self.lun_space_reservation
         if qos_policy_group_name is not None:
             msg = _('Data ONTAP operating in 7-Mode does not support QoS '
                     'policy groups.')
index 5527f45ded84a5d096315eeedcbf39f0c9c25dc1..d876adfa778c129168d787ecead7f98d42401836 100644 (file)
@@ -94,6 +94,7 @@ class NetAppBlockStorageLibrary(object):
         self.lun_table = {}
         self.lun_ostype = None
         self.host_type = None
+        self.lun_space_reservation = 'true'
         self.lookup_service = fczm_utils.create_lookup_service()
         self.app_version = kwargs.get("app_version", "unknown")
 
@@ -111,6 +112,10 @@ class NetAppBlockStorageLibrary(object):
                            or self.DEFAULT_LUN_OS)
         self.host_type = (self.configuration.netapp_host_type
                           or self.DEFAULT_HOST_TYPE)
+        if self.configuration.netapp_lun_space_reservation == 'enabled':
+            self.lun_space_reservation = 'true'
+        else:
+            self.lun_space_reservation = 'false'
 
     def check_for_setup_error(self):
         """Check that the driver is working and can communicate.
@@ -160,7 +165,7 @@ class NetAppBlockStorageLibrary(object):
         size = int(volume['size']) * units.Gi
 
         metadata = {'OsType': self.lun_ostype,
-                    'SpaceReserved': 'true',
+                    'SpaceReserved': self.lun_space_reservation,
                     'Path': '/vol/%s/%s' % (pool_name, lun_name)}
 
         qos_policy_group_info = self._setup_qos_for_volume(volume, extra_specs)
@@ -268,7 +273,7 @@ class NetAppBlockStorageLibrary(object):
 
         try:
             self._clone_lun(source_name, destination_name,
-                            space_reserved='true',
+                            space_reserved=self.lun_space_reservation,
                             qos_policy_group_name=qos_policy_group_name)
 
             if destination_size != source_size:
index 0fd2263b687668ea4a962d7b14284bc0356327c2..3e8b0868dcaaa94a5849a157ea30925d4b430729 100644 (file)
@@ -115,10 +115,12 @@ class NetAppBlockStorageCmodeLibrary(block_base.NetAppBlockStorageLibrary):
                             return igroup_name, lun_map['lun-id']
         return None, None
 
-    def _clone_lun(self, name, new_name, space_reserved='true',
+    def _clone_lun(self, name, new_name, space_reserved=None,
                    qos_policy_group_name=None, src_block=0, dest_block=0,
                    block_count=0):
         """Clone LUN with the given handle to the new name."""
+        if not space_reserved:
+            space_reserved = self.lun_space_reservation
         metadata = self._get_lun_attr(name, 'metadata')
         volume = metadata['Volume']
         self.zapi_client.clone_lun(volume, name, new_name, space_reserved,
index cdc0fe0c8052a5fc9896f39085780500d6316992..f58a6475b7e4c20269c4cc5ff6b4759f051679ec 100644 (file)
@@ -83,7 +83,14 @@ netapp_provisioning_opts = [
                      'to restrict provisioning to the specified controller '
                      'volumes. Specify the value of this option to be a '
                      'comma separated list of NetApp controller volume names '
-                     'to be used for provisioning.')), ]
+                     'to be used for provisioning.')),
+    cfg.StrOpt('netapp_lun_space_reservation',
+               default='enabled',
+               choices=['enabled', 'disabled'],
+               help=('This option determines if storage space is reserved '
+                     'for LUN allocation. If enabled, LUNs are thick '
+                     'provisioned. If space reservation is disabled, '
+                     'storage space is allocated on demand.')), ]
 
 netapp_cluster_opts = [
     cfg.StrOpt('netapp_vserver',