Merge "Adds multiple iSCSI port support to 3PAR"
This commit is contained in:
@@ -305,7 +305,10 @@ class HP3PARBaseDriver():
|
||||
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,
|
||||
@@ -333,6 +336,43 @@ class HP3PARBaseDriver():
|
||||
'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)
|
||||
|
||||
@@ -430,47 +470,26 @@ class TestHP3PARFCDriver(HP3PARBaseDriver, test.TestCase):
|
||||
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,
|
||||
@@ -577,7 +596,7 @@ class TestHP3PARFCDriver(HP3PARBaseDriver, test.TestCase):
|
||||
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)
|
||||
@@ -600,7 +619,7 @@ class TestHP3PARFCDriver(HP3PARBaseDriver, test.TestCase):
|
||||
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)
|
||||
@@ -627,7 +646,7 @@ class TestHP3PARFCDriver(HP3PARBaseDriver, test.TestCase):
|
||||
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)
|
||||
@@ -657,49 +676,19 @@ class TestHP3PARISCSIDriver(HP3PARBaseDriver, test.TestCase):
|
||||
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'}
|
||||
@@ -709,8 +698,17 @@ class TestHP3PARISCSIDriver(HP3PARBaseDriver, test.TestCase):
|
||||
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):
|
||||
@@ -812,7 +810,7 @@ class TestHP3PARISCSIDriver(HP3PARBaseDriver, test.TestCase):
|
||||
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)
|
||||
@@ -836,7 +834,7 @@ class TestHP3PARISCSIDriver(HP3PARBaseDriver, test.TestCase):
|
||||
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)
|
||||
@@ -863,7 +861,7 @@ class TestHP3PARISCSIDriver(HP3PARBaseDriver, test.TestCase):
|
||||
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)
|
||||
@@ -881,27 +879,11 @@ class TestHP3PARISCSIDriver(HP3PARBaseDriver, test.TestCase):
|
||||
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)
|
||||
|
||||
@@ -917,7 +899,7 @@ class TestHP3PARISCSIDriver(HP3PARBaseDriver, test.TestCase):
|
||||
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)
|
||||
|
||||
@@ -925,11 +907,144 @@ class TestHP3PARISCSIDriver(HP3PARBaseDriver, test.TestCase):
|
||||
_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):
|
||||
@@ -1106,3 +1221,40 @@ ISCSI_3PAR_RET = (
|
||||
'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')
|
||||
|
||||
@@ -96,7 +96,10 @@ hp3par_opts = [
|
||||
" and is deleted. This must be larger than expiration"),
|
||||
cfg.BoolOpt('hp3par_debug',
|
||||
default=False,
|
||||
help="Enable HTTP debugging to 3PAR")
|
||||
help="Enable HTTP debugging to 3PAR"),
|
||||
cfg.ListOpt('hp3par_iscsi_ips',
|
||||
default=[],
|
||||
help="List of target iSCSI addresses to use.")
|
||||
]
|
||||
|
||||
|
||||
@@ -458,7 +461,7 @@ exit
|
||||
# Protocol,Label,Partner,FailoverState
|
||||
out = out[1:len(out) - 2]
|
||||
|
||||
ports = {'FC': [], 'iSCSI': []}
|
||||
ports = {'FC': [], 'iSCSI': {}}
|
||||
for line in out:
|
||||
tmp = line.split(',')
|
||||
|
||||
@@ -477,9 +480,26 @@ exit
|
||||
for line in out:
|
||||
tmp = line.split(',')
|
||||
|
||||
if tmp:
|
||||
if tmp and len(tmp) > 2:
|
||||
if tmp[1] == 'ready':
|
||||
ports['iSCSI'].append(tmp[2])
|
||||
ports['iSCSI'][tmp[2]] = {}
|
||||
|
||||
# now get the nsp and iqn
|
||||
result = self._cli_run('showport -iscsiname', None)
|
||||
if result:
|
||||
# first line is header
|
||||
# nsp, ip,iqn
|
||||
result = result[1:]
|
||||
for line in result:
|
||||
info = line.split(",")
|
||||
if info and len(info) > 2:
|
||||
if info[1] in ports['iSCSI']:
|
||||
nsp = info[0]
|
||||
ip_addr = info[1]
|
||||
iqn = info[2]
|
||||
ports['iSCSI'][ip_addr] = {'nsp': nsp,
|
||||
'iqn': iqn
|
||||
}
|
||||
|
||||
LOG.debug("PORTS = %s" % pprint.pformat(ports))
|
||||
return ports
|
||||
|
||||
@@ -30,6 +30,8 @@ Set the following in the cinder.conf file to enable the
|
||||
volume_driver=cinder.volume.drivers.san.hp.hp_3par_iscsi.HP3PARISCSIDriver
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
from hp3parclient import exceptions as hpexceptions
|
||||
|
||||
from cinder import exception
|
||||
@@ -41,6 +43,7 @@ from cinder.volume.drivers.san import san
|
||||
|
||||
VERSION = 1.0
|
||||
LOG = logging.getLogger(__name__)
|
||||
DEFAULT_ISCSI_PORT = 3260
|
||||
|
||||
|
||||
class HP3PARISCSIDriver(cinder.volume.driver.ISCSIDriver):
|
||||
@@ -62,8 +65,7 @@ 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)
|
||||
|
||||
@@ -80,10 +82,66 @@ class HP3PARISCSIDriver(cinder.volume.driver.ISCSIDriver):
|
||||
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."""
|
||||
@@ -95,10 +153,7 @@ class HP3PARISCSIDriver(cinder.volume.driver.ISCSIDriver):
|
||||
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):
|
||||
@@ -107,10 +162,7 @@ class HP3PARISCSIDriver(cinder.volume.driver.ISCSIDriver):
|
||||
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):
|
||||
@@ -168,9 +220,6 @@ class HP3PARISCSIDriver(cinder.volume.driver.ISCSIDriver):
|
||||
* 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)
|
||||
@@ -179,11 +228,14 @@ class HP3PARISCSIDriver(cinder.volume.driver.ISCSIDriver):
|
||||
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
|
||||
}
|
||||
@@ -199,21 +251,6 @@ class HP3PARISCSIDriver(cinder.volume.driver.ISCSIDriver):
|
||||
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.
|
||||
|
||||
@@ -268,3 +305,81 @@ class HP3PARISCSIDriver(cinder.volume.driver.ISCSIDriver):
|
||||
@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
|
||||
|
||||
@@ -1176,6 +1176,9 @@
|
||||
# Enable HTTP debugging to 3PAR (boolean value)
|
||||
#hp3par_debug=false
|
||||
|
||||
#List of target iSCSI addresses to use (list value)
|
||||
#hp3par_iscsi_ips=
|
||||
|
||||
|
||||
#
|
||||
# Options defined in cinder.volume.drivers.san.san
|
||||
|
||||
Reference in New Issue
Block a user