Atualização: A partir do Ansible 2.0, agora existe um módulo genérico e abstratopackage
Exemplos de uso:
Agora, quando o nome do pacote é o mesmo em diferentes famílias de sistemas operacionais, é tão simples quanto:
---
- name: Install foo
package: name=foo state=latest
Quando o nome do pacote difere entre as famílias de SO, você pode manipulá-lo com arquivos de distribuição ou vars específicos da família de SO:
---
# 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 sistema operacional com o qual você deve lidar de maneira 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: Como Michael DeHaan (criador do Ansible) optou por não abstrair os módulos do gerenciador de pacotes, como o Chef faz,
Se você ainda estiver usando uma versão mais antiga do Ansible (Ansible <2.0) , infelizmente precisará lidar com isso em todos os seus playbooks e funções. IMHO isso empurra um monte de trabalho repetitivo desnecessário para playbook e autores de papéis ... mas é do 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 opções e comandos específicos, mas apenas temos uma maneira fácil de instalar um pacote que seja independente do gerenciador de pacotes. Também não estou dizendo que todos devemos entrar no Gerenciador de Pacotes Inteligentesbandwagon, mas que algum tipo de camada de abstração da instalação de pacotes em sua ferramenta de gerenciamento de configuração é 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 é bem-sucedido. O problema real é que os nomes dos pacotes às vezes tendem a ser diferentes nas distribuições, portanto ainda precisamos fazer declarações ou when:
declarações de casos para lidar com as diferenças.
A maneira como tenho lidado com isso é seguir essa tasks
estrutura de diretórios em um manual ou função:
roles/foo
└── tasks
├── apt_package.yml
├── foo.yml
├── homebrew_package.yml
├── main.yml
└── yum_package.yml
E então tenho 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
Isto 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'
Depois, 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 é muito repetitivo e não SECO , e embora algumas coisas possam ser diferentes nas diferentes plataformas e tenham que ser tratadas, geralmente acho que isso é detalhado e pesado quando comparado ao 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, há o argumento de que alguns nomes de pacotes são diferentes nas distribuições. E, embora atualmente haja uma falta de dados facilmente acessíveis , arrisco-me a adivinhar que os nomes de pacotes mais populares são comuns em distribuições e podem ser instalados por meio de um módulo gerenciador de pacotes abstraído. Casos especiais precisariam ser tratados de qualquer maneira e já exigiriam trabalho extra para tornar as coisas menos secas . Em caso de dúvida, consulte pkgs.org .