Ansible剧本替换模块无法正常运行

时间:2020-10-30 03:21:44

标签: ansible

在此处使用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被忽略了。

1 个答案:

答案 0 :(得分:0)

默认情况下,replace模块将替换在regexp中发现的path的所有出现。引用官方文档:

  • 此模块将替换文件中某个模式的所有实例。
  • 由用户决定是否保持同等性,方法是确保相同的模式永远不会与进行的任何替换相匹配。

为限制这一点,我们可以使用beforeafter

现在,我对此进行解释:

尽管文档没有说明beforeafter是在同一行还是在上下两行 n行。我认为,为了使replace可靠地工作,beforeafter表达式应位于同一行。

我们可以通过以下示例进行演示:

让我们考虑一个包含以下内容的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的版本。

现在解决方案

在我对问题进行评论时,有更好的选择来实现您的目标。除了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" }