Do not remove non-empty cron tabs (#74497)
* Only remove crontabs if they are empty * Add integration test to ensure system cron tab doesn't get removed. Increase cron integration tests separation. * Also detect crontab which only contains whitespace as empty. * cron integration test: Adjust system crontab path to be distribution specific. Co-authored-by: Fabian Klemp <fabian.klemp@elara-gmbh.de>
This commit is contained in:
parent
1906d75907
commit
c6ac9de67b
5 changed files with 121 additions and 20 deletions
3
changelogs/fragments/74497-keep-non-empty-crontabs.yml
Normal file
3
changelogs/fragments/74497-keep-non-empty-crontabs.yml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
bugfixes:
|
||||||
|
- ansible.builtin.cron - Keep non-empty crontabs, when removing cron jobs
|
||||||
|
(https://github.com/ansible/ansible/pull/74497).
|
|
@ -286,7 +286,10 @@ class CronTab(object):
|
||||||
if len(self.lines) == 0:
|
if len(self.lines) == 0:
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
|
for line in self.lines:
|
||||||
|
if line.strip():
|
||||||
return False
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def write(self, backup_file=None):
|
def write(self, backup_file=None):
|
||||||
"""
|
"""
|
||||||
|
@ -654,18 +657,6 @@ def main():
|
||||||
(backuph, backup_file) = tempfile.mkstemp(prefix='crontab')
|
(backuph, backup_file) = tempfile.mkstemp(prefix='crontab')
|
||||||
crontab.write(backup_file)
|
crontab.write(backup_file)
|
||||||
|
|
||||||
if crontab.cron_file and not do_install:
|
|
||||||
if module._diff:
|
|
||||||
diff['after'] = ''
|
|
||||||
diff['after_header'] = '/dev/null'
|
|
||||||
else:
|
|
||||||
diff = dict()
|
|
||||||
if module.check_mode:
|
|
||||||
changed = os.path.isfile(crontab.cron_file)
|
|
||||||
else:
|
|
||||||
changed = crontab.remove_job_file()
|
|
||||||
module.exit_json(changed=changed, cron_file=cron_file, state=state, diff=diff)
|
|
||||||
|
|
||||||
if env:
|
if env:
|
||||||
if ' ' in name:
|
if ' ' in name:
|
||||||
module.fail_json(msg="Invalid name for environment variable")
|
module.fail_json(msg="Invalid name for environment variable")
|
||||||
|
@ -708,6 +699,17 @@ def main():
|
||||||
if len(old_job) > 0:
|
if len(old_job) > 0:
|
||||||
crontab.remove_job(name)
|
crontab.remove_job(name)
|
||||||
changed = True
|
changed = True
|
||||||
|
if crontab.cron_file and crontab.is_empty():
|
||||||
|
if module._diff:
|
||||||
|
diff['after'] = ''
|
||||||
|
diff['after_header'] = '/dev/null'
|
||||||
|
else:
|
||||||
|
diff = dict()
|
||||||
|
if module.check_mode:
|
||||||
|
changed = os.path.isfile(crontab.cron_file)
|
||||||
|
else:
|
||||||
|
changed = crontab.remove_job_file()
|
||||||
|
module.exit_json(changed=changed, cron_file=cron_file, state=state, diff=diff)
|
||||||
|
|
||||||
# no changes to env/job, but existing crontab needs a terminating newline
|
# no changes to env/job, but existing crontab needs a terminating newline
|
||||||
if not changed and crontab.n_existing != '':
|
if not changed and crontab.n_existing != '':
|
||||||
|
|
|
@ -1,3 +1,22 @@
|
||||||
|
- name: Include distribution specific variables
|
||||||
|
include_vars: "{{ lookup('first_found', search) }}"
|
||||||
|
vars:
|
||||||
|
search:
|
||||||
|
files:
|
||||||
|
- '{{ ansible_distribution | lower }}.yml'
|
||||||
|
- '{{ ansible_os_family | lower }}.yml'
|
||||||
|
- '{{ ansible_system | lower }}.yml'
|
||||||
|
- default.yml
|
||||||
|
paths:
|
||||||
|
- vars
|
||||||
|
|
||||||
|
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=726661
|
||||||
|
- name: Work around vixie-cron/PAM issue on old distros
|
||||||
|
command: sed -i '/pam_loginuid/ s/^/#/' /etc/pam.d/crond
|
||||||
|
when:
|
||||||
|
- ansible_distribution in ('RedHat', 'CentOS')
|
||||||
|
- ansible_distribution_major_version is version('6', '==')
|
||||||
|
|
||||||
- name: add cron task (check mode enabled, cron task not already created)
|
- name: add cron task (check mode enabled, cron task not already created)
|
||||||
cron:
|
cron:
|
||||||
name: test cron task
|
name: test cron task
|
||||||
|
@ -131,40 +150,115 @@
|
||||||
- name: Removing a cron file when the name is specified is allowed (#57471)
|
- name: Removing a cron file when the name is specified is allowed (#57471)
|
||||||
when: ansible_distribution != 'Alpine'
|
when: ansible_distribution != 'Alpine'
|
||||||
block:
|
block:
|
||||||
|
- name: Check file does not exist
|
||||||
|
stat:
|
||||||
|
path: /etc/cron.d/cron_remove_name
|
||||||
|
register: cron_file_stats
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that: not cron_file_stats.stat.exists
|
||||||
|
|
||||||
- name: Cron file creation
|
- name: Cron file creation
|
||||||
cron:
|
cron:
|
||||||
cron_file: cron_filename
|
cron_file: cron_remove_name
|
||||||
name: "integration test cron"
|
name: "integration test cron"
|
||||||
job: 'ls'
|
job: 'ls'
|
||||||
user: root
|
user: root
|
||||||
|
|
||||||
- name: Cron file deletion
|
- name: Cron file deletion
|
||||||
cron:
|
cron:
|
||||||
cron_file: cron_filename
|
cron_file: cron_remove_name
|
||||||
name: "integration test cron"
|
name: "integration test cron"
|
||||||
state: absent
|
state: absent
|
||||||
|
|
||||||
- name: Check file succesfull deletion
|
- name: Check file succesfull deletion
|
||||||
stat:
|
stat:
|
||||||
path: /etc/cron.d/cron_filename
|
path: /etc/cron.d/cron_remove_name
|
||||||
register: cron_file_stats
|
register: cron_file_stats
|
||||||
|
|
||||||
- assert:
|
- assert:
|
||||||
that: not cron_file_stats.stat.exists
|
that: not cron_file_stats.stat.exists
|
||||||
|
|
||||||
|
# BusyBox does not have /etc/cron.d
|
||||||
|
- name: Removing a cron file, which contains only whitespace
|
||||||
|
when: ansible_distribution != 'Alpine'
|
||||||
|
block:
|
||||||
|
- name: Check file does not exist
|
||||||
|
stat:
|
||||||
|
path: /etc/cron.d/cron_remove_whitespace
|
||||||
|
register: cron_file_stats
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that: not cron_file_stats.stat.exists
|
||||||
|
|
||||||
|
- name: Cron file creation
|
||||||
|
cron:
|
||||||
|
cron_file: cron_remove_whitespace
|
||||||
|
name: "integration test cron"
|
||||||
|
job: 'ls'
|
||||||
|
user: root
|
||||||
|
|
||||||
|
- name: Add whitespace to cron file
|
||||||
|
shell: 'printf "\n \n\t\n" >> /etc/cron.d/cron_remove_whitespace'
|
||||||
|
|
||||||
|
- name: Cron file deletion
|
||||||
|
cron:
|
||||||
|
cron_file: cron_remove_whitespace
|
||||||
|
name: "integration test cron"
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- name: Check file succesfull deletion
|
||||||
|
stat:
|
||||||
|
path: /etc/cron.d/cron_remove_whitespace
|
||||||
|
register: cron_file_stats
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that: not cron_file_stats.stat.exists
|
||||||
|
|
||||||
|
- name: System cron tab does not get removed
|
||||||
|
block:
|
||||||
|
- name: Add cron job
|
||||||
|
cron:
|
||||||
|
cron_file: "{{ system_crontab }}"
|
||||||
|
user: root
|
||||||
|
name: "integration test cron"
|
||||||
|
job: 'ls'
|
||||||
|
|
||||||
|
- name: Remove cron job
|
||||||
|
cron:
|
||||||
|
cron_file: "{{ system_crontab }}"
|
||||||
|
name: "integration test cron"
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- name: Check system crontab still exists
|
||||||
|
stat:
|
||||||
|
path: "{{ system_crontab }}"
|
||||||
|
register: cron_file_stats
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that: cron_file_stats.stat.exists
|
||||||
|
|
||||||
- name: Allow non-ascii chars in job (#69492)
|
- name: Allow non-ascii chars in job (#69492)
|
||||||
when: ansible_distribution != 'Alpine'
|
when: ansible_distribution != 'Alpine'
|
||||||
block:
|
block:
|
||||||
|
- name: Check file does not exist
|
||||||
|
stat:
|
||||||
|
path: /etc/cron.d/cron_nonascii
|
||||||
|
register: cron_file_stats
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that: not cron_file_stats.stat.exists
|
||||||
|
|
||||||
- name: Cron file creation
|
- name: Cron file creation
|
||||||
cron:
|
cron:
|
||||||
cron_file: cron_filename
|
cron_file: cron_nonascii
|
||||||
name: "cron job that contain non-ascii chars in job (これは日本語です; This is Japanese)"
|
name: "cron job that contain non-ascii chars in job (これは日本語です; This is Japanese)"
|
||||||
job: 'echo "うどんは好きだがお化け👻は苦手である。"'
|
job: 'echo "うどんは好きだがお化け👻は苦手である。"'
|
||||||
user: root
|
user: root
|
||||||
|
|
||||||
- name: "Ensure cron_file contains job string"
|
- name: "Ensure cron_file contains job string"
|
||||||
replace:
|
replace:
|
||||||
path: /etc/cron.d/cron_filename
|
path: /etc/cron.d/cron_nonascii
|
||||||
regexp: "うどんは好きだがお化け👻は苦手である。"
|
regexp: "うどんは好きだがお化け👻は苦手である。"
|
||||||
replace: "それは機密情報🔓です。"
|
replace: "それは機密情報🔓です。"
|
||||||
register: find_chars
|
register: find_chars
|
||||||
|
@ -172,13 +266,13 @@
|
||||||
|
|
||||||
- name: Cron file deletion
|
- name: Cron file deletion
|
||||||
cron:
|
cron:
|
||||||
cron_file: cron_filename
|
cron_file: cron_nonascii
|
||||||
name: "cron job that contain non-ascii chars in job (これは日本語です; This is Japanese)"
|
name: "cron job that contain non-ascii chars in job (これは日本語です; This is Japanese)"
|
||||||
state: absent
|
state: absent
|
||||||
|
|
||||||
- name: Check file succesfull deletion
|
- name: Check file succesfull deletion
|
||||||
stat:
|
stat:
|
||||||
path: /etc/cron.d/cron_filename
|
path: /etc/cron.d/cron_nonascii
|
||||||
register: cron_file_stats
|
register: cron_file_stats
|
||||||
|
|
||||||
- assert:
|
- assert:
|
||||||
|
|
1
test/integration/targets/cron/vars/alpine.yml
Normal file
1
test/integration/targets/cron/vars/alpine.yml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
system_crontab: /etc/crontabs/root
|
1
test/integration/targets/cron/vars/default.yml
Normal file
1
test/integration/targets/cron/vars/default.yml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
system_crontab: /etc/crontab
|
Loading…
Reference in a new issue