salt/states/at.py
# -*- coding: utf-8 -*-
'''
Configuration disposable regularly scheduled tasks for at.
==========================================================
The at state can be add disposable regularly scheduled tasks for your system.
'''
from __future__ import absolute_import, print_function, unicode_literals
# Import Python libs
import logging
# Import salt libs
from salt.ext.six.moves import map
log = logging.getLogger(__name__)
def __virtual__():
'''
Most everything has the ability to support at(1)
'''
return 'at.at' in __salt__
def present(name, timespec, tag=None, user=None, job=None, unique_tag=False):
'''
.. versionchanged:: 2017.7.0
Add a job to queue.
job : string
Command to run.
timespec : string
The 'timespec' follows the format documented in the at(1) manpage.
tag : string
Make a tag for the job.
user : string
The user to run the at job
.. versionadded:: 2014.1.4
unique_tag : boolean
If set to True job will not be added if a job with the tag exists.
.. versionadded:: 2017.7.0
.. code-block:: yaml
rose:
at.present:
- job: 'echo "I love saltstack" > love'
- timespec: '9:09 11/09/13'
- tag: love
- user: jam
'''
ret = {'name': name,
'changes': {},
'result': True,
'comment': ''}
# if job is missing, use name
if not job:
job = name
# quick return on test=True
if __opts__['test']:
ret['result'] = None
ret['comment'] = 'job {0} added and will run on {1}'.format(
job,
timespec,
)
return ret
# quick return if unique_tag and job exists
if unique_tag:
if not tag:
ret['result'] = False
ret['comment'] = 'no tag provided and unique_tag is set to True'
return ret
elif __salt__['at.jobcheck'](tag=tag)['jobs']:
ret['comment'] = 'atleast one job with tag {tag} exists.'.format(
tag=tag
)
return ret
# create job
if user:
luser = __salt__['user.info'](user)
if not luser:
ret['result'] = False
ret['comment'] = 'user {0} does not exists'.format(user)
return ret
ret['comment'] = 'job {0} added and will run as {1} on {2}'.format(
job,
user,
timespec,
)
res = __salt__['at.at'](
timespec,
job,
tag=tag,
runas=user,
)
else:
ret['comment'] = 'job {0} added and will run on {1}'.format(
job,
timespec,
)
res = __salt__['at.at'](
timespec,
job,
tag=tag,
)
# set ret['changes']
if res.get('jobs'):
ret['changes'] = res['jobs'][0]
if 'error' in res:
ret['result'] = False
ret['comment'] = res['error']
return ret
def absent(name, jobid=None, **kwargs):
'''
.. versionchanged:: 2017.7.0
Remove a job from queue
jobid: string|int
Specific jobid to remove
tag : string
Job's tag
runas : string
Runs user-specified jobs
kwargs
Addition kwargs can be provided to filter jobs.
See output of `at.jobcheck` for more.
.. code-block:: yaml
example1:
at.absent:
.. warning::
this will remove all jobs!
.. code-block:: yaml
example2:
at.absent:
- year: 13
.. code-block:: yaml
example3:
at.absent:
- tag: rose
.. code-block:: yaml
example4:
at.absent:
- tag: rose
- day: 13
- hour: 16
.. code-block:: yaml
example5:
at.absent:
- jobid: 4
.. note:
all other filters are ignored and only job with id 4 is removed
'''
ret = {'name': name,
'changes': {},
'result': True,
'comment': ''}
# limit was never support
if 'limit' in kwargs:
ret['comment'] = 'limit parameter not supported {0}'.format(name)
ret['result'] = False
return ret
# quick return on test=True
if __opts__['test']:
ret['result'] = None
ret['comment'] = 'removed ? job(s)'
return ret
# remove specific job
if jobid:
jobs = __salt__['at.atq'](jobid)
if jobs.get('jobs'):
ret['result'] = True
ret['comment'] = 'job with id {jobid} not present'.format(
jobid=jobid
)
return ret
elif 'jobs' in jobs and len(jobs['jobs']) == 1:
if 'job' in jobs['jobs'][0] and jobs['jobs'][0]['job']:
res = __salt__['at.atrm'](jobid)
ret['result'] = jobid in res['jobs']['removed']
if ret['result']:
ret['comment'] = 'job with id {jobid} was removed'.format(
jobid=jobid
)
else:
ret['comment'] = 'failed to remove job with id {jobid}'.format(
jobid=jobid
)
ret['changes']['removed'] = res['jobs']['removed']
return ret
else:
ret['result'] = False
ret['comment'] = 'more than one job was return for job with id {jobid}'.format(
jobid=jobid
)
return ret
# remove jobs based on filter
if kwargs:
# we pass kwargs to at.jobcheck
opts = list(list(map(str, [j['job'] for j in __salt__['at.jobcheck'](**kwargs)['jobs']])))
res = __salt__['at.atrm'](*opts)
else:
# arguments to filter with, removing everything!
res = __salt__['at.atrm']('all')
if res['jobs']['removed']:
ret['changes']['removed'] = res['jobs']['removed']
ret['comment'] = 'removed {count} job(s)'.format(
count=len(res['jobs']['removed'])
)
return ret
def watch(name, timespec, tag=None, user=None, job=None, unique_tag=False):
'''
.. versionadded:: 2017.7.0
Add an at job if trigger by watch
job : string
Command to run.
timespec : string
The 'timespec' follows the format documented in the at(1) manpage.
tag : string
Make a tag for the job.
user : string
The user to run the at job
.. versionadded:: 2014.1.4
unique_tag : boolean
If set to True job will not be added if a job with the tag exists.
.. versionadded:: 2017.7.0
.. code-block:: yaml
minion_restart:
at.watch:
- job: 'salt-call --local service.restart salt-minion'
- timespec: 'now +1 min'
- tag: minion_restart
- unique_tag: trye
- watch:
- file: /etc/salt/minion
'''
return {
'name': name,
'changes': {},
'result': True,
'comment': ''
}
def mod_watch(name, **kwargs):
'''
The at watcher, called to invoke the watch command.
.. note::
This state exists to support special handling of the ``watch``
:ref:`requisite <requisites>`. It should not be called directly.
Parameters for this function should be set by the state being triggered.
name
The name of the atjob
'''
ret = {'name': name,
'changes': {},
'result': False,
'comment': ''}
if kwargs['sfun'] == 'watch':
for p in ['sfun', '__reqs__']:
del kwargs[p]
kwargs['name'] = name
ret = present(**kwargs)
return ret
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4