Reputation: 69
I am trying to extract the "host" and "port" value from the following JSON output with Jinja2:
"net_neighbors": {
"Ethernet0/0": [
{
"host": "Switch",
"platform": "Linux Unix",
"port": "Ethernet0/2"
}
],
"Ethernet0/1": [
{
"host": "DAL-R",
"platform": "Linux Unix",
"port": "Ethernet0/1"
}
]
},
Here is my Jinja2 template:
{% for interface in ansible_facts.net_neighbors %}
interface {{ interface }}
{% for dictionary in interface %}
description TO {{ dictionary['host'] }} {{ dictionary['port'] }}
{% endfor %}
{% endfor %}
The desired end-state is a template which produces output such as:
interface Ethernet0/0
description TO Switch Ethernet0/2
interface Ethernet0/1
description TO DAL-R Ethernet0/1
But I am getting the error:
fatal: [DAL-R]: FAILED! => {"changed": false, "msg": "'str object' has no attribute 'host'"}
What am I messing up here?
Upvotes: 0
Views: 71
Reputation: 311556
Your outer loop loops over a the net_neighbors
dictionary. Iterating over a dictionary produces a list of keys. That is, for each iteration of your outer loop, interface
will be a string like Ethernet0/0
, Ethernet0/1
, etc. You can verify this by simplifying your template:
{% for interface in net_neighbors %}
{{ interface }}
{% endfor %}
Which produces:
Ethernet0/0
Ethernet0/1
That means that your inner for loop doesn't make sense. When you write:
{% for dictionary in interface %}
You are iterating over the letters in the interface
value. You can see this if you add an inner loop to the previous example:
{% for interface in net_neighbors %}
{{ interface }}
{% for dictionary in interface %}
{{ dictionary }}
{% endfor %}
{% endfor %}
That will produce:
Ethernet0/0
E
t
h
e
r
n
e
t
0
/
0
Ethernet0/1
E
t
h
e
r
n
e
t
0
/
1
Incidentally, these diagnostic steps are good ideas whenever you're tacking a problem like this.
There are a couple of ways of fixing things. We can leave the outer loop as it is, and rewrite the inner loop to use the interface
variable to index the net_neighbors
dictionary:
{% for interface in net_neighbors %}
interface {{ interface }}
{% for dictionary in net_neighbors[interface] %}
description TO {{ dictionary['host'] }} {{ dictionary['port'] }}
{% endfor %}
{% endfor %}
Alternately, we can use the items()
method in the outer loop to get a list of (key, value)
tuples:
{% for interface, data in net_neighbors.items() %}
interface {{ interface }}
{% for dictionary in data %}
description TO {{ dictionary['host'] }} {{ dictionary['port'] }}
{% endfor %}
{% endfor %}
Both of these templates produce as output:
interface Ethernet0/0
description TO Switch Ethernet0/2
interface Ethernet0/1
description TO DAL-R Ethernet0/1
Upvotes: 3