diff --git a/ironic/api/controllers/v1/node.py b/ironic/api/controllers/v1/node.py index 89ce43ac72..664016b9c3 100644 --- a/ironic/api/controllers/v1/node.py +++ b/ironic/api/controllers/v1/node.py @@ -357,7 +357,7 @@ class NodeStatesController(rest.RestController): :param node_ident: the UUID or logical name of a node. :param target_raid_config: Desired target RAID configuration of - the node + the node. It may be an empty dictionary as well. :raises: UnsupportedDriverExtension, if the node's driver doesn't support RAID configuration. :raises: InvalidParameterValue, if validation of target raid config diff --git a/ironic/conductor/manager.py b/ironic/conductor/manager.py index e84ada566b..676973eae7 100644 --- a/ironic/conductor/manager.py +++ b/ironic/conductor/manager.py @@ -2086,7 +2086,7 @@ class ConductorManager(periodic_task.PeriodicTasks): :param context: request context. :param node_id: node id or uuid. :param target_raid_config: Dictionary containing the target RAID - configuration. + configuration. It may be an empty dictionary as well. :raises: UnsupportedDriverExtension, if the node's driver doesn't support RAID configuration. :raises: InvalidParameterValue, if validation of target raid config @@ -2106,7 +2106,10 @@ class ConductorManager(periodic_task.PeriodicTasks): if not getattr(task.driver, 'raid', None): raise exception.UnsupportedDriverExtension( driver=task.driver, extension='raid') - task.driver.raid.validate_raid_config(task, target_raid_config) + # Operator may try to unset node.target_raid_config. So, try to + # validate only if it is not empty. + if target_raid_config: + task.driver.raid.validate_raid_config(task, target_raid_config) node.target_raid_config = target_raid_config node.save() diff --git a/ironic/conductor/rpcapi.py b/ironic/conductor/rpcapi.py index 8cb2ef205d..29fc99c262 100644 --- a/ironic/conductor/rpcapi.py +++ b/ironic/conductor/rpcapi.py @@ -556,7 +556,7 @@ class ConductorAPI(object): :param context: request context. :param node_id: node id or uuid. :param target_raid_config: Dictionary containing the target RAID - configuration. + configuration. It may be an empty dictionary as well. :param topic: RPC topic. Defaults to self.topic. :raises: UnsupportedDriverExtension if the node's driver doesn't support RAID configuration. diff --git a/ironic/tests/conductor/test_manager.py b/ironic/tests/conductor/test_manager.py index d87e68cde1..e774be71d2 100644 --- a/ironic/tests/conductor/test_manager.py +++ b/ironic/tests/conductor/test_manager.py @@ -2886,6 +2886,15 @@ class RaidTestCases(_ServiceSetUpMixin, tests_db_base.DbTestCase): self.node.refresh() self.assertEqual(raid_config, self.node.target_raid_config) + def test_set_target_raid_config_empty(self): + self.node.target_raid_config = {'foo': 'bar'} + self.node.save() + raid_config = {} + self.service.set_target_raid_config( + self.context, self.node.uuid, raid_config) + self.node.refresh() + self.assertEqual({}, self.node.target_raid_config) + def test_set_target_raid_config_iface_not_supported(self): raid_config = {'logical_disks': [{'size_gb': 100, 'raid_level': '1'}]} self.driver.raid = None