Give Input from Text file to Ansible Playbook - ansible

In my ansible playbook I want to get the input from text file and perform some set of operations.
I have 10 user names in the text file, then the play has to pick first name from the text file and do few tasks. Once done for the first user and the play has to pick it for second user and so on.
I wrote play for a single user. Kindly help me or give some sample play for this kind of scenario.

You should be using roles and manage everything from inventory.
But however, simplest way; Create a file, and store your user names in a variable that way
users:
- user1
- user2
- user3
- user4
- user5
At the beginning of your playbook, include that file
- hosts: whatever
become: yes
vars_file:
- <<path_to_your_var_file>>
Then in the task you can use that users variable you included from the variable file
tasks:
- name: create 10 users
user:
name: "{{ item }}"
state: present
with_items:
- "{{ users }}"
Ansible will import the users variable from your var file, and loop n times with number of users you have.

Related

Is there a way to assign a user in the active directory to multiple groups with ansible?

I created an ansible-playbook which aims to add a user to a group in Active Directory via Ansible with code as shown below:
# addmembertogroup.yaml
# Skip task when 'group' or 'username' is undefined
# Show message when 'group' or 'username' doesn't exist
---
- hosts: brc.testlab.com
gather_facts: no
tasks:
- name: "Add Member to Group"
block:
- name: "Add Member to Group"
community.windows.win_domain_group_membership:
name: "{{group}}"
members: "{{username}}"
state: present
when: (group is defined) and (username is defined)
rescue:
- name: Print when error
debug:
msg: Username / Group not exist
Where the playbook is run with the following command:
Ansible-playbook –i hosts addmembertogroup.yaml –e group=DNSAdmins –e username=Cahbayu
Based on the existing ansible playbook and command, I managed to add a user with the name Cahbayu into the DNSAdmins group. However, I want the user to be in multiple groups in one command. For example, I want to add user Cahbayu into the group DNSAdmins, Backup Operators, Remote Desktop Users. I've made the group parameters into a list like the following but the result still fail:
---
- hosts: brc.testlab.com
gather_facts: no
tasks:
- name: "Add Member to Group"
block:
- name: "Add Member to Group"
community.windows.win_domain_group_membership:
name:
- "{{group}}"
members: "{{username}}"
state: present
when: (group is defined) and (username is defined)
rescue:
- name: Print when error
debug:
msg: Username / Group not exist
And here's the result:
[Failed to Add User to Multiple Groups][1]
Thus, my question is, is there a way to enter a user into multiple groups in Active Directory with Ansible? Thank you.
(Edited)
I managed to get user into multiple groups using ‘loop’ according to the answer provided.
I think you can manage to do so if you define the groups in a variable or a list and loop through the list that you want your user to be added in, check this this link it could help you manage doing it since your playbook is working and needs only a well defined loop
https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html[loops in ansible]1

Ansible - Avoid duplicates between group and host vars

I'm new at using ansible for server management and I need some help managing users and group's membership definition according to host and hosts-group, with a minimum of duplication and a maximum of scalability.
(25 users/20 groups over 50 hosts, with different "sudo" and "groups membership" at the end).
The idea is to have:
"groups_vars" files defining the users (list or hash) to create on each host of the host group.
"host_vars" files defining users for a specific host. (At the end, I will need nested groups, more than specific host_vars files)
I need these \*_vars files contents to be merged and not to be replaced (I understand how "vars precedence" work) because I want to avoid user declaration duplication.
To achieve this, I used hash syntax in \*_vars files and set hash_behaviour=merge in /etc/ansible/ansible.cfg.
Here are my files:
My inventory:
all:
children:
type_a:
hosts:
vm1:
vm2:
My debugging playbook :
- hosts: type_a
tasks:
- name: Debugging
debug:
msg: "{{ users }}"
group_vars/type_a.yaml :
users:
user1:
name: user1
user2:
name: user2
host_vars/vm1.yaml
users:
user3_vm1_specific:
name: user3_vm1_specific
At the end, I need the 3 users on the "vm1" and only "user1" and "user2" on "vm2" and then I will use the vars for the user creation.
Using the merge option (that will be deprecated in newer version of ansible) is working, but doesn't seem to be a best practice.
I searched here on StackOverflow and on other web sites, and most of the time the solutions are:
to duplicate the user definition
(more than 8 properties for each user and too many hostsgroup: unacceptable.)
to use an other name for the second user list, then to assemble both using {{ user_list1 + user_list2 }}.
Not very scalable if we want to add many nested groups. You will need to add custom named list each time. It also, makes duplicates if "host_vars" and "group_vars" have the same user defined: it does not merge the content, but declares it twice with a different content each time.
My first solution is working, but using a near-deprecated option.
So what are the best practices in managing vars in this kind of situation ? (already have read the ansible documentation about vars but it didn't really helped me).
Also, maybe ansible tower or foreman could solve this problem?
A very simple, easily maintainable, and flexible solution is to put users into one dictionary. For example
shell> cat group_vars/all/users.yml
users:
groups:
type_a:
- user1
- user2
type_b:
- user3
- user4
hosts:
vm1:
- user3_vm1_specific
vm2:
- user4_vm2_specific
Then the task below extracts all group's lists, add the host's list, makes the items unique, and sort it
shell> cat playbook.yml
- hosts: type_a
tasks:
- set_fact:
my_users: "{{ (group_names|
map('extract', users.groups)|list +
users.hosts[inventory_hostname]|default([]))|
flatten|unique|sort }}"
- debug:
var: my_users
gives
shell> ansible-playbook playbook.yml
PLAY [type_a] ****
TASK [debug] ****
ok: [vm1] =>
my_users:
- user1
- user2
- user3_vm1_specific
ok: [vm2] =>
my_users:
- user1
- user2
- user4_vm2_specific
Notes:
Lists are simpler in this use-case. Dictionaries are also possible, but the code would be more complex.
A host can be a member of more groups.
Single dictionary is easily maintainable, potentially created from an external DB (e.g. Forman Manage Users).
The task selecting the list is simple and under the admin's control.

Use ansible to create a vault file and write output to it

I want to create user accounts with corresponding passwords all in a single playbook. To do this I define the users I need for my project and want to generate passwords for them. The attached script creates a password per user and assigns it to the r variable. This all works fine, I can call the items with their passwords. However I would like to save the usernames and passwords into a vault file that is encrypted all from within the playbook. But I can't figure out a way to do this.
Currently I write the output to the userfile.txt (output is a single line of .json, would like to have it in a nicer format) but then I would have to run an extra ansible-vault encrypt command. Is there a way to do this all from within a single playbook?
vars:
users:
- testuser1
- testuser2
tasks:
- name: Generate passwords
script: generate_passwords.py "{{item}}"
register: "r"
args:
executable: python3
with_items: "{{ users }}"
# The following proves that I can call the username and password:
- debug: msg="username={{item.item}}, password={{item.stdout_lines[0]}}"
with_items: "{{r.results}}"
# This saves everything in cleartext, how to do this into a vault file?
- copy:
content: "{{r}}"
dest: userfile.txt

How to create one common playbook-wide writeable variable in ansible?

I'm writing a playbook to create many user accounts across many servers. At the end I want to get output with credentials sorted by username.
I used set_fact with run_once but it seems that defined variable is not playbook-wide.
main.yml
- name: Create users
import_tasks: creation_task.yml
creation_task.yml
- name: Init variable for creds
set_fact:
creds: []
delegate_to: localhost
run_once: true
- name: Create specific users
include: create.yml
with_items:
- input_data
- .......
- name: Print output creds
debug: var=creds
run_once: true
create.yml
- name: some actions that actually create users
....
- name: add creds to list
set_fact:
creds: "{{ creds + [ {'hostname': inventory_hostname,'username':item.name,'password':password.stdout} ]}}"
- name: add splitter to list
set_fact:
creds: "{{ creds + [ '-----------------------------------------------------' ]}}"
This is actually working but i get output sorted by server because (as I think) every host reports his version of "creds" variable.
I'd like to create one variable that will be visible and writeable across all nested plays. So output would be sorted by input data but not hostname. Is it possible?
I'd use the following syntax, to fetch a variable set from a specific host via hostvars:
- debug:
msg: "{{ groups['my_host_name']|map('extract',hostvars,'my_variable_name')|list|first }}"
when: groups['my_host_name']|map('extract',hostvars,'my_variable_name')|list|first|length > 0
Then, you can loop over your hostnames to create an array of values and sort them.
Though, printing all servers hostnames, users & plain text passwords in a text file seems to be a security risk.

Execute ansible task when variable has changed

I have a variables file that defines a number of users:
my_users:
admin:
- admin1
- admin2
user:
- bob
I have a task that adds these users to mongodb. I don't want to execute the task every time but only if the users changed. I tried the following:
- name: add users
command: "<add users>"
when: my_users|changed
However, this does not work as intended. If I add a user, the task is still skipped.
How can I execute a task only if a variable has changed?
Normally you don't do it the way you are trying. Instead, ansible must create the users if they don't already exist. The way to do it with one user is like this:
- name: Check if user george exists
command: "<return a status code of zero if user george exists>"
register: check_george_exists
ignore_errors: yes
always_run: yes
changed_when: False
- name: Create user george
command: "<create user george>"
when: check_george_exists.rc == 0
To do it for many users, see Register variables in with_items loop in Ansible playbook.

Resources