1

I've been looking around the Interwebs for a solution to one of my playbooks, but I believe I might be adding more confusion than figuring out a solution. Rather than heading into the weeds any further, I'm hoping someone from here can put me back on the right path.

In it's simplest form, my playbook needs to create an AD group and then add member(s) to the newly created AD group based on variables it receives from a request form, which does not seem terribly difficult... until I want to add more than one or five from another variable. The variable req_ad_user_name will always need to be a member of the group. The var, req_ad_user_others, is an optional field on the form. So, it may have a bunch of usernames or none based on each unique request.

test_playbook.yml

---
    - hosts: dc
      vars:
        domain_name: "{{ domain_override | default ('tst.local') }}"
        ou_path: "{{ ou_override | default('OU=IT,DC=tst,DC=local') }}"
        dc_name: "{{ dc_override | default ('dc1') }}"
        ad_group_name: "SOME_TEST_GROUP_RW"
        req_ad_user_name: "tst_user"
        req_ad_user_others: "tst_user2,tst_user3"
      tasks:
        - name: "Create AD Group for Internal Path"
          win_domain_group:
            name: "{{ ad_group_name }}"
            description: "Testing for internalpath"
            domain_server: "{{ dc_name }}"
            organizational_unit: "{{ ou_path }}"
            scope: global
            attributes:
              info: "Testing comments for tasknumber"

        - name: "Add Members to new group"
          win_domain_group_membership:
            name: "{{ ad_group_name }}"
            domain_server: "{{ dc_name }}"
            members:
              - "{{ req_ad_user_name }}"
            state: present
    ...

My initial thought was to create a list from req_ad_user_name, and if it's not null, req_ad_user_others. Then, loop through the list of members in the "win_domain_group_membership" module to add them to the group. However, I have not been able to figure what the logic would be for it in the different possible scenarios. Any help would be much appreciated.

Philly
  • 81
  • 1
  • 6

1 Answers1

1

Jinja templating can offer you all you want to achieve.
Here are decomposed steps:

  1. We need to do a list out of your req_ad_user_name variable:
- debug:
    msg: "{{ [req_ad_user_name] }}"
  1. We need to split your variable req_ad_user_others on the comma ,:
- debug:
    msg: "{{ req_ad_user_others.split(',') }}"
  1. We need to do a concatenation of those two lists
- debug:
    msg: "{{ [req_ad_user_name] + req_ad_user_others.split(',') }}"
  1. And finally, we need to account the possibility that the req_ad_user_others could be an empty string (count'ing 0 characters), in that case we should just use a list containing only req_ad_user_name
- debug:
    msg: "{{ ([req_ad_user_name] + req_ad_user_others.split(',')) if req_ad_user_others | count > 0 else [req_ad_user_name] }}"

Since this is always going to return you a list, you should be safe in feeding it directly to the members property of the win_domain_group_membership that does expect a list as argument.

- name: "Add Members to new group"
  win_domain_group_membership:
    name: "{{ ad_group_name }}"
    domain_server: "{{ dc_name }}"
    members: "{{ ([req_ad_user_name] + req_ad_user_others.split(',')) if req_ad_user_others | count > 0 else [req_ad_user_name] }}"
    state: present

Nota: I don't have an Active Directory under the hand to test this code against it, but I am pretty confident it should do the trick.

As for the demo about the variables manipulation, here it is:

---
- hosts: localhost
  connection: local

  vars:
    req_ad_user_name: "tst_user"
    req_ad_user_others: "tst_user2,tst_user3"
    req_ad_user_others_empty: ""

  tasks:
    - name: Test with req_ad_user_others, containing two users tst_user2, tst_user3
      debug:
        msg: "{{ ([req_ad_user_name] + req_ad_user_others.split(',')) if req_ad_user_others | count > 0 else [req_ad_user_name] }}"

    - name: Test with req_ad_user_others_emtpy, an empty string
      debug:
        msg: "{{ ([req_ad_user_name] + req_ad_user_others_empty.split(',')) if req_ad_user_others_empty | count > 0 else [req_ad_user_name] }}"  

This outputs

PLAY [localhost] ************************************************************************************************************************************************************

TASK [Gathering Facts] ******************************************************************************************************************************************************
ok: [localhost]

TASK [Test with req_ad_user_others, containing two users tst_user2, tst_user3] **********************************************************************************************
ok: [localhost] => {
    "msg": [
        "tst_user",
        "tst_user2",
        "tst_user3"
    ]
}

TASK [Test with req_ad_user_others_emtpy, an empty string] ******************************************************************************************************************
ok: [localhost] => {
    "msg": [
        "tst_user"
    ]
}

PLAY RECAP ******************************************************************************************************************************************************************
localhost                  : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
β.εηοιτ.βε
  • 33,893
  • 13
  • 69
  • 83
  • Thanks for the thorough answer and explanation. It's very helpful to see your methods as I learn this technology. Only one thing of note, in section 4, it seems you tripped over my variables, and it should be "req_ad_user_name", i.e. "| count > 0 else [req_ad_user_name] }}"" . In the demo section it is correct. Thanks again! – Philly Oct 16 '19 at 11:13