由于某些业务限制,出于库存目的,我编写了一个剧本,检索 resolv.conf + ntp.conf + timesyncd.conf 的内容,然后将检索到的内容写入 CSV 文件中。
从总体上看,这可能不是最佳做法,但我在每个检索文件内容的任务中都设置了一个事实,然后我按照自己的想法格式化数据,最后将它们写入 csv 中,如 data1;data2;data3;
我遇到了一些问题/疑问:
- 如果文件不存在,Ansible 任务将失败并且不会转到下一个任务,我知道这是设计使然。为了防止这种情况,在检索任务时使用 failed_when/changed_when 条件是否是一个好的解决方案?
- 在最后一个任务(“将结果写入...”)中,如何处理不存在的事实?目前,如果存在 3 个事实,则写入文件。如果 1/3 的事实不存在,但其他事实存在,则不会写入任何内容。非常感谢您的建议。剧本如下
---
- name: sys-check_conf_ntp_dns_net
hosts: my_servers
remote_user: my_user
tasks:
# RESOLV.CONF
- name: Retrieve remote /etc/resolv.conf
ansible.builtin.slurp:
src: /etc/resolv.conf
register: resolv_conf
- name: Format resolv_conf_fact data
set_fact:
resolv_conf_fact: "{{ (resolv_conf['content'] | b64decode) | regex_findall('\\s*nameserver\\s*(.*)') }}"
# NTP.CONF
- name: Retrieve remote /etc/ntp.conf
ansible.builtin.slurp:
src: /etc/ntp.conf
register: ntp_conf
- name: Format ntp_conf_fact data
set_fact:
ntp_conf_fact: "{{ (ntp_conf['content'] | b64decode) | regex_findall('(\\nserver.*?)(\\n)') }}"
# TIMESYNCD.CONF
- name: Retrieve /etc/systemd/timesyncd.conf
ansible.builtin.slurp:
src: /etc/systemd/timesyncd.conf
register: timesyncd_conf
- name: Format timesyncd_conf_fact data
set_fact:
timesyncd_conf_fact: "{{ (timesyncd_conf['content'] | b64decode) | regex_search('(NTP=f.*)') }}"
- name: Write results to /tmp/sys-check_conf_ntp_dns_net.csv
lineinfile:
path: /tmp/sys-check_conf_ntp_dns_net.csv
line: "Hostname:{{inventory_hostname}};resolv.conf:{{ resolv_conf_fact }};ntp.conf:{{ ntp_conf_fact }};timesyncd.conf:{{ timesyncd_conf_fact }};"
create: yes
delegate_to: localhost
编辑
我终于找到了解决办法,不确定它是否合法:D对于我设置的每个事实,我都添加一个默认值,然后当它通过正则表达式进行过滤时,它的行为就像事实不为空一样,所以最后似乎起作用了。
例如 :
先设定一个事实:
ntp_conf_fact: "{{ (ntp_conf['content'] | b64decode) | regex_findall('(\\nserver.*?)(\\n)') }}"
确定事实后:
ntp_conf_fact: "{{ ((ntp_conf['content']|default([blabla])) | b64decode) | regex_findall('(\\nserver.*?)(\\n)') }}"
有人可以确认这听起来是否正确吗?或者是否有人有不同的解决方案?
答案1
使用default
您的方法default
绝对正确,而且可行。
您不需要放置所有括号,您可以简单地将其写成:
{{ ntp_conf['content'] | default('') | b64decode | regex_findall('(\\nserver.*?)(\\n)') }}
如果文件不存在,slurp 会失败
slurp
如果文件不存在则会失败,其后果是执行被中断failed
。
示例输出:
TASK [Retrieve remote /etc/resolv.conf] ************************************************************
ok: [server1]
TASK [Format resolv_conf_fact data] ****************************************************************
ok: [server1]
TASK [Retrieve remote /etc/ntp.conf] ***************************************************************
fatal: [server1]: FAILED! => {"changed": false, "msg": "file not found: /etc/ntp.conf"}
PLAY RECAP *****************************************************************************************
server1 : ok=2 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
ignore_errors: true
为了防止这种情况,您应该在任务中添加slurp
。这样,如果发生错误,它将被忽略并继续执行。您可以按照上面描述的方法使用来处理此异常default
。
NTP 任务示例:
- name: Retrieve remote /etc/ntp.conf
ansible.builtin.slurp:
src: /etc/ntp.conf
ignore_errors: true
register: ntp_conf
使用set_fact
或执行任务vars
读取数据并将其存储在变量中set_fact
没有任何问题,并且可以通过这种方式实现。
注意:如果通过 存储值到变量中set_fact
,则这些值可用于所有后续任务,直到运行结束(只要不被覆盖),并可用于任意数量的任务。这同样适用于 存储的数据register:
。
如果您需要在“写入结果”任务中仅存储一次数据set_fact
,则可以在相应的任务中直接定义变量,而无需制定单独的set_fact
任务。
注意:在任务中使用 定义的变量vars:
只在该任务内有效且可用,即它们在该任务范围内。
你的剧本可以是这样的:
---
- name: sys-check_conf_ntp_dns_net
hosts: my_servers
remote_user: my_user
tasks:
# RESOLV.CONF
- name: Retrieve remote /etc/resolv.conf
ansible.builtin.slurp:
src: /etc/resolv.conf
ignore_errors: true
register: resolv_conf
# NTP.CONF
- name: Retrieve remote /etc/ntp.conf
ansible.builtin.slurp:
src: /etc/ntp.conf
ignore_errors: true
register: ntp_conf
# TIMESYNCD.CONF
- name: Retrieve /etc/systemd/timesyncd.conf
ansible.builtin.slurp:
src: /etc/systemd/timesyncd.conf
ignore_errors: true
register: timesyncd_conf
- name: Write results to /tmp/sys-check_conf_ntp_dns_net.csv
lineinfile:
path: /tmp/sys-check_conf_ntp_dns_net.csv
line: "Hostname:{{inventory_hostname}};resolv.conf:{{ resolv }};ntp.conf:{{ ntp }};timesyncd.conf:{{ timesyncd }};"
create: yes
vars:
resolv: "{{ resolv_conf['content'] | default('') | b64decode | regex_findall('\\s*nameserver\\s*(.*)') }}"
ntp: "{{ ntp_conf['content'] | default('') | b64decode | regex_findall('(\\nserver.*?)(\\n)') }}"
timesyncd: "{{ timesyncd_conf['content'] | default('') | b64decode | regex_search('(NTP=f.*)') }}"
delegate_to: localhost
如果数据仅需要一次,则使用的vars:
优点是可以加速整个剧本的执行,因为任务数量减少了。