summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Tantsur <divius.inside@gmail.com>2018-09-17 15:20:28 +0200
committerDmitry Tantsur <divius.inside@gmail.com>2018-09-18 10:13:48 +0200
commit0a26a6677d6934168318d2120204f72fdb3eb37c (patch)
tree22352ae293b51458bbf14f042222aaa34dc7b216
parent34b150340cbb1650e7195b4496a9c74150e68db8 (diff)
Add introspection rules actions to add/remove traits on nodes
Otherwise it's not possible to modify them, since they're not updated via the regular node updating mechanism. Change-Id: I338015ff9dafe07f4e70a23ddcf6cd488eda9907 Story: #2003788 Task: #26496
Notes
Notes (review): Code-Review+2: Kaifeng Wang <kaifeng.w@gmail.com> Code-Review+2: Mark Goddard <mark@stackhpc.com> Workflow+1: Mark Goddard <mark@stackhpc.com> Verified+2: Zuul Submitted-by: Zuul Submitted-at: Tue, 16 Oct 2018 06:54:27 +0000 Reviewed-on: https://review.openstack.org/603126 Project: openstack/ironic-inspector Branch: refs/heads/master
-rw-r--r--doc/source/user/usage.rst6
-rw-r--r--ironic_inspector/node_cache.py22
-rw-r--r--ironic_inspector/plugins/rules.py14
-rw-r--r--ironic_inspector/test/unit/test_plugins_rules.py38
-rw-r--r--releasenotes/notes/trait-actions-eec05cbb6a944619.yaml5
-rw-r--r--setup.cfg2
6 files changed, 87 insertions, 0 deletions
diff --git a/doc/source/user/usage.rst b/doc/source/user/usage.rst
index efae0b9..14c78a0 100644
--- a/doc/source/user/usage.rst
+++ b/doc/source/user/usage.rst
@@ -123,6 +123,12 @@ Default available actions include:
123 value as a list and appends value to it. If optional ``unique`` parameter is 123 value as a list and appends value to it. If optional ``unique`` parameter is
124 set to ``True``, nothing will be added if given value is already in a list. 124 set to ``True``, nothing will be added if given value is already in a list.
125 125
126* ``add-trait`` adds a trait to an Ironic node. Requires a ``name`` field
127 with the name of the trait to add.
128
129* ``remove-trait`` removes a trait from an Ironic node. Requires a ``name``
130 field with the name of the trait to remove.
131
126Starting from Mitaka release, ``value`` field in actions supports fetching data 132Starting from Mitaka release, ``value`` field in actions supports fetching data
127from introspection, using `python string formatting notation 133from introspection, using `python string formatting notation
128<https://docs.python.org/2/library/string.html#formatspec>`_:: 134<https://docs.python.org/2/library/string.html#formatspec>`_::
diff --git a/ironic_inspector/node_cache.py b/ironic_inspector/node_cache.py
index 3e9ca3e..9365222 100644
--- a/ironic_inspector/node_cache.py
+++ b/ironic_inspector/node_cache.py
@@ -470,6 +470,28 @@ class NodeInfo(object):
470 ironic=ironic, 470 ironic=ironic,
471 capabilities=ir_utils.dict_to_capabilities(existing)) 471 capabilities=ir_utils.dict_to_capabilities(existing))
472 472
473 def add_trait(self, trait, ironic=None):
474 """Add a trait to the node.
475
476 :param trait: trait to add
477 :param ironic: Ironic client to use instead of self.ironic
478 """
479 ironic = ironic or self.ironic
480 ironic.node.add_trait(self.uuid, trait)
481
482 def remove_trait(self, trait, ironic=None):
483 """Remove a trait from the node.
484
485 :param trait: trait to add
486 :param ironic: Ironic client to use instead of self.ironic
487 """
488 ironic = ironic or self.ironic
489 try:
490 ironic.node.remove_trait(self.uuid, trait)
491 except exceptions.NotFound:
492 LOG.debug('Trait %s is not set, cannot remove', trait,
493 node_info=self)
494
473 def delete_port(self, port, ironic=None): 495 def delete_port(self, port, ironic=None):
474 """Delete port. 496 """Delete port.
475 497
diff --git a/ironic_inspector/plugins/rules.py b/ironic_inspector/plugins/rules.py
index adc1942..dd04a18 100644
--- a/ironic_inspector/plugins/rules.py
+++ b/ironic_inspector/plugins/rules.py
@@ -151,3 +151,17 @@ class ExtendAttributeAction(base.RuleActionPlugin):
151 return values 151 return values
152 152
153 node_info.replace_field(params['path'], _replace, default=[]) 153 node_info.replace_field(params['path'], _replace, default=[])
154
155
156class AddTraitAction(base.RuleActionPlugin):
157 REQUIRED_PARAMS = {'name'}
158
159 def apply(self, node_info, params, **kwargs):
160 node_info.add_trait(params['name'])
161
162
163class RemoveTraitAction(base.RuleActionPlugin):
164 REQUIRED_PARAMS = {'name'}
165
166 def apply(self, node_info, params, **kwargs):
167 node_info.remove_trait(params['name'])
diff --git a/ironic_inspector/test/unit/test_plugins_rules.py b/ironic_inspector/test/unit/test_plugins_rules.py
index cfdbbb5..b3fd80a 100644
--- a/ironic_inspector/test/unit/test_plugins_rules.py
+++ b/ironic_inspector/test/unit/test_plugins_rules.py
@@ -14,6 +14,7 @@
14 14
15"""Tests for introspection rules plugins.""" 15"""Tests for introspection rules plugins."""
16 16
17from ironicclient import exceptions
17import mock 18import mock
18 19
19from ironic_inspector.common import ironic as ir_utils 20from ironic_inspector.common import ironic as ir_utils
@@ -222,3 +223,40 @@ class TestExtendAttributeAction(test_base.NodeTest):
222 self.node.extra['value'] = [42] 223 self.node.extra['value'] = [42]
223 self.act.apply(self.node_info, params) 224 self.act.apply(self.node_info, params)
224 self.assertFalse(mock_patch.called) 225 self.assertFalse(mock_patch.called)
226
227
228@mock.patch('ironic_inspector.common.ironic.get_client', autospec=True)
229class TestAddTraitAction(test_base.NodeTest):
230 act = rules_plugins.AddTraitAction()
231 params = {'name': 'CUSTOM_FOO'}
232
233 def test_validate(self, mock_cli):
234 self.act.validate(self.params)
235 self.assertRaises(ValueError, self.act.validate, {'value': 42})
236
237 def test_add(self, mock_cli):
238 self.act.apply(self.node_info, self.params)
239 mock_cli.return_value.node.add_trait.assert_called_once_with(
240 self.uuid, 'CUSTOM_FOO')
241
242
243@mock.patch('ironic_inspector.common.ironic.get_client', autospec=True)
244class TestRemoveTraitAction(test_base.NodeTest):
245 act = rules_plugins.RemoveTraitAction()
246 params = {'name': 'CUSTOM_FOO'}
247
248 def test_validate(self, mock_cli):
249 self.act.validate(self.params)
250 self.assertRaises(ValueError, self.act.validate, {'value': 42})
251
252 def test_remove(self, mock_cli):
253 self.act.apply(self.node_info, self.params)
254 mock_cli.return_value.node.remove_trait.assert_called_once_with(
255 self.uuid, 'CUSTOM_FOO')
256
257 def test_remove_not_found(self, mock_cli):
258 mock_cli.return_value.node.remove_trait.side_effect = (
259 exceptions.NotFound('trait not found'))
260 self.act.apply(self.node_info, self.params)
261 mock_cli.return_value.node.remove_trait.assert_called_once_with(
262 self.uuid, 'CUSTOM_FOO')
diff --git a/releasenotes/notes/trait-actions-eec05cbb6a944619.yaml b/releasenotes/notes/trait-actions-eec05cbb6a944619.yaml
new file mode 100644
index 0000000..a68a729
--- /dev/null
+++ b/releasenotes/notes/trait-actions-eec05cbb6a944619.yaml
@@ -0,0 +1,5 @@
1---
2features:
3 - |
4 Adds new introspection rules actions to add or remove traits on nodes:
5 ``add-trait`` and ``remove-trait``.
diff --git a/setup.cfg b/setup.cfg
index 2edbd69..2c84cc1 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -60,6 +60,8 @@ ironic_inspector.rules.actions =
60 set-attribute = ironic_inspector.plugins.rules:SetAttributeAction 60 set-attribute = ironic_inspector.plugins.rules:SetAttributeAction
61 set-capability = ironic_inspector.plugins.rules:SetCapabilityAction 61 set-capability = ironic_inspector.plugins.rules:SetCapabilityAction
62 extend-attribute = ironic_inspector.plugins.rules:ExtendAttributeAction 62 extend-attribute = ironic_inspector.plugins.rules:ExtendAttributeAction
63 add-trait = ironic_inspector.plugins.rules:AddTraitAction
64 remove-trait = ironic_inspector.plugins.rules:RemoveTraitAction
63ironic_inspector.pxe_filter = 65ironic_inspector.pxe_filter =
64 dnsmasq = ironic_inspector.pxe_filter.dnsmasq:DnsmasqFilter 66 dnsmasq = ironic_inspector.pxe_filter.dnsmasq:DnsmasqFilter
65 iptables = ironic_inspector.pxe_filter.iptables:IptablesFilter 67 iptables = ironic_inspector.pxe_filter.iptables:IptablesFilter