A little background info. I'm using netbox as a source of truth for our network automation and I am currently in the process of doing some test to automate juniper configuration. Netbox is currently used as my ansible inventory and is supplying host_vars.
I want to achieve a simple task of setting a "value" in my Juniper configuration based on a host var.
Problem
I'm most definetly using the wrong map/filter combination to achieve my goal of looping over the values within the dict "dns" but I've tried countless times without any success so taking my issue to the community for an advice.
I have the following host_vars:
{
"ansible_host": "192.168.1.1",
"config_context": [
{
"_utility": {
"dns": [
"10.10.10.10",
"10.10.10.20"
]
}
}
],
"device_roles": [
"leaf"
],
"device_types": [
"qfx5120-48y"
]
}
And my task currently looks like:
- name: Set DNS server
juniper.device.config:
config_mode: 'exclusive'
load: 'set'
lines:
- 'set system name-server "{{ item }}"'
loop: "{{ config_context | map(attribute='_utility') | flatten | map(attribute='dns') | flatten }}"
Which is giving out a error message
Tried to debug it registering a variable and printing this using debug msg:
DEBUG
- name: Print var
vars:
- nameservers: "{{ config_context | map(attribute='_utility') | flatten | map(attribute='dns') | flatten }}"
debug:
msg:
- "{{ nameservers }}"
Result
ok: [poc-spine01-re] => {
"msg": [
[
"10.10.10.10",
"10.10.10.20"
]
]
}
But when trying too loop over the values withing the result I get another error
DEBUG
- name: Print var loop
vars:
- nameservers: "{{ config_context | map(attribute='_utility') | flatten | map(attribute='dns') | flatten }}"
debug:
msg:
- "{{ item }}"
loop: nameservers
Result
fatal: [poc-leaf03-re]: FAILED! => {
"msg": "Invalid data passed to 'loop', it requires a list, got this instead: nameservers. Hint: If you passed a list/dict of just one element, try adding wantlist=True to your lookup invocation or use q/query instead of lookup."
}
fatal: [poc-spine01-re]: FAILED! => {
"msg": "Invalid data passed to 'loop', it requires a list, got this instead: nameservers. Hint: If you passed a list/dict of just one element, try adding wantlist=True to your lookup invocation or use q/query instead of lookup."
}
UPDATE
Hi, it worked for the loop!. I've adjusted my variables and am now contemplating if i should only get the value of the key dns1 or dns2 ( not in a loop )
host vars
{
"ansible_host": "192.168.1.1",
"config_context": [
{
"_utility": {
"dns": {
"dns1": "10.10.10.10",
"dns2": "10.10.10.20"
}
}
}
],
"device_roles": [
"leaf"
],
"device_types": [
"qfx5120-48y"
]
}
but can't get the map filter to properly display one value
task
- name: Set DNS server
vars:
ns1: "{{ config_context | map(attribute='_utility.dns.dns1') | flatten }}"
juniper.device.config:
config_mode: 'exclusive'
load: 'set'
lines:
- 'set system name-server "{{ ns1 }}"'
result
As you can see the value of 10.10.10.10 is quoted with brackets and a double quote instead of only the value string of 10.10.10.10
fatal: [poc-spine01-re]: FAILED! => {
"changed": false,
"invocation": {
"module_args": {
"lines": [
"set system name-server \"['10.10.10.10']\""
],
CodePudding user response:
Your loop should be fixed as follow:
loop: "{{ config_context | map(attribute='_utility.dns') | flatten }}"
Moreover I would add some extra filters to make sure that:
- you don't loop over the same dns twice if it is declared in several
config_context
entries (i.e.unique
) - you always go other the list in the same order (i.e.
sort
)
loop: "{{ config_context | map(attribute='_utility.dns') | flatten | unique | sort }}"
Side notes
- name: Print var loop vars: - nameservers: "{{ config_context | map(attribute='_utility') | flatten | map(attribute='dns') | flatten }}" debug: msg: - "{{ item }}" loop: nameservers
Three problems in this single task.
- Although it actually "works" with a list (which ansible automagically converts), your
vars
declaration should be a mapping:vars: nameservers: "{{ config_context | map(attribute='_utility') | flatten | map(attribute='dns') | flatten }}"
- You are looping over the string
"nameservers"
. You want to loop over the content of the variable with that name:loop: "{{ nameservers }}"
- In your debug message, you are asking to print a list which first element content is whatever value is inside the
item
variable. What you actually want is print the content of that variable directly, which can be acheived with
or since you don't have any processing on the content by addressing the var directlydebug: msg: "{{ item }}"
debug: var: item
Putting it all together and integrating my above fix which was the core of your question:
- name: Print var loop
vars:
nameservers: "{{ config_context | map(attribute='_utility.dns') | flatten | unique | sort }}"
debug:
var: item
loop: "{{ nameservers }}"