summaryrefslogtreecommitdiff
path: root/ironic
diff options
context:
space:
mode:
authorArne Wiebalck <arne.wiebalck@cern.ch>2019-02-21 17:25:54 +0000
committerArne Wiebalck <arne.wiebalck@cern.ch>2019-02-27 20:50:17 +0000
commit885ddb4362c347e4963fe36521e59dcfd9dad708 (patch)
treea412099a967e99ba5b95d1f3c282f3cd2899aa1a /ironic
parentccf2bb1ea194408eb34586ee469cf37c296e6fa4 (diff)
downloadironic-885ddb4362c347e4963fe36521e59dcfd9dad708.tar.gz
Add option to protect available nodes from accidental deletion
Ironic allows to delete nodes which are in state 'available'. As bringing nodes into 'available' comes at an operational cost (i.e. enroll, inspect, clean, ...), this patch proposes a new option 'allow_deleting_available_nodes' to support the protection of available nodes against accidental removal. Change-Id: I08d31b5ddbad626811c971389e634a450aeaf066 Story: #2005060 Task: #29604
Diffstat (limited to 'ironic')
-rw-r--r--ironic/common/states.py2
-rw-r--r--ironic/conductor/manager.py7
-rw-r--r--ironic/conf/conductor.py4
-rw-r--r--ironic/releasenotes/notes/add-protection-for-available-nodes-25f163d69782ef63.yaml12
-rw-r--r--ironic/tests/unit/conductor/test_manager.py16
5 files changed, 38 insertions, 3 deletions
diff --git a/ironic/common/states.py b/ironic/common/states.py
index e09cc9bcb..3f550d6bc 100644
--- a/ironic/common/states.py
+++ b/ironic/common/states.py
@@ -223,7 +223,7 @@ UPDATE_ALLOWED_STATES = (DEPLOYFAIL, INSPECTING, INSPECTFAIL, INSPECTWAIT,
UNRESCUEFAIL)
"""Transitional states in which we allow updating a node."""
-DELETE_ALLOWED_STATES = (AVAILABLE, MANAGEABLE, ENROLL, ADOPTFAIL)
+DELETE_ALLOWED_STATES = (MANAGEABLE, ENROLL, ADOPTFAIL)
"""States in which node deletion is allowed."""
STABLE_STATES = (ENROLL, MANAGEABLE, AVAILABLE, ACTIVE, ERROR, RESCUE)
diff --git a/ironic/conductor/manager.py b/ironic/conductor/manager.py
index 4b7b1524c..47fd71b53 100644
--- a/ironic/conductor/manager.py
+++ b/ironic/conductor/manager.py
@@ -2267,15 +2267,18 @@ class ConductorManager(base_manager.BaseConductorManager):
# CLEANFAIL -> MANAGEABLE
# INSPECTIONFAIL -> MANAGEABLE
# DEPLOYFAIL -> DELETING
+ delete_allowed_states = states.DELETE_ALLOWED_STATES
+ if CONF.conductor.allow_deleting_available_nodes:
+ delete_allowed_states += (states.AVAILABLE,)
if (not node.maintenance
and node.provision_state
- not in states.DELETE_ALLOWED_STATES):
+ not in delete_allowed_states):
msg = (_('Can not delete node "%(node)s" while it is in '
'provision state "%(state)s". Valid provision states '
'to perform deletion are: "%(valid_states)s", '
'or set the node into maintenance mode') %
{'node': node.uuid, 'state': node.provision_state,
- 'valid_states': states.DELETE_ALLOWED_STATES})
+ 'valid_states': delete_allowed_states})
raise exception.InvalidState(msg)
if node.console_enabled:
notify_utils.emit_console_notification(
diff --git a/ironic/conf/conductor.py b/ironic/conf/conductor.py
index 965e5c141..4984073da 100644
--- a/ironic/conf/conductor.py
+++ b/ironic/conf/conductor.py
@@ -194,6 +194,10 @@ opts = [
'255 characters and is case insensitive. This '
'conductor will only manage nodes with a matching '
'"conductor_group" field set on the node.')),
+ cfg.BoolOpt('allow_deleting_available_nodes',
+ default=True,
+ help=_('Allow deleting nodes which are in state '
+ '\'available\'. Defaults to True.')),
]
diff --git a/ironic/releasenotes/notes/add-protection-for-available-nodes-25f163d69782ef63.yaml b/ironic/releasenotes/notes/add-protection-for-available-nodes-25f163d69782ef63.yaml
new file mode 100644
index 000000000..7b38229ac
--- /dev/null
+++ b/ironic/releasenotes/notes/add-protection-for-available-nodes-25f163d69782ef63.yaml
@@ -0,0 +1,12 @@
+---
+features:
+ - Adds option 'allow_deleting_available_nodes' to control whether nodes in
+ state 'available' should be deletable (which is and stays the default).
+ Setting this option to False will remove 'available' from the list of
+ states in which nodes can be deleted from ironic. It hence provides
+ protection against accidental removal of nodes which are ready for
+ allocation (and is meant as a safeguard for the operational effort to
+ bring nodes into this state). For backwards compatibility reasons, the
+ default value for this option is True. The other states in which nodes
+ can be deleted from ironic ('manageable', 'enroll', and 'adoptfail')
+ remain unchanged.
diff --git a/ironic/tests/unit/conductor/test_manager.py b/ironic/tests/unit/conductor/test_manager.py
index 836678f8b..d4e4c2c4f 100644
--- a/ironic/tests/unit/conductor/test_manager.py
+++ b/ironic/tests/unit/conductor/test_manager.py
@@ -5068,6 +5068,22 @@ class DestroyNodeTestCase(mgr_utils.ServiceSetUpMixin, db_base.DbTestCase):
node.refresh()
self.assertIsNone(node.reservation)
+ def test_destroy_node_protected_provision_state_available(self):
+ CONF.set_override('allow_deleting_available_nodes',
+ False, group='conductor')
+ self._start_service()
+ node = obj_utils.create_test_node(self.context,
+ provision_state=states.AVAILABLE)
+
+ exc = self.assertRaises(messaging.rpc.ExpectedException,
+ self.service.destroy_node,
+ self.context, node.uuid)
+ # Compare true exception hidden by @messaging.expected_exceptions
+ self.assertEqual(exception.InvalidState, exc.exc_info[0])
+ # Verify reservation was released.
+ node.refresh()
+ self.assertIsNone(node.reservation)
+
def test_destroy_node_protected(self):
self._start_service()
node = obj_utils.create_test_node(self.context,