在此处使用Ansible 2.5.1
ansible-playbook 2.5.1
config file = /etc/ansible/ansible.cfg
configured module search path = [u'/home/user/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python2.7/dist-packages/ansible
executable location = /usr/bin/ansible-playbook
python version = 2.7.17 (default, Apr 15 2020, 17:20:14) [GCC 7.5.0]
我正在为grafana配置文件测试一个简单的replace
。在此文件中,我想将默认的domain = localhost
替换为实际的主机名domain = {{ ansible_host }}
我为此创建了一个简单的测试手册:
---
- name: Test replace
hosts: localhost
become: no
gather_facts: no
tasks:
- name: Update Grafana configuration - General
replace:
path: '/path/to/grafana_config_template.ini'
regexp: "{{ item.From }}"
replace: "{{ item.To }}"
before: "{{ item.Before }}"
after: "{{ item.After }}"
with_items:
- { From: "^(domain = localhost)$", To: "domain = foo", After: "[server]", Before: "[database]" } #doesn't work
- { From: "^(domain = localhost)$", To: "domain = foo", After: "", Before: "[database]" } #works
- { From: "^(domain = localhost)$", To: "domain = foo", After: "[server]", Before: "" } #works
用于grafana配置的提取文件如下:
...
#################################### Server ##############################
[server]
# Protocol (http, https, socket)
...
# The public facing domain name used to access grafana from a browser
domain = localhost
# Redirect to correct domain if host header does not match domain
# Prevents DNS rebinding attacks
enforce_domain = false
...
#################################### Database ############################
[database]
...
当我使用$ ansible-playbook test.yml -v
运行剧本时,我得到:
PLAY [Test config] *********************************************************************************************************************************************************
TASK [Update Grafana configuration - General] ******************************************************************************************************************************
ok: [localhost] => (item={u'To': u'domain = foo', u'After': u'[server]', u'From': u'^(domain = localhost)$', u'Before': u'.*[database]'}) => {"changed": false, "item": {"After": "[server]", "Before": ".*[database]", "From": "^(domain = localhost)$", "To": "domain = foo"}, "msg": ""}
changed: [localhost] => (item={u'To': u'domain = foo', u'After': u'', u'From': u'^(domain = localhost)$', u'Before': u'[database]'}) => {"changed": true, "item": {"After": "", "Before": "[database]", "From": "^(domain = localhost)$", "To": "domain = foo"}, "msg": "1 replacements made"}
ok: [localhost] => (item={u'To': u'domain = foo', u'After': u'[server]', u'From': u'^(domain = localhost)$', u'Before': u''}) => {"changed": false, "item": {"After": "[server]", "Before": "", "From": "^(domain = localhost)$", "To": "domain = foo"}, "msg": ""}
PLAY RECAP *****************************************************************************************************************************************************************
localhost : ok=1 changed=1 unreachable=0 failed=0
如您所见,“ After”或“ Before”有效,但不能同时使用。是的,我确实知道这三个替代品是互斥的。即如果#2运行,则#3不会做任何事情。另外,为了测试,我将以foo
代替{{ansible_host}}
。
知道为什么会这样吗?
编辑1:根据评论,我尝试了以下操作:
- { From: "^(domain = localhost)$", To: "domain = foo", After: "", Before: "[server]" }
- { From: "^(domain = localhost)$", To: "domain = foo", After: "[database]", Before: "" }
我期望两个替换都失败/不做任何事情,因为domain = localhost
是之后 [server]
和之前 [database]
,但是两者都被替换了...没有迹象表明为什么after / before被忽略了。
答案 0 :(得分:0)
默认情况下,replace
模块将替换在regexp
中发现的path
的所有出现。引用官方文档:
- 此模块将替换文件中某个模式的所有实例。
- 由用户决定是否保持同等性,方法是确保相同的模式永远不会与进行的任何替换相匹配。
为限制这一点,我们可以使用before
和after
。
现在,我对此进行解释:
尽管文档没有说明before
和after
是在同一行还是在上下两行 n行。我认为,为了使replace
可靠地工作,before
和after
表达式应位于同一行。
我们可以通过以下示例进行演示:
让我们考虑一个包含以下内容的sample.txt
:
ruby ansible chef
foo ansible baz
python ansible saltstack
现在假设我只想在ansible
行上将bar
更改为foo ansible baz
,那么我将执行以下任务:
- replace:
path: "sample.txt"
regexp: "ansible"
replace: "bar"
after: "foo"
before: "baz"
现在,当我们运行此任务时:
ruby ansible chef
-foo ansible baz
+foo bar baz
python ansible saltstack
注释中提到的Ansible replace中也存在一个错误,这会影响低于2.7.10的版本。
- 从Ansible 2.7.10开始,before和after的组合使用可以正常工作。如果您依靠以前的错误行为,则可能需要调整任务。有关详细信息,请参见https://github.com/ansible/ansible/issues/31354。
现在解决方案
在我对问题进行评论时,有更好的选择来实现您的目标。除了lineinfile模块之外,您还可以使用ini_file module:
- ini_file:
path: '/path/to/grafana_config_template.ini'
section: "server"
option: "{{ item.opt }}"
value: "{{ item.val }}"
with_items:
- { opt: "domain", val: "foo" }
- { opt: "enforced_domain", val: "true" }