]> 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>
Tue, 26 May 2015 20:00:47 +0000 (20:00 +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
(cherry picked from commit e52f304313efc695f7dd89c222041bffd53c131a)

12 files changed:
cinder/tests/test_netapp_nfs.py
cinder/tests/volume/drivers/netapp/dataontap/client/test_client_7mode.py
cinder/tests/volume/drivers/netapp/dataontap/client/test_client_cmode.py
cinder/tests/volume/drivers/netapp/dataontap/fakes.py
cinder/tests/volume/drivers/netapp/dataontap/test_nfs_7mode.py [new file with mode: 0644]
cinder/tests/volume/drivers/netapp/dataontap/test_nfs_base.py
cinder/tests/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 f503169ba26c437840fbb3ac506d16020500e9f5..4a2aa935663b4d8fa60ac8c9d36c0f03405dfbd9 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 59113be2524e51f624b6d807923f1ed8ca498a59..8e7eb6cc1d7183e051a40f576fbff8f1ba98554c 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 25a23ae670afb9014fdc101c673248365dbbe8c0..b8aa737cac1bde8fc9735fe54c08780c573bd415 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
@@ -670,3 +671,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/volume/drivers/netapp/dataontap/test_nfs_7mode.py b/cinder/tests/volume/drivers/netapp/dataontap/test_nfs_7mode.py
new file mode 100644 (file)
index 0000000..510c2af
--- /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 oslo_utils import units
+
+from cinder.brick.remotefs import remotefs as remotefs_brick
+from cinder import test
+from cinder.tests.volume.drivers.netapp.dataontap import fakes as fake
+from cinder.tests.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 a8cac6d35dca7174132b98f360013208f41f70cf..dc6ede87e7e8073a966426b8c2af8ed65f48f02e 100644 (file)
@@ -17,9 +17,11 @@ Mock unit tests for the NetApp nfs storage driver
 """
 
 import mock
+from oslo_utils import units
 
 from cinder.brick.remotefs import remotefs as remotefs_brick
 from cinder import test
+from cinder.tests.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 2f90277f351ae09a03a11a3e5037ef41111fe73c..7c578c1f3e36b7a4c175205a48faa457c7d95c9f 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
@@ -17,9 +17,11 @@ Mock unit tests for the NetApp cmode nfs storage driver
 """
 
 import mock
+from oslo_utils import units
 
 from cinder.brick.remotefs import remotefs as remotefs_brick
 from cinder import test
+from cinder.tests.volume.drivers.netapp.dataontap import fakes as fake
 from cinder.tests.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 5ad8d8e24c5ad2d8139ec58d198c1c69e638e419..ed7fdfa0d30a39f1fdfa03755631c75164b42081 100644 (file)
@@ -399,3 +399,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 68450a590375404e0d67511bc1e9b7f3b7a0003b..ffa9d46ae700b49173807ee1f3d0a2a5fa65ba96 100644 (file)
@@ -483,3 +483,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 a1bada0319d87bda3bac1a134a20d26285edac43..7b1bc37c95e235f9d89af994dd73fbbc1da1d115 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
 import six
 
 from cinder import exception
@@ -138,28 +138,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 8472f82a2f3a9b024c2ab069695d0c9ec3a6a0fc..8fe432b8ab0fdf3275975eb856e322e30e6f685c 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 18c7409e0a4c71a789000f5bcaff59bd54466456..0176e6bfeeabe69a5e3accf44420de77667237e6 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)