79 votes

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

Je commence par ansible et l'utilisera, entre autres, pour installer des paquets sur plusieurs distros Linux.

Je vois dans les docs que le yum y apt sont 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 quand même un ensemble d'utilisations de base communes. D'autres orchestrateurs ( le sel par exemple ) ont une seule commande d'installation.

84voto

Diaa Sami Points 1802

Mise à jour : Depuis Ansible 2.0, il y a maintenant une version générique et abstraite de l'article. package module

Exemples d'utilisation :

Maintenant, lorsque le nom du paquet est le même dans différentes familles d'OS, c'est aussi simple que cela :

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

Lorsque le nom du paquet diffère d'une famille d'OS à l'autre, vous pouvez le gérer avec des fichiers vars spécifiques à la distribution ou à la famille d'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

Ensuite, pour chaque OS 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 Michael DeHaan (créateur d'Ansible) a choisi de ne pas abstraire les modules du gestionnaire de paquets. comme Chef fait,

Si vous utilisez toujours une ancienne version d'Ansible (Ansible < 2.0) malheureusement, vous devrez vous occuper de cette opération dans tous de vos playbooks et rôles. IMHO cela impose un travail répétitif et inutile aux auteurs de livre de jeu et de rôle... mais c'est ainsi que cela se passe actuellement. Notez que je ne dis pas que nous devrions essayer d'abstraire les gestionnaires de paquets tout en essayant de supporter toutes leurs options et commandes spécifiques, mais simplement avoir un moyen facile d'installer un paquet qui est agnostique au gestionnaire de paquets. Je ne suis pas non plus en train de dire que nous devrions tous sauter sur le bouton Gestionnaire de paquets intelligent mais qu'une sorte de couche d'abstraction pour l'installation de paquets dans votre outil de gestion de la configuration est très utile pour simplifier les livres de jeux et les livres de cuisine multiplateformes. Le projet Smart a l'air intéressant, mais il est assez ambitieux pour unifier la gestion des paquets à travers les distros et les plateformes, sans avoir été adopté pour le moment... il sera intéressant de voir s'il réussit. Le vrai problème est que les noms des paquets ont parfois tendance à être différents d'une distro à l'autre, ce qui nous oblige à utiliser des instructions de type case ou when: pour gérer les différences.

La façon dont je m'en sors est de suivre ce qui suit . tasks structure de répertoire dans un playbook ou un rôle :

roles/foo
 tasks
     apt_package.yml
     foo.yml
     homebrew_package.yml
     main.yml
     yum_package.yml

Et puis j'ai ça dans mon main.yml :

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

- include: foo.yml tags=foo

Ce 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'

Puis pour les différents gestionnaires de paquets :

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

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 c'est terriblement répétitif et non pas D.R.Y. et bien que certaines choses pourrait sera différente sur les différentes plateformes et devra être gérée, en général je pense que c'est verbeux et peu maniable comparé à celle de 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

Et oui, il y a l'argument selon lequel un peu de Les noms des paquets sont différents selon les distros. Et bien qu'il existe actuellement un le manque de données facilement accessibles je me risquerais à dire que le plus Les noms de paquets populaires sont communs à toutes les distributions et peuvent être installés via un module abstrait de gestion des paquets. S pkgs.org .

15voto

xddsg Points 3144

Vous pouvez faire abstraction des gestionnaires de paquets via les faits

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

Tout ce dont vous avez besoin, c'est d'une logique qui définit ansible_pkg_mgr a apt o yum etc.

Ansible travaillent également à faire ce que vous voulez dans un futur module .

7voto

Tvartom Points 123

Dans la version 2.0 d'Ansible, il y a le nouvel élément suivant 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 tenir compte des différences de noms.

4voto

Andy Points 21

Consultez la documentation d'Ansible sur Importations conditionnelles .

Une tâche pour s'assurer qu'apache fonctionne même si le nom du service est différent sur chaque OS.

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

3voto

Mxx Points 2302

Vous ne voulez pas faire cela car certains noms de paquets diffèrent entre les distros. Par exemple, sur les distros liées à RHEL, le paquetage du serveur web le plus populaire s'appelle httpd alors que sur les distros liées à Debian, il s'appelle apache2 . De même qu'une énorme liste d'autres systèmes et bibliothèques de soutien.

Il peut y avoir un ensemble de paramètres de base communs, mais il y a aussi un certain nombre de paramètres plus avancés qui sont différents entre les gestionnaires de paquets. Et vous ne voulez pas vous retrouver dans une situation ambiguë où pour certaines commandes vous utilisez une syntaxe et pour d'autres vous en utilisez une autre.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X