Merge "Add persistent volumes for tgtd."
This commit is contained in:
@@ -14,6 +14,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import os.path
|
||||||
import string
|
import string
|
||||||
|
|
||||||
from cinder import test
|
from cinder import test
|
||||||
@@ -28,9 +29,12 @@ class TargetAdminTestCase(object):
|
|||||||
self.tid = 1
|
self.tid = 1
|
||||||
self.target_name = 'iqn.2011-09.org.foo.bar:blaa'
|
self.target_name = 'iqn.2011-09.org.foo.bar:blaa'
|
||||||
self.lun = 10
|
self.lun = 10
|
||||||
self.path = '/foo/bar/blaa'
|
self.path = '/foo'
|
||||||
|
self.vol_id = 'blaa'
|
||||||
|
|
||||||
self.script_template = None
|
self.script_template = None
|
||||||
|
self.stubs.Set(os.path, 'isfile', lambda _: True)
|
||||||
|
self.stubs.Set(os, 'unlink', lambda _: '')
|
||||||
|
|
||||||
def get_script_params(self):
|
def get_script_params(self):
|
||||||
return {'tid': self.tid,
|
return {'tid': self.tid,
|
||||||
@@ -65,11 +69,10 @@ class TargetAdminTestCase(object):
|
|||||||
def run_commands(self):
|
def run_commands(self):
|
||||||
tgtadm = iscsi.get_target_admin()
|
tgtadm = iscsi.get_target_admin()
|
||||||
tgtadm.set_execute(self.fake_execute)
|
tgtadm.set_execute(self.fake_execute)
|
||||||
tgtadm.new_target(self.target_name, self.tid)
|
tgtadm.create_iscsi_target(self.target_name, self.tid,
|
||||||
|
self.lun, self.path)
|
||||||
tgtadm.show_target(self.tid)
|
tgtadm.show_target(self.tid)
|
||||||
tgtadm.new_logicalunit(self.tid, self.lun, self.path)
|
tgtadm.remove_iscsi_target(self.tid, self.lun, self.vol_id)
|
||||||
tgtadm.delete_logicalunit(self.tid, self.lun)
|
|
||||||
tgtadm.delete_target(self.tid)
|
|
||||||
|
|
||||||
def test_target_admin(self):
|
def test_target_admin(self):
|
||||||
self.clear_cmds()
|
self.clear_cmds()
|
||||||
@@ -83,22 +86,11 @@ class TgtAdmTestCase(test.TestCase, TargetAdminTestCase):
|
|||||||
super(TgtAdmTestCase, self).setUp()
|
super(TgtAdmTestCase, self).setUp()
|
||||||
TargetAdminTestCase.setUp(self)
|
TargetAdminTestCase.setUp(self)
|
||||||
self.flags(iscsi_helper='tgtadm')
|
self.flags(iscsi_helper='tgtadm')
|
||||||
|
self.flags(volumes_dir="./")
|
||||||
self.script_template = "\n".join([
|
self.script_template = "\n".join([
|
||||||
"tgtadm --op new --lld=iscsi --mode=target --tid=%(tid)s "
|
"tgt-admin --execute --conf ./blaa --update blaa",
|
||||||
"--targetname=%(target_name)s",
|
"tgtadm --op show --lld=iscsi --mode=target --tid=1",
|
||||||
"tgtadm --op bind --lld=iscsi --mode=target --initiator-address=ALL "
|
"tgt-admin --delete iqn.2010-10.org.openstack:volume-blaa"])
|
||||||
"--tid=%(tid)s",
|
|
||||||
"tgtadm --op show --lld=iscsi --mode=target --tid=%(tid)s",
|
|
||||||
"tgtadm --op new --lld=iscsi --mode=logicalunit --tid=%(tid)s "
|
|
||||||
"--lun=%(lun)d --backing-store=%(path)s",
|
|
||||||
"tgtadm --op delete --lld=iscsi --mode=logicalunit --tid=%(tid)s "
|
|
||||||
"--lun=%(lun)d",
|
|
||||||
"tgtadm --op delete --lld=iscsi --mode=target --tid=%(tid)s"])
|
|
||||||
|
|
||||||
def get_script_params(self):
|
|
||||||
params = super(TgtAdmTestCase, self).get_script_params()
|
|
||||||
params['lun'] += 1
|
|
||||||
return params
|
|
||||||
|
|
||||||
|
|
||||||
class IetAdmTestCase(test.TestCase, TargetAdminTestCase):
|
class IetAdmTestCase(test.TestCase, TargetAdminTestCase):
|
||||||
@@ -109,8 +101,8 @@ class IetAdmTestCase(test.TestCase, TargetAdminTestCase):
|
|||||||
self.flags(iscsi_helper='ietadm')
|
self.flags(iscsi_helper='ietadm')
|
||||||
self.script_template = "\n".join([
|
self.script_template = "\n".join([
|
||||||
"ietadm --op new --tid=%(tid)s --params Name=%(target_name)s",
|
"ietadm --op new --tid=%(tid)s --params Name=%(target_name)s",
|
||||||
"ietadm --op show --tid=%(tid)s",
|
"ietadm --op new --tid=%(tid)s --lun=%(lun)s "
|
||||||
"ietadm --op new --tid=%(tid)s --lun=%(lun)d "
|
|
||||||
"--params Path=%(path)s,Type=fileio",
|
"--params Path=%(path)s,Type=fileio",
|
||||||
"ietadm --op delete --tid=%(tid)s --lun=%(lun)d",
|
"ietadm --op show --tid=%(tid)s",
|
||||||
"ietadm --op delete --tid=%(tid)s"])
|
"ietadm --op delete --tid=%(tid)s",
|
||||||
|
"ietadm --op delete --tid=%(tid)s --lun=%(lun)s"])
|
||||||
|
|||||||
@@ -274,9 +274,8 @@ class ISCSIDriver(VolumeDriver):
|
|||||||
iscsi_name = "%s%s" % (FLAGS.iscsi_target_prefix, volume['name'])
|
iscsi_name = "%s%s" % (FLAGS.iscsi_target_prefix, volume['name'])
|
||||||
volume_path = "/dev/%s/%s" % (FLAGS.volume_group, volume['name'])
|
volume_path = "/dev/%s/%s" % (FLAGS.volume_group, volume['name'])
|
||||||
|
|
||||||
self.tgtadm.new_target(iscsi_name, iscsi_target, check_exit_code=False)
|
self.tgtadm.create_iscsi_target(iscsi_name, iscsi_target,
|
||||||
self.tgtadm.new_logicalunit(iscsi_target, 0, volume_path,
|
0, volume_path, check_exit_code=False)
|
||||||
check_exit_code=False)
|
|
||||||
|
|
||||||
def _ensure_iscsi_targets(self, context, host):
|
def _ensure_iscsi_targets(self, context, host):
|
||||||
"""Ensure that target ids have been created in datastore."""
|
"""Ensure that target ids have been created in datastore."""
|
||||||
@@ -297,8 +296,8 @@ class ISCSIDriver(VolumeDriver):
|
|||||||
iscsi_name = "%s%s" % (FLAGS.iscsi_target_prefix, volume['name'])
|
iscsi_name = "%s%s" % (FLAGS.iscsi_target_prefix, volume['name'])
|
||||||
volume_path = "/dev/%s/%s" % (FLAGS.volume_group, volume['name'])
|
volume_path = "/dev/%s/%s" % (FLAGS.volume_group, volume['name'])
|
||||||
|
|
||||||
self.tgtadm.new_target(iscsi_name, iscsi_target)
|
self.tgtadm.create_iscsi_target(iscsi_name, iscsi_target,
|
||||||
self.tgtadm.new_logicalunit(iscsi_target, 0, volume_path)
|
0, volume_path)
|
||||||
|
|
||||||
model_update = {}
|
model_update = {}
|
||||||
if FLAGS.iscsi_helper == 'tgtadm':
|
if FLAGS.iscsi_helper == 'tgtadm':
|
||||||
@@ -328,8 +327,7 @@ class ISCSIDriver(VolumeDriver):
|
|||||||
"is presently exported for volume: %s"), volume['id'])
|
"is presently exported for volume: %s"), volume['id'])
|
||||||
return
|
return
|
||||||
|
|
||||||
self.tgtadm.delete_logicalunit(iscsi_target, 0)
|
self.tgtadm.remove_iscsi_target(iscsi_target, 0, volume['id'])
|
||||||
self.tgtadm.delete_target(iscsi_target)
|
|
||||||
|
|
||||||
def _do_iscsi_discovery(self, volume):
|
def _do_iscsi_discovery(self, volume):
|
||||||
#TODO(justinsb): Deprecate discovery and use stored info
|
#TODO(justinsb): Deprecate discovery and use stored info
|
||||||
|
|||||||
@@ -19,18 +19,27 @@
|
|||||||
Helper code for the iSCSI volume driver.
|
Helper code for the iSCSI volume driver.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
import os
|
||||||
|
|
||||||
|
from cinder import exception
|
||||||
from cinder import flags
|
from cinder import flags
|
||||||
from cinder.openstack.common import cfg
|
from cinder.openstack.common import cfg
|
||||||
|
from cinder.openstack.common import log as logging
|
||||||
from cinder import utils
|
from cinder import utils
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
iscsi_helper_opt = cfg.StrOpt('iscsi_helper',
|
iscsi_helper_opt = [
|
||||||
default='ietadm',
|
cfg.StrOpt('iscsi_helper',
|
||||||
help='iscsi target user-land tool to use')
|
default='tgtadm',
|
||||||
|
help='iscsi target user-land tool to use'),
|
||||||
|
cfg.StrOpt('volumes_dir',
|
||||||
|
default='$state_path/volumes',
|
||||||
|
help='Volume configfuration file storage directory'),
|
||||||
|
]
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
FLAGS = flags.FLAGS
|
||||||
FLAGS.register_opt(iscsi_helper_opt)
|
FLAGS.register_opts(iscsi_helper_opt)
|
||||||
|
|
||||||
|
|
||||||
class TargetAdmin(object):
|
class TargetAdmin(object):
|
||||||
@@ -50,23 +59,31 @@ class TargetAdmin(object):
|
|||||||
def _run(self, *args, **kwargs):
|
def _run(self, *args, **kwargs):
|
||||||
self._execute(self._cmd, *args, run_as_root=True, **kwargs)
|
self._execute(self._cmd, *args, run_as_root=True, **kwargs)
|
||||||
|
|
||||||
def new_target(self, name, tid, **kwargs):
|
def create_iscsi_target(self, name, tid, lun, path, **kwargs):
|
||||||
|
"""Create a iSCSI target and logical unit"""
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def remove_iscsi_target(self, tid, lun, vol_id, **kwargs):
|
||||||
|
"""Remove a iSCSI target and logical unit"""
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def _new_target(self, name, tid, **kwargs):
|
||||||
"""Create a new iSCSI target."""
|
"""Create a new iSCSI target."""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def delete_target(self, tid, **kwargs):
|
def _delete_target(self, tid, **kwargs):
|
||||||
"""Delete a target."""
|
"""Delete a target."""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def show_target(self, tid, **kwargs):
|
def _show_target(self, tid, **kwargs):
|
||||||
"""Query the given target ID."""
|
"""Query the given target ID."""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def new_logicalunit(self, tid, lun, path, **kwargs):
|
def _new_logicalunit(self, tid, lun, path, **kwargs):
|
||||||
"""Create a new LUN on a target using the supplied path."""
|
"""Create a new LUN on a target using the supplied path."""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def delete_logicalunit(self, tid, lun, **kwargs):
|
def _delete_logicalunit(self, tid, lun, **kwargs):
|
||||||
"""Delete a logical unit from a target."""
|
"""Delete a logical unit from a target."""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
@@ -77,23 +94,53 @@ class TgtAdm(TargetAdmin):
|
|||||||
def __init__(self, execute=utils.execute):
|
def __init__(self, execute=utils.execute):
|
||||||
super(TgtAdm, self).__init__('tgtadm', execute)
|
super(TgtAdm, self).__init__('tgtadm', execute)
|
||||||
|
|
||||||
def new_target(self, name, tid, **kwargs):
|
def create_iscsi_target(self, name, tid, lun, path, **kwargs):
|
||||||
self._run('--op', 'new',
|
try:
|
||||||
'--lld=iscsi', '--mode=target',
|
if not os.path.exists(FLAGS.volumes_dir):
|
||||||
'--tid=%s' % tid,
|
os.makedirs(FLAGS.volumes_dir)
|
||||||
'--targetname=%s' % name,
|
|
||||||
**kwargs)
|
|
||||||
self._run('--op', 'bind',
|
|
||||||
'--lld=iscsi', '--mode=target',
|
|
||||||
'--initiator-address=ALL',
|
|
||||||
'--tid=%s' % tid,
|
|
||||||
**kwargs)
|
|
||||||
|
|
||||||
def delete_target(self, tid, **kwargs):
|
# grab the volume id
|
||||||
self._run('--op', 'delete',
|
vol_id = name.split(':')[1]
|
||||||
'--lld=iscsi', '--mode=target',
|
|
||||||
'--tid=%s' % tid,
|
volume_conf = """
|
||||||
**kwargs)
|
<target %s>
|
||||||
|
backing-store %s
|
||||||
|
</target>
|
||||||
|
""" % (name, path)
|
||||||
|
|
||||||
|
LOG.info(_('Creating volume: %s') % vol_id)
|
||||||
|
volume_path = os.path.join(FLAGS.volumes_dir, vol_id)
|
||||||
|
if not os.path.isfile(volume_path):
|
||||||
|
f = open(volume_path, 'w+')
|
||||||
|
f.write(volume_conf)
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
self._execute('tgt-admin', '--execute',
|
||||||
|
'--conf %s' % volume_path,
|
||||||
|
'--update %s' % vol_id, run_as_root=True)
|
||||||
|
|
||||||
|
except Exception as ex:
|
||||||
|
LOG.exception(ex)
|
||||||
|
raise exception.Error(_('Failed to create volume: %s')
|
||||||
|
% vol_id)
|
||||||
|
|
||||||
|
def remove_iscsi_target(self, tid, lun, vol_id, **kwargs):
|
||||||
|
try:
|
||||||
|
LOG.info(_('Removing volume: %s') % vol_id)
|
||||||
|
vol_uuid_file = 'volume-%s' % vol_id
|
||||||
|
volume_path = os.path.join(FLAGS.volumes_dir, vol_uuid_file)
|
||||||
|
if os.path.isfile(volume_path):
|
||||||
|
delete_file = '%s%s' % (FLAGS.iscsi_target_prefix,
|
||||||
|
vol_uuid_file)
|
||||||
|
self._execute('tgt-admin',
|
||||||
|
'--delete',
|
||||||
|
delete_file,
|
||||||
|
run_as_root=True)
|
||||||
|
os.unlink(volume_path)
|
||||||
|
except Exception as ex:
|
||||||
|
LOG.exception(ex)
|
||||||
|
raise exception.Error(_('Failed to remove volume: %s')
|
||||||
|
% vol_id)
|
||||||
|
|
||||||
def show_target(self, tid, **kwargs):
|
def show_target(self, tid, **kwargs):
|
||||||
self._run('--op', 'show',
|
self._run('--op', 'show',
|
||||||
@@ -101,21 +148,6 @@ class TgtAdm(TargetAdmin):
|
|||||||
'--tid=%s' % tid,
|
'--tid=%s' % tid,
|
||||||
**kwargs)
|
**kwargs)
|
||||||
|
|
||||||
def new_logicalunit(self, tid, lun, path, **kwargs):
|
|
||||||
self._run('--op', 'new',
|
|
||||||
'--lld=iscsi', '--mode=logicalunit',
|
|
||||||
'--tid=%s' % tid,
|
|
||||||
'--lun=%d' % (lun + 1), # lun0 is reserved
|
|
||||||
'--backing-store=%s' % path,
|
|
||||||
**kwargs)
|
|
||||||
|
|
||||||
def delete_logicalunit(self, tid, lun, **kwargs):
|
|
||||||
self._run('--op', 'delete',
|
|
||||||
'--lld=iscsi', '--mode=logicalunit',
|
|
||||||
'--tid=%s' % tid,
|
|
||||||
'--lun=%d' % (lun + 1),
|
|
||||||
**kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class IetAdm(TargetAdmin):
|
class IetAdm(TargetAdmin):
|
||||||
"""iSCSI target administration using ietadm."""
|
"""iSCSI target administration using ietadm."""
|
||||||
@@ -123,13 +155,22 @@ class IetAdm(TargetAdmin):
|
|||||||
def __init__(self, execute=utils.execute):
|
def __init__(self, execute=utils.execute):
|
||||||
super(IetAdm, self).__init__('ietadm', execute)
|
super(IetAdm, self).__init__('ietadm', execute)
|
||||||
|
|
||||||
def new_target(self, name, tid, **kwargs):
|
def create_iscsi_target(self, name, tid, lun, path, **kwargs):
|
||||||
self._run('--op', 'new',
|
self._new_target(name, tid, **kwargs)
|
||||||
'--tid=%s' % tid,
|
self._new_logicalunit(tid, lun, path, **kwargs)
|
||||||
'--params', 'Name=%s' % name,
|
|
||||||
**kwargs)
|
|
||||||
|
|
||||||
def delete_target(self, tid, **kwargs):
|
def remove_iscsi_target(self, tid, lun, vol_id, **kwargs):
|
||||||
|
LOG.info(_('Removing volume: %s') % vol_id)
|
||||||
|
self._delete_target(tid, **kwargs)
|
||||||
|
self._delete_logicalunit(tid, lun, **kwargs)
|
||||||
|
|
||||||
|
def _new_target(self, name, tid, **kwargs):
|
||||||
|
self._run('--op', 'new',
|
||||||
|
'--tid=%s' % tid,
|
||||||
|
'--params', 'Name=%s' % name,
|
||||||
|
**kwargs)
|
||||||
|
|
||||||
|
def _delete_target(self, tid, **kwargs):
|
||||||
self._run('--op', 'delete',
|
self._run('--op', 'delete',
|
||||||
'--tid=%s' % tid,
|
'--tid=%s' % tid,
|
||||||
**kwargs)
|
**kwargs)
|
||||||
@@ -139,14 +180,14 @@ class IetAdm(TargetAdmin):
|
|||||||
'--tid=%s' % tid,
|
'--tid=%s' % tid,
|
||||||
**kwargs)
|
**kwargs)
|
||||||
|
|
||||||
def new_logicalunit(self, tid, lun, path, **kwargs):
|
def _new_logicalunit(self, tid, lun, path, **kwargs):
|
||||||
self._run('--op', 'new',
|
self._run('--op', 'new',
|
||||||
'--tid=%s' % tid,
|
'--tid=%s' % tid,
|
||||||
'--lun=%d' % lun,
|
'--lun=%d' % lun,
|
||||||
'--params', 'Path=%s,Type=fileio' % path,
|
'--params', 'Path=%s,Type=fileio' % path,
|
||||||
**kwargs)
|
**kwargs)
|
||||||
|
|
||||||
def delete_logicalunit(self, tid, lun, **kwargs):
|
def _delete_logicalunit(self, tid, lun, **kwargs):
|
||||||
self._run('--op', 'delete',
|
self._run('--op', 'delete',
|
||||||
'--tid=%s' % tid,
|
'--tid=%s' % tid,
|
||||||
'--lun=%d' % lun,
|
'--lun=%d' % lun,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
# nova/volume/iscsi.py: iscsi_helper '--op' ...
|
# nova/volume/iscsi.py: iscsi_helper '--op' ...
|
||||||
ietadm: CommandFilter, /usr/sbin/ietadm, root
|
ietadm: CommandFilter, /usr/sbin/ietadm, root
|
||||||
tgtadm: CommandFilter, /usr/sbin/tgtadm, root
|
tgtadm: CommandFilter, /usr/sbin/tgtadm, root
|
||||||
|
tgt-admin: CommandFilter, /usr/sbin/tgt-admin, root
|
||||||
|
|
||||||
# nova/volume/driver.py: 'vgs', '--noheadings', '-o', 'name'
|
# nova/volume/driver.py: 'vgs', '--noheadings', '-o', 'name'
|
||||||
vgs: CommandFilter, /sbin/vgs, root
|
vgs: CommandFilter, /sbin/vgs, root
|
||||||
|
|||||||
Reference in New Issue
Block a user