diff --git a/changelogs/fragments/128-api.yml b/changelogs/fragments/128-api.yml new file mode 100644 index 00000000..6bcc4b7e --- /dev/null +++ b/changelogs/fragments/128-api.yml @@ -0,0 +1,3 @@ +minor_changes: + - api_modify, api_info - support for API fields that can be disabled and have default value at the same time, support API paths ``interface gre``, ``interface eoip`` + (https://github.com/ansible-collections/community.routeros/pull/128). diff --git a/plugins/module_utils/_api_data.py b/plugins/module_utils/_api_data.py index fa4765dd..c094821c 100644 --- a/plugins/module_utils/_api_data.py +++ b/plugins/module_utils/_api_data.py @@ -49,8 +49,10 @@ class KeyInfo(object): def __init__(self, _dummy=None, can_disable=False, remove_value=None, absent_value=None, default=None, required=False, automatically_computed_from=None): if _dummy is not None: raise ValueError('KeyInfo() does not have positional arguments') - if sum([required, default is not None, automatically_computed_from is not None, can_disable]) > 1: - raise ValueError('required, default, automatically_computed_from, and can_disable are mutually exclusive') + if sum([required, default is not None or can_disable, automatically_computed_from is not None]) > 1: + raise ValueError( + 'required, default, automatically_computed_from, and can_disable are mutually exclusive ' + + 'besides default and can_disable which can be set together') if not can_disable and remove_value is not None: raise ValueError('remove_value can only be specified if can_disable=True') if absent_value is not None and any([default is not None, automatically_computed_from is not None, can_disable]): @@ -106,6 +108,31 @@ def join_path(path): 'vlan-filtering': KeyInfo(default=False), }, ), + ('interface', 'eoip'): APIData( + fully_understood=True, + primary_keys=('name',), + fields={ + 'allow-fast-path': KeyInfo(default=True), + 'arp': KeyInfo(default='enabled'), + 'arp-timeout': KeyInfo(default='auto'), + 'clamp-tcp-mss': KeyInfo(default=True), + 'comment': KeyInfo(can_disable=True, remove_value=''), + 'disabled': KeyInfo(default=False), + 'dont-fragment': KeyInfo(default=False), + 'dscp': KeyInfo(default='inherit'), + 'ipsec-secret': KeyInfo(can_disable=True), + 'keepalive': KeyInfo(default='10s,10', can_disable=True), + 'local-address': KeyInfo(default='0.0.0.0'), + 'loop-protect': KeyInfo(default='default'), + 'loop-protect-disable-time': KeyInfo(default='5m'), + 'loop-protect-send-interval': KeyInfo(default='5s'), + 'mac-address': KeyInfo(), + 'mtu': KeyInfo(default='auto'), + 'name': KeyInfo(), + 'remote-address': KeyInfo(required=True), + 'tunnel-id': KeyInfo(required=True), + }, + ), ('interface', 'ethernet'): APIData( fixed_entries=True, fully_understood=True, @@ -145,6 +172,24 @@ def join_path(path): 'tx-flow-control': KeyInfo(default='off'), }, ), + ('interface', 'gre'): APIData( + fully_understood=True, + primary_keys=('name', ), + fields={ + 'allow-fast-path': KeyInfo(default=True), + 'clamp-tcp-mss': KeyInfo(default=True), + 'comment': KeyInfo(can_disable=True, remove_value=''), + 'disabled': KeyInfo(default=False), + 'dont-fragment': KeyInfo(default=False), + 'dscp': KeyInfo(default='inherit'), + 'ipsec-secret': KeyInfo(can_disable=True), + 'keepalive': KeyInfo(default='10s,10', can_disable=True), + 'local-address': KeyInfo(default='0.0.0.0'), + 'mtu': KeyInfo(default='auto'), + 'name': KeyInfo(), + 'remote-address': KeyInfo(required=True), + }, + ), ('interface', 'list'): APIData( primary_keys=('name', ), fully_understood=True, diff --git a/plugins/modules/api_info.py b/plugins/modules/api_info.py index 03d024e7..f8e93377 100644 --- a/plugins/modules/api_info.py +++ b/plugins/modules/api_info.py @@ -57,9 +57,11 @@ - interface bridge settings - interface bridge vlan - interface detect-internet + - interface eoip - interface ethernet - interface ethernet switch - interface ethernet switch port + - interface gre - interface l2tp-server server - interface list - interface list member diff --git a/plugins/modules/api_modify.py b/plugins/modules/api_modify.py index 0306db3e..fc57ee09 100644 --- a/plugins/modules/api_modify.py +++ b/plugins/modules/api_modify.py @@ -62,9 +62,11 @@ - interface bridge settings - interface bridge vlan - interface detect-internet + - interface eoip - interface ethernet - interface ethernet switch - interface ethernet switch port + - interface gre - interface l2tp-server server - interface list - interface list member @@ -352,7 +354,7 @@ def find_modifications(old_entry, new_entry, path_info, module, for_text='', ret modifications['!%s' % disabled_k] = '' del updated_entry[disabled_k] continue - if k not in old_entry and path_info.fields[k].default == v: + if k not in old_entry and path_info.fields[k].default == v and not path_info.fields[k].can_disable: continue if k not in old_entry or old_entry[k] != v: modifications[k] = v @@ -368,7 +370,9 @@ def find_modifications(old_entry, new_entry, path_info, module, for_text='', ret if field_info.remove_value is not None and field_info.remove_value == old_entry[k]: continue if field_info.can_disable: - if field_info.remove_value is not None: + if field_info.default is not None: + modifications[k] = field_info.default + elif field_info.remove_value is not None: modifications[k] = field_info.remove_value else: modifications['!%s' % k] = '' @@ -380,6 +384,11 @@ def find_modifications(old_entry, new_entry, path_info, module, for_text='', ret if return_none_instead_of_fail: return None, None module.fail_json(msg='Key "{key}" cannot be removed{for_text}.'.format(key=k, for_text=for_text)) + for k in path_info.fields: + field_info = path_info.fields[k] + if k not in old_entry and k not in new_entry and field_info.can_disable and field_info.default is not None: + modifications[k] = field_info.default + updated_entry[k] = field_info.default return modifications, updated_entry diff --git a/tests/unit/plugins/module_utils/test__api_data.py b/tests/unit/plugins/module_utils/test__api_data.py index 67b5b1b4..6220e292 100644 --- a/tests/unit/plugins/module_utils/test__api_data.py +++ b/tests/unit/plugins/module_utils/test__api_data.py @@ -63,11 +63,19 @@ def test_key_info_errors(): ('can_disable', True), ] + params_allowed_together = [ + 'default', + 'can_disable', + ] + + emsg = 'required, default, automatically_computed_from, and can_disable are mutually exclusive besides default and can_disable which can be set together' for index, (param, param_value) in enumerate(values): for param2, param2_value in values[index + 1:]: + if param in params_allowed_together and param2 in params_allowed_together: + continue with pytest.raises(ValueError) as exc: KeyInfo(**{param: param_value, param2: param2_value}) - assert exc.value.args[0] == 'required, default, automatically_computed_from, and can_disable are mutually exclusive' + assert exc.value.args[0] == emsg with pytest.raises(ValueError) as exc: KeyInfo('foo') diff --git a/tests/unit/plugins/modules/fake_api.py b/tests/unit/plugins/modules/fake_api.py index b17c088d..f50c996c 100644 --- a/tests/unit/plugins/modules/fake_api.py +++ b/tests/unit/plugins/modules/fake_api.py @@ -120,7 +120,7 @@ def str_return(self): def _normalize_entry(entry, path_info): for key, data in path_info.fields.items(): - if key not in entry and data.default is not None: + if key not in entry and data.default is not None and not data.can_disable: entry[key] = data.default if data.can_disable: if key in entry and entry[key] in (None, data.remove_value):