diff --git a/ironic/drivers/modules/deploy_utils.py b/ironic/drivers/modules/deploy_utils.py index 2fd0bad101..634e33185d 100644 --- a/ironic/drivers/modules/deploy_utils.py +++ b/ironic/drivers/modules/deploy_utils.py @@ -39,6 +39,7 @@ from six.moves.urllib import parse from ironic.common import dhcp_factory from ironic.common import disk_partitioner from ironic.common import exception +from ironic.common.glance_service import service_utils from ironic.common.i18n import _ from ironic.common.i18n import _LE from ironic.common.i18n import _LI @@ -1483,3 +1484,33 @@ def tear_down_inband_cleaning(task, manage_boot=True): task.driver.boot.clean_up_ramdisk(task) tear_down_cleaning_ports(task) + + +def get_image_instance_info(node): + """Gets the image information from the node. + + Get image information for the given node instance from its + 'instance_info' property. + + :param node: a single Node. + :returns: A dict with required image properties retrieved from + node's 'instance_info'. + :raises: MissingParameterValue, if image_source is missing in node's + instance_info. Also raises same exception if kernel/ramdisk is + missing in instance_info for non-glance images. + """ + info = {} + info['image_source'] = node.instance_info.get('image_source') + + is_whole_disk_image = node.driver_internal_info.get('is_whole_disk_image') + if not is_whole_disk_image: + if not service_utils.is_glance_image(info['image_source']): + info['kernel'] = node.instance_info.get('kernel') + info['ramdisk'] = node.instance_info.get('ramdisk') + + error_msg = (_("Cannot validate image information for node %s because one " + "or more parameters are missing from its instance_info.") + % node.uuid) + check_for_missing_params(info, error_msg) + + return info diff --git a/ironic/drivers/modules/pxe.py b/ironic/drivers/modules/pxe.py index 1b923c57fc..d8d70e958a 100644 --- a/ironic/drivers/modules/pxe.py +++ b/ironic/drivers/modules/pxe.py @@ -165,35 +165,6 @@ def _parse_driver_info(node): return d_info -def _parse_instance_info(node): - """Gets the instance and driver specific Node deployment info. - - This method validates whether the 'instance_info' and 'driver_info' - property of the supplied node contains the required information for - this driver to deploy images to the node. - - :param node: a single Node. - :returns: A dict with the instance_info and driver_info values. - :raises: MissingParameterValue, image_source is missing in node's - instance_info. Also raises same exception if kernel/ramdisk is - missing in instance_info for non-glance images. - """ - info = {} - info['image_source'] = node.instance_info.get('image_source') - - is_whole_disk_image = node.driver_internal_info.get('is_whole_disk_image') - if not is_whole_disk_image: - if not service_utils.is_glance_image(info['image_source']): - info['kernel'] = node.instance_info.get('kernel') - info['ramdisk'] = node.instance_info.get('ramdisk') - - error_msg = _("Cannot validate PXE bootloader. Some parameters were " - "missing in node's instance_info.") - deploy_utils.check_for_missing_params(info, error_msg) - - return info - - def _get_instance_image_info(node, ctx): """Generate the paths for TFTP files for instance related images. @@ -214,7 +185,7 @@ def _get_instance_image_info(node, ctx): root_dir = pxe_utils.get_root_dir() i_info = node.instance_info labels = ('kernel', 'ramdisk') - d_info = _parse_instance_info(node) + d_info = deploy_utils.get_image_instance_info(node) if not (i_info.get('kernel') and i_info.get('ramdisk')): glance_service = service.GlanceImageService(version=1, context=ctx) iproperties = glance_service.show(d_info['image_source'])['properties'] @@ -451,7 +422,7 @@ class PXEBoot(base.BootInterface): validate_boot_parameters_for_trusted_boot(node) _parse_driver_info(node) - d_info = _parse_instance_info(node) + d_info = deploy_utils.get_image_instance_info(node) if node.driver_internal_info.get('is_whole_disk_image'): props = [] elif service_utils.is_glance_image(d_info['image_source']): @@ -597,9 +568,6 @@ class PXEBoot(base.BootInterface): # of the prepare() because the deployment does PXE boot the # deploy ramdisk pxe_utils.clean_up_pxe_config(task) - - # In case boot mode changes from bios to uefi, boot device order - # may get lost in some platforms. Better to re-apply boot device. deploy_utils.try_set_boot_device(task, boot_devices.DISK) def clean_up_instance(self, task): diff --git a/ironic/tests/unit/drivers/modules/test_deploy_utils.py b/ironic/tests/unit/drivers/modules/test_deploy_utils.py index 2ad49008b5..28015e4a18 100644 --- a/ironic/tests/unit/drivers/modules/test_deploy_utils.py +++ b/ironic/tests/unit/drivers/modules/test_deploy_utils.py @@ -2257,12 +2257,12 @@ class ValidateImagePropertiesTestCase(db_base.DbTestCase): driver_info=DRV_INFO_DICT, driver_internal_info=DRV_INTERNAL_INFO_DICT, ) - d_info = pxe._parse_instance_info(node) + inst_info = utils.get_image_instance_info(node) image_service_mock.return_value.show.return_value = { 'properties': {'kernel_id': '1111', 'ramdisk_id': '2222'}, } - utils.validate_image_properties(self.context, d_info, + utils.validate_image_properties(self.context, inst_info, ['kernel_id', 'ramdisk_id']) image_service_mock.assert_called_once_with( node.instance_info['image_source'], context=self.context @@ -2277,14 +2277,14 @@ class ValidateImagePropertiesTestCase(db_base.DbTestCase): driver_info=DRV_INFO_DICT, driver_internal_info=DRV_INTERNAL_INFO_DICT, ) - d_info = pxe._parse_instance_info(node) + inst_info = utils.get_image_instance_info(node) image_service_mock.return_value.show.return_value = { 'properties': {'kernel_id': '1111'}, } self.assertRaises(exception.MissingParameterValue, utils.validate_image_properties, - self.context, d_info, ['kernel_id', 'ramdisk_id']) + self.context, inst_info, ['kernel_id', 'ramdisk_id']) image_service_mock.assert_called_once_with( node.instance_info['image_source'], context=self.context ) @@ -2292,28 +2292,28 @@ class ValidateImagePropertiesTestCase(db_base.DbTestCase): @mock.patch.object(image_service, 'get_image_service', autospec=True) def test_validate_image_properties_glance_image_not_authorized( self, image_service_mock): - d_info = {'image_source': 'uuid'} + inst_info = {'image_source': 'uuid'} show_mock = image_service_mock.return_value.show show_mock.side_effect = exception.ImageNotAuthorized(image_id='uuid') self.assertRaises(exception.InvalidParameterValue, utils.validate_image_properties, self.context, - d_info, []) + inst_info, []) @mock.patch.object(image_service, 'get_image_service', autospec=True) def test_validate_image_properties_glance_image_not_found( self, image_service_mock): - d_info = {'image_source': 'uuid'} + inst_info = {'image_source': 'uuid'} show_mock = image_service_mock.return_value.show show_mock.side_effect = exception.ImageNotFound(image_id='uuid') self.assertRaises(exception.InvalidParameterValue, utils.validate_image_properties, self.context, - d_info, []) + inst_info, []) def test_validate_image_properties_invalid_image_href(self): - d_info = {'image_source': 'emule://uuid'} + inst_info = {'image_source': 'emule://uuid'} self.assertRaises(exception.InvalidParameterValue, utils.validate_image_properties, self.context, - d_info, []) + inst_info, []) @mock.patch.object(image_service.HttpImageService, 'show', autospec=True) def test_validate_image_properties_nonglance_image( @@ -2331,8 +2331,8 @@ class ValidateImagePropertiesTestCase(db_base.DbTestCase): driver_info=DRV_INFO_DICT, driver_internal_info=DRV_INTERNAL_INFO_DICT, ) - d_info = pxe._parse_instance_info(node) - utils.validate_image_properties(self.context, d_info, + inst_info = utils.get_image_instance_info(node) + utils.validate_image_properties(self.context, inst_info, ['kernel', 'ramdisk']) image_service_show_mock.assert_called_once_with( mock.ANY, instance_info['image_source']) @@ -2355,7 +2355,77 @@ class ValidateImagePropertiesTestCase(db_base.DbTestCase): driver_info=DRV_INFO_DICT, driver_internal_info=DRV_INTERNAL_INFO_DICT, ) - d_info = pxe._parse_instance_info(node) + inst_info = utils.get_image_instance_info(node) self.assertRaises(exception.InvalidParameterValue, utils.validate_image_properties, self.context, - d_info, ['kernel', 'ramdisk']) + inst_info, ['kernel', 'ramdisk']) + + +class ValidateParametersTestCase(db_base.DbTestCase): + + def _test__get_img_instance_info( + self, instance_info=INST_INFO_DICT, + driver_info=DRV_INFO_DICT, + driver_internal_info=DRV_INTERNAL_INFO_DICT): + # make sure we get back the expected things + node = obj_utils.create_test_node( + self.context, + driver='fake_pxe', + instance_info=instance_info, + driver_info=driver_info, + driver_internal_info=DRV_INTERNAL_INFO_DICT, + ) + + info = utils.get_image_instance_info(node) + self.assertIsNotNone(info.get('image_source')) + return info + + def test__get_img_instance_info_good(self): + self._test__get_img_instance_info() + + def test__get_img_instance_info_good_non_glance_image(self): + instance_info = INST_INFO_DICT.copy() + instance_info['image_source'] = 'http://image' + instance_info['kernel'] = 'http://kernel' + instance_info['ramdisk'] = 'http://ramdisk' + + info = self._test__get_img_instance_info(instance_info=instance_info) + + self.assertIsNotNone(info.get('ramdisk')) + self.assertIsNotNone(info.get('kernel')) + + def test__get_img_instance_info_non_glance_image_missing_kernel(self): + instance_info = INST_INFO_DICT.copy() + instance_info['image_source'] = 'http://image' + instance_info['ramdisk'] = 'http://ramdisk' + + self.assertRaises( + exception.MissingParameterValue, + self._test__get_img_instance_info, + instance_info=instance_info) + + def test__get_img_instance_info_non_glance_image_missing_ramdisk(self): + instance_info = INST_INFO_DICT.copy() + instance_info['image_source'] = 'http://image' + instance_info['kernel'] = 'http://kernel' + + self.assertRaises( + exception.MissingParameterValue, + self._test__get_img_instance_info, + instance_info=instance_info) + + def test__get_img_instance_info_missing_image_source(self): + instance_info = INST_INFO_DICT.copy() + del instance_info['image_source'] + + self.assertRaises( + exception.MissingParameterValue, + self._test__get_img_instance_info, + instance_info=instance_info) + + def test__get_img_instance_info_whole_disk_image(self): + driver_internal_info = DRV_INTERNAL_INFO_DICT.copy() + driver_internal_info['is_whole_disk_image'] = True + + self._test__get_img_instance_info( + driver_internal_info=driver_internal_info) diff --git a/ironic/tests/unit/drivers/test_pxe.py b/ironic/tests/unit/drivers/test_pxe.py index 178ffb0884..1c0b432113 100644 --- a/ironic/tests/unit/drivers/test_pxe.py +++ b/ironic/tests/unit/drivers/test_pxe.py @@ -46,76 +46,6 @@ DRV_INFO_DICT = db_utils.get_test_pxe_driver_info() DRV_INTERNAL_INFO_DICT = db_utils.get_test_pxe_driver_internal_info() -class PXEValidateParametersTestCase(db_base.DbTestCase): - - def _test__parse_instance_info( - self, instance_info=INST_INFO_DICT, - driver_info=DRV_INFO_DICT, - driver_internal_info=DRV_INTERNAL_INFO_DICT): - # make sure we get back the expected things - node = obj_utils.create_test_node( - self.context, - driver='fake_pxe', - instance_info=instance_info, - driver_info=driver_info, - driver_internal_info=DRV_INTERNAL_INFO_DICT, - ) - - info = pxe._parse_instance_info(node) - self.assertIsNotNone(info.get('image_source')) - return info - - def test__parse_instance_info_good(self): - self._test__parse_instance_info() - - def test__parse_instance_info_good_non_glance_image(self): - instance_info = INST_INFO_DICT.copy() - instance_info['image_source'] = 'http://image' - instance_info['kernel'] = 'http://kernel' - instance_info['ramdisk'] = 'http://ramdisk' - - info = self._test__parse_instance_info(instance_info=instance_info) - - self.assertIsNotNone(info.get('ramdisk')) - self.assertIsNotNone(info.get('kernel')) - - def test__parse_instance_info_non_glance_image_missing_kernel(self): - instance_info = INST_INFO_DICT.copy() - instance_info['image_source'] = 'http://image' - instance_info['ramdisk'] = 'http://ramdisk' - - self.assertRaises( - exception.MissingParameterValue, - self._test__parse_instance_info, - instance_info=instance_info) - - def test__parse_instance_info_non_glance_image_missing_ramdisk(self): - instance_info = INST_INFO_DICT.copy() - instance_info['image_source'] = 'http://image' - instance_info['kernel'] = 'http://kernel' - - self.assertRaises( - exception.MissingParameterValue, - self._test__parse_instance_info, - instance_info=instance_info) - - def test__parse_instance_info_missing_image_source(self): - instance_info = INST_INFO_DICT.copy() - del instance_info['image_source'] - - self.assertRaises( - exception.MissingParameterValue, - self._test__parse_instance_info, - instance_info=instance_info) - - def test__parse_instance_info_whole_disk_image(self): - driver_internal_info = DRV_INTERNAL_INFO_DICT.copy() - driver_internal_info['is_whole_disk_image'] = True - - self._test__parse_instance_info( - driver_internal_info=driver_internal_info) - - class PXEPrivateMethodsTestCase(db_base.DbTestCase): def setUp(self):