Nexenta iSCSI driver: fixed volume_migration

Fixed volume_migration updating volume provider_location.
Fixed temporal snapshot deleting after volume migrated.

Change-Id: Id23749cb3724e1510865425232b38b9fc32690f8
Closes-Bug: #1263258
This commit is contained in:
Victor Rodionov 2013-12-23 13:24:41 -08:00
parent 8a5ce963dc
commit 65c635d6a5
3 changed files with 75 additions and 22 deletions

View File

@ -160,7 +160,9 @@ class TestNexentaISCSIDriver(test.TestCase):
'capabilities': {
'vendor_name': 'Nexenta',
'location_info': 'NexentaISCSIDriver:1.1.1.1:cinder',
'free_capacity_gb': 1
'free_capacity_gb': 1,
'iscsi_target_portal_port': 3260,
'nms_url': 'http://admin:password@1.1.1.1:2000'
}
}
snapshot = {
@ -174,19 +176,26 @@ class TestNexentaISCSIDriver(test.TestCase):
src = '%(volume)s/%(zvol)s@%(snapshot)s' % {
'volume': 'cinder',
'zvol': volume['name'],
'snapshot': snapshot['name']}
'snapshot': snapshot['name']
}
dst = '1.1.1.1:cinder'
cmd = ' '.join(['rrmgr -s zfs -c 1 -q -e -w 1024 -n 2', src, dst])
self.nms_mock.appliance.execute(cmd)
self.nms_mock.snapshot.destroy('cinder/%(volume)s@%(snapshot)s' % {
'volume': volume['name'],
'snapshot': snapshot['name']}, '')
snapshot_name = 'cinder/%(volume)s@%(snapshot)s' % {
'volume': volume['name'],
'snapshot': snapshot['name']
}
self.nms_mock.snapshot.destroy(snapshot_name, '')
volume_name = 'cinder/%s' % volume['name']
self.nms_mock.zvol.get_child_props(volume_name,
'origin').AndReturn(None)
self.nms_mock.zvol.destroy(volume_name, '')
self.nms_mock.snapshot.destroy('cinder/%(volume)s@%(snapshot)s' % {
'volume': volume['name'],
'snapshot': snapshot['name']
}, '')
self.mox.ReplayAll()
self.drv.migrate_volume(None, volume, host)

View File

@ -32,7 +32,7 @@ from cinder.volume.drivers.nexenta import jsonrpc
from cinder.volume.drivers.nexenta import options
from cinder.volume.drivers.nexenta import utils
VERSION = '1.1.3'
VERSION = '1.2.1'
LOG = logging.getLogger(__name__)
@ -48,6 +48,10 @@ class NexentaISCSIDriver(driver.ISCSIDriver): # pylint: disable=R0921
1.1.2 - Optimized create_cloned_volume, replaced zfs send recv with zfs
clone.
1.1.3 - Extended volume stats provided by _update_volume_stats method.
1.2.0 - Added volume migration with storage assist method.
1.2.1 - Fixed bug #1263258: now migrate_volume update provider_location
of migrated volume; after migrating volume migrate_volume
destroy snapshot on migration destination.
"""
VERSION = VERSION
@ -73,6 +77,8 @@ class NexentaISCSIDriver(driver.ISCSIDriver): # pylint: disable=R0921
self.rrmgr_compression = self.configuration.nexenta_rrmgr_compression
self.rrmgr_tcp_buf_size = self.configuration.nexenta_rrmgr_tcp_buf_size
self.rrmgr_connections = self.configuration.nexenta_rrmgr_connections
self.iscsi_target_portal_port = \
self.configuration.nexenta_iscsi_target_portal_port
@property
def backend_name(self):
@ -125,11 +131,6 @@ class NexentaISCSIDriver(driver.ISCSIDriver): # pylint: disable=R0921
name = snapshot.split('@')[-1]
return name.startswith('cinder-clone-snapshot-')
@staticmethod
def _get_migrate_snapshot_name(volume):
"""Return name for snapshot that will be used to migrate the volume."""
return 'cinder-migrate-snapshot-%(id)s' % volume
def create_volume(self, volume):
"""Create a zvol on appliance.
@ -215,6 +216,14 @@ class NexentaISCSIDriver(driver.ISCSIDriver): # pylint: disable=R0921
tcp_buf_size=self.rrmgr_tcp_buf_size,
connections=self.rrmgr_connections)
@staticmethod
def get_nms_for_url(url):
"""Returns initialized nms object for url."""
auto, scheme, user, password, host, port, path =\
utils.parse_nms_url(url)
return jsonrpc.NexentaJSONProxy(scheme, host, port, path, user,
password, auto=auto)
def migrate_volume(self, ctxt, volume, host):
"""Migrate if volume and host are managed by Nexenta appliance.
@ -230,14 +239,23 @@ class NexentaISCSIDriver(driver.ISCSIDriver): # pylint: disable=R0921
if volume['status'] != 'available':
return false_ret
if 'location_info' not in host['capabilities']:
if 'capabilities' not in host:
return false_ret
dst_parts = host['capabilities']['location_info'].split(':')
capabilities = host['capabilities']
if host['capabilities']['vendor_name'] != 'Nexenta' or \
dst_parts[0] != self.__class__.__name__ or \
host['capabilities']['free_capacity_gb'] < volume['size']:
if 'location_info' not in capabilities or \
'iscsi_target_portal_port' not in capabilities or \
'nms_url' not in capabilities:
return false_ret
iscsi_target_portal_port = capabilities['iscsi_target_portal_port']
nms_url = capabilities['nms_url']
dst_parts = capabilities['location_info'].split(':')
if capabilities.get('vendor_name') != 'Nexenta' or \
dst_parts[0] != self.__class__.__name__ or \
capabilities['free_capacity_gb'] < volume['size']:
return false_ret
dst_host, dst_volume = dst_parts[1:]
@ -248,19 +266,22 @@ class NexentaISCSIDriver(driver.ISCSIDriver): # pylint: disable=R0921
if bind.index(dst_host) != -1:
ssh_bound = True
break
if not(ssh_bound):
if not ssh_bound:
LOG.warning(_("Remote NexentaStor appliance at %s should be "
"SSH-bound."), dst_host)
# Create temporary snapshot of volume on NexentaStor Appliance.
snapshot = {'volume_name': volume['name'],
'name': self._get_migrate_snapshot_name(volume)}
snapshot = {
'volume_name': volume['name'],
'name': utils.get_migrate_snapshot_name(volume)
}
self.create_snapshot(snapshot)
src = '%(volume)s/%(zvol)s@%(snapshot)s' % {
'volume': self.volume,
'zvol': volume['name'],
'snapshot': snapshot['name']}
'snapshot': snapshot['name']
}
dst = ':'.join([dst_host, dst_volume])
try:
@ -284,7 +305,23 @@ class NexentaISCSIDriver(driver.ISCSIDriver): # pylint: disable=R0921
"NexentaStor Appliance: %(exc)s"),
{'volume': volume['name'], 'exc': exc})
return (True, None)
dst_nms = self.get_nms_for_url(nms_url)
dst_snapshot = '%s/%s@%s' % (dst_volume, volume['name'],
snapshot['name'])
try:
dst_nms.snapshot.destroy(dst_snapshot, '')
except nexenta.NexentaException as exc:
LOG.warning(_("Cannot delete temporary destination snapshot "
"%(dst)s on NexentaStor Appliance: %(exc)s"),
{'dst': dst_snapshot, 'exc': exc})
provider_location = '%(host)s:%(port)s,1 %(name)s 0' % {
'host': dst_host,
'port': iscsi_target_portal_port,
'name': self._get_target_name(volume['name'])
}
return True, {'provider_location': provider_location}
def create_snapshot(self, snapshot):
"""Create snapshot of existing zvol on appliance.
@ -560,5 +597,7 @@ class NexentaISCSIDriver(driver.ISCSIDriver): # pylint: disable=R0921
'reserved_percentage': 0,
'QoS_support': False,
'volume_backend_name': self.backend_name,
'location_info': location_info
'location_info': location_info,
'iscsi_target_portal_port': self.iscsi_target_portal_port,
'nms_url': self.nms.url
}

View File

@ -118,3 +118,8 @@ def parse_nms_url(url):
else:
host, port = host_and_port, '2000'
return auto, scheme, user, password, host, port, '/rest/nms/'
def get_migrate_snapshot_name(volume):
"""Return name for snapshot that will be used to migrate the volume."""
return 'cinder-migrate-snapshot-%(id)s' % volume