Add a new class definition SVCDriver.FCP

Add a new class definition SVCDriver.FCP to facilitate managing
FCP devices. Also add test cases for the new class.
NOTE: It can not work in real world because it's not a complete
version. I submit this update separately to facilitate review.

Change-Id: Ib1fe806038f474c11faa0fa26d071b0baacc5ac2
This commit is contained in:
Yi Chun, Huang
2015-08-05 03:34:55 -04:00
parent 64973a51dc
commit 90f9ad4634
2 changed files with 243 additions and 1 deletions

View File

@@ -24,6 +24,7 @@ import mox
from oslo_concurrency import processutils
from oslo_config import cfg
from oslo_serialization import jsonutils
from oslo_utils import fileutils
from nova.compute import power_state
from nova import context
@@ -32,7 +33,6 @@ from nova import exception as nova_exception
from nova.i18n import _
from nova.image import glance
from nova.network import model
from nova.openstack.common import fileutils
from nova import test
from nova.tests.unit import fake_instance
from nova.virt import fake
@@ -2253,6 +2253,134 @@ class ZVMVolumeOperatorTestCase(ZVMTestCase):
self.volumeop.get_volume_connector, None)
class FCPTestCase(ZVMTestCase):
def setUp(self):
super(FCPTestCase, self).setUp()
fcp_info = ['opnstk1: FCP device number: B83D',
'opnstk1: Status: Free',
'opnstk1: NPIV world wide port number: NONE',
'opnstk1: Channel path ID: 5A',
'opnstk1: Physical world wide port number: '
'20076D8500005181']
self.fcp = volumeop.SVCDriver.FCP(fcp_info)
self.mox.UnsetStubs()
def test_init(self):
self.assertEqual('b83d', self.fcp.get_dev_no())
self.assertEqual(None, self.fcp.get_npiv_port())
self.assertEqual('5A', self.fcp.get_chpid())
self.assertEqual('20076d8500005181', self.fcp.get_physical_port())
self.assertTrue(self.fcp.is_valid())
def test_get_wwpn_from_line(self):
info_line = 'opnstk1: NPIV world wide port number: NONE'
self.assertIsNone(self.fcp._get_wwpn_from_line(info_line))
info_line = 'opnstk1: NPIV world wide port number: 20076D8500005181'
self.assertEqual('20076d8500005181',
self.fcp._get_wwpn_from_line(info_line))
info_line = 'opnstk1: Physical world wide port number:'
self.assertIsNone(self.fcp._get_wwpn_from_line(info_line))
info_line = ' '.join(['opnstk1: Physical world wide port number:',
'20076D8500005182'])
self.assertEqual('20076d8500005182',
self.fcp._get_wwpn_from_line(info_line))
def test_get_dev_number_from_line(self):
info_line = 'opnstk1: FCP device number: B83D'
self.assertEqual('b83d', self.fcp._get_dev_number_from_line(info_line))
info_line = 'opnstk1: FCP device number: '
self.assertIsNone(self.fcp._get_dev_number_from_line(info_line))
def test_get_chpid_from_line(self):
info_line = 'opnstk1: Channel path ID: 5A'
self.assertEqual('5A', self.fcp._get_chpid_from_line(info_line))
info_line = 'opnstk1: Channel path ID: '
self.assertIsNone(self.fcp._get_chpid_from_line(info_line))
def test_validate_device(self):
dev_line = 'opnstk1: FCP device number: B83D'
status_line = 'opnstk1: Status: Free'
npiv_line = 'opnstk1: NPIV world wide port number: NONE'
chpid_line = 'opnstk1: Channel path ID: 5A'
physical_port_line = ' '.join(['opnstk1:',
'Physical world wide port number:',
'20076D8500005181'])
fcp_info = ['opnstk1: FCP device number: ', status_line, npiv_line,
chpid_line, physical_port_line]
fcp = volumeop.SVCDriver.FCP(fcp_info)
self.assertFalse(fcp.is_valid())
fcp_info = ['opnstk1: FCP device number: help', status_line, npiv_line,
chpid_line, physical_port_line]
fcp = volumeop.SVCDriver.FCP(fcp_info)
self.assertFalse(fcp.is_valid())
fcp_info = [dev_line, '', npiv_line, chpid_line, physical_port_line]
fcp = volumeop.SVCDriver.FCP(fcp_info)
self.assertTrue(fcp.is_valid())
fcp_info = [dev_line, status_line,
'opnstk1: NPIV world wide port number: ',
chpid_line, physical_port_line]
fcp = volumeop.SVCDriver.FCP(fcp_info)
self.assertTrue(fcp.is_valid())
fcp_info = [dev_line, status_line,
'opnstk1: NPIV world wide port number: 20076D850000',
chpid_line, physical_port_line]
fcp = volumeop.SVCDriver.FCP(fcp_info)
self.assertFalse(fcp.is_valid())
fcp_info = [dev_line, status_line,
'opnstk1: NPIV world wide port number: 20076D850000help',
chpid_line, physical_port_line]
fcp = volumeop.SVCDriver.FCP(fcp_info)
self.assertFalse(fcp.is_valid())
fcp_info = [dev_line, status_line,
'opnstk1: NPIV world wide port number: 20076D8500005182',
chpid_line, physical_port_line]
fcp = volumeop.SVCDriver.FCP(fcp_info)
self.assertTrue(fcp.is_valid())
fcp_info = [dev_line, status_line, npiv_line,
'opnstk1: Channel path ID: ', physical_port_line]
fcp = volumeop.SVCDriver.FCP(fcp_info)
self.assertFalse(fcp.is_valid())
fcp_info = [dev_line, status_line, npiv_line,
'opnstk1: Channel path ID: help', physical_port_line]
fcp = volumeop.SVCDriver.FCP(fcp_info)
self.assertFalse(fcp.is_valid())
fcp_info = [dev_line, status_line, npiv_line,
'opnstk1: Channel path ID: 5', physical_port_line]
fcp = volumeop.SVCDriver.FCP(fcp_info)
self.assertFalse(fcp.is_valid())
fcp_info = [dev_line, status_line, npiv_line, npiv_line,
'opnstk1: Physical world wide port number: ']
fcp = volumeop.SVCDriver.FCP(fcp_info)
self.assertFalse(fcp.is_valid())
fcp_info = [dev_line, status_line, npiv_line, npiv_line,
'opnstk1: Physical world wide port number: 20076D850000']
fcp = volumeop.SVCDriver.FCP(fcp_info)
self.assertFalse(fcp.is_valid())
fcp_info = [dev_line, status_line, npiv_line, npiv_line,
'opnstk1: Physical world wide port number: '
'20076D850000help']
fcp = volumeop.SVCDriver.FCP(fcp_info)
self.assertFalse(fcp.is_valid())
fcp_info = [dev_line, status_line, npiv_line, npiv_line]
fcp = volumeop.SVCDriver.FCP(fcp_info)
self.assertFalse(fcp.is_valid())
class SVCDriverTestCase(ZVMTestCase):
def setUp(self):

View File

@@ -171,6 +171,120 @@ class DriverAPI(object):
class SVCDriver(DriverAPI):
"""SVC volume operator on IBM z/VM platform."""
class FCP(object):
"""FCP adapter class."""
_DEV_NO_PATTERN = '[0-9a-f]{1,4}'
_WWPN_PATTERN = '[0-9a-f]{16}'
_CHPID_PATTERN = '[0-9A-F]{2}'
def __init__(self, init_info):
"""Initialize a FCP device object from several lines of string
describing properties of the FCP device.
Here is a sample:
opnstk1: FCP device number: B83D
opnstk1: Status: Free
opnstk1: NPIV world wide port number: NONE
opnstk1: Channel path ID: 59
opnstk1: Physical world wide port number: 20076D8500005181
The format comes from the response of xCAT, do not support
arbitrary format.
"""
self._dev_no = None
self._npiv_port = None
self._chpid = None
self._physical_port = None
self._is_valid = True
# Sometimes nova issues get_volume_connector() for some reasons,
# which requires a FCP device being assigned to the instance. But
# nova will not attach any volume to the instance later. In this
# case we need to release the FCP device in later time. So a FCP
# device which is assigned to an instance doesn't means it's
# actually used by the instance.
self._is_reserved = False
self._is_in_use = False
self._reserve_time = 0
if isinstance(init_info, list) and (len(init_info) == 5):
self._dev_no = self._get_dev_number_from_line(init_info[0])
self._npiv_port = self._get_wwpn_from_line(init_info[2])
self._chpid = self._get_chpid_from_line(init_info[3])
self._physical_port = self._get_wwpn_from_line(init_info[4])
self._validate_device()
def _get_wwpn_from_line(self, info_line):
wwpn = info_line.split(':')[-1].strip().lower()
return wwpn if (wwpn and wwpn.upper() != 'NONE') else None
def _get_dev_number_from_line(self, info_line):
dev_no = info_line.split(':')[-1].strip().lower()
return dev_no if dev_no else None
def _get_chpid_from_line(self, info_line):
chpid = info_line.split(':')[-1].strip().upper()
return chpid if chpid else None
def _validate_device(self):
if not (self._dev_no and self._chpid):
self._is_valid = False
return
if not (self._npiv_port or self._physical_port):
self._is_valid = False
return
if not (re.match(self._DEV_NO_PATTERN, self._dev_no) and
re.match(self._CHPID_PATTERN, self._chpid)):
self._is_valid = False
return
if self._npiv_port and not re.match(self._WWPN_PATTERN,
self._npiv_port):
self._is_valid = False
return
if self._physical_port and not re.match(self._WWPN_PATTERN,
self._physical_port):
self._is_valid = False
return
def is_valid(self):
return self._is_valid
def get_dev_no(self):
return self._dev_no
def get_npiv_port(self):
return self._npiv_port
def get_chpid(self):
return self._chpid
def get_physical_port(self):
return self._physical_port
def reserve_device(self):
self._is_reserved = True
self._is_in_use = False
self._reserve_time = time.time()
def is_reserved(self):
return self._is_reserved
def set_in_use(self):
self._is_reserved = True
self._is_in_use = True
def is_in_use(self):
return self._is_in_use
def release_device(self):
self._is_reserved = False
self._is_in_use = False
self._reserve_time = 0
def get_reserve_time(self):
return self._reserve_time
def __init__(self):
self._xcat_url = zvmutils.XCATUrl()
self._path_utils = zvmutils.PathUtils()