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] }}"