Ansible lineinfile

利用lineinfile 添加dns 解析

lineinfile模块用于在源文件中插入、删除、替换行,和sed命令的功能类似,也支持正则表达式匹配和替换。

---
- name: add DNS for each
  hosts: all
  gather_facts: true
  tasks: 
    - name: add DNS
      lineinfile: 
        path: "/etc/hosts"
        line: "{{item}} {{hostvars[item].ansible_hostname}}"
      when: item != inventory_hostname
      loop: "{{ play_hosts }}"

lineinfile 字面意思为“行在文件中”

行的添加

---
- name: test inlinefile
  hosts: localhost
  gather_facts: false
  tasks: 
    - lineinfile:
        path: "a.txt"
        line: "this line must in"

如果 a.txt 中没有 this line must in 就添加到最后一行

如果再次执行,则不会再次追加此行。因为lineinfile模块的state参数默认值为present,它能保证幂等性,当要插入的行已经存在时则不会再插入。

如果要移除某行,则设置state参数值为absent即可。下面的任务会移除a.txt中所有的”this line must not in”行(如果多行则全部移除)。

- lineinfile:
    path: "a.txt"
    line: "this line must not in"
    state: absent

行前和行后插入

如果想要在某行前、某行后插入指定数据行,则结合insertbeforeinsertafter。例如:

- lineinfile:
    path: "a.txt"
    line: "LINE1"
    insertbefore: '^para.* 2'

- lineinfile:
    path: "a.txt"
    line: "LINE2"
    insertafter: '^para.* 2'

注意,insertbefore和insertafter指定的正则表达式如果匹配了多行,则默认选中最后一个匹配行,然后在被选中的行前、行后插入。如果明确要指定选中第一次匹配的行,则指定参数firstmatch=yes

- lineinfile:
    path: "a.txt"
    line: "LINE1"
    insertbefore: '^para.* 2'
    firstmatch: yes

此外,对于insertbefore,如果它的正则表达式匹配失败,则会插入到文件的尾部。

行替换

lineinfile还可以替换行,使用regexp参数指定要匹配并被替换的行即可,默认替换最后一个匹配成功的行。

- lineinfile:
    path: "a.txt"
    line: "LINE1"
    regexp: '^para.* 2'

play_hosts和hostvars变量

inventory_hostname变量已经使用过几次了,它表示当前正在执行任务的主机在inventory中定义的名称。在此示例中,inventory中的主机名都是IP地址。

play_hostshostvars是Ansible的预定义变量,执行任务时可以直接拿来使用,不过在Ansible中预定义变量有专门的称呼:魔法变量(magic variables)。Ansible支持不少魔法变量,详细信息参见官方手册:https://docs.ansible.com/ansible/latest/reference_appendices/special_variables.html#magic

首先是play_hosts变量,它存储当前play所涉及的所有主机列表,但连接失败或执行任务失败的节点不会留在此变量中。

例如,某play指定了hosts: all,那么执行这个play时,play_hosts中就以列表的方式存储了all组中的所有主机名。

hostvars变量用于保存所有和主机相关的变量,通常包括inventory中定义的主机变量和gather_facts收集到的主机信息变量hostvars是一个key/value格式的字典(即hash结构、对象),key是每个节点的主机名,value是该主机对应的变量数据。

例如,在inventory中有一行:

192.168.200.27 myvar="hello world"

如果要通过hostvars来访问该主机变量,则使用hostvars['192.168.200.27'].myvar

因为gather_facts收集的主机信息也会保存在hostvars变量中,所以也可以通过hostvars去访问收集到的信息。gather_facts中收集了非常多的信息,目前只需记住此处所涉及的ansible_hostname即可,它保存的是收集目标主机信息而来的主机名,不是定义在Ansible端inventory中的主机名(因为可能是IP地址)。

再者,由于hostvars中保存了所有目标主机的主机变量,所以任何一个节点都可以通过它去访问其它节点的主机变量。比如示例中hostvars[item].ansible_hostname访问的是某个主机的ansible_hostname变量。

再来看互相添加DNS解析记录的示例:

- name: add DNS
  lineinfile: 
    path: "/etc/hosts"
    line: "{{item}} {{hostvars[item].ansible_hostname}}"
  when: item != inventory_hostname
  loop: "{{ play_hosts }}"

Index