From f0f52a0085a1f5bbd23e6cfa8f0ea935e8fd56c8 Mon Sep 17 00:00:00 2001 From: Andrew Kerr Date: Mon, 24 Feb 2014 16:25:20 -0500 Subject: [PATCH] Segment LUN clones in NetApp iSCSI The NetApp ZAPI for clone_create and clone_start has a maximum size. This fix breaks the lun into consumable sizes for the ZAPI. Change-Id: Id4d0872c6099b7cfc73d806d772a3ae051a76b70 Closes-Bug: 1284182 --- cinder/tests/test_netapp.py | 18 +++++++++ cinder/volume/drivers/netapp/iscsi.py | 57 +++++++++++++++++++-------- 2 files changed, 59 insertions(+), 16 deletions(-) diff --git a/cinder/tests/test_netapp.py b/cinder/tests/test_netapp.py index bad9fc85f7a..682c061bbb3 100644 --- a/cinder/tests/test_netapp.py +++ b/cinder/tests/test_netapp.py @@ -340,6 +340,12 @@ class FakeDirectCMODEServerHandler(FakeHTTPRequestHandler): body = """1 """ + elif 'lun-get-geometry' == api: + body = """256 + 512 + 3221225472512 + 2147483648 + 256""" elif 'iscsi-service-get-iter' == api: body = """ @@ -636,6 +642,18 @@ class NetAppDirectCmodeISCSIDriverTestCase(test.TestCase): self.driver.delete_snapshot(self.snapshot) self.driver.delete_volume(self.volume) + def test_extend_vol_same_size(self): + self.driver.create_volume(self.volume) + self.driver.extend_volume(self.volume, self.volume['size']) + + def test_extend_vol_direct_resize(self): + self.driver.create_volume(self.volume) + self.driver.extend_volume(self.volume, 3) + + def test_extend_vol_sub_lun_clone(self): + self.driver.create_volume(self.volume) + self.driver.extend_volume(self.volume, 4) + class NetAppDriverNegativeTestCase(test.TestCase): """Test case for NetAppDriver""" diff --git a/cinder/volume/drivers/netapp/iscsi.py b/cinder/volume/drivers/netapp/iscsi.py index a8710ce2c85..65bfb92395b 100644 --- a/cinder/volume/drivers/netapp/iscsi.py +++ b/cinder/volume/drivers/netapp/iscsi.py @@ -21,6 +21,7 @@ storage systems with installed iSCSI licenses. """ import copy +import math import sys import time import uuid @@ -526,7 +527,7 @@ class NetAppDirectISCSIDriver(driver.ISCSIDriver): return lun def _clone_lun(self, name, new_name, space_reserved='true', - start_block=0, end_block=0, block_count=0): + src_block=0, dest_block=0, block_count=0): """Clone LUN with the given name to the new name.""" raise NotImplementedError() @@ -962,7 +963,7 @@ class NetAppDirectCmodeISCSIDriver(NetAppDirectISCSIDriver): return igroup_list def _clone_lun(self, name, new_name, space_reserved='true', - start_block=0, end_block=0, block_count=0): + src_block=0, dest_block=0, block_count=0): """Clone LUN with the given handle to the new name.""" metadata = self._get_lun_attr(name, 'metadata') volume = metadata['Volume'] @@ -972,19 +973,31 @@ class NetAppDirectCmodeISCSIDriver(NetAppDirectISCSIDriver): 'destination-path': new_name, 'space-reserve': space_reserved}) if block_count > 0: block_ranges = NaElement("block-ranges") - block_range = NaElement.create_node_with_children( - 'block-range', - **{'source-block-number': str(start_block), - 'destination-block-number': str(end_block), - 'block-count': str(block_count)}) - block_ranges.add_child_elem(block_range) + # zAPI can only handle 2^24 block ranges + bc_limit = 2 ** 24 # 8GB + segments = int(math.ceil(float(block_count) / float(bc_limit))) + bc = block_count + for segment in range(0, segments): + if bc > bc_limit: + block_count = bc_limit + bc -= bc_limit + else: + block_count = bc + block_range = NaElement.create_node_with_children( + 'block-range', + **{'source-block-number': str(src_block), + 'destination-block-number': str(dest_block), + 'block-count': str(block_count)}) + block_ranges.add_child_elem(block_range) + src_block = int(src_block) + int(block_count) + dest_block = int(dest_block) + int(block_count) clone_create.add_child_elem(block_ranges) self.client.invoke_successfully(clone_create, True) LOG.debug(_("Cloned LUN with new name %s") % new_name) lun = self._get_lun_by_args(vserver=self.vserver, path='/vol/%s/%s' % (volume, new_name)) if len(lun) == 0: - msg = _("No clonned lun named %s found on the filer") + msg = _("No cloned lun named %s found on the filer") raise exception.VolumeBackendAPIException(data=msg % (new_name)) clone_meta = self._create_lun_meta(lun[0]) self._add_lun_to_table(NetAppLun('%s:%s' % (clone_meta['Vserver'], @@ -1313,7 +1326,7 @@ class NetAppDirect7modeISCSIDriver(NetAppDirectISCSIDriver): return (igroup, lun_id) def _clone_lun(self, name, new_name, space_reserved='true', - start_block=0, end_block=0, block_count=0): + src_block=0, dest_block=0, block_count=0): """Clone LUN with the given handle to the new name.""" metadata = self._get_lun_attr(name, 'metadata') path = metadata['Path'] @@ -1325,12 +1338,24 @@ class NetAppDirect7modeISCSIDriver(NetAppDirectISCSIDriver): 'no-snap': 'true'}) if block_count > 0: block_ranges = NaElement("block-ranges") - block_range = NaElement.create_node_with_children( - 'block-range', - **{'source-block-number': str(start_block), - 'destination-block-number': str(end_block), - 'block-count': str(block_count)}) - block_ranges.add_child_elem(block_range) + # zAPI can only handle 2^24 block ranges + bc_limit = 2 ** 24 # 8GB + segments = int(math.ceil(float(block_count) / float(bc_limit))) + bc = block_count + for segment in range(0, segments): + if bc > bc_limit: + block_count = bc_limit + bc -= bc_limit + else: + block_count = bc + block_range = NaElement.create_node_with_children( + 'block-range', + **{'source-block-number': str(src_block), + 'destination-block-number': str(dest_block), + 'block-count': str(block_count)}) + block_ranges.add_child_elem(block_range) + src_block = int(src_block) + int(block_count) + dest_block = int(dest_block) + int(block_count) clone_start.add_child_elem(block_ranges) result = self.client.invoke_successfully(clone_start, True) clone_id_el = result.get_child_by_name('clone-id')