Recover node.startup values after discovering
os_brick updates node.startup values from default value to "automatic" when it creates iscsi connection. But existing target's node.startup values will be reverted from "automatic" to default value in creating iscsi connection process if multipath is used. When using multipath with a discovery type of backend, the "iscsiadm -m discovery -t sendtargets -p ..." command will recreate all target information of specified node.[1] node.startup value wil be reverted to default value of existing targets by recreating. As a result, "automatic" targets and default value targets will be mixed on the host. So this patch recovers node.startup values after discovering. [1] This behavior was explained in following page: https://github.com/open-iscsi/open-iscsi/issues/58 Change-Id: I30b736ae3b916f77fc0778f5364c5f6ed6fecc60 closes-bug: #1670237
This commit is contained in:
parent
63b45f5e2a
commit
3266fb51a5
|
@ -14,6 +14,7 @@
|
|||
|
||||
|
||||
import collections
|
||||
import copy
|
||||
import glob
|
||||
import os
|
||||
import re
|
||||
|
@ -412,6 +413,8 @@ class ISCSIConnector(base.BaseLinuxConnector, base_iscsi.BaseISCSIConnector):
|
|||
{'target_portal': connection_properties[
|
||||
'target_portal']})
|
||||
raise
|
||||
old_node_startups = self._get_node_startup_values(
|
||||
connection_properties)
|
||||
out = self._run_iscsiadm_bare(
|
||||
['-m', 'discoverydb',
|
||||
'-t', 'sendtargets',
|
||||
|
@ -419,13 +422,19 @@ class ISCSIConnector(base.BaseLinuxConnector, base_iscsi.BaseISCSIConnector):
|
|||
'-p', connection_properties['target_portal'],
|
||||
'--discover'],
|
||||
check_exit_code=[0, 255])[0] or ""
|
||||
self._recover_node_startup_values(connection_properties,
|
||||
old_node_startups)
|
||||
else:
|
||||
old_node_startups = self._get_node_startup_values(
|
||||
connection_properties)
|
||||
out = self._run_iscsiadm_bare(
|
||||
['-m', 'discovery',
|
||||
'-t', 'sendtargets',
|
||||
'-I', iscsi_transport,
|
||||
'-p', connection_properties['target_portal']],
|
||||
check_exit_code=[0, 255])[0] or ""
|
||||
self._recover_node_startup_values(connection_properties,
|
||||
old_node_startups)
|
||||
|
||||
ips, iqns = self._get_target_portals_from_iscsiadm_output(out)
|
||||
luns = self._get_luns(connection_properties, iqns)
|
||||
|
@ -1037,7 +1046,6 @@ class ISCSIConnector(base.BaseLinuxConnector, base_iscsi.BaseISCSIConnector):
|
|||
{'iqn': target_iqn, 'portal': portal,
|
||||
'err': err.exit_code})
|
||||
return None, None
|
||||
|
||||
self._iscsiadm_update(connection_properties,
|
||||
"node.startup",
|
||||
"automatic")
|
||||
|
@ -1092,3 +1100,47 @@ class ISCSIConnector(base.BaseLinuxConnector, base_iscsi.BaseISCSIConnector):
|
|||
{'multipath_command': multipath_command,
|
||||
'out': out, 'err': err})
|
||||
return (out, err)
|
||||
|
||||
def _get_node_startup_values(self, connection_properties):
|
||||
out, __ = self._run_iscsiadm_bare(
|
||||
['-m', 'node', '--op', 'show', '-p',
|
||||
connection_properties['target_portal']]) or ""
|
||||
node_values = out.strip()
|
||||
node_values = node_values.split("\n")
|
||||
iqn = None
|
||||
startup = None
|
||||
startup_values = {}
|
||||
|
||||
for node_value in node_values:
|
||||
node_keys = node_value.split()
|
||||
try:
|
||||
if node_keys[0] == "node.name":
|
||||
iqn = node_keys[2]
|
||||
elif node_keys[0] == "node.startup":
|
||||
startup = node_keys[2]
|
||||
|
||||
if iqn and startup:
|
||||
startup_values[iqn] = startup
|
||||
iqn = None
|
||||
startup = None
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
return startup_values
|
||||
|
||||
def _recover_node_startup_values(self, connection_properties,
|
||||
old_node_startups):
|
||||
node_startups = self._get_node_startup_values(connection_properties)
|
||||
for iqn, node_startup in node_startups.items():
|
||||
old_node_startup = old_node_startups.get(iqn, None)
|
||||
if old_node_startup and node_startup != old_node_startup:
|
||||
# _iscsiadm_update() only uses "target_portal" and "target_iqn"
|
||||
# of connection_properties.
|
||||
# And the recovering target belongs to the same target_portal
|
||||
# as discovering target.
|
||||
# So target_iqn is updated, and other values aren't updated.
|
||||
recover_connection = copy.deepcopy(connection_properties)
|
||||
recover_connection['target_iqn'] = [iqn]
|
||||
self._iscsiadm_update(recover_connection,
|
||||
"node.startup",
|
||||
old_node_startup)
|
||||
|
|
|
@ -459,9 +459,11 @@ class ISCSIConnectorTestCase(test_connector.ConnectorTestCase):
|
|||
'auth_method': discovery_auth_method,
|
||||
'username': discovery_auth_username,
|
||||
'password': discovery_auth_password},
|
||||
'iscsiadm -m node --op show -p %s' % location,
|
||||
'iscsiadm -m discoverydb -t sendtargets -I %(iface)s'
|
||||
' -p %(location)s --discover' % {'iface': interface,
|
||||
'location': location}]
|
||||
'location': location},
|
||||
'iscsiadm -m node --op show -p %s' % location]
|
||||
self.assertEqual(expected_cmds, self.cmds)
|
||||
# Reset to run with a different transport type
|
||||
self.cmds = list()
|
||||
|
@ -504,8 +506,10 @@ class ISCSIConnectorTestCase(test_connector.ConnectorTestCase):
|
|||
expected_cmds = [
|
||||
'iscsiadm -m discoverydb -t sendtargets -p %s -I default'
|
||||
' --op new' % location,
|
||||
'iscsiadm -m node --op show -p %s' % location,
|
||||
'iscsiadm -m discoverydb -t sendtargets -I default -p %s'
|
||||
' --discover' % location]
|
||||
' --discover' % location,
|
||||
'iscsiadm -m node --op show -p %s' % location]
|
||||
self.assertEqual(expected_cmds, self.cmds)
|
||||
|
||||
self.assertRaises(exception.TargetPortalNotFound,
|
||||
|
@ -1447,3 +1451,77 @@ Setting up iSCSI targets: unused
|
|||
mock.call('/dev/disk/by-id/scsi-wwn'),
|
||||
mock.call('/dev/disk/by-id/dm-...'),
|
||||
mock.call('/dev/disk/by-id/scsi-...')])
|
||||
|
||||
@mock.patch.object(iscsi.ISCSIConnector, '_run_iscsiadm_bare')
|
||||
def test_get_node_startup_values(self, run_iscsiadm_bare_mock):
|
||||
name1 = 'volume-00000001-1'
|
||||
name2 = 'volume-00000001-2'
|
||||
name3 = 'volume-00000001-3'
|
||||
vol = {'id': 1, 'name': name1}
|
||||
location = '10.0.2.15:3260'
|
||||
iqn1 = 'iqn.2010-10.org.openstack:%s' % name1
|
||||
iqn2 = 'iqn.2010-10.org.openstack:%s' % name2
|
||||
iqn3 = 'iqn.2010-10.org.openstack:%s' % name3
|
||||
connection_properties = self.iscsi_connection(vol, [location], [iqn1])
|
||||
|
||||
node_startup1 = "manual"
|
||||
node_startup2 = "automatic"
|
||||
node_startup3 = "manual"
|
||||
node_values = (
|
||||
'# BEGIN RECORD 2.0-873\n'
|
||||
'node.name = %s\n'
|
||||
'node.tpgt = 1\n'
|
||||
'node.startup = %s\n'
|
||||
'iface.hwaddress = <empty>\n'
|
||||
'# END RECORD\n'
|
||||
'# BEGIN RECORD 2.0-873\n'
|
||||
'node.name = %s\n'
|
||||
'node.tpgt = 1\n'
|
||||
'node.startup = %s\n'
|
||||
'iface.hwaddress = <empty>\n'
|
||||
'# END RECORD\n'
|
||||
'# BEGIN RECORD 2.0-873\n'
|
||||
'node.name = %s\n'
|
||||
'node.tpgt = 1\n'
|
||||
'node.startup = %s\n'
|
||||
'iface.hwaddress = <empty>\n'
|
||||
'# END RECORD\n') % (iqn1, node_startup1, iqn2, node_startup2,
|
||||
iqn3, node_startup3)
|
||||
run_iscsiadm_bare_mock.return_value = (node_values, None)
|
||||
|
||||
node_startups =\
|
||||
self.connector._get_node_startup_values(
|
||||
connection_properties['data'])
|
||||
expected_node_startups = {iqn1: node_startup1, iqn2: node_startup2,
|
||||
iqn3: node_startup3}
|
||||
self.assertEqual(node_startups, expected_node_startups)
|
||||
|
||||
@mock.patch.object(iscsi.ISCSIConnector, '_get_node_startup_values')
|
||||
@mock.patch.object(iscsi.ISCSIConnector, '_iscsiadm_update')
|
||||
def test_recover_node_startup_values(self, iscsiadm_update_mock,
|
||||
get_node_startup_values_mock):
|
||||
name1 = 'volume-00000001-1'
|
||||
name2 = 'volume-00000001-2'
|
||||
name3 = 'volume-00000001-3'
|
||||
vol = {'id': 1, 'name': name1}
|
||||
location = '10.0.2.15:3260'
|
||||
iqn1 = 'iqn.2010-10.org.openstack:%s' % name1
|
||||
iqn2 = 'iqn.2010-10.org.openstack:%s' % name2
|
||||
iqn3 = 'iqn.2010-10.org.openstack:%s' % name3
|
||||
connection_properties = self.iscsi_connection(vol, [location], [iqn1])
|
||||
recover_connection = self.iscsi_connection(vol, [location], [iqn2])
|
||||
|
||||
node_startup1 = "manual"
|
||||
node_startup2 = "automatic"
|
||||
node_startup3 = "manual"
|
||||
get_node_startup_values_mock.return_value = {iqn1: node_startup1,
|
||||
iqn2: node_startup2,
|
||||
iqn3: node_startup3}
|
||||
|
||||
old_node_startup_values = {iqn1: node_startup1,
|
||||
iqn2: "manual",
|
||||
iqn3: node_startup3}
|
||||
self.connector._recover_node_startup_values(
|
||||
connection_properties['data'], old_node_startup_values)
|
||||
iscsiadm_update_mock.assert_called_once_with(
|
||||
recover_connection['data'], "node.startup", "manual")
|
||||
|
|
Loading…
Reference in New Issue