mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge pull request #44640 from vutny/fix-cron-schedule-splay
Fix #44583: splay with cron-like scheduled jobs
This commit is contained in:
commit
06fb80b69c
2 changed files with 77 additions and 13 deletions
|
@ -1244,8 +1244,27 @@ class Schedule(object):
|
|||
|
||||
run = False
|
||||
seconds = data['_next_fire_time'] - now
|
||||
if data['_splay']:
|
||||
seconds = data['_splay'] - now
|
||||
|
||||
if 'splay' in data:
|
||||
# Got "splay" configured, make decision to run a job based on that
|
||||
if not data['_splay']:
|
||||
# Try to add "splay" time only if next job fire time is
|
||||
# still in the future. We should trigger job run
|
||||
# immediately otherwise.
|
||||
splay = _splay(data['splay'])
|
||||
if now < data['_next_fire_time'] + splay:
|
||||
log.debug('schedule.handle_func: Adding splay of '
|
||||
'{0} seconds to next run.'.format(splay))
|
||||
data['_splay'] = data['_next_fire_time'] + splay
|
||||
if 'when' in data:
|
||||
data['_run'] = True
|
||||
else:
|
||||
run = True
|
||||
|
||||
if data['_splay']:
|
||||
# The "splay" configuration has been already processed, just use it
|
||||
seconds = data['_splay'] - now
|
||||
|
||||
if seconds <= 0:
|
||||
if '_seconds' in data:
|
||||
run = True
|
||||
|
@ -1264,16 +1283,6 @@ class Schedule(object):
|
|||
run = True
|
||||
data['_run_on_start'] = False
|
||||
elif run:
|
||||
if 'splay' in data and not data['_splay']:
|
||||
splay = _splay(data['splay'])
|
||||
if now < data['_next_fire_time'] + splay:
|
||||
log.debug('schedule.handle_func: Adding splay of '
|
||||
'{0} seconds to next run.'.format(splay))
|
||||
run = False
|
||||
data['_splay'] = data['_next_fire_time'] + splay
|
||||
if 'when' in data:
|
||||
data['_run'] = True
|
||||
|
||||
if 'range' in data:
|
||||
if not _RANGE_SUPPORTED:
|
||||
log.error('Missing python-dateutil. Ignoring job {0}'.format(job))
|
||||
|
|
|
@ -5,8 +5,9 @@
|
|||
|
||||
# Import python libs
|
||||
from __future__ import absolute_import
|
||||
import os
|
||||
import copy
|
||||
import os
|
||||
import time
|
||||
|
||||
# Import Salt Testing Libs
|
||||
from tests.support.unit import skipIf, TestCase
|
||||
|
@ -17,6 +18,15 @@ import tests.integration as integration
|
|||
import salt.config
|
||||
from salt.utils.schedule import Schedule
|
||||
|
||||
# pylint: disable=import-error,unused-import
|
||||
try:
|
||||
import croniter
|
||||
_CRON_SUPPORTED = True
|
||||
except ImportError:
|
||||
_CRON_SUPPORTED = False
|
||||
# pylint: enable=import-error
|
||||
|
||||
|
||||
ROOT_DIR = os.path.join(integration.TMP, 'schedule-unit-tests')
|
||||
SOCK_DIR = os.path.join(ROOT_DIR, 'test-socks')
|
||||
|
||||
|
@ -28,6 +38,7 @@ DEFAULT_CONFIG['pki_dir'] = os.path.join(ROOT_DIR, 'pki')
|
|||
DEFAULT_CONFIG['cachedir'] = os.path.join(ROOT_DIR, 'cache')
|
||||
|
||||
|
||||
# pylint: disable=too-many-public-methods,invalid-name
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
class ScheduleTestCase(TestCase):
|
||||
'''
|
||||
|
@ -276,3 +287,47 @@ class ScheduleTestCase(TestCase):
|
|||
'''
|
||||
self.schedule.opts.update({'schedule': {}, 'pillar': {'schedule': ''}})
|
||||
self.assertRaises(ValueError, Schedule.eval, self.schedule)
|
||||
|
||||
def test_eval_schedule_time(self):
|
||||
'''
|
||||
Tests eval if the schedule setting time is in the future
|
||||
'''
|
||||
self.schedule.opts.update({'pillar': {'schedule': {}}})
|
||||
self.schedule.opts.update({'schedule': {'testjob': {'function': 'test.true', 'seconds': 60}}})
|
||||
now = int(time.time())
|
||||
self.schedule.eval()
|
||||
self.assertTrue(self.schedule.opts['schedule']['testjob']['_next_fire_time'] > now)
|
||||
|
||||
def test_eval_schedule_time_eval(self):
|
||||
'''
|
||||
Tests eval if the schedule setting time is in the future plus splay
|
||||
'''
|
||||
self.schedule.opts.update({'pillar': {'schedule': {}}})
|
||||
self.schedule.opts.update(
|
||||
{'schedule': {'testjob': {'function': 'test.true', 'seconds': 60, 'splay': 5}}})
|
||||
now = int(time.time())
|
||||
self.schedule.eval()
|
||||
self.assertTrue(self.schedule.opts['schedule']['testjob']['_splay'] - now > 60)
|
||||
|
||||
@skipIf(not _CRON_SUPPORTED, 'croniter module not installed')
|
||||
def test_eval_schedule_cron(self):
|
||||
'''
|
||||
Tests eval if the schedule is defined with cron expression
|
||||
'''
|
||||
self.schedule.opts.update({'pillar': {'schedule': {}}})
|
||||
self.schedule.opts.update({'schedule': {'testjob': {'function': 'test.true', 'cron': '* * * * *'}}})
|
||||
now = int(time.time())
|
||||
self.schedule.eval()
|
||||
self.assertTrue(self.schedule.opts['schedule']['testjob']['_next_fire_time'] > now)
|
||||
|
||||
@skipIf(not _CRON_SUPPORTED, 'croniter module not installed')
|
||||
def test_eval_schedule_cron_splay(self):
|
||||
'''
|
||||
Tests eval if the schedule is defined with cron expression plus splay
|
||||
'''
|
||||
self.schedule.opts.update({'pillar': {'schedule': {}}})
|
||||
self.schedule.opts.update(
|
||||
{'schedule': {'testjob': {'function': 'test.true', 'cron': '* * * * *', 'splay': 5}}})
|
||||
self.schedule.eval()
|
||||
self.assertTrue(self.schedule.opts['schedule']['testjob']['_splay'] >
|
||||
self.schedule.opts['schedule']['testjob']['_next_fire_time'])
|
||||
|
|
Loading…
Add table
Reference in a new issue