3

I have an issue with looping on vars,

- hosts: all
  become: yes
  vars:
    user: 
      - name: "neito"
        pubkey: "{{ lookup('file', '~/.ssh/vsphere_vm.pub') }}"
        privkey: "{{ lookup('file', '~/.ssh/vsphere_vm') }}"
  tasks:
    - name: "Add SSH public key"
      authorized_key:
        user: "{{ item.name }}"
        key: "{{ item.pubkey }}"
      loop:
        - "{{ user }}"

when running this playbook I have the following error : The error was: 'list object' has no attribute 'name'

The {{ item.name }} seems to be undefined for Ansible, I guess I'm missing something obvious here but I can't find what. (I was following this get started post

Edit 1 :

By declaring the vars like following it works :

vars:
    user:
      {
        name: "neito",
        pubkey: "{{ lookup('file', '~/.ssh/vsphere_vm.pub') }}",
        privkey: "{{ lookup('file', '~/.ssh/vsphere_vm') }}",
      }

Could someone still point me out why the first syntax didn't work?

3 Answers 3

7

The problem was the - dash in front of the "{{ user }}":

loop:
  - "{{ user }}"

Needs to be :

loop: "{{ user }}"
Sign up to request clarification or add additional context in comments.

1 Comment

This answer points to the real problem. This one shall be the accepted answer.
5

Please check the loops documentation:

You can define the list in a variables file, or in the ‘vars’ section of your play, then refer to the name of the list in the task:

loop: "{{ somelist }}"

If you modify your original task to:

tasks:
  - name: "Add SSH public key"
    authorized_key:
      user: "{{ item.name }}"
      key: "{{ item.pubkey }}"
    loop: "{{ user }}"

you should be good to go.

3 Comments

This answer doesn't show the reason for the problem. The code works though.
Since documentation suggests that using - "{{ a list }}" is not the proper way, i guess there is no point analyzing it any further. Perhaps the loop is more strict on the syntax of the input variable, than with_items is.
with_items: "{{ whatever }}" is equivalent to loop: "{{ whatever | flatten(levels=1) }}". This is why it will work if you pass a list of lists. Loop will not accept that on its own. See docs.ansible.com/ansible/latest/user_guide/…
0

Originally you defined user as a 1-element list. The little dash (-) at the beginning denoted an element of a list.

user:
  - name: "neito"
    pubkey: "{{ lookup('file', '~/.ssh/vsphere_vm.pub') }}"
    privkey: "{{ lookup('file', '~/.ssh/vsphere_vm') }}"
# in YAML, the below is equivalent to the above
user:
  [
    {
      name: "neito",
      pubkey: "{{ lookup('file', '~/.ssh/vsphere_vm.pub') }}",
      privkey: "{{ lookup('file', '~/.ssh/vsphere_vm') }}"
    }
  ]

The brackets are alternative syntax to the dashes. On a similar note, curly braces are also an alternative to specifying each property on a new line, with increased indentation. So you could rewrite your second example in the following way:

user:
  name: "neito"
  pubkey: "{{ lookup('file', '~/.ssh/vsphere_vm.pub') }}"
  privkey: "{{ lookup('file', '~/.ssh/vsphere_vm') }}" """)

Thanks to the fact that the brackets and curly braces are also valid in YAML, you can actually parse JSON files as YAML and it will work 100% (but not the other way around).

3 Comments

Thanks for the detailed explanation and extra infos.
This answer does not solve the problem. In addition to this, the proposed dictionary does not serve the purpose of iterating the users.
@VladimirBotka thanks for your feedback. I agree that iterating users would probably make sense here, but it wasn't clear from the question that OP wanted user to be a list (perhaps in such case it should have been called users?). If you take a look at the tutorial OP is following, that tutorial uses loop: ...- '"{{ user }}"' all over the place.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.