Remove need for CONF acces in brick iscsi

At some point we'd like brick to be a standalone lib,
and as such we don't want to have a requirement for
CONF files and having duplicate conf entries across
projects.

The better approach would be to let the projects decide
what they want to use, and how they want defaults to be set
and then pass those settings in via __init__ or when calling
the methods that need them.

Partial-Bug: #1230066

Change-Id: Ib108f1abb2948cb896bdad58070daa7a725a205d
This commit is contained in:
John Griffith 2013-09-26 15:23:01 -06:00
parent ddc585678d
commit 09f2bea49b
6 changed files with 101 additions and 92 deletions

View File

@ -26,8 +26,6 @@ import re
import stat import stat
import time import time
from oslo.config import cfg
from cinder.brick import exception from cinder.brick import exception
from cinder.brick import executor from cinder.brick import executor
from cinder.openstack.common import fileutils from cinder.openstack.common import fileutils
@ -38,35 +36,6 @@ from cinder.openstack.common import processutils as putils
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
iscsi_helper_opt = [cfg.StrOpt('iscsi_helper',
default='tgtadm',
help='iscsi target user-land tool to use'),
cfg.StrOpt('volumes_dir',
default='$state_path/volumes',
help='Volume configuration file storage '
'directory'),
cfg.StrOpt('iet_conf',
default='/etc/iet/ietd.conf',
help='IET configuration file'),
cfg.StrOpt('lio_initiator_iqns',
default='',
help=('Comma-separatd list of initiator IQNs '
'allowed to connect to the '
'iSCSI target. (From Nova compute nodes.)'
)
),
cfg.StrOpt('iscsi_iotype',
default='fileio',
help=('Sets the behavior of the iSCSI target '
'to either perform blockio or fileio '
'optionally, auto can be set and Cinder '
'will autodetect type of backing device')
)
]
CONF = cfg.CONF
CONF.register_opts(iscsi_helper_opt)
class TargetAdmin(executor.Executor): class TargetAdmin(executor.Executor):
"""iSCSI target administration. """iSCSI target administration.
@ -114,9 +83,14 @@ class TargetAdmin(executor.Executor):
class TgtAdm(TargetAdmin): class TgtAdm(TargetAdmin):
"""iSCSI target administration using tgtadm.""" """iSCSI target administration using tgtadm."""
def __init__(self, root_helper, execute=putils.execute): def __init__(self, root_helper, volumes_dir,
target_prefix='iqn.2010-10.org.openstack:',
execute=putils.execute):
super(TgtAdm, self).__init__('tgtadm', root_helper, execute) super(TgtAdm, self).__init__('tgtadm', root_helper, execute)
self.iscsi_target_prefix = target_prefix
self.volumes_dir = volumes_dir
def _get_target(self, iqn): def _get_target(self, iqn):
(out, err) = self._execute('tgt-admin', '--show', run_as_root=True) (out, err) = self._execute('tgt-admin', '--show', run_as_root=True)
lines = out.split('\n') lines = out.split('\n')
@ -178,7 +152,7 @@ class TgtAdm(TargetAdmin):
# Note(jdg) tid and lun aren't used by TgtAdm but remain for # Note(jdg) tid and lun aren't used by TgtAdm but remain for
# compatibility # compatibility
fileutils.ensure_tree(CONF.volumes_dir) fileutils.ensure_tree(self.volumes_dir)
vol_id = name.split(':')[1] vol_id = name.split(':')[1]
if chap_auth is None: if chap_auth is None:
@ -196,7 +170,7 @@ class TgtAdm(TargetAdmin):
""" % (name, path, chap_auth) """ % (name, path, chap_auth)
LOG.info(_('Creating iscsi_target for: %s') % vol_id) LOG.info(_('Creating iscsi_target for: %s') % vol_id)
volumes_dir = CONF.volumes_dir volumes_dir = self.volumes_dir
volume_path = os.path.join(volumes_dir, vol_id) volume_path = os.path.join(volumes_dir, vol_id)
f = open(volume_path, 'w+') f = open(volume_path, 'w+')
@ -238,7 +212,7 @@ class TgtAdm(TargetAdmin):
os.unlink(volume_path) os.unlink(volume_path)
raise exception.ISCSITargetCreateFailed(volume_id=vol_id) raise exception.ISCSITargetCreateFailed(volume_id=vol_id)
iqn = '%s%s' % (CONF.iscsi_target_prefix, vol_id) iqn = '%s%s' % (self.iscsi_target_prefix, vol_id)
tid = self._get_target(iqn) tid = self._get_target(iqn)
if tid is None: if tid is None:
LOG.error(_("Failed to create iscsi target for volume " LOG.error(_("Failed to create iscsi target for volume "
@ -274,9 +248,9 @@ class TgtAdm(TargetAdmin):
def remove_iscsi_target(self, tid, lun, vol_id, vol_name, **kwargs): def remove_iscsi_target(self, tid, lun, vol_id, vol_name, **kwargs):
LOG.info(_('Removing iscsi_target for: %s') % vol_id) LOG.info(_('Removing iscsi_target for: %s') % vol_id)
vol_uuid_file = vol_name vol_uuid_file = vol_name
volume_path = os.path.join(CONF.volumes_dir, vol_uuid_file) volume_path = os.path.join(self.volumes_dir, vol_uuid_file)
if os.path.isfile(volume_path): if os.path.isfile(volume_path):
iqn = '%s%s' % (CONF.iscsi_target_prefix, iqn = '%s%s' % (self.iscsi_target_prefix,
vol_uuid_file) vol_uuid_file)
else: else:
raise exception.ISCSITargetRemoveFailed(volume_id=vol_id) raise exception.ISCSITargetRemoveFailed(volume_id=vol_id)
@ -309,18 +283,21 @@ class TgtAdm(TargetAdmin):
class IetAdm(TargetAdmin): class IetAdm(TargetAdmin):
"""iSCSI target administration using ietadm.""" """iSCSI target administration using ietadm."""
def __init__(self, root_helper, execute=putils.execute): def __init__(self, root_helper, iet_conf='/etc/iet/ietd.conf',
iscsi_iotype='fileio', execute=putils.execute):
super(IetAdm, self).__init__('ietadm', root_helper, execute) super(IetAdm, self).__init__('ietadm', root_helper, execute)
self.iet_conf = iet_conf
self.iscsi_iotype = iscsi_iotype
def _is_block(self, path): def _is_block(self, path):
mode = os.stat(path).st_mode mode = os.stat(path).st_mode
return stat.S_ISBLK(mode) return stat.S_ISBLK(mode)
def _iotype(self, path): def _iotype(self, path):
if CONF.iscsi_iotype == 'auto': if self.iscsi_iotype == 'auto':
return 'blockio' if self._is_block(path) else 'fileio' return 'blockio' if self._is_block(path) else 'fileio'
else: else:
return CONF.iscsi_iotype return self.iscsi_iotype
@contextlib.contextmanager @contextlib.contextmanager
def temporary_chown(self, path, owner_uid=None): def temporary_chown(self, path, owner_uid=None):
@ -356,7 +333,7 @@ class IetAdm(TargetAdmin):
(type, username, password) = chap_auth.split() (type, username, password) = chap_auth.split()
self._new_auth(tid, type, username, password, **kwargs) self._new_auth(tid, type, username, password, **kwargs)
conf_file = CONF.iet_conf conf_file = self.iet_conf
if os.path.exists(conf_file): if os.path.exists(conf_file):
try: try:
volume_conf = """ volume_conf = """
@ -382,7 +359,7 @@ class IetAdm(TargetAdmin):
self._delete_logicalunit(tid, lun, **kwargs) self._delete_logicalunit(tid, lun, **kwargs)
self._delete_target(tid, **kwargs) self._delete_target(tid, **kwargs)
vol_uuid_file = vol_name vol_uuid_file = vol_name
conf_file = CONF.iet_conf conf_file = self.iet_conf
if os.path.exists(conf_file): if os.path.exists(conf_file):
with self.temporary_chown(conf_file): with self.temporary_chown(conf_file):
try: try:
@ -458,9 +435,16 @@ class FakeIscsiHelper(object):
class LioAdm(TargetAdmin): class LioAdm(TargetAdmin):
"""iSCSI target administration for LIO using python-rtslib.""" """iSCSI target administration for LIO using python-rtslib."""
def __init__(self, root_helper, execute=putils.execute): def __init__(self, root_helper, lio_initiator_iqns='',
iscsi_target_prefix='iqn.2010-10.org.openstack:',
execute=putils.execute):
super(LioAdm, self).__init__('rtstool', root_helper, execute) super(LioAdm, self).__init__('rtstool', root_helper, execute)
self.iscsi_target_prefix = iscsi_target_prefix
self.lio_initiator_iqns = lio_initiator_iqns
self._verify_rtstool()
def _verify_rtstool(self):
try: try:
self._execute('rtstool', 'verify') self._execute('rtstool', 'verify')
except (OSError, putils.ProcessExecutionError): except (OSError, putils.ProcessExecutionError):
@ -494,8 +478,8 @@ class LioAdm(TargetAdmin):
(chap_auth_userid, chap_auth_password) = chap_auth.split(' ')[1:] (chap_auth_userid, chap_auth_password) = chap_auth.split(' ')[1:]
extra_args = [] extra_args = []
if CONF.lio_initiator_iqns: if self.lio_initiator_iqns:
extra_args.append(CONF.lio_initiator_iqns) extra_args.append(self.lio_initiator_iqns)
try: try:
command_args = ['rtstool', command_args = ['rtstool',
@ -514,7 +498,7 @@ class LioAdm(TargetAdmin):
raise exception.ISCSITargetCreateFailed(volume_id=vol_id) raise exception.ISCSITargetCreateFailed(volume_id=vol_id)
iqn = '%s%s' % (CONF.iscsi_target_prefix, vol_id) iqn = '%s%s' % (self.iscsi_target_prefix, vol_id)
tid = self._get_target(iqn) tid = self._get_target(iqn)
if tid is None: if tid is None:
LOG.error(_("Failed to create iscsi target for volume " LOG.error(_("Failed to create iscsi target for volume "
@ -526,7 +510,7 @@ class LioAdm(TargetAdmin):
def remove_iscsi_target(self, tid, lun, vol_id, vol_name, **kwargs): def remove_iscsi_target(self, tid, lun, vol_id, vol_name, **kwargs):
LOG.info(_('Removing iscsi_target: %s') % vol_id) LOG.info(_('Removing iscsi_target: %s') % vol_id)
vol_uuid_name = vol_name vol_uuid_name = vol_name
iqn = '%s%s' % (CONF.iscsi_target_prefix, vol_uuid_name) iqn = '%s%s' % (self.iscsi_target_prefix, vol_uuid_name)
try: try:
self._execute('rtstool', self._execute('rtstool',
@ -566,14 +550,3 @@ class LioAdm(TargetAdmin):
LOG.error(_("Failed to add initiator iqn %s to target") % LOG.error(_("Failed to add initiator iqn %s to target") %
connector['initiator']) connector['initiator'])
raise exception.ISCSITargetAttachFailed(volume_id=volume['id']) raise exception.ISCSITargetAttachFailed(volume_id=volume['id'])
def get_target_admin(root_helper):
if CONF.iscsi_helper == 'tgtadm':
return TgtAdm(root_helper)
elif CONF.iscsi_helper == 'fake':
return FakeIscsiHelper()
elif CONF.iscsi_helper == 'lioadm':
return LioAdm(root_helper)
else:
return IetAdm(root_helper)

View File

@ -21,6 +21,7 @@ import tempfile
from cinder.brick.iscsi import iscsi from cinder.brick.iscsi import iscsi
from cinder import test from cinder import test
from cinder.volume import driver
from cinder.volume import utils as volume_utils from cinder.volume import utils as volume_utils
@ -41,15 +42,19 @@ class TargetAdminTestCase(object):
self.stubs.Set(os, 'unlink', lambda _: '') self.stubs.Set(os, 'unlink', lambda _: '')
self.stubs.Set(iscsi.TgtAdm, '_get_target', self.fake_get_target) self.stubs.Set(iscsi.TgtAdm, '_get_target', self.fake_get_target)
self.stubs.Set(iscsi.LioAdm, '_get_target', self.fake_get_target) self.stubs.Set(iscsi.LioAdm, '_get_target', self.fake_get_target)
self.stubs.Set(iscsi.LioAdm, '__init__', self.fake_init) self.stubs.Set(iscsi.LioAdm,
'_verify_rtstool',
self.fake_verify_rtstool)
self.driver = driver.ISCSIDriver()
self.stubs.Set(iscsi.TgtAdm, '_verify_backing_lun', self.stubs.Set(iscsi.TgtAdm, '_verify_backing_lun',
self.fake_verify_backing_lun) self.fake_verify_backing_lun)
self.driver = driver.ISCSIDriver()
def fake_verify_backing_lun(obj, iqn, tid): def fake_verify_backing_lun(obj, iqn, tid):
return True return True
def fake_init(obj, root_helper): def fake_verify_rtstool(obj):
return pass
def fake_get_target(obj, iqn): def fake_get_target(obj, iqn):
return 1 return 1
@ -85,7 +90,7 @@ class TargetAdminTestCase(object):
self.verify_cmds(cmds) self.verify_cmds(cmds)
def run_commands(self): def run_commands(self):
tgtadm = iscsi.get_target_admin(None) tgtadm = self.driver.get_target_admin()
tgtadm.set_execute(self.fake_execute) tgtadm.set_execute(self.fake_execute)
tgtadm.create_iscsi_target(self.target_name, self.tid, tgtadm.create_iscsi_target(self.target_name, self.tid,
self.lun, self.path) self.lun, self.path)

View File

@ -26,6 +26,7 @@ import time
from oslo.config import cfg from oslo.config import cfg
from cinder.brick.initiator import connector as initiator from cinder.brick.initiator import connector as initiator
from cinder.brick.iscsi import iscsi
from cinder import exception from cinder import exception
from cinder.image import image_utils from cinder.image import image_utils
from cinder.openstack.common import excutils from cinder.openstack.common import excutils
@ -91,7 +92,28 @@ volume_opts = [
'none, zero, shred)'), 'none, zero, shred)'),
cfg.IntOpt('volume_clear_size', cfg.IntOpt('volume_clear_size',
default=0, default=0,
help='Size in MiB to wipe at start of old volumes. 0 => all'), ] help='Size in MiB to wipe at start of old volumes. 0 => all'),
cfg.StrOpt('iscsi_helper',
default='tgtadm',
help='iscsi target user-land tool to use'),
cfg.StrOpt('volumes_dir',
default='$state_path/volumes',
help='Volume configuration file storage '
'directory'),
cfg.StrOpt('iet_conf',
default='/etc/iet/ietd.conf',
help='IET configuration file'),
cfg.StrOpt('lio_initiator_iqns',
default='',
help=('Comma-separated list of initiator IQNs '
'allowed to connect to the '
'iSCSI target. (From Nova compute nodes.)')),
cfg.StrOpt('iscsi_iotype',
default='fileio',
help=('Sets the behavior of the iSCSI target '
'to either perform blockio or fileio '
'optionally, auto can be set and Cinder '
'will autodetect type of backing device'))]
CONF = cfg.CONF CONF = cfg.CONF
@ -665,6 +687,22 @@ class ISCSIDriver(VolumeDriver):
def accept_transfer(self, context, volume, new_user, new_project): def accept_transfer(self, context, volume, new_user, new_project):
pass pass
def get_target_admin(self):
root_helper = utils.get_root_helper()
if CONF.iscsi_helper == 'tgtadm':
return iscsi.TgtAdm(root_helper,
CONF.volumes_dir,
CONF.iscsi_target_prefix)
elif CONF.iscsi_helper == 'fake':
return iscsi.FakeIscsiHelper()
elif CONF.iscsi_helper == 'lioadm':
return iscsi.LioAdm(root_helper,
CONF.lio_initiator_iqns,
CONF.iscsi_target_prefix)
else:
return iscsi.IetAdm(root_helper, CONF.iet_conf, CONF.iscsi_iotype)
class FakeISCSIDriver(ISCSIDriver): class FakeISCSIDriver(ISCSIDriver):
"""Logs calls instead of executing.""" """Logs calls instead of executing."""

View File

@ -44,8 +44,7 @@ class BlockDeviceDriver(driver.ISCSIDriver):
VERSION = '1.0.0' VERSION = '1.0.0'
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
root_helper = 'sudo cinder-rootwrap %s' % CONF.rootwrap_config self.tgtadm = self.get_target_admin()
self.tgtadm = iscsi.get_target_admin(root_helper)
super(BlockDeviceDriver, self).__init__(*args, **kwargs) super(BlockDeviceDriver, self).__init__(*args, **kwargs)
self.configuration.append_config_values(volume_opts) self.configuration.append_config_values(volume_opts)

View File

@ -83,7 +83,7 @@ class LVMVolumeDriver(driver.VolumeDriver):
def check_for_setup_error(self): def check_for_setup_error(self):
"""Verify that requirements are in place to use LVM driver.""" """Verify that requirements are in place to use LVM driver."""
if self.vg is None: if self.vg is None:
root_helper = 'sudo cinder-rootwrap %s' % CONF.rootwrap_config root_helper = utils.get_root_helper()
try: try:
self.vg = lvm.LVM(self.configuration.volume_group, self.vg = lvm.LVM(self.configuration.volume_group,
root_helper, root_helper,
@ -401,8 +401,7 @@ class LVMISCSIDriver(LVMVolumeDriver, driver.ISCSIDriver):
""" """
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
root_helper = 'sudo cinder-rootwrap %s' % CONF.rootwrap_config self.tgtadm = self.get_target_admin()
self.tgtadm = iscsi.get_target_admin(root_helper)
super(LVMISCSIDriver, self).__init__(*args, **kwargs) super(LVMISCSIDriver, self).__init__(*args, **kwargs)
self.backend_name =\ self.backend_name =\
self.configuration.safe_get('volume_backend_name') or 'LVM_iSCSI' self.configuration.safe_get('volume_backend_name') or 'LVM_iSCSI'
@ -749,7 +748,7 @@ class LVMISERDriver(LVMISCSIDriver, driver.ISERDriver):
""" """
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
root_helper = 'sudo cinder-rootwrap %s' % CONF.rootwrap_config root_helper = utils.get_root_helper()
self.tgtadm = iser.get_target_admin(root_helper) self.tgtadm = iser.get_target_admin(root_helper)
LVMVolumeDriver.__init__(self, *args, **kwargs) LVMVolumeDriver.__init__(self, *args, **kwargs)
self.backend_name =\ self.backend_name =\

View File

@ -234,29 +234,6 @@
#backup_driver=cinder.backup.drivers.swift #backup_driver=cinder.backup.drivers.swift
#
# Options defined in cinder.brick.iscsi.iscsi
#
# iscsi target user-land tool to use (string value)
#iscsi_helper=tgtadm
# Volume configuration file storage directory (string value)
#volumes_dir=$state_path/volumes
# IET configuration file (string value)
#iet_conf=/etc/iet/ietd.conf
# Comma-separatd list of initiator IQNs allowed to connect to
# the iSCSI target. (From Nova compute nodes.) (string value)
#lio_initiator_iqns=
# Sets the behavior of the iSCSI target to either perform
# blockio or fileio optionally, auto can be set and Cinder
# will autodetect type of backing device (string value)
#iscsi_iotype=fileio
# #
# Options defined in cinder.brick.iser.iser # Options defined in cinder.brick.iser.iser
# #
@ -1098,6 +1075,24 @@
# (integer value) # (integer value)
#volume_clear_size=0 #volume_clear_size=0
# iscsi target user-land tool to use (string value)
#iscsi_helper=tgtadm
# Volume configuration file storage directory (string value)
#volumes_dir=$state_path/volumes
# IET configuration file (string value)
#iet_conf=/etc/iet/ietd.conf
# Comma-separated list of initiator IQNs allowed to connect to
# the iSCSI target. (From Nova compute nodes.) (string value)
#lio_initiator_iqns=
# Sets the behavior of the iSCSI target to either perform
# blockio or fileio optionally, auto can be set and Cinder
# will autodetect type of backing device (string value)
#iscsi_iotype=fileio
# #
# Options defined in cinder.volume.drivers.block_device # Options defined in cinder.volume.drivers.block_device