使用Ansible软件包模块与apt和Homebrew一起使用

时间:2020-08-04 07:40:29

标签: macos ansible homebrew

在创建适用于linux和macOS的剧本时,我遇到两个问题。

我的剧本中有很多类似的步骤:

- name: install something
  package:
    name: [something_1, something_2, ...]
    state: present
  become: yes

它对apt和yum都很好用,但是当我尝试在macOS上运行它时,自制软件会抱怨:

Running Homebrew as root is extremely dangerous and no longer supported.

我在许多地方都找不到解决此问题的优雅方法。复制所有任务,并使用 when 子句对我来说不堪重负。也许我可以根据分发情况使用将变为_user变量设置为root / local_user,但这也有很多更改。

第二个问题是纯头公式(只能用--head标志安装的自制软件包)。如果需要使用此标志安装something_2怎么办?同样,我可以复制任务并将 package 模块更改为 homebrew ,但这是很多样板。

有帮助吗?

1 个答案:

答案 0 :(得分:2)

如果您希望一组任务足够灵活以适应多个Linux 软件包管理器和macOS brew,选择是更多逻辑还是更多 重复。

这三种模式应该会有所帮助。他们仍然有重复和 样板代码,但这就是我们与Ansible合作的领域 用于跨平台。

  1. 仅在Linux上全局声明become: yes(root)
  2. 地址包需要when所需的特定于平台的处理
    • 这可能是--head的{​​{1}},或brew设置了PPA等
  3. 地图包名称与变量之间的差异
    • 例如:aptbrew install ncursesapt install libncurses5-dev都是同一个库。

1)仅在Linux上全局声明dnf install ncurses-devel(root)

对于Linux主机,切换到root进行安装是预期的行为。 对于macOS a la Homebrew,以root身份安装不是很好。因此,使用become: yes时需要become: yestrue),否则需要brewbecome: no)(对于 Linux)。

在您的示例中,false指令嵌套在每个任务(“步骤”)中。至 防止重复,在执行任务之前以更高的词汇范围调用become 开始。随后的任务将继承become的状态,即 根据条件表达式进行设置。

不幸的是,根剧本范围中become的变量将是 未定义并在运行第一个任务之前引发错误:

become

要解决此问题,我们可以将任务存储在另一个文件中并import,或者 将任务包装在block中。这些模式都可以提供 有机会及时用我们的自定义变量值声明# 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 }}" 有一个逻辑检查,而brew一个指令 (取决于上面使用的任务模式)。所有任务将以 超级用户,除非正在使用的程序包管理器为before

2)解决需要brew

所需要的平台特定处理的软件包

Package Module十分方便,但是非常有限。通过 本身仅适用于理想情况;意思是,一个没有 需要基础软件包管理器的任何特殊处理或标志。所有 它可以通过传递要安装的软件包的文字字符串,when和 可选参数,用于强制使用特定的程序包管理器可执行文件。

下面是一个示例,该示例安装了state并完成了很短的任务,并且仅 与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 在Linux机器上产生以下输出:

ffmpeg

3)映射包名称与变量不符

这不是您的问题的一部分,但很可能会在接下来出现。

Package Module文档还提到:

软件包名称也随软件包管理器而不同;该模块不会“翻译” 他们每个发行版。例如libyaml-dev,libyaml-devel。

因此,我们可以自行处理相同软件使用不同软件的情况 软件包管理器平台之间的名称。这很常见。

有多种模式,例如:

他们都不是很愉快。这是使用role的方法。角色做 涉及更多样板和目录杂耍,但作为交换,它们提供了 模块化和局部变量环境。当一组任务中的一个角色 需要更多的努力才能正确,它不会最终污染其他任务 设置。

TASK [youtube-dl : ffmpeg is present] ******************************************
ok: [localhost]

TASK [youtube-dl : ffmpeg is present (brew)] ***********************************
skipping: [localhost]

# 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 的任务寻找一组要循环输入的项目,由 相应的程序包管理器。如果未定义正在使用的程序包管理器 在变量对象中,使用Jinja默认过滤器来引用 我们设置的ncurses值。

使用此模式,添加对另一个程序包管理器或其他程序的支持 依赖关系仅涉及更新变量对象:

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 值。它也是 与becomecmatrix一起安装时的特殊情况 ffmpeg,并在程序包管理器之间处理ncurses的备用名称。

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

Ubuntu的结果:

# 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