mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge branch '2019.2.1' into cp-52415
This commit is contained in:
commit
ecd6802b3f
8 changed files with 231 additions and 35 deletions
|
@ -3189,7 +3189,10 @@ def purge(vm_, dirs=False, removables=None, **kwargs):
|
|||
shutil.rmtree(dir_)
|
||||
if getattr(libvirt, 'VIR_DOMAIN_UNDEFINE_NVRAM', False):
|
||||
# This one is only in 1.2.8+
|
||||
dom.undefineFlags(libvirt.VIR_DOMAIN_UNDEFINE_NVRAM)
|
||||
try:
|
||||
dom.undefineFlags(libvirt.VIR_DOMAIN_UNDEFINE_NVRAM)
|
||||
except Exception:
|
||||
dom.undefine()
|
||||
else:
|
||||
dom.undefine()
|
||||
conn.close()
|
||||
|
|
|
@ -3016,7 +3016,7 @@ class GitPillar(GitBase):
|
|||
if repo.branch == '__env__' and hasattr(repo, 'all_saltenvs'):
|
||||
env = self.opts.get('pillarenv') \
|
||||
or self.opts.get('saltenv') \
|
||||
or self.opts.get('git_pillar_base')
|
||||
or 'base'
|
||||
elif repo.env:
|
||||
env = repo.env
|
||||
else:
|
||||
|
|
|
@ -56,11 +56,7 @@ class PyTestEngine(object):
|
|||
|
||||
@gen.coroutine
|
||||
def _start(self):
|
||||
if self.opts['__role'] == 'minion':
|
||||
yield self.listen_to_minion_connected_event()
|
||||
else:
|
||||
self.io_loop.spawn_callback(self.fire_master_started_event)
|
||||
|
||||
self.io_loop.spawn_callback(self.fire_master_started_event)
|
||||
port = int(self.opts['runtests_conn_check_port'])
|
||||
log.info('Starting Pytest Engine(role=%s) on port %s', self.opts['__role'], port)
|
||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
|
@ -92,19 +88,6 @@ class PyTestEngine(object):
|
|||
# This is not macOS !?
|
||||
pass
|
||||
|
||||
@gen.coroutine
|
||||
def listen_to_minion_connected_event(self):
|
||||
log.info('Listening for minion connected event...')
|
||||
minion_start_event_match = 'salt/minion/{0}/start'.format(self.opts['id'])
|
||||
event_bus = salt.utils.event.get_master_event(self.opts, self.opts['sock_dir'], listen=True)
|
||||
event_bus.subscribe(minion_start_event_match)
|
||||
while True:
|
||||
event = event_bus.get_event(full=True, no_block=True)
|
||||
if event is not None and event['tag'] == minion_start_event_match:
|
||||
log.info('Got minion connected event: %s', event)
|
||||
break
|
||||
yield gen.sleep(0.25)
|
||||
|
||||
@gen.coroutine
|
||||
def fire_master_started_event(self):
|
||||
log.info('Firing salt-master started event...')
|
||||
|
|
|
@ -11,7 +11,7 @@ from tests.support.unit import skipIf
|
|||
import salt.utils.path
|
||||
import salt.utils.platform
|
||||
|
||||
URL = 'repo.saltstack.com'
|
||||
URL = 'google-public-dns-a.google.com'
|
||||
|
||||
|
||||
class NetworkTest(ModuleCase):
|
||||
|
|
|
@ -488,6 +488,33 @@ class GitPythonMixin(object):
|
|||
'nested_dict': {'dev': True}}}
|
||||
)
|
||||
|
||||
def test_all_saltenvs_base(self):
|
||||
'''
|
||||
Test all_saltenvs parameter with base pillarenv.
|
||||
'''
|
||||
ret = self.get_pillar('''\
|
||||
file_ignore_regex: []
|
||||
file_ignore_glob: []
|
||||
git_pillar_provider: gitpython
|
||||
cachedir: {cachedir}
|
||||
extension_modules: {extmods}
|
||||
ext_pillar:
|
||||
- git:
|
||||
- __env__ {url_extra_repo}:
|
||||
- all_saltenvs: master
|
||||
- __env__ {url}:
|
||||
- mountpoint: nowhere
|
||||
''')
|
||||
self.assertEqual(
|
||||
ret,
|
||||
{'branch': 'master',
|
||||
'motd': 'The force will be with you. Always.',
|
||||
'mylist': ['master'],
|
||||
'mydict': {'master': True,
|
||||
'nested_list': ['master'],
|
||||
'nested_dict': {'master': True}}}
|
||||
)
|
||||
|
||||
|
||||
@destructiveTest
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
|
@ -1742,6 +1769,103 @@ class TestPygit2SSH(GitPillarSSHTestBase):
|
|||
''')
|
||||
self.assertEqual(ret, expected)
|
||||
|
||||
@requires_system_grains
|
||||
def test_all_saltenvs_base(self, grains):
|
||||
'''
|
||||
Test all_saltenvs parameter.
|
||||
'''
|
||||
expected = {'branch': 'master',
|
||||
'motd': 'The force will be with you. Always.',
|
||||
'mylist': ['master'],
|
||||
'mydict': {'master': True,
|
||||
'nested_list': ['master'],
|
||||
'nested_dict': {'master': True}
|
||||
}
|
||||
}
|
||||
|
||||
# Test with passphraseless key and global credential options
|
||||
ret = self.get_pillar('''\
|
||||
file_ignore_regex: []
|
||||
file_ignore_glob: []
|
||||
git_pillar_provider: pygit2
|
||||
git_pillar_pubkey: {pubkey_nopass}
|
||||
git_pillar_privkey: {privkey_nopass}
|
||||
cachedir: {cachedir}
|
||||
extension_modules: {extmods}
|
||||
ext_pillar:
|
||||
- git:
|
||||
- __env__ {url_extra_repo}:
|
||||
- all_saltenvs: master
|
||||
- __env__ {url}:
|
||||
- mountpoint: nowhere
|
||||
''')
|
||||
self.assertEqual(ret, expected)
|
||||
|
||||
# Test with passphraseless key and per-repo credential options
|
||||
ret = self.get_pillar('''\
|
||||
file_ignore_regex: []
|
||||
file_ignore_glob: []
|
||||
git_pillar_provider: pygit2
|
||||
cachedir: {cachedir}
|
||||
extension_modules: {extmods}
|
||||
ext_pillar:
|
||||
- git:
|
||||
- __env__ {url_extra_repo}:
|
||||
- all_saltenvs: master
|
||||
- pubkey: {pubkey_nopass}
|
||||
- privkey: {privkey_nopass}
|
||||
- __env__ {url}:
|
||||
- mountpoint: nowhere
|
||||
- pubkey: {pubkey_nopass}
|
||||
- privkey: {privkey_nopass}
|
||||
''')
|
||||
self.assertEqual(ret, expected)
|
||||
|
||||
if grains['os_family'] == 'Debian':
|
||||
# passphrase-protected currently does not work here
|
||||
return
|
||||
|
||||
# Test with passphrase-protected key and global credential options
|
||||
ret = self.get_pillar('''\
|
||||
file_ignore_regex: []
|
||||
file_ignore_glob: []
|
||||
git_pillar_provider: pygit2
|
||||
git_pillar_pubkey: {pubkey_withpass}
|
||||
git_pillar_privkey: {privkey_withpass}
|
||||
git_pillar_passphrase: {passphrase}
|
||||
cachedir: {cachedir}
|
||||
extension_modules: {extmods}
|
||||
ext_pillar:
|
||||
- git:
|
||||
- __env__ {url_extra_repo}:
|
||||
- all_saltenvs: master
|
||||
- __env__ {url}:
|
||||
- mountpoint: nowhere
|
||||
''')
|
||||
self.assertEqual(ret, expected)
|
||||
|
||||
# Test with passphrase-protected key and per-repo credential options
|
||||
ret = self.get_pillar('''\
|
||||
file_ignore_regex: []
|
||||
file_ignore_glob: []
|
||||
git_pillar_provider: pygit2
|
||||
cachedir: {cachedir}
|
||||
extension_modules: {extmods}
|
||||
ext_pillar:
|
||||
- git:
|
||||
- __env__ {url_extra_repo}:
|
||||
- all_saltenvs: master
|
||||
- pubkey: {pubkey_nopass}
|
||||
- privkey: {privkey_nopass}
|
||||
- passphrase: {passphrase}
|
||||
- __env__ {url}:
|
||||
- mountpoint: nowhere
|
||||
- pubkey: {pubkey_nopass}
|
||||
- privkey: {privkey_nopass}
|
||||
- passphrase: {passphrase}
|
||||
''')
|
||||
self.assertEqual(ret, expected)
|
||||
|
||||
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
@skipIf(_windows_or_mac(), 'minion is windows or mac')
|
||||
|
@ -2119,6 +2243,33 @@ class TestPygit2HTTP(GitPillarHTTPTestBase):
|
|||
'nested_dict': {'dev': True}}}
|
||||
)
|
||||
|
||||
def test_all_saltenvs_base(self):
|
||||
'''
|
||||
Test all_saltenvs parameter with base pillarenv.
|
||||
'''
|
||||
ret = self.get_pillar('''\
|
||||
file_ignore_regex: []
|
||||
file_ignore_glob: []
|
||||
git_pillar_provider: pygit2
|
||||
cachedir: {cachedir}
|
||||
extension_modules: {extmods}
|
||||
ext_pillar:
|
||||
- git:
|
||||
- __env__ {url_extra_repo}:
|
||||
- all_saltenvs: master
|
||||
- __env__ {url}:
|
||||
- mountpoint: nowhere
|
||||
''')
|
||||
self.assertEqual(
|
||||
ret,
|
||||
{'branch': 'master',
|
||||
'motd': 'The force will be with you. Always.',
|
||||
'mylist': ['master'],
|
||||
'mydict': {'master': True,
|
||||
'nested_list': ['master'],
|
||||
'nested_dict': {'master': True}}}
|
||||
)
|
||||
|
||||
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
@skipIf(_windows_or_mac(), 'minion is windows or mac')
|
||||
|
@ -2719,3 +2870,33 @@ class TestPygit2AuthenticatedHTTP(GitPillarHTTPTestBase):
|
|||
'nested_list': ['dev'],
|
||||
'nested_dict': {'dev': True}}}
|
||||
)
|
||||
|
||||
def test_all_saltenvs_base(self):
|
||||
'''
|
||||
Test all_saltenvs parameter with base pillarenv.
|
||||
'''
|
||||
ret = self.get_pillar('''\
|
||||
file_ignore_regex: []
|
||||
file_ignore_glob: []
|
||||
git_pillar_provider: pygit2
|
||||
git_pillar_user: {user}
|
||||
git_pillar_password: {password}
|
||||
git_pillar_insecure_auth: True
|
||||
cachedir: {cachedir}
|
||||
extension_modules: {extmods}
|
||||
ext_pillar:
|
||||
- git:
|
||||
- __env__ {url_extra_repo}:
|
||||
- all_saltenvs: master
|
||||
- __env__ {url}:
|
||||
- mountpoint: nowhere
|
||||
''')
|
||||
self.assertEqual(
|
||||
ret,
|
||||
{'branch': 'master',
|
||||
'motd': 'The force will be with you. Always.',
|
||||
'mylist': ['master'],
|
||||
'mydict': {'master': True,
|
||||
'nested_list': ['master'],
|
||||
'nested_dict': {'master': True}}}
|
||||
)
|
||||
|
|
|
@ -35,4 +35,4 @@ class ReactorTest(ModuleCase, SaltMinionEventAssertsMixin):
|
|||
|
||||
e.fire_event({'a': 'b'}, '/test_event')
|
||||
|
||||
self.assertMinionEventReceived({'a': 'b'})
|
||||
self.assertMinionEventReceived({'a': 'b'}, timeout=30)
|
||||
|
|
|
@ -47,6 +47,7 @@ from salt._compat import ElementTree as etree
|
|||
# Import 3rd-party libs
|
||||
from salt.ext import six
|
||||
from salt.ext.six.moves import zip # pylint: disable=import-error,redefined-builtin
|
||||
from salt.ext.six.moves.queue import Empty # pylint: disable=import-error,no-name-in-module
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
@ -660,6 +661,14 @@ def _fetch_events(q):
|
|||
sock_dir=a_config.get_config('minion')['sock_dir'],
|
||||
opts=a_config.get_config('minion'),
|
||||
)
|
||||
|
||||
# Wait for event bus to be connected
|
||||
while not event.connect_pull(30):
|
||||
time.sleep(1)
|
||||
|
||||
# Notify parent process that the event bus is connected
|
||||
q.put('CONNECTED')
|
||||
|
||||
while True:
|
||||
try:
|
||||
events = event.get_event(full=False)
|
||||
|
@ -682,6 +691,11 @@ class SaltMinionEventAssertsMixin(object):
|
|||
target=_fetch_events, args=(cls.q,)
|
||||
)
|
||||
cls.fetch_proc.start()
|
||||
# Wait for the event bus to be connected
|
||||
msg = cls.q.get(block=True)
|
||||
if msg != 'CONNECTED':
|
||||
# Just in case something very bad happens
|
||||
raise RuntimeError('Unexpected message in test\'s event queue')
|
||||
return object.__new__(cls)
|
||||
|
||||
def __exit__(self, *args, **kwargs):
|
||||
|
@ -691,19 +705,22 @@ class SaltMinionEventAssertsMixin(object):
|
|||
#TODO
|
||||
raise salt.exceptions.NotImplemented('assertMinionEventFired() not implemented')
|
||||
|
||||
def assertMinionEventReceived(self, desired_event):
|
||||
queue_wait = 5 # 2.5s
|
||||
while self.q.empty():
|
||||
time.sleep(0.5) # Wait for events to be pushed into the queue
|
||||
queue_wait -= 1
|
||||
if queue_wait <= 0:
|
||||
raise AssertionError('Queue wait timer expired')
|
||||
while not self.q.empty(): # This is not thread-safe and may be inaccurate
|
||||
event = self.q.get()
|
||||
def assertMinionEventReceived(self, desired_event, timeout=5, sleep_time=0.5):
|
||||
start = time.time()
|
||||
while True:
|
||||
try:
|
||||
event = self.q.get(False)
|
||||
except Empty:
|
||||
time.sleep(sleep_time)
|
||||
if time.time() - start >= timeout:
|
||||
break
|
||||
continue
|
||||
if isinstance(event, dict):
|
||||
event.pop('_stamp')
|
||||
if desired_event == event:
|
||||
self.fetch_proc.terminate()
|
||||
return True
|
||||
if time.time() - start >= timeout:
|
||||
break
|
||||
self.fetch_proc.terminate()
|
||||
raise AssertionError('Event {0} was not received by minion'.format(desired_event))
|
||||
|
|
|
@ -506,7 +506,10 @@ class ConfigTestCase(TestCase):
|
|||
{'personal_access_token': 'foo'},
|
||||
Requirements.serialize()
|
||||
)
|
||||
self.assertIn('is not valid under any of the given schemas', excinfo.exception.message)
|
||||
if JSONSCHEMA_VERSION >= _LooseVersion('3.0.0'):
|
||||
self.assertIn('\'ssh_key_file\' is a required property', excinfo.exception.message)
|
||||
else:
|
||||
self.assertIn('is not valid under any of the given schemas', excinfo.exception.message)
|
||||
|
||||
def test_boolean_config(self):
|
||||
item = schema.BooleanItem(title='Hungry', description='Are you hungry?')
|
||||
|
@ -1730,7 +1733,10 @@ class ConfigTestCase(TestCase):
|
|||
|
||||
with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo:
|
||||
jsonschema.validate({'item': {'sides': '4', 'color': 'blue'}}, TestConf.serialize())
|
||||
self.assertIn('is not valid under any of the given schemas', excinfo.exception.message)
|
||||
if JSONSCHEMA_VERSION >= _LooseVersion('3.0.0'):
|
||||
self.assertIn('\'4\' is not of type \'boolean\'', excinfo.exception.message)
|
||||
else:
|
||||
self.assertIn('is not valid under any of the given schemas', excinfo.exception.message)
|
||||
|
||||
class TestConf(schema.Schema):
|
||||
item = schema.DictItem(
|
||||
|
@ -1833,7 +1839,10 @@ class ConfigTestCase(TestCase):
|
|||
|
||||
with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo:
|
||||
jsonschema.validate({'item': ['maybe']}, TestConf.serialize())
|
||||
self.assertIn('is not valid under any of the given schemas', excinfo.exception.message)
|
||||
if JSONSCHEMA_VERSION >= _LooseVersion('3.0.0'):
|
||||
self.assertIn('\'maybe\' is not one of [\'yes\']', excinfo.exception.message)
|
||||
else:
|
||||
self.assertIn('is not valid under any of the given schemas', excinfo.exception.message)
|
||||
|
||||
with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo:
|
||||
jsonschema.validate({'item': 2}, TestConf.serialize())
|
||||
|
@ -1885,7 +1894,10 @@ class ConfigTestCase(TestCase):
|
|||
|
||||
with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo:
|
||||
jsonschema.validate({'item': ['maybe']}, TestConf.serialize())
|
||||
self.assertIn('is not valid under any of the given schemas', excinfo.exception.message)
|
||||
if JSONSCHEMA_VERSION >= _LooseVersion('3.0.0'):
|
||||
self.assertIn('\'maybe\' is not one of [\'yes\']', excinfo.exception.message)
|
||||
else:
|
||||
self.assertIn('is not valid under any of the given schemas', excinfo.exception.message)
|
||||
|
||||
with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo:
|
||||
jsonschema.validate({'item': 2}, TestConf.serialize())
|
||||
|
|
Loading…
Add table
Reference in a new issue