Ansible技巧:使用copy模块自动选择文件分发源(类似于Chef cookbook_file资源)的示例
选项1: 自动选择原件
在Chef的cookbook_file资源中,相当于Ansible的copy模块,复制的源文件是查找COOKBOOK_NAME/files/路径下的第一个与之匹配的文件。
-
- /主机-\$完全限定域名/\$来源
-
- /\$平台-\$平台版本/\$来源
-
- /\$平台/\$来源
-
- /默认/\$来源
- /\$来源
以下是对链接中的内容进行汉语表达的释义:
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资源一样。将首先找到的文件进行分发。
-
- “{{ 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” 的路径下
验证环境
- 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 过滤器可以用正则表达式替换和提取变量的字符串。