Installing packages on multiple Operating Systems

Hi,

I’m wondering if there’s a better way to install packages on multiple operating systems.

TL;DR: I’m looking for a method to abstract the OS differences to avoid duplicating files and templates all over the place.

Here’s what I’m currently doing:

  • name: Install OpenJDK
    apt: pkg={{ item }} state=present

with_items:

  • openjdk-7-jdk

tags:

  • java
    when: ansible_distribution == ‘Ubuntu’
  • name: Install OpenJDK
    yum: name=java-1.7.0-openjdk state=present
    tags:
  • java
    when: ansible_distribution == ‘CentOS’

This works fine when you only have 1 task or 1 role, but I currently have 10 roles with multiple configurations, and each role has its own set of tasks, files, templates, etc.

I considered creating separate directories in each role, for each OS, but then handlers, templates and other files will need to be duplicated.

Is there a “package” module to replace “yum/apt” ? If not, can someone recommend a better approach? So far all the solutions I’ve found are only good as “examples”, but far from ideal in the real world.

Thanks

I would recommend using the group_by option, which can be used to group systems based on facts or other variables. So something like this:

  • hosts: all
    tasks:

  • name: group hosts by distribution
    group_by: key=“{{ ansible_distribution }}-{{ ansible_distribution_version }}”

  • hosts: RedHat-6*:CentOS-6*:SL-6*

tasks:

  • name: Install OpenJDK
    yum: name=java-1.7.0-openjdk state=present
    tags:

  • java

  • hosts: Ubuntu-*

tasks:

  • name: Install OpenJDK
    apt: pkg=openjdk-7-jdk state=present

tags:

  • java

Dear James,

This is very neat, related to this how do i use varaibles/facts for hosts, i tried the documentation example following in ansible, ansible-playbook but could not get it working

webservers:!{{excluded}}:&{{required}}

where should I define these variables, i tried to define them in the inventory hosts files, or pass them via the “-e” option both did not work for me.

regards

Walid

Walid, this question came up the other day and I mentioned that it works correctly when setting the variable with -e. Could you post some samples of your inventory/playbook.

Also, if asking a new question it’s generally best to start a new thread, to avoid confusion and switching topics.

you can use the {{ansible_pkg_manager}} variable to try to make it a single task, but then you have the problem of the package names not matching, so James’ solution is the best option.

The host selector is there for selecting groups defined in inventory explicitly.

If you want to further pare down hosts, rather than doing the “-e” bits and making it more complex with {{ vars }}, it’s easier to just use --limit

ansible-playbook site.yml --limit pod6

Would run the whole playbook just on machines in pod6.

Can this be achieved in a single role, or would multiple roles be required, one for each OS?

This would need to be separate roles, since roles can’t contain hosts: entries.

You can just use the when statement in this case if you want to keep things in the same role.

when: ansible_os_family == ‘Debian’

etc