# License for the specific language governing permissions and limitations
# under the License.
+import os.path
import string
from cinder import test
self.tid = 1
self.target_name = 'iqn.2011-09.org.foo.bar:blaa'
self.lun = 10
- self.path = '/foo/bar/blaa'
+ self.path = '/foo'
+ self.vol_id = 'blaa'
self.script_template = None
+ self.stubs.Set(os.path, 'isfile', lambda _: True)
+ self.stubs.Set(os, 'unlink', lambda _: '')
def get_script_params(self):
return {'tid': self.tid,
def run_commands(self):
tgtadm = iscsi.get_target_admin()
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.new_logicalunit(self.tid, self.lun, self.path)
- tgtadm.delete_logicalunit(self.tid, self.lun)
- tgtadm.delete_target(self.tid)
+ tgtadm.remove_iscsi_target(self.tid, self.lun, self.vol_id)
def test_target_admin(self):
self.clear_cmds()
super(TgtAdmTestCase, self).setUp()
TargetAdminTestCase.setUp(self)
self.flags(iscsi_helper='tgtadm')
+ self.flags(volumes_dir="./")
self.script_template = "\n".join([
- "tgtadm --op new --lld=iscsi --mode=target --tid=%(tid)s "
- "--targetname=%(target_name)s",
- "tgtadm --op bind --lld=iscsi --mode=target --initiator-address=ALL "
- "--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
+ "tgt-admin --execute --conf ./blaa --update blaa",
+ "tgtadm --op show --lld=iscsi --mode=target --tid=1",
+ "tgt-admin --delete iqn.2010-10.org.openstack:volume-blaa"])
class IetAdmTestCase(test.TestCase, TargetAdminTestCase):
self.flags(iscsi_helper='ietadm')
self.script_template = "\n".join([
"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)d "
+ "ietadm --op new --tid=%(tid)s --lun=%(lun)s "
"--params Path=%(path)s,Type=fileio",
- "ietadm --op delete --tid=%(tid)s --lun=%(lun)d",
- "ietadm --op delete --tid=%(tid)s"])
+ "ietadm --op show --tid=%(tid)s",
+ "ietadm --op delete --tid=%(tid)s",
+ "ietadm --op delete --tid=%(tid)s --lun=%(lun)s"])
Helper code for the iSCSI volume driver.
"""
+import os
+from cinder import exception
from cinder import flags
from cinder.openstack.common import cfg
+from cinder.openstack.common import log as logging
from cinder import utils
+LOG = logging.getLogger(__name__)
-iscsi_helper_opt = cfg.StrOpt('iscsi_helper',
- default='ietadm',
- help='iscsi target user-land tool to use')
+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 configfuration file storage directory'),
+]
FLAGS = flags.FLAGS
-FLAGS.register_opt(iscsi_helper_opt)
+FLAGS.register_opts(iscsi_helper_opt)
class TargetAdmin(object):
def _run(self, *args, **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."""
raise NotImplementedError()
- def delete_target(self, tid, **kwargs):
+ def _delete_target(self, tid, **kwargs):
"""Delete a target."""
raise NotImplementedError()
- def show_target(self, tid, **kwargs):
+ def _show_target(self, tid, **kwargs):
"""Query the given target ID."""
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."""
raise NotImplementedError()
- def delete_logicalunit(self, tid, lun, **kwargs):
+ def _delete_logicalunit(self, tid, lun, **kwargs):
"""Delete a logical unit from a target."""
raise NotImplementedError()
def __init__(self, execute=utils.execute):
super(TgtAdm, self).__init__('tgtadm', execute)
- def new_target(self, name, tid, **kwargs):
- self._run('--op', 'new',
- '--lld=iscsi', '--mode=target',
- '--tid=%s' % tid,
- '--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):
- self._run('--op', 'delete',
- '--lld=iscsi', '--mode=target',
- '--tid=%s' % tid,
- **kwargs)
+ def create_iscsi_target(self, name, tid, lun, path, **kwargs):
+ try:
+ if not os.path.exists(FLAGS.volumes_dir):
+ os.makedirs(FLAGS.volumes_dir)
+
+ # grab the volume id
+ vol_id = name.split(':')[1]
+
+ volume_conf = """
+ <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):
self._run('--op', 'show',
'--tid=%s' % tid,
**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):
"""iSCSI target administration using ietadm."""
def __init__(self, execute=utils.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._new_target(name, tid, **kwargs)
+ self._new_logicalunit(tid, lun, path, **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)
+ '--tid=%s' % tid,
+ '--params', 'Name=%s' % name,
+ **kwargs)
- def delete_target(self, tid, **kwargs):
+ def _delete_target(self, tid, **kwargs):
self._run('--op', 'delete',
'--tid=%s' % tid,
**kwargs)
'--tid=%s' % tid,
**kwargs)
- def new_logicalunit(self, tid, lun, path, **kwargs):
+ def _new_logicalunit(self, tid, lun, path, **kwargs):
self._run('--op', 'new',
'--tid=%s' % tid,
'--lun=%d' % lun,
'--params', 'Path=%s,Type=fileio' % path,
**kwargs)
- def delete_logicalunit(self, tid, lun, **kwargs):
+ def _delete_logicalunit(self, tid, lun, **kwargs):
self._run('--op', 'delete',
'--tid=%s' % tid,
'--lun=%d' % lun,