Merge branch '2017.7' into '2018.3'

Conflicts:
  - salt/modules/win_lgpo.py
  - salt/netapi/rest_tornado/saltnado.py
This commit is contained in:
rallytime 2018-04-13 12:30:51 -04:00
commit 28a79ebba4
No known key found for this signature in database
GPG key ID: E8F1A4B90D0DEA19
4 changed files with 77 additions and 80 deletions

View file

@ -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:

View file

@ -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.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

View file

@ -383,7 +383,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 +928,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()
# 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 +941,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 +1016,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 +1065,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):

View file

@ -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',