Як уніфікувати завдання встановлення пакета в ansible?


68

Я починаю з ansible і буду використовувати його, серед інших, для встановлення пакетів у декількох дистрибутивах Linux.

Я бачу в документах, що команди yumі aptкоманди розділені - що було б найпростішим способом уніфікувати їх і використовувати щось подібне:

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

замість

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

Я розумію, що два менеджери пакунків різні, але вони все ще мають набір загальних базових звичок. Інші оркестранти (наприклад, сіль ) мають одну команду встановлення.


У вас може бути три рецепти: один, який повторюється над загальним списком, а потім один для списків, характерних для ОС. Я зараз намагаюся з’ясувати, як сповістити обробника з іменем служби, що відповідає ОС, після встановлення загального елемента конфігурації. Щасти!
— dannyman

Відповіді:


66

Оновлення: Станом на Ansible 2.0, тепер існує загальний модуль та абстрагуванняpackage

Приклади використання:

Тепер, коли назва пакету однакова в різних сімействах ОС, це так само просто, як:

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

Коли назва пакета відрізняється у сімействах ОС, ви можете обробити його за допомогою файлів vars для розповсюдження або специфічних для сім'ї ОС:

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

Потім для кожної ОС, з якою ви маєте працювати по-різному ... створіть файл 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: Оскільки Майкл ДеХаан (творець Ansible) вирішив не абстрагувати модулі менеджера пакунків, як Chef ,

Якщо ви все ще використовуєте старішу версію Ansible (Ansible <2.0) , на жаль, вам потрібно буде впоратися з цим у всіх своїх іграх і ролях. IMHO це підштовхує багато непотрібних робіт, що повторюються, на авторів ігор та ролей ... але це так, як це є зараз. Зауважте, що я не кажу, що ми повинні намагатися абстрагувати менеджерів пакунків подалі, намагаючись підтримувати всі їх конкретні параметри та команди, а просто мати простий спосіб встановити пакет, який є агностиком менеджера пакунків. Я також не кажу, що всі ми повинні стрибати на Smart Package Managerпростір, але якийсь шар абстракції від встановлення пакету у вашому інструменті управління конфігурацією дуже корисний для спрощення міжплатформних ігор / кулінарних книг. Проект Smart виглядає цікаво, але досить амбітним є уніфікація управління пакунками у різних дистрибутивах та платформах без особливого прийняття… Буде цікаво побачити, чи успішний він. Справжня проблема полягає лише в тому, що назви пакетів іноді мають різницю у різних дистрибутивах, тому нам доводиться робити заяви справи або when:заяви, щоб вирішити відмінності.

Те, як я маю справу з цим, - це слідувати цій tasksструктурі каталогів у книзі чи ролі:

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

І тоді майте це в моєму main.yml:

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

- include: foo.yml tags=foo

Це в foo.yml(для пакета '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'

Тоді для різних менеджерів пакетів:

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

Домашня мова:

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

- homebrew: >
    name=foo
    state=latest

Зауважте, що це жахливо повторюється, і це НЕ СУХО , і хоча деякі речі можуть бути різними на різних платформах, і їх потрібно буде вирішити, як правило, я вважаю, що це багатослівно і громіздко порівняно з шеф-кухарями:

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

І так, є аргумент, що назви деяких пакетів різняться по дистрибутивам. І хоча в даний час є відсутність легкодоступних даних , я б ризикнув припустити , що найбільш популярні імена пакетів є загальними для всіх дистрибутивів і можуть бути встановлені з допомогою відведеного модуля менеджера пакетів. У будь-якому випадку потрібно вирішувати особливі випадки, і це вже потребує додаткової роботи, що робить речі менше ДУХИми, якщо сумніваєтесь, перевірте pkgs.org .


За допомогою Ansible 2 ви можете використовувати модуль пакету, щоб абстрагувати все це docs.ansible.com/ansible/package_module.html
— Guido

@ GuidoGarcía: Дуже приємно! Додавання примітки про це для Ansible 2.0
— TrinitronX

Можливо, варто також згадати, що ви можете вказати список, розділений комами, або просто список пакетів.
— Уес Тернер

13

Ви можете абстрагувати менеджерів пакунків за допомогою фактів

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

Все, що вам потрібно, це певна логіка, яка встановлюється ansible_pkg_mgrна aptі yumт.д.

Відповідальні також працюють над тим, що ви хочете, у майбутньому модулі .


1
Відповідь встановлює ansible_pkg_mgrсебе для будь-якого пакувальника, про якого він знає. Вам нічого не потрібно робити. Я використовую цю конструкцію скрізь.
— Майкл Хемптон

Синтаксис все ще досить корисний для тих, хто хоче оптимізувати виконання своїх ігрових книжок. Модуль загального пакету ще не забезпечує оптимізацію for_items, тому він набагато повільніше, коли він використовується для установки декількох пакетів одночасно.
— Данила Вершинін

@DanielV. Зауважте, що проблема github дійсно вирішує цю проблему.
— Майкл Хемптон

6

З Ansible 2.0 з'явився новий Package-модуль.

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

Потім ви можете використовувати його як вашу пропозицію:

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

Ви все ще повинні врахувати відмінності імен.


3

Перегляньте документацію Ansible про умовний імпорт .

Одне завдання - забезпечити роботу apache, навіть якщо назви служб різні для кожної ОС.

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

2

Ви не хочете цього робити, оскільки певні назви пакунків відрізняються між дистрибутивами. Наприклад, у дистрибутивах, пов'язаних з RHEL, називається популярний пакет веб-серверів httpd, де, як і в дистрибутивах, пов'язаних з Debian, він названий apache2. Аналогічно з величезним списком інших системних та підтримуючих бібліотек.

Можливо, існує набір загальних основних параметрів, але тоді також існує ряд більш досконалих параметрів, які відрізняються між менеджерами пакетів. І ви не хочете опинятися в неоднозначній ситуації, коли для деяких команд ви використовуєте один синтаксис, а для інших команд - інший синтаксис.


Це більш-менш те, чого я очікував (на жаль :)), тому мені цікаво, як saltвдається об’єднати обох менеджерів пакетів. Так чи інакше, я вдадуся до подвійної конфігурації.
— WoJ

Або не керуйте зоопарком дистрибуції ;-) переходите до інфраструктури з одним дистрибутивом і живете щасливішим життям.
— Mxx

На щастя, у великій кількості лише дві тварини, але це найнижча кількість, на яку я можу зайти :)
— WoJ

1
@Mxx - це нормальна логіка для sysadmin, але як щодо постачальника програмного забезпечення або консультанта, який підтримує кілька платформ?
— Девід Х. Беннетт

@David, тоді це потрібно вирішити у постачальників дистрибутивів, щоб вони мали уніфіковані назви пакетів та встановлювали інструменти. Реально немає можливості, що Ansible може мати уніфіковане відображення ВСІХ пакетів з усіх підтримуваних дистрибутивів усіх версій.
— Mxx
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.