From 5ff9497e906c0d41a6b6ef59f057073eeb0fa1c6 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 (cherry picked from commit e52f304313efc695f7dd89c222041bffd53c131a) --- cinder/tests/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/volume/drivers/netapp/dataontap/test_nfs_7mode.py diff --git a/cinder/tests/test_netapp_nfs.py b/cinder/tests/test_netapp_nfs.py index f503169ba..4a2aa9356 100644 --- a/cinder/tests/test_netapp_nfs.py +++ b/cinder/tests/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/volume/drivers/netapp/dataontap/client/test_client_7mode.py b/cinder/tests/volume/drivers/netapp/dataontap/client/test_client_7mode.py index 59113be25..8e7eb6cc1 100644 --- a/cinder/tests/volume/drivers/netapp/dataontap/client/test_client_7mode.py +++ b/cinder/tests/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/volume/drivers/netapp/dataontap/client/test_client_cmode.py b/cinder/tests/volume/drivers/netapp/dataontap/client/test_client_cmode.py index 25a23ae67..b8aa737ca 100644 --- a/cinder/tests/volume/drivers/netapp/dataontap/client/test_client_cmode.py +++ b/cinder/tests/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 @@ -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(""" + + + + + %(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/volume/drivers/netapp/dataontap/fakes.py b/cinder/tests/volume/drivers/netapp/dataontap/fakes.py index 39075ba2c..9a22cff79 100644 --- a/cinder/tests/volume/drivers/netapp/dataontap/fakes.py +++ b/cinder/tests/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/volume/drivers/netapp/dataontap/test_nfs_7mode.py b/cinder/tests/volume/drivers/netapp/dataontap/test_nfs_7mode.py new file mode 100644 index 000000000..510c2af91 --- /dev/null +++ b/cinder/tests/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 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']) diff --git a/cinder/tests/volume/drivers/netapp/dataontap/test_nfs_base.py b/cinder/tests/volume/drivers/netapp/dataontap/test_nfs_base.py index a8cac6d35..dc6ede87e 100644 --- a/cinder/tests/volume/drivers/netapp/dataontap/test_nfs_base.py +++ b/cinder/tests/volume/drivers/netapp/dataontap/test_nfs_base.py @@ -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)]) diff --git a/cinder/tests/volume/drivers/netapp/dataontap/test_nfs_cmode.py b/cinder/tests/volume/drivers/netapp/dataontap/test_nfs_cmode.py index 2f90277f3..7c578c1f3 100644 --- a/cinder/tests/volume/drivers/netapp/dataontap/test_nfs_cmode.py +++ b/cinder/tests/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 @@ -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']) diff --git a/cinder/volume/drivers/netapp/dataontap/client/client_7mode.py b/cinder/volume/drivers/netapp/dataontap/client/client_7mode.py index 5ad8d8e24..ed7fdfa0d 100644 --- a/cinder/volume/drivers/netapp/dataontap/client/client_7mode.py +++ b/cinder/volume/drivers/netapp/dataontap/client/client_7mode.py @@ -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 diff --git a/cinder/volume/drivers/netapp/dataontap/client/client_cmode.py b/cinder/volume/drivers/netapp/dataontap/client/client_cmode.py index 68450a590..ffa9d46ae 100644 --- a/cinder/volume/drivers/netapp/dataontap/client/client_cmode.py +++ b/cinder/volume/drivers/netapp/dataontap/client/client_cmode.py @@ -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 diff --git a/cinder/volume/drivers/netapp/dataontap/nfs_7mode.py b/cinder/volume/drivers/netapp/dataontap/nfs_7mode.py index a1bada031..7b1bc37c9 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 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) diff --git a/cinder/volume/drivers/netapp/dataontap/nfs_base.py b/cinder/volume/drivers/netapp/dataontap/nfs_base.py index 8472f82a2..8fe432b8a 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 18c7409e0..0176e6bfe 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