Merge pull request #24076 from garethgreenaway/refactoring_schedule_module

Refactoring schedule module
This commit is contained in:
Thomas S Hatch 2015-05-25 13:45:50 -06:00
commit f76622ad67
5 changed files with 516 additions and 460 deletions

View File

@ -1348,11 +1348,13 @@ class Minion(MinionBase):
elif func == 'enable_job':
self.schedule.enable_job(name, where)
elif func == 'run_job':
self.schedule.run_job(name, where)
self.schedule.run_job(name)
elif func == 'disable_job':
self.schedule.disable_job(name, where)
elif func == 'reload':
self.schedule.reload(schedule)
elif func == 'list':
self.schedule.list(where)
def manage_beacons(self, package):
'''

View File

@ -57,7 +57,7 @@ SCHEDULE_CONF = [
]
def list_(show_all=False, return_yaml=True):
def list_(show_all=False, where=None, return_yaml=True):
'''
List the jobs currently scheduled on the minion
@ -70,9 +70,22 @@ def list_(show_all=False, return_yaml=True):
salt '*' schedule.list show_all=True
'''
schedule = __opts__['schedule'].copy()
if 'schedule' in __pillar__:
schedule.update(__pillar__['schedule'])
schedule = {}
try:
eventer = salt.utils.event.get_event('minion', opts=__opts__)
res = __salt__['event.fire']({'func': 'list',
'where': where}, 'manage_schedule')
if res:
event_ret = eventer.get_event(tag='/salt/minion/minion_schedule_list_complete', wait=30)
if event_ret and event_ret['complete']:
schedule = event_ret['schedule']
except KeyError:
# Effectively a no-op, since we can't really return without an event system
ret = {}
ret['comment'] = 'Event module not available. Schedule list failed.'
ret['result'] = True
log.debug('Event module not available. Schedule list failed.')
return ret
for job in list(schedule.keys()): # iterate over a copy since we will mutate it
if job == 'enabled':
@ -122,11 +135,7 @@ def purge(**kwargs):
ret = {'comment': [],
'result': True}
schedule = __opts__['schedule'].copy()
if 'schedule' in __pillar__:
schedule.update(__pillar__['schedule'])
for name in schedule:
for name in list_(show_all=True, return_yaml=False):
if name == 'enabled':
continue
if name.startswith('__'):
@ -142,8 +151,8 @@ def purge(**kwargs):
if res:
event_ret = eventer.get_event(tag='/salt/minion/minion_schedule_delete_complete', wait=30)
if event_ret and event_ret['complete']:
schedule = event_ret['schedule']
if name not in schedule:
_schedule_ret = event_ret['schedule']
if name not in _schedule_ret:
ret['result'] = True
ret['comment'].append('Deleted job: {0} from schedule.'.format(name))
else:
@ -174,49 +183,33 @@ def delete(name, **kwargs):
if not name:
ret['comment'] = 'Job name is required.'
if name in __opts__['schedule']:
if 'test' in kwargs and kwargs['test']:
ret['comment'] = 'Job: {0} would be deleted from schedule.'.format(name)
ret['result'] = True
else:
try:
eventer = salt.utils.event.get_event('minion', opts=__opts__)
res = __salt__['event.fire']({'name': name, 'func': 'delete'}, 'manage_schedule')
if res:
event_ret = eventer.get_event(tag='/salt/minion/minion_schedule_delete_complete', wait=30)
if event_ret and event_ret['complete']:
schedule = event_ret['schedule']
if name not in schedule:
ret['result'] = True
ret['comment'] = 'Deleted Job {0} from schedule.'.format(name)
else:
ret['comment'] = 'Failed to delete job {0} from schedule.'.format(name)
return ret
except KeyError:
# Effectively a no-op, since we can't really return without an event system
ret['comment'] = 'Event module not available. Schedule add failed.'
elif 'schedule' in __pillar__ and name in __pillar__['schedule']:
if 'test' in kwargs and kwargs['test']:
ret['comment'] = 'Job: {0} would be deleted from schedule.'.format(name)
else:
try:
eventer = salt.utils.event.get_event('minion', opts=__opts__)
res = __salt__['event.fire']({'name': name, 'where': 'pillar', 'func': 'delete'}, 'manage_schedule')
if res:
event_ret = eventer.get_event(tag='/salt/minion/minion_schedule_delete_complete', wait=30)
if event_ret and event_ret['complete']:
schedule = event_ret['schedule']
if name not in schedule:
ret['result'] = True
ret['comment'] = 'Deleted Job {0} from schedule.'.format(name)
else:
ret['comment'] = 'Failed to delete job {0} from schedule.'.format(name)
return ret
except KeyError:
# Effectively a no-op, since we can't really return without an event system
ret['comment'] = 'Event module not available. Schedule add failed.'
if 'test' in kwargs and kwargs['test']:
ret['comment'] = 'Job: {0} would be deleted from schedule.'.format(name)
ret['result'] = True
else:
ret['comment'] = 'Job {0} does not exist.'.format(name)
if name in list_(show_all=True, where='opts', return_yaml=False):
event_data = {'name': name, 'func': 'delete'}
elif name in list_(show_all=True, where='pillar', return_yaml=False):
event_data = {'name': name, 'where': 'pillar', 'func': 'delete'}
else:
ret['comment'] = 'Job {0} does not exist.'.format(name)
return ret
try:
eventer = salt.utils.event.get_event('minion', opts=__opts__)
res = __salt__['event.fire'](event_data, 'manage_schedule')
if res:
event_ret = eventer.get_event(tag='/salt/minion/minion_schedule_delete_complete', wait=30)
if event_ret and event_ret['complete']:
schedule = event_ret['schedule']
if name not in schedule:
ret['result'] = True
ret['comment'] = 'Deleted Job {0} from schedule.'.format(name)
else:
ret['comment'] = 'Failed to delete job {0} from schedule.'.format(name)
return ret
except KeyError:
# Effectively a no-op, since we can't really return without an event system
ret['comment'] = 'Event module not available. Schedule add failed.'
return ret
@ -323,11 +316,7 @@ def add(name, **kwargs):
ret = {'comment': 'Failed to add job {0} to schedule.'.format(name),
'result': False}
current_schedule = __opts__['schedule'].copy()
if 'schedule' in __pillar__:
current_schedule.update(__pillar__['schedule'])
if name in current_schedule:
if name in list_(show_all=True, return_yaml=False):
ret['comment'] = 'Job {0} already exists in schedule.'.format(name)
ret['result'] = False
return ret
@ -410,9 +399,7 @@ def modify(name, **kwargs):
ret['comment'] = 'Unable to use "when" and "cron" options together. Ignoring.'
return ret
current_schedule = __opts__['schedule'].copy()
if 'schedule' in __pillar__:
current_schedule.update(__pillar__['schedule'])
current_schedule = list_(show_all=True, return_yaml=False)
if name not in current_schedule:
ret['comment'] = 'Job {0} does not exist in schedule.'.format(name)
@ -437,26 +424,19 @@ def modify(name, **kwargs):
ret['changes']['diff'] = ''.join(_diff)
if name in __opts__['schedule']:
if 'test' in kwargs and kwargs['test']:
ret['comment'] = 'Job: {0} would be modified in schedule.'.format(name)
if 'test' in kwargs and kwargs['test']:
ret['comment'] = 'Job: {0} would be modified in schedule.'.format(name)
else:
if name in list_(show_all=True, where='opts', return_yaml=False):
event_data = {'name': name, 'schedule': _new, 'func': 'modify'}
elif name in list_(show_all=True, where='pillar', return_yaml=False):
event_data = {'name': name, 'schedule': _new, 'where': 'pillar', 'func': 'modify'}
out = __salt__['event.fire'](event_data, 'manage_schedule')
if out:
ret['comment'] = 'Modified job: {0} in schedule.'.format(name)
else:
out = __salt__['event.fire']({'name': name, 'schedule': _new, 'func': 'modify'}, 'manage_schedule')
if out:
ret['comment'] = 'Modified job: {0} in schedule.'.format(name)
else:
ret['comment'] = 'Failed to modify job {0} in schedule.'.format(name)
ret['result'] = False
elif 'schedule' in __pillar__ and name in __pillar__['schedule']:
if 'test' in kwargs and kwargs['test']:
ret['comment'] = 'Job: {0} would be modified in schedule.'.format(name)
else:
out = __salt__['event.fire']({'name': name, 'schedule': _new, 'where': 'pillar', 'func': 'modify'}, 'manage_schedule')
if out:
ret['comment'] = 'Modified job: {0} in schedule.'.format(name)
else:
ret['comment'] = 'Failed to modify job {0} in schedule.'.format(name)
ret['result'] = False
ret['comment'] = 'Failed to modify job {0} in schedule.'.format(name)
ret['result'] = False
return ret
@ -481,8 +461,9 @@ def run_job(name, force=False):
ret['comment'] = 'Job name is required.'
ret['result'] = False
if name in __opts__['schedule']:
data = __opts__['schedule'][name]
schedule = list_(show_all=True, return_yaml=False)
if name in schedule:
data = schedule[name]
if 'enabled' in data and not data['enabled'] and not force:
ret['comment'] = 'Job {0} is disabled.'.format(name)
else:
@ -492,17 +473,6 @@ def run_job(name, force=False):
else:
ret['comment'] = 'Failed to run job {0} on minion.'.format(name)
ret['result'] = False
elif 'schedule' in __pillar__ and name in __pillar__['schedule']:
data = __pillar__['schedule'][name]
if 'enabled' in data and not data['enabled'] and not force:
ret['comment'] = 'Job {0} is disabled.'.format(name)
else:
out = __salt__['event.fire']({'name': name, 'where': 'pillar', 'func': 'run_job'}, 'manage_schedule')
if out:
ret['comment'] = 'Scheduling Job {0} on minion.'.format(name)
else:
ret['comment'] = 'Failed to run job {0} on minion.'.format(name)
ret['result'] = False
else:
ret['comment'] = 'Job {0} does not exist.'.format(name)
ret['result'] = False
@ -527,53 +497,35 @@ def enable_job(name, **kwargs):
ret['comment'] = 'Job name is required.'
ret['result'] = False
if name in __opts__['schedule']:
if 'test' in __opts__ and __opts__['test']:
ret['comment'] = 'Job: {0} would be enabled in schedule.'.format(name)
else:
try:
eventer = salt.utils.event.get_event('minion', opts=__opts__)
res = __salt__['event.fire']({'name': name, 'func': 'enable_job'}, 'manage_schedule')
if res:
event_ret = eventer.get_event(tag='/salt/minion/minion_schedule_enabled_job_complete', wait=30)
if event_ret and event_ret['complete']:
schedule = event_ret['schedule']
# check item exists in schedule and is enabled
if name in schedule and schedule[name]['enabled']:
ret['result'] = True
ret['comment'] = 'Enabled Job {0} in schedule.'.format(name)
else:
ret['result'] = False
ret['comment'] = 'Failed to enable job {0} in schedule.'.format(name)
return ret
except KeyError:
# Effectively a no-op, since we can't really return without an event system
ret['comment'] = 'Event module not available. Schedule enable job failed.'
elif 'schedule' in __pillar__ and name in __pillar__['schedule']:
if 'test' in kwargs and kwargs['test']:
ret['comment'].append('Job: {0} would be enabled in schedule.'.format(name))
else:
try:
eventer = salt.utils.event.get_event('minion', opts=__opts__)
res = __salt__['event.fire']({'name': name, 'where': 'pillar', 'func': 'enable_job'}, 'manage_schedule')
if res:
event_ret = eventer.get_event(tag='/salt/minion/minion_schedule_enabled_job_complete', wait=30)
if event_ret and event_ret['complete']:
schedule = event_ret['schedule']
# check item exists in schedule and is enabled
if name in schedule and schedule[name]['enabled']:
ret['result'] = True
ret['comment'] = 'Enabled Job {0} in schedule.'.format(name)
else:
ret['result'] = False
ret['comment'] = 'Failed to enable job {0} in schedule.'.format(name)
return ret
except KeyError:
# Effectively a no-op, since we can't really return without an event system
ret['comment'] = 'Event module not available. Schedule enable job failed.'
if 'test' in __opts__ and __opts__['test']:
ret['comment'] = 'Job: {0} would be enabled in schedule.'.format(name)
else:
ret['comment'] = 'Job {0} does not exist.'.format(name)
ret['result'] = False
if name in list_(show_all=True, where='opts', return_yaml=False):
event_data = {'name': name, 'func': 'enable_job'}
elif name in list_(show_all=True, where='pillar', return_yaml=False):
event_data = {'name': name, 'where': 'pillar', 'func': 'enable_job'}
else:
ret['comment'] = 'Job {0} does not exist.'.format(name)
ret['result'] = False
return ret
try:
eventer = salt.utils.event.get_event('minion', opts=__opts__)
res = __salt__['event.fire'](event_data, 'manage_schedule')
if res:
event_ret = eventer.get_event(tag='/salt/minion/minion_schedule_enabled_job_complete', wait=30)
if event_ret and event_ret['complete']:
schedule = event_ret['schedule']
# check item exists in schedule and is enabled
if name in schedule and schedule[name]['enabled']:
ret['result'] = True
ret['comment'] = 'Enabled Job {0} in schedule.'.format(name)
else:
ret['result'] = False
ret['comment'] = 'Failed to enable job {0} in schedule.'.format(name)
return ret
except KeyError:
# Effectively a no-op, since we can't really return without an event system
ret['comment'] = 'Event module not available. Schedule enable job failed.'
return ret
@ -595,53 +547,35 @@ def disable_job(name, **kwargs):
ret['comment'] = 'Job name is required.'
ret['result'] = False
if name in __opts__['schedule']:
if 'test' in kwargs and kwargs['test']:
ret['comment'] = 'Job: {0} would be disabled in schedule.'.format(name)
else:
try:
eventer = salt.utils.event.get_event('minion', opts=__opts__)
res = __salt__['event.fire']({'name': name, 'func': 'disable_job'}, 'manage_schedule')
if res:
event_ret = eventer.get_event(tag='/salt/minion/minion_schedule_disabled_job_complete', wait=30)
if event_ret and event_ret['complete']:
schedule = event_ret['schedule']
# check item exists in schedule and is enabled
if name in schedule and not schedule[name]['enabled']:
ret['result'] = True
ret['comment'] = 'Disabled Job {0} in schedule.'.format(name)
else:
ret['result'] = False
ret['comment'] = 'Failed to disable job {0} in schedule.'.format(name)
return ret
except KeyError:
# Effectively a no-op, since we can't really return without an event system
ret['comment'] = 'Event module not available. Schedule enable job failed.'
elif 'schedule' in __pillar__ and name in __pillar__['schedule']:
if 'test' in kwargs and kwargs['test']:
ret['comment'].append('Job: {0} would be disabled in schedule.'.format(name))
else:
try:
eventer = salt.utils.event.get_event('minion', opts=__opts__)
res = __salt__['event.fire']({'name': name, 'where': 'pillar', 'func': 'disable_job'}, 'manage_schedule')
if res:
event_ret = eventer.get_event(tag='/salt/minion/minion_schedule_disabled_job_complete', wait=30)
if event_ret and event_ret['complete']:
schedule = event_ret['schedule']
# check item exists in schedule and is enabled
if name in schedule and not schedule[name]['enabled']:
ret['result'] = True
ret['comment'] = 'Disabled Job {0} in schedule.'.format(name)
else:
ret['result'] = False
ret['comment'] = 'Failed to disable job {0} in schedule.'.format(name)
return ret
except KeyError:
# Effectively a no-op, since we can't really return without an event system
ret['comment'] = 'Event module not available. Schedule enable job failed.'
if 'test' in kwargs and kwargs['test']:
ret['comment'] = 'Job: {0} would be disabled in schedule.'.format(name)
else:
ret['comment'] = 'Job {0} does not exist.'.format(name)
ret['result'] = False
if name in list_(show_all=True, where='opts', return_yaml=False):
event_data = {'name': name, 'func': 'disable_job'}
elif name in list_(show_all=True, where='pillar'):
event_data = {'name': name, 'where': 'pillar', 'func': 'disable_job'}
else:
ret['comment'] = 'Job {0} does not exist.'.format(name)
ret['result'] = False
return ret
try:
eventer = salt.utils.event.get_event('minion', opts=__opts__)
res = __salt__['event.fire'](event_data, 'manage_schedule')
if res:
event_ret = eventer.get_event(tag='/salt/minion/minion_schedule_disabled_job_complete', wait=30)
if event_ret and event_ret['complete']:
schedule = event_ret['schedule']
# check item exists in schedule and is enabled
if name in schedule and not schedule[name]['enabled']:
ret['result'] = True
ret['comment'] = 'Disabled Job {0} in schedule.'.format(name)
else:
ret['result'] = False
ret['comment'] = 'Failed to disable job {0} in schedule.'.format(name)
return ret
except KeyError:
# Effectively a no-op, since we can't really return without an event system
ret['comment'] = 'Event module not available. Schedule enable job failed.'
return ret
@ -820,73 +754,51 @@ def move(name, target, **kwargs):
ret['comment'] = 'Job name is required.'
ret['result'] = False
if name in __opts__['schedule']:
if 'test' in kwargs and kwargs['test']:
ret['comment'] = 'Job: {0} would be moved from schedule.'.format(name)
else:
schedule_opts = []
for key, value in six.iteritems(__opts__['schedule'][name]):
temp = '{0}={1}'.format(key, value)
schedule_opts.append(temp)
response = __salt__['publish.publish'](target, 'schedule.add', schedule_opts)
# Get errors and list of affeced minions
errors = []
minions = []
for minion in response:
minions.append(minion)
if not response[minion]:
errors.append(minion)
# parse response
if not response:
ret['comment'] = 'no servers answered the published schedule.add command'
return ret
elif len(errors) > 0:
ret['comment'] = 'the following minions return False'
ret['minions'] = errors
return ret
else:
delete(name)
ret['result'] = True
ret['comment'] = 'Moved Job {0} from schedule.'.format(name)
ret['minions'] = minions
return ret
elif 'schedule' in __pillar__ and name in __pillar__['schedule']:
if 'test' in kwargs and kwargs['test']:
ret['comment'] = 'Job: {0} would be moved from schedule.'.format(name)
else:
schedule_opts = []
for key, value in six.iteritems(__opts__['schedule'][name]):
temp = '{0}={1}'.format(key, value)
schedule_opts.append(temp)
response = __salt__['publish.publish'](target, 'schedule.add', schedule_opts)
# Get errors and list of affeced minions
errors = []
minions = []
for minion in response:
minions.append(minion)
if not response[minion]:
errors.append(minion)
# parse response
if not response:
ret['comment'] = 'no servers answered the published schedule.add command'
return ret
elif len(errors) > 0:
ret['comment'] = 'the following minions return False'
ret['minions'] = errors
return ret
else:
delete(name, where='pillar')
ret['result'] = True
ret['comment'] = 'Moved Job {0} from schedule.'.format(name)
ret['minions'] = minions
return ret
if 'test' in kwargs and kwargs['test']:
ret['comment'] = 'Job: {0} would be moved from schedule.'.format(name)
else:
ret['comment'] = 'Job {0} does not exist.'.format(name)
ret['result'] = False
opts_schedule = list_(show_all=True, where='opts', return_yaml=False)
pillar_schedule = list_(show_all=True, where='pillar', return_yaml=False)
if name in opts_schedule:
schedule_data = opts_schedule[name]
where = None
elif name in pillar_schedule:
schedule_data = pillar_schedule[name]
where = 'pillar'
else:
ret['comment'] = 'Job {0} does not exist.'.format(name)
ret['result'] = False
return ret
schedule_opts = []
for key, value in six.iteritems(schedule_data):
temp = '{0}={1}'.format(key, value)
schedule_opts.append(temp)
response = __salt__['publish.publish'](target, 'schedule.add', schedule_opts)
# Get errors and list of affeced minions
errors = []
minions = []
for minion in response:
minions.append(minion)
if not response[minion]:
errors.append(minion)
# parse response
if not response:
ret['comment'] = 'no servers answered the published schedule.add command'
return ret
elif len(errors) > 0:
ret['comment'] = 'the following minions return False'
ret['minions'] = errors
return ret
else:
delete(name, where=where)
ret['result'] = True
ret['comment'] = 'Moved Job {0} from schedule.'.format(name)
ret['minions'] = minions
return ret
return ret
@ -908,69 +820,46 @@ def copy(name, target, **kwargs):
ret['comment'] = 'Job name is required.'
ret['result'] = False
if name in __opts__['schedule']:
if 'test' in kwargs and kwargs['test']:
ret['comment'] = 'Job: {0} would be copied.'.format(name)
else:
schedule_opts = []
for key, value in six.iteritems(__opts__['schedule'][name]):
temp = '{0}={1}'.format(key, value)
schedule_opts.append(temp)
response = __salt__['publish.publish'](target, 'schedule.add', schedule_opts)
# Get errors and list of affeced minions
errors = []
minions = []
for minion in response:
minions.append(minion)
if not response[minion]:
errors.append(minion)
# parse response
if not response:
ret['comment'] = 'no servers answered the published schedule.add command'
return ret
elif len(errors) > 0:
ret['comment'] = 'the following minions return False'
ret['minions'] = errors
return ret
else:
ret['result'] = True
ret['comment'] = 'Copied Job {0} from schedule to minion(s).'.format(name)
ret['minions'] = minions
return ret
elif 'schedule' in __pillar__ and name in __pillar__['schedule']:
if 'test' in kwargs and kwargs['test']:
ret['comment'] = 'Job: {0} would be moved from schedule.'.format(name)
else:
schedule_opts = []
for key, value in six.iteritems(__opts__['schedule'][name]):
temp = '{0}={1}'.format(key, value)
schedule_opts.append(temp)
response = __salt__['publish.publish'](target, 'schedule.add', schedule_opts)
# Get errors and list of affeced minions
errors = []
minions = []
for minion in response:
minions.append(minion)
if not response[minion]:
errors.append(minion)
# parse response
if not response:
ret['comment'] = 'no servers answered the published schedule.add command'
return ret
elif len(errors) > 0:
ret['comment'] = 'the following minions return False'
ret['minions'] = errors
return ret
else:
ret['result'] = True
ret['comment'] = 'Copied Job {0} from schedule to minion(s).'.format(name)
ret['minions'] = minions
return ret
if 'test' in kwargs and kwargs['test']:
ret['comment'] = 'Job: {0} would be copied from schedule.'.format(name)
else:
ret['comment'] = 'Job {0} does not exist.'.format(name)
ret['result'] = False
opts_schedule = list_(show_all=True, where='opts', return_yaml=False)
pillar_schedule = list_(show_all=True, where='pillar', return_yaml=False)
if name in opts_schedule:
schedule_data = opts_schedule[name]
elif name in pillar_schedule:
schedule_data = pillar_schedule[name]
else:
ret['comment'] = 'Job {0} does not exist.'.format(name)
ret['result'] = False
return ret
schedule_opts = []
for key, value in six.iteritems(schedule_data):
temp = '{0}={1}'.format(key, value)
schedule_opts.append(temp)
response = __salt__['publish.publish'](target, 'schedule.add', schedule_opts)
# Get errors and list of affeced minions
errors = []
minions = []
for minion in response:
minions.append(minion)
if not response[minion]:
errors.append(minion)
# parse response
if not response:
ret['comment'] = 'no servers answered the published schedule.add command'
return ret
elif len(errors) > 0:
ret['comment'] = 'the following minions return False'
ret['minions'] = errors
return ret
else:
ret['result'] = True
ret['comment'] = 'Copied Job {0} from schedule to minion(s).'.format(name)
ret['minions'] = minions
return ret
return ret

View File

@ -256,3 +256,79 @@ def absent(name, **kwargs):
ret['comment'] = '\n'.join(ret['comment'])
return ret
def enabled(name, **kwargs):
'''
Ensure a job is enabled in the schedule
name
The unique name that is given to the scheduled job.
'''
### NOTE: The keyword arguments in **kwargs are ignored in this state, but
### cannot be removed from the function definition, otherwise the use
### of unsupported arguments will result in a traceback.
ret = {'name': name,
'result': True,
'changes': {},
'comment': []}
current_schedule = __salt__['schedule.list'](show_all=True, return_yaml=False)
if name in current_schedule:
if 'test' in __opts__ and __opts__['test']:
kwargs['test'] = True
result = __salt__['schedule.enable_job'](name, **kwargs)
ret['comment'].append(result['comment'])
else:
result = __salt__['schedule.enable_job'](name, **kwargs)
if not result['result']:
ret['result'] = result['result']
ret['comment'] = result['comment']
return ret
else:
ret['comment'].append('Enabled job {0} from schedule'.format(name))
else:
ret['comment'].append('Job {0} not present in schedule'.format(name))
ret['comment'] = '\n'.join(ret['comment'])
return ret
def disabled(name, **kwargs):
'''
Ensure a job is disabled in the schedule
name
The unique name that is given to the scheduled job.
'''
### NOTE: The keyword arguments in **kwargs are ignored in this state, but
### cannot be removed from the function definition, otherwise the use
### of unsupported arguments will result in a traceback.
ret = {'name': name,
'result': True,
'changes': {},
'comment': []}
current_schedule = __salt__['schedule.list'](show_all=True, return_yaml=False)
if name in current_schedule:
if 'test' in __opts__ and __opts__['test']:
kwargs['test'] = True
result = __salt__['schedule.disable_job'](name, **kwargs)
ret['comment'].append(result['comment'])
else:
result = __salt__['schedule.disable_job'](name, **kwargs)
if not result['result']:
ret['result'] = result['result']
ret['comment'] = result['comment']
return ret
else:
ret['comment'].append('Disabled job {0} from schedule'.format(name))
else:
ret['comment'].append('Job {0} not present in schedule'.format(name))
ret['comment'] = '\n'.join(ret['comment'])
return ret

View File

@ -451,14 +451,14 @@ class Schedule(object):
self.delete_job(name, where=where)
self.opts['schedule'][name] = schedule
def run_job(self, name, where=None):
def run_job(self, name):
'''
Run a schedule job now
'''
if where == 'pillar':
data = self.opts['pillar']['schedule'][name]
else:
data = self.opts['schedule'][name]
schedule = self.opts['schedule']
if 'schedule' in self.opts['pillar']:
schedule.update(self.opts['pillar']['schedule'])
data = schedule[name]
if 'function' in data:
func = data['function']
@ -527,6 +527,26 @@ class Schedule(object):
else:
self.opts['schedule'] = schedule
def list(self, where):
'''
List the current schedule items
'''
schedule = {}
if where == 'pillar':
if 'schedule' in self.opts['pillar']:
schedule.update(self.opts['pillar']['schedule'])
elif where == 'opts':
schedule.update(self.opts['schedule'])
else:
schedule.update(self.opts['schedule'])
if 'schedule' in self.opts['pillar']:
schedule.update(self.opts['pillar']['schedule'])
# Fire the complete event back along with the list of schedule
evt = salt.utils.event.get_event('minion', opts=self.opts)
evt.fire_event({'complete': True, 'schedule': schedule},
tag='/salt/minion/minion_schedule_list_complete')
def handle_func(self, func, data):
'''
Execute this method in a multiprocess or thread

View File

@ -25,6 +25,7 @@ ensure_in_syspath('../../')
# Import Salt Libs
from salt.modules import schedule
from salt.utils.event import SaltEvent
# Globals
schedule.__salt__ = {}
@ -46,12 +47,20 @@ class ScheduleTestCase(TestCase):
'''
Test if it list the jobs currently scheduled on the minion.
'''
with patch.dict(schedule.__opts__, {'schedule': {'_seconds': []}}):
self.assertEqual(schedule.list_(), 'schedule:\n _seconds: []\n')
self.assertDictEqual(schedule.list_(True, False), {'_seconds': []})
with patch.dict(schedule.__opts__, {'schedule': {'_seconds': []}, 'sock_dir': SOCK_DIR}):
mock = MagicMock(return_value=True)
with patch.dict(schedule.__salt__, {'event.fire': mock}):
_ret_value = {'complete': True, 'schedule': {'_seconds': []}}
with patch.object(SaltEvent, 'get_event', return_value=_ret_value):
self.assertEqual(schedule.list_(), 'schedule:\n _seconds: []\n')
self.assertDictEqual(schedule.list_(show_all=True, return_yaml=False), {'_seconds': []})
with patch.dict(schedule.__opts__, {'schedule': {}}):
self.assertDictEqual(schedule.list_(), {'schedule': {}})
with patch.dict(schedule.__opts__, {'schedule': {}, 'sock_dir': SOCK_DIR}):
mock = MagicMock(return_value=True)
with patch.dict(schedule.__salt__, {'event.fire': mock}):
_ret_value = {'complete': True, 'schedule': {}}
with patch.object(SaltEvent, 'get_event', return_value=_ret_value):
self.assertDictEqual(schedule.list_(), {'schedule': {}})
# 'purge' function tests: 1
@ -59,9 +68,13 @@ class ScheduleTestCase(TestCase):
'''
Test if it purge all the jobs currently scheduled on the minion.
'''
with patch.dict(schedule.__opts__, {'schedule': {}}):
self.assertDictEqual(schedule.purge(), {'comment': [],
'result': True})
with patch.dict(schedule.__opts__, {'schedule': {}, 'sock_dir': SOCK_DIR}):
mock = MagicMock(return_value=True)
with patch.dict(schedule.__salt__, {'event.fire': mock}):
_ret_value = {'complete': True, 'schedule': {}}
with patch.object(SaltEvent, 'get_event', return_value=_ret_value):
self.assertDictEqual(schedule.purge(), {'comment': ['Deleted job: schedule from schedule.'],
'result': True})
# 'delete' function tests: 1
@ -69,10 +82,14 @@ class ScheduleTestCase(TestCase):
'''
Test if it delete a job from the minion's schedule.
'''
with patch.dict(schedule.__opts__, {'schedule': {}}):
self.assertDictEqual(schedule.delete('job1'),
{'comment': 'Job job1 does not exist.',
'result': False})
with patch.dict(schedule.__opts__, {'schedule': {}, 'sock_dir': SOCK_DIR}):
mock = MagicMock(return_value=True)
with patch.dict(schedule.__salt__, {'event.fire': mock}):
_ret_value = {'complete': True, 'schedule': {}}
with patch.object(SaltEvent, 'get_event', return_value=_ret_value):
self.assertDictEqual(schedule.delete('job1'),
{'comment': 'Job job1 does not exist.',
'result': False})
# 'build_schedule_item' function tests: 1
@ -115,21 +132,30 @@ class ScheduleTestCase(TestCase):
' or "days" with "when" or "cron" options.')
comm3 = 'Unable to use "when" and "cron" options together. Ignoring.'
comm4 = 'Job: job2 would be added to schedule.'
with patch.dict(schedule.__opts__, {'schedule': {'job1': 'salt'}}):
self.assertDictEqual(schedule.add('job1'),
{'comment': comm1, 'result': False})
with patch.dict(schedule.__opts__, {'schedule': {'job1': 'salt'}, 'sock_dir': SOCK_DIR}):
mock = MagicMock(return_value=True)
with patch.dict(schedule.__salt__, {'event.fire': mock}):
_ret_value = {'complete': True, 'schedule': {'job1': {'salt': 'salt'}}}
with patch.object(SaltEvent, 'get_event', return_value=_ret_value):
self.assertDictEqual(schedule.add('job1'),
{'comment': comm1, 'result': False})
self.assertDictEqual(schedule.add('job2', function='test.ping',
seconds=3600, when='2400'),
{'comment': comm2, 'result': False})
_ret_value = {'complete': True, 'schedule': {}}
with patch.object(SaltEvent, 'get_event', return_value=_ret_value):
self.assertDictEqual(schedule.add('job2', function='test.ping',
seconds=3600, when='2400'),
{'comment': comm2, 'result': False})
self.assertDictEqual(schedule.add('job2', function='test.ping',
when='2400', cron='2'),
{'comment': comm3, 'result': False})
self.assertDictEqual(schedule.add('job2', function='test.ping',
test=True),
{'comment': comm4, 'result': True})
_ret_value = {'complete': True, 'schedule': {}}
with patch.object(SaltEvent, 'get_event', return_value=_ret_value):
self.assertDictEqual(schedule.add('job2', function='test.ping',
when='2400', cron='2'),
{'comment': comm3, 'result': False})
_ret_value = {'complete': True, 'schedule': {}}
with patch.object(SaltEvent, 'get_event', return_value=_ret_value):
self.assertDictEqual(schedule.add('job2', function='test.ping',
test=True),
{'comment': comm4, 'result': True})
# 'modify' function tests: 1
@ -143,29 +169,37 @@ class ScheduleTestCase(TestCase):
comm3 = 'Job job2 does not exist in schedule.'
comm4 = 'Job: job3 would be modified in schedule.'
with patch.dict(schedule.__opts__, {'schedule': {'job1': JOB1,
'job3': {}}}):
self.assertDictEqual(schedule.modify('job1', function='test.ping',
seconds=3600, when='2400'),
{'changes': {}, 'comment': comm1,
'result': False})
'job3': {}},
'sock_dir': SOCK_DIR}):
self.assertDictEqual(schedule.modify('job1', function='test.ping',
when='2400', cron='2'),
{'changes': {}, 'comment': comm2,
'result': False})
mock = MagicMock(return_value=True)
with patch.dict(schedule.__salt__, {'event.fire': mock}):
_ret_value = {'complete': True, 'schedule': {'job1': JOB1,
'job3': {}}}
with patch.object(SaltEvent, 'get_event', return_value=_ret_value):
self.assertDictEqual(schedule.modify('job1', function='test.ping',
seconds=3600, when='2400'),
{'changes': {}, 'comment': comm1,
'result': False})
self.assertDictEqual(schedule.modify('job2'), {'changes': {},
'comment': comm3,
'result': False})
self.assertDictEqual(schedule.modify('job1', function='test.ping',
when='2400', cron='2'),
{'changes': {}, 'comment': comm2,
'result': False})
self.assertDictEqual(schedule.modify('job1', function='test.ping'),
{'changes': {},
'comment': 'Job job1 in correct state',
'result': True})
self.assertDictEqual(schedule.modify('job2'), {'changes': {},
'comment': comm3,
'result': False})
ret = schedule.modify('job3', function='test.ping', test=True)
del ret['changes']['diff'] # difflib formatting changes between 2.6 and 2.7
self.assertDictEqual(ret, {'changes': {}, 'comment': comm4, 'result': True})
self.assertDictEqual(schedule.modify('job1', function='test.ping'),
{'changes': {},
'comment': 'Job job1 in correct state',
'result': True})
ret = schedule.modify('job3', function='test.ping', test=True)
if 'diff' in ret['changes']:
del ret['changes']['diff'] # difflib formatting changes between 2.6 and 2.7
self.assertDictEqual(ret, {'changes': {}, 'comment': comm4, 'result': True})
# 'run_job' function tests: 1
@ -173,10 +207,14 @@ class ScheduleTestCase(TestCase):
'''
Test if it run a scheduled job on the minion immediately.
'''
with patch.dict(schedule.__opts__, {'schedule': {}}):
self.assertDictEqual(schedule.run_job('job1'),
{'comment': 'Job job1 does not exist.',
'result': False})
with patch.dict(schedule.__opts__, {'schedule': {}, 'sock_dir': SOCK_DIR}):
mock = MagicMock(return_value=True)
with patch.dict(schedule.__salt__, {'event.fire': mock}):
_ret_value = {'complete': True, 'schedule': {}}
with patch.object(SaltEvent, 'get_event', return_value=_ret_value):
self.assertDictEqual(schedule.run_job('job1'),
{'comment': 'Job job1 does not exist.',
'result': False})
# 'enable_job' function tests: 1
@ -184,10 +222,14 @@ class ScheduleTestCase(TestCase):
'''
Test if it enable a job in the minion's schedule.
'''
with patch.dict(schedule.__opts__, {'schedule': {}}):
self.assertDictEqual(schedule.enable_job('job1'),
{'comment': 'Job job1 does not exist.',
'result': False})
with patch.dict(schedule.__opts__, {'schedule': {}, 'sock_dir': SOCK_DIR}):
mock = MagicMock(return_value=True)
with patch.dict(schedule.__salt__, {'event.fire': mock}):
_ret_value = {'complete': True, 'schedule': {}}
with patch.object(SaltEvent, 'get_event', return_value=_ret_value):
self.assertDictEqual(schedule.enable_job('job1'),
{'comment': 'Job job1 does not exist.',
'result': False})
# 'disable_job' function tests: 1
@ -195,10 +237,14 @@ class ScheduleTestCase(TestCase):
'''
Test if it disable a job in the minion's schedule.
'''
with patch.dict(schedule.__opts__, {'schedule': {}}):
self.assertDictEqual(schedule.disable_job('job1'),
{'comment': 'Job job1 does not exist.',
'result': False})
with patch.dict(schedule.__opts__, {'schedule': {}, 'sock_dir': SOCK_DIR}):
mock = MagicMock(return_value=True)
with patch.dict(schedule.__salt__, {'event.fire': mock}):
_ret_value = {'complete': True, 'schedule': {}}
with patch.object(SaltEvent, 'get_event', return_value=_ret_value):
self.assertDictEqual(schedule.disable_job('job1'),
{'comment': 'Job job1 does not exist.',
'result': False})
# 'save' function tests: 1
@ -208,9 +254,15 @@ class ScheduleTestCase(TestCase):
'''
comm1 = 'Schedule (non-pillar items) saved to ///schedule.conf.'
with patch.dict(schedule.__opts__, {'config_dir': '', 'schedule': {},
'default_include': '/tmp'}):
self.assertDictEqual(schedule.save(),
{'comment': comm1, 'result': True})
'default_include': '/tmp',
'sock_dir': SOCK_DIR}):
mock = MagicMock(return_value=True)
with patch.dict(schedule.__salt__, {'event.fire': mock}):
_ret_value = {'complete': True, 'schedule': {}}
with patch.object(SaltEvent, 'get_event', return_value=_ret_value):
self.assertDictEqual(schedule.save(),
{'comment': comm1, 'result': True})
# 'enable' function tests: 1
@ -255,54 +307,62 @@ class ScheduleTestCase(TestCase):
comm2 = 'the following minions return False'
comm3 = 'Moved Job job1 from schedule.'
with patch.dict(schedule.__opts__, {'schedule': {'job1': JOB1}, 'sock_dir': SOCK_DIR}):
mock = MagicMock(return_value={})
with patch.dict(schedule.__salt__, {'publish.publish': mock}):
self.assertDictEqual(schedule.move('job1', 'minion1'),
{'comment': comm1, 'result': True})
mock = MagicMock(return_value=True)
with patch.dict(schedule.__salt__, {'event.fire': mock}):
_ret_value = {'complete': True, 'schedule': {'job1': JOB1}}
with patch.object(SaltEvent, 'get_event', return_value=_ret_value):
mock = MagicMock(return_value={})
with patch.dict(schedule.__salt__, {'publish.publish': mock}):
self.assertDictEqual(schedule.move('job1', 'minion1'),
{'comment': comm1, 'result': True})
mock = MagicMock(return_value={'minion1': ''})
with patch.dict(schedule.__salt__, {'publish.publish': mock}):
self.assertDictEqual(schedule.move('job1', 'minion1'),
{'comment': comm2, 'minions': ['minion1'],
'result': True})
mock = MagicMock(return_value={'minion1': ''})
with patch.dict(schedule.__salt__, {'publish.publish': mock}):
self.assertDictEqual(schedule.move('job1', 'minion1'),
{'comment': comm2, 'minions': ['minion1'],
'result': True})
mock = MagicMock(return_value={'minion1': 'job1'})
with patch.dict(schedule.__salt__, {'publish.publish': mock}):
mock = MagicMock(return_value=True)
with patch.dict(schedule.__salt__, {'event.fire': mock}):
self.assertDictEqual(schedule.move('job1', 'minion1'),
{'comment': comm3,
'minions': ['minion1'],
'result': True})
mock = MagicMock(return_value={'minion1': 'job1'})
with patch.dict(schedule.__salt__, {'publish.publish': mock}):
mock = MagicMock(return_value=True)
with patch.dict(schedule.__salt__, {'event.fire': mock}):
self.assertDictEqual(schedule.move('job1', 'minion1'),
{'comment': comm3,
'minions': ['minion1'],
'result': True})
self.assertDictEqual(schedule.move('job3', 'minion1'),
{'comment': 'Job job3 does not exist.',
'result': False})
self.assertDictEqual(schedule.move('job3', 'minion1'),
{'comment': 'Job job3 does not exist.',
'result': False})
mock = MagicMock(side_effect=[{}, {'job1': {}}])
with patch.dict(schedule.__opts__, {'schedule': mock, 'sock_dir': SOCK_DIR}):
with patch.dict(schedule.__pillar__, {'schedule': {'job1': JOB1}}):
mock = MagicMock(return_value={})
with patch.dict(schedule.__salt__, {'publish.publish': mock}):
self.assertDictEqual(schedule.move('job1', 'minion1'),
{'comment': comm1,
'result': True})
mock = MagicMock(return_value=True)
with patch.dict(schedule.__salt__, {'event.fire': mock}):
_ret_value = {'complete': True, 'schedule': {'job1': JOB1}}
with patch.object(SaltEvent, 'get_event', return_value=_ret_value):
with patch.dict(schedule.__pillar__, {'schedule': {'job1': JOB1}}):
mock = MagicMock(return_value={})
with patch.dict(schedule.__salt__, {'publish.publish': mock}):
self.assertDictEqual(schedule.move('job1', 'minion1'),
{'comment': comm1,
'result': True})
mock = MagicMock(return_value={'minion1': ''})
with patch.dict(schedule.__salt__, {'publish.publish': mock}):
self.assertDictEqual(schedule.move('job1', 'minion1'),
{'comment': comm2,
'minions': ['minion1'],
'result': True})
mock = MagicMock(return_value={'minion1': ''})
with patch.dict(schedule.__salt__, {'publish.publish': mock}):
self.assertDictEqual(schedule.move('job1', 'minion1'),
{'comment': comm2,
'minions': ['minion1'],
'result': True})
mock = MagicMock(return_value={'minion1': 'job1'})
with patch.dict(schedule.__salt__, {'publish.publish': mock}):
mock = MagicMock(return_value=True)
with patch.dict(schedule.__salt__, {'event.fire': mock}):
self.assertDictEqual(schedule.move('job1', 'minion1'),
{'comment': comm3,
'minions': ['minion1'],
'result': True})
mock = MagicMock(return_value={'minion1': 'job1'})
with patch.dict(schedule.__salt__, {'publish.publish': mock}):
mock = MagicMock(return_value=True)
with patch.dict(schedule.__salt__, {'event.fire': mock}):
self.assertDictEqual(schedule.move('job1', 'minion1'),
{'comment': comm3,
'minions': ['minion1'],
'result': True})
# 'copy' function tests: 1
@ -313,54 +373,63 @@ class ScheduleTestCase(TestCase):
comm1 = 'no servers answered the published schedule.add command'
comm2 = 'the following minions return False'
comm3 = 'Copied Job job1 from schedule to minion(s).'
with patch.dict(schedule.__opts__, {'schedule': {'job1': JOB1}}):
mock = MagicMock(return_value={})
with patch.dict(schedule.__salt__, {'publish.publish': mock}):
self.assertDictEqual(schedule.copy('job1', 'minion1'),
{'comment': comm1, 'result': True})
with patch.dict(schedule.__opts__, {'schedule': {'job1': JOB1}, 'sock_dir': SOCK_DIR}):
mock = MagicMock(return_value=True)
with patch.dict(schedule.__salt__, {'event.fire': mock}):
_ret_value = {'complete': True, 'schedule': {'job1': {'job1': JOB1}}}
with patch.object(SaltEvent, 'get_event', return_value=_ret_value):
mock = MagicMock(return_value={})
with patch.dict(schedule.__salt__, {'publish.publish': mock}):
self.assertDictEqual(schedule.copy('job1', 'minion1'),
{'comment': comm1, 'result': True})
mock = MagicMock(return_value={'minion1': ''})
with patch.dict(schedule.__salt__, {'publish.publish': mock}):
self.assertDictEqual(schedule.copy('job1', 'minion1'),
{'comment': comm2, 'minions': ['minion1'],
'result': True})
mock = MagicMock(return_value={'minion1': ''})
with patch.dict(schedule.__salt__, {'publish.publish': mock}):
self.assertDictEqual(schedule.copy('job1', 'minion1'),
{'comment': comm2, 'minions': ['minion1'],
'result': True})
mock = MagicMock(return_value={'minion1': 'job1'})
with patch.dict(schedule.__salt__, {'publish.publish': mock}):
mock = MagicMock(return_value=True)
with patch.dict(schedule.__salt__, {'event.fire': mock}):
self.assertDictEqual(schedule.copy('job1', 'minion1'),
{'comment': comm3,
'minions': ['minion1'],
'result': True})
mock = MagicMock(return_value={'minion1': 'job1'})
with patch.dict(schedule.__salt__, {'publish.publish': mock}):
mock = MagicMock(return_value=True)
with patch.dict(schedule.__salt__, {'event.fire': mock}):
self.assertDictEqual(schedule.copy('job1', 'minion1'),
{'comment': comm3,
'minions': ['minion1'],
'result': True})
self.assertDictEqual(schedule.copy('job3', 'minion1'),
{'comment': 'Job job3 does not exist.',
'result': False})
self.assertDictEqual(schedule.copy('job3', 'minion1'),
{'comment': 'Job job3 does not exist.',
'result': False})
mock = MagicMock(side_effect=[{}, {'job1': {}}])
with patch.dict(schedule.__opts__, {'schedule': mock}):
with patch.dict(schedule.__opts__, {'schedule': mock, 'sock_dir': SOCK_DIR}):
with patch.dict(schedule.__pillar__, {'schedule': {'job1': JOB1}}):
mock = MagicMock(return_value={})
with patch.dict(schedule.__salt__, {'publish.publish': mock}):
self.assertDictEqual(schedule.copy('job1', 'minion1'),
{'comment': comm1, 'result': True})
mock = MagicMock(return_value=True)
with patch.dict(schedule.__salt__, {'event.fire': mock}):
_ret_value = {'complete': True, 'schedule': {'job1': {'job1': JOB1}}}
with patch.object(SaltEvent, 'get_event', return_value=_ret_value):
mock = MagicMock(return_value={'minion1': ''})
with patch.dict(schedule.__salt__, {'publish.publish': mock}):
self.assertDictEqual(schedule.copy('job1', 'minion1'),
{'comment': comm2,
'minions': ['minion1'],
'result': True})
mock = MagicMock(return_value={})
with patch.dict(schedule.__salt__, {'publish.publish': mock}):
self.assertDictEqual(schedule.copy('job1', 'minion1'),
{'comment': comm1, 'result': True})
mock = MagicMock(return_value={'minion1': 'job1'})
with patch.dict(schedule.__salt__, {'publish.publish': mock}):
mock = MagicMock(return_value=True)
with patch.dict(schedule.__salt__, {'event.fire': mock}):
self.assertDictEqual(schedule.copy('job1', 'minion1'),
{'comment': comm3,
'minions': ['minion1'],
'result': True})
mock = MagicMock(return_value={'minion1': ''})
with patch.dict(schedule.__salt__, {'publish.publish': mock}):
self.assertDictEqual(schedule.copy('job1', 'minion1'),
{'comment': comm2,
'minions': ['minion1'],
'result': True})
mock = MagicMock(return_value={'minion1': 'job1'})
with patch.dict(schedule.__salt__, {'publish.publish': mock}):
mock = MagicMock(return_value=True)
with patch.dict(schedule.__salt__, {'event.fire': mock}):
self.assertDictEqual(schedule.copy('job1', 'minion1'),
{'comment': comm3,
'minions': ['minion1'],
'result': True})
if __name__ == '__main__':