Skip to content

Commit 92717d3

Browse files
Last tests and validation for complex filter dsl
Signed-off-by: Stew Francis <[email protected]>
1 parent 4afa8d2 commit 92717d3

File tree

4 files changed

+213
-94
lines changed

4 files changed

+213
-94
lines changed

build.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ pip install -r requirements.txt
5959
echo "/* -------------------------------------------------------------------------- */"
6060
echo "/* Integration tests Python 2.7 */"
6161
echo "/* -------------------------------------------------------------------------- */"
62-
(set -x; ansible-test integration --python 2.7)
62+
(set -x; ansible-test integration cics_cmci --python 2.7)
6363
deactivate
6464

6565
source "$CMCI_PYTHON_38/bin/activate"

plugins/doc_fragments/cmci.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,8 @@ class ModuleDocFragment(object):
202202
These operators are accepted: C(<) or C(LT) (less than), C(<=) or
203203
C(LE) (less than or equal to), C(=) or C(EQ) (equal to), C(>) or
204204
C(GT) (greater than), C(>=) or C(GE) (greater than or equal to),
205-
C(==) or C(IS) (is), C(¬=), C(!=), or C(NE) (not equal to).
205+
C(==) or C(IS) (is), C(¬=), C(!=), or C(NE) (not equal to). If
206+
not supplied when 'attribute' is used, C(EQ) will be assumed.
206207
type: str
207208
required: false
208209
choices:
@@ -221,7 +222,6 @@ class ModuleDocFragment(object):
221222
- LE
222223
- NE
223224
- IS
224-
default: EQ
225225
value:
226226
description:
227227
- The value by which you are to filter the resource attributes.

plugins/module_utils/cmci.py

Lines changed: 66 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,12 @@ def parameters_argument(name): # type: (str) -> Dict[str, Any]
7171
OPERATORS = ['<', '<=', '=', '>', '>=', '¬=', '==', '!=', 'EQ', 'NE', 'LT',
7272
'LE', 'GE', 'GT', 'IS']
7373

74+
ATTRIBUTE = 'attribute'
75+
AND = 'and'
76+
OR = 'or'
77+
OPERATOR = 'operator'
78+
VALUE = 'value'
79+
7480
RESOURCES_ARGUMENT = {
7581
RESOURCES: {
7682
'type': 'dict',
@@ -84,37 +90,37 @@ def parameters_argument(name): # type: (str) -> Dict[str, Any]
8490
'type': 'dict',
8591
'required': False,
8692
'required_together': [
87-
('attribute', 'value')
93+
(ATTRIBUTE, VALUE)
8894
],
8995
'required_one_of': [
90-
('attribute', 'and', 'or')
96+
(ATTRIBUTE, AND, OR)
9197
],
9298
'required_by': {
93-
'operator': 'attribute'
99+
OPERATOR: ATTRIBUTE
94100
},
95101
'mutually_exclusive': [
96-
('attribute', 'and', 'or')
102+
(ATTRIBUTE, AND, OR)
97103
],
98104
'options': {
99-
'attribute': {
105+
ATTRIBUTE: {
100106
'type': 'str',
101107
'required': False
102108
},
103-
'operator': {
109+
OPERATOR: {
104110
'type': 'str',
105111
'required': False,
106112
'choices': OPERATORS
107113
},
108-
'value': {
114+
VALUE: {
109115
'type': 'str',
110116
'required': False
111117
},
112-
'and': {
118+
AND: {
113119
'type': 'list',
114120
'elements': 'dict',
115121
'required': False
116122
},
117-
'or': {
123+
OR: {
118124
'type': 'list',
119125
'elements': 'dict',
120126
'required': False
@@ -408,32 +414,32 @@ def get_resources_request_params(self): # type: () -> Dict[str, str]
408414
if not request_params:
409415
request_params = OrderedDict({})
410416

411-
and_item = complex_filter['and']
412-
or_item = complex_filter['or']
413-
attribute_item = complex_filter['attribute']
417+
and_item = complex_filter[AND]
418+
or_item = complex_filter[OR]
419+
attribute_item = complex_filter[ATTRIBUTE]
414420

415421
if and_item is not None:
416422
complex_filter_string = self._get_filter(
417423
and_item,
418424
complex_filter_string,
419425
' AND ',
420-
' -> and'
426+
' -> ' + AND
421427
)
422428

423429
if or_item is not None:
424430
complex_filter_string = self._get_filter(
425431
or_item,
426432
complex_filter_string,
427433
' OR ',
428-
' -> or'
434+
' -> ' + OR
429435
)
430436

431437
if attribute_item is not None:
432438
operator = self._convert_filter_operator(
433-
complex_filter['operator'],
439+
complex_filter[OPERATOR],
434440
""
435441
)
436-
value = complex_filter['value']
442+
value = complex_filter[VALUE]
437443

438444
if operator == '¬=':
439445
# Provides a filter string in the format NOT(FOO=='BAR')
@@ -597,12 +603,7 @@ def _get_filter(self, list_of_filters, complex_filter_string, joiner, path):
597603
"resources -> complex_filter%s" % (type(i), path)
598604
)
599605

600-
and_item = i.get('and')
601-
or_item = i.get('or')
602-
attribute = i.get('attribute')
603-
op = i.get('operator')
604-
605-
valid_keys = ['and', 'attribute', 'operator', 'or', 'value']
606+
valid_keys = [AND, ATTRIBUTE, OPERATOR, OR, VALUE]
606607
diff = set(i.keys()) - set(valid_keys)
607608
if len(diff) != 0:
608609
self._fail(
@@ -612,25 +613,41 @@ def _get_filter(self, list_of_filters, complex_filter_string, joiner, path):
612613
% (", ".join(diff), path, ", ".join(valid_keys))
613614
)
614615

616+
# Validate required_one_of
617+
and_item = i.get(AND)
618+
or_item = i.get(OR)
619+
attribute = i.get(ATTRIBUTE)
620+
621+
if not and_item and not or_item and not attribute:
622+
self._fail(
623+
"one of the following is required: %s found"
624+
" in resources -> complex_filter%s"
625+
% (", ".join([ATTRIBUTE, AND, OR]), path)
626+
)
627+
628+
# Validate required_by
629+
op = i.get(OPERATOR)
630+
615631
if op and not attribute:
616632
self._fail(
617-
"missing parameter(s) required by 'operator': attribute"
633+
"missing parameter(s) required by '%s': %s"
634+
% (OPERATOR, ATTRIBUTE)
618635
)
619636

620637
# Validate mutually exclusive parameters
621638
if (and_item and or_item) or (and_item and attribute) or \
622639
(or_item and attribute):
623640
self._fail(
624-
'parameters are mutually exclusive: attribute|and|or found '
625-
'in resources -> complex_filter%s' % path
641+
'parameters are mutually exclusive: %s|%s|%s found in '
642+
'resources -> complex_filter%s' % (ATTRIBUTE, AND, OR, path)
626643
)
627644

628645
if and_item is not None:
629646
and_filter_string = self._get_filter(
630647
and_item,
631648
'',
632649
' AND ',
633-
path + ' -> and'
650+
'%s -> %s' % (path, AND)
634651
)
635652
complex_filter_string = _append_filter_string(
636653
complex_filter_string,
@@ -641,20 +658,39 @@ def _get_filter(self, list_of_filters, complex_filter_string, joiner, path):
641658
or_item,
642659
'',
643660
' OR ',
644-
path + ' -> or'
661+
'%s -> %s' % (path, OR)
645662
)
646663
complex_filter_string = _append_filter_string(
647664
complex_filter_string,
648665
or_filter_string, joiner
649666
)
650667
if attribute is not None:
651668
operator = self._convert_filter_operator(op, path)
652-
value = i.get('value')
669+
670+
# Validate attribute type
671+
if not isinstance(attribute, str):
672+
self._fail(
673+
"%s must be of type str, was: %s found in "
674+
"resources -> complex_filter%s"
675+
% (ATTRIBUTE, type(attribute), path)
676+
)
677+
678+
value = i.get(VALUE)
653679

654680
if value is None:
655681
self._fail(
656-
'parameters are required together: attribute, value '
657-
'found in resources -> complex_filter%s' % path)
682+
'parameters are required together: %s, %s found in '
683+
'resources -> complex_filter%s'
684+
% (ATTRIBUTE, VALUE, path)
685+
)
686+
687+
# Validate value type
688+
if not isinstance(value, str):
689+
self._fail(
690+
"%s must be of type str, was: %s found in "
691+
"resources -> complex_filter%s"
692+
% (VALUE, type(value), path)
693+
)
658694

659695
if operator == '¬=':
660696
# Provides a filter string in the format NOT(FOO=='BAR')

0 commit comments

Comments
 (0)