diff options
author | Arne Wiebalck <arne.wiebalck@cern.ch> | 2019-02-21 17:25:54 +0000 |
---|---|---|
committer | Arne Wiebalck <arne.wiebalck@cern.ch> | 2019-02-27 20:50:17 +0000 |
commit | 885ddb4362c347e4963fe36521e59dcfd9dad708 (patch) | |
tree | a412099a967e99ba5b95d1f3c282f3cd2899aa1a /ironic | |
parent | ccf2bb1ea194408eb34586ee469cf37c296e6fa4 (diff) | |
download | ironic-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.py | 2 | ||||
-rw-r--r-- | ironic/conductor/manager.py | 7 | ||||
-rw-r--r-- | ironic/conf/conductor.py | 4 | ||||
-rw-r--r-- | ironic/releasenotes/notes/add-protection-for-available-nodes-25f163d69782ef63.yaml | 12 | ||||
-rw-r--r-- | ironic/tests/unit/conductor/test_manager.py | 16 |
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, |