]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Use nfs_oversub_ratio when reporting pool capacity
authorTom Barron <tpb@dyncloud.net>
Tue, 21 Apr 2015 15:07:30 +0000 (11:07 -0400)
committerTom Barron <tpb@dyncloud.net>
Wed, 13 May 2015 20:52:57 +0000 (20:52 +0000)
Currently NetApp NFS drivers do not make use of the nfs_oversub_ratio
configuration parameter to enable OpenStack administrators to report
anything other than the most conservative capacity and usage information
up to the scheduler

This commit:
  *  modifies the NetApp drivers to use the nfs_oversub_ratio as
     documented.
  *  uses direct API with filers to gather capacity information rather
     than stat and du commands
  *  brings our reporting of reserved percentage in line with the way
     the scheduler actually makes use of this statistic
  *  simplifies and cleans up the way we gather and report pool statistics

Note that this fix addresses an in-the-field bug report from juno
and is intended to be the basis for backported fixes.

In kilo, a more general approach to overprovisioning using
     max_oversubscription_ratio
was introduced via commit 3548a4bc9edbb26b248b5af5ecc2145f2c6f7481.
In this newer approach, the scheduler computes "virtual" free space
rather than the driver reporting "apparent" free space.

This fix to bring NetApp NFS drivers into conformity with the generic
NFS driver is not intended as a substitute for introducing support
in our drivers for the newer approach to overprovisioning.  Rather,
it is a bug-fix for an existing failure to honor the nfs_oversub_ratio.

DocImpact
Co-Authored-By: Dustin Schoenbrun <dustin.schoenbrun@netapp.com>
Closes-bug: 1449620
Change-Id: Ic7b606b88f063b9ed6df62fd1fb7248922496326

12 files changed:
cinder/tests/unit/test_netapp_nfs.py
cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_7mode.py
cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_cmode.py
cinder/tests/unit/volume/drivers/netapp/dataontap/fakes.py
cinder/tests/unit/volume/drivers/netapp/dataontap/test_nfs_7mode.py [new file with mode: 0644]
cinder/tests/unit/volume/drivers/netapp/dataontap/test_nfs_base.py
cinder/tests/unit/volume/drivers/netapp/dataontap/test_nfs_cmode.py
cinder/volume/drivers/netapp/dataontap/client/client_7mode.py
cinder/volume/drivers/netapp/dataontap/client/client_cmode.py
cinder/volume/drivers/netapp/dataontap/nfs_7mode.py
cinder/volume/drivers/netapp/dataontap/nfs_base.py
cinder/volume/drivers/netapp/dataontap/nfs_cmode.py

index 3fcf99cb41be8b7714e34a769ee82123f50faf57..d906052cd1618ef390c8e70c90b76e520e4bc228 100644 (file)
@@ -445,7 +445,7 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
         mox.StubOutWithMock(drv, '_delete_files_till_bytes_free')
         mox.StubOutWithMock(drv, '_get_capacity_info')
 
-        drv._get_capacity_info('testshare').AndReturn((100, 19, 81))
+        drv._get_capacity_info('testshare').AndReturn((100, 19))
         drv._find_old_cache_files('testshare').AndReturn(['f1', 'f2'])
         drv._delete_files_till_bytes_free(
             ['f1', 'f2'], 'testshare', bytes_to_free=31)
index ca2a9e8e4eaac9703a88b9b531e1ede2c053509c..4f3467c00d06d777a1a522fce2dbe25305d97f46 100644 (file)
@@ -1,4 +1,5 @@
 # Copyright (c) 2014 Alex Meade.  All rights reserved.
+# Copyright (c) 2015 Dustin Schoenbrun. All rights reserved.
 # All Rights Reserved.
 #
 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -643,3 +644,26 @@ class NetApp7modeClientTestCase(test.TestCase):
         wwpns = self.client.get_fc_target_wwpns()
 
         self.assertSetEqual(set(wwpns), set([wwpn1, wwpn2]))
+
+    def test_get_flexvol_capacity(self):
+        expected_total_bytes = 1000
+        expected_available_bytes = 750
+        fake_flexvol_path = '/fake/vol'
+        response = netapp_api.NaElement(
+            etree.XML("""
+            <results status="passed">
+                <volumes>
+                    <volume-info>
+                        <size-total>%(total_bytes)s</size-total>
+                        <size-available>%(available_bytes)s</size-available>
+                    </volume-info>
+                </volumes>
+            </results>""" % {'total_bytes': expected_total_bytes,
+                             'available_bytes': expected_available_bytes}))
+        self.connection.invoke_successfully.return_value = response
+
+        total_bytes, available_bytes = (
+            self.client.get_flexvol_capacity(fake_flexvol_path))
+
+        self.assertEqual(expected_total_bytes, total_bytes)
+        self.assertEqual(expected_available_bytes, available_bytes)
index 655eb838ed2c2c241da1c06737824c0b66f40b8d..f999ba97b97732e45b9df7a397d6e4af3bf221a0 100644 (file)
@@ -1,4 +1,5 @@
 # Copyright (c) 2014 Alex Meade.
+# Copyright (c) 2015 Dustin Schoenbrun.
 # All rights reserved.
 #
 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -672,3 +673,28 @@ class NetAppCmodeClientTestCase(test.TestCase):
             self.client.get_operational_network_interface_addresses())
 
         self.assertEqual(expected_result, address_list)
+
+    def test_get_flexvol_capacity(self):
+        expected_total_size = 1000
+        expected_available_size = 750
+        fake_flexvol_path = '/fake/vol'
+        response = netapp_api.NaElement(
+            etree.XML("""
+            <results status="passed">
+                <attributes-list>
+                    <volume-attributes>
+                        <volume-space-attributes>
+                            <size-available>%(available_size)s</size-available>
+                            <size-total>%(total_size)s</size-total>
+                        </volume-space-attributes>
+                    </volume-attributes>
+                </attributes-list>
+            </results>""" % {'available_size': expected_available_size,
+                             'total_size': expected_total_size}))
+        self.connection.invoke_successfully.return_value = response
+
+        total_size, available_size = (
+            self.client.get_flexvol_capacity(fake_flexvol_path))
+
+        self.assertEqual(expected_total_size, total_size)
+        self.assertEqual(expected_available_size, available_size)
index 39075ba2cc101fb6912f7bd781ebe8b6759e83dd..9a22cff798befb8c4c0a62502dd9f7c553552ec6 100644 (file)
@@ -111,3 +111,16 @@ ISCSI_TARGET_DETAILS_LIST = [
     {'address': '1.2.3.4', 'port': '3260'},
     {'address': '99.98.97.96', 'port': '3260'},
 ]
+
+HOSTNAME = 'fake.host.com'
+IPV4_ADDRESS = '192.168.14.2'
+IPV6_ADDRESS = 'fe80::6e40:8ff:fe8a:130'
+EXPORT_PATH = '/fake/export/path'
+NFS_SHARE = HOSTNAME + ':' + EXPORT_PATH
+NFS_SHARE_IPV4 = IPV4_ADDRESS + ':' + EXPORT_PATH
+NFS_SHARE_IPV6 = IPV6_ADDRESS + ':' + EXPORT_PATH
+
+RESERVED_PERCENTAGE = 7
+TOTAL_BYTES = 4797892092432
+AVAILABLE_BYTES = 13479932478
+CAPACITY_VALUES = (TOTAL_BYTES, AVAILABLE_BYTES)
diff --git a/cinder/tests/unit/volume/drivers/netapp/dataontap/test_nfs_7mode.py b/cinder/tests/unit/volume/drivers/netapp/dataontap/test_nfs_7mode.py
new file mode 100644 (file)
index 0000000..2ff1d54
--- /dev/null
@@ -0,0 +1,75 @@
+# Copyright (c) 2015 Tom Barron.  All rights reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+"""
+Mock unit tests for the NetApp 7mode nfs storage driver
+"""
+
+import mock
+from os_brick.remotefs import remotefs as remotefs_brick
+from oslo_utils import units
+
+from cinder import test
+from cinder.tests.unit.volume.drivers.netapp.dataontap import fakes as fake
+from cinder.tests.unit.volume.drivers.netapp import fakes as na_fakes
+from cinder import utils
+from cinder.volume.drivers.netapp.dataontap import nfs_7mode
+from cinder.volume.drivers.netapp import utils as na_utils
+
+
+class NetApp7modeNfsDriverTestCase(test.TestCase):
+    def setUp(self):
+        super(NetApp7modeNfsDriverTestCase, self).setUp()
+
+        kwargs = {'configuration': self.get_config_7mode()}
+
+        with mock.patch.object(utils, 'get_root_helper',
+                               return_value=mock.Mock()):
+            with mock.patch.object(remotefs_brick, 'RemoteFsClient',
+                                   return_value=mock.Mock()):
+                self.driver = nfs_7mode.NetApp7modeNfsDriver(**kwargs)
+                self.driver._mounted_shares = [fake.NFS_SHARE]
+                self.driver.ssc_vols = True
+
+    def get_config_7mode(self):
+        config = na_fakes.create_configuration_cmode()
+        config.netapp_storage_protocol = 'nfs'
+        config.netapp_login = 'root'
+        config.netapp_password = 'pass'
+        config.netapp_server_hostname = '127.0.0.1'
+        config.netapp_transport_type = 'http'
+        config.netapp_server_port = '80'
+        return config
+
+    def test_get_pool_stats(self):
+
+        total_capacity_gb = na_utils.round_down(
+            fake.TOTAL_BYTES / units.Gi, '0.01')
+        free_capacity_gb = na_utils.round_down(
+            fake.AVAILABLE_BYTES / units.Gi, '0.01')
+        capacity = dict(
+            reserved_percentage = fake.RESERVED_PERCENTAGE,
+            total_capacity_gb = total_capacity_gb,
+            free_capacity_gb = free_capacity_gb,
+        )
+
+        mock_get_capacity = self.mock_object(
+            self.driver, '_get_share_capacity_info')
+        mock_get_capacity.return_value = capacity
+
+        result = self.driver._get_pool_stats()
+
+        self.assertEqual(fake.RESERVED_PERCENTAGE,
+                         result[0]['reserved_percentage'])
+        self.assertEqual(total_capacity_gb, result[0]['total_capacity_gb'])
+        self.assertEqual(free_capacity_gb, result[0]['free_capacity_gb'])
index 086985b621141010d25ac8186ca055558da4eef1..89c993b0ac8b5a3fc60e49c61246a4dd1d82eb52 100644 (file)
@@ -18,8 +18,10 @@ Mock unit tests for the NetApp nfs storage driver
 
 import mock
 from os_brick.remotefs import remotefs as remotefs_brick
+from oslo_utils import units
 
 from cinder import test
+from cinder.tests.unit.volume.drivers.netapp.dataontap import fakes as fake
 from cinder import utils
 from cinder.volume.drivers.netapp.dataontap import nfs_base
 from cinder.volume.drivers.netapp import utils as na_utils
@@ -31,6 +33,8 @@ class NetAppNfsDriverTestCase(test.TestCase):
         super(NetAppNfsDriverTestCase, self).setUp()
         configuration = mock.Mock()
         configuration.nfs_mount_point_base = '/mnt/test'
+        configuration.nfs_used_ratio = 0.89
+        configuration.nfs_oversub_ratio = 3.0
 
         kwargs = {'configuration': configuration}
 
@@ -47,3 +51,50 @@ class NetAppNfsDriverTestCase(test.TestCase):
 
         self.assertTrue(mock_check_flags.called)
         self.assertTrue(mock_super_do_setup.called)
+
+    def test_get_share_capacity_info(self):
+        mock_get_capacity = self.mock_object(self.driver, '_get_capacity_info')
+        mock_get_capacity.return_value = fake.CAPACITY_VALUES
+        expected_total_capacity_gb = (na_utils.round_down(
+            (fake.TOTAL_BYTES *
+             self.driver.configuration.nfs_oversub_ratio) /
+            units.Gi, '0.01'))
+        expected_free_capacity_gb = (na_utils.round_down(
+            (fake.AVAILABLE_BYTES *
+             self.driver.configuration.nfs_oversub_ratio) /
+            units.Gi, '0.01'))
+        expected_reserved_percentage = round(
+            100 * (1 - self.driver.configuration.nfs_used_ratio))
+
+        result = self.driver._get_share_capacity_info(fake.NFS_SHARE)
+
+        self.assertEqual(expected_total_capacity_gb,
+                         result['total_capacity_gb'])
+        self.assertEqual(expected_free_capacity_gb,
+                         result['free_capacity_gb'])
+        self.assertEqual(expected_reserved_percentage,
+                         result['reserved_percentage'])
+
+    def test_get_capacity_info_ipv4_share(self):
+        expected = fake.CAPACITY_VALUES
+        self.driver.zapi_client = mock.Mock()
+        get_capacity = self.driver.zapi_client.get_flexvol_capacity
+        get_capacity.return_value = fake.CAPACITY_VALUES
+
+        result = self.driver._get_capacity_info(fake.NFS_SHARE_IPV4)
+
+        self.assertEqual(expected, result)
+        get_capacity.assert_has_calls([
+            mock.call(fake.EXPORT_PATH)])
+
+    def test_get_capacity_info_ipv6_share(self):
+        expected = fake.CAPACITY_VALUES
+        self.driver.zapi_client = mock.Mock()
+        get_capacity = self.driver.zapi_client.get_flexvol_capacity
+        get_capacity.return_value = fake.CAPACITY_VALUES
+
+        result = self.driver._get_capacity_info(fake.NFS_SHARE_IPV6)
+
+        self.assertEqual(expected, result)
+        get_capacity.assert_has_calls([
+            mock.call(fake.EXPORT_PATH)])
index 41ed696506a5fe0f4feb823bcb888581a6793357..1fb6b7cee87eea1654c4a1a25460ada4ad64c5bb 100644 (file)
@@ -1,5 +1,5 @@
 # Copyright (c) 2014 Andrew Kerr.  All rights reserved.
-# All Rights Reserved.
+# Copyright (c) 2015 Tom Barron.  All rights reserved.
 #
 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
 #    not use this file except in compliance with the License. You may obtain
@@ -18,8 +18,10 @@ Mock unit tests for the NetApp cmode nfs storage driver
 
 import mock
 from os_brick.remotefs import remotefs as remotefs_brick
+from oslo_utils import units
 
 from cinder import test
+from cinder.tests.unit.volume.drivers.netapp.dataontap import fakes as fake
 from cinder.tests.unit.volume.drivers.netapp import fakes as na_fakes
 from cinder import utils
 from cinder.volume.drivers.netapp.dataontap.client import client_cmode
@@ -39,6 +41,8 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
             with mock.patch.object(remotefs_brick, 'RemoteFsClient',
                                    return_value=mock.Mock()):
                 self.driver = nfs_cmode.NetAppCmodeNfsDriver(**kwargs)
+                self.driver._mounted_shares = [fake.NFS_SHARE]
+                self.driver.ssc_vols = True
 
     def get_config_cmode(self):
         config = na_fakes.create_configuration_cmode()
@@ -59,3 +63,30 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
 
         self.assertTrue(mock_check_flags.called)
         self.assertTrue(mock_super_do_setup.called)
+
+    def test_get_pool_stats(self):
+
+        total_capacity_gb = na_utils.round_down(
+            fake.TOTAL_BYTES / units.Gi, '0.01')
+        free_capacity_gb = na_utils.round_down(
+            fake.AVAILABLE_BYTES / units.Gi, '0.01')
+        capacity = dict(
+            reserved_percentage = fake.RESERVED_PERCENTAGE,
+            total_capacity_gb = total_capacity_gb,
+            free_capacity_gb = free_capacity_gb,
+        )
+
+        mock_get_capacity = self.mock_object(
+            self.driver, '_get_share_capacity_info')
+        mock_get_capacity.return_value = capacity
+
+        mock_get_vol_for_share = self.mock_object(
+            self.driver, '_get_vol_for_share')
+        mock_get_vol_for_share.return_value = None
+
+        result = self.driver._get_pool_stats()
+
+        self.assertEqual(fake.RESERVED_PERCENTAGE,
+                         result[0]['reserved_percentage'])
+        self.assertEqual(total_capacity_gb, result[0]['total_capacity_gb'])
+        self.assertEqual(free_capacity_gb, result[0]['free_capacity_gb'])
index 4e3f4004897fd89b5696583479f0cf8f03f848bf..c20fb6679a911d674e70fc1c043541d7f56c9b03 100644 (file)
@@ -398,3 +398,20 @@ class Client(client_base.Client):
     def get_ifconfig(self):
         ifconfig = netapp_api.NaElement('net-ifconfig-get')
         return self.connection.invoke_successfully(ifconfig)
+
+    def get_flexvol_capacity(self, flexvol_path):
+        """Gets total capacity and free capacity, in bytes, of the flexvol."""
+
+        api_args = {'volume': flexvol_path, 'verbose': 'false'}
+
+        result = self.send_request('volume-list-info', api_args)
+
+        flexvol_info_list = result.get_child_by_name('volumes')
+        flexvol_info = flexvol_info_list.get_children()[0]
+
+        total_bytes = float(
+            flexvol_info.get_child_content('size-total'))
+        available_bytes = float(
+            flexvol_info.get_child_content('size-available'))
+
+        return total_bytes, available_bytes
index 2a536cee6609dc935175db1c8fae97f4d80836c8..daeb877c261652ec4dc1461390d62e08045baa79 100644 (file)
@@ -482,3 +482,39 @@ class Client(client_base.Client):
 
         return [lif_info.get_child_content('address') for lif_info in
                 lif_info_list.get_children()]
+
+    def get_flexvol_capacity(self, flexvol_path):
+        """Gets total capacity and free capacity, in bytes, of the flexvol."""
+
+        api_args = {
+            'query': {
+                'volume-attributes': {
+                    'volume-id-attributes': {
+                        'junction-path': flexvol_path
+                    }
+                }
+            },
+            'desired-attributes': {
+                'volume-attributes': {
+                    'volume-space-attributes': {
+                        'size-available': None,
+                        'size-total': None,
+                    }
+                }
+            },
+        }
+
+        result = self.send_request('volume-get-iter', api_args)
+
+        attributes_list = result.get_child_by_name('attributes-list')
+        volume_attributes = attributes_list.get_child_by_name(
+            'volume-attributes')
+        volume_space_attributes = volume_attributes.get_child_by_name(
+            'volume-space-attributes')
+
+        size_available = float(
+            volume_space_attributes.get_child_content('size-available'))
+        size_total = float(
+            volume_space_attributes.get_child_content('size-total'))
+
+        return size_total, size_available
index e15e9fcfcc116592d0c48d13345349d75930d331..8b4fab714058b8fa692777b5d076c21b794b0072 100644 (file)
@@ -4,6 +4,7 @@
 # Copyright (c) 2014 Clinton Knight.  All rights reserved.
 # Copyright (c) 2014 Alex Meade.  All rights reserved.
 # Copyright (c) 2014 Bob Callaway.  All rights reserved.
+# Copyright (c) 2015 Tom Barron.  All rights reserved.
 #
 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
 #    not use this file except in compliance with the License. You may obtain
@@ -21,7 +22,6 @@ Volume driver for NetApp NFS storage.
 """
 
 from oslo_log import log as logging
-from oslo_utils import units
 
 from cinder import exception
 from cinder.i18n import _, _LE, _LI
@@ -137,28 +137,12 @@ class NetApp7modeNfsDriver(nfs_base.NetAppNfsDriver):
 
         for nfs_share in self._mounted_shares:
 
-            capacity = self._get_extended_capacity_info(nfs_share)
+            capacity = self._get_share_capacity_info(nfs_share)
 
             pool = dict()
             pool['pool_name'] = nfs_share
             pool['QoS_support'] = False
-            pool['reserved_percentage'] = 0
-
-            # Report pool as reserved when over the configured used_ratio
-            if capacity['used_ratio'] > self.configuration.nfs_used_ratio:
-                pool['reserved_percentage'] = 100
-
-            # Report pool as reserved when over the subscribed ratio
-            if capacity['subscribed_ratio'] >=\
-                    self.configuration.nfs_oversub_ratio:
-                pool['reserved_percentage'] = 100
-
-            # convert sizes to GB
-            total = float(capacity['apparent_size']) / units.Gi
-            pool['total_capacity_gb'] = na_utils.round_down(total, '0.01')
-
-            free = float(capacity['apparent_available']) / units.Gi
-            pool['free_capacity_gb'] = na_utils.round_down(free, '0.01')
+            pool.update(capacity)
 
             pools.append(pool)
 
index e402aac24b392c52c633cc2831858996b5a27e48..919885a78e6ecafe589c67eb20301ace6858efc5 100644 (file)
@@ -4,6 +4,7 @@
 # Copyright (c) 2014 Clinton Knight.  All rights reserved.
 # Copyright (c) 2014 Alex Meade.  All rights reserved.
 # Copyright (c) 2014 Bob Callaway.  All rights reserved.
+# Copyright (c) 2015 Tom Barron.  All rights reserved.
 #
 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
 #    not use this file except in compliance with the License. You may obtain
@@ -73,6 +74,7 @@ class NetAppNfsDriver(nfs.NfsDriver):
         super(NetAppNfsDriver, self).do_setup(context)
         self._context = context
         na_utils.check_flags(self.REQUIRED_FLAGS, self.configuration)
+        self.zapi_client = None
 
     def check_for_setup_error(self):
         """Returns an error if prerequisites aren't met."""
@@ -292,7 +294,7 @@ class NetAppNfsDriver(nfs.NfsDriver):
                 self.configuration.thres_avl_size_perc_stop
             for share in getattr(self, '_mounted_shares', []):
                 try:
-                    total_size, total_avl, _total_alc = \
+                    total_size, total_avl = \
                         self._get_capacity_info(share)
                     avl_percent = int((total_avl / total_size) * 100)
                     if avl_percent <= thres_size_perc_start:
@@ -625,7 +627,7 @@ class NetAppNfsDriver(nfs.NfsDriver):
 
     def _check_share_can_hold_size(self, share, size):
         """Checks if volume can hold image with size."""
-        _tot_size, tot_available, _tot_allocated = self._get_capacity_info(
+        _tot_size, tot_available = self._get_capacity_info(
             share)
         if tot_available < size:
             msg = _("Container size smaller than required file size.")
@@ -666,22 +668,38 @@ class NetAppNfsDriver(nfs.NfsDriver):
                 'A volume ID or share was not specified.')
         return host_ip, export_path
 
-    def _get_extended_capacity_info(self, nfs_share):
-        """Returns an extended set of share capacity metrics."""
+    def _get_share_capacity_info(self, nfs_share):
+        """Returns the share capacity metrics needed by the scheduler."""
 
-        total_size, total_available, total_allocated = \
-            self._get_capacity_info(nfs_share)
+        used_ratio = self.configuration.nfs_used_ratio
+        oversub_ratio = self.configuration.nfs_oversub_ratio
 
-        used_ratio = (total_size - total_available) / total_size
-        subscribed_ratio = total_allocated / total_size
-        apparent_size = max(0, total_size * self.configuration.nfs_used_ratio)
-        apparent_available = max(0, apparent_size - total_allocated)
+        # The scheduler's capacity filter will reduce the amount of
+        # free space that we report to it by the reserved percentage.
+        reserved_ratio = 1 - used_ratio
+        reserved_percentage = round(100 * reserved_ratio)
 
-        return {'total_size': total_size, 'total_available': total_available,
-                'total_allocated': total_allocated, 'used_ratio': used_ratio,
-                'subscribed_ratio': subscribed_ratio,
-                'apparent_size': apparent_size,
-                'apparent_available': apparent_available}
+        total_size, total_available = self._get_capacity_info(nfs_share)
+
+        apparent_size = total_size * oversub_ratio
+        apparent_size_gb = na_utils.round_down(
+            apparent_size / units.Gi, '0.01')
+
+        apparent_free_size = total_available * oversub_ratio
+        apparent_free_gb = na_utils.round_down(
+            float(apparent_free_size) / units.Gi, '0.01')
+
+        capacity = dict()
+        capacity['reserved_percentage'] = reserved_percentage
+        capacity['total_capacity_gb'] = apparent_size_gb
+        capacity['free_capacity_gb'] = apparent_free_gb
+
+        return capacity
+
+    def _get_capacity_info(self, nfs_share):
+        """Get total capacity and free capacity in bytes for an nfs share."""
+        export_path = nfs_share.rsplit(':', 1)[1]
+        return self.zapi_client.get_flexvol_capacity(export_path)
 
     def _check_volume_type(self, volume, share, file_name):
         """Match volume type for share file."""
index 538428212cef8ab52c343edd9dddbd7a948e5d04..c5e3e8bd69ef9f45062f4edc205b37257222ef33 100644 (file)
@@ -4,6 +4,7 @@
 # Copyright (c) 2014 Clinton Knight.  All rights reserved.
 # Copyright (c) 2014 Alex Meade.  All rights reserved.
 # Copyright (c) 2014 Bob Callaway.  All rights reserved.
+# Copyright (c) 2015 Tom Barron.  All rights reserved.
 #
 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
 #    not use this file except in compliance with the License. You may obtain
@@ -24,7 +25,6 @@ import os
 import uuid
 
 from oslo_log import log as logging
-from oslo_utils import units
 import six
 
 from cinder import exception
@@ -198,28 +198,12 @@ class NetAppCmodeNfsDriver(nfs_base.NetAppNfsDriver):
 
         for nfs_share in self._mounted_shares:
 
-            capacity = self._get_extended_capacity_info(nfs_share)
+            capacity = self._get_share_capacity_info(nfs_share)
 
             pool = dict()
             pool['pool_name'] = nfs_share
             pool['QoS_support'] = False
-            pool['reserved_percentage'] = 0
-
-            # Report pool as reserved when over the configured used_ratio
-            if capacity['used_ratio'] > self.configuration.nfs_used_ratio:
-                pool['reserved_percentage'] = 100
-
-            # Report pool as reserved when over the subscribed ratio
-            if capacity['subscribed_ratio'] >=\
-                    self.configuration.nfs_oversub_ratio:
-                pool['reserved_percentage'] = 100
-
-            # convert sizes to GB
-            total = float(capacity['apparent_size']) / units.Gi
-            pool['total_capacity_gb'] = na_utils.round_down(total, '0.01')
-
-            free = float(capacity['apparent_available']) / units.Gi
-            pool['free_capacity_gb'] = na_utils.round_down(free, '0.01')
+            pool.update(capacity)
 
             # add SSC content if available
             vol = self._get_vol_for_share(nfs_share)