Jak ujednolicić zadania instalacji pakietu w ansible?

68

Zaczynam od ansible i wykorzystam go między innymi do instalowania pakietów na kilku dystrybucjach Linuksa.

W dokumentach widzę, że polecenia yumi aptsą rozdzielone - jaki byłby najłatwiejszy sposób na ich ujednolicenie i użycie czegoś takiego:

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

zamiast

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

Rozumiem, że dwaj menedżerowie pakietów są różni, ale nadal mają zestaw wspólnych podstawowych zastosowań. Inni orkiestatorzy ( na przykład sól ) mają jedno polecenie instalacji.

WoJ
źródło
Możesz mieć trzy przepisy: jedną, która iteruje wspólną listę, a następnie jedną dla list specyficznych dla systemu operacyjnego. Próbuję teraz dowiedzieć się, jak powiadomić program obsługi o nazwie usługi specyficznej dla systemu operacyjnego po ustawieniu wspólnego elementu konfiguracji. powodzenia!
dannyman

Odpowiedzi:

66

Aktualizacja: Począwszy od Ansible 2.0, jest teraz ogólny i abstrakcyjny packagemoduł

Przykłady użycia:

Teraz, gdy nazwa pakietu jest taka sama w różnych rodzinach systemów operacyjnych, jest tak prosta jak:

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

Gdy nazwa pakietu różni się w zależności od rodziny systemów operacyjnych, możesz obsługiwać ją za pomocą plików vars związanych z dystrybucją lub rodziną systemów operacyjnych:

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

Następnie dla każdego systemu operacyjnego, który musisz obsługiwać inaczej ... utwórz plik 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



EDYCJA: Ponieważ Michael DeHaan (twórca Ansible) postanowił nie wyodrębniać modułów menedżera pakietów, tak jak robi to Chef ,

Jeśli nadal używasz starszej wersji Ansible (Ansible <2.0) , niestety musisz poradzić sobie z robieniem tego we wszystkich swoich podręcznikach i rolach. IMHO popycha to wiele niepotrzebnych powtarzających się prac do autorów podręczników i ról ... ale tak już jest. Zauważ, że nie mówię, że powinniśmy próbować oddzielić menedżerów pakietów od siebie, jednocześnie próbując wesprzeć wszystkie ich specyficzne opcje i polecenia, ale po prostu mieć łatwy sposób na zainstalowanie pakietu, który jest niezależny od menedżera pakietów. Nie mówię też, że wszyscy powinniśmy wskoczyć na Smart Package Managerabandwagon, ale ten rodzaj warstwy abstrakcji instalacji pakietu w narzędziu do zarządzania konfiguracją jest bardzo przydatny do uproszczenia wieloplatformowych podręczników / książek kucharskich. Projekt Smart wygląda interesująco, ale ambitne jest ujednolicenie zarządzania pakietami w różnych dystrybucjach i platformach bez większego wdrożenia, jednak ... Ciekawe będzie, czy odniesie sukces. Prawdziwy problem polega na tym, że nazwy pakietów czasami różnią się w zależności od dystrybucji, więc nadal musimy wykonywać instrukcje case lub when:instrukcje, aby poradzić sobie z różnicami.

Sposób, w jaki sobie z tym poradziłem, polega na przestrzeganiu tej tasksstruktury katalogów w podręczniku lub roli:

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

A potem mam to w moim main.yml:

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

- include: foo.yml tags=foo

To w foo.yml(dla pakietu „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'

Następnie dla różnych menedżerów pakietów:

Trafny:

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

Mniam:

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

Pamiętaj, że jest to strasznie powtarzalne, a nie SUCHE , i chociaż niektóre rzeczy mogą być różne na różnych platformach i będą musiały być obsługiwane, ogólnie myślę, że jest to pełne i niewygodne w porównaniu do szefa kuchni:

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

I tak, istnieje argument, że niektóre nazwy pakietów różnią się w zależności od dystrybucji. I choć nie jest obecnie brak łatwo dostępnych danych , to ośmielam się domyślać, że najbardziej popularne nazwy pakietów są powszechne w dystrybucji i mogą być instalowane za pomocą pobieranej modułu menedżera pakietów. W każdym razie należałoby poradzić sobie ze specjalnymi przypadkami, które wymagałyby dodatkowej pracy, zmniejszając SUSZENIE W razie wątpliwości sprawdź pkgs.org .

TrinitronX
źródło
Za pomocą Ansible 2 możesz użyć modułu pakietu do streszczenia wszystkich tych docs.ansible.com/ansible/package_module.html
Guido
@ GuidoGarcía: Bardzo miło! Dodając notatkę na ten temat dla Ansible 2.0
TrinitronX
Być może warto również wspomnieć, że możesz podać listę oddzieloną przecinkami lub po prostu listę pakietów.
Wes Turner,
13

Za pomocą faktów można wyodrębnić menedżerów pakietów

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

Wszystko czego potrzebujesz to jakiś logiczny, który wyznacza ansible_pkg_mgrsię aptlub yumitd.

Ansible pracuje także nad tym, co chcesz w przyszłym module .

xddsg
źródło
1
Ansible ustawia ansible_pkg_mgrsię dla każdego programu pakującego, o którym wie. Nie musisz nic robić. Używam tego konkretnego konstruktu wszędzie.
Michael Hampton
Składnia jest nadal bardzo przydatna dla tych, którzy chcą zoptymalizować przebieg swoich podręczników. Ogólny moduł pakietu nie zapewnia jeszcze optymalizacji dla elementów with_items, więc jest znacznie wolniejszy, gdy jest używany do instalowania wielu pakietów jednocześnie.
Danila Vershinin
@DanielV. Zauważ, że problem github zapewnia obejście tego problemu.
Michael Hampton
3

Sprawdź dokumentację Ansible na temat importów warunkowych .

Jedno zadanie, aby upewnić się, że apache działa, nawet jeśli nazwy usług są różne w poszczególnych systemach operacyjnych.

---
- 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
źródło
2

Nie chcesz tego robić, ponieważ niektóre nazwy pakietów różnią się między dystrybucjami. Na przykład w dystrybucjach związanych z RHEL nazywa się popularny pakiet serwerów WWW httpd, a podobnie jak w dystrybucjach związanych z Debianem apache2. Podobnie z ogromną listą innych bibliotek systemowych i pomocniczych.

Może istnieć zestaw wspólnych podstawowych parametrów, ale jest też wiele bardziej zaawansowanych parametrów, które różnią się między menedżerami pakietów. I nie chcesz być w dwuznacznej sytuacji, w której dla niektórych poleceń używasz jednej składni, a dla innych poleceń używasz innej składni.

Mxx
źródło
Jest to mniej więcej to, czego się spodziewałem (niestety :)), więc zastanawiam się, jak saltudało się ujednolicić oba menedżery pakietów. W każdym razie skorzystam z podwójnej konfiguracji.
WoJ
Albo nie zarządzaj zoo w dystrybucji ;-) migruj do infrastruktury z pojedynczą dystrybucją i żyj szczęśliwszym życiem.
Mxx
Zoo jest na szczęście tylko dwoma zwierzętami, ale jest to najniższy numer, do jakiego mogę się udać :)
WoJ
1
@Mxx to logika dla administratora systemu, ale co z dostawcą oprogramowania lub konsultantem obsługującym wiele platform?
David H. Bennett
@David, należy to zająć u dystrybutorów, aby mieli ujednolicone nazwy pakietów i instalowali narzędzia. Realistycznie nie ma możliwości, aby Ansible mógł mieć ujednolicone mapowanie WSZYSTKICH pakietów ze wszystkich obsługiwanych dystrybucji wszystkich wersji.
Mxx