From eba768acca047b97b2463155b3545e19c051f950 Mon Sep 17 00:00:00 2001 From: Andreas Scheuring Date: Tue, 16 Jan 2018 10:00:27 +0100 Subject: [PATCH] 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 --- nova_dpm/tests/unit/virt/dpm/test_driver.py | 69 +------------------ nova_dpm/tests/unit/virt/dpm/test_vm.py | 44 +++++++++++-- nova_dpm/virt/dpm/driver.py | 73 +++------------------ nova_dpm/virt/dpm/vm.py | 23 +++++-- 4 files changed, 64 insertions(+), 145 deletions(-) diff --git a/nova_dpm/tests/unit/virt/dpm/test_driver.py b/nova_dpm/tests/unit/virt/dpm/test_driver.py index fe1252d..b0d844e 100644 --- a/nova_dpm/tests/unit/virt/dpm/test_driver.py +++ b/nova_dpm/tests/unit/virt/dpm/test_driver.py @@ -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') diff --git a/nova_dpm/tests/unit/virt/dpm/test_vm.py b/nova_dpm/tests/unit/virt/dpm/test_vm.py index 0638920..837d3b7 100755 --- a/nova_dpm/tests/unit/virt/dpm/test_vm.py +++ b/nova_dpm/tests/unit/virt/dpm/test_vm.py @@ -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, diff --git a/nova_dpm/virt/dpm/driver.py b/nova_dpm/virt/dpm/driver.py index 362bf73..1a3c39d 100644 --- a/nova_dpm/virt/dpm/driver.py +++ b/nova_dpm/virt/dpm/driver.py @@ -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) diff --git a/nova_dpm/virt/dpm/vm.py b/nova_dpm/virt/dpm/vm.py index 192990f..2884729 100644 --- a/nova_dpm/virt/dpm/vm.py +++ b/nova_dpm/virt/dpm/vm.py @@ -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')