Open gardar opened 4 days ago
Looks like I should perhaps use api_find_and_modify
instead of api_modify
for this.
It is not working as expected though when I try to use it in a loop, as it's not finding any matches.
More specifically the issue seems to be with the vlan-ids
field.
This gives no matches:
- name: Configure vlans on bridge # noqa args[module]
community.routeros.api_find_and_modify:
path: "interface bridge vlan"
find:
bridge: "{{ item.bridge }}"
vlan-ids: "{{ item.vlan_id }}"
values:
vlan-ids: "{{ item.vlan_id }}"
bridge: "{{ item.bridge }}"
tagged: "{{ item.tagged }}"
loop: "{{ __vlans }}"
vars:
__vlans:
- bridge: bridge0
vlan_id: 2
tagged: ether2
whereas this gives a match:
- name: Configure vlans on bridge # noqa args[module]
community.routeros.api_find_and_modify:
path: "interface bridge vlan"
find:
bridge: "{{ item.bridge }}"
vlan-ids: 2
values:
vlan-ids: 2
bridge: "{{ item.bridge }}"
tagged: "{{ item.tagged }}"
loop: "{{ __vlans }}"
vars:
__vlans:
- bridge: bridge0
vlan_id: 2
tagged: ether2
I thought perhaps it might be that the vlan ids in the loop were interpreted as a string and not int but forcing the int data type with vlan-ids: "{{ item.vlan_id | int }}"
does not help either.
Also, using variables does not seem to be the issue, as this works just fine:
- name: Configure vlans on bridge # noqa args[module]
community.routeros.api_find_and_modify:
path: "interface bridge vlan"
find:
bridge: "{{ bridge }}"
vlan-ids: "{{ vlan_id }}"
values:
vlan-ids: "{{ vlan_id }}"
bridge: "{{ bridge }}"
tagged: "{{ tagged }}"
vars:
bridge: bridge0
vlan_id: 2
tagged: ether2
Looking at the verbose output I notice that vlan-ids
shows up as a quoted string under invocation.module_args.find
when using a loop.
{
"ansible_loop_var": "item",
"changed": false,
"invocation": {
"module_args": {
"allow_no_matches": true,
"ca_path": null,
"encoding": "UTF-8",
"find": {
"bridge": "bridge0",
"vlan-ids": "2"
},
But when not using a loop it is unquoted.
{
"ansible_loop_var": "item",
"changed": false,
"invocation": {
"module_args": {
"allow_no_matches": true,
"ca_path": null,
"encoding": "UTF-8",
"find": {
"bridge": "bridge0",
"vlan-ids": 2
},
Looks like this could be the same issue with the loops: https://github.com/ansible-collections/community.routeros/issues/169
Found a workaround for the api_find_and_modify
data type issue when using loops by using the dict()
function.
- name: Configure vlans on bridge # noqa args[module]
community.routeros.api_find_and_modify:
path: "interface bridge vlan"
find: >-
{{
dict([
['vlan-ids', item.vlan_id],
['bridge', item.bridge]
])
}}
values:
vlan-ids: "{{ item.vlan_id }}"
bridge: "{{ item.bridge }}"
tagged: "{{ item.tagged }}"
loop: "{{ __vlans }}"
vars:
__vlans:
- bridge: bridge0
vlan_id: 2
tagged: ether2
The same data type issue also affects the values
field of the api_find_and_modify
when using a loop and the task is not immutable and always shows as changed
even though the old_data
and new_data
shown in the return values is identical.
But using dict()
as a workaround resolves that issue as well.
- name: Configure vlans on bridge # noqa args[module]
community.routeros.api_find_and_modify:
path: "interface bridge vlan"
find: >-
{{
dict([
['vlan-ids', item.vlan_id],
['bridge', item.bridge]
])
}}
values: >-
{{
dict([
['vlan-ids', item.vlan_id],
['bridge', item.bridge],
['tagged', item.tagged]
])
}}
loop: "{{ __vlans }}"
vars:
__vlans:
- bridge: bridge0
vlan_id: 2
tagged: ether2
I tried few approaches, using the dict filter, using to/from json/yaml filters, creating the dict with inline jinja2, using block scalar to avoid the quotes around the variable, etc. but only dict()
seems to return the correct data type.
I'm not sure if this issue is tied directly to the api_find_and_modify
module as I'm able to replicate the issue with ansible.builtin.debug
. But perhaps some workarounds can be integrated in the module.
- name: "Debug vlans"
ansible.builtin.debug:
msg: { vlan-id: "{{ item.vlan_id }}" }
loop: "{{ __vlans }}"
vars:
vlan_id: 2
__vlans:
- bridge: bridge0
vlan_id: 2
tagged: ether3
Incorrectly returns a string:
{
"msg": {
"vlan-id": "2"
}
}
- name: "Debug vlans"
ansible.builtin.debug:
msg: { vlan-id: "{{ vlan_id }}" }
loop: "{{ __vlans }}"
vars:
vlan_id: 2
__vlans:
- bridge: bridge0
vlan_id: 2
tagged: ether3
Correctly returns a int:
{
"msg": {
"vlan-id": 2
}
}
SUMMARY
It's only possible to use the
interface bridge vlan
path with theapi_modify
module if the vlan does not already exist. It errors out if the vlan exists, both when attempting to modify the vlan but also when the config matches the existing vlan and it should not be attempting to modify it.ISSUE TYPE
COMPONENT NAME
api_modify
interface bridge vlan
ANSIBLE VERSION
COLLECTION VERSION
CONFIGURATION
OS / ENVIRONMENT
STEPS TO REPRODUCE
EXPECTED RESULTS
The vlan should be modified if the
data
is different than the configuration on the device. If it's the same then it should not change the interface and give ok status.ACTUAL RESULTS