Update SolidFire to use target driver model
A while back we broke the inheritance chain of transport and backend by moving the target drivers outside of the drivers. This means you can instantiate and use any target (data transport) method that your device supports without requiring a separate driver (again, if your device can support it). This was particularly important for the LVM ref driver and the 5 iSCSI options that go with it. This patch converts the SolidFire driver to use the same model. For the most part it's pretty simple: * Create an internal class for the target driver * Instantiate the target driver that you want to use * wrap the old transport calls that come to the driver to call the new target driver objects This exposed some issues with the abc work that was being done. There are a number of items that are marked as required but are really only necessary for LVM based drivers. So this also creates a san/3'rd party iSCSI subclass as well that has the more appropriate abc settings for such devices. Change-Id: I02ceaac58d0e4176ccad423763ae0101cfb8446b
This commit is contained in:
@@ -22,6 +22,7 @@ import time
|
|||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
from oslo_utils import importutils
|
||||||
from oslo_utils import timeutils
|
from oslo_utils import timeutils
|
||||||
from oslo_utils import units
|
from oslo_utils import units
|
||||||
import requests
|
import requests
|
||||||
@@ -33,6 +34,7 @@ from cinder.i18n import _, _LE, _LI, _LW
|
|||||||
from cinder.image import image_utils
|
from cinder.image import image_utils
|
||||||
from cinder.volume.drivers.san import san
|
from cinder.volume.drivers.san import san
|
||||||
from cinder.volume import qos_specs
|
from cinder.volume import qos_specs
|
||||||
|
from cinder.volume.targets import iscsi as iscsi_driver
|
||||||
from cinder.volume import volume_types
|
from cinder.volume import volume_types
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
@@ -67,7 +69,7 @@ sf_opts = [
|
|||||||
cfg.IntOpt('sf_api_port',
|
cfg.IntOpt('sf_api_port',
|
||||||
default=443,
|
default=443,
|
||||||
help='SolidFire API port. Useful if the device api is behind '
|
help='SolidFire API port. Useful if the device api is behind '
|
||||||
'a proxy on a different port.'), ]
|
'a proxy on a different port.')]
|
||||||
|
|
||||||
|
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
@@ -156,6 +158,11 @@ class SolidFireDriver(san.SanISCSIDriver):
|
|||||||
if self.configuration.sf_allow_template_caching:
|
if self.configuration.sf_allow_template_caching:
|
||||||
account = self.configuration.sf_template_account_name
|
account = self.configuration.sf_template_account_name
|
||||||
self.template_account_id = self._create_template_account(account)
|
self.template_account_id = self._create_template_account(account)
|
||||||
|
self.target_driver = (
|
||||||
|
importutils.import_object(
|
||||||
|
'cinder.volume.drivers.solidfire.SolidFireISCSI',
|
||||||
|
solidfire_driver=self,
|
||||||
|
configuration=self.configuration))
|
||||||
|
|
||||||
def _create_template_account(self, account_name):
|
def _create_template_account(self, account_name):
|
||||||
id = self._issue_api_request(
|
id = self._issue_api_request(
|
||||||
@@ -292,17 +299,6 @@ class SolidFireDriver(san.SanISCSIDriver):
|
|||||||
|
|
||||||
return data['result']
|
return data['result']
|
||||||
|
|
||||||
def _do_export(self, volume):
|
|
||||||
"""Gets the associated account, retrieves CHAP info and updates."""
|
|
||||||
sfaccount = self._get_sfaccount(volume['project_id'])
|
|
||||||
|
|
||||||
model_update = {}
|
|
||||||
model_update['provider_auth'] = ('CHAP %s %s'
|
|
||||||
% (sfaccount['username'],
|
|
||||||
sfaccount['targetSecret']))
|
|
||||||
|
|
||||||
return model_update
|
|
||||||
|
|
||||||
def _generate_random_string(self, length):
|
def _generate_random_string(self, length):
|
||||||
"""Generates random_string to use for CHAP password."""
|
"""Generates random_string to use for CHAP password."""
|
||||||
|
|
||||||
@@ -869,17 +865,6 @@ class SolidFireDriver(san.SanISCSIDriver):
|
|||||||
"the SolidFire Cluster while attempting "
|
"the SolidFire Cluster while attempting "
|
||||||
"delete_volume operation!"), volume['id'])
|
"delete_volume operation!"), volume['id'])
|
||||||
|
|
||||||
def ensure_export(self, context, volume):
|
|
||||||
"""Verify the iscsi export info."""
|
|
||||||
try:
|
|
||||||
return self._do_export(volume)
|
|
||||||
except exception.SolidFireAPIException:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def create_export(self, context, volume):
|
|
||||||
"""Setup the iscsi export info."""
|
|
||||||
return self._do_export(volume)
|
|
||||||
|
|
||||||
def delete_snapshot(self, snapshot):
|
def delete_snapshot(self, snapshot):
|
||||||
"""Delete the specified snapshot from the SolidFire cluster."""
|
"""Delete the specified snapshot from the SolidFire cluster."""
|
||||||
sf_snap_name = 'UUID-%s' % snapshot['id']
|
sf_snap_name = 'UUID-%s' % snapshot['id']
|
||||||
@@ -1084,8 +1069,7 @@ class SolidFireDriver(san.SanISCSIDriver):
|
|||||||
|
|
||||||
volume['project_id'] = new_project
|
volume['project_id'] = new_project
|
||||||
volume['user_id'] = new_user
|
volume['user_id'] = new_user
|
||||||
model_update = self._do_export(volume)
|
return self.target_driver.ensure_export(context, volume, None)
|
||||||
return model_update
|
|
||||||
|
|
||||||
def retype(self, ctxt, volume, new_type, diff, host):
|
def retype(self, ctxt, volume, new_type, diff, host):
|
||||||
"""Convert the volume to be of the new type.
|
"""Convert the volume to be of the new type.
|
||||||
@@ -1228,3 +1212,64 @@ class SolidFireDriver(san.SanISCSIDriver):
|
|||||||
params, version='5.0')
|
params, version='5.0')
|
||||||
if 'result' not in data:
|
if 'result' not in data:
|
||||||
raise exception.SolidFireAPIDataException(data=data)
|
raise exception.SolidFireAPIDataException(data=data)
|
||||||
|
|
||||||
|
# #### Interface methods for transport layer #### #
|
||||||
|
|
||||||
|
# TODO(jdg): SolidFire can mix and do iSCSI and FC on the
|
||||||
|
# same cluster, we'll modify these later to check based on
|
||||||
|
# the volume info if we need an FC target driver or an
|
||||||
|
# iSCSI target driver
|
||||||
|
def ensure_export(self, context, volume):
|
||||||
|
return self.target_driver.ensure_export(context, volume, None)
|
||||||
|
|
||||||
|
def create_export(self, context, volume):
|
||||||
|
return self.target_driver.create_export(
|
||||||
|
context,
|
||||||
|
volume,
|
||||||
|
None)
|
||||||
|
|
||||||
|
def remove_export(self, context, volume):
|
||||||
|
return self.target_driver.remove_export(context, volume)
|
||||||
|
|
||||||
|
def initialize_connection(self, volume, connector):
|
||||||
|
return self.target_driver.initialize_connection(volume, connector)
|
||||||
|
|
||||||
|
def validate_connector(self, connector):
|
||||||
|
return self.target_driver.validate_connector(connector)
|
||||||
|
|
||||||
|
def terminate_connection(self, volume, connector, **kwargs):
|
||||||
|
return self.target_driver.terminate_connection(volume, connector,
|
||||||
|
**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class SolidFireISCSI(iscsi_driver.SanISCSITarget):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(SolidFireISCSI, self).__init__(*args, **kwargs)
|
||||||
|
self.sf_driver = kwargs.get('solidfire_driver')
|
||||||
|
|
||||||
|
def _do_iscsi_export(self, volume):
|
||||||
|
sfaccount = self.sf_driver._get_sfaccount(volume['project_id'])
|
||||||
|
model_update = {}
|
||||||
|
model_update['provider_auth'] = ('CHAP %s %s'
|
||||||
|
% (sfaccount['username'],
|
||||||
|
sfaccount['targetSecret']))
|
||||||
|
|
||||||
|
return model_update
|
||||||
|
|
||||||
|
def create_export(self, context, volume, volume_path):
|
||||||
|
return self._do_iscsi_export(volume)
|
||||||
|
|
||||||
|
def ensure_export(self, context, volume, volume_path):
|
||||||
|
try:
|
||||||
|
return self._do_iscsi_export(volume)
|
||||||
|
except exception.SolidFireAPIException:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Following are abc's that we make sure are caught and
|
||||||
|
# paid attention to. In our case we don't use them
|
||||||
|
# so just stub them out here.
|
||||||
|
def remove_export(self, context, volume):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def terminate_connection(self, volume, connector, **kwargs):
|
||||||
|
pass
|
||||||
|
|||||||
@@ -354,3 +354,56 @@ class ISCSITarget(driver.Target):
|
|||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def _get_target(self, iqn):
|
def _get_target(self, iqn):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class SanISCSITarget(ISCSITarget):
|
||||||
|
"""iSCSI target for san devices.
|
||||||
|
|
||||||
|
San devices are slightly different, they don't need to implement
|
||||||
|
all of the same things that we need to implement locally fro LVM
|
||||||
|
and local block devices when we create and manage our own targets.
|
||||||
|
|
||||||
|
"""
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(SanISCSITarget, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def create_export(self, context, volume, volume_path):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def remove_export(self, context, volume):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def ensure_export(self, context, volume, volume_path):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def terminate_connection(self, volume, connector, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# NOTE(jdg): Items needed for local iSCSI target drivers,
|
||||||
|
# but NOT sans Stub them out here to make abc happy
|
||||||
|
|
||||||
|
# Use care when looking at these to make sure something
|
||||||
|
# that's inheritted isn't dependent on one of
|
||||||
|
# these.
|
||||||
|
def _get_target_and_lun(self, context, volume):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _get_target_chap_auth(self, context, iscsi_name):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def create_iscsi_target(self, name, tid, lun, path,
|
||||||
|
chap_auth, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def remove_iscsi_target(self, tid, lun, vol_id, vol_name, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _get_iscsi_target(self, context, vol_id):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _get_target(self, iqn):
|
||||||
|
pass
|
||||||
|
|||||||
Reference in New Issue
Block a user