cinder/cinder/tests/test_hp3par.py

1489 lines
58 KiB
Python

#
# (c) Copyright 2013-2014 Hewlett-Packard Development Company, L.P.
# 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.
"""Unit tests for OpenStack Cinder volume drivers."""
import ast
import mock
import mox
import shutil
import tempfile
from hp3parclient import exceptions as hpexceptions
from cinder import context
from cinder import exception
from cinder.openstack.common import log as logging
from cinder import test
from cinder.volume import configuration as conf
from cinder.volume.drivers.san.hp import hp_3par_fc as hpfcdriver
from cinder.volume.drivers.san.hp import hp_3par_iscsi as hpdriver
LOG = logging.getLogger(__name__)
HP3PAR_DOMAIN = 'OpenStack',
HP3PAR_CPG = 'OpenStackCPG',
HP3PAR_CPG_SNAP = 'OpenStackCPGSnap'
CLI_CR = '\r\n'
class FakeHP3ParClient(object):
PORT_MODE_TARGET = 2
PORT_MODE_INITIATOR = 3
PORT_MODE_PEER = 4
PORT_TYPE_HOST = 1
PORT_TYPE_DISK = 2
PORT_TYPE_FREE = 3
PORT_TYPE_RCIP = 6
PORT_TYPE_ISCSI = 7
PORT_PROTO_FC = 1
PORT_PROTO_ISCSI = 2
PORT_PROTO_IP = 4
PORT_STATE_READY = 4
PORT_STATE_SYNC = 5
PORT_STATE_OFFLINE = 10
HOST_EDIT_ADD = 1
HOST_EDIT_REMOVE = 2
api_url = None
debug = False
connection_count = 0
volumes = []
hosts = []
vluns = []
cpgs = [
{'SAGrowth': {'LDLayout': {'diskPatterns': [{'diskType': 2}]},
'incrementMiB': 8192},
'SAUsage': {'rawTotalMiB': 24576,
'rawUsedMiB': 768,
'totalMiB': 8192,
'usedMiB': 256},
'SDGrowth': {'LDLayout': {'RAIDType': 4,
'diskPatterns': [{'diskType': 2}]},
'incrementMiB': 32768},
'SDUsage': {'rawTotalMiB': 49152,
'rawUsedMiB': 1023,
'totalMiB': 36864,
'usedMiB': 768},
'UsrUsage': {'rawTotalMiB': 57344,
'rawUsedMiB': 43349,
'totalMiB': 43008,
'usedMiB': 32512},
'additionalStates': [],
'degradedStates': [],
'domain': HP3PAR_DOMAIN,
'failedStates': [],
'id': 5,
'name': HP3PAR_CPG,
'numFPVVs': 2,
'numTPVVs': 0,
'state': 1,
'uuid': '29c214aa-62b9-41c8-b198-543f6cf24edf'}]
def __init__(self, api_url):
self.api_url = api_url
self.volumes = []
self.hosts = []
self.vluns = []
def debug_rest(self, flag):
self.debug = flag
def login(self, username, password, optional=None):
self.connection_count += 1
return None
def logout(self):
if self.connection_count < 1:
raise hpexceptions.CommandError('No connection to log out.')
self.connection_count -= 1
return None
def getVolumes(self):
return self.volumes
def getVolume(self, name):
if self.volumes:
for volume in self.volumes:
if volume['name'] == name:
return volume
msg = {'code': 'NON_EXISTENT_HOST',
'desc': "VOLUME '%s' was not found" % name}
raise hpexceptions.HTTPNotFound(msg)
def createVolume(self, name, cpgName, sizeMiB, optional=None):
new_vol = {'additionalStates': [],
'adminSpace': {'freeMiB': 0,
'rawReservedMiB': 384,
'reservedMiB': 128,
'usedMiB': 128},
'baseId': 115,
'comment': optional['comment'],
'copyType': 1,
'creationTime8601': '2012-10-22T16:37:57-07:00',
'creationTimeSec': 1350949077,
'degradedStates': [],
'domain': HP3PAR_DOMAIN,
'failedStates': [],
'id': 115,
'name': name,
'policies': {'caching': True,
'oneHost': False,
'staleSS': True,
'system': False,
'zeroDetect': False},
'provisioningType': 1,
'readOnly': False,
'sizeMiB': sizeMiB,
'snapCPG': optional['snapCPG'],
'snapshotSpace': {'freeMiB': 0,
'rawReservedMiB': 683,
'reservedMiB': 512,
'usedMiB': 512},
'ssSpcAllocLimitPct': 0,
'ssSpcAllocWarningPct': 0,
'state': 1,
'userCPG': cpgName,
'userSpace': {'freeMiB': 0,
'rawReservedMiB': 41984,
'reservedMiB': 31488,
'usedMiB': 31488},
'usrSpcAllocLimitPct': 0,
'usrSpcAllocWarningPct': 0,
'uuid': '1e7daee4-49f4-4d07-9ab8-2b6a4319e243',
'wwn': '50002AC00073383D'}
self.volumes.append(new_vol)
return None
def deleteVolume(self, name):
volume = self.getVolume(name)
self.volumes.remove(volume)
def createSnapshot(self, name, copyOfName, optional=None):
new_snap = {'additionalStates': [],
'adminSpace': {'freeMiB': 0,
'rawReservedMiB': 0,
'reservedMiB': 0,
'usedMiB': 0},
'baseId': 342,
'comment': optional['comment'],
'copyOf': copyOfName,
'copyType': 3,
'creationTime8601': '2012-11-09T15:13:28-08:00',
'creationTimeSec': 1352502808,
'degradedStates': [],
'domain': HP3PAR_DOMAIN,
'expirationTime8601': '2012-11-09T17:13:28-08:00',
'expirationTimeSec': 1352510008,
'failedStates': [],
'id': 343,
'name': name,
'parentId': 342,
'policies': {'caching': True,
'oneHost': False,
'staleSS': True,
'system': False,
'zeroDetect': False},
'provisioningType': 3,
'readOnly': True,
'retentionTime8601': '2012-11-09T16:13:27-08:00',
'retentionTimeSec': 1352506407,
'sizeMiB': 256,
'snapCPG': HP3PAR_CPG_SNAP,
'snapshotSpace': {'freeMiB': 0,
'rawReservedMiB': 0,
'reservedMiB': 0,
'usedMiB': 0},
'ssSpcAllocLimitPct': 0,
'ssSpcAllocWarningPct': 0,
'state': 1,
'userCPG': HP3PAR_CPG,
'userSpace': {'freeMiB': 0,
'rawReservedMiB': 0,
'reservedMiB': 0,
'usedMiB': 0},
'usrSpcAllocLimitPct': 0,
'usrSpcAllocWarningPct': 0,
'uuid': 'd7a40b8f-2511-46a8-9e75-06383c826d19',
'wwn': '50002AC00157383D'}
self.volumes.append(new_snap)
return None
def deleteSnapshot(self, name):
volume = self.getVolume(name)
self.volumes.remove(volume)
def createCPG(self, name, optional=None):
cpg = {'SAGrowth': {'LDLayout': {'diskPatterns': [{'diskType': 2}]},
'incrementMiB': 8192},
'SAUsage': {'rawTotalMiB': 24576,
'rawUsedMiB': 768,
'totalMiB': 8192,
'usedMiB': 256},
'SDGrowth': {'LDLayout': {'RAIDType': 4,
'diskPatterns': [{'diskType': 2}]},
'incrementMiB': 32768},
'SDUsage': {'rawTotalMiB': 49152,
'rawUsedMiB': 1023,
'totalMiB': 36864,
'usedMiB': 768},
'UsrUsage': {'rawTotalMiB': 57344,
'rawUsedMiB': 43349,
'totalMiB': 43008,
'usedMiB': 32512},
'additionalStates': [],
'degradedStates': [],
'domain': HP3PAR_DOMAIN,
'failedStates': [],
'id': 1,
'name': name,
'numFPVVs': 2,
'numTPVVs': 0,
'state': 1,
'uuid': '29c214aa-62b9-41c8-b198-000000000000'}
new_cpg = cpg.copy()
new_cpg.update(optional)
self.cpgs.append(new_cpg)
def getCPGs(self):
return self.cpgs
def getCPG(self, name):
if self.cpgs:
for cpg in self.cpgs:
if cpg['name'] == name:
return cpg
msg = {'code': 'NON_EXISTENT_HOST',
'desc': "CPG '%s' was not found" % name}
raise hpexceptions.HTTPNotFound(msg)
def deleteCPG(self, name):
cpg = self.getCPG(name)
self.cpgs.remove(cpg)
def createVLUN(self, volumeName, lun, hostname=None,
portPos=None, noVcn=None,
overrideLowerPriority=None):
vlun = {'active': False,
'failedPathInterval': 0,
'failedPathPol': 1,
'hostname': hostname,
'lun': lun,
'multipathing': 1,
'portPos': portPos,
'type': 4,
'volumeName': volumeName,
'volumeWWN': '50002AC00077383D'}
self.vluns.append(vlun)
return None
def deleteVLUN(self, name, lunID, hostname=None, port=None):
vlun = self.getVLUN(name)
self.vluns.remove(vlun)
def getVLUNs(self):
return self.vluns
def getVLUN(self, volumeName):
for vlun in self.vluns:
if vlun['volumeName'] == volumeName:
return vlun
msg = {'code': 'NON_EXISTENT_HOST',
'desc': "VLUN '%s' was not found" % volumeName}
raise hpexceptions.HTTPNotFound(msg)
def getHost(self, hostname):
return None
def modifyHost(self, hostname, options):
return None
def getPorts(self):
return None
class HP3PARBaseDriver():
VOLUME_ID = "d03338a9-9115-48a3-8dfc-35cdfcdc15a7"
CLONE_ID = "d03338a9-9115-48a3-8dfc-000000000000"
VOLUME_NAME = "volume-d03338a9-9115-48a3-8dfc-35cdfcdc15a7"
SNAPSHOT_ID = "2f823bdc-e36e-4dc8-bd15-de1c7a28ff31"
SNAPSHOT_NAME = "snapshot-2f823bdc-e36e-4dc8-bd15-de1c7a28ff31"
VOLUME_3PAR_NAME = "osv-0DM4qZEVSKON-DXN-NwVpw"
SNAPSHOT_3PAR_NAME = "oss-L4I73ONuTci9Fd4ceij-MQ"
FAKE_HOST = "fakehost"
USER_ID = '2689d9a913974c008b1d859013f23607'
PROJECT_ID = 'fac88235b9d64685a3530f73e490348f'
VOLUME_ID_SNAP = '761fc5e5-5191-4ec7-aeba-33e36de44156'
FAKE_DESC = 'test description name'
FAKE_FC_PORTS = [{'portPos': {'node': 7, 'slot': 1, 'cardPort': 1},
'portWWN': '0987654321234',
'protocol': 1,
'mode': 2,
'linkState': 4},
{'portPos': {'node': 6, 'slot': 1, 'cardPort': 1},
'portWWN': '123456789000987',
'protocol': 1,
'mode': 2,
'linkState': 4}]
QOS = {'qos:maxIOPS': '1000', 'qos:maxBWS': '50'}
VVS_NAME = "myvvs"
FAKE_ISCSI_PORT = {'portPos': {'node': 8, 'slot': 1, 'cardPort': 1},
'protocol': 2,
'mode': 2,
'IPAddr': '1.1.1.2',
'iSCSIName': ('iqn.2000-05.com.3pardata:'
'21810002ac00383d'),
'linkState': 4}
volume = {'name': VOLUME_NAME,
'id': VOLUME_ID,
'display_name': 'Foo Volume',
'size': 2,
'host': FAKE_HOST,
'volume_type': None,
'volume_type_id': None}
volume_qos = {'name': VOLUME_NAME,
'id': VOLUME_ID,
'display_name': 'Foo Volume',
'size': 2,
'host': FAKE_HOST,
'volume_type': None,
'volume_type_id': 'gold'}
snapshot = {'name': SNAPSHOT_NAME,
'id': SNAPSHOT_ID,
'user_id': USER_ID,
'project_id': PROJECT_ID,
'volume_id': VOLUME_ID_SNAP,
'volume_name': VOLUME_NAME,
'status': 'creating',
'progress': '0%',
'volume_size': 2,
'display_name': 'fakesnap',
'display_description': FAKE_DESC}
connector = {'ip': '10.0.0.2',
'initiator': 'iqn.1993-08.org.debian:01:222',
'wwpns': ["123456789012345", "123456789054321"],
'wwnns': ["223456789012345", "223456789054321"],
'host': 'fakehost'}
volume_type = {'name': 'gold',
'deleted': False,
'updated_at': None,
'extra_specs': {'qos:maxBWS': '50',
'qos:maxIOPS': '1000'},
'deleted_at': None,
'id': 'gold'}
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_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, "_set_connections",
self.fake_set_connections)
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(hpdriver.hpcommon.HP3PARCommon, "get_cpg",
self.fake_get_cpg)
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon,
"get_volume_settings_from_type",
self.fake_get_volume_settings_from_type)
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 fake_get_cpg(self, volume, allowSnap=False):
return HP3PAR_CPG
def fake_set_connections(self):
return
def fake_get_domain(self, cpg):
return HP3PAR_DOMAIN
def fake_extend_volume(self, volume, new_size):
vol = self.driver.common.client.getVolume(volume['name'])
old_size = vol['sizeMiB']
option = {'comment': vol['comment'], 'snapCPG': vol['snapCPG']}
self.driver.common.client.deleteVolume(volume['name'])
self.driver.common.client.createVolume(vol['name'],
vol['userCPG'],
new_size, option)
def fake_get_3par_host(self, hostname):
if hostname not in self._hosts:
msg = {'code': 'NON_EXISTENT_HOST',
'desc': "HOST '%s' was not found" % hostname}
raise hpexceptions.HTTPNotFound(msg)
else:
return self._hosts[hostname]
def fake_delete_3par_host(self, hostname):
if hostname not in self._hosts:
msg = {'code': 'NON_EXISTENT_HOST',
'desc': "HOST '%s' was not found" % hostname}
raise hpexceptions.HTTPNotFound(msg)
else:
del self._hosts[hostname]
def fake_create_3par_vlun(self, volume, hostname, nsp):
self.driver.common.client.createVLUN(volume, 19, hostname, nsp)
def fake_get_ports(self):
ports = self.FAKE_FC_PORTS
ports.append(self.FAKE_ISCSI_PORT)
return {'members': ports}
def fake_get_volume_type(self, type_id):
return self.volume_type
def fake_get_qos_by_volume_type(self, volume_type):
return self.QOS
def fake_add_volume_to_volume_set(self, volume, volume_name,
cpg, vvs_name, qos):
return volume
def fake_copy_volume(self, src_name, dest_name, cpg=None,
snap_cpg=None, tpvv=True):
pass
def fake_get_volume_stats(self, vol_name):
return "normal"
def fake_get_volume_settings_from_type(self, volume):
return {'cpg': HP3PAR_CPG,
'snap_cpg': HP3PAR_CPG_SNAP,
'vvs_name': self.VVS_NAME,
'qos': self.QOS,
'tpvv': True,
'volume_type': self.volume_type}
def fake_get_volume_settings_from_type_noqos(self, volume):
return {'cpg': HP3PAR_CPG,
'snap_cpg': HP3PAR_CPG_SNAP,
'vvs_name': None,
'qos': None,
'tpvv': True,
'volume_type': None}
def test_create_volume(self):
self.flags(lock_path=self.tempdir)
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon,
"get_volume_settings_from_type",
self.fake_get_volume_settings_from_type_noqos)
self.driver.create_volume(self.volume)
volume = self.driver.common.client.getVolume(self.VOLUME_3PAR_NAME)
self.assertEqual(volume['name'], self.VOLUME_3PAR_NAME)
def test_create_volume_qos(self):
self.flags(lock_path=self.tempdir)
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon,
"get_volume_settings_from_type",
self.fake_get_volume_settings_from_type)
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon,
"_add_volume_to_volume_set",
self.fake_add_volume_to_volume_set)
self.driver.create_volume(self.volume_qos)
volume = self.driver.common.client.getVolume(self.VOLUME_3PAR_NAME)
self.assertEqual(volume['name'], self.VOLUME_3PAR_NAME)
self.assertNotIn(self.QOS, dict(ast.literal_eval(volume['comment'])))
def test_delete_volume(self):
self.flags(lock_path=self.tempdir)
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon,
"get_volume_settings_from_type",
self.fake_get_volume_settings_from_type)
self.driver.delete_volume(self.volume)
self.assertRaises(hpexceptions.HTTPNotFound,
self.driver.common.client.getVolume,
self.VOLUME_ID)
def test_create_cloned_volume(self):
self.flags(lock_path=self.tempdir)
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon,
"get_volume_settings_from_type",
self.fake_get_volume_settings_from_type)
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_copy_volume",
self.fake_copy_volume)
volume = {'name': HP3PARBaseDriver.VOLUME_NAME,
'id': HP3PARBaseDriver.CLONE_ID,
'display_name': 'Foo Volume',
'size': 2,
'host': HP3PARBaseDriver.FAKE_HOST,
'source_volid': HP3PARBaseDriver.VOLUME_ID}
src_vref = {}
model_update = self.driver.create_cloned_volume(volume, src_vref)
self.assertIsNotNone(model_update)
@mock.patch.object(hpdriver.hpcommon.HP3PARCommon, '_run_ssh')
def test_attach_volume(self, mock_run_ssh):
mock_run_ssh.side_effect = [[CLI_CR, ''], Exception('Custom ex')]
self.driver.attach_volume(context.get_admin_context(),
self.volume,
'abcdef',
'newhost',
'/dev/vdb')
self.assertTrue(mock_run_ssh.called)
self.assertRaises(exception.CinderException,
self.driver.attach_volume,
context.get_admin_context(),
self.volume,
'abcdef',
'newhost',
'/dev/vdb')
@mock.patch.object(hpdriver.hpcommon.HP3PARCommon, '_run_ssh')
def test_detach_volume(self, mock_run_ssh):
mock_run_ssh.side_effect = [[CLI_CR, ''], Exception('Custom ex')]
self.driver.detach_volume(context.get_admin_context(), self.volume)
self.assertTrue(mock_run_ssh.called)
self.assertRaises(exception.CinderException,
self.driver.detach_volume,
context.get_admin_context(),
self.volume)
def test_create_snapshot(self):
self.flags(lock_path=self.tempdir)
self.driver.create_snapshot(self.snapshot)
# check to see if the snapshot was created
snap_vol = self.driver.common.client.getVolume(self.SNAPSHOT_3PAR_NAME)
self.assertEqual(snap_vol['name'], self.SNAPSHOT_3PAR_NAME)
def test_delete_snapshot(self):
self.flags(lock_path=self.tempdir)
self.driver.create_snapshot(self.snapshot)
#make sure it exists first
vol = self.driver.common.client.getVolume(self.SNAPSHOT_3PAR_NAME)
self.assertEqual(vol['name'], self.SNAPSHOT_3PAR_NAME)
self.driver.delete_snapshot(self.snapshot)
# the snapshot should be deleted now
self.assertRaises(hpexceptions.HTTPNotFound,
self.driver.common.client.getVolume,
self.SNAPSHOT_3PAR_NAME)
def test_delete_snapshot_in_use(self):
self.flags(lock_path=self.tempdir)
self.driver.create_snapshot(self.snapshot)
self.driver.create_volume_from_snapshot(self.volume, self.snapshot)
ex = hpexceptions.HTTPConflict("In use")
self.driver.common.client.deleteVolume = mock.Mock(side_effect=ex)
# Deleting the snapshot that a volume is dependent on should fail
self.assertRaises(exception.SnapshotIsBusy,
self.driver.delete_snapshot,
self.snapshot)
def test_create_volume_from_snapshot(self):
self.flags(lock_path=self.tempdir)
self.driver.create_volume_from_snapshot(self.volume, self.snapshot)
snap_vol = self.driver.common.client.getVolume(self.VOLUME_3PAR_NAME)
self.assertEqual(snap_vol['name'], self.VOLUME_3PAR_NAME)
volume = self.volume.copy()
volume['size'] = 1
self.assertRaises(exception.InvalidInput,
self.driver.create_volume_from_snapshot,
volume, self.snapshot)
def test_create_volume_from_snapshot_qos(self):
self.flags(lock_path=self.tempdir)
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_get_volume_type",
self.fake_get_volume_type)
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon,
"_get_qos_by_volume_type",
self.fake_get_qos_by_volume_type)
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon,
"_add_volume_to_volume_set",
self.fake_add_volume_to_volume_set)
self.driver.create_volume_from_snapshot(self.volume_qos, self.snapshot)
snap_vol = self.driver.common.client.getVolume(self.VOLUME_3PAR_NAME)
self.assertEqual(snap_vol['name'], self.VOLUME_3PAR_NAME)
self.assertNotIn(self.QOS, dict(ast.literal_eval(snap_vol['comment'])))
volume = self.volume.copy()
volume['size'] = 1
self.assertRaises(exception.InvalidInput,
self.driver.create_volume_from_snapshot,
volume, self.snapshot)
def test_terminate_connection(self):
self.flags(lock_path=self.tempdir)
#setup the connections
self.driver.initialize_connection(self.volume, self.connector)
vlun = self.driver.common.client.getVLUN(self.VOLUME_3PAR_NAME)
self.assertEqual(vlun['volumeName'], self.VOLUME_3PAR_NAME)
self.driver.terminate_connection(self.volume, self.connector,
force=True)
# vlun should be gone.
self.assertRaises(hpexceptions.HTTPNotFound,
self.driver.common.client.getVLUN,
self.VOLUME_3PAR_NAME)
@mock.patch.object(hpdriver.hpcommon.HP3PARCommon, '_run_ssh')
def test_update_volume_key_value_pair(self, mock_run_ssh):
mock_run_ssh.return_value = [CLI_CR, '']
self.assertEqual(
self.driver.common.update_volume_key_value_pair(self.volume,
'a',
'b'),
None)
update_cmd = ['setvv', '-setkv', 'a=b', self.VOLUME_3PAR_NAME]
mock_run_ssh.assert_called_once_with(update_cmd, False)
self.assertRaises(exception.VolumeBackendAPIException,
self.driver.common.update_volume_key_value_pair,
self.volume,
None,
'b')
@mock.patch.object(hpdriver.hpcommon.HP3PARCommon, '_run_ssh')
def test_clear_volume_key_value_pair(self, mock_run_ssh):
mock_run_ssh.side_effect = [[CLI_CR, ''], Exception('Custom ex')]
self.assertEqual(
self.driver.common.clear_volume_key_value_pair(self.volume, 'a'),
None)
clear_cmd = ['setvv', '-clrkey', 'a', self.VOLUME_3PAR_NAME]
mock_run_ssh.assert_called_once_with(clear_cmd, False)
self.assertRaises(exception.VolumeBackendAPIException,
self.driver.common.clear_volume_key_value_pair,
self.volume,
None)
def test_extend_volume(self):
self.flags(lock_path=self.tempdir)
self.stubs.UnsetAll()
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "extend_volume",
self.fake_extend_volume)
option = {'comment': '', 'snapCPG': HP3PAR_CPG_SNAP}
self.driver.common.client.createVolume(self.volume['name'],
HP3PAR_CPG,
self.volume['size'],
option)
old_size = self.volume['size']
volume = self.driver.common.client.getVolume(self.volume['name'])
self.driver.extend_volume(volume, str(old_size + 1))
vol = self.driver.common.client.getVolume(self.volume['name'])
self.assertEqual(vol['sizeMiB'], str(old_size + 1))
class TestHP3PARFCDriver(HP3PARBaseDriver, test.TestCase):
_hosts = {}
def setUp(self):
self.tempdir = tempfile.mkdtemp()
super(TestHP3PARFCDriver, self).setUp()
self.setup_driver(self.setup_configuration())
self.setup_fakes()
def setup_fakes(self):
super(TestHP3PARFCDriver, self).setup_fakes()
self.stubs.Set(hpfcdriver.HP3PARFCDriver,
"_create_3par_fibrechan_host",
self.fake_create_3par_fibrechan_host)
def tearDown(self):
shutil.rmtree(self.tempdir)
self.assertEqual(0, self.driver.common.client.connection_count,
'Leaked hp3parclient connection.')
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.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_set_connections",
self.fake_set_connections)
self.driver.do_setup(None)
def fake_create_3par_fibrechan_host(self, hostname, wwn,
domain, persona_id):
host = {'FCPaths': [{'driverVersion': None,
'firmwareVersion': None,
'hostSpeed': 0,
'model': None,
'portPos': {'cardPort': 1, 'node': 1,
'slot': 2},
'vendor': None,
'wwn': wwn[0]},
{'driverVersion': None,
'firmwareVersion': None,
'hostSpeed': 0,
'model': None,
'portPos': {'cardPort': 1, 'node': 0,
'slot': 2},
'vendor': None,
'wwn': wwn[1]}],
'descriptors': None,
'domain': domain,
'iSCSIPaths': [],
'id': 11,
'name': hostname}
self._hosts[hostname] = host
self.properties = {'data':
{'target_discovered': True,
'target_lun': 186,
'target_portal': '1.1.1.2:1234'},
'driver_volume_type': 'fibre_channel'}
return hostname
def test_initialize_connection(self):
self.flags(lock_path=self.tempdir)
result = self.driver.initialize_connection(self.volume, self.connector)
self.assertEqual(result['driver_volume_type'], 'fibre_channel')
# we should have a host and a vlun now.
host = self.fake_get_3par_host(self.FAKE_HOST)
self.assertEqual(self.FAKE_HOST, host['name'])
self.assertEqual(HP3PAR_DOMAIN, host['domain'])
vlun = self.driver.common.client.getVLUN(self.VOLUME_3PAR_NAME)
self.assertEqual(self.VOLUME_3PAR_NAME, vlun['volumeName'])
self.assertEqual(self.FAKE_HOST, vlun['hostname'])
def test_get_volume_stats(self):
self.flags(lock_path=self.tempdir)
def fake_safe_get(*args):
return "HP3PARFCDriver"
self.stubs.Set(self.driver.configuration, 'safe_get', fake_safe_get)
stats = self.driver.get_volume_stats(True)
self.assertEqual(stats['storage_protocol'], 'FC')
self.assertEqual(stats['total_capacity_gb'], 'infinite')
self.assertEqual(stats['free_capacity_gb'], 'infinite')
#modify the CPG to have a limit
old_cpg = self.driver.common.client.getCPG(HP3PAR_CPG)
options = {'SDGrowth': {'limitMiB': 8192}}
self.driver.common.client.deleteCPG(HP3PAR_CPG)
self.driver.common.client.createCPG(HP3PAR_CPG, options)
const = 0.0009765625
stats = self.driver.get_volume_stats(True)
self.assertEqual(stats['storage_protocol'], 'FC')
total_capacity_gb = 8192 * const
self.assertEqual(stats['total_capacity_gb'], total_capacity_gb)
free_capacity_gb = int((8192 - old_cpg['UsrUsage']['usedMiB']) * const)
self.assertEqual(stats['free_capacity_gb'], free_capacity_gb)
self.driver.common.client.deleteCPG(HP3PAR_CPG)
self.driver.common.client.createCPG(HP3PAR_CPG, {})
def test_create_host(self):
self.flags(lock_path=self.tempdir)
#record
self.clear_mox()
self.stubs.Set(hpfcdriver.hpcommon.HP3PARCommon, "get_cpg",
self.fake_get_cpg)
self.stubs.Set(hpfcdriver.hpcommon.HP3PARCommon, "get_domain",
self.fake_get_domain)
_run_ssh = self.mox.CreateMock(hpdriver.hpcommon.HP3PARCommon._run_ssh)
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_run_ssh", _run_ssh)
getHost = self.mox.CreateMock(FakeHP3ParClient.getHost)
self.stubs.Set(FakeHP3ParClient, "getHost", getHost)
ex = hpexceptions.HTTPNotFound('Host not found.')
getHost('fakehost').AndRaise(ex)
create_host_cmd = (['createhost', '-persona', '1', '-domain',
('OpenStack',), 'fakehost', '123456789012345',
'123456789054321'])
_run_ssh(create_host_cmd, False).AndReturn([CLI_CR, ''])
getHost('fakehost').AndReturn({'name': self.FAKE_HOST,
'FCPaths': [{'wwn': '123456789012345'},
{'wwn': '123456789054321'}]}
)
self.mox.ReplayAll()
host = self.driver._create_host(self.volume, self.connector)
self.assertEqual(host['name'], self.FAKE_HOST)
def test_create_invalid_host(self):
self.flags(lock_path=self.tempdir)
#record
self.clear_mox()
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "get_cpg",
self.fake_get_cpg)
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "get_domain",
self.fake_get_domain)
_run_ssh = self.mox.CreateMock(hpdriver.hpcommon.HP3PARCommon._run_ssh)
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_run_ssh", _run_ssh)
getHost = self.mox.CreateMock(FakeHP3ParClient.getHost)
self.stubs.Set(FakeHP3ParClient, "getHost", getHost)
not_found_ex = hpexceptions.HTTPNotFound('Host not found.')
getHost('fakehost').AndRaise(not_found_ex)
create_host_cmd = (['createhost', '-persona', '1', '-domain',
('OpenStack',), 'fakehost', '123456789012345',
'123456789054321'])
create_host_ret = pack(CLI_CR +
'already used by host fakehost.foo (19)')
_run_ssh(create_host_cmd, False).AndReturn([create_host_ret, ''])
host_ret = {
'name': 'fakehost.foo',
'FCPaths': [{'wwn': '123456789012345'},
{'wwn': '123456789054321'}]}
getHost('fakehost.foo').AndReturn(host_ret)
self.mox.ReplayAll()
host = self.driver._create_host(self.volume, self.connector)
self.assertEqual(host['name'], 'fakehost.foo')
def test_create_modify_host(self):
self.flags(lock_path=self.tempdir)
#record
self.clear_mox()
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "get_cpg",
self.fake_get_cpg)
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "get_domain",
self.fake_get_domain)
getHost = self.mox.CreateMock(FakeHP3ParClient.getHost)
self.stubs.Set(FakeHP3ParClient, "getHost", getHost)
modifyHost = self.mox.CreateMock(FakeHP3ParClient.modifyHost)
self.stubs.Set(FakeHP3ParClient, "modifyHost", modifyHost)
getHost('fakehost').AndReturn(({'name': self.FAKE_HOST,
'FCPaths': []}))
modifyHost('fakehost', {'FCWWNs':
['123456789012345', '123456789054321'],
'pathOperation': 1})
getHost('fakehost').AndReturn({'name': self.FAKE_HOST,
'FCPaths': [{'wwn': '123456789012345'},
{'wwn': '123456789054321'}]}
)
self.mox.ReplayAll()
host = self.driver._create_host(self.volume, self.connector)
self.assertEqual(host['name'], self.FAKE_HOST)
self.assertEqual(len(host['FCPaths']), 2)
def test_modify_host_with_new_wwn(self):
self.flags(lock_path=self.tempdir)
self.clear_mox()
hpdriver.hpcommon.HP3PARCommon.get_cpg = mock.Mock(
return_value=self.fake_get_cpg)
hpdriver.hpcommon.HP3PARCommon.get_domain = mock.Mock(
return_value=self.fake_get_domain)
# set up the getHost mock
self.driver.common.client.getHost = mock.Mock()
# define the return values for the 2 calls
getHost_ret1 = {
'name': self.FAKE_HOST,
'FCPaths': [{'wwn': '123456789054321'}]}
getHost_ret2 = {
'name': self.FAKE_HOST,
'FCPaths': [{'wwn': '123456789012345'},
{'wwn': '123456789054321'}]}
self.driver.common.client.getHost.side_effect = [
getHost_ret1, getHost_ret2]
# setup the modifyHost mock
self.driver.common.client.modifyHost = mock.Mock()
host = self.driver._create_host(self.volume, self.connector)
# mock assertions
self.driver.common.client.getHost.assert_has_calls([
mock.call('fakehost'),
mock.call('fakehost')])
self.driver.common.client.modifyHost.assert_called_once_with(
'fakehost', {'FCWWNs': ['123456789012345'], 'pathOperation': 1})
self.assertEqual(host['name'], self.FAKE_HOST)
self.assertEqual(len(host['FCPaths']), 2)
def test_modify_host_with_unknown_wwn_and_new_wwn(self):
self.flags(lock_path=self.tempdir)
self.clear_mox()
hpdriver.hpcommon.HP3PARCommon.get_cpg = mock.Mock(
return_value=self.fake_get_cpg)
hpdriver.hpcommon.HP3PARCommon.get_domain = mock.Mock(
return_value=self.fake_get_domain)
# set up the getHost mock
self.driver.common.client.getHost = mock.Mock()
# define the return values for the 2 calls
getHost_ret1 = {
'name': self.FAKE_HOST,
'FCPaths': [{'wwn': '123456789054321'},
{'wwn': 'xxxxxxxxxxxxxxx'}]}
getHost_ret2 = {
'name': self.FAKE_HOST,
'FCPaths': [{'wwn': '123456789012345'},
{'wwn': '123456789054321'},
{'wwn': 'xxxxxxxxxxxxxxx'}]}
self.driver.common.client.getHost.side_effect = [
getHost_ret1, getHost_ret2]
# setup the modifyHost mock
self.driver.common.client.modifyHost = mock.Mock()
host = self.driver._create_host(self.volume, self.connector)
# mock assertions
self.driver.common.client.getHost.assert_has_calls([
mock.call('fakehost'),
mock.call('fakehost')])
self.driver.common.client.modifyHost.assert_called_once_with(
'fakehost', {'FCWWNs': ['123456789012345'], 'pathOperation': 1})
self.assertEqual(host['name'], self.FAKE_HOST)
self.assertEqual(len(host['FCPaths']), 3)
class TestHP3PARISCSIDriver(HP3PARBaseDriver, test.TestCase):
TARGET_IQN = "iqn.2000-05.com.3pardata:21810002ac00383d"
_hosts = {}
def setUp(self):
self.tempdir = tempfile.mkdtemp()
super(TestHP3PARISCSIDriver, self).setUp()
self.setup_driver(self.setup_configuration())
self.setup_fakes()
def setup_fakes(self):
super(TestHP3PARISCSIDriver, self).setup_fakes()
self.stubs.Set(hpdriver.HP3PARISCSIDriver, "_create_3par_iscsi_host",
self.fake_create_3par_iscsi_host)
#target_iqn = 'iqn.2000-05.com.3pardata:21810002ac00383d'
self.properties = {'data':
{'target_discovered': True,
'target_iqn': self.TARGET_IQN,
'target_lun': 186,
'target_portal': '1.1.1.2:1234'},
'driver_volume_type': 'iscsi'}
def tearDown(self):
shutil.rmtree(self.tempdir)
self.assertEqual(0, self.driver.common.client.connection_count,
'Leaked hp3parclient connection.')
self._hosts = {}
super(TestHP3PARISCSIDriver, self).tearDown()
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.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_set_connections",
self.fake_set_connections)
self.driver.do_setup(None)
def fake_create_3par_iscsi_host(self, hostname, iscsi_iqn,
domain, persona_id):
host = {'FCPaths': [],
'descriptors': None,
'domain': domain,
'iSCSIPaths': [{'driverVersion': None,
'firmwareVersion': None,
'hostSpeed': 0,
'ipAddr': '10.10.221.59',
'model': None,
'name': iscsi_iqn,
'portPos': {'cardPort': 1, 'node': 1,
'slot': 8},
'vendor': None}],
'id': 11,
'name': hostname}
self._hosts[hostname] = host
return hostname
def test_initialize_connection(self):
self.flags(lock_path=self.tempdir)
result = self.driver.initialize_connection(self.volume, self.connector)
self.assertEqual(result['driver_volume_type'], 'iscsi')
self.assertEqual(result['data']['target_iqn'],
self.properties['data']['target_iqn'])
self.assertEqual(result['data']['target_portal'],
self.properties['data']['target_portal'])
self.assertEqual(result['data']['target_discovered'],
self.properties['data']['target_discovered'])
# we should have a host and a vlun now.
host = self.fake_get_3par_host(self.FAKE_HOST)
self.assertEqual(self.FAKE_HOST, host['name'])
self.assertEqual(HP3PAR_DOMAIN, host['domain'])
vlun = self.driver.common.client.getVLUN(self.VOLUME_3PAR_NAME)
self.assertEqual(self.VOLUME_3PAR_NAME, vlun['volumeName'])
self.assertEqual(self.FAKE_HOST, vlun['hostname'])
def test_get_volume_stats(self):
self.flags(lock_path=self.tempdir)
def fake_safe_get(*args):
return "HP3PARFCDriver"
self.stubs.Set(self.driver.configuration, 'safe_get', fake_safe_get)
stats = self.driver.get_volume_stats(True)
self.assertEqual(stats['storage_protocol'], 'iSCSI')
self.assertEqual(stats['total_capacity_gb'], 'infinite')
self.assertEqual(stats['free_capacity_gb'], 'infinite')
#modify the CPG to have a limit
old_cpg = self.driver.common.client.getCPG(HP3PAR_CPG)
options = {'SDGrowth': {'limitMiB': 8192}}
self.driver.common.client.deleteCPG(HP3PAR_CPG)
self.driver.common.client.createCPG(HP3PAR_CPG, options)
const = 0.0009765625
stats = self.driver.get_volume_stats(True)
self.assertEqual(stats['storage_protocol'], 'iSCSI')
total_capacity_gb = 8192 * const
self.assertEqual(stats['total_capacity_gb'], total_capacity_gb)
free_capacity_gb = int((8192 - old_cpg['UsrUsage']['usedMiB']) * const)
self.assertEqual(stats['free_capacity_gb'], free_capacity_gb)
self.driver.common.client.deleteCPG(HP3PAR_CPG)
self.driver.common.client.createCPG(HP3PAR_CPG, {})
def test_create_host(self):
self.flags(lock_path=self.tempdir)
#record
self.clear_mox()
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "get_cpg",
self.fake_get_cpg)
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "get_domain",
self.fake_get_domain)
_run_ssh = self.mox.CreateMock(hpdriver.hpcommon.HP3PARCommon._run_ssh)
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_run_ssh", _run_ssh)
getHost = self.mox.CreateMock(FakeHP3ParClient.getHost)
self.stubs.Set(FakeHP3ParClient, "getHost", getHost)
not_found_ex = hpexceptions.HTTPNotFound('Host not found.')
getHost('fakehost').AndRaise(not_found_ex)
create_host_cmd = (['createhost', '-iscsi', '-persona', '1', '-domain',
('OpenStack',), 'fakehost',
'iqn.1993-08.org.debian:01:222'])
_run_ssh(create_host_cmd, False).AndReturn([CLI_CR, ''])
getHost('fakehost').AndReturn({'name': self.FAKE_HOST})
self.mox.ReplayAll()
host = self.driver._create_host(self.volume, self.connector)
self.assertEqual(host['name'], self.FAKE_HOST)
def test_create_invalid_host(self):
self.flags(lock_path=self.tempdir)
#record
self.clear_mox()
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "get_cpg",
self.fake_get_cpg)
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "get_domain",
self.fake_get_domain)
_run_ssh = self.mox.CreateMock(hpdriver.hpcommon.HP3PARCommon._run_ssh)
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_run_ssh", _run_ssh)
getHost = self.mox.CreateMock(FakeHP3ParClient.getHost)
self.stubs.Set(FakeHP3ParClient, "getHost", getHost)
not_found_ex = hpexceptions.HTTPNotFound('Host not found.')
getHost('fakehost').AndRaise(not_found_ex)
create_host_cmd = (['createhost', '-iscsi', '-persona', '1', '-domain',
('OpenStack',), 'fakehost',
'iqn.1993-08.org.debian:01:222'])
in_use_ret = pack('\r\nalready used by host fakehost.foo ')
_run_ssh(create_host_cmd, False).AndReturn([in_use_ret, ''])
getHost('fakehost.foo').AndReturn({'name': 'fakehost.foo'})
self.mox.ReplayAll()
host = self.driver._create_host(self.volume, self.connector)
self.assertEqual(host['name'], 'fakehost.foo')
def test_create_modify_host(self):
self.flags(lock_path=self.tempdir)
#record
self.clear_mox()
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "get_cpg",
self.fake_get_cpg)
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "get_domain",
self.fake_get_domain)
getHost = self.mox.CreateMock(FakeHP3ParClient.getHost)
self.stubs.Set(FakeHP3ParClient, "getHost", getHost)
modifyHost = self.mox.CreateMock(FakeHP3ParClient.modifyHost)
self.stubs.Set(FakeHP3ParClient, "modifyHost", modifyHost)
getHost('fakehost').AndReturn(({'name': self.FAKE_HOST,
'iSCSIPaths': []}))
modifyHost('fakehost', {'iSCSINames':
['iqn.1993-08.org.debian:01:222'],
'pathOperation': 1})
ret_value = {'name': self.FAKE_HOST,
'iSCSIPaths': [{'name': 'iqn.1993-08.org.debian:01:222'}]
}
getHost('fakehost').AndReturn(ret_value)
self.mox.ReplayAll()
host = self.driver._create_host(self.volume, self.connector)
self.assertEqual(host['name'], self.FAKE_HOST)
self.assertEqual(len(host['iSCSIPaths']), 1)
def test_get_ports(self):
self.flags(lock_path=self.tempdir)
#record
self.clear_mox()
getPorts = self.mox.CreateMock(FakeHP3ParClient.getPorts)
self.stubs.Set(FakeHP3ParClient, "getPorts", getPorts)
getPorts().AndReturn(PORTS1_RET)
self.mox.ReplayAll()
ports = self.driver.common.get_ports()['members']
self.assertEqual(len(ports), 3)
def test_get_least_used_nsp_for_host_single(self):
self.flags(lock_path=self.tempdir)
self.clear_mox()
self.driver.common.client.getPorts = mock.Mock(
return_value=PORTS_RET)
self.driver.common.client.getVLUNs = mock.Mock(
return_value=VLUNS1_RET)
#Setup a single ISCSI IP
iscsi_ips = ["10.10.220.253"]
self.driver.configuration.hp3par_iscsi_ips = iscsi_ips
self.driver.initialize_iscsi_ports()
nsp = self.driver._get_least_used_nsp_for_host('newhost')
self.assertEqual(nsp, "1:8:1")
def test_get_least_used_nsp_for_host_new(self):
self.flags(lock_path=self.tempdir)
self.clear_mox()
self.driver.common.client.getPorts = mock.Mock(
return_value=PORTS_RET)
self.driver.common.client.getVLUNs = mock.Mock(
return_value=VLUNS1_RET)
#Setup two ISCSI IPs
iscsi_ips = ["10.10.220.252", "10.10.220.253"]
self.driver.configuration.hp3par_iscsi_ips = iscsi_ips
self.driver.initialize_iscsi_ports()
# Host 'newhost' does not yet have any iscsi paths,
# so the 'least used' is returned
nsp = self.driver._get_least_used_nsp_for_host('newhost')
self.assertEqual(nsp, "1:8:2")
def test_get_least_used_nsp_for_host_reuse(self):
self.flags(lock_path=self.tempdir)
self.clear_mox()
self.driver.common.client.getPorts = mock.Mock(
return_value=PORTS_RET)
self.driver.common.client.getVLUNs = mock.Mock(
return_value=VLUNS1_RET)
#Setup two ISCSI IPs
iscsi_ips = ["10.10.220.252", "10.10.220.253"]
self.driver.configuration.hp3par_iscsi_ips = iscsi_ips
self.driver.initialize_iscsi_ports()
# hosts 'foo' and 'bar' already have active iscsi paths
# the same one should be used
nsp = self.driver._get_least_used_nsp_for_host('foo')
self.assertEqual(nsp, "1:8:2")
nsp = self.driver._get_least_used_nsp_for_host('bar')
self.assertEqual(nsp, "1:8:1")
def test_get_least_used_nps_for_host_fc(self):
# Ensure that with an active FC path setup
# an ISCSI path is used
self.flags(lock_path=self.tempdir)
self.clear_mox()
self.driver.common.client.getPorts = mock.Mock(
return_value=PORTS1_RET)
self.driver.common.client.getVLUNs = mock.Mock(
return_value=VLUNS5_RET)
#Setup two ISCSI IPs
iscsi_ips = ["10.10.220.252", "10.10.220.253"]
self.driver.configuration.hp3par_iscsi_ips = iscsi_ips
self.driver.initialize_iscsi_ports()
nsp = self.driver._get_least_used_nsp_for_host('newhost')
self.assertNotEqual(nsp, "0:6:3")
self.assertEqual(nsp, "1:8:1")
def test_invalid_iscsi_ip(self):
self.flags(lock_path=self.tempdir)
#record driver set up
self.clear_mox()
getPorts = self.mox.CreateMock(FakeHP3ParClient.getPorts)
self.stubs.Set(FakeHP3ParClient, "getPorts", getPorts)
getPorts().AndReturn(PORTS_RET)
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()
getVLUNs = self.mox.CreateMock(FakeHP3ParClient.getVLUNs)
self.stubs.Set(FakeHP3ParClient, "getVLUNs", getVLUNs)
getVLUNs().AndReturn(VLUNS3_RET)
getVLUNs().AndReturn(VLUNS4_RET)
getVLUNs().AndReturn(VLUNS4_RET)
self.mox.ReplayAll()
# in use count
vluns = self.driver.common.client.getVLUNs()
nsp = self.driver._get_least_used_nsp(vluns['members'],
['0:2:1', '1:8:1'])
self.assertEqual(nsp, '1:8:1')
# in use count
vluns = self.driver.common.client.getVLUNs()
nsp = self.driver._get_least_used_nsp(vluns['members'],
['0:2:1', '1:2:1'])
self.assertEqual(nsp, '1:2:1')
# in use count
vluns = self.driver.common.client.getVLUNs()
nsp = self.driver._get_least_used_nsp(vluns['members'],
['1:1:1', '1:2:1'])
self.assertEqual(nsp, '1:1:1')
def pack(arg):
header = '\r\n\r\n\r\n\r\n\r\n'
footer = '\r\n\r\n\r\n'
return header + arg + footer
PORTS_RET = ({'members':
[{'portPos': {'node': 1, 'slot': 8, 'cardPort': 2},
'protocol': 2,
'IPAddr': '10.10.220.252',
'linkState': 4,
'device': [],
'iSCSIName': 'iqn.2000-05.com.3pardata:21820002ac00383d',
'mode': 2,
'HWAddr': '2C27D75375D2',
'type': 8},
{'portPos': {'node': 1, 'slot': 8, 'cardPort': 1},
'protocol': 2,
'IPAddr': '10.10.220.253',
'linkState': 4,
'device': [],
'iSCSIName': 'iqn.2000-05.com.3pardata:21810002ac00383d',
'mode': 2,
'HWAddr': '2C27D75375D6',
'type': 8}]})
PORTS1_RET = ({'members':
[{'portPos': {'node': 0, 'slot': 8, 'cardPort': 2},
'protocol': 2,
'IPAddr': '10.10.120.252',
'linkState': 4,
'device': [],
'iSCSIName': 'iqn.2000-05.com.3pardata:21820002ac00383d',
'mode': 2,
'HWAddr': '2C27D75375D2',
'type': 8},
{'portPos': {'node': 1, 'slot': 8, 'cardPort': 1},
'protocol': 2,
'IPAddr': '10.10.220.253',
'linkState': 4,
'device': [],
'iSCSIName': 'iqn.2000-05.com.3pardata:21810002ac00383d',
'mode': 2,
'HWAddr': '2C27D75375D6',
'type': 8},
{'portWWN': '20210002AC00383D',
'protocol': 1,
'linkState': 4,
'mode': 2,
'device': ['cage2'],
'nodeWWN': '20210002AC00383D',
'type': 2,
'portPos': {'node': 0, 'slot': 6, 'cardPort': 3}}]})
VLUNS1_RET = ({'members':
[{'portPos': {'node': 1, 'slot': 8, 'cardPort': 2},
'hostname': 'foo', 'active': True},
{'portPos': {'node': 1, 'slot': 8, 'cardPort': 1},
'hostname': 'bar', 'active': True},
{'portPos': {'node': 1, 'slot': 8, 'cardPort': 1},
'hostname': 'bar', 'active': True},
{'portPos': {'node': 1, 'slot': 8, 'cardPort': 1},
'hostname': 'bar', 'active': True}]})
VLUNS2_RET = ({'members':
[{'portPos': {'node': 1, 'slot': 8, 'cardPort': 2},
'hostname': 'bar', 'active': True},
{'portPos': {'node': 1, 'slot': 8, 'cardPort': 1},
'hostname': 'bar', 'active': True},
{'portPos': {'node': 1, 'slot': 8, 'cardPort': 2},
'hostname': 'bar', 'active': True},
{'portPos': {'node': 1, 'slot': 8, 'cardPort': 2},
'hostname': 'fakehost', 'active': True}]})
VLUNS3_RET = ({'members':
[{'portPos': {'node': 1, 'slot': 8, 'cardPort': 2},
'active': True},
{'portPos': {'node': 1, 'slot': 8, 'cardPort': 1},
'active': True},
{'portPos': {'node': 1, 'slot': 8, 'cardPort': 2},
'active': True},
{'portPos': {'node': 0, 'slot': 2, 'cardPort': 2},
'active': True},
{'portPos': {'node': 0, 'slot': 2, 'cardPort': 1},
'active': True},
{'portPos': {'node': 0, 'slot': 2, 'cardPort': 1},
'active': True},
{'portPos': {'node': 0, 'slot': 2, 'cardPort': 1},
'active': True},
{'portPos': {'node': 0, 'slot': 2, 'cardPort': 1},
'active': True}]})
VLUNS4_RET = ({'members':
[{'portPos': {'node': 1, 'slot': 2, 'cardPort': 1},
'active': True},
{'portPos': {'node': 1, 'slot': 2, 'cardPort': 1},
'active': True},
{'portPos': {'node': 1, 'slot': 2, 'cardPort': 1},
'active': True},
{'portPos': {'node': 1, 'slot': 2, 'cardPort': 1},
'active': True},
{'portPos': {'node': 0, 'slot': 2, 'cardPort': 1},
'active': True},
{'portPos': {'node': 0, 'slot': 2, 'cardPort': 1},
'active': True},
{'portPos': {'node': 0, 'slot': 2, 'cardPort': 1},
'active': True},
{'portPos': {'node': 0, 'slot': 2, 'cardPort': 1},
'active': True},
{'portPos': {'node': 0, 'slot': 2, 'cardPort': 1},
'active': True}]})
VLUNS5_RET = ({'members':
[{'portPos': {'node': 0, 'slot': 8, 'cardPort': 2},
'active': True},
{'portPos': {'node': 1, 'slot': 8, 'cardPort': 1},
'active': True}]})