Atualização: A partir do Ansible 2.0, existe agora um & genérico & package
module
Exemplos de uso:
Agora, quando o nome do pacote é o mesmo em diferentes famílias de SO, é tão simples quanto:
---
- name: Install foo
package: name=foo state=latest
Quando o nome do pacote difere entre as famílias do SO, você pode manipulá-lo com distribuição ou arquivos vars específicos da família OS:
---
# roles/apache/apache.yml: Tasks entry point for 'apache' role. Called by main.yml
# Load a variable file based on the OS type, or a default if not found.
- include_vars: "{{ item }}"
with_first_found:
- "../vars/{{ ansible_distribution }}-{{ ansible_distribution_major_version | int}}.yml"
- "../vars/{{ ansible_distribution }}.yml"
- "../vars/{{ ansible_os_family }}.yml"
- "../vars/default.yml"
when: apache_package_name is not defined or apache_service_name is not defined
- name: Install Apache
package: >
name={{ apache_package_name }}
state=latest
- name: Enable apache service
service: >
name={{ apache_service_name }}
state=started
enabled=yes
tags: packages
Em seguida, para cada SO que você deve manipular de forma diferente ... crie um arquivo vars:
---
# roles/apache/vars/default.yml
apache_package_name: apache2
apache_service_name: apache2
---
# roles/apache/vars/RedHat.yml
apache_package_name: httpd
apache_service_name: httpd
---
# roles/apache/vars/SLES.yml
apache_package_name: apache2
apache_service_name: apache2
---
# roles/apache/vars/Debian.yml
apache_package_name: apache2
apache_service_name: apache2
---
# roles/apache/vars/Archlinux.yml
apache_package_name: apache
apache_service_name: httpd
EDIT: Desde Michael DeHaan (criador do Ansible) optou por não abstrair os módulos do gerenciador de pacotes como Chef ,
Se você ainda estiver usando uma versão mais antiga do Ansible (Ansible < 2.0) , infelizmente você precisará lidar com isso em todos IMHO isto empurra muito trabalho repetitivo desnecessário para a cartilha & autores de papéis ... mas é o jeito que é atualmente. Observe que não estou dizendo que devemos tentar abstrair os gerenciadores de pacotes enquanto ainda tentamos oferecer suporte a todas as suas opções e comandos específicos, mas apenas temos uma maneira fácil de instalar um pacote que seja agnóstico do gerenciador de pacotes. Eu também não estou dizendo que todos nós devemos pular no bandwagon Smart Package Manager , mas que algum tipo de camada de abstração de instalação de pacotes em sua configuração ferramenta de gerenciamento é muito útil para simplificar playbooks / livros de receitas entre plataformas. O projeto Smart parece interessante, mas é bastante ambicioso unificar o gerenciamento de pacotes em distribuições e plataformas sem muita adoção ainda ... será interessante ver se ele é bem-sucedido. A questão real é que os nomes dos pacotes às vezes tendem a ser diferentes entre distros, então ainda temos que fazer instruções case ou when:
para lidar com as diferenças.
A maneira como tenho lidado com isso é seguir essa estrutura de diretório tasks
em um playbook ou função:
roles/foo
└── tasks
├── apt_package.yml
├── foo.yml
├── homebrew_package.yml
├── main.yml
└── yum_package.yml
E, em seguida, tem isso no meu main.yml
:
---
# foo: entry point for tasks
# Generally only include other file(s) and add tags here.
- include: foo.yml tags=foo
Isso em foo.yml
(para o pacote 'foo'):
---
# foo: Tasks entry point. Called by main.yml
- include: apt_package.yml
when: ansible_pkg_mgr == 'apt'
- include: yum_package.yml
when: ansible_pkg_mgr == 'yum'
- include: homebrew_package.yml
when: ansible_os_family == 'Darwin'
- name: Enable foo service
service: >
name=foo
state=started
enabled=yes
tags: packages
when: ansible_os_family != 'Darwin'
Em seguida, para os diferentes gerenciadores de pacotes:
Apt:
---
# tasks file for installing foo on apt based distros
- name: Install foo package via apt
apt: >
name=foo{% if foo_version is defined %}={{ foo_version }}{% endif %}
state={% if foo_install_latest is defined and foo_version is not defined %}latest{% else %}present{% endif %}
tags: packages
Yum:
---
# tasks file for installing foo on yum based distros
- name: Install EPEL 6.8 repos (...because it's RedHat and foo is in EPEL for example purposes...)
yum: >
name={{ docker_yum_repo_url }}
state=present
tags: packages
when: ansible_os_family == "RedHat" and ansible_distribution_major_version|int == 6
- name: Install foo package via yum
yum: >
name=foo{% if foo_version is defined %}-{{ foo_version }}{% endif %}
state={% if foo_install_latest is defined and foo_version is not defined %}latest{% else %}present{% endif %}
tags: packages
- name: Install RedHat/yum-based distro specific stuff...
yum: >
name=some-other-custom-dependency-on-redhat
state=latest
when: ansible_os_family == "RedHat"
tags: packages
Homebrew:
---
- name: Tap homebrew foobar/foo
homebrew_tap: >
name=foobar/foo
state=present
- homebrew: >
name=foo
state=latest
Observe que isso é terrivelmente repetitivo e não DRY e, embora algumas coisas possam ser diferente nas diferentes plataformas e terá que ser tratado, geralmente eu acho que isso é detalhado e pesado quando comparado ao do Chef:
package 'foo' do
version node['foo']['version']
end
case node["platform"]
when "debian", "ubuntu"
# do debian/ubuntu things
when "redhat", "centos", "fedora"
# do redhat/centos/fedora things
end
E sim, existe o argumento de que os nomes dos pacotes alguns são diferentes nas distribuições. E embora exista atualmente uma falta de dados facilmente acessíveis , eu arriscaria adivinhar que A maioria dos nomes populares de pacotes é comum em distros e pode ser instalada através de um módulo gerenciador de pacotes. Casos especiais precisariam ser tratados de qualquer maneira, e já exigiriam trabalho extra tornando as coisas menos D.R.Y. Em caso de dúvida, verifique pkgs.org .