mirror of
https://github.com/ansible-collections/community.routeros.git
synced 2025-06-21 17:39:04 +02:00
Allow to differ on API paths based on RouterOS version (1/2) (#209)
* Allow to provide definition for path based on API version.
* The paths added in 343c4883c0
are RouterOS 7+.
This commit is contained in:
parent
1ed4690240
commit
4b0995135c
7 changed files with 3158 additions and 2710 deletions
File diff suppressed because it is too large
Load diff
|
@ -97,6 +97,7 @@ def _ros_api_connect(module, username, password, host, port, use_tls, force_no_c
|
||||||
|
|
||||||
|
|
||||||
def create_api(module):
|
def create_api(module):
|
||||||
|
"""Create an API object."""
|
||||||
return _ros_api_connect(
|
return _ros_api_connect(
|
||||||
module,
|
module,
|
||||||
module.params['username'],
|
module.params['username'],
|
||||||
|
@ -111,3 +112,9 @@ def create_api(module):
|
||||||
module.params['encoding'],
|
module.params['encoding'],
|
||||||
module.params['timeout'],
|
module.params['timeout'],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_api_version(api):
|
||||||
|
"""Given an API object, query the system's version."""
|
||||||
|
system_info = list(api.path().join('system', 'resource'))[0]
|
||||||
|
return system_info['version'].split(' ', 1)[0]
|
||||||
|
|
|
@ -282,6 +282,7 @@ from ansible_collections.community.routeros.plugins.module_utils.api import (
|
||||||
api_argument_spec,
|
api_argument_spec,
|
||||||
check_has_library,
|
check_has_library,
|
||||||
create_api,
|
create_api,
|
||||||
|
get_api_version,
|
||||||
)
|
)
|
||||||
|
|
||||||
from ansible_collections.community.routeros.plugins.module_utils._api_data import (
|
from ansible_collections.community.routeros.plugins.module_utils._api_data import (
|
||||||
|
@ -324,9 +325,14 @@ def main():
|
||||||
api = create_api(module)
|
api = create_api(module)
|
||||||
|
|
||||||
path = split_path(module.params['path'])
|
path = split_path(module.params['path'])
|
||||||
path_info = PATHS.get(tuple(path))
|
versioned_path_info = PATHS.get(tuple(path))
|
||||||
if path_info is None:
|
if versioned_path_info is None:
|
||||||
module.fail_json(msg='Path /{path} is not yet supported'.format(path='/'.join(path)))
|
module.fail_json(msg='Path /{path} is not yet supported'.format(path='/'.join(path)))
|
||||||
|
if versioned_path_info.needs_version:
|
||||||
|
api_version = get_api_version(api)
|
||||||
|
if not versioned_path_info.provide_version(api_version):
|
||||||
|
module.fail_json(msg='Path /{path} is not supported for API version {api_version}'.format(path='/'.join(path), api_version=api_version))
|
||||||
|
path_info = versioned_path_info.get_data()
|
||||||
|
|
||||||
handle_disabled = module.params['handle_disabled']
|
handle_disabled = module.params['handle_disabled']
|
||||||
hide_defaults = module.params['hide_defaults']
|
hide_defaults = module.params['hide_defaults']
|
||||||
|
|
|
@ -331,6 +331,7 @@ from ansible_collections.community.routeros.plugins.module_utils.api import (
|
||||||
api_argument_spec,
|
api_argument_spec,
|
||||||
check_has_library,
|
check_has_library,
|
||||||
create_api,
|
create_api,
|
||||||
|
get_api_version,
|
||||||
)
|
)
|
||||||
|
|
||||||
from ansible_collections.community.routeros.plugins.module_utils._api_data import (
|
from ansible_collections.community.routeros.plugins.module_utils._api_data import (
|
||||||
|
@ -1003,8 +1004,23 @@ def get_backend(path_info):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def has_backend(versioned_path_info):
|
||||||
|
if not versioned_path_info.fully_understood:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if versioned_path_info.unversioned is not None:
|
||||||
|
return get_backend(versioned_path_info.unversioned) is not None
|
||||||
|
|
||||||
|
if versioned_path_info.versioned is not None:
|
||||||
|
for dummy, dummy, unversioned in versioned_path_info.versioned:
|
||||||
|
if get_backend(unversioned) is not None:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
path_choices = sorted([join_path(path) for path, path_info in PATHS.items() if get_backend(path_info) is not None])
|
path_choices = sorted([join_path(path) for path, versioned_path_info in PATHS.items() if has_backend(versioned_path_info)])
|
||||||
module_args = dict(
|
module_args = dict(
|
||||||
path=dict(type='str', required=True, choices=path_choices),
|
path=dict(type='str', required=True, choices=path_choices),
|
||||||
data=dict(type='list', elements='dict', required=True),
|
data=dict(type='list', elements='dict', required=True),
|
||||||
|
@ -1029,7 +1045,13 @@ def main():
|
||||||
api = create_api(module)
|
api = create_api(module)
|
||||||
|
|
||||||
path = split_path(module.params['path'])
|
path = split_path(module.params['path'])
|
||||||
path_info = PATHS.get(tuple(path))
|
versioned_path_info = PATHS.get(tuple(path))
|
||||||
|
if versioned_path_info.needs_version:
|
||||||
|
api_version = get_api_version(api)
|
||||||
|
if not versioned_path_info.provide_version(api_version):
|
||||||
|
module.fail_json(msg='Path /{path} is not supported for API version {api_version}'.format(path='/'.join(path), api_version=api_version))
|
||||||
|
path_info = versioned_path_info.get_data()
|
||||||
|
|
||||||
backend = get_backend(path_info)
|
backend = get_backend(path_info)
|
||||||
if path_info is None or backend is None:
|
if path_info is None or backend is None:
|
||||||
module.fail_json(msg='Path /{path} is not yet supported'.format(path='/'.join(path)))
|
module.fail_json(msg='Path /{path} is not yet supported'.format(path='/'.join(path)))
|
||||||
|
|
|
@ -10,7 +10,7 @@ __metaclass__ = type
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from ansible_collections.community.routeros.plugins.module_utils._api_data import (
|
from ansible_collections.community.routeros.plugins.module_utils._api_data import (
|
||||||
APIData,
|
VersionedAPIData,
|
||||||
KeyInfo,
|
KeyInfo,
|
||||||
split_path,
|
split_path,
|
||||||
join_path,
|
join_path,
|
||||||
|
@ -19,7 +19,7 @@ from ansible_collections.community.routeros.plugins.module_utils._api_data impor
|
||||||
|
|
||||||
def test_api_data_errors():
|
def test_api_data_errors():
|
||||||
with pytest.raises(ValueError) as exc:
|
with pytest.raises(ValueError) as exc:
|
||||||
APIData()
|
VersionedAPIData()
|
||||||
assert exc.value.args[0] == 'fields must be provided'
|
assert exc.value.args[0] == 'fields must be provided'
|
||||||
|
|
||||||
values = [
|
values = [
|
||||||
|
@ -33,39 +33,39 @@ def test_api_data_errors():
|
||||||
for index, (param, param_value) in enumerate(values):
|
for index, (param, param_value) in enumerate(values):
|
||||||
for param2, param2_value in values[index + 1:]:
|
for param2, param2_value in values[index + 1:]:
|
||||||
with pytest.raises(ValueError) as exc:
|
with pytest.raises(ValueError) as exc:
|
||||||
APIData(**{param: param_value, param2: param2_value})
|
VersionedAPIData(**{param: param_value, param2: param2_value})
|
||||||
assert exc.value.args[0] == 'primary_keys, stratify_keys, has_identifier, single_value, and unknown_mechanism are mutually exclusive'
|
assert exc.value.args[0] == 'primary_keys, stratify_keys, has_identifier, single_value, and unknown_mechanism are mutually exclusive'
|
||||||
|
|
||||||
with pytest.raises(ValueError) as exc:
|
with pytest.raises(ValueError) as exc:
|
||||||
APIData(unknown_mechanism=True, fully_understood=True)
|
VersionedAPIData(unknown_mechanism=True, fully_understood=True)
|
||||||
assert exc.value.args[0] == 'unknown_mechanism and fully_understood cannot be combined'
|
assert exc.value.args[0] == 'unknown_mechanism and fully_understood cannot be combined'
|
||||||
|
|
||||||
with pytest.raises(ValueError) as exc:
|
with pytest.raises(ValueError) as exc:
|
||||||
APIData(unknown_mechanism=True, fixed_entries=True)
|
VersionedAPIData(unknown_mechanism=True, fixed_entries=True)
|
||||||
assert exc.value.args[0] == 'fixed_entries can only be used with primary_keys'
|
assert exc.value.args[0] == 'fixed_entries can only be used with primary_keys'
|
||||||
|
|
||||||
with pytest.raises(ValueError) as exc:
|
with pytest.raises(ValueError) as exc:
|
||||||
APIData(primary_keys=['foo'], fields={})
|
VersionedAPIData(primary_keys=['foo'], fields={})
|
||||||
assert exc.value.args[0] == 'Primary key foo must be in fields!'
|
assert exc.value.args[0] == 'Primary key foo must be in fields!'
|
||||||
|
|
||||||
with pytest.raises(ValueError) as exc:
|
with pytest.raises(ValueError) as exc:
|
||||||
APIData(stratify_keys=['foo'], fields={})
|
VersionedAPIData(stratify_keys=['foo'], fields={})
|
||||||
assert exc.value.args[0] == 'Stratify key foo must be in fields!'
|
assert exc.value.args[0] == 'Stratify key foo must be in fields!'
|
||||||
|
|
||||||
with pytest.raises(ValueError) as exc:
|
with pytest.raises(ValueError) as exc:
|
||||||
APIData(required_one_of=['foo'], fields={})
|
VersionedAPIData(required_one_of=['foo'], fields={})
|
||||||
assert exc.value.args[0] == 'Require one of element at index #1 must be a list!'
|
assert exc.value.args[0] == 'Require one of element at index #1 must be a list!'
|
||||||
|
|
||||||
with pytest.raises(ValueError) as exc:
|
with pytest.raises(ValueError) as exc:
|
||||||
APIData(required_one_of=[['foo']], fields={})
|
VersionedAPIData(required_one_of=[['foo']], fields={})
|
||||||
assert exc.value.args[0] == 'Require one of key foo must be in fields!'
|
assert exc.value.args[0] == 'Require one of key foo must be in fields!'
|
||||||
|
|
||||||
with pytest.raises(ValueError) as exc:
|
with pytest.raises(ValueError) as exc:
|
||||||
APIData(mutually_exclusive=['foo'], fields={})
|
VersionedAPIData(mutually_exclusive=['foo'], fields={})
|
||||||
assert exc.value.args[0] == 'Mutually exclusive element at index #1 must be a list!'
|
assert exc.value.args[0] == 'Mutually exclusive element at index #1 must be a list!'
|
||||||
|
|
||||||
with pytest.raises(ValueError) as exc:
|
with pytest.raises(ValueError) as exc:
|
||||||
APIData(mutually_exclusive=[['foo']], fields={})
|
VersionedAPIData(mutually_exclusive=[['foo']], fields={})
|
||||||
assert exc.value.args[0] == 'Mutually exclusive key foo must be in fields!'
|
assert exc.value.args[0] == 'Mutually exclusive key foo must be in fields!'
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,9 @@ __metaclass__ = type
|
||||||
from ansible_collections.community.routeros.plugins.module_utils._api_data import PATHS
|
from ansible_collections.community.routeros.plugins.module_utils._api_data import PATHS
|
||||||
|
|
||||||
|
|
||||||
|
FAKE_ROS_VERSION = '7.0.0'
|
||||||
|
|
||||||
|
|
||||||
class FakeLibRouterosError(Exception):
|
class FakeLibRouterosError(Exception):
|
||||||
def __init__(self, message):
|
def __init__(self, message):
|
||||||
self.message = message
|
self.message = message
|
||||||
|
@ -16,7 +19,7 @@ class FakeLibRouterosError(Exception):
|
||||||
|
|
||||||
|
|
||||||
class TrapError(FakeLibRouterosError):
|
class TrapError(FakeLibRouterosError):
|
||||||
def __init__(self, message="failure: already have interface with such name"):
|
def __init__(self, message='failure: already have interface with such name'):
|
||||||
super(TrapError, self).__init__(message)
|
super(TrapError, self).__init__(message)
|
||||||
|
|
||||||
|
|
||||||
|
@ -133,7 +136,9 @@ def _normalize_entry(entry, path_info, on_create=False):
|
||||||
|
|
||||||
|
|
||||||
def massage_expected_result_data(values, path, keep_all=False, remove_dynamic=False, remove_builtin=False):
|
def massage_expected_result_data(values, path, keep_all=False, remove_dynamic=False, remove_builtin=False):
|
||||||
path_info = PATHS[path]
|
versioned_path_info = PATHS[path]
|
||||||
|
versioned_path_info.provide_version(FAKE_ROS_VERSION)
|
||||||
|
path_info = versioned_path_info.get_data()
|
||||||
if remove_dynamic:
|
if remove_dynamic:
|
||||||
values = [entry for entry in values if not entry.get('dynamic', False)]
|
values = [entry for entry in values if not entry.get('dynamic', False)]
|
||||||
if remove_builtin:
|
if remove_builtin:
|
||||||
|
@ -155,7 +160,9 @@ def massage_expected_result_data(values, path, keep_all=False, remove_dynamic=Fa
|
||||||
class Path(object):
|
class Path(object):
|
||||||
def __init__(self, path, initial_values, read_only=False):
|
def __init__(self, path, initial_values, read_only=False):
|
||||||
self._path = path
|
self._path = path
|
||||||
self._path_info = PATHS[path]
|
versioned_path_info = PATHS[path]
|
||||||
|
versioned_path_info.provide_version(FAKE_ROS_VERSION)
|
||||||
|
self._path_info = versioned_path_info.get_data()
|
||||||
self._values = [entry.copy() for entry in initial_values]
|
self._values = [entry.copy() for entry in initial_values]
|
||||||
for entry in self._values:
|
for entry in self._values:
|
||||||
_normalize_entry(entry, self._path_info)
|
_normalize_entry(entry, self._path_info)
|
||||||
|
|
|
@ -9,7 +9,12 @@
|
||||||
Updates DOCUMENTATION of modules using module_utils._api_data with the correct list of supported paths.
|
Updates DOCUMENTATION of modules using module_utils._api_data with the correct list of supported paths.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
from plugins.module_utils._api_data import (
|
import sys
|
||||||
|
|
||||||
|
# Ensure that we can import things from ansible_collections
|
||||||
|
sys.path.append('../../..')
|
||||||
|
|
||||||
|
from ansible_collections.community.routeros.plugins.module_utils._api_data import (
|
||||||
PATHS,
|
PATHS,
|
||||||
join_path,
|
join_path,
|
||||||
)
|
)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue