self.assertEqual(CONNECTOR['host'],
self.driver._get_igroup(VOLUME, CONNECTOR))
- def test_wait_for_export_config(self):
- """Queries to cluster nodes verify export config."""
- bn = "/vshare/config/export/container/myContainer/lun/%s" \
+ def test_wait_for_export_state(self):
+ """Queries to cluster nodes verify export state."""
+ bn = "/vshare/state/local/container/myContainer/lun/%s/usn_id" \
% VOLUME['id']
- response = {'/vshare/config/export/container/myContainer/lun/vol-01':
- VOLUME['id']}
+ response = {bn: '012345'}
conf = {
'basic.get_node_values.return_value': response,
self.driver.mga = self.setup_mock_vshare(m_conf=conf)
self.driver.mgb = self.setup_mock_vshare(m_conf=conf)
- result = self.driver._wait_for_export_config(VOLUME['id'], state=True)
+ result = self.driver._wait_for_export_state(VOLUME['id'], state=True)
self.driver.mga.basic.get_node_values.assert_called_with(bn)
self.driver.mgb.basic.get_node_values.assert_called_with(bn)
self.assertTrue(result)
- def test_wait_for_export_config_with_no_config(self):
- """Queries to cluster nodes verify *no* export config."""
- response = {}
+ def test_wait_for_export_state_with_no_state(self):
+ """Queries to cluster nodes verify *no* export state."""
+ bn = "/vshare/state/local/container/myContainer/lun/%s/usn_id" \
+ % VOLUME['id']
+ response = {bn: '(not exported)'}
conf = {
'basic.get_node_values.return_value': response,
self.driver.mga = self.setup_mock_vshare(m_conf=conf)
self.driver.mgb = self.setup_mock_vshare(m_conf=conf)
- self.assertTrue(self.driver._wait_for_export_config(
+ self.assertTrue(self.driver._wait_for_export_state(
VOLUME['id'], state=False))
def test_is_supported_vmos_version(self):
self.driver.common._send_cmd_and_verify.assert_called_with(
self.driver.common.vip.lun.export_lun,
- self.driver.common._wait_for_export_config, '',
+ self.driver.common._wait_for_export_state, '',
[self.driver.common.container, VOLUME['id'], 'all',
- igroup, 'auto'], [VOLUME['id'], 'state=True'])
+ igroup, 'auto'], [VOLUME['id'], None, True])
self.driver.common._get_lun_id.assert_called_with(VOLUME['id'])
self.assertEqual(lun_id, result)
self.driver.common._send_cmd_and_verify.assert_called_with(
self.driver.common.vip.lun.unexport_lun,
- self.driver.common._wait_for_export_config, '',
+ self.driver.common._wait_for_export_state, '',
[self.driver.common.container, VOLUME['id'], 'all', 'all', 'auto'],
- [VOLUME['id'], 'state=False'])
+ [VOLUME['id'], None, False])
self.assertTrue(result is None)
def test_unexport_lun_fails_with_exception(self):
self.driver.common.vip = self.setup_mock_vshare()
self.driver.common._send_cmd = mock.Mock(return_value=response)
- self.driver.common._wait_for_export_config = mock.Mock()
+ self.driver.common._wait_for_export_state = mock.Mock()
self.driver.common._get_snapshot_id = mock.Mock(return_value=lun_id)
result = self.driver._export_snapshot(SNAPSHOT, CONNECTOR, igroup)
self.driver.common.vip.snapshot.export_lun_snapshot, '',
self.driver.common.container, SNAPSHOT['volume_id'],
SNAPSHOT['id'], igroup, 'all', 'auto')
- self.driver.common._wait_for_export_config.assert_called_with(
+ self.driver.common._wait_for_export_state.assert_called_with(
SNAPSHOT['volume_id'], SNAPSHOT['id'], state=True)
self.driver.common._get_snapshot_id.assert_called_once_with(
SNAPSHOT['volume_id'], SNAPSHOT['id'])
self.driver.common.vip = self.setup_mock_vshare()
self.driver.common._send_cmd = mock.Mock(return_value=response)
- self.driver.common._wait_for_export_config = mock.Mock()
+ self.driver.common._wait_for_export_state = mock.Mock()
result = self.driver._unexport_snapshot(SNAPSHOT)
self.driver.common.vip.snapshot.unexport_lun_snapshot, '',
self.driver.common.container, SNAPSHOT['volume_id'],
SNAPSHOT['id'], 'all', 'all', 'auto', False)
- self.driver.common._wait_for_export_config.assert_called_with(
+ self.driver.common._wait_for_export_state.assert_called_with(
SNAPSHOT['volume_id'], SNAPSHOT['id'], state=False)
self.assertTrue(result is None)
def test_initialize_connection(self):
lun_id = 1
igroup = None
+ target_name = self.driver.TARGET_GROUP_NAME
tgt = self.driver.array_info[0]
iqn = "%s%s:%s" % (self.conf.iscsi_target_prefix,
- tgt['node'], VOLUME['id'])
+ tgt['node'], target_name)
volume = mock.MagicMock(spec=models.Volume)
def getitem(name):
volume.__getitem__.side_effect = getitem
self.driver.common.vip = self.setup_mock_vshare()
- self.driver._get_short_name = mock.Mock(return_value=VOLUME['id'])
- self.driver._create_iscsi_target = mock.Mock(return_value=tgt)
+ self.driver._get_iscsi_target = mock.Mock(return_value=tgt)
self.driver._export_lun = mock.Mock(return_value=lun_id)
props = self.driver.initialize_connection(volume, CONNECTOR)
- self.driver._get_short_name.assert_called_with(volume['id'])
- self.driver._create_iscsi_target.assert_called_with(volume)
- self.driver._export_lun.assert_called_with(volume, CONNECTOR, igroup)
+ self.driver._get_iscsi_target.assert_called_once_with()
+ self.driver._export_lun.assert_called_once_with(
+ volume, CONNECTOR, igroup)
self.driver.common.vip.basic.save_config.assert_called_with()
self.assertEqual("1.2.3.4:3260", props['data']['target_portal'])
self.assertEqual(iqn, props['data']['target_iqn'])
def test_initialize_connection_with_snapshot_object(self):
lun_id = 1
igroup = None
+ target_name = self.driver.TARGET_GROUP_NAME
tgt = self.driver.array_info[0]
iqn = "%s%s:%s" % (self.conf.iscsi_target_prefix,
- tgt['node'], SNAPSHOT['id'])
+ tgt['node'], target_name)
snapshot = mock.MagicMock(spec=models.Snapshot)
def getitem(name):
snapshot.__getitem__.side_effect = getitem
self.driver.common.vip = self.setup_mock_vshare()
- self.driver._get_short_name = mock.Mock(return_value=SNAPSHOT['id'])
- self.driver._create_iscsi_target = mock.Mock(return_value=tgt)
+ self.driver._get_iscsi_target = mock.Mock(return_value=tgt)
self.driver._export_snapshot = mock.Mock(return_value=lun_id)
props = self.driver.initialize_connection(snapshot, CONNECTOR)
- self.driver._get_short_name.assert_called_with(SNAPSHOT['id'])
- self.driver._create_iscsi_target.assert_called_with(snapshot)
- self.driver._export_snapshot.assert_called_with(snapshot, CONNECTOR,
- igroup)
+ self.driver._get_iscsi_target.assert_called_once_with()
+ self.driver._export_snapshot.assert_called_once_with(
+ snapshot, CONNECTOR, igroup)
self.driver.common.vip.basic.save_config.assert_called_with()
self.assertEqual("1.2.3.4:3260", props['data']['target_portal'])
self.assertEqual(iqn, props['data']['target_iqn'])
self.conf.use_igroups = True
lun_id = 1
igroup = 'test-igroup-1'
+ target_name = self.driver.TARGET_GROUP_NAME
tgt = self.driver.array_info[0]
iqn = "%s%s:%s" % (self.conf.iscsi_target_prefix,
- tgt['node'], VOLUME['id'])
+ tgt['node'], target_name)
volume = mock.MagicMock(spec=models.Volume)
def getitem(name):
self.driver.common.vip = self.setup_mock_vshare()
self.driver.common._get_igroup = mock.Mock(return_value=igroup)
self.driver._add_igroup_member = mock.Mock()
- self.driver._get_short_name = mock.Mock(return_value=VOLUME['id'])
- self.driver._create_iscsi_target = mock.Mock(return_value=tgt)
+ self.driver._get_iscsi_target = mock.Mock(return_value=tgt)
self.driver._export_lun = mock.Mock(return_value=lun_id)
props = self.driver.initialize_connection(volume, CONNECTOR)
- self.driver.common._get_igroup.assert_called_with(volume, CONNECTOR)
- self.driver._add_igroup_member.assert_called_with(CONNECTOR, igroup)
- self.driver._get_short_name.assert_called_with(volume['id'])
- self.driver._create_iscsi_target.assert_called_with(volume)
- self.driver._export_lun.assert_called_with(volume, CONNECTOR, igroup)
- self.driver.common.vip.basic.save_config.assert_called_with()
+ self.driver.common._get_igroup.assert_called_once_with(
+ volume, CONNECTOR)
+ self.driver._add_igroup_member.assert_called_once_with(
+ CONNECTOR, igroup)
+ self.driver._get_iscsi_target.assert_called_once_with()
+ self.driver._export_lun.assert_called_once_with(
+ volume, CONNECTOR, igroup)
+ self.driver.common.vip.basic.save_config.assert_called_once_with()
self.assertEqual("1.2.3.4:3260", props['data']['target_portal'])
self.assertEqual(iqn, props['data']['target_iqn'])
self.assertEqual(lun_id, props['data']['target_lun'])
self.driver.common.vip = self.setup_mock_vshare()
self.driver._unexport_lun = mock.Mock()
- self.driver._delete_iscsi_target = mock.Mock()
result = self.driver.terminate_connection(volume, CONNECTOR)
- self.driver._unexport_lun.assert_called_with(volume)
- self.driver._delete_iscsi_target.assert_called_with(volume)
+ self.driver._unexport_lun.assert_called_once_with(volume)
self.driver.common.vip.basic.save_config.assert_called_with()
self.assertTrue(result is None)
self.driver.common.vip = self.setup_mock_vshare()
self.driver._unexport_snapshot = mock.Mock()
- self.driver._delete_iscsi_target = mock.Mock()
result = self.driver.terminate_connection(snapshot, CONNECTOR)
- self.driver._unexport_snapshot.assert_called_with(snapshot)
- self.driver._delete_iscsi_target.assert_called_with(snapshot)
+ self.driver._unexport_snapshot.assert_called_once_with(snapshot)
self.driver.common.vip.basic.save_config.assert_called_with()
self.assertTrue(result is None)
self.driver._update_stats.assert_called_with()
self.assertEqual(self.driver.stats, result)
- def test_create_iscsi_target(self):
- target_name = VOLUME['id']
- response = {'code': 0, 'message': 'success'}
+ def test_create_iscsi_target_group(self):
+ target_name = self.driver.TARGET_GROUP_NAME
+ bn = "/vshare/config/iscsi/target/%s" % target_name
+ response1 = {}
+ response2 = {'code': 0, 'message': 'success'}
- m_vshare = self.setup_mock_vshare()
+ conf = {
+ 'basic.get_node_values.return_value': response1,
+ }
+ m_vshare = self.setup_mock_vshare(conf)
self.driver.common.vip = m_vshare
self.driver.common.mga = m_vshare
self.driver.common.mgb = m_vshare
- self.driver._get_short_name = mock.Mock(return_value=VOLUME['id'])
self.driver.common._send_cmd_and_verify = mock.Mock(
- return_value=response)
- self.driver.common._send_cmd = mock.Mock(return_value=response)
+ return_value=response2)
+ self.driver.common._send_cmd = mock.Mock(return_value=response2)
calls = [mock.call(self.driver.common.mga.iscsi.bind_ip_to_target, '',
- VOLUME['id'],
+ target_name,
self.driver.gateway_iscsi_ip_addresses_mga),
mock.call(self.driver.common.mgb.iscsi.bind_ip_to_target, '',
- VOLUME['id'],
+ target_name,
self.driver.gateway_iscsi_ip_addresses_mgb)]
- result = self.driver._create_iscsi_target(VOLUME)
+ result = self.driver._create_iscsi_target_group()
- self.driver._get_short_name.assert_called_with(VOLUME['id'])
+ self.driver.common.vip.basic.get_node_values.assert_called_with(bn)
self.driver.common._send_cmd_and_verify.assert_called_with(
self.driver.common.vip.iscsi.create_iscsi_target,
- self.driver._wait_for_targetstate, '',
+ self.driver._wait_for_target_state, '',
[target_name], [target_name])
self.driver.common._send_cmd.assert_has_calls(calls)
- self.assertTrue(result in self.driver.array_info)
-
- def test_delete_iscsi_target(self):
- response = {'code': 0, 'message': 'success'}
-
- self.driver.common.vip = self.setup_mock_vshare()
- self.driver._get_short_name = mock.Mock(return_value=VOLUME['id'])
- self.driver.common._send_cmd = mock.Mock(return_value=response)
-
- result = self.driver._delete_iscsi_target(VOLUME)
-
- self.driver._get_short_name.assert_called_with(VOLUME['id'])
- self.driver.common._send_cmd(
- self.driver.common.vip.iscsi.delete_iscsi_target,
- '', VOLUME['id'])
self.assertTrue(result is None)
- def test_delete_iscsi_target_fails_with_exception(self):
- response = {'code': 14000, 'message': 'Generic error'}
- failure = exception.ViolinBackendErr
-
- self.driver.common.vip = self.setup_mock_vshare()
- self.driver._get_short_name = mock.Mock(return_value=VOLUME['id'])
- self.driver.common._send_cmd = mock.Mock(
- side_effect=failure(response['message']))
-
- self.assertRaises(failure, self.driver._delete_iscsi_target, VOLUME)
-
def test_export_lun(self):
+ target_name = self.driver.TARGET_GROUP_NAME
igroup = 'test-igroup-1'
lun_id = '1'
response = {'code': 0, 'message': ''}
self.driver.common.vip = self.setup_mock_vshare()
- self.driver._get_short_name = mock.Mock(return_value=VOLUME['id'])
self.driver.common._send_cmd_and_verify = mock.Mock(
return_value=response)
self.driver.common._get_lun_id = mock.Mock(return_value=lun_id)
result = self.driver._export_lun(VOLUME, CONNECTOR, igroup)
- self.driver._get_short_name.assert_called_with(VOLUME['id'])
self.driver.common._send_cmd_and_verify.assert_called_with(
self.driver.common.vip.lun.export_lun,
- self.driver.common._wait_for_export_config, '',
- [self.driver.common.container, VOLUME['id'], VOLUME['id'],
- igroup, 'auto'], [VOLUME['id'], 'state=True'])
+ self.driver.common._wait_for_export_state, '',
+ [self.driver.common.container, VOLUME['id'], target_name,
+ igroup, 'auto'], [VOLUME['id'], None, True])
self.driver.common._get_lun_id.assert_called_with(VOLUME['id'])
self.assertEqual(lun_id, result)
failure = exception.ViolinBackendErr
self.driver.common.vip = self.setup_mock_vshare()
- self.driver._get_short_name = mock.Mock(return_value=VOLUME['id'])
self.driver.common._send_cmd_and_verify = mock.Mock(
side_effect=failure(response['message']))
self.driver._get_lun_id = mock.Mock(return_value=lun_id)
self.driver.common._send_cmd_and_verify.assert_called_with(
self.driver.common.vip.lun.unexport_lun,
- self.driver.common._wait_for_export_config, '',
+ self.driver.common._wait_for_export_state, '',
[self.driver.common.container, VOLUME['id'], 'all', 'all', 'auto'],
- [VOLUME['id'], 'state=False'])
+ [VOLUME['id'], None, False])
self.assertTrue(result is None)
def test_unexport_lun_fails_with_exception(self):
def test_export_snapshot(self):
lun_id = '1'
+ target_name = self.driver.TARGET_GROUP_NAME
igroup = 'test-igroup-1'
response = {'code': 0, 'message': ''}
self.driver.common.vip = self.setup_mock_vshare()
- self.driver._get_short_name = mock.Mock(return_value=SNAPSHOT['id'])
self.driver.common._send_cmd = mock.Mock(return_value=response)
- self.driver.common._wait_for_export_config = mock.Mock()
+ self.driver.common._wait_for_export_state = mock.Mock()
self.driver.common._get_snapshot_id = mock.Mock(return_value=lun_id)
result = self.driver._export_snapshot(SNAPSHOT, CONNECTOR, igroup)
- self.driver._get_short_name.assert_called_with(SNAPSHOT['id'])
self.driver.common._send_cmd.assert_called_with(
self.driver.common.vip.snapshot.export_lun_snapshot, '',
self.driver.common.container, SNAPSHOT['volume_id'],
- SNAPSHOT['id'], igroup, SNAPSHOT['id'], 'auto')
- self.driver.common._wait_for_export_config.assert_called_with(
+ SNAPSHOT['id'], igroup, target_name, 'auto')
+ self.driver.common._wait_for_export_state.assert_called_with(
SNAPSHOT['volume_id'], SNAPSHOT['id'], state=True)
self.driver.common._get_snapshot_id.assert_called_once_with(
SNAPSHOT['volume_id'], SNAPSHOT['id'])
self.driver.common.vip = self.setup_mock_vshare()
self.driver.common._send_cmd = mock.Mock(return_value=response)
- self.driver.common._wait_for_export_config = mock.Mock()
+ self.driver.common._wait_for_export_state = mock.Mock()
result = self.driver._unexport_snapshot(SNAPSHOT)
self.driver.common.vip.snapshot.unexport_lun_snapshot, '',
self.driver.common.container, SNAPSHOT['volume_id'],
SNAPSHOT['id'], 'all', 'all', 'auto', False)
- self.driver.common._wait_for_export_config.assert_called_with(
+ self.driver.common._wait_for_export_state.assert_called_with(
SNAPSHOT['volume_id'], SNAPSHOT['id'], state=False)
self.assertTrue(result is None)
self.assertEqual(self.conf.san_ip, self.driver._get_hostname())
- def test_wait_for_targetstate(self):
+ def test_wait_for_target_state(self):
target = 'mytarget'
- bn = "/vshare/config/iscsi/target/%s" % target
+ bn = "/vshare/state/local/target/iscsi/%s" % target
response = {bn: target}
conf = {
self.driver.common.mga = self.setup_mock_vshare(m_conf=conf)
self.driver.common.mgb = self.setup_mock_vshare(m_conf=conf)
- result = self.driver._wait_for_targetstate(target)
+ result = self.driver._wait_for_target_state(target)
self.driver.common.mga.basic.get_node_values.assert_called_with(bn)
self.driver.common.mgb.basic.get_node_values.assert_called_with(bn)
LOG.info(_LI("Running with vmemclient version: %s."),
vmemclient.__version__)
-# version vmos versions V6.3.0.4 or newer
VMOS_SUPPORTED_VERSION_PATTERNS = ['V6.3.0.[4-9]', 'V6.3.[1-9].?[0-9]?']
violin_opts = [
Version history:
1.0 - Initial driver
+ 1.0.1 - Fixes polling for export completion
"""
- VERSION = '1.0'
+ VERSION = '1.0.1'
def __init__(self, config):
self.vip = None
return igroup_name
- def _wait_for_export_config(self, volume_name, snapshot_name=None,
- state=False):
- """Polls backend to verify volume's export configuration.
+ def _wait_for_export_state(self, volume_name, snapshot_name=None,
+ state=False):
+ """Polls backend to verify volume's export state.
XG sets/queries following a request to create or delete a lun
export may fail on the backend if vshared is still processing
(depending on 'state' param)
"""
if not snapshot_name:
- bn = "/vshare/config/export/container/%s/lun/%s" \
+ bn = "/vshare/state/local/container/%s/lun/%s/usn_id" \
% (self.container, volume_name)
else:
- bn = "/vshare/config/export/snapshot/container/%s/lun/%s/snap/%s" \
+ bn = "/vshare/state/snapshot/container/%s/lun/%s/snap/%s/usn_id" \
% (self.container, volume_name, snapshot_name)
def _loop_func(state):
status = [False, False]
mg_conns = [self.mga, self.mgb]
- LOG.debug("Entering _wait_for_export_config loop: state=%s.",
+ LOG.debug("Entering _wait_for_export_state loop: state=%s.",
state)
+ # TODO(rlucio): May need to handle situations where export
+ # fails, i.e., HBAs go offline and the array is in
+ # degraded mode.
+ #
for node_id in range(2):
resp = mg_conns[node_id].basic.get_node_values(bn)
- if state and len(resp.keys()):
- status[node_id] = True
- elif (not state) and (not len(resp.keys())):
- status[node_id] = True
+
+ if state:
+ # Verify export was added. Validates when the usn_id is
+ # altered to a non-default binding string.
+ #
+ if resp[bn] != "(not exported)":
+ status[node_id] = True
+ else:
+ # Verify export was removed. Validates when the usn_id is
+ # reset to the default binding string.
+ #
+ if resp[bn] == "(not exported)":
+ status[node_id] = True
if status[0] and status[1]:
+ LOG.debug("_wait_for_export_state loopingcall complete.")
raise loopingcall.LoopingCallDone(retvalue=True)
timer = loopingcall.FixedIntervalLoopingCall(_loop_func, state)
Version history:
1.0 - Initial driver
+ 1.0.1 - Fixes polling for export completion
"""
- VERSION = '1.0'
+ VERSION = '1.0.1'
def __init__(self, *args, **kwargs):
super(V6000FCDriver, self).__init__(*args, **kwargs)
try:
self.common._send_cmd_and_verify(
- v.lun.export_lun, self.common._wait_for_export_config, '',
+ v.lun.export_lun, self.common._wait_for_export_state, '',
[self.common.container, volume['id'], 'all', export_to,
- 'auto'], [volume['id'], 'state=True'])
+ 'auto'], [volume['id'], None, True])
except Exception:
LOG.exception(_LE("LUN export for %s failed!"), volume['id'])
try:
self.common._send_cmd_and_verify(
- v.lun.unexport_lun, self.common._wait_for_export_config, '',
+ v.lun.unexport_lun, self.common._wait_for_export_state, '',
[self.common.container, volume['id'], 'all', 'all', 'auto'],
- [volume['id'], 'state=False'])
+ [volume['id'], None, False])
except exception.ViolinBackendErrNotFound:
LOG.debug("Lun %s already unexported, continuing.", volume['id'])
raise
else:
- self.common._wait_for_export_config(snapshot['volume_id'],
- snapshot['id'], state=True)
+ self.common._wait_for_export_state(snapshot['volume_id'],
+ snapshot['id'], state=True)
lun_id = self.common._get_snapshot_id(snapshot['volume_id'],
snapshot['id'])
raise
else:
- self.common._wait_for_export_config(snapshot['volume_id'],
- snapshot['id'], state=False)
+ self.common._wait_for_export_state(snapshot['volume_id'],
+ snapshot['id'], state=False)
def _add_igroup_member(self, connector, igroup):
"""Add an initiator to the openstack igroup so it can see exports.
Version history:
1.0 - Initial driver
+ 1.0.1 - Fixes polling for export completion
"""
- VERSION = '1.0'
+ VERSION = '1.0.1'
+ TARGET_GROUP_NAME = 'openstack'
def __init__(self, *args, **kwargs):
super(V6000ISCSIDriver, self).__init__(*args, **kwargs)
"addr": ip,
"conn": self.common.mgb})
+ # setup global target group for exports to use
+ self._create_iscsi_target_group()
+
def check_for_setup_error(self):
"""Returns an error if prerequisites aren't met."""
self.common.check_for_setup_error()
igroup = self.common._get_igroup(volume, connector)
self._add_igroup_member(connector, igroup)
- vol = self._get_short_name(volume['id'])
- tgt = self._create_iscsi_target(volume)
+ tgt = self._get_iscsi_target()
+ target_name = self.TARGET_GROUP_NAME
+
if isinstance(volume, models.Volume):
lun = self._export_lun(volume, connector, igroup)
else:
lun = self._export_snapshot(volume, connector, igroup)
iqn = "%s%s:%s" % (self.configuration.iscsi_target_prefix,
- tgt['node'], vol)
+ tgt['node'], target_name)
self.common.vip.basic.save_config()
properties = {}
self._unexport_lun(volume)
else:
self._unexport_snapshot(volume)
- self._delete_iscsi_target(volume)
self.common.vip.basic.save_config()
def get_volume_stats(self, refresh=False):
self._update_stats()
return self.stats
- @utils.synchronized('vmem-export')
- def _create_iscsi_target(self, volume):
+ def _create_iscsi_target_group(self):
"""Creates a new target for use in exporting a lun.
- Openstack does not yet support multipathing. We still create
- HA targets but we pick a single random target for the
- Openstack infrastructure to use. This at least allows us to
- evenly distribute LUN connections across the storage cluster.
+ Create an HA target on the backend that will be used for all
+ lun exports made via this driver.
+
The equivalent CLI commands are "iscsi target create
<target_name>" and "iscsi target bind <target_name> to
<ip_of_mg_eth_intf>".
-
- Arguments:
- volume -- volume object provided by the Manager
-
- Returns:
- reference to randomly selected target object
"""
v = self.common.vip
- target_name = self._get_short_name(volume['id'])
+ target_name = self.TARGET_GROUP_NAME
+
+ bn = "/vshare/config/iscsi/target/%s" % target_name
+ resp = self.common.vip.basic.get_node_values(bn)
+
+ if resp:
+ LOG.debug("iscsi target group %s already exists.", target_name)
+ return
LOG.debug("Creating iscsi target %s.", target_name)
try:
self.common._send_cmd_and_verify(v.iscsi.create_iscsi_target,
- self._wait_for_targetstate,
+ self._wait_for_target_state,
'', [target_name], [target_name])
except Exception:
self.common._send_cmd(self.common.mgb.iscsi.bind_ip_to_target,
'', target_name,
self.gateway_iscsi_ip_addresses_mgb)
+
except Exception:
LOG.exception(_LE("Failed to bind iSCSI targets!"))
raise
- return self.array_info[random.randint(0, len(self.array_info) - 1)]
-
- @utils.synchronized('vmem-export')
- def _delete_iscsi_target(self, volume):
- """Deletes the iscsi target for a lun.
-
- The CLI equivalent is "no iscsi target create <target_name>".
+ def _get_iscsi_target(self):
+ """Get a random target IP for OpenStack to connect to.
- Arguments:
- volume -- volume object provided by the Manager
+ For the non-multipath case we pick a single random target for
+ the Openstack infrastructure to use. This at least allows us
+ to evenly distribute LUN connections across the storage
+ cluster.
"""
- v = self.common.vip
- success_msgs = ['', 'Invalid target']
- target_name = self._get_short_name(volume['id'])
-
- LOG.debug("Deleting iscsi target for %s.", target_name)
-
- try:
- self.common._send_cmd(v.iscsi.delete_iscsi_target,
- success_msgs, target_name)
- except Exception:
- LOG.exception(_LE("Failed to delete iSCSI target!"))
- raise
+ return self.array_info[random.randint(0, len(self.array_info) - 1)]
@utils.synchronized('vmem-export')
def _export_lun(self, volume, connector=None, igroup=None):
else:
raise exception.Error(_("No initiators found, cannot proceed"))
- target_name = self._get_short_name(volume['id'])
+ target_name = self.TARGET_GROUP_NAME
LOG.debug("Exporting lun %s.", volume['id'])
try:
self.common._send_cmd_and_verify(
- v.lun.export_lun, self.common._wait_for_export_config, '',
+ v.lun.export_lun, self.common._wait_for_export_state, '',
[self.common.container, volume['id'], target_name,
- export_to, 'auto'], [volume['id'], 'state=True'])
+ export_to, 'auto'], [volume['id'], None, True])
except Exception:
LOG.exception(_LE("LUN export for %s failed!"), volume['id'])
try:
self.common._send_cmd_and_verify(
- v.lun.unexport_lun, self.common._wait_for_export_config, '',
+ v.lun.unexport_lun, self.common._wait_for_export_state, '',
[self.common.container, volume['id'], 'all', 'all', 'auto'],
- [volume['id'], 'state=False'])
+ [volume['id'], None, False])
except exception.ViolinBackendErrNotFound:
LOG.debug("Lun %s already unexported, continuing.", volume['id'])
export_to = ''
v = self.common.vip
- target_name = self._get_short_name(snapshot['id'])
+ target_name = self.TARGET_GROUP_NAME
LOG.debug("Exporting snapshot %s.", snapshot['id'])
raise
else:
- self.common._wait_for_export_config(snapshot['volume_id'],
- snapshot['id'], state=True)
+ self.common._wait_for_export_state(snapshot['volume_id'],
+ snapshot['id'], state=True)
lun_id = self.common._get_snapshot_id(snapshot['volume_id'],
snapshot['id'])
raise
else:
- self.common._wait_for_export_config(snapshot['volume_id'],
- snapshot['id'], state=False)
+ self.common._wait_for_export_state(snapshot['volume_id'],
+ snapshot['id'], state=False)
def _add_igroup_member(self, connector, igroup):
"""Add an initiator to an igroup so it can see exports.
return hostname
- def _wait_for_targetstate(self, target_name):
+ def _wait_for_target_state(self, target_name):
"""Polls backend to verify an iscsi target configuration.
This function will try to verify the creation of an iscsi
target_name -- name of iscsi target to be polled
Returns:
- True if the export state was correctly added
+ True if the target state was correctly added
"""
- bn = "/vshare/config/iscsi/target/%s" % (target_name)
+ bn = "/vshare/state/local/target/iscsi/%s" % (target_name)
def _loop_func():
status = [False, False]
mg_conns = [self.common.mga, self.common.mgb]
- LOG.debug("Entering _wait_for_targetstate loop: target=%s.",
+ LOG.debug("Entering _wait_for_target_state loop: target=%s.",
target_name)
for node_id in range(2):