Home > Software engineering >  Ansible cannot invoke variable for hostname in playbook
Ansible cannot invoke variable for hostname in playbook

Time:12-29

I need to add new users to multiple Ubuntu servers. Unfortunately, the password and username are not consistent. Every machine has its own username and the password cannot be the same. For example, host-1 will have a user account host-1_username with password host-1_password and host-2 will have a user account host-2_username with password host-2_password, and so on.

I would like to do that by Ansible. I have a list.yaml file:

---
list:
  - hostname: host-1
    username: host-1_username
    password: host-1_password
  - hostname: host-2
    username: host-2_username
    password: host-2_password
  - hostname: host-3
    username: host-3_username
    password: host-3_password

Here is my Ansible playbook:

- name: Crate new user
  vars_files:
    - list.yml
  hosts: "{{ item.hostname }}"
  remote_user: root
  become: true

  tasks:
  - name: Create new user
    ansible.builtin.user:
      name: "{{ item.username }}"
      groups: sudo
      password: "{{ item.password | password_hash('sha512') }}"
      shell: /bin/bash

  - name: Modify sshd_config 
    ansible.builtin.lineinfile:
      dest: /etc/ssh/sshd_config
      line: 'AllowUsers {{ item.username }}'
    
    loop: "{{ list }}"

But looks like Ansible cannot invoke the variable to add into hosts column:

ERROR! couldn't resolve module/action 'hosts'. This often indicates a misspelling, missing collection, or incorrect module path.

I am very new to Ansible, any help is appreciated!

CodePudding user response:

Given the data

shell> cat list.yml 
users_list:
  - hostname: host-1
    username: host-1_username
    password: host-1_password
  - hostname: host-2
    username: host-2_username
    password: host-2_password
  - hostname: host-3
    username: host-3_username
    password: host-3_password

Create an inventory file, e.g.

shell> cat hosts
host-1
host-2
host-3

Convert the data to dictionaries, e.g.

- hosts: all
  gather_facts: false
  vars_files:
    - list.yml
  tasks:
    - set_fact:
        users_dict: "{{ users_list|items2dict(key_name='hostname', value_name='username') }}"
        psswd_dict: "{{ users_list|items2dict(key_name='hostname', value_name='password') }}"
      run_once: true

gives

  users_dict:
    host-1: host-1_username
    host-2: host-2_username
    host-3: host-3_username

and

  psswd_dict:
    host-1: host-1_password
    host-2: host-2_password
    host-3: host-3_password

Use the dictionaries to select the hosts' specific users and passwords, e.g.

    - debug:
        msg: "Create user: {{ users_dict[inventory_hostname] }}
              password: {{ psswd_dict[inventory_hostname] }}"

gives

TASK [debug] ***************************************************************
ok: [host-1] => 
  msg: 'Create user: host-1_username password: host-1_password'
ok: [host-2] => 
  msg: 'Create user: host-2_username password: host-2_password'
ok: [host-3] => 
  msg: 'Create user: host-3_username password: host-3_password'

You can omit the inventory file and create a playbook completely driven by the data. Create dynamic group my_group in the first play and use it in the second one. The playbook below gives the same results

- name: Create dynamic group of the hosts from users_list
  hosts: localhost
  gather_facts: false
  vars_files:
    - list.yml
  tasks:
    - add_host:
        name: "{{ item.hostname }}"
        groups: my_group
      loop: "{{ users_list }}"

- name: Create users
  hosts: my_group
  gather_facts: false
  vars_files:
    - list.yml
  tasks:
    - set_fact:
        users_dict: "{{ users_list|items2dict(key_name='hostname', value_name='username') }}"
        psswd_dict: "{{ users_list|items2dict(key_name='hostname', value_name='password') }}"
      run_once: true
    - debug:
        var: users_dict
      run_once: true
    - debug:
        var: psswd_dict
      run_once: true
    - debug:
        msg: "Create user: {{ users_dict[inventory_hostname] }}
              password: {{ psswd_dict[inventory_hostname] }}"
  • Related