summaryrefslogtreecommitdiff
path: root/ironic/tests/unit/drivers/modules/test_image_utils.py
diff options
context:
space:
mode:
authorvmud213 <vinay50muddu@yahoo.com>2020-07-03 06:15:25 +0000
committervmud213 <vinay50muddu@yahoo.com>2020-08-24 10:25:46 +0000
commitc165f71a562a31f0541118b940fb0fb935b73fc6 (patch)
treec0eeee46f207b6fae1ff19fa0cc0bfc65a0cc537 /ironic/tests/unit/drivers/modules/test_image_utils.py
parent325dfbafc9ac8650ff71803cb4e5289515694dbd (diff)
downloadironic-c165f71a562a31f0541118b940fb0fb935b73fc6.tar.gz
Decouple the ISO creation logic from redfish
Currently the functionality of creating the ISO and floppy images is tightly coupled with the redfish boot interface implementation. Move this to a common place so that this can be levereged when needed. Change-Id: Iea1991690e28d31a54afeaf5231ddc5798c8213c Story: #2007940 Task: #40405
Diffstat (limited to 'ironic/tests/unit/drivers/modules/test_image_utils.py')
-rw-r--r--ironic/tests/unit/drivers/modules/test_image_utils.py413
1 files changed, 413 insertions, 0 deletions
diff --git a/ironic/tests/unit/drivers/modules/test_image_utils.py b/ironic/tests/unit/drivers/modules/test_image_utils.py
new file mode 100644
index 000000000..6b9f85ca5
--- /dev/null
+++ b/ironic/tests/unit/drivers/modules/test_image_utils.py
@@ -0,0 +1,413 @@
+# Copyright 2019 Red Hat, Inc.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import os
+from unittest import mock
+
+from oslo_utils import importutils
+
+from ironic.common import images
+from ironic.conductor import task_manager
+from ironic.drivers.modules import image_utils
+from ironic.tests.unit.db import base as db_base
+from ironic.tests.unit.db import utils as db_utils
+from ironic.tests.unit.objects import utils as obj_utils
+
+sushy = importutils.try_import('sushy')
+
+INFO_DICT = db_utils.get_test_redfish_info()
+
+
+class RedfishImageHandlerTestCase(db_base.DbTestCase):
+
+ def setUp(self):
+ super(RedfishImageHandlerTestCase, self).setUp()
+ self.config(enabled_hardware_types=['redfish'],
+ enabled_power_interfaces=['redfish'],
+ enabled_boot_interfaces=['redfish-virtual-media'],
+ enabled_management_interfaces=['redfish'],
+ enabled_inspect_interfaces=['redfish'],
+ enabled_bios_interfaces=['redfish'])
+ self.node = obj_utils.create_test_node(
+ self.context, driver='redfish', driver_info=INFO_DICT)
+
+ def test__append_filename_param_without_qs(self):
+ img_handler_obj = image_utils.ImageHandler(self.node.driver)
+ res = img_handler_obj._append_filename_param(
+ 'http://a.b/c', 'b.img')
+ expected = 'http://a.b/c?filename=b.img'
+ self.assertEqual(expected, res)
+
+ def test__append_filename_param_with_qs(self):
+ img_handler_obj = image_utils.ImageHandler(self.node.driver)
+ res = img_handler_obj._append_filename_param(
+ 'http://a.b/c?d=e&f=g', 'b.img')
+ expected = 'http://a.b/c?d=e&f=g&filename=b.img'
+ self.assertEqual(expected, res)
+
+ def test__append_filename_param_with_filename(self):
+ img_handler_obj = image_utils.ImageHandler(self.node.driver)
+ res = img_handler_obj._append_filename_param(
+ 'http://a.b/c?filename=bootme.img', 'b.img')
+ expected = 'http://a.b/c?filename=bootme.img'
+ self.assertEqual(expected, res)
+
+ @mock.patch.object(image_utils, 'swift', autospec=True)
+ def test_publish_image_swift(self, mock_swift):
+ img_handler_obj = image_utils.ImageHandler(self.node.driver)
+ mock_swift_api = mock_swift.SwiftAPI.return_value
+ mock_swift_api.get_temp_url.return_value = 'https://a.b/c.f?e=f'
+
+ url = img_handler_obj.publish_image('file.iso', 'boot.iso')
+
+ self.assertEqual(
+ 'https://a.b/c.f?e=f&filename=file.iso', url)
+
+ mock_swift.SwiftAPI.assert_called_once_with()
+
+ mock_swift_api.create_object.assert_called_once_with(
+ mock.ANY, mock.ANY, mock.ANY, mock.ANY)
+
+ mock_swift_api.get_temp_url.assert_called_once_with(
+ mock.ANY, mock.ANY, mock.ANY)
+
+ @mock.patch.object(image_utils, 'swift', autospec=True)
+ def test_unpublish_image_swift(self, mock_swift):
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ img_handler_obj = image_utils.ImageHandler(self.node.driver)
+ object_name = 'image-%s' % task.node.uuid
+
+ img_handler_obj.unpublish_image(object_name)
+
+ mock_swift.SwiftAPI.assert_called_once_with()
+ mock_swift_api = mock_swift.SwiftAPI.return_value
+
+ mock_swift_api.delete_object.assert_called_once_with(
+ 'ironic_redfish_container', object_name)
+
+ @mock.patch.object(image_utils.ImageHandler, '_is_swift_enabled',
+ autospec=True)
+ @mock.patch.object(os, 'chmod', autospec=True)
+ @mock.patch.object(image_utils, 'shutil', autospec=True)
+ @mock.patch.object(os, 'link', autospec=True)
+ @mock.patch.object(os, 'mkdir', autospec=True)
+ def test_publish_image_local_link(
+ self, mock_mkdir, mock_link, mock_shutil, mock_chmod,
+ mock__is_swift):
+ img_handler_obj = image_utils.ImageHandler(self.node.driver)
+ mock__is_swift.return_value = False
+ self.config(use_swift=False, group='redfish')
+ self.config(http_url='http://localhost', group='deploy')
+
+ url = img_handler_obj.publish_image('file.iso', 'boot.iso')
+
+ self.assertEqual(
+ 'http://localhost/redfish/boot.iso?filename=file.iso', url)
+
+ mock_mkdir.assert_called_once_with('/httpboot/redfish', 0o755)
+ mock_link.assert_called_once_with(
+ 'file.iso', '/httpboot/redfish/boot.iso')
+ mock_chmod.assert_called_once_with('file.iso', 0o644)
+
+ @mock.patch.object(image_utils.ImageHandler, '_is_swift_enabled',
+ autospec=True)
+ @mock.patch.object(os, 'chmod', autospec=True)
+ @mock.patch.object(image_utils, 'shutil', autospec=True)
+ @mock.patch.object(os, 'link', autospec=True)
+ @mock.patch.object(os, 'mkdir', autospec=True)
+ def test_publish_image_local_copy(self, mock_mkdir, mock_link,
+ mock_shutil, mock_chmod,
+ mock__is_swift):
+ mock__is_swift.return_value = False
+ self.config(use_swift=False, group='redfish')
+ self.config(http_url='http://localhost', group='deploy')
+ img_handler_obj = image_utils.ImageHandler(self.node.driver)
+
+ mock_link.side_effect = OSError()
+
+ url = img_handler_obj.publish_image('file.iso', 'boot.iso')
+
+ self.assertEqual(
+ 'http://localhost/redfish/boot.iso?filename=file.iso', url)
+
+ mock_mkdir.assert_called_once_with('/httpboot/redfish', 0o755)
+
+ mock_shutil.copyfile.assert_called_once_with(
+ 'file.iso', '/httpboot/redfish/boot.iso')
+ mock_chmod.assert_called_once_with('/httpboot/redfish/boot.iso',
+ 0o644)
+
+ @mock.patch.object(image_utils.ImageHandler, '_is_swift_enabled',
+ autospec=True)
+ @mock.patch.object(image_utils, 'ironic_utils', autospec=True)
+ def test_unpublish_image_local(self, mock_ironic_utils, mock__is_swift):
+ self.config(use_swift=False, group='redfish')
+ mock__is_swift.return_value = False
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ img_handler_obj = image_utils.ImageHandler(self.node.driver)
+ object_name = 'image-%s' % task.node.uuid
+
+ expected_file = '/httpboot/redfish/' + object_name
+
+ img_handler_obj.unpublish_image(object_name)
+
+ mock_ironic_utils.unlink_without_raise.assert_called_once_with(
+ expected_file)
+
+
+class RedfishImageUtilsTestCase(db_base.DbTestCase):
+
+ def setUp(self):
+ super(RedfishImageUtilsTestCase, self).setUp()
+ self.config(enabled_hardware_types=['redfish'],
+ enabled_power_interfaces=['redfish'],
+ enabled_boot_interfaces=['redfish-virtual-media'],
+ enabled_management_interfaces=['redfish'],
+ enabled_inspect_interfaces=['redfish'],
+ enabled_bios_interfaces=['redfish'])
+ self.node = obj_utils.create_test_node(
+ self.context, driver='redfish', driver_info=INFO_DICT)
+
+ @mock.patch.object(image_utils.ImageHandler, 'unpublish_image',
+ autospec=True)
+ def test_cleanup_floppy_image(self, mock_unpublish):
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ image_utils.cleanup_floppy_image(task)
+
+ object_name = 'image-%s' % task.node.uuid
+
+ mock_unpublish.assert_called_once_with(mock.ANY, object_name)
+
+ @mock.patch.object(image_utils.ImageHandler, 'publish_image',
+ autospec=True)
+ @mock.patch.object(images, 'create_vfat_image', autospec=True)
+ def test_prepare_floppy_image(
+ self, mock_create_vfat_image, mock_publish_image):
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ expected_url = 'https://a.b/c.f?e=f'
+
+ mock_publish_image.return_value = expected_url
+
+ url = image_utils.prepare_floppy_image(task)
+
+ object_name = 'image-%s' % task.node.uuid
+
+ mock_publish_image.assert_called_once_with(mock.ANY,
+ mock.ANY, object_name)
+
+ mock_create_vfat_image.assert_called_once_with(
+ mock.ANY, parameters=mock.ANY)
+
+ self.assertEqual(expected_url, url)
+
+ @mock.patch.object(image_utils.ImageHandler, 'unpublish_image',
+ autospec=True)
+ def test_cleanup_iso_image(self, mock_unpublish):
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ image_utils.cleanup_iso_image(task)
+
+ object_name = 'boot-%s' % task.node.uuid
+
+ mock_unpublish.assert_called_once_with(mock.ANY, object_name)
+
+ @mock.patch.object(image_utils.ImageHandler, 'publish_image',
+ autospec=True)
+ @mock.patch.object(images, 'create_boot_iso', autospec=True)
+ def test__prepare_iso_image_uefi(
+ self, mock_create_boot_iso, mock_publish_image):
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ task.node.instance_info.update(deploy_boot_mode='uefi')
+
+ expected_url = 'https://a.b/c.f?e=f'
+
+ mock_publish_image.return_value = expected_url
+
+ url = image_utils._prepare_iso_image(
+ task, 'http://kernel/img', 'http://ramdisk/img',
+ 'http://bootloader/img', root_uuid=task.node.uuid)
+
+ object_name = 'boot-%s' % task.node.uuid
+
+ mock_publish_image.assert_called_once_with(
+ mock.ANY, mock.ANY, object_name)
+
+ mock_create_boot_iso.assert_called_once_with(
+ mock.ANY, mock.ANY, 'http://kernel/img', 'http://ramdisk/img',
+ boot_mode='uefi', esp_image_href='http://bootloader/img',
+ configdrive_href=mock.ANY,
+ kernel_params='nofb nomodeset vga=normal',
+ root_uuid='1be26c0b-03f2-4d2e-ae87-c02d7f33c123',
+ base_iso=None)
+
+ self.assertEqual(expected_url, url)
+
+ @mock.patch.object(image_utils.ImageHandler, 'publish_image',
+ autospec=True)
+ @mock.patch.object(images, 'create_boot_iso', autospec=True)
+ def test__prepare_iso_image_bios(
+ self, mock_create_boot_iso, mock_publish_image):
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+
+ expected_url = 'https://a.b/c.f?e=f'
+
+ mock_publish_image.return_value = expected_url
+
+ url = image_utils._prepare_iso_image(
+ task, 'http://kernel/img', 'http://ramdisk/img',
+ bootloader_href=None, root_uuid=task.node.uuid, base_iso=None)
+
+ object_name = 'boot-%s' % task.node.uuid
+
+ mock_publish_image.assert_called_once_with(
+ mock.ANY, mock.ANY, object_name)
+
+ mock_create_boot_iso.assert_called_once_with(
+ mock.ANY, mock.ANY, 'http://kernel/img', 'http://ramdisk/img',
+ boot_mode=None, esp_image_href=None,
+ configdrive_href=mock.ANY,
+ kernel_params='nofb nomodeset vga=normal',
+ root_uuid='1be26c0b-03f2-4d2e-ae87-c02d7f33c123',
+ base_iso=None)
+
+ self.assertEqual(expected_url, url)
+
+ @mock.patch.object(image_utils.ImageHandler, 'publish_image',
+ autospec=True)
+ @mock.patch.object(images, 'create_boot_iso', autospec=True)
+ def test__prepare_iso_image_kernel_params(
+ self, mock_create_boot_iso, mock_publish_image):
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ kernel_params = 'network-config=base64-cloudinit-blob'
+
+ task.node.instance_info.update(kernel_append_params=kernel_params)
+
+ image_utils._prepare_iso_image(
+ task, 'http://kernel/img', 'http://ramdisk/img',
+ bootloader_href=None, root_uuid=task.node.uuid,
+ base_iso='/path/to/baseiso')
+
+ mock_create_boot_iso.assert_called_once_with(
+ mock.ANY, mock.ANY, 'http://kernel/img', 'http://ramdisk/img',
+ boot_mode=None, esp_image_href=None,
+ configdrive_href=mock.ANY,
+ kernel_params=kernel_params,
+ root_uuid='1be26c0b-03f2-4d2e-ae87-c02d7f33c123',
+ base_iso='/path/to/baseiso')
+
+ @mock.patch.object(image_utils, '_prepare_iso_image', autospec=True)
+ def test_prepare_deploy_iso(self, mock__prepare_iso_image):
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+
+ d_info = {
+ 'deploy_kernel': 'kernel',
+ 'deploy_ramdisk': 'ramdisk',
+ 'bootloader': 'bootloader'
+ }
+ task.node.driver_info.update(d_info)
+
+ task.node.instance_info.update(deploy_boot_mode='uefi')
+
+ image_utils.prepare_deploy_iso(task, {}, 'deploy', d_info)
+
+ mock__prepare_iso_image.assert_called_once_with(
+ task, 'kernel', 'ramdisk', 'bootloader', params={})
+
+ @mock.patch.object(image_utils, '_prepare_iso_image', autospec=True)
+ @mock.patch.object(images, 'create_vfat_image', autospec=True)
+ def test_prepare_deploy_iso_network_data(
+ self, mock_create_vfat_image, mock__prepare_iso_image):
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+
+ d_info = {
+ 'deploy_kernel': 'kernel',
+ 'deploy_ramdisk': 'ramdisk'
+ }
+ task.node.driver_info.update(d_info)
+
+ task.node.instance_info.update()
+
+ network_data = {'a': ['b']}
+
+ mock_get_node_nw_data = mock.MagicMock(return_value=network_data)
+ task.driver.network.get_node_network_data = mock_get_node_nw_data
+
+ image_utils.prepare_deploy_iso(task, {}, 'deploy', d_info)
+
+ mock_create_vfat_image.assert_called_once_with(
+ mock.ANY, mock.ANY)
+
+ mock__prepare_iso_image.assert_called_once_with(
+ task, 'kernel', 'ramdisk', bootloader_href=None,
+ configdrive=mock.ANY, params={})
+
+ @mock.patch.object(image_utils, '_prepare_iso_image', autospec=True)
+ @mock.patch.object(images, 'create_boot_iso', autospec=True)
+ def test_prepare_boot_iso(self, mock_create_boot_iso,
+ mock__prepare_iso_image):
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ d_info = {
+ 'deploy_kernel': 'kernel',
+ 'deploy_ramdisk': 'ramdisk',
+ 'bootloader': 'bootloader'
+ }
+ task.node.driver_info.update(d_info)
+
+ task.node.instance_info.update(
+ {'image_source': 'http://boot/iso',
+ 'kernel': 'http://kernel/img',
+ 'ramdisk': 'http://ramdisk/img'})
+
+ image_utils.prepare_boot_iso(
+ task, d_info, root_uuid=task.node.uuid)
+
+ mock__prepare_iso_image.assert_called_once_with(
+ mock.ANY, 'http://kernel/img', 'http://ramdisk/img',
+ 'bootloader', root_uuid=task.node.uuid,
+ base_iso=None)
+
+ @mock.patch.object(image_utils, '_prepare_iso_image', autospec=True)
+ @mock.patch.object(images, 'create_boot_iso', autospec=True)
+ def test_prepare_boot_iso_user_supplied(self, mock_create_boot_iso,
+ mock__prepare_iso_image):
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ d_info = {
+ 'deploy_kernel': 'kernel',
+ 'deploy_ramdisk': 'ramdisk',
+ 'bootloader': 'bootloader'
+ }
+ task.node.driver_info.update(d_info)
+
+ task.node.instance_info.update(
+ {'boot_iso': 'http://boot/iso'})
+
+ image_utils.prepare_boot_iso(
+ task, d_info, root_uuid=task.node.uuid)
+
+ mock__prepare_iso_image.assert_called_once_with(
+ mock.ANY, None, None,
+ 'bootloader', root_uuid=task.node.uuid,
+ base_iso='http://boot/iso')