diff --git a/ironic/common/pxe_utils.py b/ironic/common/pxe_utils.py index 88c55d6d7d..40ad982176 100644 --- a/ironic/common/pxe_utils.py +++ b/ironic/common/pxe_utils.py @@ -681,8 +681,10 @@ def get_instance_image_info(task, ipxe_enabled=False): def _get_image_properties(): nonlocal image_properties if not image_properties: - glance_service = service.GlanceImageService(context=ctx) - image_properties = glance_service.show( + i_service = service.get_image_service( + d_info['image_source'], + context=ctx) + image_properties = i_service.show( d_info['image_source'])['properties'] labels = ('kernel', 'ramdisk') @@ -691,10 +693,13 @@ def get_instance_image_info(task, ipxe_enabled=False): # we won't use any of them. We'll use the values specified # with the image, which we assume have been set. _get_image_properties() - for label in labels: - i_info[label] = str(image_properties[label + '_id']) - node.instance_info = i_info - node.save() + if image_properties: + # This is intended for Glance usage, but all image properties + # should be routed through the image service request routing. + for label in labels: + i_info[label] = str(image_properties[label + '_id']) + node.instance_info = i_info + node.save() anaconda_labels = () if deploy_utils.get_boot_option(node) == 'kickstart': diff --git a/ironic/tests/unit/common/test_pxe_utils.py b/ironic/tests/unit/common/test_pxe_utils.py index c6dc9bffab..3ef6062771 100644 --- a/ironic/tests/unit/common/test_pxe_utils.py +++ b/ironic/tests/unit/common/test_pxe_utils.py @@ -27,6 +27,7 @@ from oslo_utils import uuidutils from ironic.common import exception from ironic.common.glance_service import image_service +from ironic.common import image_service as base_image_service from ironic.common import pxe_utils from ironic.common import states from ironic.common import utils @@ -1463,6 +1464,65 @@ class PXEInterfacesTestCase(db_base.DbTestCase): self.assertEqual('https://server/fake.tmpl', image_info['ks_template'][0]) + @mock.patch('ironic.drivers.modules.deploy_utils.get_boot_option', + return_value='kickstart', autospec=True) + @mock.patch.object(base_image_service.HttpImageService, 'show', + autospec=True) + def test_get_instance_image_info_with_kickstart_url_http( + self, image_show_mock, boot_opt_mock): + properties = {'properties': {}} + expected_info = {'ramdisk': + ('http://fake.url/ramdisk', + os.path.join(CONF.pxe.tftp_root, + self.node.uuid, + 'ramdisk')), + 'kernel': + ('http://fake.url/kernel', + os.path.join(CONF.pxe.tftp_root, + self.node.uuid, + 'kernel')), + 'ks_template': + (CONF.anaconda.default_ks_template, + os.path.join(CONF.deploy.http_root, + self.node.uuid, + 'ks.cfg.template')), + 'ks_cfg': + ('', + os.path.join(CONF.deploy.http_root, + self.node.uuid, + 'ks.cfg'))} + image_show_mock.return_value = properties + self.context.auth_token = 'fake' + with task_manager.acquire(self.context, self.node.uuid, + shared=True) as task: + dii = task.node.driver_internal_info + dii['is_source_a_path'] = True + task.node.driver_internal_info = dii + i_info = task.node.instance_info + i_info['image_source'] = 'http://fake.url/path' + i_info['kernel'] = 'http://fake.url/kernel' + i_info['ramdisk'] = 'http://fake.url/ramdisk' + task.node.instance_info = i_info + task.node.save() + image_info = pxe_utils.get_instance_image_info( + task, ipxe_enabled=False) + self.assertEqual(expected_info, image_info) + # In the absense of kickstart template in both instance_info and + # image default kickstart template is used + self.assertEqual(CONF.anaconda.default_ks_template, + image_info['ks_template'][0]) + calls = [mock.call(task.node), mock.call(task.node)] + boot_opt_mock.assert_has_calls(calls) + # Instance info gets presedence over kickstart template on the + # image + properties['properties'] = {'ks_template': 'glance://template_id'} + task.node.instance_info['ks_template'] = 'https://server/fake.tmpl' + image_show_mock.return_value = properties + image_info = pxe_utils.get_instance_image_info( + task, ipxe_enabled=False) + self.assertEqual('https://server/fake.tmpl', + image_info['ks_template'][0]) + @mock.patch('ironic.drivers.modules.deploy_utils.get_boot_option', return_value='kickstart', autospec=True) @mock.patch.object(image_service.GlanceImageService, 'show', autospec=True) diff --git a/releasenotes/notes/fix-pxe-glance-lookup-anaconda-86fe616c6286ec08.yaml b/releasenotes/notes/fix-pxe-glance-lookup-anaconda-86fe616c6286ec08.yaml new file mode 100644 index 0000000000..bf6b8ea851 --- /dev/null +++ b/releasenotes/notes/fix-pxe-glance-lookup-anaconda-86fe616c6286ec08.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + Fixes an issue in the ``anaconda`` deployment interface where PXE argument + processing and preparation was erroniously directly connecting to Glance, + potentially leading to an exception in the standalone use case.