¿Cómo unificar las tareas de instalación de paquetes en ansible?

68

Estoy comenzando con ansible y lo usaré , entre otros, para instalar paquetes en varias distribuciones de Linux.

Veo en los documentos que los comandos yumy aptestán separados: cuál sería la forma más fácil de unificarlos y usar algo como esto:

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

en lugar 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"

Entiendo que los dos administradores de paquetes son diferentes, pero aún tienen un conjunto de usos básicos comunes. Otros orquestadores ( sal, por ejemplo ) tienen un solo comando de instalación.

WoJ
fuente
Podría tener tres recetas: una que itera sobre una lista común y luego una para cada una de las listas específicas del sistema operativo. Lo que estoy tratando de descubrir ahora es cómo notificar a un controlador con un nombre de servicio específico del sistema operativo después de configurar un elemento de configuración común. ¡buena suerte!
dannyman

Respuestas:

66

Actualización: a partir de Ansible 2.0, ahora hay un módulo genérico y abstractopackage

Ejemplos de uso:

Ahora, cuando el nombre del paquete es el mismo en diferentes familias de sistemas operativos, es tan simple como:

---
- name: Install foo
  package: name=foo state=latest

Cuando el nombre del paquete difiere entre las familias del sistema operativo, puede manejarlo con distribución o archivos vars específicos de la familia del sistema operativo:

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

Luego, para cada sistema operativo que debe manejar de manera diferente ... cree un archivo 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: dado que Michael DeHaan (creador de Ansible) ha elegido no resumir los módulos del administrador de paquetes como lo hace Chef ,

Si todavía usa una versión anterior de Ansible (Ansible <2.0) , desafortunadamente tendrá que manejar esto en todos sus libros de jugadas y roles. En mi humilde opinión, esto empuja mucho trabajo repetitivo innecesario en el libro de jugadas y los autores de roles ... pero es como es actualmente. Tenga en cuenta que no estoy diciendo que debamos tratar de abstraer los administradores de paquetes mientras intentamos admitir todas sus opciones y comandos específicos, sino simplemente tener una manera fácil de instalar un paquete que sea independiente del administrador de paquetes. Tampoco estoy diciendo que todos deberíamos saltar al Smart Package Manager, pero que algún tipo de capa de abstracción de instalación de paquetes en su herramienta de administración de configuración es muy útil para simplificar libros de cocina / libros de cocina multiplataforma. El proyecto Smart parece interesante, pero es bastante ambicioso unificar la gestión de paquetes en distribuciones y plataformas sin mucha adopción todavía ... será interesante ver si tiene éxito. El problema real es solo que los nombres de paquetes a veces tienden a ser diferentes en las distribuciones, por lo que todavía tenemos que hacer declaraciones de casos o when:declaraciones para manejar las diferencias.

La forma en que lo he tratado es seguir esta tasksestructura de directorios en un libro de jugadas o rol:

roles/foo
└── tasks
    ├── apt_package.yml
    ├── foo.yml
    ├── homebrew_package.yml
    ├── main.yml
    └── yum_package.yml

Y luego tener esto en mi main.yml:

---
# foo: entry point for tasks
#                 Generally only include other file(s) and add tags here.

- include: foo.yml tags=foo

Esto en foo.yml(para el paquete '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'

Luego para los diferentes gestores de paquetes:

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

Mmm:

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

Cerveza casera:

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

- homebrew: >
    name=foo
    state=latest

Tenga en cuenta que esto es terriblemente repetitivo y no SECO , y aunque algunas cosas pueden ser diferentes en las diferentes plataformas y tendrán que manejarse, en general creo que esto es detallado y difícil de manejar en comparación con 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

Y sí, existe el argumento de que algunos nombres de paquetes son diferentes en las distribuciones. Y aunque actualmente hay una falta de datos fácilmente accesibles , me aventuraría a adivinar que los nombres de paquetes más populares son comunes en todas las distribuciones y podrían instalarse a través de un módulo de administrador de paquetes abstraído. Los casos especiales tendrían que manejarse de todos modos, y ya requerirían un trabajo extra para que las cosas sean menos SECAS. En caso de duda, consulte pkgs.org .

TrinitronX
fuente
Con Ansible 2 puede usar el módulo del paquete para resumir
Guido
@ GuidoGarcía: ¡Muy lindo! Agregar una nota sobre esto para Ansible 2.0
TrinitronX
Quizás también valga la pena mencionar que puede especificar una lista separada por comas o simplemente una lista de paquetes.
Wes Turner
13

Puede resumir los administradores de paquetes a través de hechos

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

Todo lo que necesitas es alguna lógica que se establezca ansible_pkg_mgren apto yumetc.

Ansible también está trabajando para hacer lo que quiere en un módulo futuro .

xddsg
fuente
1
Ansible se establece ansible_pkg_mgrpara cualquier empaquetador que conozca. No es necesario que hagas nada. Yo uso esta construcción particular en todas partes.
Michael Hampton
La sintaxis sigue siendo bastante útil para aquellos que desean optimizar el funcionamiento de sus libros de jugadas. El módulo de paquete genérico aún no proporciona optimización para with_items, por lo que es mucho más lento cuando se utiliza para instalar varios paquetes a la vez.
Danila Vershinin
@DanielV. Tenga en cuenta que el problema de github proporciona una solución para eso.
Michael Hampton
3

Consulte la documentación de Ansible sobre Importaciones condicionales .

Una tarea para garantizar que apache se esté ejecutando incluso si los nombres de los servicios son diferentes en cada sistema operativo.

---
- hosts: all
  remote_user: root
  vars_files:
    - "vars/common.yml"
    - [ "vars/{{ ansible_os_family }}.yml", "vars/os_defaults.yml" ]
  tasks:
  - name: make sure apache is running
    service: name={{ apache }} state=running
David Vasandani
fuente
2

No desea hacer eso porque ciertos nombres de paquetes difieren entre las distribuciones. Por ejemplo, en las distribuciones relacionadas con RHEL se nombra el popular paquete de servidor web httpd, mientras que en las distribuciones relacionadas con Debian se nombra apache2. Del mismo modo, con una gran lista de otros sistemas y bibliotecas de soporte.

Puede haber un conjunto de parámetros básicos comunes, pero también hay una serie de parámetros más avanzados que son diferentes entre los administradores de paquetes. Y no desea estar en una situación ambigua en la que para algunos comandos use una sintaxis y para otros comandos use otra sintaxis.

Mxx
fuente
Esto es más o menos lo que esperaba (desafortunadamente :)), así que me pregunto cómo se las saltarregla para unificar ambos administradores de paquetes. De todos modos, recurriré a una configuración doble, entonces.
WoJ
O no gestiones un zoológico de distribución ;-) migra a una infraestructura de distribución única y vive una vida más feliz.
Mxx
Afortunadamente, el zoológico tiene solo dos animales, pero este es el número más bajo al que puedo ir :)
WoJ
1
@Mxx es una buena lógica para un administrador de sistemas, pero ¿qué pasa con un proveedor o consultor de software que admite múltiples plataformas?
David H. Bennett
@David, entonces esto debe ser tomado con los proveedores de distribución, para que tengan nombres de paquetes unificados e instalen herramientas. Realmente no hay forma de que Ansible pueda tener una asignación unificada de TODOS los paquetes de todas las distribuciones compatibles de todas las versiones.
Mxx