Using Ansible to provisioning users: Modify facts/expand hostvars

ansibledynamichosts

First off, I apologize for the terrible title. I'm not entirely sure how to succinctly describe the problem.

So here's my challenge. I'm working on provisioning database users and would like a flexible method of defining users. I'm encountering a problem with using Jinja for conditionals and ansible loops because I'm doing things I think that ansible wasn't necessarily designed to do. Let's start with the variable:

mysql_users:
  - user: biggles
    password: boggles
    group: app
    database: some_db
  - user: boogers
    password: boogers
    hosts:
      - "12.34.56.78"
      - "12.34.56.79"
      - "12.34.56.80"
    database: another_db

I'd like to take the group key in the first item and expand it into a list of ip addresses (like in the second item). group refers to an ansible hosts group. To do that, I've got this:

- name: Expand Mysql users hosts from their group name
  set_fact:
  args:
    mysql_users_dirty:
      user: "{{ item }}"
      hosts: "{{ groups[item.group | default('')] | default(item.hosts) }}"
  with_items: mysql_users
  register: mysql_users_results
  # when: item.group is defined | default(false)

- name: Map fact result list to correct ansible fact
  set_fact:
    mysql_users_expanded: "{{ mysql_users_results.results | map(attribute='ansible_facts.mysql_users_dirty') | list }}"

This transforms mysql_users into mysql_users_expanded:

mysql_users_expanded:
  - hosts:
      - "23.34.56.78"
      - "23.34.56.79"
      - "23.34.56.80"
    user:
      user: biggles
      password: boggles
      group: app
      database: some_db
  - hosts:
      - "12.34.56.78"
      - "12.34.56.79"
      - "12.34.56.80"
    user: 
      user: boogers
      password: boogers
      database: another_db
      hosts:
        - "12.34.56.78"
        - "12.34.56.79"
        - "12.34.56.80"

And then we add the users:

- name: Create/assign additional database users to db and grant permissions (group hosts)
  mysql_user: name="{{ item.0.user.user }}"
              password="{{ item.0.user.password }}"
              host="{{ hostvars[ item.1 ]['ansible_' + private_iface ]['ipv4']['address'] | default(item.1) }}"
              priv="{{ item.0.user.database }}.*:{{ item.0.user.priv | default('ALL')}}"
              state=present
              login_host="localhost"
              login_user=root
              login_password="{{ mysql_root_password }}"
  with_subelements:
    - mysql_users_expanded
    - hosts
  when: item.1 is defined | default(false)

I've got this going, but ansible yells at me saying it can't find "12.34.56.78" because it's trying to use that ip address as the key to lookup the host in hostvars. I'm having trouble finding a better way of handling ip address lookup and rescuing failed lookups.

First off, is there a simpler way of doing this? Am I making this too complicated? Second, I'm wondering if there's a way to better map the host ips to the fact.

Best Answer

I found this helpful thread and ended up building a var file template locally and then loading it in the playbook. It enabled me to utilize more logic in building the var file.