cron module: add enviroment variables management

This commit is contained in:
Luca Berruti 2014-09-30 17:46:32 +02:00 committed by Luca Berruti
parent 51c3aa4267
commit 933a44ba78

View file

@ -5,6 +5,7 @@
# (c) 2013, Mike Grozak <mike.grozak@gmail.com> # (c) 2013, Mike Grozak <mike.grozak@gmail.com>
# (c) 2013, Patrick Callahan <pmc@patrickcallahan.com> # (c) 2013, Patrick Callahan <pmc@patrickcallahan.com>
# (c) 2015, Evan Kaufman <evan@digitalflophouse.com> # (c) 2015, Evan Kaufman <evan@digitalflophouse.com>
# (c) 2015, Luca Berruti <nadirio@gmail.com>
# #
# This file is part of Ansible # This file is part of Ansible
# #
@ -35,17 +36,22 @@ DOCUMENTATION = """
module: cron module: cron
short_description: Manage cron.d and crontab entries. short_description: Manage cron.d and crontab entries.
description: description:
- Use this module to manage crontab entries. This module allows you to create named - Use this module to manage crontab and environment variables entries. This module allows
crontab entries, update, or delete them. you to create environment variables and named crontab entries, update, or delete them.
- 'The module includes one line with the description of the crontab entry C("#Ansible: <name>") - 'When crontab jobs are managed: the module includes one line with the description of the
corresponding to the "name" passed to the module, which is used by future ansible/module calls crontab entry C("#Ansible: <name>") corresponding to the "name" passed to the module,
to find/check the state. The "name" parameter should be unique, and changing the "name" value which is used by future ansible/module calls to find/check the state. The "name"
will result in a new cron task being created (or a different one being removed)' parameter should be unique, and changing the "name" value will result in a new cron
task being created (or a different one being removed).'
- 'When environment variables are managed: no comment line is added, but, when the module
needs to find/check the state, it uses the "name" parameter to find the environment
variable definition line.'
version_added: "0.9" version_added: "0.9"
options: options:
name: name:
description: description:
- Description of a crontab entry. Required if state=absent - Description of a crontab entry or, if env is set, the name of environment variable.
Required if state=absent
default: null default: null
required: false required: false
user: user:
@ -55,12 +61,14 @@ options:
default: root default: root
job: job:
description: description:
- The command to execute. Required if state=present. - The command to execute or, if env is set, the value of environment variable.
Required if state=present.
required: false required: false
aliases: ['value']
default: null default: null
state: state:
description: description:
- Whether to ensure the job is present or absent. - Whether to ensure the job or environment variable is present or absent.
required: false required: false
default: present default: present
choices: [ "present", "absent" ] choices: [ "present", "absent" ]
@ -124,6 +132,28 @@ options:
version_added: "2.0" version_added: "2.0"
required: false required: false
default: false default: false
env:
description:
- If set, manages a crontab's environment variable. New variables are added on top of crontab.
"name" and "value" paramenters are the name and the value of environment variable.
version_added: "2"
required: false
default: "no"
choices: [ "yes", "no" ]
insertafter:
description:
- Used with C(state=present) and C(env). If specified, the environment variable will be
inserted after the declaration of specified environment variable.
version_added: "2"
required: false
default: null
insertbefore:
description:
- Used with C(state=present) and C(env). If specified, the environment variable will be
inserted before the declaration of specified environment variable.
version_added: "2"
required: false
default: null
requirements: requirements:
- cron - cron
author: author:
@ -131,6 +161,7 @@ author:
- 'Mike Grozak' - 'Mike Grozak'
- 'Patrick Callahan' - 'Patrick Callahan'
- 'Evan Kaufman (@EvanK)' - 'Evan Kaufman (@EvanK)'
- 'Luca Berruti (@lberruti)'
""" """
EXAMPLES = ''' EXAMPLES = '''
@ -145,6 +176,13 @@ EXAMPLES = '''
# Creates an entry like "@reboot /some/job.sh" # Creates an entry like "@reboot /some/job.sh"
- cron: name="a job for reboot" special_time=reboot job="/some/job.sh" - cron: name="a job for reboot" special_time=reboot job="/some/job.sh"
# Creates an entry like "PATH=/opt/bin" on top of crontab
- cron: name=PATH env=yes value=/opt/bin
# Creates an entry like "APP_HOME=/srv/app" and insert it after PATH
# declaration
- cron: name=APP_HOME env=yes value=/srv/app insertafter=PATH
# Creates a cron file under /etc/cron.d # Creates a cron file under /etc/cron.d
- cron: name="yum autoupdate" weekday="2" minute=0 hour=12 - cron: name="yum autoupdate" weekday="2" minute=0 hour=12
user="root" job="YUMINTERACTIVE=0 /usr/sbin/yum-autoupdate" user="root" job="YUMINTERACTIVE=0 /usr/sbin/yum-autoupdate"
@ -152,6 +190,9 @@ EXAMPLES = '''
# Removes a cron file from under /etc/cron.d # Removes a cron file from under /etc/cron.d
- cron: name="yum autoupdate" cron_file=ansible_yum-autoupdate state=absent - cron: name="yum autoupdate" cron_file=ansible_yum-autoupdate state=absent
# Removes "APP_HOME" environment variable from crontab
- cron: name=APP_HOME env=yes state=absent
''' '''
import os import os
@ -272,6 +313,38 @@ class CronTab(object):
def do_remove_job(self, lines, comment, job): def do_remove_job(self, lines, comment, job):
return None return None
def add_env(self, decl, insertafter=None, insertbefore=None):
if not (insertafter or insertbefore):
self.lines.insert(0, decl)
return
if insertafter:
other_name = insertafter
elif insertbefore:
other_name = insertbefore
other_decl = self.find_env(other_name)
if len(other_decl) > 0:
if insertafter:
index = other_decl[0]+1
elif insertbefore:
index = other_decl[0]
self.lines.insert(index, decl)
return
self.module.fail_json(msg="Variable named '%s' not found." % other_name)
def update_env(self, name, decl):
return self._update_env(name, decl, self.do_add_env)
def do_add_env(self, lines, decl):
lines.append(decl)
def remove_env(self, name):
return self._update_env(name, '', self.do_remove_env)
def do_remove_env(self, lines, decl):
return None
def remove_job_file(self): def remove_job_file(self):
try: try:
os.unlink(self.cron_file) os.unlink(self.cron_file)
@ -295,6 +368,13 @@ class CronTab(object):
return [] return []
def find_env(self, name):
for index, l in enumerate(self.lines):
if re.match( r'^%s=' % name, l):
return [index, l]
return []
def get_cron_job(self,minute,hour,day,month,weekday,job,special,disabled): def get_cron_job(self,minute,hour,day,month,weekday,job,special,disabled):
if disabled: if disabled:
disable_prefix = '#' disable_prefix = '#'
@ -323,6 +403,15 @@ class CronTab(object):
return jobnames return jobnames
def get_envnames(self):
envnames = []
for l in self.lines:
if re.match( r'^\S+=' , l):
envnames.append(l.split('=')[0])
return envnames
def _update_job(self, name, job, addlinesfunction): def _update_job(self, name, job, addlinesfunction):
ansiblename = "%s%s" % (self.ansible, name) ansiblename = "%s%s" % (self.ansible, name)
newlines = [] newlines = []
@ -344,6 +433,17 @@ class CronTab(object):
else: else:
return False # TODO add some more error testing return False # TODO add some more error testing
def _update_env(self, name, decl, addenvfunction):
newlines = []
for l in self.lines:
if re.match( r'^%s=' % name, l):
addenvfunction(newlines, decl)
else:
newlines.append(l)
self.lines = newlines
def render(self): def render(self):
""" """
Render this crontab as it would be in the crontab. Render this crontab as it would be in the crontab.
@ -400,7 +500,11 @@ def main():
# - name: no job # - name: no job
# cron: name="an old job" state=absent # cron: name="an old job" state=absent
# #
# - name: sets env
# cron: name="PATH" env=yes value="/bin:/usr/bin"
#
# Would produce: # Would produce:
# PATH=/bin:/usr/bin
# # Ansible: check dirs # # Ansible: check dirs
# * * 5,2 * * ls -alh > /dev/null # * * 5,2 * * ls -alh > /dev/null
# # Ansible: do the job # # Ansible: do the job
@ -410,7 +514,7 @@ def main():
argument_spec = dict( argument_spec = dict(
name=dict(required=False), name=dict(required=False),
user=dict(required=False), user=dict(required=False),
job=dict(required=False), job=dict(required=False, aliases=['value']),
cron_file=dict(required=False), cron_file=dict(required=False),
state=dict(default='present', choices=['present', 'absent']), state=dict(default='present', choices=['present', 'absent']),
backup=dict(default=False, type='bool'), backup=dict(default=False, type='bool'),
@ -424,9 +528,16 @@ def main():
default=None, default=None,
choices=["reboot", "yearly", "annually", "monthly", "weekly", "daily", "hourly"], choices=["reboot", "yearly", "annually", "monthly", "weekly", "daily", "hourly"],
type='str'), type='str'),
disabled=dict(default=False, type='bool') disabled=dict(default=False, type='bool'),
env=dict(required=False, type='bool'),
insertafter=dict(required=False),
insertbefore=dict(required=False),
), ),
supports_check_mode = False, supports_check_mode = False,
mutually_exclusive=[
['reboot', 'special_time'],
['insertafter', 'insertbefore'],
]
) )
name = module.params['name'] name = module.params['name']
@ -443,6 +554,9 @@ def main():
reboot = module.params['reboot'] reboot = module.params['reboot']
special_time = module.params['special_time'] special_time = module.params['special_time']
disabled = module.params['disabled'] disabled = module.params['disabled']
env = module.params['env']
insertafter = module.params['insertafter']
insertbefore = module.params['insertbefore']
do_install = state == 'present' do_install = state == 'present'
changed = False changed = False
@ -464,22 +578,13 @@ def main():
if not user: if not user:
module.fail_json(msg="To use cron_file=... parameter you must specify user=... as well") module.fail_json(msg="To use cron_file=... parameter you must specify user=... as well")
if reboot and special_time:
module.fail_json(msg="reboot and special_time are mutually exclusive")
if name is None and do_install:
module.fail_json(msg="You must specify 'name' to install a new cron job")
if job is None and do_install: if job is None and do_install:
module.fail_json(msg="You must specify 'job' to install a new cron job") module.fail_json(msg="You must specify 'job' to install a new cron job or variable")
if job and name is None and not do_install: if (insertafter or insertafter) and not env and do_install:
module.fail_json(msg="You must specify 'name' to remove a cron job") module.fail_json(msg="Insertafter and insertbefore parameters are valid only with env=yes")
if reboot: if reboot:
if special_time:
module.fail_json(msg="reboot and special_time are mutually exclusive")
else:
special_time = "reboot" special_time = "reboot"
# if requested make a backup before making a change # if requested make a backup before making a change
@ -492,6 +597,24 @@ def main():
changed = crontab.remove_job_file() changed = crontab.remove_job_file()
module.exit_json(changed=changed,cron_file=cron_file,state=state) module.exit_json(changed=changed,cron_file=cron_file,state=state)
if env:
if ' ' in name:
module.fail_json(msg="Invalid name for environment variable")
decl = '%s="%s"' % (name, job)
old_decl = crontab.find_env(name)
if do_install:
if len(old_decl) == 0:
crontab.add_env(decl, insertafter, insertbefore)
changed = True
if len(old_decl) > 0 and old_decl[1] != decl:
crontab.update_env(name, decl)
changed = True
else:
if len(old_decl) > 0:
crontab.remove_env(name)
changed = True
else:
job = crontab.get_cron_job(minute, hour, day, month, weekday, job, special_time, disabled) job = crontab.get_cron_job(minute, hour, day, month, weekday, job, special_time, disabled)
old_job = crontab.find_job(name) old_job = crontab.find_job(name)
@ -508,7 +631,9 @@ def main():
changed = True changed = True
res_args = dict( res_args = dict(
jobs = crontab.get_jobnames(), changed = changed jobs = crontab.get_jobnames(),
envs = crontab.get_envnames(),
changed = changed
) )
if changed: if changed: