2

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.

Michael Hampton
  • 244,070
  • 43
  • 506
  • 972
  • What are the database users associated with? – Michael Hampton Jun 03 '15 at 17:49
  • @MichaelHampton not sure what you mean? `mysql_users` is a variable in group_vars that's referenced by a playbook that installs and configures mysql. – Nathaniel Schweinberg Jun 03 '15 at 18:12
  • I mean: You are creating database users for a specific purpose, right? To serve some application, be administrators, whatever. No? – Michael Hampton Jun 03 '15 at 18:13
  • @MichaelHampton correct. I've already got the application users taken care of, now I'm just trying to account for users that aren't tied to a specific application. – Nathaniel Schweinberg Jun 03 '15 at 18:29
  • I'd probably just stick variables right in a playbook, e.g. `mysql_admins.yml` for administrators, `app.yml` for users who admin a single application, etc. – Michael Hampton Jun 03 '15 at 18:35
  • @MichaelHampton Oh, sure, but that's not the problem I'm encountering. I'm having trouble taking an ansible host group and extracting the ip addresses from the group so the `mysql_user` module can create a user tied to that ip address. Does that make sense? With the method you're proposing I'd have to have knowledge of the ip addresses, and those could change quite often. – Nathaniel Schweinberg Jun 03 '15 at 18:38
  • @MichaelHampton at least that's what I think you're proposing. I could be misunderstanding you. – Nathaniel Schweinberg Jun 03 '15 at 18:38

2 Answers2

1

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.

0

This would probably be solved using the map and list filters, as described in the second example here:

http://docs.ansible.com/ansible/set_fact_module.html

# Example setting host facts using complex arguments
- set_fact:
     one_fact: something
     other_fact: "{{ local_var * 2 }}"
     another_fact: "{{ some_registered_var.results | map(attribute='ansible_facts.some_fact') | list }}"

I go into a bit more depth here: http://smileytechadventures.blogspot.com/2015/07/ansible-filter-results.html

senorsmile
  • 713
  • 8
  • 20