Skip to content

Commit 379de4c

Browse files
committed
Finished 'src/usage/playbook/man_data.md'.
1 parent 5ca37ea commit 379de4c

File tree

4 files changed

+218
-7
lines changed

4 files changed

+218
-7
lines changed

adv_syntax/demo.yml

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
1-
---
2-
- name: Data manipulating
1+
- hosts: all
32
gather_facts: yes
4-
hosts: all
53

64
tasks:
7-
- name: Get the unique list of values of a variable that vary per host
5+
- name: Show the uptime in days/hours/minutes/seconds
86
ansible.builtin.debug:
9-
msg: "{{ unique_value_list }}"
10-
vars:
11-
unique_value_list: "{{ groups['all'] | map('extract', hostvars, 'varname') | list | unique }}"
7+
msg: Uptime {{ now().replace(microsecond=0) - now().fromtimestamp(now(fmt='%s') | int - ansible_uptime_seconds) }}

adv_syntax/files/prod/demo.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
prod: demo

adv_syntax/files/web/demo.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
web: demo

src/usage/playbook/man_data.md

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,216 @@ ok: [localhost] => {
103103

104104
### 找出挂载点
105105

106+
107+
在这个示例中,我们打算找出所有机器上,某个指定路径的挂载点,由于我们已经收集了挂载事实,因此我们可使用下面的方法:
108+
109+
110+
```yaml
111+
---
112+
- hosts: all:!win10-133
113+
gather_facts: yes
114+
vars:
115+
path: /boot
116+
117+
tasks:
118+
- name: The mount point for {{path}}, found using the Ansible mount facts, [-1] is the same as the 'last' filter
119+
ansible.builtin.debug:
120+
msg: "{{(ansible_facts.mounts | selectattr('mount', 'in', path) | list | sort(attribute='mount'))[-1]['mount']}}"
121+
```
122+
123+
> **译注**:可以看到,在任务的 `name` 字段中,也可以使用模板插值语法。
124+
125+
126+
### 略去列表中的一些元素
127+
128+
129+
这个特殊的 `omit` 变量,只适用于模组的选项,但咱们仍可以其他方式,将其用作其他裁剪某个元素清单的标识符:
130+
131+
132+
*在喂给某个模组选项数据时的内联列表过滤器*
133+
134+
135+
```yaml
136+
- name: Enable a list of Windows features, by name
137+
ansible.builtin.set_fact:
138+
win_feature_list: "{{ namestuff | reject('equalto', omit) | list }}"
139+
vars:
140+
namestuff:
141+
- "{{ (fs_installed_smb_v1 | default(False)) | ternary(omit, 'FS-SMB1') }}"
142+
- "foo"
143+
- "bar"
144+
```
145+
146+
另一种方法是避免在列表开头添加元素,这样咱们就可以直接使用,another way is to avoid adding elements to the list in the first place, so you can just use it directly:
147+
148+
149+
*在循环中使用 `set_fact` 有条件地递增某个列表*
150+
151+
152+
```yaml
153+
- name: Build unique list with some items conditionally omitted
154+
ansible.builtin.debug:
155+
msg: ' {{ (namestuff | default([])) | union([item]) }}'
156+
when: item != omit
157+
loop:
158+
- "{{ (fs_installed_smb_v1 | default(False)) | ternary(omit, 'FS-SMB1') }}"
159+
- "foo"
160+
- "bar"
161+
```
162+
163+
164+
### 合并同一字典列表中的值
165+
166+
167+
结合上述示例中的正向与负向过滤器,咱们就可以得到 “确实存在的值”,以及当不存在时的 “回退值”。
168+
169+
170+
*使用 `selectattr` 和 `rejectattr` 获取获取所需的 `ansible_host` 或 `inventory_hostname`*
171+
172+
```yaml
173+
- hosts: localhost
174+
175+
tasks:
176+
- name: Check hosts in inventory that respond to ssh port
177+
wait_for:
178+
host: "{{ item }}"
179+
port: 22
180+
loop: '{{ has_ah + no_ah }}'
181+
vars:
182+
has_ah: '{{ hostvars|dictsort|selectattr("1.ansible_host", "defined")|map(attribute="1.ansible_host")|list }}'
183+
no_ah: '{{ hostvars|dictsort|rejectattr("1.ansible_host", "defined")|map(attribute="0")|list }}'
184+
```
185+
186+
### 根据某个变量定制 `fileglob`
187+
188+
下面这个示例使用了 [Python 参数列表解包语法](https://docs.python.org/3/tutorial/controlflow.html#unpacking-argument-lists),以根据某个变量,创建出一个自定义的 `fileglob` 列表。
189+
190+
191+
```yaml
192+
- hosts: webservers
193+
gather_facts: no
194+
195+
vars:
196+
mygroups:
197+
- prod
198+
- web
199+
200+
tasks:
201+
- name: Copy a glob of files based on a list of groups
202+
copy:
203+
src: "{{ item }}"
204+
dest: "/tmp/{{ item }}"
205+
loop: '{{ q("fileglob", *globlist) }}'
206+
vars:
207+
globlist: '{{ mygroups | map("regex_replace", "^(.*)$", "files/\1/*.conf") | list }}'
208+
```
209+
210+
> **译注**:这个示例中,`globlist` 的值如下:
211+
212+
```json
213+
[
214+
"files/prod/*.conf",
215+
"files/web/*.conf"
216+
]
217+
```
218+
219+
> `q("fileglob", *globlist)` 将查找出 playbook 所在目录下,与 `globlist` 匹配的文件。
220+
221+
222+
## 复杂的类型转换
223+
224+
225+
Jinja 提供了简单数据类型转换(`int`、`bool` 等)的过滤器,但当咱们想转换某些数据结构时,事情就没那么简单了。咱们可以使用循环和列表综合(如上示)来帮忙,也可使用一些其他可以链接起来的过滤器和查找,实现更复杂的转换。
226+
227+
228+
### 从列表创建字典
229+
230+
在大多数语言中,从成对的列表,创建出字典(也称为映射/关联数组/哈希表,map/associative array/hash,等)都不难。在 Ansible 中,有几种方法可以做到这点,而最适合咱们的方法,则可能取决于咱们的数据源。
231+
232+
233+
下面这两个示例,会产生出 `{"a": "b", "c": "d"}` 这个字典。
234+
235+
236+
*假定列表为 `[key, value, key, value, ...]` 形式下的简单列表到字典转换*
237+
238+
239+
```yaml
240+
vars:
241+
single_list: [ 'a', 'b', 'c', 'd' ]
242+
mydict: "{{ dict(single_list[::2] | zip_longest(single_list[1::2])) }}"
243+
```
244+
245+
*当咱们有个成对的列表时,就更简单*:
246+
247+
248+
```yaml
249+
vars:
250+
list_of_pairs: [ ['a', 'b'], ['c', 'd'] ]
251+
mydict: "{{ dict(list_of_pairs) }}"
252+
```
253+
254+
255+
两者的最终结果一样,`zip_longest` 将 `single_list`,转换为一个 `list_of_pairs` 的生成器。
256+
257+
258+
稍微复杂一些,使用 `set_fact` 和 `loop`,从来自 2 个列表的键值对创建/更新出一个字典:
259+
260+
*使用 `set_fact` 从列表集合创建出一个字典*
261+
262+
```yaml
263+
- name: Uses 'combine' to update the dictionary and 'zip' to make pairs of both lists
264+
ansible.builtin.set_fact:
265+
mydict: "{{ mydict | default({}) | combine({item[0]: item[1]}) }}"
266+
loop: "{{ (keys | zip(values)) | list }}"
267+
vars:
268+
keys:
269+
- foo
270+
- var
271+
- bar
272+
values:
273+
- a
274+
- b
275+
- c
276+
```
277+
278+
这会得到 `{"foo": "a", "var": "b", "bar": "c"}`。
279+
280+
咱们甚至可以将这些简单示例与其他筛选器和查找插件结合,通过变量名模式匹配,动态地创建出字典:
281+
282+
283+
```yaml
284+
vars:
285+
xyz_stuff: 1234
286+
xyz_morestuff: 567
287+
abc_stuff: 890
288+
myvarnames: "{{ q('varnames', '^xyz_') }}"
289+
mydict: "{{ dict(myvarnames|map('regex_replace', '^xyz_', '')|list | zip(q('vars', *myvarnames))) }}"
290+
```
291+
292+
简单解释一下,因为从这两行中可以看出很多东西:
293+
294+
- 其中的 `varnames` 查找,会返回一个匹配 “以 `xyz_` 开头” 的变量列表;
295+
- 随后将上一步的列表,喂给其中的 `vars` 查找,以获得值的列表。`*` 用于 “解引用列表”(一种在 Jinja 中有效的 python 机制),否则他将把该列表作为单一参数;
296+
- 两个列表都会传递给 `zip` 过滤器,将他们配对成一个统一列表`(key、value、key2、value2...)`;
297+
- 随后 `dict` 函数会利用这个 “配对列表”,创建出字典。
298+
299+
下面是个如何使用事实,找出某个满足条件 X 的主机数据:
300+
301+
```yaml
302+
vars:
303+
uptime_of_host_most_recently_rebooted: "{{ansible_play_hosts_all | map('extract', hostvars, 'ansible_uptime_seconds') | sort | first}}"
304+
```
305+
306+
307+
下面是个以 天/小时/分钟/秒 为单位,显示某个主机运行时间的示例(假设事实已收集)。
308+
309+
310+
```yaml
311+
- name: Show the uptime in days/hours/minutes/seconds
312+
ansible.builtin.debug:
313+
msg: Uptime {{ now().replace(microsecond=0) - now().fromtimestamp(now(fmt='%s') | int - ansible_uptime_seconds) }}
314+
```
315+
316+
(End)
317+
318+

0 commit comments

Comments
 (0)