Como unificar tarefas de instalação de pacotes em ansible?

61

Estou começando com ansible e vou usá-lo, entre outros, para instalar pacotes em várias distribuições Linux.

Eu vejo nos documentos que os comandos yum e apt estão separados - qual seria a maneira mais fácil de unificá-los e usar algo assim:

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

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

Eu entendo que os dois gerenciadores de pacotes são diferentes, mas eles ainda têm um conjunto de usos básicos comuns. Outros orquestradores ( sal, por exemplo ) possuem um único comando de instalação .

    
por WoJ 09.04.2014 / 13:45

5 respostas

60

Atualização: A partir do Ansible 2.0, existe agora um & genérico & package module

Exemplos de uso:

Agora, quando o nome do pacote é o mesmo em diferentes famílias de SO, é tão simples quanto:

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

Quando o nome do pacote difere entre as famílias do SO, você pode manipulá-lo com distribuição ou arquivos vars específicos da família 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

Em seguida, para cada SO que você deve manipular de forma diferente ... crie um arquivo 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: Desde Michael DeHaan (criador do Ansible) optou por não abstrair os módulos do gerenciador de pacotes como Chef ,

Se você ainda estiver usando uma versão mais antiga do Ansible (Ansible < 2.0) , infelizmente você precisará lidar com isso em todos IMHO isto empurra muito trabalho repetitivo desnecessário para a cartilha & autores de papéis ... mas é o jeito que é atualmente. Observe que não estou dizendo que devemos tentar abstrair os gerenciadores de pacotes enquanto ainda tentamos oferecer suporte a todas as suas opções e comandos específicos, mas apenas temos uma maneira fácil de instalar um pacote que seja agnóstico do gerenciador de pacotes. Eu também não estou dizendo que todos nós devemos pular no bandwagon Smart Package Manager , mas que algum tipo de camada de abstração de instalação de pacotes em sua configuração ferramenta de gerenciamento é muito útil para simplificar playbooks / livros de receitas entre plataformas. O projeto Smart parece interessante, mas é bastante ambicioso unificar o gerenciamento de pacotes em distribuições e plataformas sem muita adoção ainda ... será interessante ver se ele é bem-sucedido. A questão real é que os nomes dos pacotes às vezes tendem a ser diferentes entre distros, então ainda temos que fazer instruções case ou when: para lidar com as diferenças.

A maneira como tenho lidado com isso é seguir essa estrutura de diretório tasks em um playbook ou função:

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

E, em seguida, tem isso no meu main.yml :

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

- include: foo.yml tags=foo

Isso em foo.yml (para o pacote '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'

Em seguida, para os diferentes gerenciadores de pacotes:

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

Homebrew:

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

- homebrew: >
    name=foo
    state=latest

Observe que isso é terrivelmente repetitivo e não DRY e, embora algumas coisas possam ser diferente nas diferentes plataformas e terá que ser tratado, geralmente eu acho que isso é detalhado e pesado quando comparado ao do 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

E sim, existe o argumento de que os nomes dos pacotes alguns são diferentes nas distribuições. E embora exista atualmente uma falta de dados facilmente acessíveis , eu arriscaria adivinhar que A maioria dos nomes populares de pacotes é comum em distros e pode ser instalada através de um módulo gerenciador de pacotes. Casos especiais precisariam ser tratados de qualquer maneira, e já exigiriam trabalho extra tornando as coisas menos D.R.Y. Em caso de dúvida, verifique pkgs.org .

    
por 05.12.2014 / 04:14
13

Você pode abstrair os gerentes de pacotes por meio de fatos

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

Tudo o que você precisa é de uma lógica que defina ansible_pkg_mgr a apt ou yum etc.

Ansible também estão trabalhando para fazer o que você quer em um futuro módulo .

    
por 09.06.2015 / 20:08
6

Do Ansible 2.0, há o novo Package -modul.

link

Você pode usá-lo como sua proposta:

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

Você ainda precisa considerar diferenças de nome.

    
por 15.11.2015 / 12:52
3

Confira a documentação da Ansible sobre Importações condicionais .

Uma tarefa para garantir que o apache esteja sendo executado, mesmo que os nomes de serviço sejam diferentes em cada sistema operacional.

---
- 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
    
por 17.03.2015 / 17:19
2

Você não quer fazer isso porque certos nomes de pacotes diferem entre distros. Por exemplo, em distros relacionadas ao RHEL, o popular pacote de servidores web é chamado de httpd , onde, como nas distribuições relacionadas ao Debian, é nomeado apache2 . Da mesma forma, com uma lista enorme de outras bibliotecas de suporte e sistema.

Pode haver um conjunto de parâmetros básicos comuns, mas também há vários parâmetros mais avançados que são diferentes entre os gerenciadores de pacotes. E você não quer estar em uma situação ambígua onde para alguns comandos você usa uma sintaxe e para outros comandos você usa outra sintaxe.

    
por 10.04.2014 / 14:00