self.mox.ReplayAll()
result = self.drv.create_volume(TEST_VOLUME)
self.assertEqual(result, {
- 'provider_location': 'None:3260,None None '
- 'None dev_path'})
+ 'provider_location': 'dev_path'})
def test_update_volume_stats(self):
self.mox.StubOutWithMock(self.drv, '_devices_sizes')
execute=self.drv._execute)
self.mox.ReplayAll()
self.assertEqual(self.drv.create_cloned_volume(TEST_VOLUME, TEST_SRC),
- {'provider_location': 'None:3260,'
- 'None None None /dev/loop2'})
+ {'provider_location': '/dev/loop2'})
def test_copy_image_to_volume(self):
TEST_VOLUME = {'provider_location': '1 2 3 /dev/loop1', 'size': 1}
self.path = '/foo'
self.vol_id = 'blaa'
self.vol_name = 'volume-blaa'
+ self.db = {}
self.script_template = None
self.stubs.Set(os.path, 'isfile', lambda _: True)
self.verify_cmds(cmds)
def run_commands(self):
- target_helper = self.driver.get_target_helper()
+ target_helper = self.driver.get_target_helper(self.db)
target_helper.set_execute(self.fake_execute)
target_helper.create_iscsi_target(self.target_name, self.tid,
self.lun, self.path)
from oslo.config import cfg
-from cinder.brick.iscsi import iscsi
from cinder import exception
from cinder.image import image_utils
from cinder.openstack.common import excutils
from cinder.openstack.common import log as logging
from cinder.openstack.common import processutils
from cinder import utils
+from cinder.volume import iscsi
from cinder.volume import rpcapi as volume_rpcapi
from cinder.volume import utils as volume_utils
data['QoS_support'] = False
self._stats = data
- def get_target_helper(self):
+ def get_target_helper(self, db):
root_helper = utils.get_root_helper()
if CONF.iscsi_helper == 'iseradm':
return iscsi.ISERTgtAdm(root_helper, CONF.volumes_dir,
- CONF.iscsi_target_prefix)
+ CONF.iscsi_target_prefix, db=db)
elif CONF.iscsi_helper == 'tgtadm':
return iscsi.TgtAdm(root_helper,
CONF.volumes_dir,
- CONF.iscsi_target_prefix)
+ CONF.iscsi_target_prefix,
+ db=db)
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)
+ CONF.iscsi_target_prefix, db=db)
else:
- return iscsi.IetAdm(root_helper, CONF.iet_conf, CONF.iscsi_iotype)
+ return iscsi.IetAdm(root_helper, CONF.iet_conf, CONF.iscsi_iotype,
+ db=db)
class FakeISCSIDriver(ISCSIDriver):
data['QoS_support'] = False
self._stats = data
- def get_target_helper(self):
+ def get_target_helper(self, db):
root_helper = utils.get_root_helper()
if CONF.iser_helper == 'fake':
return iscsi.FakeIscsiHelper()
else:
return iscsi.ISERTgtAdm(root_helper,
- CONF.volumes_dir)
+ CONF.volumes_dir, db=db)
class FakeISERDriver(FakeISCSIDriver):
from oslo.config import cfg
-from cinder.brick.iscsi import iscsi
from cinder import context
from cinder.db.sqlalchemy import api
from cinder import exception
from cinder.image import image_utils
from cinder.openstack.common import log as logging
-from cinder import utils
from cinder.volume import driver
from cinder.volume import utils as volutils
VERSION = '1.0.0'
def __init__(self, *args, **kwargs):
- self.target_helper = self.get_target_helper()
-
+ self.target_helper = self.get_target_helper(kwargs.get('db'))
super(BlockDeviceDriver, self).__init__(*args, **kwargs)
self.configuration.append_config_values(volume_opts)
def set_execute(self, execute):
super(BlockDeviceDriver, self).set_execute(execute)
- self.target_helper.set_execute(execute)
+ if self.target_helper is not None:
+ self.target_helper.set_execute(execute)
def check_for_setup_error(self):
pass
device = self.find_appropriate_size_device(volume['size'])
LOG.info("Create %s on %s" % (volume['name'], device))
return {
- 'provider_location': self._iscsi_location(None, None, None, None,
- device),
+ 'provider_location': device,
}
def initialize_connection(self, volume, connector):
def create_export(self, context, volume):
"""Creates an export for a logical volume."""
-
- iscsi_name = "%s%s" % (self.configuration.iscsi_target_prefix,
- volume['name'])
volume_path = self.local_path(volume)
- model_update = {}
-
- # TODO(jdg): In the future move all of the dependent stuff into the
- # corresponding target admin class
- if not isinstance(self.target_helper, iscsi.TgtAdm):
- lun = 0
- self._ensure_iscsi_targets(context, volume['host'])
- iscsi_target = self.db.volume_allocate_iscsi_target(context,
- volume['id'],
- volume['host'])
- else:
- lun = 1 # For tgtadm the controller is lun 0, dev starts at lun 1
- iscsi_target = 0 # NOTE(jdg): Not used by tgtadm
-
- # Use the same method to generate the username and the password.
- chap_username = utils.generate_username()
- chap_password = utils.generate_password()
- chap_auth = self._iscsi_authentication('IncomingUser', chap_username,
- chap_password)
- # NOTE(jdg): For TgtAdm case iscsi_name is the ONLY param we need
- # should clean this all up at some point in the future
- tid = self.target_helper.create_iscsi_target(iscsi_name,
- iscsi_target,
- 0,
- volume_path,
- chap_auth)
- model_update['provider_location'] = self._iscsi_location(
- self.configuration.iscsi_ip_address, tid, iscsi_name, lun,
- volume_path)
- model_update['provider_auth'] = self._iscsi_authentication(
- 'CHAP', chap_username, chap_password)
- return model_update
+ data = self.target_helper.create_export(context, volume, volume_path)
+ return {
+ 'provider_location': data['location'] + ' ' + volume_path,
+ 'provider_auth': data['auth'],
+ }
def remove_export(self, context, volume):
- """Removes an export for a logical volume."""
- # NOTE(jdg): tgtadm doesn't use the iscsi_targets table
- # TODO(jdg): In the future move all of the dependent stuff into the
- # corresponding target admin class
-
- if isinstance(self.target_helper, iscsi.LioAdm):
- try:
- iscsi_target = self.db.volume_get_iscsi_target_num(
- context,
- volume['id'])
- except exception.NotFound:
- LOG.info(_("Skipping remove_export. No iscsi_target "
- "provisioned for volume: %s"), volume['id'])
- return
- self.target_helper.remove_iscsi_target(iscsi_target,
- 0,
- volume['id'],
- volume['name'])
- return
- elif not isinstance(self.target_helper, iscsi.TgtAdm):
- try:
- iscsi_target = self.db.volume_get_iscsi_target_num(
- context,
- volume['id'])
- except exception.NotFound:
- LOG.info(_("Skipping remove_export. No iscsi_target "
- "provisioned for volume: %s"), volume['id'])
- return
- else:
- iscsi_target = 0
- try:
- # NOTE: provider_location may be unset if the volume hasn't
- # been exported
- location = volume['provider_location'].split(' ')
- iqn = location[1]
- # ietadm show will exit with an error
- # this export has already been removed
- self.target_helper.show_target(iscsi_target, iqn=iqn)
- except Exception:
- LOG.info(_("Skipping remove_export. No iscsi_target "
- "is presently exported for volume: %s"), volume['id'])
- return
- self.target_helper.remove_iscsi_target(iscsi_target, 0, volume['id'],
- volume['name'])
+ self.target_helper.remove_export(context, volume)
def ensure_export(self, context, volume):
- """Synchronously recreates an export for a logical volume.
- :param context:
- :param volume:
- """
- # NOTE(jdg): tgtadm doesn't use the iscsi_targets table
- # TODO(jdg): In the future move all of the dependent stuff into the
- # corresponding target admin class
-
- if isinstance(self.target_helper, iscsi.LioAdm):
- try:
- volume_info = self.db.volume_get(context, volume['id'])
- (auth_method,
- auth_user,
- auth_pass) = volume_info['provider_auth'].split(' ', 3)
- chap_auth = self._iscsi_authentication(auth_method,
- auth_user,
- auth_pass)
- except exception.NotFound:
- LOG.debug("volume_info:", volume_info)
- LOG.info(_("Skipping ensure_export. No iscsi_target "
- "provision for volume: %s"), volume['id'])
- return
- iscsi_name = "%s%s" % (self.configuration.iscsi_target_prefix,
- volume['name'])
- volume_path = self.local_path(volume)
- iscsi_target = 1
- self.target_helper.create_iscsi_target(iscsi_name, iscsi_target,
- 0, volume_path, chap_auth,
- check_exit_code=False)
- return
- if not isinstance(self.target_helper, iscsi.TgtAdm):
- try:
- iscsi_target = self.db.volume_get_iscsi_target_num(
- context,
- volume['id'])
- except exception.NotFound:
- LOG.info(_("Skipping ensure_export. No iscsi_target "
- "provisioned for volume: %s"), volume['id'])
- return
- else:
- iscsi_target = 1 # dummy value when using TgtAdm
-
- chap_auth = None
-
- # Check for https://bugs.launchpad.net/cinder/+bug/1065702
- old_name = None
volume_name = volume['name']
iscsi_name = "%s%s" % (self.configuration.iscsi_target_prefix,
# NOTE(jdg): For TgtAdm case iscsi_name is the ONLY param we need
# should clean this all up at some point in the future
- self.target_helper.create_iscsi_target(iscsi_name, iscsi_target,
- 0, volume_path, chap_auth,
- check_exit_code=False,
- old_name=old_name)
-
- def _iscsi_location(self, ip, target, iqn, lun=None, device=None):
- return "%s:%s,%s %s %s %s" % (ip, self.configuration.iscsi_port,
- target, iqn, lun, device)
-
- def _iscsi_authentication(self, chap, name, password):
- return "%s %s %s" % (chap, name, password)
-
- def _ensure_iscsi_targets(self, context, host):
- """Ensure that target ids have been created in datastore."""
- # NOTE(jdg): tgtadm doesn't use the iscsi_targets table
- # TODO(jdg): In the future move all of the dependent stuff into the
- # corresponding target admin class
- if not isinstance(self.target_helper, iscsi.TgtAdm):
- host_iscsi_targets = self.db.iscsi_target_count_by_host(context,
- host)
- if host_iscsi_targets >= self.configuration.iscsi_num_targets:
- return
-
- # NOTE(vish): Target ids start at 1, not 0.
- target_end = self.configuration.iscsi_num_targets + 1
- for target_num in xrange(1, target_end):
- target = {'host': host, 'target_num': target_num}
- self.db.iscsi_target_create_safe(context, target)
+ self.target_helper.ensure_export(context, volume, iscsi_name,
+ volume_path)
def delete_volume(self, volume):
"""Deletes a logical volume."""
def local_path(self, volume):
if volume['provider_location']:
- path = volume['provider_location'].split(" ")
- return path[3]
+ path = volume['provider_location'].rsplit(" ", 1)
+ return path[-1]
else:
return None
self.configuration.volume_dd_blocksize,
execute=self._execute)
return {
- 'provider_location': self._iscsi_location(None, None, None, None,
- device),
+ 'provider_location': device,
}
def get_volume_stats(self, refresh=False):
"""
import os
-import re
import socket
from oslo.config import cfg
from cinder.brick import exception as brick_exception
-from cinder.brick.iscsi import iscsi
from cinder.brick.local_dev import lvm as lvm
from cinder import exception
from cinder.image import image_utils
"""
def __init__(self, *args, **kwargs):
- self.target_helper = self.get_target_helper()
+ self.db = kwargs.get('db')
+ self.target_helper = self.get_target_helper(self.db)
super(LVMISCSIDriver, self).__init__(*args, **kwargs)
self.backend_name =\
self.configuration.safe_get('volume_backend_name') or 'LVM_iSCSI'
def set_execute(self, execute):
super(LVMISCSIDriver, self).set_execute(execute)
- self.target_helper.set_execute(execute)
+ if self.target_helper is not None:
+ self.target_helper.set_execute(execute)
def _create_target(self, iscsi_name, iscsi_target,
volume_path, chap_auth, lun=0,
return tid
def ensure_export(self, context, volume):
- """Synchronously recreates an export for a logical volume."""
- # NOTE(jdg): tgtadm doesn't use the iscsi_targets table
- # TODO(jdg): In the future move all of the dependent stuff into the
- # corresponding target admin class
-
- if isinstance(self.target_helper, iscsi.LioAdm):
- try:
- volume_info = self.db.volume_get(context, volume['id'])
- (auth_method,
- auth_user,
- auth_pass) = volume_info['provider_auth'].split(' ', 3)
- chap_auth = self._iscsi_authentication(auth_method,
- auth_user,
- auth_pass)
- except exception.NotFound:
- LOG.debug(_("volume_info:%s"), volume_info)
- LOG.info(_("Skipping ensure_export. No iscsi_target "
- "provision for volume: %s"), volume['id'])
- return
-
- iscsi_name = "%s%s" % (self.configuration.iscsi_target_prefix,
- volume['name'])
- volume_path = "/dev/%s/%s" % (self.configuration.volume_group,
- volume['name'])
- iscsi_target = 1
-
- self._create_target(iscsi_name, iscsi_target,
- volume_path, chap_auth)
-
- return
-
- if not isinstance(self.target_helper, iscsi.TgtAdm):
- try:
- iscsi_target = self.db.volume_get_iscsi_target_num(
- context,
- volume['id'])
- except exception.NotFound:
- LOG.info(_("Skipping ensure_export. No iscsi_target "
- "provisioned for volume: %s"), volume['id'])
- return
- else:
- iscsi_target = 1 # dummy value when using TgtAdm
-
- chap_auth = None
-
- # Check for https://bugs.launchpad.net/cinder/+bug/1065702
- old_name = None
volume_name = volume['name']
- if (volume['provider_location'] is not None and
- volume['name'] not in volume['provider_location']):
-
- msg = _('Detected inconsistency in provider_location id')
- LOG.debug(_('%s'), msg)
- old_name = self._fix_id_migration(context, volume)
- if 'in-use' in volume['status']:
- volume_name = old_name
- old_name = None
-
iscsi_name = "%s%s" % (self.configuration.iscsi_target_prefix,
volume_name)
volume_path = "/dev/%s/%s" % (self.configuration.volume_group,
volume_name)
-
# NOTE(jdg): For TgtAdm case iscsi_name is the ONLY param we need
# should clean this all up at some point in the future
- self._create_target(iscsi_name, iscsi_target,
- volume_path, chap_auth,
- lun=0,
- check_exit_code=False,
- old_name=old_name)
-
- return
-
- def _fix_id_migration(self, context, volume):
- """Fix provider_location and dev files to address bug 1065702.
-
- For volumes that the provider_location has NOT been updated
- and are not currently in-use we'll create a new iscsi target
- and remove the persist file.
-
- If the volume is in-use, we'll just stick with the old name
- and when detach is called we'll feed back into ensure_export
- again if necessary and fix things up then.
-
- Details at: https://bugs.launchpad.net/cinder/+bug/1065702
- """
-
- model_update = {}
- pattern = re.compile(r":|\s")
- fields = pattern.split(volume['provider_location'])
- old_name = fields[3]
-
- volume['provider_location'] = \
- volume['provider_location'].replace(old_name, volume['name'])
- model_update['provider_location'] = volume['provider_location']
-
- self.db.volume_update(context, volume['id'], model_update)
-
- start = os.getcwd()
- os.chdir('/dev/%s' % self.configuration.volume_group)
-
- try:
- (out, err) = self._execute('readlink', old_name)
- except processutils.ProcessExecutionError:
- link_path = '/dev/%s/%s' % (self.configuration.volume_group,
- old_name)
- LOG.debug(_('Symbolic link %s not found') % link_path)
- os.chdir(start)
- return
-
- rel_path = out.rstrip()
- self._execute('ln',
- '-s',
- rel_path, volume['name'],
- run_as_root=True)
- os.chdir(start)
- return old_name
-
- def _ensure_iscsi_targets(self, context, host):
- """Ensure that target ids have been created in datastore."""
- # NOTE(jdg): tgtadm doesn't use the iscsi_targets table
- # TODO(jdg): In the future move all of the dependent stuff into the
- # corresponding target admin class
- if not isinstance(self.target_helper, iscsi.TgtAdm):
- host_iscsi_targets = self.db.iscsi_target_count_by_host(context,
- host)
- if host_iscsi_targets >= self.configuration.iscsi_num_targets:
- return
-
- # NOTE(vish): Target ids start at 1, not 0.
- target_end = self.configuration.iscsi_num_targets + 1
- for target_num in xrange(1, target_end):
- target = {'host': host, 'target_num': target_num}
- self.db.iscsi_target_create_safe(context, target)
+ model_update = self.target_helper.ensure_export(context, volume,
+ iscsi_name,
+ volume_path)
+ if model_update:
+ self.db.volume_update(context, volume['id'], model_update)
def create_export(self, context, volume):
return self._create_export(context, volume)
if vg is None:
vg = self.configuration.volume_group
- iscsi_name = "%s%s" % (self.configuration.iscsi_target_prefix,
- volume['name'])
volume_path = "/dev/%s/%s" % (vg, volume['name'])
- model_update = {}
-
- # TODO(jdg): In the future move all of the dependent stuff into the
- # corresponding target admin class
- if not isinstance(self.target_helper, iscsi.TgtAdm):
- lun = 0
- self._ensure_iscsi_targets(context, volume['host'])
- iscsi_target = self.db.volume_allocate_iscsi_target(context,
- volume['id'],
- volume['host'])
- else:
- lun = 1 # For tgtadm the controller is lun 0, dev starts at lun 1
- iscsi_target = 0 # NOTE(jdg): Not used by tgtadm
-
- # Use the same method to generate the username and the password.
- chap_username = utils.generate_username()
- chap_password = utils.generate_password()
- chap_auth = self._iscsi_authentication('IncomingUser', chap_username,
- chap_password)
- tid = self._create_target(iscsi_name, iscsi_target,
- volume_path, chap_auth)
-
- model_update['provider_location'] = self._iscsi_location(
- self.configuration.iscsi_ip_address, tid, iscsi_name, lun)
- model_update['provider_auth'] = self._iscsi_authentication(
- 'CHAP', chap_username, chap_password)
- return model_update
+ data = self.target_helper.create_export(context, volume, volume_path)
+ return {
+ 'provider_location': data['location'],
+ 'provider_auth': data['auth'],
+ }
def remove_export(self, context, volume):
- """Removes an export for a logical volume."""
- # NOTE(jdg): tgtadm doesn't use the iscsi_targets table
- # TODO(jdg): In the future move all of the dependent stuff into the
- # corresponding target admin class
-
- if isinstance(self.target_helper, iscsi.LioAdm):
- try:
- iscsi_target = self.db.volume_get_iscsi_target_num(
- context,
- volume['id'])
- except exception.NotFound:
- LOG.info(_("Skipping remove_export. No iscsi_target "
- "provisioned for volume: %s"), volume['id'])
- return
-
- self.target_helper.remove_iscsi_target(iscsi_target,
- 0,
- volume['id'],
- volume['name'])
-
- return
-
- elif not isinstance(self.target_helper, iscsi.TgtAdm):
- try:
- iscsi_target = self.db.volume_get_iscsi_target_num(
- context,
- volume['id'])
- except exception.NotFound:
- LOG.info(_("Skipping remove_export. No iscsi_target "
- "provisioned for volume: %s"), volume['id'])
- return
-
- else:
- iscsi_target = 0
-
- try:
-
- # NOTE: provider_location may be unset if the volume hasn't
- # been exported
- location = volume['provider_location'].split(' ')
- iqn = location[1]
-
- # ietadm show will exit with an error
- # this export has already been removed
- self.target_helper.show_target(iscsi_target, iqn=iqn)
-
- except Exception:
- LOG.info(_("Skipping remove_export. No iscsi_target "
- "is presently exported for volume: %s"), volume['id'])
- return
-
- self.target_helper.remove_iscsi_target(iscsi_target,
- 0,
- volume['name_id'],
- volume['name'])
+ self.target_helper.remove_export(context, volume)
def migrate_volume(self, ctxt, volume, host, thin=False, mirror_count=0):
"""Optimize the migration if the destination is on the same server.
"""
def __init__(self, *args, **kwargs):
- self.target_helper = self.get_target_helper()
+ self.target_helper = self.get_target_helper(kwargs.get('db'))
LVMVolumeDriver.__init__(self, *args, **kwargs)
self.backend_name =\
self.configuration.safe_get('volume_backend_name') or 'LVM_iSER'
--- /dev/null
+# Copyright (c) 2013 Mirantis, Inc.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import os
+import re
+
+from oslo.config import cfg
+
+from cinder.brick import exception
+from cinder.brick.iscsi import iscsi
+from cinder.openstack.common.gettextutils import _
+from cinder.openstack.common import log as logging
+from cinder.openstack.common import processutils as putils
+from cinder import utils
+
+LOG = logging.getLogger(__name__)
+CONF = cfg.CONF
+
+
+class _ExportMixin(object):
+
+ def __init__(self, *args, **kwargs):
+ self.db = kwargs.pop('db', None)
+ super(_ExportMixin, self).__init__(*args, **kwargs)
+
+ def create_export(self, context, volume, volume_path):
+ """Creates an export for a logical volume."""
+ iscsi_name = "%s%s" % (CONF.iscsi_target_prefix,
+ volume['name'])
+ iscsi_target, lun = self._get_target_and_lun(context, volume)
+ chap_username = utils.generate_username()
+ chap_password = utils.generate_password()
+ chap_auth = self._iscsi_authentication('IncomingUser', chap_username,
+ chap_password)
+ # NOTE(jdg): For TgtAdm case iscsi_name is the ONLY param we need
+ # should clean this all up at some point in the future
+ tid = self.create_iscsi_target(iscsi_name,
+ iscsi_target,
+ 0,
+ volume_path,
+ chap_auth)
+ data = {}
+ data['location'] = self._iscsi_location(
+ CONF.iscsi_ip_address, tid, iscsi_name, lun)
+ data['auth'] = self._iscsi_authentication(
+ 'CHAP', chap_username, chap_password)
+ return data
+
+ def remove_export(self, context, volume):
+ try:
+ iscsi_target = self._get_iscsi_target(context, volume['id'])
+ except exception.NotFound:
+ LOG.info(_("Skipping remove_export. No iscsi_target "
+ "provisioned for volume: %s"), volume['id'])
+ return
+ try:
+
+ # NOTE: provider_location may be unset if the volume hasn't
+ # been exported
+ location = volume['provider_location'].split(' ')
+ iqn = location[1]
+
+ # ietadm show will exit with an error
+ # this export has already been removed
+ self.show_target(iscsi_target, iqn=iqn)
+
+ except Exception:
+ LOG.info(_("Skipping remove_export. No iscsi_target "
+ "is presently exported for volume: %s"), volume['id'])
+ return
+
+ self.remove_iscsi_target(iscsi_target, 0, volume['id'], volume['name'])
+
+ def ensure_export(self, context, volume, iscsi_name, volume_path,
+ old_name=None):
+ iscsi_target = self._get_target_for_ensure_export(context,
+ volume['id'])
+ if iscsi_target is None:
+ LOG.info(_("Skipping remove_export. No iscsi_target "
+ "provisioned for volume: %s"), volume['id'])
+ return
+ chap_auth = None
+ # Check for https://bugs.launchpad.net/cinder/+bug/1065702
+ old_name = None
+ if (volume['provider_location'] is not None and
+ volume['name'] not in volume['provider_location']):
+
+ msg = _('Detected inconsistency in provider_location id')
+ LOG.debug(_('%s'), msg)
+ old_name = self._fix_id_migration(context, volume)
+ if 'in-use' in volume['status']:
+ old_name = None
+ self.create_iscsi_target(iscsi_name, iscsi_target, 0, volume_path,
+ chap_auth, check_exit_code=False,
+ old_name=old_name)
+
+ def _ensure_iscsi_targets(self, context, host):
+ """Ensure that target ids have been created in datastore."""
+ # NOTE(jdg): tgtadm doesn't use the iscsi_targets table
+ # TODO(jdg): In the future move all of the dependent stuff into the
+ # cooresponding target admin class
+ host_iscsi_targets = self.db.iscsi_target_count_by_host(context,
+ host)
+ if host_iscsi_targets >= CONF.iscsi_num_targets:
+ return
+
+ # NOTE(vish): Target ids start at 1, not 0.
+ target_end = CONF.iscsi_num_targets + 1
+ for target_num in xrange(1, target_end):
+ target = {'host': host, 'target_num': target_num}
+ self.db.iscsi_target_create_safe(context, target)
+
+ def _get_target_for_ensure_export(self, context, volume_id):
+ try:
+ iscsi_target = self.db.volume_get_iscsi_target_num(context,
+ volume_id)
+ return iscsi_target
+ except exception.NotFound:
+ return None
+
+ def _get_target_and_lun(self, context, volume):
+ lun = 0
+ self._ensure_iscsi_targets(context, volume['host'])
+ iscsi_target = self.db.volume_allocate_iscsi_target(context,
+ volume['id'],
+ volume['host'])
+ return iscsi_target, lun
+
+ def _get_iscsi_target(self, context, vol_id):
+ return self.db.volume_get_iscsi_target_num(context, vol_id)
+
+ def _iscsi_authentication(self, chap, name, password):
+ return "%s %s %s" % (chap, name, password)
+
+ def _iscsi_location(self, ip, target, iqn, lun=None):
+ return "%s:%s,%s %s %s" % (ip, CONF.iscsi_port,
+ target, iqn, lun)
+
+ def _fix_id_migration(self, context, volume):
+ """Fix provider_location and dev files to address bug 1065702.
+
+ For volumes that the provider_location has NOT been updated
+ and are not currently in-use we'll create a new iscsi target
+ and remove the persist file.
+
+ If the volume is in-use, we'll just stick with the old name
+ and when detach is called we'll feed back into ensure_export
+ again if necessary and fix things up then.
+
+ Details at: https://bugs.launchpad.net/cinder/+bug/1065702
+ """
+
+ model_update = {}
+ pattern = re.compile(r":|\s")
+ fields = pattern.split(volume['provider_location'])
+ old_name = fields[3]
+
+ volume['provider_location'] = \
+ volume['provider_location'].replace(old_name, volume['name'])
+ model_update['provider_location'] = volume['provider_location']
+
+ self.db.volume_update(context, volume['id'], model_update)
+
+ start = os.getcwd()
+ os.chdir('/dev/%s' % CONF.volume_group)
+
+ try:
+ (out, err) = self._execute('readlink', old_name)
+ except putils.ProcessExecutionError:
+ link_path = '/dev/%s/%s' % (CONF.volume_group,
+ old_name)
+ LOG.debug(_('Symbolic link %s not found') % link_path)
+ os.chdir(start)
+ return
+
+ rel_path = out.rstrip()
+ self._execute('ln',
+ '-s',
+ rel_path, volume['name'],
+ run_as_root=True)
+ os.chdir(start)
+ return old_name
+
+
+class TgtAdm(_ExportMixin, iscsi.TgtAdm):
+
+ def _get_target_and_lun(self, context, volume):
+ lun = 1 # For tgtadm the controller is lun 0, dev starts at lun 1
+ iscsi_target = 0 # NOTE(jdg): Not used by tgtadm
+ return iscsi_target, lun
+
+ def _get_iscsi_target(self, context, vol_id):
+ return 0
+
+ def _get_target_for_ensure_export(self, context, volume_id):
+ return 1
+
+
+class FakeIscsiHelper(_ExportMixin, iscsi.FakeIscsiHelper):
+
+ def create_export(self, context, volume, volume_path):
+ return {
+ 'location': "fake_location",
+ 'auth': "fake_auth"
+ }
+
+ def remove_export(self, context, volume):
+ pass
+
+ def ensure_export(self, context, volume_id, iscsi_name, volume_path,
+ old_name=None):
+ pass
+
+
+class LioAdm(_ExportMixin, iscsi.LioAdm):
+
+ def remove_export(self, context, volume):
+ try:
+ iscsi_target = self.db.volume_get_iscsi_target_num(context,
+ volume['id'])
+ except exception.NotFound:
+ LOG.info(_("Skipping remove_export. No iscsi_target "
+ "provisioned for volume: %s"), volume['id'])
+ return
+
+ self.remove_iscsi_target(iscsi_target, 0, volume['id'], volume['name'])
+
+ def ensure_export(self, context, volume_id, iscsi_name, volume_path,
+ old_name=None):
+ try:
+ volume_info = self.db.volume_get(context, volume_id)
+ (auth_method,
+ auth_user,
+ auth_pass) = volume_info['provider_auth'].split(' ', 3)
+ chap_auth = self._iscsi_authentication(auth_method,
+ auth_user,
+ auth_pass)
+ except exception.NotFound:
+ LOG.debug(_("volume_info:%s"), volume_info)
+ LOG.info(_("Skipping ensure_export. No iscsi_target "
+ "provision for volume: %s"), volume_id)
+
+ iscsi_target = 1
+
+ self.create_iscsi_target(iscsi_name, iscsi_target, 0, volume_path,
+ chap_auth, check_exit_code=False)
+
+
+class IetAdm(_ExportMixin, iscsi.IetAdm):
+ pass
+
+
+class ISERTgtAdm(_ExportMixin, iscsi.ISERTgtAdm):
+ pass