diff --git a/plugins/doc_fragments/api.py b/plugins/doc_fragments/api.py index c10d844f..b0ad9799 100644 --- a/plugins/doc_fragments/api.py +++ b/plugins/doc_fragments/api.py @@ -107,6 +107,11 @@ class ModuleDocFragment(object): - The field whose values to restrict. required: true type: str + match_disabled: + description: + - Whether disabled or not provided values should match. + type: bool + default: false values: description: - The values of the field to limit to. @@ -115,8 +120,6 @@ class ModuleDocFragment(object): and librouteros converts the value returned by the API to the integer V(0), then this will not match. If you are not sure, better include both variants: both the string and the integer. - - Use V(none) for disabled values. - - Either O(restrict[].values) or O(restrict[].regex), but not both, must be specified. type: list elements: raw regex: @@ -124,6 +127,12 @@ class ModuleDocFragment(object): - A regular expression matching values of the field to limit to. - Note that all values will be converted to strings before matching. - It is not possible to match disabled values with regular expressions. - - Either O(restrict[].values) or O(restrict[].regex), but not both, must be specified. + Set O(restrict[].match_disabled=true) if you also want to match disabled values. type: str + invert: + description: + - Invert the condition. This affects O(restrict[].match_disabled), O(restrict[].values), + and O(restrict[].regex). + type: bool + default: false ''' diff --git a/plugins/module_utils/_api_helper.py b/plugins/module_utils/_api_helper.py index 505397fb..d7e2ab88 100644 --- a/plugins/module_utils/_api_helper.py +++ b/plugins/module_utils/_api_helper.py @@ -27,10 +27,14 @@ def validate_and_prepare_restrict(module, path_info): if f is None: module.fail_json(msg='restrict: the field "{0}" does not exist for this path'.format(field)) - new_rule = dict(field=field) + new_rule = dict( + field=field, + match_disabled=rule['match_disabled'], + invert==rule['invert'], + ) if rule['values'] is not None: new_rule['values'] = rule['values'] - elif rule['regex'] is not None: + if rule['regex'] is not None: regex = rule['regex'] try: new_rule['regex'] = re.compile(regex) @@ -41,6 +45,25 @@ def validate_and_prepare_restrict(module, path_info): return restrict_data +def _value_to_str(value): + if value is None: + return None + value_str = to_text(value) + if isinstance(value, bool): + value_str = value_str.lower() + return value_str + + +def _test_rule_except_invert(value, rule): + if value is None and rule['match_disabled']: + return True + if 'values' in rule and value in rule['values']: + return True + if 'regex' in rule and value is not None and rule['regex'].match(value_to_str(value)): + return True + return False + + def restrict_entry_accepted(entry, path_info, restrict_data): if restrict_data is None: return True @@ -54,18 +77,12 @@ def restrict_entry_accepted(entry, path_info, restrict_data): if field not in entry and field_info.absent_value: value = field_info.absent_value - # Actual test - if 'values' in rule and value not in rule['values']: + # Check + matches_rule = _test_rule_except_invert(value, rule) + if rule['invert']: + matches_rule = not matches_rule + if not matches_rule: return False - if 'regex' in rule: - if value is None: - # regex cannot match None - return False - value_str = to_text(value) - if isinstance(value, bool): - value_str = value_str.lower() - if rule['regex'].match(value_str): - return False return True @@ -76,14 +93,10 @@ def restrict_argument_spec(): elements='dict', options=dict( field=dict(type='str', required=True), + match_disabled=dict(type='bool', default=False), values=dict(type='list', elements='raw'), regex=dict(type='str'), + invert=dict(type='bool', default=False), ), - mutually_exclusive=[ - ('values', 'regex'), - ], - required_one_of=[ - ('values', 'regex'), - ], ), )