manila/manila/tests/test_hp3par.py

1045 lines
41 KiB
Python

#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# (c) Copyright 2013 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 Manila volume drivers
"""
import mox
import shutil
import tempfile
from hp3parclient import exceptions as hpexceptions
from manila import exception
from manila.openstack.common import log as logging
from manila import test
from manila.volume import configuration as conf
from manila.volume.drivers.san.hp import hp_3par_fc as hpfcdriver
from manila.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):
api_url = None
debug = False
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):
return None
def logout(self):
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)
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 = ['0987654321234', '123456789000987']
FAKE_ISCSI_PORTS = ['10.10.10.10', '10.10.10.11']
volume = {'name': VOLUME_NAME,
'id': VOLUME_ID,
'display_name': 'Foo Volume',
'size': 2,
'host': FAKE_HOST,
'volume_type': None,
'volume_type_id': None}
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'}
def fake_create_client(self):
return FakeHP3ParClient(self.driver.configuration.hp3par_api_url)
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:
self._hosts[hostname] = None
def fake_create_3par_vlun(self, volume, hostname):
self.driver.client.createVLUN(volume, 19, hostname)
def fake_get_ports(self):
return {'FC': self.FAKE_FC_PORTS, 'iSCSI': self.FAKE_ISCSI_PORTS}
def fake_copy_volume(self, src_name, dest_name):
pass
def fake_get_volume_state(self, vol_name):
return "normal"
def test_delete_volume(self):
self.flags(lock_path=self.tempdir)
self.driver.delete_volume(self.volume)
self.assertRaises(hpexceptions.HTTPNotFound,
self.driver.client.getVolume,
self.VOLUME_ID)
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.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.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.client.getVolume,
self.SNAPSHOT_3PAR_NAME)
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.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_terminate_connection(self):
self.flags(lock_path=self.tempdir)
#setup the connections
self.driver.initialize_connection(self.volume, self.connector)
vlun = self.driver.client.getVLUN(self.VOLUME_3PAR_NAME)
self.assertEqual(vlun['volumeName'], self.VOLUME_3PAR_NAME)
self.driver.terminate_connection(self.volume, self.connector, True)
# vlun should be gone.
self.assertRaises(hpexceptions.HTTPNotFound,
self.driver.client.getVLUN,
self.VOLUME_3PAR_NAME)
class TestHP3PARFCDriver(HP3PARBaseDriver, test.TestCase):
_hosts = {}
def setUp(self):
self.tempdir = tempfile.mkdtemp()
super(TestHP3PARFCDriver, self).setUp()
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 = ""
self.stubs.Set(hpfcdriver.HP3PARFCDriver, "_create_client",
self.fake_create_client)
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.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 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'}
def test_create_volume(self):
self.flags(lock_path=self.tempdir)
model_update = self.driver.create_volume(self.volume)
metadata = model_update['metadata']
self.assertFalse(metadata['3ParName'] is None)
self.assertEqual(metadata['CPG'], HP3PAR_CPG)
self.assertEqual(metadata['snapCPG'], HP3PAR_CPG_SNAP)
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.assertEquals(self.FAKE_HOST, host['name'])
self.assertEquals(HP3PAR_DOMAIN, host['domain'])
vlun = self.driver.client.getVLUN(self.VOLUME_3PAR_NAME)
self.assertEquals(self.VOLUME_3PAR_NAME, vlun['volumeName'])
self.assertEquals(self.FAKE_HOST, vlun['hostname'])
def test_create_cloned_volume(self):
self.flags(lock_path=self.tempdir)
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_get_volume_state",
self.fake_get_volume_state)
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_copy_volume",
self.fake_copy_volume)
self.state_tries = 0
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.assertTrue(model_update is not None)
metadata = model_update['metadata']
self.assertFalse(metadata['3ParName'] is None)
self.assertEqual(metadata['CPG'], HP3PAR_CPG)
self.assertEqual(metadata['snapCPG'], HP3PAR_CPG_SNAP)
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.assertEquals(stats['storage_protocol'], 'FC')
self.assertEquals(stats['total_capacity_gb'], 'infinite')
self.assertEquals(stats['free_capacity_gb'], 'infinite')
#modify the CPG to have a limit
old_cpg = self.driver.client.getCPG(HP3PAR_CPG)
options = {'SDGrowth': {'limitMiB': 8192}}
self.driver.client.deleteCPG(HP3PAR_CPG)
self.driver.client.createCPG(HP3PAR_CPG, options)
const = 0.0009765625
stats = self.driver.get_volume_stats(True)
self.assertEquals(stats['storage_protocol'], 'FC')
total_capacity_gb = 8192 * const
self.assertEquals(stats['total_capacity_gb'], total_capacity_gb)
free_capacity_gb = int((8192 - old_cpg['UsrUsage']['usedMiB']) * const)
self.assertEquals(stats['free_capacity_gb'], free_capacity_gb)
self.driver.client.deleteCPG(HP3PAR_CPG)
self.driver.client.createCPG(HP3PAR_CPG, {})
def test_create_host(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_host_cmd = 'showhost -verbose fakehost'
_run_ssh(show_host_cmd, False).AndReturn([pack('no hosts listed'), ''])
create_host_cmd = ('createhost -persona 1 -domain (\'OpenStack\',) '
'fakehost 123456789012345 123456789054321')
_run_ssh(create_host_cmd, False).AndReturn([CLI_CR, ''])
_run_ssh(show_host_cmd, False).AndReturn([pack(FC_HOST_RET), ''])
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.stubs.UnsetAll()
_run_ssh = self.mox.CreateMock(hpdriver.hpcommon.HP3PARCommon._run_ssh)
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_run_ssh", _run_ssh)
show_host_cmd = 'showhost -verbose fakehost'
_run_ssh(show_host_cmd, False).AndReturn([pack('no hosts listed'), ''])
create_host_cmd = ('createhost -persona 1 -domain (\'OpenStack\',) '
'fakehost 123456789012345 123456789054321')
create_host_ret = pack(CLI_CR + 'already used by host fakehost.foo ')
_run_ssh(create_host_cmd, False).AndReturn([create_host_ret, ''])
self.mox.ReplayAll()
self.assertRaises(exception.Duplicate3PARHost,
self.driver._create_host,
self.volume,
self.connector)
def test_create_modify_host(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_host_cmd = 'showhost -verbose fakehost'
_run_ssh(show_host_cmd, False).AndReturn([pack(NO_FC_HOST_RET), ''])
create_host_cmd = ('createhost -add fakehost '
'123456789012345 123456789054321')
_run_ssh(create_host_cmd, False).AndReturn([CLI_CR, ''])
show_host_cmd = 'showhost -verbose fakehost'
_run_ssh(show_host_cmd, False).AndReturn([pack(FC_HOST_RET), ''])
self.mox.ReplayAll()
host = self.driver._create_host(self.volume, self.connector)
self.assertEqual(host['name'], self.FAKE_HOST)
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()
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 = ""
self.stubs.Set(hpdriver.HP3PARISCSIDriver, "_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.driver = hpdriver.HP3PARISCSIDriver(configuration=configuration)
self.driver.do_setup(None)
target_iqn = 'iqn.2000-05.com.3pardata:21810002ac00383d'
self.properties = {'data':
{'target_discovered': True,
'target_iqn': target_iqn,
'target_lun': 186,
'target_portal': '1.1.1.2:1234'},
'driver_volume_type': 'iscsi'}
def tearDown(self):
shutil.rmtree(self.tempdir)
self._hosts = {}
super(TestHP3PARISCSIDriver, self).tearDown()
def fake_iscsi_discover_target_iqn(self, ip_address):
return self.TARGET_IQN
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
def test_create_volume(self):
self.flags(lock_path=self.tempdir)
model_update = self.driver.create_volume(self.volume)
metadata = model_update['metadata']
self.assertFalse(metadata['3ParName'] is None)
self.assertEqual(metadata['CPG'], HP3PAR_CPG)
self.assertEqual(metadata['snapCPG'], HP3PAR_CPG_SNAP)
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.assertEquals(self.FAKE_HOST, host['name'])
self.assertEquals(HP3PAR_DOMAIN, host['domain'])
vlun = self.driver.client.getVLUN(self.VOLUME_3PAR_NAME)
self.assertEquals(self.VOLUME_3PAR_NAME, vlun['volumeName'])
self.assertEquals(self.FAKE_HOST, vlun['hostname'])
def test_create_cloned_volume(self):
self.flags(lock_path=self.tempdir)
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_get_volume_state",
self.fake_get_volume_state)
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_copy_volume",
self.fake_copy_volume)
self.state_tries = 0
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.assertTrue(model_update is not None)
metadata = model_update['metadata']
self.assertFalse(metadata['3ParName'] is None)
self.assertEqual(metadata['CPG'], HP3PAR_CPG)
self.assertEqual(metadata['snapCPG'], HP3PAR_CPG_SNAP)
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.assertEquals(stats['storage_protocol'], 'iSCSI')
self.assertEquals(stats['total_capacity_gb'], 'infinite')
self.assertEquals(stats['free_capacity_gb'], 'infinite')
#modify the CPG to have a limit
old_cpg = self.driver.client.getCPG(HP3PAR_CPG)
options = {'SDGrowth': {'limitMiB': 8192}}
self.driver.client.deleteCPG(HP3PAR_CPG)
self.driver.client.createCPG(HP3PAR_CPG, options)
const = 0.0009765625
stats = self.driver.get_volume_stats(True)
self.assertEquals(stats['storage_protocol'], 'iSCSI')
total_capacity_gb = 8192 * const
self.assertEquals(stats['total_capacity_gb'], total_capacity_gb)
free_capacity_gb = int((8192 - old_cpg['UsrUsage']['usedMiB']) * const)
self.assertEquals(stats['free_capacity_gb'], free_capacity_gb)
self.driver.client.deleteCPG(HP3PAR_CPG)
self.driver.client.createCPG(HP3PAR_CPG, {})
def test_create_host(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_host_cmd = 'showhost -verbose fakehost'
_run_ssh(show_host_cmd, False).AndReturn([pack('no hosts listed'), ''])
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, ''])
_run_ssh(show_host_cmd, False).AndReturn([pack(ISCSI_HOST_RET), ''])
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.stubs.UnsetAll()
_run_ssh = self.mox.CreateMock(hpdriver.hpcommon.HP3PARCommon._run_ssh)
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_run_ssh", _run_ssh)
show_host_cmd = 'showhost -verbose fakehost'
_run_ssh(show_host_cmd, False).AndReturn([pack('no hosts listed'), ''])
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, ''])
self.mox.ReplayAll()
self.assertRaises(exception.Duplicate3PARHost,
self.driver._create_host,
self.volume,
self.connector)
def test_create_modify_host(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_host_cmd = 'showhost -verbose fakehost'
_run_ssh(show_host_cmd, False).AndReturn([pack(ISCSI_NO_HOST_RET), ''])
create_host_cmd = ('createhost -iscsi -add fakehost '
'iqn.1993-08.org.debian:01:222')
_run_ssh(create_host_cmd, False).AndReturn([CLI_CR, ''])
_run_ssh(show_host_cmd, False).AndReturn([pack(ISCSI_HOST_RET), ''])
self.mox.ReplayAll()
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()
_run_ssh = self.mox.CreateMock(hpdriver.hpcommon.HP3PARCommon._run_ssh)
self.stubs.Set(hpdriver.hpcommon.HP3PARCommon, "_run_ssh", _run_ssh)
show_vv_cmd = ('showvv -state '
'volume-d03338a9-9115-48a3-8dfc-35cdfcdc15a7')
_run_ssh(show_vv_cmd, False).AndReturn([pack(VOLUME_STATE_RET), ''])
self.mox.ReplayAll()
status = self.driver.common._get_volume_state(self.VOLUME_NAME)
self.assertEqual(status, 'normal')
def test_get_ports(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'
_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), ''])
self.mox.ReplayAll()
ports = self.driver.common.get_ports()
self.assertEqual(ports['FC'][0], '20210002AC00383D')
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
FC_HOST_RET = (
'Id,Name,Persona,-WWN/iSCSI_Name-,Port,IP_addr\r\n'
'75,fakehost,Generic,50014380242B8B4C,0:2:1,n/a\r\n'
'75,fakehost,Generic,50014380242B8B4E,---,n/a\r\n'
'75,fakehost,Generic,1000843497F90711,0:2:1,n/a \r\n'
'75,fakehost,Generic,1000843497F90715,1:2:1,n/a\r\n'
'\r\n'
'Id,Name,-Initiator_CHAP_Name-,-Target_CHAP_Name-\r\n'
'75,fakehost,--,--\r\n'
'\r\n'
'---------- Host fakehost ----------\r\n'
'Name : fakehost\r\n'
'Domain : FAKE_TEST\r\n'
'Id : 75\r\n'
'Location : --\r\n'
'IP Address : --\r\n'
'OS : --\r\n'
'Model : --\r\n'
'Contact : --\r\n'
'Comment : -- \r\n\r\n\r\n')
NO_FC_HOST_RET = (
'Id,Name,Persona,-WWN/iSCSI_Name-,Port,IP_addr\r\n'
'\r\n'
'Id,Name,-Initiator_CHAP_Name-,-Target_CHAP_Name-\r\n'
'75,fakehost,--,--\r\n'
'\r\n'
'---------- Host fakehost ----------\r\n'
'Name : fakehost\r\n'
'Domain : FAKE_TEST\r\n'
'Id : 75\r\n'
'Location : --\r\n'
'IP Address : --\r\n'
'OS : --\r\n'
'Model : --\r\n'
'Contact : --\r\n'
'Comment : -- \r\n\r\n\r\n')
ISCSI_HOST_RET = (
'Id,Name,Persona,-WWN/iSCSI_Name-,Port,IP_addr\r\n'
'75,fakehost,Generic,iqn.1993-08.org.debian:01:222,---,10.10.222.12\r\n'
'\r\n'
'Id,Name,-Initiator_CHAP_Name-,-Target_CHAP_Name-\r\n'
'75,fakehost,--,--\r\n'
'\r\n'
'---------- Host fakehost ----------\r\n'
'Name : fakehost\r\n'
'Domain : FAKE_TEST\r\n'
'Id : 75\r\n'
'Location : --\r\n'
'IP Address : --\r\n'
'OS : --\r\n'
'Model : --\r\n'
'Contact : --\r\n'
'Comment : -- \r\n\r\n\r\n')
ISCSI_NO_HOST_RET = (
'Id,Name,Persona,-WWN/iSCSI_Name-,Port,IP_addr\r\n'
'\r\n'
'Id,Name,-Initiator_CHAP_Name-,-Target_CHAP_Name-\r\n'
'75,fakehost,--,--\r\n'
'\r\n'
'---------- Host fakehost ----------\r\n'
'Name : fakehost\r\n'
'Domain : FAKE_TEST\r\n'
'Id : 75\r\n'
'Location : --\r\n'
'IP Address : --\r\n'
'OS : --\r\n'
'Model : --\r\n'
'Contact : --\r\n'
'Comment : -- \r\n\r\n\r\n')
ISCSI_PORT_IDS_RET = (
'N:S:P,-Node_WWN/IPAddr-,-----------Port_WWN/iSCSI_Name-----------\r\n'
'0:2:1,28210002AC00383D,20210002AC00383D\r\n'
'0:2:2,2FF70002AC00383D,20220002AC00383D\r\n'
'0:2:3,2FF70002AC00383D,20230002AC00383D\r\n'
'0:2:4,2FF70002AC00383D,20240002AC00383D\r\n'
'0:5:1,2FF70002AC00383D,20510002AC00383D\r\n'
'0:5:2,2FF70002AC00383D,20520002AC00383D\r\n'
'0:5:3,2FF70002AC00383D,20530002AC00383D\r\n'
'0:5:4,2FF70202AC00383D,20540202AC00383D\r\n'
'0:6:4,2FF70002AC00383D,20640002AC00383D\r\n'
'0:8:1,10.10.120.253,iqn.2000-05.com.3pardata:21810002ac00383d\r\n'
'0:8:2,0.0.0.0,iqn.2000-05.com.3pardata:20820002ac00383d\r\n'
'1:2:1,29210002AC00383D,21210002AC00383D\r\n'
'1:2:2,2FF70002AC00383D,21220002AC00383D\r\n'
'-----------------------------------------------------------------\r\n')
VOLUME_STATE_RET = (
'Id,Name,Prov,Type,State,-Detailed_State-\r\n'
'410,volume-d03338a9-9115-48a3-8dfc-35cdfcdc15a7,snp,vcopy,normal,'
'normal\r\n'
'-----------------------------------------------------------------\r\n')
PORT_RET = (
'N:S:P,Mode,State,----Node_WWN----,-Port_WWN/HW_Addr-,Type,Protocol,'
'Label,Partner,FailoverState\r\n'
'0:2:1,target,ready,28210002AC00383D,20210002AC00383D,host,FC,'
'-,1:2:1,none\r\n'
'0:2:2,initiator,loss_sync,2FF70002AC00383D,20220002AC00383D,free,FC,'
'-,-,-\r\n'
'0:2:3,initiator,loss_sync,2FF70002AC00383D,20230002AC00383D,free,FC,'
'-,-,-\r\n'
'0:2:4,initiator,loss_sync,2FF70002AC00383D,20240002AC00383D,free,FC,'
'-,-,-\r\n'
'0:5:1,initiator,loss_sync,2FF70002AC00383D,20510002AC00383D,free,FC,'
'-,-,-\r\n'
'0:5:2,initiator,loss_sync,2FF70002AC00383D,20520002AC00383D,free,FC,'
'-,-,-\r\n'
'0:5:3,initiator,loss_sync,2FF70002AC00383D,20530002AC00383D,free,FC,'
'-,-,-\r\n'
'0:5:4,initiator,ready,2FF70202AC00383D,20540202AC00383D,host,FC,'
'-,1:5:4,active\r\n'
'0:6:1,initiator,ready,2FF70002AC00383D,20610002AC00383D,disk,FC,'
'-,-,-\r\n'
'0:6:2,initiator,ready,2FF70002AC00383D,20620002AC00383D,disk,FC,'
'-,-,-\r\n')
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,loss_sync,0.0.0.0,0.0.0.0,0.0.0.0,82,1500,n/a,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,loss_sync,0.0.0.0,0.0.0.0,0.0.0.0,182,1500,n/a,0,0.0.0.0,3205\r\n')