Collecting files across all the roles a host belongs to

52 views
Skip to first unread message

JK Laiho

unread,
Feb 9, 2015, 8:40:04 AM2/9/15
to ansible...@googlegroups.com
I'm new to Ansible, and trying to wrap my head around the variety of ways to organize playbooks and achieve certain tasks in a DRY way, without duplicating too much logic in several places.

Right now I'm trying to find a way in which I could have with_fileglob consolidate files of a certain pattern from all of the roles that a host belongs to. Specifically, some roles contain apt keys, some roles don't.

The way I envisioned setting this up is as follows. First, the role hierarchy:

roles/
  common/
    files/
      ... # no apt keys for this role
  db/
    files/
      ... # no apt keys for this role
  rabbitmq/
    files/
      apt_keys/
        some_rabbitmq_specific_key.asc
  web/
    files/
      apt_keys/
        some_web_specific_key.asc
  
The task in roles/common/tasks/main.yml:

- name: add apt keys
  apt_key: file="{{ item }}"
  sudo: true
  with_fileglob:
    - apt_keys/*.asc

In my ideal world, if a host belongs to common and web, with_fileglob would add some_web_specific_key.asc. If a host belongs to commondb and rabbitmq, it would add some_rabbitmq_specific_key.asc

As you've probably guessed from the fact that I'm writing this post, this approach doesn't work. The task, placed inside common, is simply skipped, apparently because the common role contains no apt keys (and even if it did, it would still ignore the keys in rabbitmq and web).

Is this type of cross-role file aggregation possible? I can sort of see why it wouldn't be, though in my current circumstance it would seem very useful.

The deeper rationale here is that I want a certain other task to get run after all the apt keys that apply to a host through all of its role memberships have been added. Had the approach above worked, I would have simply placed this task right after the apt_key task in common/tasks/main.yml, but since it doesn't, I don't know how to achieve this. Suggestions?

James Cammarata

unread,
Feb 9, 2015, 8:25:25 PM2/9/15
to ansible...@googlegroups.com
Hi,

I believe if you want to keep this in a common role, the best way would be to simply list each task to install the key as follows:

- name: install rabbitmq key
  apt_key: file="apt_keys/some_rabbitmq_specific_key.asc
  when: "rabbitmq" in group_names

...


If you wanted to make it more generic, you could store the group names/keys in some sort of variable structure and loop over that, but as you noted the approach you're taking won't work as with_fileglob only operates on the directory relative to the current role being run.

Hope that helps!


--
You received this message because you are subscribed to the Google Groups "Ansible Project" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ansible-proje...@googlegroups.com.
To post to this group, send email to ansible...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/ansible-project/d8dfcf1b-501c-4808-87a5-2ffc8153b05e%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

JK Laiho

unread,
Feb 10, 2015, 6:55:15 AM2/10/15
to ansible...@googlegroups.com
Hi James,

Thanks for your help! You put me on the right track. Here's what I ended up doing (in case someone else finds this useful).

First, for DRY's sake, I collected the absolute paths to the apt keys in group_vars/all to make them "global" and role-independent, in a form that could be consumed using with_subelements:

---
apt_keys_by_role:
  - role: common
    keyfiles:
      - path: "{{ inventory_dir }}/roles/common/files/apt_keys"
        filename: some_common_key.asc
        pub: 90FDDD2E
      - path: "{{ inventory_dir }}/roles/common/files/apt_keys"
        filename: some_other_common_key.asc
        pub: D88E42B4
  - role: rabbitmq
    keyfiles:
      - path: "{{ inventory_dir }}/roles/rabbitmq/files/apt_keys"
        filename: some_rabbitmq_key.asc
        pub: 056E8E56

On the server, I have /etc/ansible/facts.d/installed_apt_keys.fact, a bash script that takes the output of apt-key list and transforms the pub values contained within to a JSON list. (Script omitted here, left as an exercise for the reader.)

Since (AFAIK, based on Googling) there's no way for a task to know what are the currently active roles, I also had to create a custom list variable for it and place it inside my hosts-to-roles mapping files. This is something that I hope future versions of Ansible will address by making a variable called e.g. role_names available to tasks, just like group_names already is. Here is webservers.yml as an example:

---
- hosts: webservers
  roles:
    - common
    - rabbitmq
    - web
  # No access to current role names without specifying them as a variable
  vars:
    role_names:
      - common
      - rabbitmq
      - web

Finally, in roles/common/tasks/main.yml I copy the key files to the target host, add them with apt_key and then remove them (since apt_key doesn't transfer the file parameters over, they need to be on the server before running it):

# copying to /tmp omitted, same logic as below

- name: add apt keys from /tmp
  sudo: true
  apt_key: file="/tmp/{{ item.1.filename }}"
  when: "'{{ item.0.role }}' in role_names and '{{ item.1.pub }}' not in ansible_local.installed_apt_keys.key_list"
  with_subelements:
    - apt_keys_by_role
    - keyfiles

# removal from /tmp omitted, same logic as above

The solution is not quite as clean as I'd hope it to be, but it's the best effort I've managed to piece together so far given Ansible's current limitations (and those of my Ansible knowhow).
Reply all
Reply to author
Forward
0 new messages