Centralized User List

Good evening all!

I am new to Ansible (only 2 days in), but am quite excited by the prospects.

I have a laundry list of questions but I figured it’d be best to separate them into multiple posts to help people searching these lists in the future.

The first question is:…

  • After much searching, I found an archived exchange that points out a way to have a list of users in a group_vars/xxxx.yaml file, and then in a “add_users.yaml” playbook, do something like the following:

1 —
2 - hosts: all
3 vars_files:
4 - /etc/ansible/group_vars/[some-group-name-goes-here]/users.yaml
5 tasks:
6 - name: Create user.
7 user: home=/home/{{ item }} name={{ item }} shell=/bin/bash state=present
8 with_items: users
9 - name: copy per-user ssh key (authorized_keys2) to the destination server
10 action: copy src=/usr/share/ansible/files/ssh/{{ item }}/authorized_keys2 dest=/home/{{ item }}/.ssh/authorized_keys2 mode=755
11 with_items: users

This works quite well (thank to to whomever it was who posted that solution). However, I personally don’t like the idea of having to maintain multiple files of users per group/pattern. What I’d like to be able to do, is the same way I have 1 hosts file (/etc/ansible/hosts) that has all of my hosts and groups in one nicely organized file, I would like to have one giant users.yaml which has different groups of users (ie: one for the database boxes, one for the staging boxes, one for the production boxes, etc.)

Perhaps I’m thinking of this the wrong way, but it seems like something that should be easy to do. This is kind of a “global variable” concept, I’d just like to centralize the management of this.

Any thoughts on the syntax to properly do this? Thanks!!! :o)

Let me show you how I do this.

I have a vars file with al my users containing:

1/ A list of users with config details:

user:
paul:
description: Paul McCartney
uid: 1001
ringo
description: Ringo Star
uid: 1002

2/ several lists of users, e.g.

users_apple_admin:

  • paul
  • john

users_apple_dev:

  • ringo
  • george

Then, in the inventory, e.g. for the group “apple”, I define:

users_admin:

  • “{{users_apple_admin}}”

users_dev:

  • “{{users_apple_dev}}”
  • "{{users_virgin_dev}}

Finally, in a playbooks role, where I create all users, I call the role with:

  • role: real_user
    real_user_list:
  • “{{users_admin}}”
  • “{{users_dev}}”

and in the role, the create user tasks uses this loop

action:
module: user
name: “{{ item }}”
comment: “{{ user[item][‘description’] }}”
uid: “{{ user[item][‘uid’] }}”
with_flattened: real_user_list

Elsewhere, where I create groups, I’ll do something like this

  • name: Assign Developer roles
    action:
    module: user
    name: “{{ item }}”
    groups: “{{ lookup(‘flattened’, groups_dev) }}”
    append: “yes”
    state: present
    with_flattened: users_dev

Where groups_dev is set somewhere in the inventory, and is a list of groups that developers should be member of, for the group where it was set.

groups_dev:

  • developers
  • tomcat_user

Hope this helps,

Serge

First off, allow me to thank you for your post. I was able to get what I wanted by looking over your code. However, perhaps I am grossly over simplifying things, but here’s my set up now:

$ cat /etc/ansible/users.yaml
all_users:
- user1
- user2
- user3
- user4
- user5
- user6

Ops:
- user1
- user2
- user3
- user4

databaseTeam:
- user5
- user6

Then, in my add_users.yaml file:


- hosts: all
vars_files:
- /etc/ansible/users.yaml
tasks:
- name: Create user.
user: home=/home/{{ item }} name={{ item }} shell=/bin/bash state=present
with_items: Ops
- name: copy per-user ssh key (authorized_keys2) to the destination server
action: copy src=/usr/share/ansible/files/ssh/{{ item }}/authorized_keys2 dest=/home/{{ item }}/.ssh/authorized_keys2 mode=755
with_items: Ops

This works, and I like it becuase I have one centralized users.yaml file to edit whenever someone joins/leaves.

The only question remaining I have, is how to make the add_users.yaml file even more generic. What I’d like to do is something like:


- hosts: all
vars_files:
- /etc/ansible/users.yaml
tasks:
- name: Create user.
user: home=/home/{{ item }} name={{ item }} shell=/bin/bash state=present
with_items: accounts_to_add
- name: copy per-user ssh key (authorized_keys2) to the destination server
action: copy src=/usr/share/ansible/files/ssh/{{ item }}/authorized_keys2 dest=/home/{{ item }}/.ssh/authorized_keys2 mode=755
with_items: accounts_to_add

and then run: ansible-playbook add_users.yaml -u root --check --extra-vars “accounts_to_add=databaseTeam”

to only add the databaseTeam.

Basically, I’m looking to make this thing as modular as humanly possible, and hardcode as little as possible.
(Note: the above throws an error and does not “expand” on accounts_to_add)

TASK: [Create user.] **********************************************************
changed: [xxxxxxxxx] => (item=databaseTeam)

TASK: [copy per-user ssh key (authorized_keys2) to the destination server] ****
failed: [xxxxxxxxx] => (item=databaseTeam)

OK, I got it working, but would still like to see if someone could view and see if it’s the “right” way of doing it. Since I’m still learning, I’d like to learn the proper way of doing it (I’m assuming this has something to do with roles?

  1. users.yaml

$ cat /etc/ansible/users.yaml
all_users:

  • user1

  • user2

  • user3

- user4
- user5
- user6

Ops:

  • user1

  • user2

  • user3

- user4

databaseTeam:
- user5
- user6

  1. add_users.yaml

1 —
2 - hosts: all
3 vars_files:
4 - /etc/ansible/users.yaml
5 tasks:
6 - name: Create user.
7 user: home=/home/{{ item }} name={{ item }} shell=/bin/bash state=present
8 with_items: $accounts_to_add
9 - name: copy per-user ssh key (authorized_keys2) to the destination server
10 action: copy src=/usr/share/ansible/files/ssh/{{ item }}/authorized_keys2 dest=/home/{{ item }}/.ssh/authorized_keys2 mode=755
11 with_items: $accounts_to_add

  1. xyz_boxes.yaml

" 11 with_items: $accounts_to_add"

Legacy variable usage, which 1.4 will rightfully warn you about. Correct:

with_items: accounts_to_add

I had thought I had read that that was legacy, however for some reason when I did just "accounts_to_add" it was taking it literally and not as a variable to expand.

Will take another look.

As it turns out, the updates repo in FC19 only has 1.3.4 as the latest version, which might be why it wasn’t working the other way.

I just followed this example with:

ansible 1.5 (devel 7aa35d64c2) last updated 2013/12/04 19:15:46 (GMT +000)

and it only works for me with the $ in front of accounts_to_add.

GATHERING FACTS ***************************************************************
ok: [ubuntu-01]

TASK: [Add group {{item.name}}] ***********************************************
fatal: [ubuntu-01] => One or more undefined variables: ‘unicode object’ has no attribute ‘name’

Thanks for the follow up Pete!

I have not gotten a chance to check any further into this, especially since it’s working with the $$ and not throwing warnings, I’ve moved ahead with this solution until I can upgrade / it starts warning.

However it’s interesting that your 1.5 version still functions the same as my 1.3.x version.

“and it only works for me with the $ in front of accounts_to_add”

Are you sure you are running 1.5? (see ansible --version?)

I use list variables without a prefix all of the time and it’s fine.

with_items: imalist

etc

FC19 just got 1.4.1:

$ ansible --version
ansible 1.4.1

and I still can only get it to work with $ in front:

TASK: [Create user.] **********************************************************
changed: [server1] => (item=Ops)

(vs)

TASK: [Create user.] **********************************************************
changed: [server1] => (item=user1)
changed: [server1] => (item=user2)
changed: [server1] => (item=user3)
changed: [server1] => (item=user4)