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