-1

I'm trying to write an Ansible playbook which will allow me to define a list of groups to apply to a list of users, across a list of defined servers.

It seems to be getting close to working except the users being created are the literal list value such as ['mike'] in /etc/passwd.

How do I tell Ansible to use the value of the which_users?

---
- hosts: all
  gather_facts: false
  vars:
    local_group_info:

      - name : developer group
        which_users  :
          - mike
          - george
        which_groups :
          - adm
          - www-data
        on_hosts  :
          - test.sv1.org
          - punchy.sv1.org

      - name: admin group
        which_users:
          - kelly
        which_groups:
          - sudo
        on_hosts  :
          - test.sv1.org

  tasks:
    - name: Add users to local groups if current host matches
      when: inventory_hostname in item.0.on_hosts or 'all' in item.0.on_hosts
      debug:
        msg: "user {{ item.0.which_users }} should be in group {{ item.1 }}"
      with_subelements:
        - "{{ local_group_info }}"
        - which_groups

output:

PLAY [all] **************************************************************************************************************************

TASK [Add users to local groups if current host matches] ****************************************************************************
ok: [test.sv1.org] => (item=[{u'which_users': [u'mike', u'george'], u'name': u'developer group', u'on_hosts': [u'test.sv1.org', u'punchy.sv1.org']}, u'adm']) => {
    "msg": "user [u'mike', u'george'] should be in group adm"
}
ok: [test.sv1.org] => (item=[{u'which_users': [u'mike', u'george'], u'name': u'developer group', u'on_hosts': [u'test.sv1.org', u'punchy.sv1.org']}, u'www-data']) => {
    "msg": "user [u'mike', u'george'] should be in group www-data"
}
ok: [test.sv1.org] => (item=[{u'which_users': [u'kelly'], u'name': u'admin group', u'on_hosts': [u'test.sv1.org']}, u'sudo']) => {
    "msg": "user [u'kelly'] should be in group sudo"
}

PLAY RECAP **************************************************************************************************************************
test.sv1.org       : ok=1    changed=0    unreachable=0    failed=0   

2 Answers 2

0

This doesn't work like this as you have three items to loop over in two levels (List of user classes in the first level, list of unix groups and list of users in the second). This is a part where Ansible tends to get a bit complicated

You can split this off in two parts:

  • A role that creates a list of users in a group
  • Your task that iterates over the list of user classes and unix groups.

Something like this:

  1. roles/testrole/tasks/main.yml

    - name: Creating list of users in named groups
      tags: ['testing']
      debug:
          msg: "User {{ item2 }} should be in group {{ current_group }}"
      loop_control:
          loop_var: item2
      with_items:
        - "{{ current_userlist }}"
    
  2. your_playbook.yml

    - name:          Mimimal playbook
      hosts:         all
      tags: ['testing']
    
      tasks:
      - include_role:
        name:    testrole
        tags: ['testing']
        vars:
          - current_group: "{{ item.1 }}"
          - current_userlist: "{{ item.0.userlist }}"
        with_subelements:
          - "{{ userclass }}"
          - grouplist
    

and the following variable definition:

userclass:
    - name: Testgroup 1
      userlist:
          - homer
          - bart
      grouplist:
          - adm
    - name: Testgroup 2
      userlist:
          - lisa
          - maggie
          - marge
      grouplist:
          - exec
          - board

This results in the following:

PLAY [Mimimal playbook] ***********************************************************************************************************************************************************

TASK [include_role : testrole] ****************************************************************************************************************************************************

TASK [testrole : Creating list of users in named groups] **************************************************************************************************************************
ok: [ansible.example.com] => (item=homer) => {
    "msg": "User homer should be in group adm"
}
ok: [ansible.example.com] => (item=bart) => {
    "msg": "User bart should be in group adm"
}

TASK [testrole : Creating list of users in named groups] **************************************************************************************************************************
ok: [ansible.example.com] => (item=lisa) => {
    "msg": "User lisa should be in group exec"
}
ok: [ansible.example.com] => (item=maggie) => {
    "msg": "User maggie should be in group exec"
}
ok: [ansible.example.com] => (item=marge) => {
    "msg": "User marge should be in group exec"
}

TASK [testrole : Creating list of users in named groups] **************************************************************************************************************************
ok: [ansible.example.com] => (item=lisa) => {
    "msg": "User lisa should be in group board"
}
ok: [ansible.example.com] => (item=maggie) => {
    "msg": "User maggie should be in group board"
}
ok: [ansible.example.com] => (item=marge) => {
    "msg": "User marge should be in group board"
}

PLAY RECAP ************************************************************************************************************************************************************************
ansible.example.com         : ok=3    changed=0    unreachable=0    failed=0

Other variants would exist. You could just iterate over the user classes in the play and then rewrite the role to use with_nested with both users and unix groups.

0

You can create a mapping (first filtering the local_group_info list for the hosts you specified in when, then concatenating the Cartesian product of the which_users and which_groups for each of the filtered elements) and iterate over it:

- name: Create user to group mapping
  set_fact:
    user_group_mapping: "{{ user_group_mapping | default([]) + item.which_users | product(item.which_groups) | list }}"
  loop: "{{ local_group_info | json_query(query) }}"
  vars:
    query: "@[?contains(on_hosts, `{{ inventory_hostname }}`) || contains(on_hosts, `all`)].{which_users: which_users, which_groups: which_groups}"

- name: Add users to local groups if current host matches
  debug:
    msg: "user {{ item.0 }} should be in group {{ item.1 }}"
  loop: "{{ user_group_mapping }}"

Depending on your objectives (whether you want to proceed or fail with incomplete data) you might, or might not add default({}) filter to the item.which_users and item.which_groups.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .