Add new condition: is-empty

Now, if operators want to check some attribute isn't specified,
they should use 'eq' condition with None, '', etc values:

    {'op': 'eq', 'field': 'inventory.bmc_addres', 'value': ''}

It would be useful to have condition plugin witch verify this case,
'is-empty' checks that field is empty string, list, dict or None value:

    {'op': 'is-empty', 'field': 'inventory.bmc_addres'}

Change-Id: I6596a067e769530092c3db34405e0f0917d2f052
This commit is contained in:
Anton Arefiev 2016-02-11 10:13:45 +02:00
parent a181378acf
commit 061d839a26
6 changed files with 39 additions and 2 deletions

View File

@ -69,7 +69,10 @@ A condition is represented by an object with fields:
* ``matches`` - requires a full match against a given regular expression; * ``matches`` - requires a full match against a given regular expression;
* ``contains`` - requires a value to contain a given regular expression. * ``contains`` - requires a value to contain a given regular expression;
* ``is-empty`` - checks that field is an empty string, list, dict or
None value.
``field`` a `JSON path <http://goessner.net/articles/JsonPath/>`_ to the field ``field`` a `JSON path <http://goessner.net/articles/JsonPath/>`_ to the field
in the introspection data to use in comparison. in the introspection data to use in comparison.

View File

@ -67,6 +67,13 @@ class NeCondition(SimpleCondition):
op = operator.ne op = operator.ne
class EmptyCondition(base.RuleConditionPlugin):
REQUIRED_PARAMS = set()
def check(self, node_info, field, params, **kwargs):
return field in ('', None, [], {})
class NetCondition(base.RuleConditionPlugin): class NetCondition(base.RuleConditionPlugin):
def validate(self, params, **kwargs): def validate(self, params, **kwargs):
super(NetCondition, self).validate(params, **kwargs) super(NetCondition, self).validate(params, **kwargs)

View File

@ -94,7 +94,8 @@ class Base(base.NodeTest):
'bmc_address': self.bmc_address 'bmc_address': self.bmc_address
}, },
'root_disk': {'name': '/dev/sda', 'model': 'Big Data Disk', 'root_disk': {'name': '/dev/sda', 'model': 'Big Data Disk',
'size': 1000 * units.Gi}, 'size': 1000 * units.Gi,
'wwn': None},
} }
self.data_old_ramdisk = { self.data_old_ramdisk = {
'cpus': 4, 'cpus': 4,
@ -308,6 +309,7 @@ class Test(Base):
{'field': 'local_gb', 'op': 'lt', 'value': 1000}, {'field': 'local_gb', 'op': 'lt', 'value': 1000},
{'field': 'local_gb', 'op': 'matches', 'value': '[0-9]+'}, {'field': 'local_gb', 'op': 'matches', 'value': '[0-9]+'},
{'field': 'cpu_arch', 'op': 'contains', 'value': '[0-9]+'}, {'field': 'cpu_arch', 'op': 'contains', 'value': '[0-9]+'},
{'field': 'root_disk.wwn', 'op': 'is-empty'}
], ],
'actions': [ 'actions': [
{'action': 'set-attribute', 'path': '/extra/foo', {'action': 'set-attribute', 'path': '/extra/foo',

View File

@ -115,6 +115,26 @@ class TestNetCondition(test_base.BaseTest):
{'value': '192.0.2.1/24'})) {'value': '192.0.2.1/24'}))
class TestEmptyCondition(test_base.BaseTest):
cond = rules_plugins.EmptyCondition()
def test_check_none(self):
self.assertTrue(self.cond.check(None, None, {}))
self.assertFalse(self.cond.check(None, 0, {}))
def test_check_empty_string(self):
self.assertTrue(self.cond.check(None, '', {}))
self.assertFalse(self.cond.check(None, '16', {}))
def test_check_empty_list(self):
self.assertTrue(self.cond.check(None, [], {}))
self.assertFalse(self.cond.check(None, ['16'], {}))
def test_check_empty_dict(self):
self.assertTrue(self.cond.check(None, {}, {}))
self.assertFalse(self.cond.check(None, {'test': '16'}, {}))
class TestFailAction(test_base.BaseTest): class TestFailAction(test_base.BaseTest):
act = rules_plugins.FailAction() act = rules_plugins.FailAction()

View File

@ -0,0 +1,4 @@
---
features:
- Added new condition plugin "is-empty", which allows to match
empty string, list, dictionary or None.

View File

@ -45,6 +45,7 @@ ironic_inspector.rules.conditions =
in-net = ironic_inspector.plugins.rules:NetCondition in-net = ironic_inspector.plugins.rules:NetCondition
matches = ironic_inspector.plugins.rules:MatchesCondition matches = ironic_inspector.plugins.rules:MatchesCondition
contains = ironic_inspector.plugins.rules:ContainsCondition contains = ironic_inspector.plugins.rules:ContainsCondition
is-empty = ironic_inspector.plugins.rules:EmptyCondition
ironic_inspector.rules.actions = ironic_inspector.rules.actions =
example = ironic_inspector.plugins.example:ExampleRuleAction example = ironic_inspector.plugins.example:ExampleRuleAction
fail = ironic_inspector.plugins.rules:FailAction fail = ironic_inspector.plugins.rules:FailAction