New feature: automatic job batching

This commit creates a new feature that provides automatic batching of
jobs if the job would have executed on too many minions.

See comments provided in commit for additional details.
Ref: #19054 (https://github.com/saltstack/salt/issues/19054)
This commit is contained in:
Michael Lustfield 2017-05-03 03:08:24 -05:00
parent 1c0c53bcd0
commit 02614bdfd1
4 changed files with 41 additions and 7 deletions

View file

@ -279,6 +279,15 @@
# a value for you. Default is disabled.
# ipc_write_buffer: 'dynamic'
# These two batch settings, batch_safe_limit and batch_safe_size, are used to
# automatically switch to a batch mode execution. If a command would have been
# sent to more than <batch_safe_limit> minions, then run the command in
# batches of <batch_safe_size>. If no batch_safe_size is specified, a default
# of 8 will be used. If no batch_safe_limit is specified, then no automatic
# batching will occur.
#batch_safe_limit: 100
#batch_safe_size: 8
##### Security settings #####
##########################################

View file

@ -103,7 +103,7 @@ class Batch(object):
if i:
del wait[:i]
def run(self):
def run(self, safe_batch=False):
'''
Execute the batch run
'''
@ -113,6 +113,8 @@ class Batch(object):
self.opts['timeout'],
'list',
]
if safe_batch:
self.opts['batch'] = str(safe_batch)
bnum = self.get_bnum()
# No targets to run
if not self.minions:

View file

@ -39,8 +39,7 @@ class SaltCMD(parsers.SaltCMDOptionParser):
try:
# We don't need to bail on config file permission errors
# if the CLI
# process is run with the -a flag
# if the CLI process is run with the -a flag
skip_perm_errors = self.options.eauth != ''
self.local_client = salt.client.get_local_client(
@ -61,6 +60,7 @@ class SaltCMD(parsers.SaltCMDOptionParser):
if self.options.preview_target:
self._preview_target()
self._output_ret(minion_list, self.config.get('output', 'nested'))
return
if self.options.timeout <= 0:
@ -88,6 +88,13 @@ class SaltCMD(parsers.SaltCMDOptionParser):
else:
kwargs['tgt_type'] = 'glob'
# If batch_safe_limit is set, check minions matching target and
# potentially switch to batch execution
if self.options.batch_safe_limit > 1:
if len(self._preview_target()) >= int(self.options.batch_safe_limit):
self._run_batch(self.options.batch_safe_size)
return
if getattr(self.options, 'return'):
kwargs['ret'] = getattr(self.options, 'return')
@ -202,10 +209,9 @@ class SaltCMD(parsers.SaltCMDOptionParser):
'''
Return a list of minions from a given target
'''
minion_list = self.local_client.gather_minions(self.config['tgt'], self.selected_target_option or 'glob')
self._output_ret(minion_list, self.config.get('output', 'nested'))
return self.local_client.gather_minions(self.config['tgt'], self.selected_target_option or 'glob')
def _run_batch(self):
def _run_batch(self, safe_batch=False):
import salt.cli.batch
eauth = {}
if 'token' in self.config:
@ -254,9 +260,12 @@ class SaltCMD(parsers.SaltCMDOptionParser):
except salt.exceptions.SaltClientError as exc:
# We will print errors to the console further down the stack
sys.exit(1)
if safe_batch:
# Batch was triggered by safe limit check, use safe_batch size
batch.opts['batch'] = safe_batch
# Printing the output is already taken care of in run() itself
retcode = 0
for res in batch.run():
for res in batch.run(safe_batch):
for ret in six.itervalues(res):
job_retcode = salt.utils.job.get_retcode(ret)
if job_retcode > retcode:

View file

@ -1913,6 +1913,20 @@ class SaltCMDOptionParser(six.with_metaclass(OptionParserMeta,
help=('Wait the specified time in seconds after each job is done '
'before freeing the slot in the batch for the next one.')
)
self.add_option(
'--batch-safe-limit',
default=0,
dest='batch_safe_limit',
type=int,
help=('Execute the salt job in batch mode if the job would have '
'executed on more than this many minions.')
)
self.add_option(
'--batch-safe-size',
default=8,
dest='batch_safe_size',
help=('Batch size to use for batch jobs created by batch-safe-limit.')
)
self.add_option(
'--return',
default='',