What is wrong when iterating over a collection in ansible?
When executing ansible-playbook -i "localhost," -c local main.yml the error is
- name: echo kerberos
shell: echo "addprinc -pw {{ item.password }} {{ item.username }}"
^ here
We could be wrong, but this one looks like it might be an issue with
missing quotes. Always quote template expression brackets when they
start a value. For instance:
with_items:
- {{ foo }}
Should be written as:
with_items:
- "{{ foo }}"
But for me it looks like I am already correctly following these rules.
Here my minimal example:
main.yml
---
- hosts: all
tasks:
- name: echo kerberos
shell: echo "addprinc -pw {{ item.password }} {{ item.username }}"
with_items: "{{ users }}"
users.yml
---
users:
- username: test_user
password: test_user
sn: User
uid: 50001
gid: 100
- username: test_user1
password: test_user
cn: Test User1
sn: User1
uid: 50002
gid: 100
user_groups:
- cn: access1
gid: 100001
users:
- test_user1
You should be careful with padding in YAML:
---
- hosts: all
tasks:
- name: echo kerberos
shell: echo "addprinc -pw {{ item.password }} {{ item.username }}"
with_items: "{{ users }}"
shell and with_items are aligned with name.
Related
This is playbook that creates users.I want to create user(that takes username and uid) accoording to userlist.yml but passwords will be taken in passwords.yml. But don't know exact syntax
- name: add users
hosts: new
vars_files:
- userlist.yml
- passwords.yml
tasks:
- name: adduser
user:
name: "{{ item.username }}"
password: "{{ item.password | password_hash('sha512') }}"
uid: "{{item.uid}}"
state: present
with_items:
?????????????
#userlist.yml
users:
- username: xman
uid: 8254
- username: yman
uid: 8252
- username: zman
uid: 8258
#passwords.yml
password: devops2019!
Given "passwords will be taken in passwords.yml". For example
#passwords.yml
password:
- 'devops2019!'
- 'devops2020!'
- 'devops2021!'
The task below does the job
- name: adduser
user:
name: "{{ item.0.username }}"
password: "{{ item.1 | password_hash('sha512') }}"
uid: "{{ item.0.uid }}"
state: present
loop: "{{ users | zip(password) | list }}"
(not tested)
I am writing a playbook to create a user if it does not exist. If it exist then it ask again for a new username. It must ask again for new user input. But var_promt runs only one time. How can I do that?
- name: An example prompting playbook
hosts: all
vars_prompt:
- name: username
prompt: "Enter a username"
tasks:
- name: Print out your input
debug:
msg: "You provided the {{ username }} for the prompt"
- name: User Exist
command: grep {{ username }} /etc/passwd
ignore_errors: yes
register: user_exist
- name: User Existance output
debug: var=user_exist.stdout
- name: User creation
user: name={{ username }}
when: user_exist.stdout is not match(".*:.*:.*:.*::.*:")
- name: Display Message
debug:
msg: "User {{ username }} already exists"
when: user_exist.stdout is match(".*:.*:.*:.*::.*:")
- name: User check
command: id {{ username }}
ignore_errors: yes
register: ID
- name: UserID of Username
debug: var=ID.stdout
name: An example prompting playbook
hosts: localhost
vars_files:
/root/users.yml
tasks:
name: Create deploy user
user:
name: "{{ item.name }}"
shell: "{{ item.shell }}"
password: "{{ lookup('password', '/tmp/{{ item.name }}.txt chars=ascii_letters') | password_hash('sha512') }}"
createhome: yes
groups: "{{ item.groups }}"
update_password: on_create
with_items: "{{ users }}"
I've got an ansible playbook for adding over 50 ssh-users for a packer ami build.
Here is how my /playbooks/roles/users/tasks/create_user.yml: looks like.
---
- name: "User {{ item.name }}"
user:
comment: "Add {{ item.name }} account"
name: "{{ item.name }}"
home: "/data/companies/project/{{ item.name }}"
state: present
uid: "{{ item.uid }}"
group: company
groups: company
shell: /sbin/nologin
state: present
generate_ssh_key: no
password: "{{ item.password }}"
- name: "Create home directory for {{ item.name }}"
file:
path: "/data/companies/project/{{ item.name }}"
state: directory
owner: "{{ item.name }}"
group: company
mode: 0700
Here's how /playbooks/roles/users/vars/main.yml file looks like
---
location: UK
users:
- name: user1
password: $6$8T8lH2vS$JKIdqkQmHUHR/s75RYMguPyHTisnNrXIPOjJ9IWxMHB4LY9PJX.3rgkmfLCWAHDi5VYZno2ntlYm7Kkdy0iAZ.
uid: 601
location: UK
- name: user2
password: $6$8T8lH2vS$JKIdqkQmHUHR/s75RYMguPyHTisnNrXIPOjJ9IWxMHB4LY9PJX.3rgkmfLCWAHDi5VYZno2ntlYm7Kkdy0iAZ
uid: 602
location: USA
Here's how my "/playbooks/roles/users/tasks/main.yml" looks like
---
- name: Create users based on location
include: create_users.yml
loop: "{{ users | selectattr('location', 'equalto', location) | list }}"
When the corresponding packer build has been run there are no errors but user1,user2 and their attributes are not getting created.
amazon-ebs: TASK [: Create users based on location] ***********************************
amazon-ebs:
amazon-ebs: PLAY RECAP *********************************************************************
amazon-ebs: default : ok=10 changed=7 unreachable=0 failed=0
amazon-ebs:
Please can someone help me understand as to why users are not getting created? Thanks
This is commonly approached through the use of variables and loops. Extract all the variable stuff out into a list variable, containing dictionaries of params, then use a loop to read through and apply. So based on your role approach:
Create a task file containing the two tasks to run - /playbooks/roles/users/tasks/create_user.yml:
---
- name: User "{{ item.name }}"
user:
comment "{{ item.name }} company account"
name: "{{ item.name }}"
home: "/data/company/{{ item.name }}"
state: present
uid: 666
group: company
groups: company
shell: /bin/bash
state: present
generate_ssh_key: no
password: "{{ item.password }}"
- name: "Create home directory for {{ item.name }}"
file:
path: "/data/company/{{ item.name }}"
state: directory
owner: "{{ item.name }}"
group: company
mode: 0700
Create a vars file containing your users - /playbooks/roles/users/vars/main.yml:
---
location: UK # This will be your default. It can be overridden in a variety of places
users:
- name: user1
password: <some password>
location: US
- name: user2
password: <some password>
location: UK
- name: user3
password: <some password>
location: UK
then in /playbooks/roles/users/tasks/main.yml:
---
- name: Create users based on location
include: create_user.yml
loop: "{{ users | selectattr('location', 'equalto', location) | list }}"
Hopefully most of it is self explanatory. Because you are using a role, by placing the users variable in /playbooks/roles/users/vars/main.yml, the variable is automatically made available. The users | selectattr('location', 'equalto', location) expression, takes the user variable and filters the list to only include objects where the 'location' element is equal to the value specified in the 'location' variable.
Variables
Loops
Roles
Some additional hints, you can use defaults too.
Also, in case you want to protect the encrypted passwords, you can store them in Ansible Vault:
users.yml example:
users:
- name: user1
uid: 666
group: group1
groups: [allusers]
comment: User One
home: /home/user1
shell: /bin/bash
passwords: "{{ vault_passwords }}"
The vault file you crypt with 'ansible-vault' command looks like (decrypted):
passwords:
- name: user1
password: $6$509875346RH.RAaVNW2iWtf/QJ4zUGaJiEyh.
playbook included tasks file example:
- name: Set up user accounts
user:
name: "{{ item.name }}"
create_home: '{{ item.createhome | default("no") }}'
uid: "{{ item.uid }}"
group: "{{ item.group }}"
state: '{{ item.state | default("present") }}'
comment: '{{ item.comment | default("Ansible created comment") }}'
home: "{{ item.home }}"
shell: '{{ item.shell | default("/bin/bash") }}'
with_items: "{{ users }}"
- name: Set up user account passwords
user:
name: "{{ item.name }}"
password: '{{ item.password | default("*") }}'
with_items: "{{ passwords }}"
I am trying to check if inventory_hostname is in a list into an imported variable.
vars/users.yml file:
---
users:
- username: user1
comment: "User 1"
group: admin
password: "sha password"
keys:
active:
- "ssh-rsa etc"
admin: yes
- username: user2
comment: "User 2"
group: users
groups: deployer
keys:
active:
- "ssh-rsa etc"
hosts:
user:
- host1
- host2
deployer:
- host3
I want to execute a task only if inventory_hostname is into any of hosts lists (user, deployer, others ...).
I tried this:
- name: Create users
user:
name: "{{ item.username }}"
comment: "{{ item.comment | default('User {{item.username}}') }}"
password: "{{ item.password | default('!') }}"
state: "{{ item.state | default('present') }}"
shell: "{{ item.shell | default('/bin/bash') }}"
group: "{{ item.group | default('users') }}"
with_items: '{{ users }}'
when: item.username is defined and ((item.admin is defined and item.admin == True) or (item.hosts is defined and item.hosts.user is defined and inventory_hostname in item.hosts.user)
It works for user1 (which have admin enabled) but not for user2 (if this play is executed on host1 which is included into user2's hosts.user list).
Well .. I tried your code snippet and it works well for both users. Only thing which can make it fail is that hostnames in item.host.user are not matching the inventory_hostname. You can try to debug the inventory_hostname before this task to see what are the inventory hostnames read by ansible and whether you have specified them correctly in item.host.user list.
- debug: var=inventory_hostname
First thing first - I'm not an Ansible wiz and I guess there is a better way to do this, but this is how I managed to do this.
I needed to create users on Linux servers, I used this to read the users parameters from a file and create all by using 'with_items'.
This worked perfectly.
I wanted to add an option to create only one user from the list.
This is my yml script:
---
- hosts: all
user: deploy
become: yes
tasks:
- include_vars: ../variables/users.yml
# - command: echo {{ Guser }}
- debug: msg={{ users }}
- name: Create DevOps team users
user: name={{ item.username }} shell=/bin/bash createhome=yes comment='Created by Ansi' groups={{ item.use_sudo }} uid={{ item.use_uid }} group={{ item.use_group }} state=present
ignore_errors: yes
with_items:
- '{{ Guser }}'
when: Guser is defined
And this is how I run it:
ansible-playbook --extra-vars "Guser=gilil2" -l myserver /home/devops/roles/create-users/tasks/create_user_by_name.yml -u deploy
Snip from my variables/users.yml
---
users:
- username: gilil
use_sudo:
use_uid: 2005
use_group: users
- username: gilil2
use_sudo:
use_uid: 1010
use_group: users
- username: gilil3
use_sudo:
use_uid: 1011
use_group: users
Use selectattr Jinja2 filter:
- name: Create DevOps team users
user: name={{ item.username }} shell=/bin/bash createhome=yes comment='Created by Ansi' groups={{ item.use_sudo }} uid={{ item.use_uid }} group={{ item.use_group }} state=present
ignore_errors: yes
with_items: "{{ users | selectattr('username','equalto',Guser|default('uknown')) | list }}"
This will reduce original users list to a list of elements where username attribute equals to Guser vars' value or unknown if Guser is undefined. I assume that there are no user with uknown username, so selectattr can generate empty list in this case.