更新:从Ansible 2.0开始,现在有一个通用的抽象package
模块
用法示例:
现在,当不同操作系统系列的程序包名称相同时,它很简单:
---
- name: Install foo
package: name=foo state=latest
当软件包名称在OS系列中不同时,可以使用发行版或OS系列特定的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
编辑: 由于Michael DeHaan(Ansible的创建者)选择不像Chef那样抽象出软件包管理器模块,
如果您仍在使用旧版本的Ansible(Ansible <2.0),那么不幸的是,您需要在所有剧本和角色中进行此操作。 恕我直言,这将许多不必要的重复性工作推到了剧本和角色作者上……但这是目前的方式。请注意,我并不是说我们应该尝试抽象化软件包管理器,同时仍然尝试支持其所有特定选项和命令,而只是提供了一种安装与软件包管理器无关的软件包的简便方法。我并不是说我们都应该跳上 Smart Package Manager潮流,但是您的配置管理工具中的某种程序包安装抽象层对于简化跨平台的剧本/烹饪书非常有用。Smart项目看起来很有趣,但是要在许多发行版和平台上统一软件包管理却又没有被广泛采用的想法是相当大的。真正的问题只是包名称有时在发行版中会有所不同,因此我们仍然必须执行case语句或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'
然后针对不同的包管理器:
易于:
---
# 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
百胜:
---
# 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
请注意,这是完全重复的,而不是DRY,尽管在不同的平台上某些内容可能有所不同并且必须进行处理,但与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
是的,有一个论点是某些软件包名称在发行版之间是不同的。而且,尽管目前缺少易于访问的数据,但我敢猜测大多数流行的软件包名称在发行版中很常见,并且可以通过抽象的软件包管理器模块进行安装。特殊情况下无论如何都将需要处理,并且已经需要额外的工作以使事情减少DRY如有疑问,请检查pkgs.org。