如何统一软件包安装任务?

我从一开始就会使用它,在其他Linux发行版上安装软件包。

我在文档中看到, yumapt命令是分开的 – 将统一它们并使用类似这样的最简单的方法是什么:

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

我知道这两个软件包pipe理者是不同的,但他们仍然有一套共同的基本用法。 其他编排器( 例如salt )只有一个安装命令。

更新:从Ansible 2.0开始,现在有一个通用和抽象的package模块

用法示例:

现在,当不同操作系统系列中的软件包名称相同时,就像下面这样简单:

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

当不同操作系统的软件包名称不同时,您可以使用分发或操作系统系列特定的variables文件来处理它:

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

然后,对于您必须以不同方式处理的每个操作系统…创build一个variables文件:

 --- # 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的创build者) select不抽象像厨师那样的包pipe理器模块 ,

如果您仍在使用Ansible(Ansible <2.0)的旧版本,那么不幸的是,您需要在所有的剧本和angular色中处理这个问题。 恕我直言,这将大量不必要的重复性工作推到剧本和angular色作者身上……但是这是现在的方式。 请注意,我并不是说我们应该尝试抽象包pipe理器,同时仍然尝试支持所有特定的选项和命令,但是只需要一个简单的方法来安装与包pipe理器无关的包。 我也并不是说我们应该全力支持智能包pipe理器 ,但是configurationpipe理工具中的某种包安装抽象层对于简化跨平台的手册/食谱非常有用。 Smart项目看起来很有趣,但是统一整个发行版和平台之间的包pipe理却相当有雄心,却没有太多的采用呢……看看它是否成功将是有趣的。 真正的问题在于包名在发行版中有时会有所不同,所以我们仍然需要在case语句或when:语句来处理差异。

我一直在处理的方式是在剧本或angular色中遵循这个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' 

那么对于不同的包pipe理者来说:

易于:

 --- # 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 ,虽然有些事情可能会在不同的平台上有所不同,将不得不处理,但一般来说,我认为这是冗长的和笨重的,

 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 

是的,有一种说法是, 一些软件包名称在发行版中是不同的。 虽然目前缺乏易于访问的数据 ,但我敢说, 大多数stream行的软件包名称在发行版中都是常见的,可以通过抽象的软件包pipe理器模块进行安装。 特殊情况下需要处理,并且已经需要额外的工作,减less干扰如果有疑问,请查看pkgs.org 。

你可以通过事实抽象出包pipe理者

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

所有你需要的是将ansible_pkg_mgr设置为aptyum等的逻辑。

Ansible 也正在努力在未来的模块中做你想做的事情 。

从Ansible 2.0有新的Package模式。

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

你可以像你的build议一样使用它:

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

你仍然需要考虑名字的区别。

你不想这样做,因为发行版之间的某些软件包名称是不同的。 例如在RHEL相关的发行版上,stream行的web服务器软件包名为httpd ,与Debian相关的发行版一样,它被命名为apache2 。 与其他系统和支持库的大量列表类似。

可能有一组常见的基本参数,但是在包pipe理器之间还有一些更高级的参数是不同的。 而且你不想处于一种模棱两可的情况,对于某些命令你使用一种语法,对于其他命令你使用另一种语法。

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