summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvinay50muddu <vinay50muddu@yahoo.com>2021-07-05 10:09:35 +0000
committerNisha Agarwal <agarwalnisha1980@gmail.com>2021-09-08 04:09:01 -0700
commitdf4778605da461ef91b79fae4110347dc28f3a47 (patch)
treea943edf0b76f1ad4b0a3abd065c362978b9a1de8
parent8434b56766cf42e8faa36cad8cc39eaf43ac5ca7 (diff)
downloadironic-df4778605da461ef91b79fae4110347dc28f3a47.tar.gz
Clean step to remove CA certificates from iLO
Implements clean step "clear_ca_certificates" to remove any 3rd party expired/revoked CA certificates from iLO. Change-Id: I0a3c1da9b94e4037a53ade100354ac51ca08db35 Story: #2008784 Task: #42175
-rw-r--r--doc/source/admin/drivers/ilo.rst36
-rw-r--r--ironic/drivers/modules/ilo/boot.py7
-rw-r--r--ironic/drivers/modules/ilo/common.py5
-rw-r--r--ironic/drivers/modules/ilo/management.py62
-rw-r--r--ironic/tests/unit/drivers/modules/ilo/test_boot.py21
-rw-r--r--ironic/tests/unit/drivers/modules/ilo/test_common.py30
-rw-r--r--ironic/tests/unit/drivers/modules/ilo/test_management.py162
-rw-r--r--releasenotes/notes/clear_ca_cert-db41e7be9723c0fb.yaml5
8 files changed, 316 insertions, 12 deletions
diff --git a/doc/source/admin/drivers/ilo.rst b/doc/source/admin/drivers/ilo.rst
index 74153cc9c..40bb06735 100644
--- a/doc/source/admin/drivers/ilo.rst
+++ b/doc/source/admin/drivers/ilo.rst
@@ -56,6 +56,7 @@ The hardware type ``ilo`` supports following HPE server features:
* `Update Minimum Password Length security parameter as manual clean step`_
* `Update Authentication Failure Logging security parameter as manual clean step`_
* `Activating iLO Advanced license as manual clean step`_
+* `Removing CA certificates from iLO as manual clean step`_
* `Firmware based UEFI iSCSI boot from volume support`_
* `Certificate based validation in iLO`_
* `Rescue mode support`_
@@ -702,6 +703,10 @@ Supported **Manual** Cleaning Operations
delivered with a flexible-quantity kit or after completing an Activation
Key Agreement (AKA), then the driver can still be used for executing
this cleaning step.
+ ``clear_ca_certificates``:
+ Removes the CA certificates from iLO. See
+ `Removing CA certificates from iLO as manual clean step`_ for user
+ guidance on usage.
``apply_configuration``:
Applies given BIOS settings on the node. See
`BIOS configuration support`_. This step is part of the ``bios`` interface.
@@ -1477,6 +1482,37 @@ The different attributes of ``activate_license`` clean step are as follows:
"``args``", "Keyword-argument entry (<name>: <value>) being passed to clean step"
"``args.ilo_license_key``", "iLO Advanced license key to activate enterprise features. This is mandatory."
+Removing CA certificates from iLO as manual clean step
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+iLO driver can remove the invalidated CA certificates as a manual step.
+Any manual cleaning step can only be initiated when a node is in the
+``manageable`` state. Once the manual cleaning is finished, the node will be
+put in the ``manageable`` state again. User can follow steps from
+:ref:`manual_cleaning` to initiate manual cleaning operation on a node.
+
+An example of a manual clean step with ``clear_ca_certificates`` as the only clean
+step could be::
+
+ "clean_steps": [{
+ "interface": "management",
+ "step": "clear_ca_certificates",
+ "args": {
+ "certificate_files" : ["/path/to/certsA", "/path/to/certsB"]
+ }
+ }]
+
+The different attributes of ``clear_ca_certificates`` clean step are as follows:
+
+.. csv-table::
+ :header: "Attribute", "Description"
+ :widths: 30, 120
+
+ "``interface``", "Interface of clean step, here ``management``"
+ "``step``", "Name of clean step, here ``clear_ca_certificates``"
+ "``args``", "Keyword-argument entry (<name>: <value>) being passed to clean step"
+ "``args.certificate_files``", "List of CA certificates which are to be removed. "
+ "This is mandatory."
+
Initiating firmware update as manual clean step
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
iLO driver can invoke secure firmware update as a manual cleaning step. Any
diff --git a/ironic/drivers/modules/ilo/boot.py b/ironic/drivers/modules/ilo/boot.py
index bcfb7bb96..60e0c3a25 100644
--- a/ironic/drivers/modules/ilo/boot.py
+++ b/ironic/drivers/modules/ilo/boot.py
@@ -1022,11 +1022,16 @@ class IloUefiHttpsBoot(base.BootInterface):
iso_ref = image_utils.prepare_deploy_iso(task, ramdisk_params,
mode, d_info)
+ # NOTE(vmud213): Do not call if it is in the middle of
+ # clear_ca_certificates clean step as the TLS pending settings will
+ # be overridden
+ if not node.driver_internal_info.get('clear_ca_certs_flag'):
+ ilo_common.add_certificates(task)
+
LOG.debug("Set 'UEFIHTTP' as one time boot option on the node "
"%(node)s to boot from URL %(iso_ref)s.",
{'node': node.uuid, 'iso_ref': iso_ref})
- ilo_common.add_certificates(task)
ilo_common.setup_uefi_https(task, iso_ref)
@METRICS.timer('IloUefiHttpsBoot.clean_up_ramdisk')
diff --git a/ironic/drivers/modules/ilo/common.py b/ironic/drivers/modules/ilo/common.py
index 69161499b..a69a4e3ec 100644
--- a/ironic/drivers/modules/ilo/common.py
+++ b/ironic/drivers/modules/ilo/common.py
@@ -1068,10 +1068,13 @@ def clear_certificates(task, cert_file_list=None):
node = task.node
operation = (_("Clearing certificates from node %(node)s.") %
{'node': node.uuid})
+ # NOTE(vmud213): Exclude the certificates used to boot deploy images
+ exclude_cfl = _get_certificate_file_list(None)
try:
ilo_object = get_ilo_object(node)
- ilo_object.remove_tls_certificate(cert_file_list)
+ ilo_object.remove_tls_certificate(
+ cert_file_list=cert_file_list, excl_cert_file_list=exclude_cfl)
except ilo_error.IloCommandNotSupportedInBiosError as ilo_exception:
raise exception.IloOperationNotSupported(operation=operation,
error=ilo_exception)
diff --git a/ironic/drivers/modules/ilo/management.py b/ironic/drivers/modules/ilo/management.py
index 17516b4b8..e78db25ef 100644
--- a/ironic/drivers/modules/ilo/management.py
+++ b/ironic/drivers/modules/ilo/management.py
@@ -186,6 +186,20 @@ _FIRMWARE_UPDATE_SUM_ARGSINFO = {
}
}
+_CLEAR_CA_CERTS_ARGSINFO = {
+ 'certificate_files': {
+ 'description': (
+ "The list of files containing the certificates to be cleared. "
+ "If empty list is specified, all the certificates on the ilo "
+ "will be cleared, except the certificates in the file "
+ "configured with configuration parameter 'webserver_verify_ca' "
+ "are spared as they are required for booting the deploy image "
+ "for some boot interfaces."
+ ),
+ 'required': True
+ }
+}
+
def _execute_ilo_step(node, step, *args, **kwargs):
"""Executes a particular deploy or clean step.
@@ -1128,3 +1142,51 @@ class Ilo5Management(IloManagement):
{'node': task.node.uuid, 'message': ilo_exception})
manager_utils.cleaning_error_handler(task, log_msg,
errmsg=ilo_exception)
+
+ @base.clean_step(priority=0, argsinfo=_CLEAR_CA_CERTS_ARGSINFO)
+ def clear_ca_certificates(self, task, certificate_files):
+ """Clears the certificates provided in the list of files to iLO.
+
+ :param task: a task from TaskManager.
+ :param certificate_files: a list of cerificate files.
+ :raises: NodeCleaningFailure, on failure to execute of clean step.
+ :raises: InstanceDeployFailure, on failure to execute of deploy step.
+ """
+ node = task.node
+ driver_internal_info = node.driver_internal_info
+
+ if driver_internal_info.get('clear_ca_certs_flag'):
+ # NOTE(vmud213): Clear the flag and do nothing as this flow
+ # is part of the reboot required by the clean step that is
+ # already executed.
+ driver_internal_info.pop('clear_ca_certs_flag', None)
+ node.driver_internal_info = driver_internal_info
+ node.save()
+ return
+
+ try:
+ ilo_common.clear_certificates(task, certificate_files)
+ except (exception.IloOperationNotSupported,
+ exception.IloOperationError) as ir_exception:
+ msg = (_("Step 'clear_ca_certificates' failed on node %(node)s "
+ "with error: %(err)s") %
+ {'node': node.uuid, 'err': ir_exception})
+ if node.clean_step:
+ raise exception.NodeCleaningFailure(msg)
+ raise exception.InstanceDeployFailure(msg)
+
+ driver_internal_info['clear_ca_certs_flag'] = True
+ node.driver_internal_info = driver_internal_info
+ node.save()
+
+ deploy_opts = deploy_utils.build_agent_options(task.node)
+ task.driver.boot.prepare_ramdisk(task, deploy_opts)
+ manager_utils.node_power_action(task, states.REBOOT)
+
+ # set_async_step_flags calls node.save()
+ deploy_utils.set_async_step_flags(
+ node,
+ reboot=True,
+ skip_current_step=False)
+
+ return deploy_utils.get_async_step_return_state(task.node)
diff --git a/ironic/tests/unit/drivers/modules/ilo/test_boot.py b/ironic/tests/unit/drivers/modules/ilo/test_boot.py
index 2fae7b9c3..128f603c5 100644
--- a/ironic/tests/unit/drivers/modules/ilo/test_boot.py
+++ b/ironic/tests/unit/drivers/modules/ilo/test_boot.py
@@ -1812,7 +1812,11 @@ class IloUefiHttpsBootTestCase(db_base.DbTestCase):
task, ramdisk_params, mode, d_info)
setup_uefi_https_mock.assert_called_once_with(task,
'recreated-iso')
- add_mock.assert_called_once_with(task)
+ if task.node.driver_internal_info.get("clear_ca_certs_flag",
+ False):
+ add_mock.assert_not_called()
+ else:
+ add_mock.assert_called_once_with(task)
def test_prepare_ramdisk_rescue_glance_image(self):
self._test_prepare_ramdisk(
@@ -1832,6 +1836,21 @@ class IloUefiHttpsBootTestCase(db_base.DbTestCase):
self.node.instance_info['boot_iso'])
def test_prepare_ramdisk_glance_image(self):
+ driver_internal_info = self.node.driver_internal_info
+ driver_internal_info['clear_ca_certs_flag'] = False
+ self.node.driver_internal_info = driver_internal_info
+ self.node.save()
+ self._test_prepare_ramdisk(
+ ilo_boot_iso='swift:abcdef',
+ image_source='6b2f0c0c-79e8-4db6-842e-43c9764204af')
+ self.node.refresh()
+ self.assertNotIn('boot_iso', self.node.instance_info)
+
+ def test_prepare_ramdisk_middle_of_clean_step(self):
+ driver_internal_info = self.node.driver_internal_info
+ driver_internal_info['clear_ca_certs_flag'] = True
+ self.node.driver_internal_info = driver_internal_info
+ self.node.save()
self._test_prepare_ramdisk(
ilo_boot_iso='swift:abcdef',
image_source='6b2f0c0c-79e8-4db6-842e-43c9764204af')
diff --git a/ironic/tests/unit/drivers/modules/ilo/test_common.py b/ironic/tests/unit/drivers/modules/ilo/test_common.py
index f1d9cd241..1d4bfd8b2 100644
--- a/ironic/tests/unit/drivers/modules/ilo/test_common.py
+++ b/ironic/tests/unit/drivers/modules/ilo/test_common.py
@@ -1370,34 +1370,50 @@ class IloCommonMethodsTestCase(BaseIloTest):
get_cl_mock.assert_called_once_with(c_l)
ilo_mock_object.add_tls_certificate.assert_called_once_with(c_l)
+ @mock.patch.object(ilo_common, '_get_certificate_file_list',
+ spec_set=True, autospec=True)
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
autospec=True)
- def test_clear_certificates(self, get_ilo_object_mock):
+ def test_clear_certificates(self, get_ilo_object_mock,
+ get_certs_mock):
ilo_mock_object = get_ilo_object_mock.return_value
c_l = ['/file/path/a', '/file/path/b']
+ get_certs_mock.return_value = ['/file/path/x']
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
ilo_common.clear_certificates(task, c_l)
- ilo_mock_object.remove_tls_certificate.assert_called_once_with(c_l)
+ ilo_mock_object.remove_tls_certificate.assert_called_once_with(
+ cert_file_list=c_l, excl_cert_file_list=['/file/path/x'])
+ get_certs_mock.assert_called_once_with(None)
+ @mock.patch.object(ilo_common, '_get_certificate_file_list',
+ spec_set=True, autospec=True)
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
autospec=True)
- def test_clear_certificates_default(self, get_ilo_object_mock):
+ def test_clear_certificates_default(self, get_ilo_object_mock,
+ get_certs_mock):
ilo_mock_object = get_ilo_object_mock.return_value
+ get_certs_mock.return_value = ['/file/path/x']
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
ilo_common.clear_certificates(task)
- ilo_mock_object.remove_tls_certificate.assert_called_once_with(None)
+ ilo_mock_object.remove_tls_certificate.assert_called_once_with(
+ cert_file_list=None, excl_cert_file_list=['/file/path/x'])
+ get_certs_mock.assert_called_once_with(None)
+ @mock.patch.object(ilo_common, '_get_certificate_file_list',
+ spec_set=True, autospec=True)
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
autospec=True)
- def test_clear_certificates_raises_ilo_error(self, get_ilo_object_mock):
+ def test_clear_certificates_raises_ilo_error(self, get_ilo_object_mock,
+ get_certs_mock):
ilo_mock_object = get_ilo_object_mock.return_value
c_l = ['/file/path/a', '/file/path/b']
+ get_certs_mock.return_value = ['/file/path/x']
exc = ilo_error.IloError('error')
ilo_mock_object.remove_tls_certificate.side_effect = exc
@@ -1407,7 +1423,9 @@ class IloCommonMethodsTestCase(BaseIloTest):
ilo_common.clear_certificates,
task, c_l)
- ilo_mock_object.remove_tls_certificate.assert_called_once_with(c_l)
+ ilo_mock_object.remove_tls_certificate.assert_called_once_with(
+ cert_file_list=c_l, excl_cert_file_list=['/file/path/x'])
+ get_certs_mock.assert_called_once_with(None)
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
autospec=True)
diff --git a/ironic/tests/unit/drivers/modules/ilo/test_management.py b/ironic/tests/unit/drivers/modules/ilo/test_management.py
index 80cb07c9f..e4d891c3d 100644
--- a/ironic/tests/unit/drivers/modules/ilo/test_management.py
+++ b/ironic/tests/unit/drivers/modules/ilo/test_management.py
@@ -1525,12 +1525,10 @@ class Ilo5ManagementTestCase(db_base.DbTestCase):
def setUp(self):
super(Ilo5ManagementTestCase, self).setUp()
self.driver = mock.Mock(management=ilo_management.Ilo5Management())
- self.clean_step = {'step': 'erase_devices',
- 'interface': 'management'}
+
n = {
'driver': 'ilo5',
'driver_info': INFO_DICT,
- 'clean_step': self.clean_step,
}
self.config(enabled_hardware_types=['ilo5'],
enabled_boot_interfaces=['ilo-virtual-media'],
@@ -1547,6 +1545,9 @@ class Ilo5ManagementTestCase(db_base.DbTestCase):
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
def test_erase_devices_hdd(self, mock_power, ilo_mock, build_agent_mock):
+ self.node.clean_step = {'interface': 'management',
+ 'step': 'erase_devices'}
+ self.node.save()
ilo_mock_object = ilo_mock.return_value
ilo_mock_object.get_available_disk_types.return_value = ['HDD']
build_agent_mock.return_value = []
@@ -1572,6 +1573,9 @@ class Ilo5ManagementTestCase(db_base.DbTestCase):
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
def test_erase_devices_ssd(self, mock_power, ilo_mock, build_agent_mock):
+ self.node.clean_step = {'interface': 'management',
+ 'step': 'erase_devices'}
+ self.node.save()
ilo_mock_object = ilo_mock.return_value
ilo_mock_object.get_available_disk_types.return_value = ['SSD']
build_agent_mock.return_value = []
@@ -1601,6 +1605,9 @@ class Ilo5ManagementTestCase(db_base.DbTestCase):
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
def test_erase_devices_ssd_when_hdd_done(self, mock_power, ilo_mock,
build_agent_mock):
+ self.node.clean_step = {'interface': 'management',
+ 'step': 'erase_devices'}
+ self.node.save()
build_agent_mock.return_value = []
ilo_mock_object = ilo_mock.return_value
ilo_mock_object.get_available_disk_types.return_value = ['HDD', 'SSD']
@@ -1632,6 +1639,9 @@ class Ilo5ManagementTestCase(db_base.DbTestCase):
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
def test_erase_devices_completed(self, ilo_mock, disk_status_mock,
log_mock):
+ self.node.clean_step = {'interface': 'management',
+ 'step': 'erase_devices'}
+ self.node.save()
ilo_mock_object = ilo_mock.return_value
ilo_mock_object.get_available_disk_types.return_value = ['HDD', 'SSD']
disk_status_mock.return_value = True
@@ -1655,6 +1665,9 @@ class Ilo5ManagementTestCase(db_base.DbTestCase):
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
def test_erase_devices_hdd_with_erase_pattern_zero(
self, mock_power, ilo_mock, build_agent_mock):
+ self.node.clean_step = {'interface': 'management',
+ 'step': 'erase_devices'}
+ self.node.save()
ilo_mock_object = ilo_mock.return_value
ilo_mock_object.get_available_disk_types.return_value = ['HDD']
build_agent_mock.return_value = []
@@ -1680,6 +1693,9 @@ class Ilo5ManagementTestCase(db_base.DbTestCase):
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
def test_erase_devices_when_no_drive_available(
self, ilo_mock, log_mock):
+ self.node.clean_step = {'interface': 'management',
+ 'step': 'erase_devices'}
+ self.node.save()
ilo_mock_object = ilo_mock.return_value
ilo_mock_object.get_available_disk_types.return_value = []
with task_manager.acquire(self.context, self.node.uuid,
@@ -1689,6 +1705,9 @@ class Ilo5ManagementTestCase(db_base.DbTestCase):
def test_erase_devices_hdd_with_invalid_format_erase_pattern(
self):
+ self.node.clean_step = {'interface': 'management',
+ 'step': 'erase_devices'}
+ self.node.save()
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
self.assertRaises(exception.InvalidParameterValue,
@@ -1697,6 +1716,9 @@ class Ilo5ManagementTestCase(db_base.DbTestCase):
def test_erase_devices_hdd_with_invalid_device_type_erase_pattern(
self):
+ self.node.clean_step = {'interface': 'management',
+ 'step': 'erase_devices'}
+ self.node.save()
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
self.assertRaises(exception.InvalidParameterValue,
@@ -1705,6 +1727,9 @@ class Ilo5ManagementTestCase(db_base.DbTestCase):
def test_erase_devices_hdd_with_invalid_erase_pattern(
self):
+ self.node.clean_step = {'interface': 'management',
+ 'step': 'erase_devices'}
+ self.node.save()
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
self.assertRaises(exception.InvalidParameterValue,
@@ -1716,6 +1741,9 @@ class Ilo5ManagementTestCase(db_base.DbTestCase):
autospec=True)
def test_erase_devices_hdd_ilo_error(self, clean_err_handler_mock,
ilo_mock):
+ self.node.clean_step = {'interface': 'management',
+ 'step': 'erase_devices'}
+ self.node.save()
ilo_mock_object = ilo_mock.return_value
ilo_mock_object.get_available_disk_types.return_value = ['HDD']
exc = ilo_error.IloError('error')
@@ -1776,3 +1804,131 @@ class Ilo5ManagementTestCase(db_base.DbTestCase):
errmsg=exc)
self.assertTrue(
ilo_mock_object.do_one_button_secure_erase.called)
+
+ @mock.patch.object(deploy_utils, 'get_async_step_return_state',
+ spec_set=True, autospec=True)
+ @mock.patch.object(deploy_utils, 'set_async_step_flags',
+ spec_set=True, autospec=True)
+ @mock.patch.object(deploy_utils, 'build_agent_options',
+ spec_set=True, autospec=True)
+ @mock.patch.object(manager_utils, 'node_power_action', autospec=True)
+ @mock.patch.object(ilo_boot.IloVirtualMediaBoot, 'prepare_ramdisk',
+ spec_set=True, autospec=True)
+ @mock.patch.object(ilo_common, 'clear_certificates', spec_set=True,
+ autospec=True)
+ def test_clear_ca_certificates(self, clear_certs_mock,
+ prepare_ramdisk_mock, node_power_mock,
+ build_agent_mock, set_async_mock,
+ get_async_ret_mock):
+ self.node.clean_step = {'interface': 'management',
+ 'step': 'clear_ca_certificates'}
+ self.node.save()
+ build_agent_mock.return_value = {'a': 'x', 'b': 'y'}
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+
+ certificate_files = ["/path/to/certsA", "/path/to/certsB"]
+
+ task.driver.management.clear_ca_certificates(
+ task, certificate_files)
+ clear_certs_mock.assert_called_once_with(
+ task, certificate_files)
+ self.assertTrue(task.node.driver_internal_info.get(
+ 'clear_ca_certs_flag'))
+ build_agent_mock.assert_called_once_with(task.node)
+ prepare_ramdisk_mock.assert_called_once_with(
+ mock.ANY, task, {'a': 'x', 'b': 'y'})
+ node_power_mock.assert_called_once_with(task, states.REBOOT)
+ set_async_mock.assert_called_once_with(
+ task.node, reboot=True, skip_current_step=False)
+ get_async_ret_mock.assert_called_once_with(task.node)
+
+ @mock.patch.object(deploy_utils, 'get_async_step_return_state',
+ spec_set=True, autospec=True)
+ @mock.patch.object(deploy_utils, 'set_async_step_flags',
+ spec_set=True, autospec=True)
+ @mock.patch.object(deploy_utils, 'build_agent_options',
+ spec_set=True, autospec=True)
+ @mock.patch.object(manager_utils, 'node_power_action', autospec=True)
+ @mock.patch.object(ilo_boot.IloVirtualMediaBoot, 'prepare_ramdisk',
+ spec_set=True, autospec=True)
+ @mock.patch.object(ilo_common, 'clear_certificates', spec_set=True,
+ autospec=True)
+ def test_clear_ca_certificates_clear_flag(
+ self, clear_certs_mock, prepare_ramdisk_mock, node_power_mock,
+ build_agent_mock, set_async_mock, get_async_ret_mock):
+ self.node.clean_step = {'interface': 'management',
+ 'step': 'clear_ca_certificates'}
+
+ self.node.save()
+ build_agent_mock.return_value = {'a': 'x', 'b': 'y'}
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+
+ certificate_files = ["/path/to/certsA", "/path/to/certsB"]
+ driver_internal_info = task.node.driver_internal_info
+ driver_internal_info['clear_ca_certs_flag'] = True
+ task.node.driver_internal_info = driver_internal_info
+
+ task.driver.management.clear_ca_certificates(
+ task, certificate_files)
+ clear_certs_mock.assert_not_called()
+
+ build_agent_mock.assert_not_called()
+ prepare_ramdisk_mock.assert_not_called()
+ node_power_mock.assert_not_called()
+ set_async_mock.assert_not_called()
+ get_async_ret_mock.assert_not_called()
+
+ @mock.patch.object(deploy_utils, 'get_async_step_return_state',
+ spec_set=True, autospec=True)
+ @mock.patch.object(deploy_utils, 'set_async_step_flags',
+ spec_set=True, autospec=True)
+ @mock.patch.object(deploy_utils, 'build_agent_options',
+ spec_set=True, autospec=True)
+ @mock.patch.object(manager_utils, 'node_power_action', autospec=True)
+ @mock.patch.object(ilo_boot.IloVirtualMediaBoot, 'prepare_ramdisk',
+ spec_set=True, autospec=True)
+ @mock.patch.object(ilo_common, 'clear_certificates', spec_set=True,
+ autospec=True)
+ def test_clear_ca_certificates_ilo_operation_not_supported(
+ self, clear_certs_mock, prepare_ramdisk_mock, node_power_mock,
+ build_agent_mock, set_async_mock, get_async_ret_mock):
+ self.node.clean_step = {'interface': 'management',
+ 'step': 'clear_ca_certificates'}
+ self.node.save()
+ exc = exception.IloOperationNotSupported('error')
+ clear_certs_mock.side_effect = exc
+
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+
+ certificate_files = ["/path/to/certsA", "/path/to/certsB"]
+
+ self.assertRaises(exception.NodeCleaningFailure,
+ task.driver.management.clear_ca_certificates,
+ task, certificate_files)
+ build_agent_mock.assert_not_called()
+ prepare_ramdisk_mock.assert_not_called()
+ node_power_mock.assert_not_called()
+ set_async_mock.assert_not_called()
+ get_async_ret_mock.assert_not_called()
+
+ @mock.patch.object(ilo_common, 'clear_certificates', spec_set=True,
+ autospec=True)
+ def test_clear_ca_certificates_ilo_operation_error(self, clear_certs_mock):
+ self.node.deploy_step = {'interface': 'management',
+ 'step': 'clear_ca_certificates'}
+ self.node.save()
+
+ exc = exception.IloOperationError('error')
+ clear_certs_mock.side_effect = exc
+
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+
+ certificate_files = ["/path/to/certsA", "/path/to/certsB"]
+
+ self.assertRaises(exception.InstanceDeployFailure,
+ task.driver.management.clear_ca_certificates,
+ task, certificate_files)
diff --git a/releasenotes/notes/clear_ca_cert-db41e7be9723c0fb.yaml b/releasenotes/notes/clear_ca_cert-db41e7be9723c0fb.yaml
new file mode 100644
index 000000000..4df3c382d
--- /dev/null
+++ b/releasenotes/notes/clear_ca_cert-db41e7be9723c0fb.yaml
@@ -0,0 +1,5 @@
+---
+features:
+ - |
+ Manual clean step ``clear_ca_certificates`` is added to remove the
+ CA certificates from iLO.