Если вам нужен единый набор задач, достаточно гибкий для нескольких Linux менеджеров пакетов и macOS brew, вы можете выбрать больше logi c или больше дублирования.
Эти три шаблона должны помочь . У них все еще есть повторение и шаблонный код, но это территория, на которой мы находимся с Ansible воспроизведением для кроссплатформенных.
- Объявить
become: yes
(root) глобально только для Linux - Адреса пакетов, требующих специфической для платформы c обработки по мере необходимости с помощью
when
- Это может быть
--head
для brew
или настройка PPA для apt
, et c
- Сопоставьте несоответствия имен пакетов с переменными
- Например:
brew install ncurses
, apt install libncurses5-dev
и dnf install ncurses-devel
- это одна и та же библиотека.
1) Объявить become: yes
(root) глобально только для Linux
Для Linux хостов, переключение на root для установка - это предполагаемое поведение. Для macOS a la Homebrew установка root не подходит. Итак, нам нужно become: yes
(true
) при использовании brew
и become: no
(false
) в противном случае (для Linux).
В вашем примере директива become
вложены в каждую задачу («шаг»). Чтобы предотвратить дублирование, перед запуском задач вызовите become
в более высокой лексической области. Последующие задачи затем унаследуют состояние become
, которое устанавливается на основе условного выражения.
К сожалению, переменная для become
в области воспроизведения root будет неопределенной и вызовет ошибку перед запускается первая задача:
# playbook.yml
- name: Demo
hosts: localhost
connection: local
# This works
become: True
# This doesn't - the variable is undefined
become: "{{ False if ansible_pkg_mgr == 'brew' else True }}"
# Nor does this - also undefined
become: "{{ False if ansible_os_family == 'Darwin' else True }}"
tasks:
# ...
Чтобы исправить это, мы можем сохранить задачи в другом файле и импортировать их или заключить задачи в блок . Любой из этих шаблонов предоставит возможность объявить become
с нашим значением настраиваемой переменной вовремя, чтобы задачи его подобрали:
# playbook.yml
---
- name: Demo
hosts: localhost
connection: local
vars:
# This variable gives us a boolean for deciding whether or not to become
# root. It cascades down to any subsequent tasks unless overwritten.
should_be_root: "{{ true if ansible_pkg_mgr != 'brew' else false }}"
# It could also be based on the OS type, but since brew is the main cause
# it's probably better this way.
# should_be_root: "{{ False if ansible_os_family == 'Darwin' else True }}"
tasks:
# Import the tasks from another file, which gives us a chance to pass along
# a `become` context with our variable:
- import_tasks: test_tasks.yml
become: "{{ should_be_root }}"
# Wrapping the tasks in a block will also work:
- block:
- name: ncurses is present
package:
name: [libncurses5-dev, libncursesw5-dev]
state: present
- name: cmatrix is present
package:
name: cmatrix
state: present
become: "{{ should_be_root }}"
Теперь есть одна logi c проверка на brew
и одна директива before
(в зависимости от того, какой шаблон задачи используется выше). Все задачи будут выполняться от имени пользователя root, за исключением случаев, когда используется менеджер пакетов brew
.
2) Адресация пакетов, требующих обработки c в зависимости от платформы, с помощью when
Пакетный модуль очень удобен, но весьма ограничен. Сам по себе он работает только для идеальных сценариев; Это означает, что пакет не требует специальной обработки или флагов от базового менеджера пакетов. Все, что он может сделать, это передать буквальную строку пакета для установки, state
и необязательный параметр для принудительного использования указанного c исполняемого файла диспетчера пакетов.
Вот пример, который устанавливает wget
с красивой короткой задачей и становится подробным только для обработки особого случая ffmpeg
при установке с brew
:
# playbook.yml
# ...
tasks:
# wget is the same among package managers, nothing to see here
- name: wget is present
when: ansible_pkg_mgr != 'brew'
package:
name: wget
state: present
# This will only run on hosts that do not use `brew`, like linux
- name: ffmpeg is present
when: ansible_pkg_mgr != 'brew'
package:
name: ffmpeg
state: present
# This will only run on hosts that use `brew`, i.e. macOS
- name: ffmpeg is present (brew)
when: ansible_pkg_mgr == 'brew'
homebrew:
name: ffmpeg
# head flag
state: head
# --with-chromaprint --with-fdk-aac --with-etc-etc
install_options: with-chromaprint, with-fdk-aac, with-etc-etc
Приведенная выше игра даст этот результат для ffmpeg
против Linux box:
TASK [youtube-dl : ffmpeg is present] ******************************************
ok: [localhost]
TASK [youtube-dl : ffmpeg is present (brew)] ***********************************
skipping: [localhost]
3) Сопоставьте несоответствия в названии пакетов с переменными
Это не является частью вашего вопроса, но, скорее всего, он появится позже.
Модуль пакета в документации также упоминается:
Имена пакетов также зависят от диспетчера пакетов; этот модуль не будет «переводить» их для каждого дистрибутива. Например, libyaml-dev, libyaml-devel.
Итак, мы сами можем обрабатывать случаи, когда одно и то же программное обеспечение использует разные имена между платформами диспетчера пакетов. Это довольно часто.
Для этого существует несколько шаблонов, например:
Ни один из них не очень приятный. Вот подход с использованием роли . Роли действительно включают больше шаблонов и манипуляций с каталогами, но взамен они обеспечивают модульность и среду локальных переменных. Когда набор задач в роли требует большего количества изысков, чтобы получить правильное решение, это не приводит к загрязнению других наборов задач.
# playbook.yml
---
- name: Demo
hosts: localhost
connection: local
roles:
- cmatrix
# roles/cmatrix/defaults/main.yml
---
ncurses:
default:
- ncurses
# Important: these keys need to exactly match the name of package managers for
# our logic to hold up
apt:
- libncurses5-dev
- libncursesw5-dev
brew:
- pkg-config
- ncurses
# roles/cmatrix/tasks/main.yml
---
- name: cmatix and its dependencies are present
become: "{{ should_be_root }}"
block:
- name: ncurses is present
package:
name: '{{ item }}'
state: latest
loop: "{{ ncurses[ansible_pkg_mgr] | default(ncurses['default']) }}"
- name: cmatrix is present
when: ansible_pkg_mgr != 'brew'
package:
name: cmatrix
state: present
Задача для ncurses
ищет массив элементов для l oop с помощью ключей соответствующего пакета управляющий делами. Если используемый диспетчер пакетов не определен в объекте переменной, фильтр Jinja по умолчанию используется для ссылки на установленное нами значение default
.
В этом шаблоне просто добавляется поддержка другого диспетчера пакетов или дополнительных зависимостей. включает обновление объекта переменных:
# roles/cmatrix/defaults/main.yml
---
ncurses:
default:
- ncurses
apt:
- libncurses5-dev
- libncursesw5-dev
# add a new dependency for Debian
- imaginarycurses-dep
brew:
- pkg-config
- ncurses
# add support for Fedora
dnf:
- ncurses-devel
Объединение всего в реальную игру
Вот полный пример, охватывающий все три аспекта. В сборнике есть две роли, каждая из которых использует правильное значение become
на основе одной переменной. Он также включает особые случаи для cmatrix
и ffmpeg
при установке с brew
и обрабатывает альтернативные имена для ncurses между менеджерами пакетов.
# playbook.yml
---
- name: Demo
hosts: localhost
connection: local
vars:
should_be_root: "{{ true if ansible_pkg_mgr != 'brew' else false }}"
roles:
- cmatrix
- youtube-dl
# roles/cmatrix/defaults/main.yml
ncurses:
default:
- ncurses
apt:
- libncurses5-dev
- libncursesw5-dev
brew:
- pkg-config
- ncurses
dnf:
- ncurses-devel
# roles/cmatrix/tasks/main.yml
---
- name: cmatrix and dependencies are present
# A var from above, in the playbook
become: "{{ should_be_root }}"
block:
- name: ncurses is present
package:
name: '{{ item }}'
state: latest
# Get an array of the correct package names to install from the map in our
# default variables file
loop: "{{ ncurses[ansible_pkg_mgr] | default(ncurses['default']) }}"
# Install as usual if this is not a brew system
- name: cmatrix is present
when: ansible_pkg_mgr != 'brew'
package:
name: cmatrix
state: present
# If it is a brew system, use this instead
- name: cmatrix is present (brew)
when: ansible_pkg_mgr == 'brew'
homebrew:
name: cmatrix
state: head
install_options: with-some-option
# roles/youtube-dl/tasks/main.yml
---
- name: youtube-dl and dependencies are present
become: "{{ should_be_root }}"
block:
- name: ffmpeg is present
when: ansible_pkg_mgr != 'brew'
package:
name: ffmpeg
state: latest
- name: ffmpeg is present (brew)
when: ansible_pkg_mgr == 'brew'
homebrew:
name: ffmpeg
state: head
install_options: with-chromaprint, with-fdk-aac, with-etc-etc
- name: atomicparsley is present
package:
name: atomicparsley
state: latest
- name: youtube-dl is present
package:
name: youtube-dl
state: latest
Результат для Ubuntu:
$ ansible-playbook demo.yml
[WARNING]: provided hosts list is empty, only localhost is available. Note that
the implicit localhost does not match 'all'
PLAY [Demo] ********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [localhost]
TASK [cmatrix : ncurses is present] ********************************************
ok: [localhost] => (item=libncurses5-dev)
ok: [localhost] => (item=libncursesw5-dev)
TASK [cmatrix : cmatrix is present] ********************************************
ok: [localhost]
TASK [cmatrix : cmatrix is present (brew)] *************************************
skipping: [localhost]
TASK [youtube-dl : ffmpeg is present] ******************************************
ok: [localhost]
TASK [youtube-dl : ffmpeg is present (brew)] ***********************************
skipping: [localhost]
TASK [youtube-dl : atomicparsley is present] ***********************************
ok: [localhost]
TASK [youtube-dl : youtube-dl is present] **************************************
ok: [localhost]
PLAY RECAP *********************************************************************
localhost : ok=6 changed=0 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0