mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge pull request #47062 from rallytime/merge-2018.3
[2018.3] Merge forward from 2017.7 to 2018.3
This commit is contained in:
commit
7bfa608e9f
4 changed files with 78 additions and 80 deletions
|
@ -2403,9 +2403,8 @@ def get_server_id():
|
|||
if py_ver >= (3, 3):
|
||||
# Python 3.3 enabled hash randomization, so we need to shell out to get
|
||||
# a reliable hash.
|
||||
py_bin = 'python{0}.{1}'.format(*py_ver)
|
||||
id_hash = __salt__['cmd.run'](
|
||||
[py_bin, '-c', 'print(hash("{0}"))'.format(id_)],
|
||||
[sys.executable, '-c', 'print(hash("{0}"))'.format(id_)],
|
||||
env={'PYTHONHASHSEED': '0'}
|
||||
)
|
||||
try:
|
||||
|
|
|
@ -49,6 +49,7 @@ import time
|
|||
|
||||
# Import Salt libs
|
||||
from salt.exceptions import CommandExecutionError, SaltInvocationError
|
||||
from salt.serializers.configparser import deserialize
|
||||
import salt.utils.dictupdate as dictupdate
|
||||
import salt.utils.files
|
||||
import salt.utils.path
|
||||
|
@ -4652,37 +4653,34 @@ def _writeAdminTemplateRegPolFile(admtemplate_data,
|
|||
def _getScriptSettingsFromIniFile(policy_info):
|
||||
'''
|
||||
helper function to parse/read a GPO Startup/Shutdown script file
|
||||
|
||||
psscript.ini and script.ini file definitions are here
|
||||
https://msdn.microsoft.com/en-us/library/ff842529.aspx
|
||||
https://msdn.microsoft.com/en-us/library/dd303238.aspx
|
||||
'''
|
||||
_existingData = _read_regpol_file(policy_info['ScriptIni']['IniPath'])
|
||||
if _existingData:
|
||||
_existingData = _existingData.split('\r\n')
|
||||
script_settings = {}
|
||||
this_section = None
|
||||
for eLine in _existingData:
|
||||
if eLine.startswith('[') and eLine.endswith(']'):
|
||||
this_section = eLine.replace('[', '').replace(']', '')
|
||||
log.debug('adding section %s', this_section)
|
||||
if this_section:
|
||||
script_settings[this_section] = {}
|
||||
else:
|
||||
if '=' in eLine:
|
||||
log.debug('working with config line %s', eLine)
|
||||
eLine = eLine.split('=')
|
||||
if this_section in script_settings:
|
||||
script_settings[this_section][eLine[0]] = eLine[1]
|
||||
if 'SettingName' in policy_info['ScriptIni']:
|
||||
log.debug('Setting Name is in policy_info')
|
||||
if policy_info['ScriptIni']['SettingName'] in script_settings[policy_info['ScriptIni']['Section']]:
|
||||
log.debug('the value is set in the file')
|
||||
return script_settings[policy_info['ScriptIni']['Section']][policy_info['ScriptIni']['SettingName']]
|
||||
_existingData = None
|
||||
if os.path.isfile(policy_info['ScriptIni']['IniPath']):
|
||||
with salt.utils.files.fopen(policy_info['ScriptIni']['IniPath'], 'rb') as fhr:
|
||||
_existingData = fhr.read()
|
||||
if _existingData:
|
||||
try:
|
||||
_existingData = deserialize(_existingData.decode('utf-16-le').lstrip('\ufeff'))
|
||||
log.debug('Have deserialized data %s', _existingData)
|
||||
except Exception as error:
|
||||
log.error('An error occurred attempting to deserialize data for %s', policy_info['Policy'])
|
||||
raise CommandExecutionError(error)
|
||||
if 'Section' in policy_info['ScriptIni'] and policy_info['ScriptIni']['Section'].lower() in [z.lower() for z in _existingData.keys()]:
|
||||
if 'SettingName' in policy_info['ScriptIni']:
|
||||
log.debug('Need to look for %s', policy_info['ScriptIni']['SettingName'])
|
||||
if policy_info['ScriptIni']['SettingName'].lower() in [z.lower() for z in _existingData[policy_info['ScriptIni']['Section']].keys()]:
|
||||
return _existingData[policy_info['ScriptIni']['Section']][policy_info['ScriptIni']['SettingName'].lower()]
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
return _existingData[policy_info['ScriptIni']['Section']]
|
||||
else:
|
||||
return None
|
||||
elif policy_info['ScriptIni']['Section'] in script_settings:
|
||||
log.debug('no setting name')
|
||||
return script_settings[policy_info['ScriptIni']['Section']]
|
||||
else:
|
||||
log.debug('broad else')
|
||||
return None
|
||||
|
||||
return None
|
||||
|
||||
|
||||
|
|
|
@ -213,6 +213,7 @@ ioloop.install()
|
|||
import salt.netapi
|
||||
import salt.utils.args
|
||||
import salt.utils.event
|
||||
import salt.utils.jid
|
||||
import salt.utils.json
|
||||
import salt.utils.yaml
|
||||
from salt.utils.event import tagify
|
||||
|
@ -383,7 +384,7 @@ class EventListener(object):
|
|||
for (tag, matcher), futures in six.iteritems(self.tag_map):
|
||||
try:
|
||||
is_matched = matcher(mtag, tag)
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
log.error('Failed to run a matcher.', exc_info=True)
|
||||
is_matched = False
|
||||
|
||||
|
@ -928,7 +929,11 @@ class SaltAPIHandler(BaseSaltAPIHandler): # pylint: disable=W0223
|
|||
'''
|
||||
Dispatch local client commands
|
||||
'''
|
||||
chunk_ret = {}
|
||||
# Generate jid before triggering a job to subscribe all returns from minions
|
||||
chunk['jid'] = salt.utils.jid.gen_jid(self.application.opts)
|
||||
|
||||
# Subscribe returns from minions before firing a job
|
||||
future_minion_map = self.subscribe_minion_returns(chunk['jid'], chunk['tgt'])
|
||||
|
||||
f_call = self._format_call_run_job_async(chunk)
|
||||
# fire a job off
|
||||
|
@ -937,64 +942,71 @@ class SaltAPIHandler(BaseSaltAPIHandler): # pylint: disable=W0223
|
|||
# if the job didn't publish, lets not wait around for nothing
|
||||
# TODO: set header??
|
||||
if 'jid' not in pub_data:
|
||||
for future in future_minion_map:
|
||||
try:
|
||||
future.set_result(None)
|
||||
except Exception:
|
||||
pass
|
||||
raise tornado.gen.Return('No minions matched the target. No command was sent, no jid was assigned.')
|
||||
|
||||
# seed minions_remaining with the pub_data
|
||||
minions_remaining = pub_data['minions']
|
||||
|
||||
syndic_min_wait = None
|
||||
if self.application.opts['order_masters']:
|
||||
syndic_min_wait = tornado.gen.sleep(self.application.opts['syndic_wait'])
|
||||
|
||||
# To ensure job_not_running and all_return are terminated by each other, communicate using a future
|
||||
is_finished = Future()
|
||||
|
||||
job_not_running_future = self.job_not_running(pub_data['jid'],
|
||||
chunk['tgt'],
|
||||
f_call['kwargs']['tgt_type'],
|
||||
is_finished,
|
||||
minions_remaining=list(minions_remaining),
|
||||
)
|
||||
is_finished)
|
||||
|
||||
# if we have a min_wait, do that
|
||||
if syndic_min_wait is not None:
|
||||
yield syndic_min_wait
|
||||
|
||||
all_return_future = self.all_returns(pub_data['jid'],
|
||||
is_finished,
|
||||
minions_remaining=list(minions_remaining),
|
||||
)
|
||||
minion_returns_future = self.sanitize_minion_returns(future_minion_map, pub_data['minions'], is_finished)
|
||||
|
||||
yield job_not_running_future
|
||||
raise tornado.gen.Return((yield all_return_future))
|
||||
raise tornado.gen.Return((yield minion_returns_future))
|
||||
|
||||
def subscribe_minion_returns(self, jid, minions):
|
||||
# Subscribe each minion event
|
||||
future_minion_map = {}
|
||||
for minion in minions:
|
||||
tag = tagify([jid, 'ret', minion], 'job')
|
||||
minion_future = self.application.event_listener.get_event(self,
|
||||
tag=tag,
|
||||
matcher=EventListener.exact_matcher,
|
||||
timeout=self.application.opts['timeout'])
|
||||
future_minion_map[minion_future] = minion
|
||||
return future_minion_map
|
||||
|
||||
@tornado.gen.coroutine
|
||||
def all_returns(self,
|
||||
jid,
|
||||
is_finished,
|
||||
minions_remaining=None,
|
||||
):
|
||||
def sanitize_minion_returns(self, future_minion_map, minions, is_finished):
|
||||
'''
|
||||
Return a future which will complete once all returns are completed
|
||||
(according to minions_remaining), or one of the passed in "is_finished" completes
|
||||
(according to minions), or one of the passed in "finish_chunk_ret_future" completes
|
||||
'''
|
||||
if minions_remaining is None:
|
||||
minions_remaining = []
|
||||
if minions is None:
|
||||
minions = []
|
||||
|
||||
# Remove redundant minions
|
||||
redundant_minion_futures = [future for future in future_minion_map.keys() if future_minion_map[future] not in minions]
|
||||
for redundant_minion_future in redundant_minion_futures:
|
||||
try:
|
||||
redundant_minion_future.set_result(None)
|
||||
except Exception:
|
||||
pass
|
||||
del future_minion_map[redundant_minion_future]
|
||||
|
||||
chunk_ret = {}
|
||||
|
||||
minion_events = {}
|
||||
for minion in minions_remaining:
|
||||
tag = tagify([jid, 'ret', minion], 'job')
|
||||
minion_event = self.application.event_listener.get_event(self,
|
||||
tag=tag,
|
||||
matcher=EventListener.exact_matcher,
|
||||
timeout=self.application.opts['timeout'])
|
||||
minion_events[minion_event] = minion
|
||||
|
||||
while True:
|
||||
f = yield Any(minion_events.keys() + [is_finished])
|
||||
f = yield Any(future_minion_map.keys() + [is_finished])
|
||||
try:
|
||||
# When finished entire routine, cleanup other futures and return result
|
||||
if f is is_finished:
|
||||
for event in minion_events:
|
||||
for event in future_minion_map.keys():
|
||||
if not event.done():
|
||||
event.set_result(None)
|
||||
raise tornado.gen.Return(chunk_ret)
|
||||
|
@ -1005,31 +1017,22 @@ class SaltAPIHandler(BaseSaltAPIHandler): # pylint: disable=W0223
|
|||
|
||||
# clear finished event future
|
||||
try:
|
||||
minions_remaining.remove(minion_events[f])
|
||||
del minion_events[f]
|
||||
minions.remove(future_minion_map[f])
|
||||
del future_minion_map[f]
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
if len(minions_remaining) == 0:
|
||||
if not minions:
|
||||
if not is_finished.done():
|
||||
is_finished.set_result(True)
|
||||
raise tornado.gen.Return(chunk_ret)
|
||||
|
||||
@tornado.gen.coroutine
|
||||
def job_not_running(self,
|
||||
jid,
|
||||
tgt,
|
||||
tgt_type,
|
||||
is_finished,
|
||||
minions_remaining=None,
|
||||
):
|
||||
def job_not_running(self, jid, tgt, tgt_type, is_finished):
|
||||
'''
|
||||
Return a future which will complete once jid (passed in) is no longer
|
||||
running on tgt
|
||||
'''
|
||||
if minions_remaining is None:
|
||||
minions_remaining = []
|
||||
|
||||
ping_pub_data = yield self.saltclients['local'](tgt,
|
||||
'saltutil.find_job',
|
||||
[jid],
|
||||
|
@ -1063,13 +1066,11 @@ class SaltAPIHandler(BaseSaltAPIHandler): # pylint: disable=W0223
|
|||
ping_tag = tagify([ping_pub_data['jid'], 'ret'], 'job')
|
||||
minion_running = False
|
||||
continue
|
||||
|
||||
# Minions can return, we want to see if the job is running...
|
||||
if event['data'].get('return', {}) == {}:
|
||||
continue
|
||||
minion_running = True
|
||||
id_ = event['data']['id']
|
||||
if id_ not in minions_remaining:
|
||||
minions_remaining.append(event['data']['id'])
|
||||
|
||||
@tornado.gen.coroutine
|
||||
def _disbatch_local_async(self, chunk):
|
||||
|
|
|
@ -83,7 +83,7 @@ class PkgrepoTest(ModuleCase, SaltReturnAssertsMixin):
|
|||
'''
|
||||
os_family = grains['os_family'].lower()
|
||||
|
||||
if os_family in ('redhat', 'suse'):
|
||||
if os_family in ('redhat',):
|
||||
kwargs = {
|
||||
'name': 'examplerepo',
|
||||
'baseurl': 'http://example.com/repo',
|
||||
|
|
Loading…
Add table
Reference in a new issue