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.

7
  • What are the database users associated with? Jun 3, 2015 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. Jun 3, 2015 at 18:12
  • I mean: You are creating database users for a specific purpose, right? To serve some application, be administrators, whatever. No? Jun 3, 2015 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. Jun 3, 2015 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. Jun 3, 2015 at 18:35

2 Answers 2

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

You must log in to answer this question.

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