Hello, I was doing lab creating users and setting the password after a prompt.
I understand loop(module?) puts all the users in the variables, but I have no idea about name: "{{ item }}"
what does exactly name: "{{ item }}" do?
in the line of the shell module, I could understand if the command was [passwd --stdin " {{ users }}"] but I've got no idea where the "{{ item }}" came from and the role
Please help!
Thanks!
Hello @spurs !
Thanks for reaching out!
The {{ item }} variable is a loop variable that contains the value of the current item in the loop. When the playbook is executed, the value of the item variable will be replaced with the name of each user in the users variable.
means that : name: "{{ item }}" with loop: "{{ users }}" will create a loop ( iterate over ) over the items in the users variable. It will run for the number of items in the users list - here 3 times - lisa, lucy & lori.
Same way - shell: echo "{{ item }}" | passwd --stdin "{{ item }}" - will be executed thrice to set the password for each user in the users variable. The echo command is used to print the value of the item variable to the standard output. The passwd --stdin command is used to change the password of the user specified by the standard input.
As @laurpaum mentioned :
Refer : https://docs.ansible.com/archive/ansible/2.6/user_guide/playbooks_loops.html
@spurs That wont work ( If I got your query correctly ) - you might get error like this :
What you are suggesting will work for a single user but for multiple users you must use a loop as suggested here in the official docs :
Refer : https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_loops.html#standard-loops
@Chetan_Tiwary_said: "What you are suggesting will work for a single user but for multiple users you must use a loop"
Correct. This is specifically because the name option for the ansible.builtin.user module expects its value to be a string with a single user name in it, and doesn't accept a list. From the docs:
= name
Name of the user to create, remove or modify.
aliases: [user]
type: str
Other modules might differ. For example, ansible.builtin.yum *does* accept a list for their name option, in that case it's a list of package names. You have to check the module's documentation (with ansible-doc or ansible-navigator doc) to see what a particular module expects. From the docs, you'll see that it does accept a list:
- name
A package name or package specifier with version, like
`name-1.0'.
Comparison operators for package version are valid here `>',
`<', `>=', `<='. Example - `name>=1.0'
If a previous version is specified, the task also needs to
turn `allow_downgrade' on. See the `allow_downgrade'
documentation for caveats with downgrading packages.
When using state=latest, this can be `'*'' which means run
`yum -y update'.
You can also pass a url or a local path to a rpm file (using
state=present). To operate on several packages this can accept
a comma separated string of packages or (as of 2.0) a list of
packages.
aliases: [pkg]
default: null
elements: str
type: list
This makes sense, if you think about it. The ansible.builtin.user module is pretty much set up to process one user at a time like /usr/bin/useradd; you might be setting shells, home directories, UIDs, and so on when you're processing with that module and they might vary by user. The ansible.builtin.yum module might accept a list of packages, especially if you're meeting dependencies and so on, just like /usr/bin/yum.
Thanks @bonnevil for the detailed explanation !
The variable name "item" is the default loop variable name. At each iteration of the loop, this variable contains the value of the current element in the list.
In your example, the "create the user" task will be executed with a value of "lisa" for the variable "item" during the first iteration, then "lucy" for the second, and so on.
The variable name can be changed using loop_control options. See the loop documentation for more detailed explanation (especially "adding controls to loops" section).
Hello @spurs !
Thanks for reaching out!
The {{ item }} variable is a loop variable that contains the value of the current item in the loop. When the playbook is executed, the value of the item variable will be replaced with the name of each user in the users variable.
means that : name: "{{ item }}" with loop: "{{ users }}" will create a loop ( iterate over ) over the items in the users variable. It will run for the number of items in the users list - here 3 times - lisa, lucy & lori.
Same way - shell: echo "{{ item }}" | passwd --stdin "{{ item }}" - will be executed thrice to set the password for each user in the users variable. The echo command is used to print the value of the item variable to the standard output. The passwd --stdin command is used to change the password of the user specified by the standard input.
As @laurpaum mentioned :
Refer : https://docs.ansible.com/archive/ansible/2.6/user_guide/playbooks_loops.html
Thanks for the answer!
instead of name: "{{ item }}" with loop: "{{ users }}", what about name: "{{ users }}"? Will it work as well??because vars itself can identify all the values (lisa, lucy, lori)
@spurs That wont work ( If I got your query correctly ) - you might get error like this :
What you are suggesting will work for a single user but for multiple users you must use a loop as suggested here in the official docs :
Refer : https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_loops.html#standard-loops
@Chetan_Tiwary_said: "What you are suggesting will work for a single user but for multiple users you must use a loop"
Correct. This is specifically because the name option for the ansible.builtin.user module expects its value to be a string with a single user name in it, and doesn't accept a list. From the docs:
= name
Name of the user to create, remove or modify.
aliases: [user]
type: str
Other modules might differ. For example, ansible.builtin.yum *does* accept a list for their name option, in that case it's a list of package names. You have to check the module's documentation (with ansible-doc or ansible-navigator doc) to see what a particular module expects. From the docs, you'll see that it does accept a list:
- name
A package name or package specifier with version, like
`name-1.0'.
Comparison operators for package version are valid here `>',
`<', `>=', `<='. Example - `name>=1.0'
If a previous version is specified, the task also needs to
turn `allow_downgrade' on. See the `allow_downgrade'
documentation for caveats with downgrading packages.
When using state=latest, this can be `'*'' which means run
`yum -y update'.
You can also pass a url or a local path to a rpm file (using
state=present). To operate on several packages this can accept
a comma separated string of packages or (as of 2.0) a list of
packages.
aliases: [pkg]
default: null
elements: str
type: list
This makes sense, if you think about it. The ansible.builtin.user module is pretty much set up to process one user at a time like /usr/bin/useradd; you might be setting shells, home directories, UIDs, and so on when you're processing with that module and they might vary by user. The ansible.builtin.yum module might accept a list of packages, especially if you're meeting dependencies and so on, just like /usr/bin/yum.
Thank you so much.
Basically, my idea can be used when there's a variable with one user name.
Then I can use name: {{ variable }} without using name: {{ item }} and loop.
On the other hand, if there are multiple users in the variable, I need to use name: {{ item }} with loop: {{ variable }} as {{ item }} will call a username one by one from the variable
Thanks @bonnevil for the detailed explanation !
Red Hat
Learning Community
A collaborative learning environment, enabling open source skill development.