VOLUME_ID_SNAP = '761fc5e5-5191-4ec7-aeba-33e36de44156'
FAKE_DESC = 'test description name'
FAKE_FC_PORTS = ['0987654321234', '123456789000987']
- FAKE_ISCSI_PORTS = ['10.10.10.10', '10.10.10.11']
+ FAKE_ISCSI_PORTS = {'1.1.1.2': {'nsp': '8:1:1',
+ 'iqn': ('iqn.2000-05.com.3pardata:'
+ '21810002ac00383d'),
+ 'ip_port': '3262'}}
volume = {'name': VOLUME_NAME,
'id': VOLUME_ID,
'wwnns': ["223456789012345", "223456789054321"],
'host': 'fakehost'}
+ def setup_configuration(self):
+ configuration = mox.MockObject(conf.Configuration)
+ configuration.hp3par_debug = False
+ configuration.hp3par_username = 'testUser'
+ configuration.hp3par_password = 'testPassword'
+ configuration.hp3par_api_url = 'https://1.1.1.1/api/v1'
+ configuration.hp3par_domain = HP3PAR_DOMAIN
+ configuration.hp3par_cpg = HP3PAR_CPG
+ configuration.hp3par_cpg_snap = HP3PAR_CPG_SNAP
+ configuration.iscsi_ip_address = '1.1.1.2'
+ configuration.iscsi_port = '1234'
+ configuration.san_ip = '2.2.2.2'
+ configuration.san_login = 'test'
+ configuration.san_password = 'test'
+ configuration.hp3par_snapshot_expiration = ""
+ configuration.hp3par_snapshot_retention = ""
+ configuration.hp3par_iscsi_ips = []
+ return configuration
+
+ def setup_fakes(self):
+ self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_create_client",
+ self.fake_create_client)
+ self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_get_3par_host",
+ self.fake_get_3par_host)
+ self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_delete_3par_host",
+ self.fake_delete_3par_host)
+ self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_create_3par_vlun",
+ self.fake_create_3par_vlun)
+ self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "get_ports",
+ self.fake_get_ports)
+ self.stubs.Set(hpfcdriver.hpcommon.HP3PARCommon, "get_domain",
+ self.fake_get_domain)
+
+ def clear_mox(self):
+ self.mox.ResetAll()
+ self.stubs.UnsetAll()
+
def fake_create_client(self):
return FakeHP3ParClient(self.driver.configuration.hp3par_api_url)
def setUp(self):
self.tempdir = tempfile.mkdtemp()
super(TestHP3PARFCDriver, self).setUp()
+ self.setup_driver(self.setup_configuration())
+ self.setup_fakes()
- configuration = mox.MockObject(conf.Configuration)
- configuration.hp3par_debug = False
- configuration.hp3par_username = 'testUser'
- configuration.hp3par_password = 'testPassword'
- configuration.hp3par_api_url = 'https://1.1.1.1/api/v1'
- configuration.hp3par_cpg = HP3PAR_CPG
- configuration.hp3par_cpg_snap = HP3PAR_CPG_SNAP
- configuration.iscsi_ip_address = '1.1.1.2'
- configuration.iscsi_port = '1234'
- configuration.san_ip = '2.2.2.2'
- configuration.san_login = 'test'
- configuration.san_password = 'test'
- configuration.hp3par_snapshot_expiration = ""
- configuration.hp3par_snapshot_retention = ""
- self.stubs.Set(hpfcdriver.hpcommon.HP3PARCommon, "_create_client",
- self.fake_create_client)
+ def setup_fakes(self):
+ super(TestHP3PARFCDriver, self).setup_fakes()
self.stubs.Set(hpfcdriver.HP3PARFCDriver,
"_create_3par_fibrechan_host",
self.fake_create_3par_fibrechan_host)
- self.stubs.Set(hpfcdriver.hpcommon.HP3PARCommon, "_get_3par_host",
- self.fake_get_3par_host)
- self.stubs.Set(hpfcdriver.hpcommon.HP3PARCommon, "_delete_3par_host",
- self.fake_delete_3par_host)
- self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_create_3par_vlun",
- self.fake_create_3par_vlun)
- self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "get_ports",
- self.fake_get_ports)
- self.stubs.Set(hpfcdriver.hpcommon.HP3PARCommon, "get_domain",
- self.fake_get_domain)
-
- self.configuration = configuration
-
- self.driver = hpfcdriver.HP3PARFCDriver(configuration=configuration)
- self.driver.do_setup(None)
-
def tearDown(self):
shutil.rmtree(self.tempdir)
super(TestHP3PARFCDriver, self).tearDown()
+ def setup_driver(self, configuration):
+ self.driver = hpfcdriver.HP3PARFCDriver(configuration=configuration)
+
+ self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_create_client",
+ self.fake_create_client)
+ self.driver.do_setup(None)
+
def fake_create_3par_fibrechan_host(self, hostname, wwn,
domain, persona_id):
host = {'FCPaths': [{'driverVersion': None,
self.flags(lock_path=self.tempdir)
#record
- self.stubs.UnsetAll()
+ self.clear_mox()
self.stubs.Set(hpfcdriver.hpcommon.HP3PARCommon, "get_domain",
self.fake_get_domain)
_run_ssh = self.mox.CreateMock(hpdriver.hpcommon.HP3PARCommon._run_ssh)
self.flags(lock_path=self.tempdir)
#record
- self.stubs.UnsetAll()
+ self.clear_mox()
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "get_domain",
self.fake_get_domain)
_run_ssh = self.mox.CreateMock(hpdriver.hpcommon.HP3PARCommon._run_ssh)
self.flags(lock_path=self.tempdir)
#record
- self.stubs.UnsetAll()
+ self.clear_mox()
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "get_domain",
self.fake_get_domain)
_run_ssh = self.mox.CreateMock(hpdriver.hpcommon.HP3PARCommon._run_ssh)
def setUp(self):
self.tempdir = tempfile.mkdtemp()
super(TestHP3PARISCSIDriver, self).setUp()
+ self.setup_driver(self.setup_configuration())
+ self.setup_fakes()
- configuration = mox.MockObject(conf.Configuration)
- configuration.hp3par_debug = False
- configuration.hp3par_username = 'testUser'
- configuration.hp3par_password = 'testPassword'
- configuration.hp3par_api_url = 'https://1.1.1.1/api/v1'
- configuration.hp3par_cpg = HP3PAR_CPG
- configuration.hp3par_cpg_snap = HP3PAR_CPG_SNAP
- configuration.iscsi_ip_address = '1.1.1.2'
- configuration.iscsi_port = '1234'
- configuration.san_ip = '2.2.2.2'
- configuration.san_login = 'test'
- configuration.san_password = 'test'
- configuration.hp3par_snapshot_expiration = ""
- configuration.hp3par_snapshot_retention = ""
+ def setup_fakes(self):
+ super(TestHP3PARISCSIDriver, self).setup_fakes()
- self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_create_client",
- self.fake_create_client)
- self.stubs.Set(hpdriver.HP3PARISCSIDriver,
- "_iscsi_discover_target_iqn",
- self.fake_iscsi_discover_target_iqn)
self.stubs.Set(hpdriver.HP3PARISCSIDriver, "_create_3par_iscsi_host",
self.fake_create_3par_iscsi_host)
- self.stubs.Set(hpdriver.HP3PARISCSIDriver,
- "_iscsi_discover_target_iqn",
- self.fake_iscsi_discover_target_iqn)
-
- self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_get_3par_host",
- self.fake_get_3par_host)
- self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_delete_3par_host",
- self.fake_delete_3par_host)
- self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_create_3par_vlun",
- self.fake_create_3par_vlun)
- self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "get_domain",
- self.fake_get_domain)
-
- self.driver = hpdriver.HP3PARISCSIDriver(configuration=configuration)
- self.driver.do_setup(None)
- target_iqn = 'iqn.2000-05.com.3pardata:21810002ac00383d'
+ #target_iqn = 'iqn.2000-05.com.3pardata:21810002ac00383d'
self.properties = {'data':
{'target_discovered': True,
- 'target_iqn': target_iqn,
+ 'target_iqn': self.TARGET_IQN,
'target_lun': 186,
'target_portal': '1.1.1.2:1234'},
'driver_volume_type': 'iscsi'}
self._hosts = {}
super(TestHP3PARISCSIDriver, self).tearDown()
- def fake_iscsi_discover_target_iqn(self, ip_address):
- return self.TARGET_IQN
+ def setup_driver(self, configuration, set_up_fakes=True):
+ self.driver = hpdriver.HP3PARISCSIDriver(configuration=configuration)
+
+ self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_create_client",
+ self.fake_create_client)
+
+ if set_up_fakes:
+ self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "get_ports",
+ self.fake_get_ports)
+
+ self.driver.do_setup(None)
def fake_create_3par_iscsi_host(self, hostname, iscsi_iqn,
domain, persona_id):
self.flags(lock_path=self.tempdir)
#record
- self.stubs.UnsetAll()
+ self.clear_mox()
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "get_domain",
self.fake_get_domain)
_run_ssh = self.mox.CreateMock(hpdriver.hpcommon.HP3PARCommon._run_ssh)
self.flags(lock_path=self.tempdir)
#record
- self.stubs.UnsetAll()
+ self.clear_mox()
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "get_domain",
self.fake_get_domain)
_run_ssh = self.mox.CreateMock(hpdriver.hpcommon.HP3PARCommon._run_ssh)
self.flags(lock_path=self.tempdir)
#record
- self.stubs.UnsetAll()
+ self.clear_mox()
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "get_domain",
self.fake_get_domain)
_run_ssh = self.mox.CreateMock(hpdriver.hpcommon.HP3PARCommon._run_ssh)
host = self.driver._create_host(self.volume, self.connector)
self.assertEqual(host['name'], self.FAKE_HOST)
- def test_iscsi_discover_target_iqn(self):
- self.flags(lock_path=self.tempdir)
-
- #record
- self.stubs.UnsetAll()
- _run_ssh = self.mox.CreateMock(hpdriver.hpcommon.HP3PARCommon._run_ssh)
- self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_run_ssh", _run_ssh)
-
- show_port_cmd = 'showport -ids'
- _run_ssh(show_port_cmd, False).AndReturn([pack(ISCSI_PORT_IDS_RET),
- ''])
- self.mox.ReplayAll()
-
- iqn = self.driver._iscsi_discover_target_iqn('10.10.120.253')
- self.assertEqual(iqn, self.TARGET_IQN)
-
def test_get_volume_state(self):
self.flags(lock_path=self.tempdir)
#record
- self.stubs.UnsetAll()
+ self.clear_mox()
_run_ssh = self.mox.CreateMock(hpdriver.hpcommon.HP3PARCommon._run_ssh)
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_run_ssh", _run_ssh)
self.flags(lock_path=self.tempdir)
#record
- self.stubs.UnsetAll()
+ self.clear_mox()
_run_ssh = self.mox.CreateMock(hpdriver.hpcommon.HP3PARCommon._run_ssh)
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_run_ssh", _run_ssh)
_run_ssh(show_port_cmd, False).AndReturn([pack(PORT_RET), ''])
show_port_i_cmd = 'showport -iscsi'
- _run_ssh(show_port_i_cmd, False).AndReturn([pack(ISCSI_PORT_RET), ''])
+ _run_ssh(show_port_i_cmd, False).AndReturn([pack(READY_ISCSI_PORT_RET),
+ ''])
+
+ show_port_i_cmd = 'showport -iscsiname'
+ _run_ssh(show_port_i_cmd, False).AndReturn([pack(SHOW_PORT_ISCSI),
+ ''])
self.mox.ReplayAll()
ports = self.driver.common.get_ports()
self.assertEqual(ports['FC'][0], '20210002AC00383D')
+ self.assertEqual(ports['iSCSI']['10.10.120.252']['nsp'], '0:8:2')
+
+ def test_get_iscsi_ip_active(self):
+ self.flags(lock_path=self.tempdir)
+
+ #record set up
+ self.clear_mox()
+ _run_ssh = self.mox.CreateMock(hpdriver.hpcommon.HP3PARCommon._run_ssh)
+ self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_run_ssh", _run_ssh)
+
+ show_port_cmd = 'showport'
+ _run_ssh(show_port_cmd, False).AndReturn([pack(PORT_RET), ''])
+
+ show_port_i_cmd = 'showport -iscsi'
+ _run_ssh(show_port_i_cmd, False).AndReturn([pack(READY_ISCSI_PORT_RET),
+ ''])
+
+ show_port_i_cmd = 'showport -iscsiname'
+ _run_ssh(show_port_i_cmd, False).AndReturn([pack(SHOW_PORT_ISCSI), ''])
+
+ self.mox.ReplayAll()
+
+ config = self.setup_configuration()
+ config.hp3par_iscsi_ips = ['10.10.220.253', '10.10.220.252']
+ self.setup_driver(config, set_up_fakes=False)
+
+ #record
+ self.clear_mox()
+ _run_ssh = self.mox.CreateMock(hpdriver.hpcommon.HP3PARCommon._run_ssh)
+ self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_run_ssh", _run_ssh)
+
+ show_vlun_cmd = 'showvlun -a -host fakehost'
+ _run_ssh(show_vlun_cmd, False).AndReturn([pack(SHOW_VLUN), ''])
+
+ self.mox.ReplayAll()
+
+ ip = self.driver._get_iscsi_ip('fakehost')
+ self.assertEqual(ip, '10.10.220.253')
+
+ def test_get_iscsi_ip(self):
+ self.flags(lock_path=self.tempdir)
+
+ #record driver set up
+ self.clear_mox()
+ _run_ssh = self.mox.CreateMock(hpdriver.hpcommon.HP3PARCommon._run_ssh)
+ self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_run_ssh", _run_ssh)
+
+ show_port_cmd = 'showport'
+ _run_ssh(show_port_cmd, False).AndReturn([pack(PORT_RET), ''])
+
+ show_port_i_cmd = 'showport -iscsi'
+ _run_ssh(show_port_i_cmd, False).AndReturn([pack(READY_ISCSI_PORT_RET),
+ ''])
+
+ show_port_i_cmd = 'showport -iscsiname'
+ _run_ssh(show_port_i_cmd, False).AndReturn([pack(SHOW_PORT_ISCSI), ''])
+
+ #record
+ show_vlun_cmd = 'showvlun -a -host fakehost'
+ show_vlun_ret = 'no vluns listed\r\n'
+ _run_ssh(show_vlun_cmd, False).AndReturn([pack(show_vlun_ret), ''])
+ show_vlun_cmd = 'showvlun -a -showcols Port'
+ _run_ssh(show_vlun_cmd, False).AndReturn([pack(SHOW_VLUN_NONE), ''])
+
+ self.mox.ReplayAll()
+
+ config = self.setup_configuration()
+ config.iscsi_ip_address = '10.10.10.10'
+ config.hp3par_iscsi_ips = ['10.10.220.253', '10.10.220.252']
+ self.setup_driver(config, set_up_fakes=False)
+
+ ip = self.driver._get_iscsi_ip('fakehost')
+ self.assertEqual(ip, '10.10.220.252')
+
+ def test_invalid_iscsi_ip(self):
+ self.flags(lock_path=self.tempdir)
+
+ #record driver set up
+ self.clear_mox()
+ _run_ssh = self.mox.CreateMock(hpdriver.hpcommon.HP3PARCommon._run_ssh)
+ self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_run_ssh", _run_ssh)
+
+ show_port_cmd = 'showport'
+ _run_ssh(show_port_cmd, False).AndReturn([pack(PORT_RET), ''])
+
+ show_port_i_cmd = 'showport -iscsi'
+ _run_ssh(show_port_i_cmd, False).AndReturn([pack(READY_ISCSI_PORT_RET),
+ ''])
+
+ show_port_i_cmd = 'showport -iscsiname'
+ _run_ssh(show_port_i_cmd, False).AndReturn([pack(SHOW_PORT_ISCSI), ''])
+
+ config = self.setup_configuration()
+ config.hp3par_iscsi_ips = ['10.10.220.250', '10.10.220.251']
+ config.iscsi_ip_address = '10.10.10.10'
+ self.mox.ReplayAll()
+
+ # no valid ip addr should be configured.
+ self.assertRaises(exception.InvalidInput,
+ self.setup_driver,
+ config,
+ set_up_fakes=False)
+
+ def test_get_least_used_nsp(self):
+ self.flags(lock_path=self.tempdir)
+
+ #record
+ self.clear_mox()
+ _run_ssh = self.mox.CreateMock(hpdriver.hpcommon.HP3PARCommon._run_ssh)
+ self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_run_ssh", _run_ssh)
+
+ show_vlun_cmd = 'showvlun -a -showcols Port'
+ _run_ssh(show_vlun_cmd, False).AndReturn([pack(SHOW_VLUN_NONE), ''])
+ _run_ssh(show_vlun_cmd, False).AndReturn([pack(SHOW_VLUN_NONE), ''])
+ _run_ssh(show_vlun_cmd, False).AndReturn([pack(SHOW_VLUN_NONE), ''])
+
+ self.mox.ReplayAll()
+ # in use count 11 12
+ nsp = self.driver._get_least_used_nsp(['0:2:1', '1:8:1'])
+ self.assertEqual(nsp, '0:2:1')
+
+ # in use count 11 10
+ nsp = self.driver._get_least_used_nsp(['0:2:1', '1:2:1'])
+ self.assertEqual(nsp, '1:2:1')
+
+ # in use count 0 10
+ nsp = self.driver._get_least_used_nsp(['1:1:1', '1:2:1'])
+ self.assertEqual(nsp, '1:1:1')
def pack(arg):
'Model : --\r\n'
'Contact : --\r\n'
'Comment : -- \r\n\r\n\r\n')
+
+SHOW_PORT_ISCSI = (
+ 'N:S:P,IPAddr,---------------iSCSI_Name----------------\r\n'
+ '0:8:1,1.1.1.2,iqn.2000-05.com.3pardata:21810002ac00383d\r\n'
+ '0:8:2,10.10.120.252,iqn.2000-05.com.3pardata:20820002ac00383d\r\n'
+ '1:8:1,10.10.220.253,iqn.2000-05.com.3pardata:21810002ac00383d\r\n'
+ '1:8:2,10.10.220.252,iqn.2000-05.com.3pardata:21820002ac00383d\r\n'
+ '-------------------------------------------------------------\r\n')
+
+SHOW_VLUN = (
+ 'Lun,VVName,HostName,---------Host_WWN/iSCSI_Name----------,Port,Type,'
+ 'Status,ID\r\n'
+ '0,a,fakehost,iqn.1993-08.org.debian:01:3a779e4abc22,1:8:1,matched set,'
+ 'active,0\r\n'
+ '------------------------------------------------------------------------'
+ '--------------\r\n')
+
+SHOW_VLUN_NONE = (
+ 'Port\r\n0:2:1\r\n0:2:1\r\n1:8:1\r\n1:8:1\r\n1:8:1\r\n1:2:1\r\n'
+ '1:2:1\r\n1:2:1\r\n1:2:1\r\n1:2:1\r\n1:2:1\r\n1:8:1\r\n1:8:1\r\n1:8:1\r\n'
+ '1:8:1\r\n1:8:1\r\n1:8:1\r\n0:2:1\r\n0:2:1\r\n0:2:1\r\n0:2:1\r\n0:2:1\r\n'
+ '0:2:1\r\n0:2:1\r\n1:8:1\r\n1:8:1\r\n0:2:1\r\n0:2:1\r\n1:2:1\r\n1:2:1\r\n'
+ '1:2:1\r\n1:2:1\r\n1:8:1\r\n-----')
+
+READY_ISCSI_PORT_RET = (
+ 'N:S:P,State,IPAddr,Netmask,Gateway,TPGT,MTU,Rate,DHCP,iSNS_Addr,'
+ 'iSNS_Port\r\n'
+ '0:8:1,ready,10.10.120.253,255.255.224.0,0.0.0.0,81,1500,10Gbps,'
+ '0,0.0.0.0,3205\r\n'
+ '0:8:2,ready,10.10.120.252,255.255.224.0,0.0.0.0,82,1500,10Gbps,0,'
+ '0.0.0.0,3205\r\n'
+ '1:8:1,ready,10.10.220.253,255.255.224.0,0.0.0.0,181,1500,10Gbps,'
+ '0,0.0.0.0,3205\r\n'
+ '1:8:2,ready,10.10.220.252,255.255.224.0,0.0.0.0,182,1500,10Gbps,0,'
+ '0.0.0.0,3205\r\n'
+ '-------------------------------------------------------------------'
+ '----------------------\r\n')
volume_driver=cinder.volume.drivers.san.hp.hp_3par_iscsi.HP3PARISCSIDriver
"""
+import sys
+
from hp3parclient import exceptions as hpexceptions
from cinder import exception
VERSION = 1.0
LOG = logging.getLogger(__name__)
+DEFAULT_ISCSI_PORT = 3260
class HP3PARISCSIDriver(cinder.volume.driver.ISCSIDriver):
def _check_flags(self):
"""Sanity check to ensure we have required options set."""
required_flags = ['hp3par_api_url', 'hp3par_username',
- 'hp3par_password', 'iscsi_ip_address',
- 'iscsi_port', 'san_ip', 'san_login',
+ 'hp3par_password', 'san_ip', 'san_login',
'san_password']
self.common.check_flags(self.configuration, required_flags)
def do_setup(self, context):
self.common = self._init_common()
self._check_flags()
- self.common.do_setup(context)
- # make sure ssh works.
- self._iscsi_discover_target_iqn(self.configuration.iscsi_ip_address)
+ # map iscsi_ip-> ip_port
+ # -> iqn
+ # -> nsp
+ self.iscsi_ips = {}
+ temp_iscsi_ip = {}
+
+ # use the 3PAR ip_addr list for iSCSI configuration
+ if len(self.configuration.hp3par_iscsi_ips) > 0:
+ # add port values to ip_addr, if necessary
+ for ip_addr in self.configuration.hp3par_iscsi_ips:
+ ip = ip_addr.split(':')
+ if len(ip) == 1:
+ temp_iscsi_ip[ip_addr] = {'ip_port': DEFAULT_ISCSI_PORT}
+ elif len(ip) == 2:
+ temp_iscsi_ip[ip[0]] = {'ip_port': ip[1]}
+ else:
+ msg = _("Invalid IP address format '%s'") % ip_addr
+ LOG.warn(msg)
+
+ # add the single value iscsi_ip_address option to the IP dictionary.
+ # This way we can see if it's a valid iSCSI IP. If it's not valid,
+ # we won't use it and won't bother to report it, see below
+ if (self.configuration.iscsi_ip_address not in temp_iscsi_ip):
+ ip = self.configuration.iscsi_ip_address
+ ip_port = self.configuration.iscsi_port
+ temp_iscsi_ip[ip] = {'ip_port': ip_port}
+
+ # get all the valid iSCSI ports from 3PAR
+ # when found, add the valid iSCSI ip, ip port, iqn and nsp
+ # to the iSCSI IP dictionary
+ # ...this will also make sure ssh works.
+ iscsi_ports = self.common.get_ports()['iSCSI']
+ for (ip, iscsi_info) in iscsi_ports.iteritems():
+ if ip in temp_iscsi_ip:
+ ip_port = temp_iscsi_ip[ip]['ip_port']
+ self.iscsi_ips[ip] = {'ip_port': ip_port,
+ 'nsp': iscsi_info['nsp'],
+ 'iqn': iscsi_info['iqn']
+ }
+ del temp_iscsi_ip[ip]
+
+ # if the single value iscsi_ip_address option is still in the
+ # temp dictionary it's because it defaults to $my_ip which doesn't
+ # make sense in this context. So, if present, remove it and move on.
+ if (self.configuration.iscsi_ip_address in temp_iscsi_ip):
+ del temp_iscsi_ip[self.configuration.iscsi_ip_address]
+
+ # lets see if there are invalid iSCSI IPs left in the temp dict
+ if len(temp_iscsi_ip) > 0:
+ msg = _("Found invalid iSCSI IP address(s) in configuration "
+ "option(s) hp3par_iscsi_ips or iscsi_ip_address '%s.'") % \
+ (", ".join(temp_iscsi_ip))
+ LOG.warn(msg)
+
+ if not len(self.iscsi_ips) > 0:
+ msg = _('At least one valid iSCSI IP address must be set.')
+ raise exception.InvalidInput(reason=(msg))
+
+ self.common.do_setup(context)
def check_for_setup_error(self):
"""Returns an error if prerequisites aren't met."""
metadata = self.common.create_volume(volume)
self.common.client_logout()
- return {'provider_location': "%s:%s" %
- (self.configuration.iscsi_ip_address,
- self.configuration.iscsi_port),
- 'metadata': metadata}
+ return {'metadata': metadata}
@utils.synchronized('3par', external=True)
def create_cloned_volume(self, volume, src_vref):
new_vol = self.common.create_cloned_volume(volume, src_vref)
self.common.client_logout()
- return {'provider_location': "%s:%s" %
- (self.configuration.iscsi_ip_address,
- self.configuration.iscsi_port),
- 'metadata': new_vol}
+ return {'metadata': new_vol}
@utils.synchronized('3par', external=True)
def delete_volume(self, volume):
* create vlun on the 3par
"""
self.common.client_login()
- # get the target_iqn on the 3par interface.
- target_iqn = self._iscsi_discover_target_iqn(
- self.configuration.iscsi_ip_address)
# we have to make sure we have a host
host = self._create_host(volume, connector)
vlun = self.common.create_vlun(volume, host)
self.common.client_logout()
+
+ iscsi_ip = self._get_iscsi_ip(host['name'])
+ iscsi_ip_port = self.iscsi_ips[iscsi_ip]['ip_port']
+ iscsi_target_iqn = self.iscsi_ips[iscsi_ip]['iqn']
info = {'driver_volume_type': 'iscsi',
'data': {'target_portal': "%s:%s" %
- (self.configuration.iscsi_ip_address,
- self.configuration.iscsi_port),
- 'target_iqn': target_iqn,
+ (iscsi_ip, iscsi_ip_port),
+ 'target_iqn': iscsi_target_iqn,
'target_lun': vlun['lun'],
'target_discovered': True
}
connector['initiator'])
self.common.client_logout()
- def _iscsi_discover_target_iqn(self, remote_ip):
- result = self.common._cli_run('showport -ids', None)
-
- iqn = None
- if result:
- # first line is header
- result = result[1:]
- for line in result:
- info = line.split(",")
- if info and len(info) > 2:
- if info[1] == remote_ip:
- iqn = info[2]
-
- return iqn
-
def _create_3par_iscsi_host(self, hostname, iscsi_iqn, domain, persona_id):
"""Create a 3PAR host.
@utils.synchronized('3par', external=True)
def remove_export(self, context, volume):
pass
+
+ def _get_iscsi_ip(self, hostname):
+ """Get an iSCSI IP address to use.
+
+ Steps to determine which IP address to use.
+ * If only one IP address, return it
+ * If there is an active vlun, return the IP associated with it
+ * Return IP with fewest active vluns
+ """
+ if len(self.iscsi_ips) == 1:
+ return self.iscsi_ips.keys()[0]
+
+ # if we currently have an active port, use it
+ nsp = self._get_active_nsp(hostname)
+
+ if nsp is None:
+ # no active vlun, find least busy port
+ nsp = self._get_least_used_nsp(self._get_iscsi_nsps())
+ if nsp is None:
+ msg = _("Least busy iSCSI port not found, "
+ "using first iSCSI port in list.")
+ LOG.warn(msg)
+ return self.iscsi_ips.keys()[0]
+
+ return self._get_ip_using_nsp(nsp)
+
+ def _get_iscsi_nsps(self):
+ """Return the list of candidate nsps."""
+ nsps = []
+ for value in self.iscsi_ips.values():
+ nsps.append(value['nsp'])
+ return nsps
+
+ def _get_ip_using_nsp(self, nsp):
+ """Return IP assiciated with given nsp."""
+ for (key, value) in self.iscsi_ips.items():
+ if value['nsp'] == nsp:
+ return key
+
+ def _get_active_nsp(self, hostname):
+ """Return the active nsp, if one exists, for the given host."""
+ result = self.common._cli_run('showvlun -a -host %s' % hostname, None)
+ if result:
+ # first line is header
+ result = result[1:]
+ for line in result:
+ info = line.split(",")
+ if info and len(info) > 4:
+ return info[4]
+
+ def _get_least_used_nsp(self, nspss):
+ """"Return the nsp that has the fewest active vluns."""
+ # return only the nsp (node:server:port)
+ result = self.common._cli_run('showvlun -a -showcols Port', None)
+
+ # count the number of nsps (there is 1 for each active vlun)
+ nsp_counts = {}
+ for nsp in nspss:
+ # initialize counts to zero
+ nsp_counts[nsp] = 0
+
+ current_least_used_nsp = None
+ if result:
+ # first line is header
+ result = result[1:]
+ for line in result:
+ nsp = line.strip()
+ if nsp in nsp_counts:
+ nsp_counts[nsp] = nsp_counts[nsp] + 1
+
+ # identify key (nsp) of least used nsp
+ current_smallest_count = sys.maxint
+ for (nsp, count) in nsp_counts.iteritems():
+ if count < current_smallest_count:
+ current_least_used_nsp = nsp
+ current_smallest_count = count
+
+ return current_least_used_nsp