Dell SC driver honoring folder name after volume creation.
The Dell SC driver was not honoring the volume folder name after creation. This has been changed so that find_volume now checks the dell_sc_volume_folder for the requested volume before doing a general search of the storage center. In either case if more than one volume is returned (two in the dell_sc_volume_folder or two outside of that folder) then an exception is thrown. Also the dell_sc_volume_folder, dell_sc_server_folder and dell_sc_ssn variables are no longer being passed arond. They are saved as part of the backend API object. Tests have been updated. Change-Id: I962ea3ed262d21deff65cdc8476939aab6ba07e2 Closes-Bug: #1449290
This commit is contained in:
parent
e26120354f
commit
5a5b9ca3ed
|
@ -207,10 +207,20 @@ class DellSCSanFCDriverTestCase(test.TestCase):
|
|||
mock_init):
|
||||
volume = {'id': self.volume_name}
|
||||
connector = self.connector
|
||||
data = self.driver.initialize_connection(volume, connector)
|
||||
self.assertEqual(data['driver_volume_type'], 'fibre_channel')
|
||||
res = self.driver.initialize_connection(volume, connector)
|
||||
expected = {'data':
|
||||
{'initiator_target_map':
|
||||
{u'21000024FF30441C': [u'5000D31000FCBE35'],
|
||||
u'21000024FF30441D': [u'5000D31000FCBE3D']},
|
||||
'target_discovered': True,
|
||||
'target_lun': 1,
|
||||
'target_wwn':
|
||||
[u'5000D31000FCBE3D', u'5000D31000FCBE35']},
|
||||
'driver_volume_type': 'fibre_channel'}
|
||||
|
||||
self.assertEqual(expected, res, 'Unexpected return data')
|
||||
# verify find_volume has been called and that is has been called twice
|
||||
mock_find_volume.assert_any_call(64702, self.volume_name)
|
||||
mock_find_volume.assert_any_call(self.volume_name)
|
||||
assert mock_find_volume.call_count == 2
|
||||
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
|
@ -378,8 +388,11 @@ class DellSCSanFCDriverTestCase(test.TestCase):
|
|||
mock_init):
|
||||
volume = {'id': self.volume_name}
|
||||
connector = self.connector
|
||||
self.driver.terminate_connection(volume, connector)
|
||||
res = self.driver.terminate_connection(volume, connector)
|
||||
mock_unmap_volume.assert_called_once_with(self.VOLUME, self.SCSERVER)
|
||||
expected = {'driver_volume_type': 'fibre_channel',
|
||||
'data': {}}
|
||||
self.assertEqual(expected, res, 'Unexpected return data')
|
||||
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'find_sc',
|
||||
|
@ -499,7 +512,10 @@ class DellSCSanFCDriverTestCase(test.TestCase):
|
|||
# self.driver.terminate_connection,
|
||||
# volume,
|
||||
# connector)
|
||||
self.driver.terminate_connection(volume, connector)
|
||||
res = self.driver.terminate_connection(volume, connector)
|
||||
expected = {'driver_volume_type': 'fibre_channel',
|
||||
'data': {}}
|
||||
self.assertEqual(expected, res, 'Unexpected return data')
|
||||
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'find_sc',
|
||||
|
@ -542,6 +558,54 @@ class DellSCSanFCDriverTestCase(test.TestCase):
|
|||
volume,
|
||||
connector)
|
||||
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'find_sc',
|
||||
return_value=64702)
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'find_server',
|
||||
return_value=SCSERVER)
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'find_volume',
|
||||
return_value=VOLUME)
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'unmap_volume',
|
||||
return_value=True)
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'find_wwns',
|
||||
return_value=(1,
|
||||
[u'5000D31000FCBE3D',
|
||||
u'5000D31000FCBE35'],
|
||||
{u'21000024FF30441C':
|
||||
[u'5000D31000FCBE35'],
|
||||
u'21000024FF30441D':
|
||||
[u'5000D31000FCBE3D']}))
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'get_volume_count',
|
||||
return_value=0)
|
||||
def test_terminate_connection_vol_count_zero(self,
|
||||
mock_get_volume_count,
|
||||
mock_find_wwns,
|
||||
mock_unmap_volume,
|
||||
mock_find_volume,
|
||||
mock_find_server,
|
||||
mock_find_sc,
|
||||
mock_close_connection,
|
||||
mock_open_connection,
|
||||
mock_init):
|
||||
# Test case where get_volume_count is zero
|
||||
volume = {'id': self.volume_name}
|
||||
connector = self.connector
|
||||
res = self.driver.terminate_connection(volume, connector)
|
||||
mock_unmap_volume.assert_called_once_with(self.VOLUME, self.SCSERVER)
|
||||
expected = {'data':
|
||||
{'initiator_target_map':
|
||||
{u'21000024FF30441C': [u'5000D31000FCBE35'],
|
||||
u'21000024FF30441D': [u'5000D31000FCBE3D']},
|
||||
'target_wwn':
|
||||
[u'5000D31000FCBE3D', u'5000D31000FCBE35']},
|
||||
'driver_volume_type': 'fibre_channel'}
|
||||
self.assertEqual(expected, res, 'Unexpected return data')
|
||||
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'find_sc',
|
||||
return_value=64702)
|
||||
|
|
|
@ -273,9 +273,7 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
|
|||
volume = {'id': self.volume_name, 'size': 1}
|
||||
self.driver.create_volume(volume)
|
||||
mock_create_volume.assert_called_once_with(self.volume_name,
|
||||
1,
|
||||
12345,
|
||||
u'opnstktst')
|
||||
1)
|
||||
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'create_volume',
|
||||
|
@ -307,7 +305,7 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
|
|||
mock_init):
|
||||
volume = {'id': self.volume_name, 'size': 1}
|
||||
self.driver.delete_volume(volume)
|
||||
mock_delete_volume.assert_called_once_with(12345, self.volume_name)
|
||||
mock_delete_volume.assert_called_once_with(self.volume_name)
|
||||
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'delete_volume',
|
||||
|
@ -359,7 +357,7 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
|
|||
data = self.driver.initialize_connection(volume, connector)
|
||||
self.assertEqual(data['driver_volume_type'], 'iscsi')
|
||||
# verify find_volume has been called and that is has been called twice
|
||||
mock_find_volume.assert_any_call(12345, self.volume_name)
|
||||
mock_find_volume.assert_any_call(self.volume_name)
|
||||
assert mock_find_volume.call_count == 2
|
||||
expected = {'data':
|
||||
{'access_mode': 'rw',
|
||||
|
@ -406,7 +404,7 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
|
|||
data = self.driver.initialize_connection(volume, connector)
|
||||
self.assertEqual(data['driver_volume_type'], 'iscsi')
|
||||
# verify find_volume has been called and that is has been called twice
|
||||
mock_find_volume.assert_any_call(12345, self.volume_name)
|
||||
mock_find_volume.assert_any_call(self.volume_name)
|
||||
assert mock_find_volume.call_count == 2
|
||||
expected = {'data':
|
||||
{'access_mode': 'rw',
|
||||
|
@ -573,8 +571,9 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
|
|||
mock_init):
|
||||
volume = {'id': self.volume_name}
|
||||
connector = self.connector
|
||||
self.driver.terminate_connection(volume, connector)
|
||||
res = self.driver.terminate_connection(volume, connector)
|
||||
mock_unmap_volume.assert_called_once_with(self.VOLUME, self.SCSERVER)
|
||||
self.assertIsNone(res, 'None expected')
|
||||
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'find_sc',
|
||||
|
@ -823,7 +822,6 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
|
|||
self.driver.create_cloned_volume(volume, src_vref)
|
||||
mock_create_cloned_volume. \
|
||||
assert_called_once_with(self.volume_name + '_clone',
|
||||
self.configuration.dell_sc_volume_folder,
|
||||
self.VOLUME)
|
||||
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
|
@ -912,7 +910,7 @@ class DellSCSanISCSIDriverTestCase(test.TestCase):
|
|||
volume = {'id': self.VOLUME.get(u'name')}
|
||||
self.driver.ensure_export(context, volume)
|
||||
mock_find_volume.assert_called_once_with(
|
||||
12345, self.VOLUME.get(u'name'))
|
||||
self.VOLUME.get(u'name'))
|
||||
|
||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||
'find_sc',
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -122,12 +122,27 @@ class StorageCenterApiHelper(object):
|
|||
self.config = config
|
||||
|
||||
def open_connection(self):
|
||||
'''Open connection to Enterprise Manager.'''
|
||||
connection = StorageCenterApi(self.config.san_ip,
|
||||
self.config.dell_sc_api_port,
|
||||
self.config.san_login,
|
||||
self.config.san_password)
|
||||
connection.open_connection()
|
||||
connection = None
|
||||
ssn = self.config.dell_sc_ssn
|
||||
LOG.info(_LI('open_connection to %(s)s at %(ip)s'),
|
||||
{'s': ssn,
|
||||
'ip': self.config.san_ip})
|
||||
if ssn:
|
||||
'''Open connection to Enterprise Manager.'''
|
||||
connection = StorageCenterApi(self.config.san_ip,
|
||||
self.config.dell_sc_api_port,
|
||||
self.config.san_login,
|
||||
self.config.san_password)
|
||||
# This instance is for a single backend. That backend has a
|
||||
# few items of information we should save rather than passing them
|
||||
# about.
|
||||
connection.ssn = ssn
|
||||
connection.vfname = self.config.dell_sc_volume_folder
|
||||
connection.sfname = self.config.dell_sc_server_folder
|
||||
connection.open_connection()
|
||||
else:
|
||||
raise exception.VolumeBackendAPIException('Configuration error. '
|
||||
'dell_sc_ssn not set.')
|
||||
return connection
|
||||
|
||||
|
||||
|
@ -142,6 +157,9 @@ class StorageCenterApi(object):
|
|||
|
||||
def __init__(self, host, port, user, password):
|
||||
self.notes = 'Created by Dell Cinder Driver'
|
||||
self.ssn = None
|
||||
self.vfname = 'openstack'
|
||||
self.sfname = 'openstack'
|
||||
self.client = HttpClient(host,
|
||||
port,
|
||||
user,
|
||||
|
@ -228,32 +246,32 @@ class StorageCenterApi(object):
|
|||
'r': r.reason})
|
||||
self.client = None
|
||||
|
||||
def find_sc(self, ssn):
|
||||
'''This is really just a check that the sc is there and being managed by
|
||||
EM.
|
||||
def find_sc(self):
|
||||
'''This is really just a check that the sc is there and being managed
|
||||
by EM.
|
||||
'''
|
||||
r = self.client.get('StorageCenter/StorageCenter')
|
||||
result = self._get_result(r,
|
||||
'scSerialNumber',
|
||||
ssn)
|
||||
self.ssn)
|
||||
if result is None:
|
||||
LOG.error(_LE('Failed to find %(s)s. Result %(r)s'),
|
||||
{'s': ssn,
|
||||
{'s': self.ssn,
|
||||
'r': r})
|
||||
raise exception.VolumeBackendAPIException(
|
||||
_('Failed to find Storage Center'))
|
||||
|
||||
return self._get_id(result)
|
||||
|
||||
# Volume functions
|
||||
# Folder functions
|
||||
|
||||
def _create_folder(self, url, ssn, parent, folder):
|
||||
def _create_folder(self, url, parent, folder):
|
||||
'''This is generic to server and volume folders.
|
||||
'''
|
||||
f = None
|
||||
payload = {}
|
||||
payload['Name'] = folder
|
||||
payload['StorageCenter'] = ssn
|
||||
payload['StorageCenter'] = self.ssn
|
||||
if parent != '':
|
||||
payload['Parent'] = parent
|
||||
payload['Notes'] = self.notes
|
||||
|
@ -269,7 +287,7 @@ class StorageCenterApi(object):
|
|||
f = self._first_result(r)
|
||||
return f
|
||||
|
||||
def _create_folder_path(self, url, ssn, foldername):
|
||||
def _create_folder_path(self, url, foldername):
|
||||
'''This is generic to server and volume folders.
|
||||
'''
|
||||
path = self._path_to_array(foldername)
|
||||
|
@ -284,14 +302,12 @@ class StorageCenterApi(object):
|
|||
if found:
|
||||
listurl = url + '/GetList'
|
||||
f = self._find_folder(listurl,
|
||||
ssn,
|
||||
folderpath)
|
||||
if f is None:
|
||||
found = False
|
||||
# We didn't find it so create it
|
||||
if found is False:
|
||||
f = self._create_folder(url,
|
||||
ssn,
|
||||
instanceId,
|
||||
folder)
|
||||
# If we haven't found a folder or created it then leave
|
||||
|
@ -304,7 +320,7 @@ class StorageCenterApi(object):
|
|||
folderpath = folderpath + '/'
|
||||
return f
|
||||
|
||||
def _find_folder(self, url, ssn, foldername):
|
||||
def _find_folder(self, url, foldername):
|
||||
'''Most of the time the folder will already have been created so
|
||||
we look for the end folder and check that the rest of the path is
|
||||
right.
|
||||
|
@ -312,13 +328,13 @@ class StorageCenterApi(object):
|
|||
This is generic to server and volume folders.
|
||||
'''
|
||||
pf = PayloadFilter()
|
||||
pf.append('scSerialNumber', ssn)
|
||||
pf.append('scSerialNumber', self.ssn)
|
||||
basename = os.path.basename(foldername)
|
||||
pf.append('Name', basename)
|
||||
# If we have any kind of path we add '/' to match the storage
|
||||
# center's convention and throw it into the filters.
|
||||
# If we have any kind of path we throw it into the filters.
|
||||
folderpath = os.path.dirname(foldername)
|
||||
if folderpath != '':
|
||||
# SC convention is to end with a '/' so make sure we do.
|
||||
folderpath += '/'
|
||||
pf.append('folderPath', folderpath)
|
||||
folder = None
|
||||
|
@ -335,15 +351,14 @@ class StorageCenterApi(object):
|
|||
'r': r.reason})
|
||||
return folder
|
||||
|
||||
def _create_volume_folder_path(self, ssn, foldername):
|
||||
return self._create_folder_path('StorageCenter/ScVolumeFolder',
|
||||
ssn,
|
||||
foldername)
|
||||
|
||||
def _find_volume_folder(self, ssn, foldername):
|
||||
return self._find_folder('StorageCenter/ScVolumeFolder/GetList',
|
||||
ssn,
|
||||
foldername)
|
||||
def _find_volume_folder(self, create=False):
|
||||
folder = self._find_folder('StorageCenter/ScVolumeFolder/GetList',
|
||||
self.vfname)
|
||||
# Doesn't exist? make it
|
||||
if folder is None and create is True:
|
||||
folder = self._create_folder_path('StorageCenter/ScVolumeFolder',
|
||||
self.vfname)
|
||||
return folder
|
||||
|
||||
def _init_volume(self, scvolume):
|
||||
'''Maps the volume to a random server and immediately unmaps
|
||||
|
@ -370,37 +385,34 @@ class StorageCenterApi(object):
|
|||
scserver)
|
||||
break
|
||||
|
||||
def create_volume(self, name, size, ssn, volfolder):
|
||||
def create_volume(self, name, size):
|
||||
'''This creates a new volume on the storage center. It
|
||||
will create it in volfolder. If volfolder does not
|
||||
exist it will create it. If it cannot create volfolder
|
||||
will create it in a folder called self.vfname. If self.vfname
|
||||
does not exist it will create it. If it cannot create it
|
||||
the volume will be created in the root.
|
||||
'''
|
||||
scvolume = None
|
||||
# Find our folder
|
||||
LOG.debug('Create Volume %(name)s %(ssn)s %(folder)s',
|
||||
{'name': name,
|
||||
'ssn': ssn,
|
||||
'folder': volfolder})
|
||||
folder = self._find_volume_folder(ssn,
|
||||
volfolder)
|
||||
'ssn': self.ssn,
|
||||
'folder': self.vfname})
|
||||
|
||||
# Doesn't exist? make it
|
||||
if folder is None:
|
||||
folder = self._create_volume_folder_path(ssn,
|
||||
volfolder)
|
||||
# Find our folder
|
||||
folder = self._find_volume_folder(True)
|
||||
|
||||
# If we actually have a place to put our volume create it
|
||||
if folder is None:
|
||||
LOG.error(_LE('Unable to create folder %s'),
|
||||
volfolder)
|
||||
LOG.warning(_LW('Unable to create folder %s'),
|
||||
self.vfname)
|
||||
|
||||
# Init our return.
|
||||
scvolume = None
|
||||
|
||||
# Create the volume
|
||||
payload = {}
|
||||
payload['Name'] = name
|
||||
payload['Notes'] = self.notes
|
||||
payload['Size'] = '%d GB' % size
|
||||
payload['StorageCenter'] = ssn
|
||||
payload['StorageCenter'] = self.ssn
|
||||
if folder is not None:
|
||||
payload['VolumeFolder'] = self._get_id(folder)
|
||||
r = self.client.post('StorageCenter/ScVolume',
|
||||
|
@ -412,6 +424,7 @@ class StorageCenterApi(object):
|
|||
{'name': name,
|
||||
'c': r.status_code,
|
||||
'r': r.reason})
|
||||
return None
|
||||
if scvolume:
|
||||
LOG.info(_LI('Created volume %(instanceId)s: %(name)s'),
|
||||
{'instanceId': scvolume['instanceId'],
|
||||
|
@ -421,46 +434,84 @@ class StorageCenterApi(object):
|
|||
' Attempting to locate volume'))
|
||||
# In theory it is there since success was returned.
|
||||
# Try one last time to find it before returning.
|
||||
scvolume = self.find_volume(ssn, name, None)
|
||||
scvolume = self.find_volume(name)
|
||||
|
||||
return scvolume
|
||||
|
||||
def find_volume(self, ssn, name=None, instanceid=None):
|
||||
'''search ssn for volume of name and/or instance id
|
||||
def _get_volume_list(self, name, filterbyvfname=True):
|
||||
'''Return the list of volumes with name of name.
|
||||
:param name: Volume name.
|
||||
:param filterbyvfname: If true filters by the preset folder name.
|
||||
:return: Returns the scvolume or None.
|
||||
'''
|
||||
LOG.debug('finding volume %(sn)s : %(name)s : %(id)s',
|
||||
{'sn': ssn,
|
||||
'name': name,
|
||||
'id': instanceid})
|
||||
result = None
|
||||
pf = PayloadFilter()
|
||||
pf.append('scSerialNumber', ssn)
|
||||
# We need at least a name and or an instance id. If we have
|
||||
# that we can find a volume.
|
||||
if instanceid is not None:
|
||||
pf.append('instanceId', instanceid)
|
||||
elif name is not None:
|
||||
pf.append('scSerialNumber', self.ssn)
|
||||
# We need a name to find a volume.
|
||||
if name is not None:
|
||||
pf.append('Name', name)
|
||||
else:
|
||||
return None
|
||||
# set folderPath
|
||||
if filterbyvfname:
|
||||
vfname = (self.vfname if self.vfname.endswith('/')
|
||||
else self.vfname + '/')
|
||||
pf.append('volumeFolderPath', vfname)
|
||||
r = self.client.post('StorageCenter/ScVolume/GetList',
|
||||
pf.payload)
|
||||
if r.status_code != 200:
|
||||
LOG.debug('ScVolume GetList error %(i)s: %(c)d %(r)s',
|
||||
{'i': instanceid,
|
||||
LOG.debug('ScVolume GetList error %(n)s: %(c)d %(r)s',
|
||||
{'n': name,
|
||||
'c': r.status_code,
|
||||
'r': r.reason})
|
||||
return self._first_result(r)
|
||||
else:
|
||||
result = self._get_json(r)
|
||||
# We return None if there was an error and a list if the command
|
||||
# succeeded. It might be an empty list.
|
||||
return result
|
||||
|
||||
def delete_volume(self, ssn, name):
|
||||
# find our volume
|
||||
vol = self.find_volume(ssn, name, None)
|
||||
def find_volume(self, name):
|
||||
'''Search self.ssn for volume of name.
|
||||
'''
|
||||
LOG.debug('Searching %(sn)s for %(name)s',
|
||||
{'sn': self.ssn,
|
||||
'name': name})
|
||||
|
||||
# Cannot find a volume without the name
|
||||
if name is None:
|
||||
return None
|
||||
|
||||
# Look for our volume in our folder.
|
||||
vollist = self._get_volume_list(name,
|
||||
True)
|
||||
# If an empty list was returned they probably moved the volumes or
|
||||
# changed the folder name so try again without the folder.
|
||||
if not vollist:
|
||||
LOG.debug('Cannot find volume %(n)s in %(v)s. Searching SC.',
|
||||
{'n': name,
|
||||
'v': self.vfname})
|
||||
vollist = self._get_volume_list(name,
|
||||
False)
|
||||
|
||||
# If multiple volumes of the same name are found we need to error.
|
||||
if len(vollist) > 1:
|
||||
# blow up
|
||||
raise exception.VolumeBackendAPIException(
|
||||
_('Multiple copies of volume %s found.') % name)
|
||||
|
||||
# We made it and should have a valid volume.
|
||||
return None if not vollist else vollist[0]
|
||||
|
||||
def delete_volume(self, name):
|
||||
# Delete our volume.
|
||||
vol = self.find_volume(name)
|
||||
if vol is not None:
|
||||
r = self.client.delete('StorageCenter/ScVolume/%s'
|
||||
% self._get_id(vol))
|
||||
if r.status_code != 200:
|
||||
raise exception.VolumeBackendAPIException(
|
||||
_('Error deleting volume %(ssn)s: %(sn)s: %(c)d %(r)s') %
|
||||
{'ssn': ssn,
|
||||
{'ssn': self.ssn,
|
||||
'sn': name,
|
||||
'c': r.status_code,
|
||||
'r': r.reason})
|
||||
|
@ -471,15 +522,13 @@ class StorageCenterApi(object):
|
|||
# If we can't find the volume then it is effectively gone.
|
||||
return True
|
||||
|
||||
def _create_server_folder_path(self, ssn, foldername):
|
||||
return self._create_folder_path('StorageCenter/ScServerFolder',
|
||||
ssn,
|
||||
foldername)
|
||||
|
||||
def _find_server_folder(self, ssn, foldername):
|
||||
return self._find_folder('StorageCenter/ScServerFolder/GetList',
|
||||
ssn,
|
||||
foldername)
|
||||
def _find_server_folder(self, create=False):
|
||||
folder = self._find_folder('StorageCenter/ScServerFolder/GetList',
|
||||
self.sfname)
|
||||
if folder is None and create is True:
|
||||
folder = self._create_folder_path('StorageCenter/ScServerFolder',
|
||||
self.sfname)
|
||||
return folder
|
||||
|
||||
def _add_hba(self, scserver, wwnoriscsiname, isfc=False):
|
||||
'''Adds an HBA to the scserver. The HBA will be added
|
||||
|
@ -506,12 +555,12 @@ class StorageCenterApi(object):
|
|||
|
||||
# We do not know that we are red hat linux 6.x but that works
|
||||
# best for red hat and ubuntu. So, there.
|
||||
def _find_serveros(self, ssn, osname='Red Hat Linux 6.x'):
|
||||
def _find_serveros(self, osname='Red Hat Linux 6.x'):
|
||||
'''Returns the serveros instance id of the specified osname.
|
||||
Required to create a server.
|
||||
'''
|
||||
pf = PayloadFilter()
|
||||
pf.append('scSerialNumber', ssn)
|
||||
pf.append('scSerialNumber', self.ssn)
|
||||
r = self.client.post('StorageCenter/ScServerOperatingSystem/GetList',
|
||||
pf.payload)
|
||||
if r.status_code == 200:
|
||||
|
@ -527,7 +576,7 @@ class StorageCenterApi(object):
|
|||
'r': r.reason})
|
||||
return None
|
||||
|
||||
def create_server_multiple_hbas(self, ssn, foldername, wwns):
|
||||
def create_server_multiple_hbas(self, wwns):
|
||||
'''Same as create_server except it can take a list of hbas. hbas
|
||||
can be wwns or iqns.
|
||||
'''
|
||||
|
@ -537,9 +586,7 @@ class StorageCenterApi(object):
|
|||
for wwn in wwns:
|
||||
if scserver is None:
|
||||
# Use the fist wwn to create the server.
|
||||
scserver = self.create_server(ssn,
|
||||
foldername,
|
||||
wwn,
|
||||
scserver = self.create_server(wwn,
|
||||
True)
|
||||
else:
|
||||
# Add the wwn to our server
|
||||
|
@ -548,27 +595,23 @@ class StorageCenterApi(object):
|
|||
True)
|
||||
return scserver
|
||||
|
||||
def create_server(self, ssn, foldername, wwnoriscsiname, isfc=False):
|
||||
'''creates a server on the the storage center ssn. Adds the first
|
||||
def create_server(self, wwnoriscsiname, isfc=False):
|
||||
'''creates a server on the the storage center self.ssn. Adds the first
|
||||
HBA to it.
|
||||
'''
|
||||
scserver = None
|
||||
payload = {}
|
||||
payload['Name'] = 'Server_' + wwnoriscsiname
|
||||
payload['StorageCenter'] = ssn
|
||||
payload['StorageCenter'] = self.ssn
|
||||
payload['Notes'] = self.notes
|
||||
# We pick Red Hat Linux 6.x because it supports multipath and
|
||||
# will attach luns to paths as they are found.
|
||||
scserveros = self._find_serveros(ssn, 'Red Hat Linux 6.x')
|
||||
scserveros = self._find_serveros('Red Hat Linux 6.x')
|
||||
if scserveros is not None:
|
||||
payload['OperatingSystem'] = scserveros
|
||||
|
||||
# Find our folder or make it
|
||||
folder = self._find_server_folder(ssn,
|
||||
foldername)
|
||||
if folder is None:
|
||||
folder = self._create_server_folder_path(ssn,
|
||||
foldername)
|
||||
folder = self._find_server_folder(True)
|
||||
|
||||
# At this point it doesn't matter if the folder was created or not.
|
||||
# We just attempt to create the server. Let it be in the root if
|
||||
|
@ -600,7 +643,7 @@ class StorageCenterApi(object):
|
|||
# Success or failure is determined by the caller
|
||||
return scserver
|
||||
|
||||
def find_server(self, ssn, instance_name):
|
||||
def find_server(self, instance_name):
|
||||
'''Hunts for a server by looking for an HBA with the server's IQN
|
||||
or wwn.
|
||||
|
||||
|
@ -608,13 +651,13 @@ class StorageCenterApi(object):
|
|||
'''
|
||||
scserver = None
|
||||
# We search for our server by first finding our HBA
|
||||
hba = self._find_serverhba(ssn, instance_name)
|
||||
hba = self._find_serverhba(instance_name)
|
||||
# Once created hbas stay in the system. So it isn't enough
|
||||
# that we found one it actually has to be attached to a
|
||||
# server.
|
||||
if hba is not None and hba.get('server') is not None:
|
||||
pf = PayloadFilter()
|
||||
pf.append('scSerialNumber', ssn)
|
||||
pf.append('scSerialNumber', self.ssn)
|
||||
pf.append('instanceId', self._get_id(hba['server']))
|
||||
r = self.client.post('StorageCenter/ScServer/GetList',
|
||||
pf.payload)
|
||||
|
@ -629,7 +672,7 @@ class StorageCenterApi(object):
|
|||
instance_name)
|
||||
return scserver
|
||||
|
||||
def _find_serverhba(self, ssn, instance_name):
|
||||
def _find_serverhba(self, instance_name):
|
||||
'''Hunts for a sc server HBA by looking for an HBA with the
|
||||
server's IQN or wwn.
|
||||
|
||||
|
@ -638,7 +681,7 @@ class StorageCenterApi(object):
|
|||
scserverhba = None
|
||||
# We search for our server by first finding our HBA
|
||||
pf = PayloadFilter()
|
||||
pf.append('scSerialNumber', ssn)
|
||||
pf.append('scSerialNumber', self.ssn)
|
||||
pf.append('instanceName', instance_name)
|
||||
r = self.client.post('StorageCenter/ScServerHba/GetList',
|
||||
pf.payload)
|
||||
|
@ -984,12 +1027,12 @@ class StorageCenterApi(object):
|
|||
rtn = False
|
||||
return rtn
|
||||
|
||||
def get_storage_usage(self, ssn):
|
||||
def get_storage_usage(self):
|
||||
'''get_storage_usage'''
|
||||
storageusage = None
|
||||
if ssn is not None:
|
||||
if self.ssn is not None:
|
||||
r = self.client.get('StorageCenter/StorageCenter/%s/StorageUsage'
|
||||
% ssn)
|
||||
% self.ssn)
|
||||
if r.status_code == 200:
|
||||
storageusage = self._get_json(r)
|
||||
else:
|
||||
|
@ -1085,21 +1128,12 @@ class StorageCenterApi(object):
|
|||
# We either couldn't find it or expired it.
|
||||
return True
|
||||
|
||||
def create_view_volume(self, volname, volfolder, screplay):
|
||||
def create_view_volume(self, volname, screplay):
|
||||
'''create_view_volume
|
||||
|
||||
creates a new volume named volname in the folder
|
||||
volfolder from the screplay.
|
||||
creates a new volume named volname from the screplay.
|
||||
'''
|
||||
# find our ssn and get our folder
|
||||
ssn = screplay.get('scSerialNumber')
|
||||
folder = self._find_volume_folder(ssn,
|
||||
volfolder)
|
||||
|
||||
# Doesn't exist? make it
|
||||
if folder is None:
|
||||
folder = self._create_volume_folder_path(ssn,
|
||||
volfolder)
|
||||
folder = self._find_volume_folder(True)
|
||||
|
||||
# payload is just the volume name and folder if we have one.
|
||||
payload = {}
|
||||
|
@ -1124,7 +1158,7 @@ class StorageCenterApi(object):
|
|||
|
||||
return volume
|
||||
|
||||
def create_cloned_volume(self, volumename, volumefolder, scvolume):
|
||||
def create_cloned_volume(self, volumename, scvolume):
|
||||
'''create_cloned_volume
|
||||
|
||||
creates a temporary replay and then creates a
|
||||
|
@ -1136,7 +1170,6 @@ class StorageCenterApi(object):
|
|||
60)
|
||||
if replay is not None:
|
||||
clone = self.create_view_volume(volumename,
|
||||
volumefolder,
|
||||
replay)
|
||||
else:
|
||||
LOG.error(_LE('Error: unable to snap replay'))
|
||||
|
|
|
@ -81,30 +81,23 @@ class DellCommonDriver(san.SanDriver):
|
|||
def check_for_setup_error(self):
|
||||
'''Validates the configuration information.'''
|
||||
with self._client.open_connection() as api:
|
||||
ssn = self.configuration.safe_get('dell_sc_ssn')
|
||||
api.find_sc(ssn)
|
||||
api.find_sc()
|
||||
|
||||
def create_volume(self, volume):
|
||||
'''Create a volume.'''
|
||||
|
||||
# We use id as our name as it is unique.
|
||||
volume_name = volume.get('id')
|
||||
volume_size = volume.get('size')
|
||||
LOG.debug('Creating volume %(name)s of size %(size)s',
|
||||
{'name': volume_name, 'size': volume_size})
|
||||
LOG.debug('Creating volume %(n)s of size %(s)s',
|
||||
{'n': volume_name,
|
||||
's': volume_size})
|
||||
scvolume = None
|
||||
with self._client.open_connection() as api:
|
||||
try:
|
||||
# we use id as our name as it s unique
|
||||
volume_folder = self.configuration.dell_sc_volume_folder
|
||||
ssn = api.find_sc(self.configuration.dell_sc_ssn)
|
||||
LOG.debug('create_volume: %(name)s on %(ssn)s in %(vf)s',
|
||||
{'name': volume_name,
|
||||
'ssn': ssn,
|
||||
'vf': volume_folder})
|
||||
if ssn is not None:
|
||||
if api.find_sc():
|
||||
scvolume = api.create_volume(volume_name,
|
||||
volume_size,
|
||||
ssn,
|
||||
volume_folder)
|
||||
volume_size)
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error(_LE('Failed to create volume %s'),
|
||||
|
@ -120,10 +113,8 @@ class DellCommonDriver(san.SanDriver):
|
|||
LOG.debug('Deleting volume %s', volume_name)
|
||||
with self._client.open_connection() as api:
|
||||
try:
|
||||
ssn = api.find_sc(self.configuration.dell_sc_ssn)
|
||||
if ssn is not None:
|
||||
deleted = api.delete_volume(ssn,
|
||||
volume_name)
|
||||
if api.find_sc():
|
||||
deleted = api.delete_volume(volume_name)
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error(_LE('Failed to delete volume %s'),
|
||||
|
@ -141,12 +132,11 @@ class DellCommonDriver(san.SanDriver):
|
|||
volume_name = snapshot.get('volume_id')
|
||||
snapshot_id = snapshot.get('id')
|
||||
LOG.debug('Creating snapshot %(snap)s on volume %(vol)s',
|
||||
{'snap': snapshot_id, 'vol': volume_name})
|
||||
{'snap': snapshot_id,
|
||||
'vol': volume_name})
|
||||
with self._client.open_connection() as api:
|
||||
ssn = api.find_sc(self.configuration.dell_sc_ssn)
|
||||
if ssn is not None:
|
||||
scvolume = api.find_volume(ssn,
|
||||
volume_name)
|
||||
if api.find_sc():
|
||||
scvolume = api.find_volume(volume_name)
|
||||
if scvolume is not None:
|
||||
if api.create_replay(scvolume,
|
||||
snapshot_id,
|
||||
|
@ -176,18 +166,15 @@ class DellCommonDriver(san.SanDriver):
|
|||
'src': src_volume_name})
|
||||
with self._client.open_connection() as api:
|
||||
try:
|
||||
volume_folder = self.configuration.dell_sc_volume_folder
|
||||
ssn = api.find_sc(self.configuration.dell_sc_ssn)
|
||||
srcvol = api.find_volume(ssn,
|
||||
src_volume_name)
|
||||
if srcvol is not None:
|
||||
replay = api.find_replay(srcvol,
|
||||
snapshot_id)
|
||||
if replay is not None:
|
||||
volume_name = volume.get('id')
|
||||
scvolume = api.create_view_volume(volume_name,
|
||||
volume_folder,
|
||||
replay)
|
||||
if api.find_sc():
|
||||
srcvol = api.find_volume(src_volume_name)
|
||||
if srcvol is not None:
|
||||
replay = api.find_replay(srcvol,
|
||||
snapshot_id)
|
||||
if replay is not None:
|
||||
volume_name = volume.get('id')
|
||||
scvolume = api.create_view_volume(volume_name,
|
||||
replay)
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error(_LE('Failed to create volume %s'),
|
||||
|
@ -210,14 +197,11 @@ class DellCommonDriver(san.SanDriver):
|
|||
'vol': src_volume_name})
|
||||
with self._client.open_connection() as api:
|
||||
try:
|
||||
volume_folder = self.configuration.dell_sc_volume_folder
|
||||
ssn = api.find_sc(self.configuration.dell_sc_ssn)
|
||||
srcvol = api.find_volume(ssn,
|
||||
src_volume_name)
|
||||
if srcvol is not None:
|
||||
scvolume = api.create_cloned_volume(volume_name,
|
||||
volume_folder,
|
||||
srcvol)
|
||||
if api.find_sc():
|
||||
srcvol = api.find_volume(src_volume_name)
|
||||
if srcvol is not None:
|
||||
scvolume = api.create_cloned_volume(volume_name,
|
||||
srcvol)
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error(_LE('Failed to create volume %s'),
|
||||
|
@ -238,10 +222,8 @@ class DellCommonDriver(san.SanDriver):
|
|||
{'snap': snapshot_id,
|
||||
'vol': volume_name})
|
||||
with self._client.open_connection() as api:
|
||||
ssn = api.find_sc(self.configuration.dell_sc_ssn)
|
||||
if ssn is not None:
|
||||
scvolume = api.find_volume(ssn,
|
||||
volume_name)
|
||||
if api.find_sc():
|
||||
scvolume = api.find_volume(volume_name)
|
||||
if scvolume is not None:
|
||||
if api.delete_replay(scvolume,
|
||||
snapshot_id):
|
||||
|
@ -270,10 +252,8 @@ class DellCommonDriver(san.SanDriver):
|
|||
LOG.debug('Checking existence of volume %s', volume_name)
|
||||
with self._client.open_connection() as api:
|
||||
try:
|
||||
ssn = api.find_sc(self.configuration.dell_sc_ssn)
|
||||
if ssn is not None:
|
||||
scvolume = api.find_volume(ssn,
|
||||
volume_name)
|
||||
if api.find_sc():
|
||||
scvolume = api.find_volume(volume_name)
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error(_LE('Failed to ensure export of volume %s'),
|
||||
|
@ -297,10 +277,8 @@ class DellCommonDriver(san.SanDriver):
|
|||
{'vol': volume_name, 'size': new_size})
|
||||
if volume is not None:
|
||||
with self._client.open_connection() as api:
|
||||
ssn = api.find_sc(self.configuration.dell_sc_ssn)
|
||||
if ssn is not None:
|
||||
scvolume = api.find_volume(ssn,
|
||||
volume_name)
|
||||
if api.find_sc():
|
||||
scvolume = api.find_volume(volume_name)
|
||||
if api.expand_volume(scvolume, new_size) is not None:
|
||||
return
|
||||
# If we are here nothing good happened.
|
||||
|
@ -320,8 +298,7 @@ class DellCommonDriver(san.SanDriver):
|
|||
def _update_volume_stats(self):
|
||||
'''Retrieve stats info from volume group.'''
|
||||
with self._client.open_connection() as api:
|
||||
ssn = api.find_sc(self.configuration.dell_sc_ssn)
|
||||
storageusage = api.get_storage_usage(ssn)
|
||||
storageusage = api.get_storage_usage() if api.find_sc() else None
|
||||
|
||||
# all of this is basically static for now
|
||||
data = {}
|
||||
|
|
|
@ -60,32 +60,25 @@ class DellStorageCenterFCDriver(dell_storagecenter_common.DellCommonDriver,
|
|||
LOG.debug('Initialize connection: %s', volume_name)
|
||||
with self._client.open_connection() as api:
|
||||
try:
|
||||
ssn = api.find_sc(self.configuration.dell_sc_ssn)
|
||||
# Find our server.
|
||||
wwpns = connector.get('wwpns')
|
||||
for wwn in wwpns:
|
||||
scserver = api.find_server(ssn,
|
||||
wwn)
|
||||
scserver = api.find_server(wwn)
|
||||
if scserver is not None:
|
||||
break
|
||||
|
||||
# No? Create it.
|
||||
if scserver is None:
|
||||
server_folder = self.configuration.dell_sc_server_folder
|
||||
scserver = api.create_server_multiple_hbas(ssn,
|
||||
server_folder,
|
||||
wwpns)
|
||||
scserver = api.create_server_multiple_hbas(wwpns)
|
||||
# Find the volume on the storage center.
|
||||
scvolume = api.find_volume(ssn,
|
||||
volume_name)
|
||||
scvolume = api.find_volume(volume_name)
|
||||
if scserver is not None and scvolume is not None:
|
||||
mapping = api.map_volume(scvolume,
|
||||
scserver)
|
||||
if mapping is not None:
|
||||
# Since we just mapped our volume we had best update
|
||||
# our sc volume object.
|
||||
scvolume = api.find_volume(ssn,
|
||||
volume_name)
|
||||
scvolume = api.find_volume(volume_name)
|
||||
lun, targets, init_targ_map = api.find_wwns(scvolume,
|
||||
scserver)
|
||||
if lun is not None and len(targets) > 0:
|
||||
|
@ -115,17 +108,14 @@ class DellStorageCenterFCDriver(dell_storagecenter_common.DellCommonDriver,
|
|||
LOG.debug('Terminate connection: %s', volume_name)
|
||||
with self._client.open_connection() as api:
|
||||
try:
|
||||
ssn = api.find_sc(self.configuration.dell_sc_ssn)
|
||||
wwpns = connector.get('wwpns')
|
||||
for wwn in wwpns:
|
||||
scserver = api.find_server(ssn,
|
||||
wwn)
|
||||
scserver = api.find_server(wwn)
|
||||
if scserver is not None:
|
||||
break
|
||||
|
||||
# Find the volume on the storage center.
|
||||
scvolume = api.find_volume(ssn,
|
||||
volume_name)
|
||||
scvolume = api.find_volume(volume_name)
|
||||
# Get our target map so we can return it to free up a zone.
|
||||
lun, targets, init_targ_map = api.find_wwns(scvolume,
|
||||
scserver)
|
||||
|
|
|
@ -54,19 +54,13 @@ class DellStorageCenterISCSIDriver(san.SanISCSIDriver,
|
|||
|
||||
with self._client.open_connection() as api:
|
||||
try:
|
||||
ssn = api.find_sc(self.configuration.dell_sc_ssn)
|
||||
# Find our server.
|
||||
server = api.find_server(ssn,
|
||||
initiator_name)
|
||||
server = api.find_server(initiator_name)
|
||||
# No? Create it.
|
||||
if server is None:
|
||||
server_folder = self.configuration.dell_sc_server_folder
|
||||
server = api.create_server(ssn,
|
||||
server_folder,
|
||||
initiator_name)
|
||||
server = api.create_server(initiator_name)
|
||||
# Find the volume on the storage center.
|
||||
scvolume = api.find_volume(ssn,
|
||||
volume_name)
|
||||
scvolume = api.find_volume(volume_name)
|
||||
|
||||
# if we have a server and a volume lets bring them together.
|
||||
if server is not None and scvolume is not None:
|
||||
|
@ -75,8 +69,7 @@ class DellStorageCenterISCSIDriver(san.SanISCSIDriver,
|
|||
if mapping is not None:
|
||||
# Since we just mapped our volume we had best update
|
||||
# our sc volume object.
|
||||
scvolume = api.find_volume(ssn,
|
||||
volume_name)
|
||||
scvolume = api.find_volume(volume_name)
|
||||
|
||||
if multipath:
|
||||
# Just return our properties with all the mappings
|
||||
|
@ -136,12 +129,9 @@ class DellStorageCenterISCSIDriver(san.SanISCSIDriver,
|
|||
'i': initiator_name})
|
||||
with self._client.open_connection() as api:
|
||||
try:
|
||||
ssn = api.find_sc(self.configuration.dell_sc_ssn)
|
||||
scserver = api.find_server(ssn,
|
||||
initiator_name)
|
||||
scserver = api.find_server(initiator_name)
|
||||
# Find the volume on the storage center.
|
||||
scvolume = api.find_volume(ssn,
|
||||
volume_name)
|
||||
scvolume = api.find_volume(volume_name)
|
||||
|
||||
# If we have a server and a volume lets pull them apart.
|
||||
if (scserver is not None and
|
||||
|
|
Loading…
Reference in New Issue