From 4de908587a35b0c594ba4ed2d599c9f51d465cd8 Mon Sep 17 00:00:00 2001 From: Luong Anh Tuan Date: Wed, 27 Sep 2017 15:02:37 +0700 Subject: [PATCH] Secure boot support for irmc-virtual-media driver This patch adds secure boot support for irmc-virtual-media boot interface as follows: - Implement secure boot support for irmc-virtual-media boot interface - Update irmc driver documentation Change-Id: I13961aaf6e26591f724d5f52d0a503c71eb6824a Closes-Bug: #1694649 --- doc/source/admin/drivers/irmc.rst | 4 + ironic/drivers/modules/irmc/boot.py | 8 ++ .../unit/drivers/modules/irmc/test_boot.py | 133 ++++++++++++++++++ ...ure-boot-suport-irmc-9509f3735df2aa5d.yaml | 5 + 4 files changed, 150 insertions(+) create mode 100644 releasenotes/notes/add-secure-boot-suport-irmc-9509f3735df2aa5d.yaml diff --git a/doc/source/admin/drivers/irmc.rst b/doc/source/admin/drivers/irmc.rst index d4d0d9e66e..0f8babec40 100644 --- a/doc/source/admin/drivers/irmc.rst +++ b/doc/source/admin/drivers/irmc.rst @@ -214,6 +214,8 @@ Node configuration irmc_username. - ``properties/capabilities`` property to be ``boot_mode:uefi`` if UEFI boot is required. + - ``properties/capabilities`` property to be ``secure_boot:true`` if + Secure Boot is required. - ``driver_info/irmc_deploy_iso`` property to be either ``deploy iso file name``, ``Glance UUID``, ``Glance URL`` or ``Image Service URL``. @@ -296,6 +298,8 @@ Node configuration irmc_username. - ``properties/capabilities`` property to be ``boot_mode:uefi`` if UEFI boot is required. + - ``properties/capabilities`` property to be ``secure_boot:true`` if + Secure Boot is required. - ``driver_info/irmc_deploy_iso`` property to be either ``deploy iso file name``, ``Glance UUID``, ``Glance URL`` or ``Image Service URL``. diff --git a/ironic/drivers/modules/irmc/boot.py b/ironic/drivers/modules/irmc/boot.py index 615a9ac791..dbb40059ff 100644 --- a/ironic/drivers/modules/irmc/boot.py +++ b/ironic/drivers/modules/irmc/boot.py @@ -995,6 +995,10 @@ class IRMCVirtualMediaBoot(base.BootInterface, IRMCVolumeBootMixIn): root_uuid_or_disk_id = driver_internal_info['root_uuid_or_disk_id'] self._configure_vmedia_boot(task, root_uuid_or_disk_id) + # Enable secure boot, if being requested + if deploy_utils.is_secure_boot_requested(node): + irmc_common.set_secure_boot_mode(node, enable=True) + @METRICS.timer('IRMCVirtualMediaBoot.clean_up_instance') def clean_up_instance(self, task): """Cleans up the boot of instance. @@ -1010,6 +1014,10 @@ class IRMCVirtualMediaBoot(base.BootInterface, IRMCVolumeBootMixIn): self._cleanup_boot_from_volume(task) return + # Disable secure boot, if enabled secure boot + if deploy_utils.is_secure_boot_requested(task.node): + irmc_common.set_secure_boot_mode(task.node, enable=False) + _remove_share_file(_get_boot_iso_name(task.node)) driver_internal_info = task.node.driver_internal_info driver_internal_info.pop('irmc_boot_iso', None) diff --git a/ironic/tests/unit/drivers/modules/irmc/test_boot.py b/ironic/tests/unit/drivers/modules/irmc/test_boot.py index bfc3b3b23d..d911a27894 100644 --- a/ironic/tests/unit/drivers/modules/irmc/test_boot.py +++ b/ironic/tests/unit/drivers/modules/irmc/test_boot.py @@ -1075,6 +1075,139 @@ class IRMCVirtualMediaBootTestCase(db_base.DbTestCase): self.assertRaises(ValueError, cfg.CONF.set_override, 'remote_image_share_type', 'fake', 'irmc') + @mock.patch.object(irmc_common, 'set_secure_boot_mode', spec_set=True, + autospec=True) + @mock.patch.object(irmc_boot.IRMCVirtualMediaBoot, + '_configure_vmedia_boot', spec_set=True, + autospec=True) + @mock.patch.object(irmc_boot, '_cleanup_vmedia_boot', spec_set=True, + autospec=True) + def test_prepare_instance_with_secure_boot(self, mock_cleanup_vmedia_boot, + mock_configure_vmedia_boot, + mock_set_secure_boot_mode): + self.node.driver_internal_info = {'root_uuid_or_disk_id': "12312642"} + self.node.provision_state = states.DEPLOYING + self.node.target_provision_state = states.ACTIVE + self.node.instance_info = { + 'capabilities': { + "secure_boot": "true" + } + } + self.node.save() + with task_manager.acquire(self.context, self.node.uuid, + shared=False) as task: + task.driver.boot.prepare_instance(task) + mock_cleanup_vmedia_boot.assert_called_once_with(task) + mock_set_secure_boot_mode.assert_called_once_with(task.node, + enable=True) + mock_configure_vmedia_boot.assert_called_once_with(mock.ANY, task, + "12312642") + + @mock.patch.object(irmc_common, 'set_secure_boot_mode', spec_set=True, + autospec=True) + @mock.patch.object(irmc_boot.IRMCVirtualMediaBoot, + '_configure_vmedia_boot', spec_set=True, + autospec=True) + @mock.patch.object(irmc_boot, '_cleanup_vmedia_boot', spec_set=True, + autospec=True) + def test_prepare_instance_with_secure_boot_false( + self, mock_cleanup_vmedia_boot, mock_configure_vmedia_boot, + mock_set_secure_boot_mode): + self.node.driver_internal_info = {'root_uuid_or_disk_id': "12312642"} + self.node.provision_state = states.DEPLOYING + self.node.target_provision_state = states.ACTIVE + self.node.instance_info = { + 'capabilities': { + "secure_boot": "false" + } + } + self.node.save() + with task_manager.acquire(self.context, self.node.uuid, + shared=False) as task: + task.driver.boot.prepare_instance(task) + mock_cleanup_vmedia_boot.assert_called_once_with(task) + self.assertFalse(mock_set_secure_boot_mode.called) + mock_configure_vmedia_boot.assert_called_once_with(mock.ANY, task, + "12312642") + + @mock.patch.object(irmc_common, 'set_secure_boot_mode', spec_set=True, + autospec=True) + @mock.patch.object(irmc_boot.IRMCVirtualMediaBoot, + '_configure_vmedia_boot', spec_set=True, + autospec=True) + @mock.patch.object(irmc_boot, '_cleanup_vmedia_boot', spec_set=True, + autospec=True) + def test_prepare_instance_without_secure_boot( + self, mock_cleanup_vmedia_boot, mock_configure_vmedia_boot, + mock_set_secure_boot_mode): + self.node.driver_internal_info = {'root_uuid_or_disk_id': "12312642"} + self.node.provision_state = states.DEPLOYING + self.node.target_provision_state = states.ACTIVE + self.node.save() + with task_manager.acquire(self.context, self.node.uuid, + shared=False) as task: + task.driver.boot.prepare_instance(task) + mock_cleanup_vmedia_boot.assert_called_once_with(task) + self.assertFalse(mock_set_secure_boot_mode.called) + mock_configure_vmedia_boot.assert_called_once_with(mock.ANY, task, + "12312642") + + @mock.patch.object(irmc_common, 'set_secure_boot_mode', spec_set=True, + autospec=True) + @mock.patch.object(irmc_boot, '_cleanup_vmedia_boot', spec_set=True, + autospec=True) + def test_clean_up_instance_with_secure_boot(self, mock_cleanup_vmedia_boot, + mock_set_secure_boot_mode): + self.node.provision_state = states.CLEANING + self.node.target_provision_state = states.AVAILABLE + self.node.instance_info = { + 'capabilities': { + "secure_boot": "true" + } + } + self.node.save() + with task_manager.acquire(self.context, self.node.uuid, + shared=False) as task: + task.driver.boot.clean_up_instance(task) + mock_set_secure_boot_mode.assert_called_once_with(task.node, + enable=False) + mock_cleanup_vmedia_boot.assert_called_once_with(task) + + @mock.patch.object(irmc_common, 'set_secure_boot_mode', spec_set=True, + autospec=True) + @mock.patch.object(irmc_boot, '_cleanup_vmedia_boot', spec_set=True, + autospec=True) + def test_clean_up_instance_with_secure_boot_false( + self, mock_cleanup_vmedia_boot, mock_set_secure_boot_mode): + self.node.provision_state = states.CLEANING + self.node.target_provision_state = states.AVAILABLE + self.node.instance_info = { + 'capabilities': { + "secure_boot": "false" + } + } + self.node.save() + with task_manager.acquire(self.context, self.node.uuid, + shared=False) as task: + task.driver.boot.clean_up_instance(task) + self.assertFalse(mock_set_secure_boot_mode.called) + mock_cleanup_vmedia_boot.assert_called_once_with(task) + + @mock.patch.object(irmc_common, 'set_secure_boot_mode', spec_set=True, + autospec=True) + @mock.patch.object(irmc_boot, '_cleanup_vmedia_boot', spec_set=True, + autospec=True) + def test_clean_up_instance_without_secure_boot( + self, mock_cleanup_vmedia_boot, mock_set_secure_boot_mode): + self.node.provision_state = states.CLEANING + self.node.target_provision_state = states.AVAILABLE + self.node.save() + with task_manager.acquire(self.context, self.node.uuid, + shared=False) as task: + task.driver.boot.clean_up_instance(task) + self.assertFalse(mock_set_secure_boot_mode.called) + mock_cleanup_vmedia_boot.assert_called_once_with(task) + class IRMCPXEBootTestCase(db_base.DbTestCase): diff --git a/releasenotes/notes/add-secure-boot-suport-irmc-9509f3735df2aa5d.yaml b/releasenotes/notes/add-secure-boot-suport-irmc-9509f3735df2aa5d.yaml new file mode 100644 index 0000000000..30d26f787c --- /dev/null +++ b/releasenotes/notes/add-secure-boot-suport-irmc-9509f3735df2aa5d.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + Adds support to provision an instance in secure boot mode for + ``irmc-virtual-media`` boot interface. \ No newline at end of file