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
This commit is contained in:
parent
ccf2bb1ea1
commit
885ddb4362
@ -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)
|
||||
|
@ -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(
|
||||
|
@ -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.')),
|
||||
]
|
||||
|
||||
|
||||
|
@ -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.
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user