如何使用Ansible解析crontab并导出条目至JSON文件
Ansible批量采集Crontab+集中管理落地方案
实现思路
整个方案分两个核心环节:先无侵入采集所有目标节点的全量Crontab条目,汇总到管理节点生成结构化JSON文件;后续直接编辑该JSON文件做配置调整,再通过幂等playbook批量推送到对应节点,全程不用登录目标节点手动操作。
需要覆盖的Crontab存储位置(遗漏任何一处都会导致采集不全):
- 所有系统用户的个人crontab配置
- 系统全局crontab文件
/etc/crontab /etc/cron.d/目录下的自定义定时任务文件/etc/cron.hourly///etc/cron.daily///etc/cron.weekly//etc/cron.monthly/目录下的周期执行脚本
第一步:全量采集生成JSON文件
直接用下面的playbook完成采集,不需要在目标节点安装额外依赖,兼容Debian、RHEL等主流发行版。
将以下内容保存为collect_cron.yml:
- name: 采集节点全量cron数据 hosts: all gather_facts: yes become: yes tasks: - name: 遍历所有系统用户读取个人crontab shell: "crontab -l -u {{ item }}" loop: "{{ ansible_facts.getent_passwd.keys() | list }}" register: user_cron_res failed_when: false changed_when: false # 自动忽略未配置crontab的用户抛出的报错 - name: 读取系统全局crontab文件 slurp: src: /etc/crontab register: system_cron_res failed_when: false - name: 扫描/etc/cron.d下的自定义任务文件 find: paths: /etc/cron.d file_type: file register: cron_d_files failed_when: false - name: 读取cron.d下所有任务文件内容 slurp: src: "{{ item.path }}" loop: "{{ cron_d_files.files | default([]) }}" register: cron_d_res failed_when: false - name: 扫描周期执行目录下的可执行脚本 find: paths: "{{ item }}" file_type: file mode: "+111" loop: - /etc/cron.hourly - /etc/cron.daily - /etc/cron.weekly - /etc/cron.monthly register: periodic_cron_res failed_when: false - name: 组装单节点结构化cron数据 set_fact: node_cron_data: hostname: "{{ ansible_hostname }}" os_version: "{{ ansible_distribution }} {{ ansible_distribution_version }}" user_crontabs: "{{ user_cron_res.results | rejectattr('rc', 'ne', 0) | items2dict(key_name='item', value_name='stdout') }}" system_crontab: "{{ system_cron_res.content | b64decode | default('') }}" cron_d_tasks: "{{ cron_d_res.results | items2dict(key_name='item', value_name='content') | dict2items | map(attribute='value') | map('b64decode') | list }}" periodic_scripts: "{{ periodic_cron_res.results | map(attribute='files') | flatten | map(attribute='path') | list }}" - name: 传递单节点数据到管理节点做聚合 add_host: name: "{{ ansible_hostname }}_temp" groups: cron_agg_group cron_data: "{{ node_cron_data }}" changed_when: false - name: 聚合数据写入管理节点JSON文件 hosts: localhost gather_facts: no tasks: - name: 生成全节点cron配置JSON copy: content: "{{ groups['cron_agg_group'] | map('extract', hostvars, 'cron_data') | list | to_nice_json(indent=2, ensure_ascii=False) }}" dest: "./all_nodes_cron_config.json" mode: "0600"
注:不建议直接读取/var/spool下的crontab原始文件,不同发行版对该目录的权限限制差异大,通过crontab -l命令读取兼容性最好,不会出现权限报错。
执行采集命令:
ansible-playbook -i 你的资产文件路径 collect_cron.yml
命令执行完成后,当前目录会生成all_nodes_cron_config.json,按节点维度存储了所有类型的cron任务,支持直接编辑调整配置。
第二步:基于JSON批量推送Cron配置
配置更新推荐用Ansible自带的cron模块操作,自带幂等性,不会重复添加任务,也不会破坏原有crontab的格式。
将以下内容保存为push_cron.yml:
- name: 从JSON读取配置批量推送cron hosts: all gather_facts: yes become: yes vars: all_cron_config: "{{ lookup('file', './all_nodes_cron_config.json') | from_json }}" current_node_config: "{{ all_cron_config | selectattr('hostname', 'equalto', ansible_hostname) | first | default({}) }}" tasks: - name: 推送用户级crontab任务 cron: name: "{{ item.name }}" user: "{{ item.user | default('root') }}" minute: "{{ item.schedule.minute | default('*') }}" hour: "{{ item.schedule.hour | default('*') }}" day: "{{ item.schedule.day | default('*') }}" month: "{{ item.schedule.month | default('*') }}" weekday: "{{ item.schedule.weekday | default('*') }}" job: "{{ item.job_cmd }}" state: "{{ item.state | default('present') }}" loop: "{{ current_node_config.parsed_user_tasks | default([]) }}" # 提前把JSON里的原始crontab文本拆成调度周期、执行命令、所属用户的结构化字段即可直接传入参数
系统级crontab、cron.d下的任务文件、周期目录下的脚本,直接用copy模块将编辑后的内容推送到目标节点对应路径即可,配置权限时注意:
- crontab任务文件权限设为
0644,属主属组为root - 周期执行脚本权限设为
0755,确保有可执行权限
注意事项
- 采集和推送都需要root权限,确保Ansible执行账号在目标节点有sudo免密权限
- 首次推送前先加
--check参数做干跑,确认变更内容符合预期后再全量执行 - 原始采集的JSON里保留了注释、空行,如果要做精细化管理,可以在采集步骤加过滤规则,自动将单行crontab文本解析为结构化字段,减少后续手动编辑的工作量
- 回滚时直接用第一次采集生成的JSON文件重新推送即可,不需要额外做备份
内容的提问来源于stack exchange,提问作者cilap
相关产品推荐
相关产品推荐

