Skip to content

Commit

Permalink
NetApp fix create vol different size than snapshot
Browse files Browse the repository at this point in the history
This fixes the issue of creating vol of different
size than snapshot and creating cloned vol of
different size than original.

This change adds a lot of additional LUN geometry
and sub-LUN cloning code which is neccesary to
support extreme resizes, since normal resize
operations are limitted to be within a certain factor
of the original LUN size.

Closes-Bug:#1098581

Change-Id: I8652bfaa67c12c790fa80650a051497f70279b9c
  • Loading branch information
singn committed Jul 31, 2013
1 parent 26044e7 commit 204c3a3
Show file tree
Hide file tree
Showing 5 changed files with 381 additions and 122 deletions.
104 changes: 74 additions & 30 deletions cinder/tests/test_netapp.py
Expand Up @@ -136,7 +136,7 @@ def do_POST(s):
</is-space-reservation-enabled>
<mapped>false</mapped><multiprotocol-type>linux
</multiprotocol-type>
<online>true</online><path>/vol/navneet/lun2</path>
<online>true</online><path>/vol/navneet/lun1</path>
<prefix-size>0</prefix-size><qtree></qtree><read-only>
false</read-only><serial-number>2FfGI$APyN68</serial-number>
<share-state>none</share-state><size>20971520</size>
Expand Down Expand Up @@ -389,6 +389,28 @@ def do_POST(s):
<num-records>1</num-records></results>"""
elif 'ems-autosupport-log' == api:
body = """<results status="passed"/>"""
elif 'lun-resize' == api:
body = """<results status="passed"/>"""
elif 'lun-get-geometry' == api:
body = """<results status="passed">
<size>1</size>
<bytes-per-sector>2</bytes-per-sector>
<sectors-per-track>8</sectors-per-track>
<tracks-per-cylinder>2</tracks-per-cylinder>
<cylinders>4</cylinders>
<max-resize-size>5</max-resize-size>
</results>"""
elif 'volume-options-list-info' == api:
body = """<results status="passed">
<options>
<option>
<name>compression</name>
<value>off</value>
</option>
</options>
</results>"""
elif 'lun-move' == api:
body = """<results status="passed"/>"""
else:
# Unknown API
s.send_response(500)
Expand Down Expand Up @@ -477,12 +499,18 @@ class NetAppDirectCmodeISCSIDriverTestCase(test.TestCase):
'id': 'lun1', 'provider_auth': None, 'project_id': 'project',
'display_name': None, 'display_description': 'lun1',
'volume_type_id': None}
volume_clone_fail = {'name': 'cl_fail', 'size': 1, 'volume_name': 'fail',
'os_type': 'linux', 'provider_location': 'cl_fail',
'id': 'lun1', 'provider_auth': None,
'project_id': 'project', 'display_name': None,
'display_description': 'lun1',
'volume_type_id': None}
volume_clone = {'name': 'cl_sm', 'size': 3, 'volume_name': 'lun1',
'os_type': 'linux', 'provider_location': 'cl_sm',
'id': 'lun1', 'provider_auth': None,
'project_id': 'project', 'display_name': None,
'display_description': 'lun1',
'volume_type_id': None}
volume_clone_large = {'name': 'cl_lg', 'size': 6, 'volume_name': 'lun1',
'os_type': 'linux', 'provider_location': 'cl_lg',
'id': 'lun1', 'provider_auth': None,
'project_id': 'project', 'display_name': None,
'display_description': 'lun1',
'volume_type_id': None}
connector = {'initiator': 'iqn.1993-08.org.debian:01:10'}
vol_fail = {'name': 'lun_fail', 'size': 10000, 'volume_name': 'lun1',
'os_type': 'linux', 'provider_location': 'lun1',
Expand Down Expand Up @@ -567,34 +595,12 @@ def test_map_unmap(self):
self.driver.terminate_connection(self.volume, self.connector)
self.driver.delete_volume(self.volume)

def test_fail_vol_from_snapshot_creation(self):
self.driver.create_volume(self.volume)
try:
self.driver.create_volume_from_snapshot(self.volume,
self.snapshot_fail)
raise AssertionError()
except exception.VolumeBackendAPIException:
pass
finally:
self.driver.delete_volume(self.volume)

def test_cloned_volume_destroy(self):
self.driver.create_volume(self.volume)
self.driver.create_cloned_volume(self.snapshot, self.volume)
self.driver.delete_volume(self.snapshot)
self.driver.delete_volume(self.volume)

def test_fail_cloned_volume_creation(self):
self.driver.create_volume(self.volume)
try:
self.driver.create_cloned_volume(self.volume_clone_fail,
self.volume)
raise AssertionError()
except exception.VolumeBackendAPIException:
pass
finally:
self.driver.delete_volume(self.volume)

def test_map_by_creating_igroup(self):
self.driver.create_volume(self.volume)
updates = self.driver.create_export(None, self.volume)
Expand All @@ -615,6 +621,22 @@ def test_fail_create_vol(self):
def test_vol_stats(self):
self.driver.get_volume_stats(refresh=True)

def test_create_vol_snapshot_diff_size_resize(self):
self.driver.create_volume(self.volume)
self.driver.create_snapshot(self.snapshot)
self.driver.create_volume_from_snapshot(
self.volume_clone, self.snapshot)
self.driver.delete_snapshot(self.snapshot)
self.driver.delete_volume(self.volume)

def test_create_vol_snapshot_diff_size_subclone(self):
self.driver.create_volume(self.volume)
self.driver.create_snapshot(self.snapshot)
self.driver.create_volume_from_snapshot(
self.volume_clone_large, self.snapshot)
self.driver.delete_snapshot(self.snapshot)
self.driver.delete_volume(self.volume)


class NetAppDriverNegativeTestCase(test.TestCase):
"""Test case for NetAppDriver"""
Expand Down Expand Up @@ -691,7 +713,7 @@ def do_POST(s):
<are-vols-busy>false</are-vols-busy>
<luns>
<lun-info>
<path>/vol/vol1/clone1</path>
<path>/vol/vol1/lun1</path>
<size>20971520</size>
<online>true</online>
<mapped>false</mapped>
Expand Down Expand Up @@ -997,6 +1019,28 @@ def do_POST(s):
body = """<results status="passed"/>"""
elif 'ems-autosupport-log' == api:
body = """<results status="passed"/>"""
elif 'lun-resize' == api:
body = """<results status="passed"/>"""
elif 'lun-get-geometry' == api:
body = """<results status="passed">
<size>1</size>
<bytes-per-sector>2</bytes-per-sector>
<sectors-per-track>8</sectors-per-track>
<tracks-per-cylinder>2</tracks-per-cylinder>
<cylinders>4</cylinders>
<max-resize-size>5</max-resize-size>
</results>"""
elif 'volume-options-list-info' == api:
body = """<results status="passed">
<options>
<option>
<name>compression</name>
<value>off</value>
</option>
</options>
</results>"""
elif 'lun-move' == api:
body = """<results status="passed"/>"""
else:
# Unknown API
s.send_response(500)
Expand Down
26 changes: 9 additions & 17 deletions cinder/tests/test_netapp_nfs.py
Expand Up @@ -51,6 +51,9 @@ def __init__(self, size=0):
def __getitem__(self, key):
return self.__dict__[key]

def __setitem__(self, key, val):
self.__dict__[key] = val


class FakeSnapshot(object):
def __init__(self, volume_size=0):
Expand Down Expand Up @@ -100,21 +103,20 @@ def test_create_volume_from_snapshot(self):
drv = self._driver
mox = self.mox
volume = FakeVolume(1)
snapshot = FakeSnapshot(2)

self.assertRaises(exception.CinderException,
drv.create_volume_from_snapshot,
volume,
snapshot)

snapshot = FakeSnapshot(1)

location = '127.0.0.1:/nfs'
expected_result = {'provider_location': location}
mox.StubOutWithMock(drv, '_clone_volume')
mox.StubOutWithMock(drv, '_get_volume_location')
mox.StubOutWithMock(drv, 'local_path')
mox.StubOutWithMock(drv, '_discover_file_till_timeout')
mox.StubOutWithMock(drv, '_set_rw_permissions_for_all')
drv._clone_volume(IgnoreArg(), IgnoreArg(), IgnoreArg())
drv._get_volume_location(IgnoreArg()).AndReturn(location)
drv.local_path(IgnoreArg()).AndReturn('/mnt')
drv._discover_file_till_timeout(IgnoreArg()).AndReturn(True)
drv._set_rw_permissions_for_all(IgnoreArg())

mox.ReplayAll()

Expand Down Expand Up @@ -163,16 +165,6 @@ def test_delete_missing_snapshot(self):

mox.VerifyAll()

def test_cloned_volume_size_fail(self):
volume_clone_fail = FakeVolume(1)
volume_src = FakeVolume(2)
try:
self._driver.create_cloned_volume(volume_clone_fail,
volume_src)
raise AssertionError()
except exception.CinderException:
pass

def _custom_setup(self):
kwargs = {}
kwargs['netapp_mode'] = 'proxy'
Expand Down
6 changes: 3 additions & 3 deletions cinder/volume/drivers/netapp/api.py
Expand Up @@ -125,10 +125,10 @@ def set_api_version(self, major, minor):
self._refresh_conn = True

def get_api_version(self):
"""Gets the api version."""
"""Gets the api version tuple."""
if hasattr(self, '_api_version'):
return self._api_version
return self._api_version
return (self._api_major_version, self._api_minor_version)
return None

def set_port(self, port):
"""Set the server communication port."""
Expand Down

0 comments on commit 204c3a3

Please sign in to comment.