Ansible技巧:使用copy模块自动选择文件分发源(类似于Chef cookbook_file资源)的示例

选项1: 自动选择原件

在Chef的cookbook_file资源中,相当于Ansible的copy模块,复制的源文件是查找COOKBOOK_NAME/files/路径下的第一个与之匹配的文件。

    1. /主机-\$完全限定域名/\$来源

 

    1. /\$平台-\$平台版本/\$来源

 

    1. /\$平台/\$来源

 

    1. /默认/\$来源

 

    /\$来源

以下是对链接中的内容进行汉语表达的释义:

1. https://docs.chef.io/resources/cookbook_file/
厨师文档库的资源页面,用于解释如何使用Cookbook File。

2. https://docs.chef.io/resources/cookbook_file/#cookbook_file_specificity
厨师文档库的资源页面中关于Cookbook File特定性的内容。

然而,Ansible的copy模块并没有该种自动选择复制源的功能。
要实现这种功能,应该怎么做呢?

设定2:将文件分发源设置为inventory_dir/files下。

在Ansible的copy模块中,文件的来源路径是相对路径指定的情况下,会从playbook_dir/files和playbook_dir下进行搜索。

然而,如果想要将playbook与逻辑分开、将inventory与数据分开的话,则最好将配布的来源放在playbook_dir下面inventory_dir下方。

补充/纠正

在ansible-playbook命令的-i选项中,可以指定可以用于主机清单的选项,例如-i inventory_dir可以指定目录。可以放置主机清单文件本身,或者放置在inventory_dir/host_vars或inventory_dir/group_vars中进行使用。然而,如果包含inventory_dir/files等不属于原始主机清单信息的文件,则会导致错误。因此,如果考虑到目录指定的问题,最好将其放置在inventory_dir之外。

最終的目標

我想要按照以下顺序搜索并分发复制源文件,就像Chef的cookbook_file资源一样。将首先找到的文件进行分发。

    1. “{{ inventory_dir }}/files/{{ inventory_hostname }}” 的路径下

 

    1. “{{ inventory_dir }}/files/{{ ansible_distribution }}-{{ ansible_distribution_version }}” 的路径下

 

    1. “{{ inventory_dir }}/files/{{ ansible_distribution }}” 的路径下

 

    1. “{{ inventory_dir }}/files/default” 的路径下

 

    “{{ inventory_dir }}/files” 的路径下

验证环境

    ansible 2.9.4

目录图像

inventory_dir
│
├── hosts             # inventory file
│
├── host_vars         # host_varsはinventory_dir下を使用している
│   ├── host01
│   │   └── main.yml
│   └── host02
│       └── main.yml
│
├── group_vars        # group_varsもinventory_dir下を使用している
│   └── all
│       └── main.yml
│
└── files             # **** ファイル配布元もinventory_dir下に置きたい ****
    ├── default     # 個別のノードで指定しない場合のデフォルト(Chef準拠)
    │   └── etc
    │       └── hosts
    ├── host01        # 個別のノードで指定する場合(Chef準拠)
    │   └── etc
    │       └── hosts

任务的示例对应
任务的例子对应
任务例子的对应

  - name: copy files from inventory_dir/files
    copy:
      src: "{{ lookup('first_found', paths|map('regex_replace','$',item)|list ) }}"
      dest: "{{ item }}"
    vars:
      paths:
      - "{{ inventory_dir }}/files/{{ inventory_hostname }}"
      - "{{ inventory_dir }}/files/{{ ansible_distribution }}-{{ ansible_distribution_version }}"
      - "{{ inventory_dir }}/files/{{ ansible_distribution }}"
      - "{{ inventory_dir }}/files/default"
      - "{{ inventory_dir }}/files"
    loop:
    - "/etc/hosts"
TASK [copy files from inventory_dir/files] *************************************************************************************
ok: [host01] => (item=/etc/hosts)
    • lookup(‘first_found’, … にて、コントローラーノード上でリスト順で最初に見つかったファイルをソースとする。

with_first_found: を用いると、ファイル名でのloopを行うには、ファイルを分けてimport_tasksなどを使用しなければいけなくなる。
jinja2によるfor loopと組み合わせる事でも対応可能。(可読性は落ちるが、柔軟な処理が可能)

mapフィルターにて、Arrayであるpathsの各要素に操作を行う。

操作を行うフィルターへのパラメーターは、map内での第2パラメーター以降で設定する。

つまり、各要素に | regex_replace(‘$’,item) というフィルターを掛け、各要素の最後にファイル名を付与する

最後にlistフィルターでArrayに戻す。

pathsに探索順にパスを定義

inventory_dir や inventory_hostname は Ansible が設定する値

copy対象ファイルはloop:にて回す

パス情報の管理を容易とするために絶対パス指定としている

请根据以下要求进行操作。

首次找到 – 从列表中返回第一个找到的文件
https://docs.ansible.com/ansible/latest/plugins/lookup/first_found.html

使用ansible 1.6版本时,在with_items循环中使用with_first_found功能?

使用`map(*args, **kwargs)`函数进行映射操作。详细信息请参考:https://jinja.palletsprojects.com/en/2.11.x/templates/#map

正则表达式过滤器
https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html#regular-expression-filters

Ansible Jinja2 过滤器可以用正则表达式替换和提取变量的字符串。

bannerAds