From e52f304313efc695f7dd89c222041bffd53c131a Mon Sep 17 00:00:00 2001 From: Tom Barron Date: Tue, 21 Apr 2015 11:07:30 -0400 Subject: [PATCH] Use nfs_oversub_ratio when reporting pool capacity 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 Closes-bug: 1449620 Change-Id: Ic7b606b88f063b9ed6df62fd1fb7248922496326 --- cinder/tests/unit/test_netapp_nfs.py | 2 +- .../dataontap/client/test_client_7mode.py | 24 ++++++ .../dataontap/client/test_client_cmode.py | 26 +++++++ .../volume/drivers/netapp/dataontap/fakes.py | 13 ++++ .../netapp/dataontap/test_nfs_7mode.py | 75 +++++++++++++++++++ .../drivers/netapp/dataontap/test_nfs_base.py | 51 +++++++++++++ .../netapp/dataontap/test_nfs_cmode.py | 33 +++++++- .../netapp/dataontap/client/client_7mode.py | 17 +++++ .../netapp/dataontap/client/client_cmode.py | 36 +++++++++ .../drivers/netapp/dataontap/nfs_7mode.py | 22 +----- .../drivers/netapp/dataontap/nfs_base.py | 48 ++++++++---- .../drivers/netapp/dataontap/nfs_cmode.py | 22 +----- 12 files changed, 314 insertions(+), 55 deletions(-) create mode 100644 cinder/tests/unit/volume/drivers/netapp/dataontap/test_nfs_7mode.py diff --git a/cinder/tests/unit/test_netapp_nfs.py b/cinder/tests/unit/test_netapp_nfs.py index 3fcf99cb4..d906052cd 100644 --- a/cinder/tests/unit/test_netapp_nfs.py +++ b/cinder/tests/unit/test_netapp_nfs.py @@ -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) diff --git a/cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_7mode.py b/cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_7mode.py index ca2a9e8e4..4f3467c00 100644 --- a/cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_7mode.py +++ b/cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_7mode.py @@ -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(""" + + + + %(total_bytes)s + %(available_bytes)s + + + """ % {'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) diff --git a/cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_cmode.py b/cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_cmode.py index 655eb838e..f999ba97b 100644 --- a/cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_cmode.py +++ b/cinder/tests/unit/volume/drivers/netapp/dataontap/client/test_client_cmode.py @@ -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(""" + + + + + %(available_size)s + %(total_size)s + + + + """ % {'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) diff --git a/cinder/tests/unit/volume/drivers/netapp/dataontap/fakes.py b/cinder/tests/unit/volume/drivers/netapp/dataontap/fakes.py index 39075ba2c..9a22cff79 100644 --- a/cinder/tests/unit/volume/drivers/netapp/dataontap/fakes.py +++ b/cinder/tests/unit/volume/drivers/netapp/dataontap/fakes.py @@ -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 index 000000000..2ff1d54b3 --- /dev/null +++ b/cinder/tests/unit/volume/drivers/netapp/dataontap/test_nfs_7mode.py @@ -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']) diff --git a/cinder/tests/unit/volume/drivers/netapp/dataontap/test_nfs_base.py b/cinder/tests/unit/volume/drivers/netapp/dataontap/test_nfs_base.py index 086985b62..89c993b0a 100644 --- a/cinder/tests/unit/volume/drivers/netapp/dataontap/test_nfs_base.py +++ b/cinder/tests/unit/volume/drivers/netapp/dataontap/test_nfs_base.py @@ -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)]) diff --git a/cinder/tests/unit/volume/drivers/netapp/dataontap/test_nfs_cmode.py b/cinder/tests/unit/volume/drivers/netapp/dataontap/test_nfs_cmode.py index 41ed69650..1fb6b7cee 100644 --- a/cinder/tests/unit/volume/drivers/netapp/dataontap/test_nfs_cmode.py +++ b/cinder/tests/unit/volume/drivers/netapp/dataontap/test_nfs_cmode.py @@ -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']) diff --git a/cinder/volume/drivers/netapp/dataontap/client/client_7mode.py b/cinder/volume/drivers/netapp/dataontap/client/client_7mode.py index 4e3f40048..c20fb6679 100644 --- a/cinder/volume/drivers/netapp/dataontap/client/client_7mode.py +++ b/cinder/volume/drivers/netapp/dataontap/client/client_7mode.py @@ -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 diff --git a/cinder/volume/drivers/netapp/dataontap/client/client_cmode.py b/cinder/volume/drivers/netapp/dataontap/client/client_cmode.py index 2a536cee6..daeb877c2 100644 --- a/cinder/volume/drivers/netapp/dataontap/client/client_cmode.py +++ b/cinder/volume/drivers/netapp/dataontap/client/client_cmode.py @@ -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 diff --git a/cinder/volume/drivers/netapp/dataontap/nfs_7mode.py b/cinder/volume/drivers/netapp/dataontap/nfs_7mode.py index e15e9fcfc..8b4fab714 100644 --- a/cinder/volume/drivers/netapp/dataontap/nfs_7mode.py +++ b/cinder/volume/drivers/netapp/dataontap/nfs_7mode.py @@ -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) diff --git a/cinder/volume/drivers/netapp/dataontap/nfs_base.py b/cinder/volume/drivers/netapp/dataontap/nfs_base.py index e402aac24..919885a78 100644 --- a/cinder/volume/drivers/netapp/dataontap/nfs_base.py +++ b/cinder/volume/drivers/netapp/dataontap/nfs_base.py @@ -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.""" diff --git a/cinder/volume/drivers/netapp/dataontap/nfs_cmode.py b/cinder/volume/drivers/netapp/dataontap/nfs_cmode.py index 538428212..c5e3e8bd6 100644 --- a/cinder/volume/drivers/netapp/dataontap/nfs_cmode.py +++ b/cinder/volume/drivers/netapp/dataontap/nfs_cmode.py @@ -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) -- 2.45.2