Ansible 技巧之场

Ansible 技巧之场

看到技巧之场,我就想起来被百万氪金王支配的恐惧!

拼接主机与http或其他字符串

有时候我们有一个列表,里面是IP地址。但是有时候我们要将http://拼接在每个IP地址的开头,可以利用Jinja2语法进行操作。

在模版中:

1
2
3
4
5
{% set http_hosts=[] %} # 定一个list变量
{% set hosts_list = discovery_seed_hosts | flatten %} # 将列表扁平化,因为这个变量列表里面存在嵌套的情况
{% for host in hosts_list %}
{% set _ = http_hosts.append("http://%s:%s" % (host,9200)) %} #使用Python语法进行操作。
{% endfor %}

在Plybook中(从网上找到的未经过测试,理论可行):

1
2
3
4
5
6
7
8
9
10
11
12
13
set_fact:
cluster_address: |
[
{% set pxc_hosts = groups.pxc %}
{% for host in pxc_hosts %}
{% set pxc_ip = hostvars[host].inventory_hostname | default(host) %}
{% set pxc_port = group_port %}
"{{ pxc_ip }}:{{ pxc_port }}"
{% endfor -}
]

# 使用的时候
{{ cluster_address | join(',') }}' # 使用join 过滤器可生成',' 分隔的字符串,分隔符自己定义

对字符串的操作

得益于Python特性,在Ansible中可以使用Python中处理字符串的语法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
你可以对字符串进行取单个字符等操作: {{ vars[2] }}

也可以切片: {{ vars[3:6]}}

判断某些字符是否在字符串中: when: "'haha' in vars"

使用加号连接两个字符串: {{ var1+var2 }}

使用乘号*连续输出字符串: {{ var1*3 / 'la'*nums }}

使用find函数查找:

when: {{ vars.find('test') == -1 }} # 值为

find函数的语法是find(string,begin,end)

when: {{ vars.find('test',5) == -1 }} # 从第5位开始查找

任务委派

有时候你想让某一个tasks在指定的某一个受控主机上运行而不是要在Play中指定的组或主机中全部运行这个tasks。

这种情况下可以新写一个Play,然后将hosts和tasks进行指定。但是这样要新建一个Play,有点麻烦。

可以使用delegate_to关键字来让某一个tasks指定运行在某一台主机上,任务委派时不会去看目标主机是否在inventory主机清单中。可以指定代码块进行任务委派。

1
2
3
4
5
6
7
8
9
- debug:
msg: "only host"
delegate_to: 192.168.1.196

---

ok: [192.168.1.39 -> 192.168.1.196] => {
"msg": "only host"
}

仅在主机上执行

如果指向让某一个任务在本主机上运行。你可以使用刚刚的任务委派,来指向Ansible控制节点。也可以尝试connection: local关键字。

connection关键字也可以用于代码块和任务。

1
2
3
4
5
6
- block:
- systemd:
name: elasticsearch
state: restarted
connection: local

仅运行一遍任务

在某些情况下,下载资源到本地时,你只需要下载一次就可以。但是任务却执行和主机清单中相同的次数。得益于Ansible模块幂等性,虽然说任务运行很多次,但只有第一次真正进行了下载,对我们的影响不大。但是能否继续减少性能开支呢。

使用run_once: true关键字让任务或代码块只运行一次。

1
2
3
4
5
6
7
8
9
10
11
12
- hosts: all
  gather_facts: no
  tasks:
  - get_url:
      url: "https://github.com/rofl0r/proxychains-ng/archive/v4.14.tar.gz"
      dest: "/tmp"
    connection: local
    run_once: true
 
  - copy:
      src: "/tmp/v4.14.tar.gz"
      dest: "/tmp"

遇到过的错误…

在when关键字中使用了Jinja2语法

[WARNING]: conditional statements should not include jinja2 templating delimiters such as {{ }} or {% %}. Found:XXX

在when关键字中不应该包含Jinja2语法。在使用循环或者变量时不小心就会顺手把花括号加上。此时会发出警告。

1
2
3
4
5
错误用法:
when: "'{{item.hosts}}' in group_names"

正确用法:
when: item.hosts in group_names

没有获取事实就要使用hostvars获取变量

在主机没有gether facts事实之前,是无法通过hostvars来获取它的事实变量的。这个错误在生成hosts文件时出现过一次,折腾了好久。难受的是没有指向正确的报错位置,这导致我在错误的方向研究了好久都没有解决。

1
2
3
4
5
6
7
错误用法:
when: "'{{item.hosts}}' in group_names"

---

正确用法:
when: item.hosts in group_names