Merge pull request #50586 from garethgreenaway/50562_minion_blackout_scheduler

[2018.3] minion_blackout for scheduled jobs
This commit is contained in:
Mike Place 2018-11-23 06:15:38 -05:00 committed by GitHub
commit 59809a1e1b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 63 additions and 1 deletions

View file

@ -47,6 +47,10 @@ import salt.log.setup as log_setup
import salt.defaults.exitcodes
from salt.utils.odict import OrderedDict
from salt.exceptions import (
SaltInvocationError
)
# Import 3rd-party libs
from salt.ext import six
@ -609,6 +613,7 @@ class Schedule(object):
log.warning('schedule: The metadata parameter must be '
'specified as a dictionary. Ignoring.')
data_returner = data.get('returner', None)
salt.utils.process.appendproctitle('{0} {1}'.format(self.__class__.__name__, ret['jid']))
if not self.standalone:
@ -626,6 +631,22 @@ class Schedule(object):
# TODO: Make it readable! Splt to funcs, remove nested try-except-finally sections.
try:
minion_blackout_violation = False
if self.opts.get('pillar', {}).get('minion_blackout', False):
whitelist = self.opts.get('pillar', {}).get('minion_blackout_whitelist', [])
# this minion is blacked out. Only allow saltutil.refresh_pillar and the whitelist
if func != 'saltutil.refresh_pillar' and func not in whitelist:
minion_blackout_violation = True
elif self.opts.get('grains', {}).get('minion_blackout', False):
whitelist = self.opts.get('grains', {}).get('minion_blackout_whitelist', [])
if func != 'saltutil.refresh_pillar' and func not in whitelist:
minion_blackout_violation = True
if minion_blackout_violation:
raise SaltInvocationError('Minion in blackout mode. Set \'minion_blackout\' '
'to False in pillar or grains to resume operations. Only '
'saltutil.refresh_pillar allowed in blackout mode.')
ret['pid'] = os.getpid()
if not self.standalone:
@ -704,6 +725,7 @@ class Schedule(object):
self.functions[mod_name].__globals__[global_key] = value
self.functions.pack['__context__']['retcode'] = 0
ret['return'] = self.functions[func](*args, **kwargs)
if not self.standalone:
@ -713,7 +735,6 @@ class Schedule(object):
ret['success'] = True
data_returner = data.get('returner', None)
if data_returner or self.schedule_returner:
if 'return_config' in data:
ret['ret_config'] = data['return_config']

View file

@ -7,6 +7,7 @@
from __future__ import absolute_import, print_function, unicode_literals
import copy
import datetime
import logging
import os
# Import Salt Testing Libs
@ -26,6 +27,7 @@ except ImportError:
_CRON_SUPPORTED = False
# pylint: enable=import-error
log = logging.getLogger(__name__)
ROOT_DIR = os.path.join(integration.TMP, 'schedule-unit-tests')
SOCK_DIR = os.path.join(ROOT_DIR, 'test-socks')
@ -331,3 +333,42 @@ class ScheduleTestCase(TestCase):
self.schedule.eval()
self.assertTrue(self.schedule.opts['schedule']['testjob']['_splay'] >
self.schedule.opts['schedule']['testjob']['_next_fire_time'])
def test_handle_func_schedule_minion_blackout(self):
'''
Tests eval if the schedule from pillar is not a dictionary
'''
self.schedule.opts.update({'pillar': {'schedule': {}}})
self.schedule.opts.update({'grains': {'minion_blackout': True}})
self.schedule.opts.update(
{'schedule': {'testjob': {'function': 'test.true',
'seconds': 60}}})
data = {'function': 'test.true',
'_next_scheduled_fire_time': datetime.datetime(2018,
11,
21,
14,
9,
53,
903438),
'run': True,
'name': 'testjob',
'seconds': 60,
'_splay': None,
'_seconds': 60,
'jid_include': True,
'maxrunning': 1,
'_next_fire_time': datetime.datetime(2018,
11,
21,
14,
8,
53,
903438)}
with patch.object(salt.utils.schedule, 'log') as log_mock:
with patch('salt.utils.process.daemonize'), \
patch('sys.platform', 'linux2'):
self.schedule.handle_func(False, 'test.ping', data)
self.assertTrue(log_mock.exception.called)