# User Creation: Better way to do this?

**URL:** <https://forum.ansible.com/t/user-creation-better-way-to-do-this/15250>\
**Category:** Ansible Project\
**Created:** [May 15, 2014, 9:41pm UTC](https://forum.ansible.com/t/user-creation-better-way-to-do-this/15250 "2014-05-15T21:41:49Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![Raja\_Mukherjee](https://avatars.discourse-cdn.com/v4/letter/r/54ee81/32.png) [@Raja\_Mukherjee](https://forum.ansible.com/u/Raja_Mukherjee)\
**Post date:** [May 15, 2014, 9:41pm UTC](https://forum.ansible.com/t/user-creation-better-way-to-do-this/15250/1 "2014-05-15T21:41:49Z")

</div>

Newbie to ansible…

Use case: at the create time users are assigned a default password and will be asked to change the password at the first login

What I came up with (in a role)…

- name: Create User  
user: name=“{{ item.username }}”  
groups=“{{ def\_user\_groups | union(item.groups) | join(‘,’) if item.groups is defined  
and item.groups is iterable  
else def\_user\_groups | join(”,“) }}”  
comment=“{{ item.name }}”  
uid=“{{ item.uid }}”  
password=“{{ def\_user\_passwd }}”  
update\_password=on\_create  
append=yes  
state=present  
with\_items:  
add\_users  
tags: ‘users’

- name: List users who has default password  
shell: grep “{{ def\_user\_passwd }}” /etc/shadow | cut -d’:’ -f1  
register: users\_with\_def\_passwd

- name: Force user with default password to change password at next login  
command: chage -d 0 {{ item }}  
with\_items: users\_with\_def\_passwd.stdout.split()

Is there a better way to accomplish this? Feel like I should be able to somehow distinguish the newly created users and be able to do this more elegantly…

Thought I run it by the experts.

Appreciate your feedback.

Thanks

.raja

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan1](https://avatars.discourse-cdn.com/v4/letter/m/5e9695/32.png) [@Michael\_DeHaan1](https://forum.ansible.com/u/Michael_DeHaan1)\
**Post date:** [May 15, 2014, 10:06pm UTC](https://forum.ansible.com/t/user-creation-better-way-to-do-this/15250/2 "2014-05-15T22:06:39Z")

</div>

Unrelated feedback – The groups black magic you have on line 2 is definitely against the Ansible “keep it simple” motif by a large factor and would keep me from using Ansible if I saw it first on a blog post. I’d try to simplify that 🙂

I’d just call the variable groups and do the join on it – and that’s it.

{{ groups.join(“,”) }}

I’m not sure what the other logic does.

Also the new line after the “with\_items” can be removed.

with\_items: add\_users

Further

stdout.split()

can be replaced with

stdout\_lines

Can also be written on the same line.

To your question though –

There is no chage setting for new user creation right now, so what you have is reasonable.

---

<div class="post-metadata">

**Author:** ![James\_Cammarata](https://avatars.discourse-cdn.com/v4/letter/j/7c8e57/32.png) [@James\_Cammarata](https://forum.ansible.com/u/James_Cammarata)\
**Post date:** [May 15, 2014, 10:24pm UTC](https://forum.ansible.com/t/user-creation-better-way-to-do-this/15250/3 "2014-05-15T22:24:16Z")

</div>

I believe you could just register the results of the user add step and then iterate over that:

- name: Create User  
user: …  
register: created\_users  
with\_items: add\_users  
tags:

- users

- name: Force new user to change password at next login  
command: chage -d 0 {{ item }}  
when: item.changed  
with\_items: created\_users.results

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan1](https://avatars.discourse-cdn.com/v4/letter/m/5e9695/32.png) [@Michael\_DeHaan1](https://forum.ansible.com/u/Michael_DeHaan1)\
**Post date:** [May 15, 2014, 10:32pm UTC](https://forum.ansible.com/t/user-creation-better-way-to-do-this/15250/4 "2014-05-15T22:32:29Z")

</div>

To make it somewhat easier, I’d be ok with modifications that made the user module return an added: True/False or something to compliment changed.

---

<div class="post-metadata">

**Author:** ![Raja\_Mukherjee](https://avatars.discourse-cdn.com/v4/letter/r/54ee81/32.png) [@Raja\_Mukherjee](https://forum.ansible.com/u/Raja_Mukherjee)\
**Post date:** [May 15, 2014, 11:06pm UTC](https://forum.ansible.com/t/user-creation-better-way-to-do-this/15250/5 "2014-05-15T23:06:16Z")

</div>

Michael,

Appreciate you taking the time to review and providing feedback…I am all for simplifying it. Here’s how I got to the group statement…

Every users will belong to a set of default groups, so if this list changes I don’t have to edit it for every users. e.g.

def\_user\_groups:

- ‘cdrom’
- ‘dip’
- ‘plugdev’
- ‘sambashare’

If at a later time, all users have to added to a new “public” group, I can simply modify this variable and rerun the user role to all hosts.

- And then there are user specific group, e.g. additionally raja will be a sudo user

add\_users:

- username: raja  
name: Raja Mukherjee  
groups:

- ‘sudo’

- ‘adm’  
uid: 1002  
ssh\_key\_files:

- id\_rsa.pub

To accommodate this, my first iteration was

groups="{{ def\_user\_groups | union(item.groups) | join(‘,’) }} - simply merge the two lists

Well that broke the variable syntax when “groups” attribute is missing in variable declaration - for users who will only have the default groups.

- username: andrew  
name: Andrew McCarthy  
uid: 1002

ssh\_key\_files:

- id\_rsa.pub

To accommodate that my group line evolved to  
groups="{{ def\_user\_groups | union(item.groups) | join(‘,’) if item.groups is defined else def\_user\_groups | join(‘,’) }}

Otherwise I was getting an error saying that the group attribute is undefined. Extra check for iterator came later to accommodate syntax when “groups” is defined but empty

- username: andrew  
name: Andrew McCarthy  
groups:  
uid: 1002

ssh\_key\_files:

- id\_rsa.pub

This use case (empty attribute) is not that important, and I will definitely skip that.

Is there a better way to accommodate/simplify this line?

groups="{{ def\_user\_groups | union(item.groups) | join(‘,’) if item.groups is defined else def\_user\_groups | join(‘,’) }}

Or any alternate design suggestion?

I already made the other suggested changes. Having fun learning new stuff.

Once again thank you for your time and help.

.raja

---

<div class="post-metadata">

**Author:** ![Raja\_Mukherjee](https://avatars.discourse-cdn.com/v4/letter/r/54ee81/32.png) [@Raja\_Mukherjee](https://forum.ansible.com/u/Raja_Mukherjee)\
**Post date:** [May 15, 2014, 11:11pm UTC](https://forum.ansible.com/t/user-creation-better-way-to-do-this/15250/6 "2014-05-15T23:11:23Z")

</div>

James,

Thanks for taking the time and reviewing the code…

In your suggested change, wouldn’t it trigger a chage for any changes? For example, appending a new group for a user will then force them to change password? Unless I am misunderstanding…

.raja

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan1](https://avatars.discourse-cdn.com/v4/letter/m/5e9695/32.png) [@Michael\_DeHaan1](https://forum.ansible.com/u/Michael_DeHaan1)\
**Post date:** [May 16, 2014, 12:15am UTC](https://forum.ansible.com/t/user-creation-better-way-to-do-this/15250/7 "2014-05-16T00:15:56Z")

</div>

Untested:

vars:  
my\_groups: “{{ def\_user\_groups | union(item.groups|default()) | join(”,") }}

And keep your playbook clean:

{{ my\_groups }}

Ansible will lazy-evaluate the variables.

But really even this is massively overcomplicated.

First add the user with the defined groups in with\_items, if any, and then call the module again to append the groups from the other list, passing append=yes.

---

<div class="post-metadata">

**Author:** ![Raja\_Mukherjee](https://avatars.discourse-cdn.com/v4/letter/r/54ee81/32.png) [@Raja\_Mukherjee](https://forum.ansible.com/u/Raja_Mukherjee)\
**Post date:** [May 16, 2014, 9:04pm UTC](https://forum.ansible.com/t/user-creation-better-way-to-do-this/15250/8 "2014-05-16T21:04:08Z")

</div>

Michael,

Once again, thanks for your continued support.

I did not get this.

vars:  
my\_groups: “{{ def\_user\_groups | union(item.groups|default()) | join(”,") }}

Is there a provision to provide vars inside loop?

However, it did give me an idea and I was able to rewrite the variable initialized to ‘’ and remove the conditional statements from the tasks.

roles/users/defaults/main.yml

def\_user\_passwd: ‘$6$RGIwNOafbq$i870.hwdIBRoMOXSLjGZSDdZxl79sMCG7jxxv2nYqtCQWr26L6tKBnoRUIiYkc5xGFgg7oJJ/NhLQBsxpHGqh1’

def\_user\_groups:

- ‘cdrom’
- ‘dip’
- ‘plugdev’
- ‘sambashare’

roles/users/vars/main.yml

add\_users:

- username: mimi  
name: Mimi Mukherjee  
groups:

- ‘sudo’

- ‘adm’  
uid: 1002

- username: andrew  
name: Andrew Mukherjee  
groups:   
uid: 1003

And the task

roles/users/tasks/main.yml

- name: Create User  
user: name=“{{ item.username }}”  
groups=“{{ def\_user\_groups | union(item.groups) | join(‘,’) }}”  
comment=“{{ item.name }}”  
uid=“{{ item.uid }}”  
password=“{{ def\_user\_passwd }}”  
update\_password=on\_create  
append=yes  
state=present  
with\_items: add\_users  
tags: ‘users’

- name: List users who has default password  
shell: grep “{{ def\_user\_passwd }}” /etc/shadow | cut -d’:’ -f1  
register: users\_with\_def\_passwd  
tags: ‘users’

- name: Force user with default password to change password at next login  
command: chage -d 0 {{ item }}  
with\_items: users\_with\_def\_passwd.stdout\_lines  
tags: ‘users’

Thanks again

.raja

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan1](https://avatars.discourse-cdn.com/v4/letter/m/5e9695/32.png) [@Michael\_DeHaan1](https://forum.ansible.com/u/Michael_DeHaan1)\
**Post date:** [May 19, 2014, 3:02am UTC](https://forum.ansible.com/t/user-creation-better-way-to-do-this/15250/9 "2014-05-19T03:02:58Z")

</div>

“Is there a provision to provide vars inside loop?”

You’ve lost me on this part - though glad to see things got cleaned up!

---

<div class="post-metadata">

**Author:** ![Raja\_Mukherjee](https://avatars.discourse-cdn.com/v4/letter/r/54ee81/32.png) [@Raja\_Mukherjee](https://forum.ansible.com/u/Raja_Mukherjee)\
**Post date:** [May 19, 2014, 2:02pm UTC](https://forum.ansible.com/t/user-creation-better-way-to-do-this/15250/10 "2014-05-19T14:02:17Z")

</div>

Thanks Michael, appreciate all your help…

.raja

---

<div class="post-metadata">

**Author:** ![Raja\_Mukherjee](https://avatars.discourse-cdn.com/v4/letter/r/54ee81/32.png) [@Raja\_Mukherjee](https://forum.ansible.com/u/Raja_Mukherjee)\
**Post date:** [May 19, 2014, 2:03pm UTC](https://forum.ansible.com/t/user-creation-better-way-to-do-this/15250/11 "2014-05-19T14:03:28Z")

</div>

Somehow I missed this post. This would be really helpful…

Thanks

.raja
