Comment unifier les tâches d'installation de paquet dans ansible?

68

Je commence par ansible et l’utiliserai, entre autres, pour installer des paquets sur plusieurs distributions Linux.

Je vois dans la documentation que les commandes yumet aptsont séparées - quel serait le moyen le plus simple de les unifier et d’utiliser quelque chose comme ceci:

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

au lieu 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"

Je comprends que les deux gestionnaires de paquets sont différents, mais ils ont toujours un ensemble d’utilisations de base communes. Les autres orchestres ( salt, par exemple ) ont une seule commande d'installation.

WoJ
la source
Vous pouvez avoir trois recettes: une qui itère sur une liste commune et une autre pour les listes spécifiques à un système d'exploitation. Ce que j'essaie de comprendre maintenant, c'est comment notifier un gestionnaire avec un nom de service spécifique au système d'exploitation après la définition d'un élément de configuration commun. bonne chance!
dannyman

Réponses:

66

Mise à jour: à partir de Ansible 2.0, il existe maintenant un module générique et résumépackage

Exemples d'utilisation:

Désormais, lorsque le nom du package est identique dans différentes familles de systèmes d'exploitation, il suffit de:

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

Lorsque le nom du package diffère selon les familles de systèmes d'exploitation, vous pouvez le gérer avec des fichiers vars de distribution ou de familles de systèmes d'exploitation:

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

Ensuite, pour chaque système d'exploitation que vous devez gérer différemment ... créez un fichier 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: Depuis que Michael DeHaan (créateur d’Ansible) a choisi de ne pas faire abstraction des modules de gestion de paquets comme le fait Chef ,

Si vous utilisez toujours une ancienne version de Ansible (Ansible <2.0) , vous devrez malheureusement le faire dans tous vos playbooks et rôles. IMHO, cela impose beaucoup de travail répétitif inutile sur les auteurs de playbooks et de rôles ... mais c'est comme ça actuellement. Notez que je ne dis pas que nous devrions essayer d’abstraire les gestionnaires de paquets tout en essayant de prendre en charge toutes leurs options et commandes spécifiques, mais simplement un moyen facile d’installer un paquet qui n’est pas agnostique. Je ne dis pas non plus que nous devrions tous sauter dans le gestionnaire de paquets intelligent.Cela dit, une couche d’abstraction pour l’installation de paquetages dans votre outil de gestion de la configuration est très utile pour simplifier les livres de lecture / livres de cuisine multiplates-formes. Le projet Smart semble intéressant, mais il est assez ambitieux d’unifier la gestion des paquets entre les distributrices et les plates-formes sans grande adoption pour le moment… il sera intéressant de voir s’il a du succès. Le vrai problème, c'est que les noms de paquets ont parfois tendance à être différents d'une distribution à l'autre. Nous devons donc toujours faire des déclarations de cas ou des when:déclarations pour gérer les différences.

La façon dont je l'ai traitée est de suivre cette tasksstructure de répertoire dans un livre de lecture ou un rôle:

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

Et puis avoir ceci dans mon main.yml:

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

- include: foo.yml tags=foo

Ceci dans foo.yml(pour le paquet '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'

Ensuite pour les différents gestionnaires de paquets:

Apte:

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

Miam:

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

Notez que ceci est terriblement répétitif et non DRY , et bien que certaines choses puissent être différentes sur les différentes plates-formes et devront être gérées, généralement je pense que cela est verbeux et difficile à manier par rapport à Chef's:

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

Et oui, il y a l'argument selon lequel certains noms de paquetages sont différents d'une distribution à l'autre. Et bien qu’il existe actuellement un manque de données facilement accessibles , je me risquerais à deviner que les noms de paquets les plus populaires sont communs à toutes les distributions et qu’ils pourraient être installés via un module de gestionnaire de paquets abstraite. Les cas spéciaux devront de toute façon être traités et nécessiteront déjà un travail supplémentaire rendant les choses moins sèches . En cas de doute, vérifiez pkgs.org .

TrinitronX
la source
Avec Ansible 2, vous pouvez utiliser le module package pour résumer
Guido
@ GuidoGarcía: Très bien! Ajout d'une note à ce sujet pour Ansible 2.0
TrinitronX
Vous pouvez également mentionner que vous pouvez spécifier une liste séparée par des virgules ou juste une liste de packages.
Wes Turner
13

Vous pouvez extraire les gestionnaires de paquets via des faits

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

Tout ce dont vous avez besoin est d’une certaine logique qui vous amène ansible_pkg_mgrà aptou yumetc.

Ansible travaille également sur ce que vous voulez dans un futur module .

xddsg
la source
1
Ansible se fixe ansible_pkg_mgrpour tous les emballeurs qu’il connaît. Il n'est pas nécessaire que vous fassiez quoi que ce soit. J'utilise cette construction particulière partout.
Michael Hampton
La syntaxe est encore très utile pour ceux qui veulent optimiser l'exécution de leurs playbooks. Le module de paquet générique ne fournit pas encore d'optimisation pour with_items , il est donc beaucoup plus lent lorsqu'il est utilisé pour installer plusieurs paquets à la fois.
Danila Vershinin
@DanielV. Notez que le problème github fournit une solution de contournement à cela.
Michael Hampton
6

À partir de Ansible 2.0, il y a le nouveau Package-modul.

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

Vous pouvez ensuite l'utiliser comme votre proposition:

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

Vous devez toujours prendre en compte les différences de nom.

Tvartom
la source
3

Consultez la documentation de Ansible sur les importations conditionnelles .

Une tâche consiste à s’assurer que Apache est en cours d’exécution même si les noms de service sont différents d’un système à l’autre.

---
- 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
la source
2

Vous ne voulez pas faire cela parce que certains noms de paquetages diffèrent entre les distributions. Par exemple, sur les distributions liées à RHEL, le paquet de serveur Web populaire porte le nom httpd, alors que sur les distributions liées à Debian, il est nommé apache2. De même avec une liste énorme d'autres bibliothèques système et de soutien.

Il peut exister un ensemble de paramètres de base communs, mais il existe également un certain nombre de paramètres plus avancés qui diffèrent entre les gestionnaires de packages. Et vous ne voulez pas être dans une situation ambiguë dans laquelle vous utiliserez une syntaxe pour certaines commandes et une autre pour une autre.

Mxx
la source
C’est plus ou moins ce à quoi j’attendais (malheureusement :)), alors je me demande comment on saltparvient à unifier les deux gestionnaires de paquets. Quoi qu'il en soit, je vais recourir à une double configuration, alors.
WoJ
Ou ne gérez pas un zoo de distribution ;-) migrez vers une infrastructure à distribution unique et vivez une vie plus heureuse.
Mxx
Le zoo n’a heureusement que deux animaux de taille importante, mais c’est le chiffre le plus bas
auquel
1
@Mxx, c’est une bonne logique pour un administrateur système, mais qu’en est-il des fournisseurs de logiciels ou des consultants prenant en charge plusieurs plates-formes?
David H. Bennett
@David, cela doit être repris par les vendeurs de distribution, pour qu’ils aient des noms de paquet unifiés et installer des outils. Il est pratiquement impossible qu'Ansible dispose d'un mappage unifié de TOUS les packages de toutes les distributions prises en charge de toutes les versions.
MXx