Como unificar tarefas de instalação de pacotes em ansible?

Como unificar tarefas de instalação de pacotes em ansible?

estou começando comansiblee irá utilizá-lo, entre outros, para instalar pacotes em diversas distros Linux.

Vejo nos documentos que os comandos yume aptestão separados - qual seria a maneira mais fácil de unificá-los e usar algo assim:

- name: install the latest version of Apache
  unified_install: name=httpd state=latest

em vez de

- name: install the latest version of Apache on CentOS
  yum: name=httpd state=latest
  when: ansible_os_family == "RedHat"

- name: install the latest version of Apache on Debian
  apt: pkg=httpd state=latest 
  when: ansible_os_family == "Debian"

Entendo que os dois gerenciadores de pacotes são diferentes, mas ainda têm um conjunto de usos básicos comuns. Outros orquestradores (sal por exemplo) têm um único comando de instalação.

Responder1

Atualização: A partir do Ansible 2.0, agora existe um genérico e abstraídopackagemódulo

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 sistemas operacionais, você pode lidar com isso com arquivos vars específicos da distribuição ou da família de sistemas operacionais:

---
# 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

Então, para cada sistema operacional que você deve tratar 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



EDITAR: Desde Michael DeHaan (criador do Ansible)optou por não abstrair os módulos do gerenciador de pacotescomoChefe de cozinhafaz,

Se você ainda estiver usando uma versão mais antiga do Ansible (Ansible <2.0), infelizmente você precisará lidar com isso emtodosde seus manuais e funções. Na minha humilde opiniãoisso empurra muito trabalho repetitivo desnecessário para os autores de manuais e funções... mas é assim 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 ter uma maneira fácil de instalar um pacote que seja independente do gerenciador de pacotes. Também não estou dizendo que todos deveríamos pular noGerenciador de pacotes inteligentemovimento, mas algum tipo de camada de abstração de instalação de pacote em sua ferramenta de gerenciamento de configuração é muito útil para simplificar manuais/livros de receitas de plataforma cruzada. O projeto Smart parece interessante, mas é bastante ambicioso para unificar o gerenciamento de pacotes entre distros e plataformas sem muita adoção ainda... será interessante ver se terá sucesso. A verdadeira questão é que os nomes dos pacotes às vezes tendem a ser diferentes entre as distros, então ainda temos que fazer declarações case ou when:declarações para lidar com as diferenças.

A maneira como tenho lidado com isso é seguir esta tasksestrutura 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 coloque 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'

Então, para os diferentes gerenciadores de pacotes:

Apto:

---
# 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

Hum:

---
# 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

Preparação caseira:

---
- name: Tap homebrew foobar/foo
  homebrew_tap: >
    name=foobar/foo
    state=present

- homebrew: >
    name=foo
    state=latest

Observe que isso é terrivelmente repetitivo e nãoSECOe embora algumas coisaspoderser diferente nas diferentes plataformas e terá que ser tratado, geralmente acho que isso é detalhado e complicado 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, há o argumento de quealgunsos nomes dos pacotes são diferentes entre as distros. E embora exista atualmente umafalta de dados facilmente acessíveis, atrevo-me a adivinhar quemaiorianomes de pacotes populares são comuns em distros e podem ser instalados por meio de um módulo gerenciador de pacotes abstrato. Casos especiais precisariam ser tratados de qualquer maneira e já exigiriam trabalho extra para tornar as coisas menos SECAS. Em caso de dúvida, verifiquepkgs.org.

Responder2

Você pode abstrair os gerenciadores de pacotes por meio de fatos

- name: Install packages
  with_items: package_list
  action: "{{ ansible_pkg_mgr }} state=installed name={{ item }}"

Tudo que você precisa é de alguma lógica que defina ansible_pkg_mgrcomo aptou yumetc.

Ansibletambém estamos trabalhando para fazer o que quiser em um módulo futuro.

Responder3

Do Ansible 2.0 existe o novo Package-modul.

http://docs.ansible.com/ansible/package_module.html

Você pode então usá-lo como sua proposta:

- name: install the latest version of Apache
  package: name=httpd state=latest

Você ainda precisa considerar as diferenças de nomes.

Responder4

Você não quer fazer isso porque certos nomes de pacotes diferem entre distros. Por exemplo, em distros relacionadas ao RHEL, o popular pacote de servidor web é denominado httpd, enquanto nas distros relacionadas ao Debian é denominado apache2. Da mesma forma, com uma lista enorme de outros sistemas e bibliotecas de suporte.

Pode haver um conjunto de parâmetros básicos comuns, mas também há vários parâmetros mais avançados que são diferentes entre gerenciadores de pacotes. E você não quer estar em uma situação ambígua em que para alguns comandos você usa uma sintaxe e para outros comandos você usa outra sintaxe.

informação relacionada