Move creation of boot properties into vm class

We build up all the properties required for boot now in the
vm class. The driver does not need to deal with gathering
information for boot anymore.

Change-Id: Iad15a7a404a3467d417f27e739a3e4dc7233af6f
This commit is contained in:
Andreas Scheuring 2018-01-16 10:00:27 +01:00
parent 8aef196ad4
commit eba768acca
4 changed files with 64 additions and 145 deletions

View File

@ -19,7 +19,6 @@ from nova import context as context_object
from nova import exception
from nova.objects import flavor as flavor_object
from nova.test import TestCase
from nova.virt import driver as basedriver
from nova_dpm.tests.unit.virt.dpm import test_data as utils
from nova_dpm.virt.dpm import driver
from nova_dpm.virt.dpm import exceptions
@ -32,19 +31,6 @@ import zhmcclient
import zhmcclient_mock
PARTITION_WWPN = 'C05076FFEB8000D6'
BLOCK_DEVICE = [{
'connection_info': {
'driver_volume_type': 'fibre_channel',
'connector': {
'wwpns': [PARTITION_WWPN],
'host': '3cfb165c-0df3-4d80-87b2-4c353e61318f'},
'data': {
'initiator_target_map': {
PARTITION_WWPN: [
'500507680B214AC1',
'500507680B244AC0']},
'target_discovered': False,
'target_lun': 0}}}]
def fake_session():
@ -147,58 +133,6 @@ class DPMdriverInitHostTestCase(TestCase):
self.dpmdriver.init_host,
None)
@mock.patch.object(vm.PartitionInstance, 'get_partition')
@mock.patch.object(basedriver, 'block_device_info_get_mapping')
def test_get_fc_boot_props(self, mock_block_device,
mock_get_partition):
mock_get_partition.return_value = self.partition
mock_block_device.return_value = BLOCK_DEVICE
inst = vm.PartitionInstance(mock.Mock(), mock.Mock())
target_wwpn, lun = self.dpmdriver.get_fc_boot_props(
mock.Mock(), inst)
self.assertEqual(target_wwpn, '500507680B214AC1')
self.assertEqual(lun, '0')
def test_validate_volume_type_unsupported(self):
bdms = [
{'connection_info': {'driver_volume_type': 'fake_vol_type'}}]
self.assertRaises(exceptions.UnsupportedVolumeTypeException,
self.dpmdriver._validate_volume_type, bdms)
bdms = [
{'connection_info': {'driver_volume_type': 'fake_vol_type'}},
{'connection_info': {'driver_volume_type': 'fake_vol_type'}}]
self.assertRaises(exceptions.UnsupportedVolumeTypeException,
self.dpmdriver._validate_volume_type, bdms)
bdms = [
{'connection_info': {'driver_volume_type': 'fibre_channel'}},
{'connection_info': {'driver_volume_type': 'fake_vol_type'}}]
self.assertRaises(exceptions.UnsupportedVolumeTypeException,
self.dpmdriver._validate_volume_type, bdms)
def test_validate_volume_type_supported(self):
bdms = [
{'connection_info': {'driver_volume_type': 'fibre_channel'}},
{'connection_info': {'driver_volume_type': 'fibre_channel'}}]
self.dpmdriver._validate_volume_type(bdms)
@mock.patch.object(vm.PartitionInstance, 'get_partition')
@mock.patch.object(basedriver, 'block_device_info_get_mapping')
def test_get_fc_boot_props_ignore_list(self, mock_block_device,
mock_get_partition):
mock_get_partition.return_value = self.partition
mock_block_device.return_value = BLOCK_DEVICE
self.flags(group="dpm", target_wwpn_ignore_list=["500507680B214AC1"])
self.dpmdriver.init_host(None)
inst = vm.PartitionInstance(mock.Mock(), mock.Mock())
target_wwpn, lun = self.dpmdriver.get_fc_boot_props(
mock.Mock(), inst)
self.assertEqual(target_wwpn, '500507680B244AC0')
self.assertEqual(lun, '0')
@mock.patch.object(flavor_object.Flavor, 'get_by_id')
@mock.patch.object(context_object, 'get_admin_context')
@mock.patch.object(vm.PartitionInstance, 'create')
@ -321,8 +255,7 @@ class DPMDriverInstanceTestCase(TestCase):
dpmdriver.spawn, None, mock_instance, None, None,
None, None, network_info)
@mock.patch.object(driver.DPMDriver, 'get_fc_boot_props',
return_value=(None, None))
@mock.patch.object(vm.PartitionInstance, 'set_boot_properties')
@mock.patch.object(vm.PartitionInstance, 'get_boot_hba')
@mock.patch.object(vm.PartitionInstance, 'launch')
@mock.patch.object(vm.PartitionInstance, 'attach_hbas')

View File

@ -26,6 +26,23 @@ import zhmcclient
import zhmcclient_mock
PARTITION_WWPN = 'CCCCCCCCCCCCCCCC'
LUN = 0
BLOCK_DEVICE = {
'connection_info': {
'driver_volume_type': 'fibre_channel',
'connector': {
'wwpns': [PARTITION_WWPN],
'host': '3cfb165c-0df3-4d80-87b2-4c353e61318f'},
'data': {
'initiator_target_map': {
PARTITION_WWPN: [
'AAAAAAAAAAAAAAAA',
'BBBBBBBBBBBBBBBB']},
'target_discovered': False,
'target_lun': LUN}}}
def fake_session():
session = zhmcclient_mock.FakedSession(
'fake-host', 'fake-hmc', '2.13.1', '1.8')
@ -243,13 +260,28 @@ class VmPartitionInstanceTestCase(TestCase):
exceptions.BootOsSpecificParametersPropertyExceededError,
self.partition_inst.set_boot_os_specific_parameters, data)
def test_set_boot_properties(self):
@mock.patch.object(vm.BlockDevice, "get_target_wwpn")
@mock.patch.object(vm.PartitionInstance, "get_boot_hba")
@mock.patch.object(vm.BlockDevice, "lun", new_callable=mock.PropertyMock)
def test_set_boot_properties(self, mock_lun, mock_get_hba, mock_gtw):
mock_lun.return_value = '1'
wwpn = 'DDDDDDDDDDDDDDDD'
mock_gtw.return_value = wwpn
booturi = '/api/partitions/1/hbas/1'
mock_hba = mock.Mock()
mock_hba.get_property = lambda prop: {'element-uri': booturi,
'wwpn': wwpn}[prop]
mock_get_hba.return_value = mock_hba
bdm = [BLOCK_DEVICE]
self.partition_inst.set_boot_properties(bdm)
mock_gtw.assert_called_once_with(wwpn)
wwpn = '500507680B214AC1'
lun = 1
booturi = '/api/partitions/4/hbas/1'
partition = self.cpc.partitions.find(**{"name": self.part_name})
self.partition_inst.set_boot_properties(wwpn, lun)
self.assertEqual(
'storage-adapter',
partition.get_property('boot-device'))
@ -257,7 +289,7 @@ class VmPartitionInstanceTestCase(TestCase):
wwpn,
partition.get_property('boot-world-wide-port-name'))
self.assertEqual(
lun,
'1',
partition.get_property('boot-logical-unit-number'))
self.assertEqual(
booturi,

View File

@ -327,6 +327,13 @@ class DPMDriver(driver.ComputeDriver):
inst.attach_hbas()
@staticmethod
def _get_block_device_mapping(block_device_info):
bdm = driver.block_device_info_get_mapping(
block_device_info)
LOG.debug("Block device mapping %s", str(bdm))
return bdm
def spawn(self, context, instance, image_meta, injected_files,
admin_password, allocations, network_info=None,
block_device_info=None):
@ -353,72 +360,10 @@ class DPMDriver(driver.ComputeDriver):
nic_boot_string += self._get_nic_string_for_guest_os(nic, vif)
inst.set_boot_os_specific_parameters(nic_boot_string)
target_wwpn, lun = self.get_fc_boot_props(
block_device_info, inst)
inst.set_boot_properties(target_wwpn, lun)
inst.set_boot_properties(
self._get_block_device_mapping(block_device_info))
inst.launch()
def get_fc_boot_props(self, block_device_info, inst):
# block_device_mapping is a list of mapped block devices.
# In dpm case we are mapping only one device
# So block_device_mapping contains one item in the list
# i.e. block_device_mapping[0]
block_device_mapping = driver.block_device_info_get_mapping(
block_device_info)
self._validate_volume_type(block_device_mapping)
LOG.debug("Block device mapping %s", str(block_device_mapping))
partition_hba = inst.get_boot_hba()
partition_wwpn = partition_hba.get_property('wwpn')
mapped_block_device = block_device_mapping[0]
host_wwpns = (mapped_block_device['connection_info']
['connector']['wwpns'])
if partition_wwpn not in host_wwpns:
raise Exception('Partition WWPN not found from cinder')
# There is a list of target WWPNs which can be configured that
# has to be ignored. The storewize driver as of today returns
# complete set of Target WWPNS both supported and unsupported
# (nas/file module connected)out of which we need to filter
# out those mentioned as target_wwpn_ignore_list
target_wwpn = self._fetch_valid_target_wwpn(mapped_block_device,
partition_wwpn)
lun = str(mapped_block_device['connection_info']
['data']['target_lun'])
return target_wwpn, lun
def _fetch_valid_target_wwpn(self, mapped_block_device, partition_wwpn):
LOG.debug("_fetch_valid_target_wwpn")
list_target_wwpns = (mapped_block_device['connection_info']['data']
['initiator_target_map'][partition_wwpn])
target_wwpns = [wwpn for wwpn in list_target_wwpns
if wwpn not in CONF.dpm.target_wwpn_ignore_list]
# target_wwpns is a list of wwpns which will be accessible
# from host wwpn. So we can use any of the target wwpn in the
# list.
target_wwpn = (target_wwpns[0]
if len(target_wwpns) > 0 else '')
LOG.debug("Returning valid target WWPN %s", target_wwpn)
return target_wwpn
def _validate_volume_type(self, bdms):
for bdm in bdms:
vol_type = bdm['connection_info']['driver_volume_type']
if vol_type != 'fibre_channel':
raise exceptions.UnsupportedVolumeTypeException(
vol_type=vol_type)
def destroy(self, context, instance, network_info, block_device_info=None,
destroy_disks=True, migrate_data=None):
inst = self._get_partition_instance(instance)

View File

@ -26,6 +26,7 @@ from nova.compute import vm_states
from nova import exception
from nova.i18n import _
from nova_dpm import conf
from nova_dpm.virt.dpm.block_device import BlockDevice
from nova_dpm.virt.dpm import constants
from nova_dpm.virt.dpm import exceptions
from nova_dpm.virt.dpm import utils
@ -273,14 +274,22 @@ class PartitionInstance(object):
partition_wwpns.append(wwpn.replace('0x', ''))
return partition_wwpns
def set_boot_properties(self, wwpn, lun):
def set_boot_properties(self, bdm):
LOG.debug('set_boot_properties')
booturi = self.get_boot_hba().get_property("element-uri")
bootProperties = {'boot-device': 'storage-adapter',
'boot-storage-device': booturi,
'boot-world-wide-port-name': wwpn,
'boot-logical-unit-number': lun}
self.partition.update_properties(properties=bootProperties)
# block_device_mapping is a list of mapped block devices.
# In dpm case we are mapping only the first device for now
# So block_device_mapping contains one item in the list
# i.e. block_device_mapping[0]
bd = BlockDevice(bdm[0])
boot_hba = self.get_boot_hba()
boot_properties = {
'boot-device': 'storage-adapter',
'boot-storage-device': boot_hba.get_property("element-uri"),
'boot-world-wide-port-name': bd.get_target_wwpn(
boot_hba.get_property('wwpn')),
'boot-logical-unit-number': bd.lun}
self.partition.update_properties(properties=boot_properties)
def launch(self, partition=None):
LOG.debug('Partition launch triggered')