I'm losing my mind here but i just cant seem to see where my problem lies! Im trying to have ansible create me users on a Cisco ASA and im using Jinja 2 templates.
I have a host vars file where i am specifying the users (sensitised data):
users:
tom:
sshkey: "xxxx"
privilegelevel: 15
dick:
sshkey: "xxxx"
privilegelevel: 15
harry:
password: "yyyy"
privilegelevel: 15
My templates for creating the users (users.j2):
{% if users is defined %}
{% for user, value in users.items() %}
username {{ value }} privilege {{ value.privilegelevel }}
{% endfor %}
{% endif %}
and if they have an ssh key (users-ssh.j2):
{% if users and 'sshkey' is defined %}
{% for user, value in users.items() %}
username {{ value }} privilege {{ value.privilegelevel }}
username {{ value }} attributes
ssh authentication publickey {{ value.sshkey }}
{% endfor %}
{% endif %}
And last but not least the playbook:
- name: create users
asa_config:
src: templates/users.j2
provider: "{{ cli }}"
save: yes
tags: users
- name: create ssh pubkey auth
asa_config:
src: templates/users-ssh.j2
provider: "{{ cli }}"
save: yes
tags: users
When running the playbook, the user.j2 works fine, but user-ssh.j2 fails with:
fatal: [HOSTNAME_HERE]: FAILED! => {"changed": false, "msg": "'dict object' has no attribute 'sshkey'"}
When calling the dict values with:
- name: Output dict
debug:
msg: "User is {{ item.key }} and the ssh key is {{ item.value.sshkey }}"
loop: "{{ lookup('dict', users) }}"
tags: users
It gives me the correct values:
ok: [fw01.prd.sc1] => (item={'key': 'tom', 'value': {'sshkey': 'xxxx', 'privilegelevel': 15}}) => {
"msg": "User is tom and the ssh key is xxxx"
}
ok: [fw01.prd.sc1] => (item={'key': 'dick', 'value': {'sshkey': 'xxxx', 'privilegelevel': 15}}) => {
"msg": "User is dick and the ssh key is xxxx"
}
Can anyone see where i may be going wrong with my J2 templating as ive a fair few things but getting nowhere!
Many thanks in advance :)
Kris
This loop...
{% if users and 'sshkey' is defined %}
{% for user, value in users.items() %}
username {{ value }} privilege {{ value.privilegelevel }}
username {{ value }} attributes
ssh authentication publickey {{ value.sshkey }}
{% endfor %}
{% endif %}
...doesn't check if a user has an sshkey
attribute. The expression if users and 'sshkey' is defined
is identical to writing if users
, because the expressionif 'sshkey' is defined
will always be true
-- 'sshkey'
is a literal string, not a variable.
Since the loop runs for all users, it fails when you get to harry
, because harry
doesn't have an sshkey
attribute.
You need to filter your users for those that have an sshkey
attribute, for example by using a loop filtering as described in the documentation:
{% for user, value in users.items() if value.sshkey is defined %}
username {{ user }} privilege {{ value.privilegelevel }}
username {{ user }} attributes
ssh authentication publickey {{ value.sshkey }}
{% endfor %}
Note that I've also replaced username {{ value }}
with username {{ user }}
, because I'm reasonably sure the former was not what you meant.
For example, this playbook:
- hosts: localhost
gather_facts: false
vars:
users:
tom:
sshkey: "xxxx"
privilegelevel: 15
dick:
sshkey: "xxxx"
privilegelevel: 15
harry:
password: "yyyy"
privilegelevel: 15
tasks:
- copy:
dest: users.txt
content: |
{% for user, value in users.items() if value.sshkey is defined %}
username {{ user }} privilege {{ value.privilegelevel }}
username {{ user }} attributes
ssh authentication publickey {{ value.sshkey }}
{% endfor %}
Produces as output in users.txt
:
username tom privilege 15
username tom attributes
ssh authentication publickey xxxx
username dick privilege 15
username dick attributes
ssh authentication publickey xxxx