我正在寻找一种修改配置文件并保留本地修改的方法。配置文件的格式类似于以下内容:
entry1: This is a local
entry2: modification.
entry3:
该文件由可变数量的键(entry1、entry2、entry3,以及可能稍后的entry4等 - 它可能最多为 100 个,将来甚至可能多达 2000 个左右)组成,这些键应由 Ansible 进行设置,然后是另一个程序将添加到配置文件中的附加选项。
我希望 Ansible 能够向文件添加新密钥,同时保留任何现有的本地修改。
最自然的选择似乎是 lineinfile - 但不幸的是,它只给了我任何一个保留本地修改(使用 backref=yes),或者添加新键(backref=yes 不会添加新行)。
有什么好方法可以实现我的需要吗?
我可以通过启用 lineinfile 和 backref 来修改现有条目:
- lineinfile:
path: myfile.conf
regexp: "^{{ item }}: (.*)"
backref: yes
line: "{{ item }}: \1"
with_items:
- entry1
- entry2
- entry3
- entry4
但这不会将 entry4 添加到我的文件中。
或者我可以使用 backref: no
- lineinfile:
path: myfile.conf
regexp: "^{{ item }}: (.*)"
backref: no
line: "{{ item }}:"
with_items:
- entry1
- entry2
- entry3
- entry4
但这会破坏entry1、entry2和entry3的本地修改。
或者我可以改变正则表达式:
- lineinfile:
path: myfile.conf
regexp: "^"
backref: no
line: "{{ item }}:"
with_items:
- entry1
- entry2
- entry3
- entry4
但这当然会在每次运行时添加每个键。
我也研究过使用模板(但还没有找到一种简单的方法来用它来操作现有文件)。
当然我可以编写自己的 Python 模块,但是一定有更简单的方法来做到这一点?
答案1
如果您正在修改众所周知的配置文件,则可以使用 Augeas 和以下 ansible augeas 插件:https://github.com/paluh/ansible-augeas
这是如何使用 augeas 的一个示例:
- name: Force password on sudo group
action: augeas path=/files/etc/sudoers/spec[user=\"sudo\"]/host_group/command/tag value=PASSWD
另一个选择是使用 lineinfile 命令来确保所需的行在文件中可用:http://docs.ansible.com/ansible/latest/lineinfile_module.html
例子:
- lineinfile:
path: /etc/selinux/config
regexp: '^SELINUX='
line: 'SELINUX=enforcing'
答案2
我找到了一种方法来做到这一点。诀窍是首先使用 grep 仅查找缺失的条目。
如果文件不存在,grep 将出错,因此我首先创建该文件:
copy: dest: myfile.conf content: "" force: no # set mode, owner, group to taste
现在使用 grep 来查找缺失的项目。如果条目已经存在,Grep 将返回 0,如果不存在,则返回 1。通常,返回代码 1 表示 Ansible 失败。failed_when: True 会改变这种情况。由于这只是检索信息而不是更改任何内容,因此它永远不会报告为“已更改”,因此也需要设置changed_when。
command: 'grep "^{{ item }}" myfile.conf' with_items: - entry1 - entry2 - entry3 - entry4 failed_when: False changed_when: False register: grep_output
Grep 会将输出结果存入已注册的变量 grep_output。在循环中使用时,grep_output 将包含一个名为 results 的数组,其中包含循环中每个项目的哈希值。在该数组中,我们找到了所需的所有信息:返回代码(称为 rc)和循环中的原始项目(称为 item)。
现在我们可以通过检查 rc 来添加缺失的条目。我不确定这里是否需要正则表达式。
lineinfile: path: myfile.conf regexp: "^{{ item.item }} *(.*)" insertafter: EOF line: '{{ item.item }}' state: present when: "item.rc > 0" with_items: "{{ grep_output.results }}"
答案3
lineinfile: path: myfile.conf regexp: "^{{ item }}: (.*)" backref: no line: "{{ item }}:" with_items: - entry1 - entry2 - entry3 - entry4