From 69ce8e832cf8c5077e36ef1bdde43a29e8c898a2 Mon Sep 17 00:00:00 2001 From: "Gareth J. Greenaway" Date: Mon, 18 May 2015 13:33:22 -0700 Subject: [PATCH 1/3] refactoring the schedule execution module, also fixing issues that resulted in a disconnect when using salt vs salt-call to call the module function. --- salt/minion.py | 4 +- salt/modules/schedule.py | 518 +++++++++++++++------------------------ salt/utils/schedule.py | 32 ++- 3 files changed, 233 insertions(+), 321 deletions(-) diff --git a/salt/minion.py b/salt/minion.py index 2aee4d316f..0c3abcc4de 100644 --- a/salt/minion.py +++ b/salt/minion.py @@ -1344,11 +1344,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): ''' diff --git a/salt/modules/schedule.py b/salt/modules/schedule.py index 06e07c7cd0..d3aecaf31d 100644 --- a/salt/modules/schedule.py +++ b/salt/modules/schedule.py @@ -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,19 @@ 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']) + 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 for job in list(schedule.keys()): # iterate over a copy since we will mutate it if job == 'enabled': @@ -122,11 +132,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 +148,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 +180,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 +313,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 +396,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 +421,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 +458,11 @@ 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: + log.debug('schedule {0}'.format(type(schedule))) + log.debug('schedule {0}'.format(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 +472,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 +496,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 +546,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 +753,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 +819,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 diff --git a/salt/utils/schedule.py b/salt/utils/schedule.py index 21116fa153..153a38cc66 100644 --- a/salt/utils/schedule.py +++ b/salt/utils/schedule.py @@ -353,12 +353,14 @@ class Schedule(object): if where is None or where != 'pillar': # ensure job exists, then delete it if name in self.opts['schedule']: + log.debug('==== Deleting {0} ===='.format(name)) del self.opts['schedule'][name] schedule = self.opts['schedule'] else: # If job is in pillar, delete it there too if 'schedule' in self.opts['pillar']: if name in self.opts['pillar']['schedule']: + log.debug('==== Deleting {0} ====='.format(name)) del self.opts['pillar']['schedule'][name] schedule = self.opts['pillar']['schedule'] @@ -451,14 +453,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 +529,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 From a9c475a1005bb5ba4e94ba911020b0b7c772f7d8 Mon Sep 17 00:00:00 2001 From: "Gareth J. Greenaway" Date: Tue, 19 May 2015 12:14:20 -0700 Subject: [PATCH 2/3] removing logging statements. --- salt/modules/schedule.py | 2 - salt/states/schedule.py | 80 ++++++++++++++++++++++++++++++++++++++++ salt/utils/schedule.py | 2 - 3 files changed, 80 insertions(+), 4 deletions(-) diff --git a/salt/modules/schedule.py b/salt/modules/schedule.py index d3aecaf31d..46dc25a3eb 100644 --- a/salt/modules/schedule.py +++ b/salt/modules/schedule.py @@ -460,8 +460,6 @@ def run_job(name, force=False): schedule = list_(show_all=True, return_yaml=False) if name in schedule: - log.debug('schedule {0}'.format(type(schedule))) - log.debug('schedule {0}'.format(schedule)) data = schedule[name] if 'enabled' in data and not data['enabled'] and not force: ret['comment'] = 'Job {0} is disabled.'.format(name) diff --git a/salt/states/schedule.py b/salt/states/schedule.py index c61f0bdd28..1007f5f3df 100644 --- a/salt/states/schedule.py +++ b/salt/states/schedule.py @@ -79,6 +79,9 @@ Management of the Salt scheduler ''' +import logging +log = logging.getLogger(__name__) + def present(name, **kwargs): @@ -256,3 +259,80 @@ 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) + log.debug('current_schedule {0}'.format(current_schedule)) + 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 diff --git a/salt/utils/schedule.py b/salt/utils/schedule.py index 153a38cc66..22367ba413 100644 --- a/salt/utils/schedule.py +++ b/salt/utils/schedule.py @@ -353,14 +353,12 @@ class Schedule(object): if where is None or where != 'pillar': # ensure job exists, then delete it if name in self.opts['schedule']: - log.debug('==== Deleting {0} ===='.format(name)) del self.opts['schedule'][name] schedule = self.opts['schedule'] else: # If job is in pillar, delete it there too if 'schedule' in self.opts['pillar']: if name in self.opts['pillar']['schedule']: - log.debug('==== Deleting {0} ====='.format(name)) del self.opts['pillar']['schedule'][name] schedule = self.opts['pillar']['schedule'] From a09f0b23bdf2dfccb22f0961eec56ee3cd24c234 Mon Sep 17 00:00:00 2001 From: "Gareth J. Greenaway" Date: Fri, 22 May 2015 09:06:15 -0700 Subject: [PATCH 3/3] Updating schedule unit tests to align with refactoring changes. --- salt/modules/schedule.py | 3 + salt/states/schedule.py | 4 - tests/unit/modules/schedule_test.py | 347 +++++++++++++++++----------- 3 files changed, 211 insertions(+), 143 deletions(-) diff --git a/salt/modules/schedule.py b/salt/modules/schedule.py index 46dc25a3eb..7606f2e65d 100644 --- a/salt/modules/schedule.py +++ b/salt/modules/schedule.py @@ -70,6 +70,7 @@ def list_(show_all=False, where=None, return_yaml=True): salt '*' schedule.list show_all=True ''' + schedule = {} try: eventer = salt.utils.event.get_event('minion', opts=__opts__) res = __salt__['event.fire']({'func': 'list', @@ -83,6 +84,8 @@ def list_(show_all=False, where=None, return_yaml=True): 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': diff --git a/salt/states/schedule.py b/salt/states/schedule.py index 1007f5f3df..c2ca2dc350 100644 --- a/salt/states/schedule.py +++ b/salt/states/schedule.py @@ -79,9 +79,6 @@ Management of the Salt scheduler ''' -import logging -log = logging.getLogger(__name__) - def present(name, **kwargs): @@ -317,7 +314,6 @@ def disabled(name, **kwargs): 'comment': []} current_schedule = __salt__['schedule.list'](show_all=True, return_yaml=False) - log.debug('current_schedule {0}'.format(current_schedule)) if name in current_schedule: if 'test' in __opts__ and __opts__['test']: kwargs['test'] = True diff --git a/tests/unit/modules/schedule_test.py b/tests/unit/modules/schedule_test.py index 9a7df0134e..c6f60c08fe 100644 --- a/tests/unit/modules/schedule_test.py +++ b/tests/unit/modules/schedule_test.py @@ -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__':