1
0

__init__.py 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. # -*- coding: utf-8 -*-
  2. '''
  3. Set up the Salt multimaster test suite
  4. '''
  5. # Import Python libs
  6. from __future__ import absolute_import, print_function
  7. import copy
  8. import logging
  9. import os
  10. import shutil
  11. import stat
  12. import sys
  13. import threading
  14. import time
  15. from collections import OrderedDict
  16. # Import salt tests support dirs
  17. from tests.support.paths import (
  18. ENGINES_DIR,
  19. FILES,
  20. INTEGRATION_TEST_DIR,
  21. LOG_HANDLERS_DIR,
  22. SCRIPT_DIR,
  23. TMP,
  24. )
  25. from tests.support.runtests import RUNTIME_VARS
  26. from tests.support.parser import PNUM, print_header
  27. from tests.support.processes import start_daemon
  28. # Import Salt libs
  29. from tests.integration import (
  30. SocketServerRequestHandler,
  31. TestDaemon,
  32. TestDaemonStartFailed,
  33. ThreadedSocketServer,
  34. get_unused_localhost_port,
  35. )
  36. import salt.config
  37. import salt.log.setup as salt_log_setup
  38. import salt.utils.path
  39. import salt.utils.platform
  40. from salt.utils.immutabletypes import freeze
  41. from salt.utils.verify import verify_env
  42. # Import salt tests support libs
  43. from tests.support.processes import SaltMaster, SaltMinion
  44. log = logging.getLogger(__name__)
  45. SALT_LOG_PORT = get_unused_localhost_port()
  46. class MultimasterTestDaemon(TestDaemon):
  47. '''
  48. Set up the master and minion daemons, and run related cases
  49. '''
  50. def __enter__(self):
  51. '''
  52. Start a master and minion
  53. '''
  54. # Setup the multiprocessing logging queue listener
  55. salt_log_setup.setup_multiprocessing_logging_listener(
  56. self.mm_master_opts
  57. )
  58. # Set up PATH to mockbin
  59. self._enter_mockbin()
  60. self.master_targets = [self.mm_master_opts, self.mm_sub_master_opts]
  61. self.minion_targets = set(['mm-minion', 'mm-sub-minion'])
  62. if self.parser.options.transport == 'zeromq':
  63. self.start_zeromq_daemons()
  64. elif self.parser.options.transport == 'raet':
  65. self.start_raet_daemons()
  66. elif self.parser.options.transport == 'tcp':
  67. self.start_tcp_daemons()
  68. self.pre_setup_minions()
  69. self.setup_minions()
  70. #if getattr(self.parser.options, 'ssh', False):
  71. #self.prep_ssh()
  72. self.wait_for_minions(time.time(), self.MINIONS_CONNECT_TIMEOUT)
  73. if self.parser.options.sysinfo:
  74. try:
  75. print_header(
  76. '~~~~~~~ Versions Report ', inline=True,
  77. width=getattr(self.parser.options, 'output_columns', PNUM)
  78. )
  79. except TypeError:
  80. print_header('~~~~~~~ Versions Report ', inline=True)
  81. print('\n'.join(salt.version.versions_report()))
  82. try:
  83. print_header(
  84. '~~~~~~~ Minion Grains Information ', inline=True,
  85. width=getattr(self.parser.options, 'output_columns', PNUM)
  86. )
  87. except TypeError:
  88. print_header('~~~~~~~ Minion Grains Information ', inline=True)
  89. grains = self.client.cmd('minion', 'grains.items')
  90. minion_opts = self.mm_minion_opts.copy()
  91. minion_opts['color'] = self.parser.options.no_colors is False
  92. salt.output.display_output(grains, 'grains', minion_opts)
  93. try:
  94. print_header(
  95. '=', sep='=', inline=True,
  96. width=getattr(self.parser.options, 'output_columns', PNUM)
  97. )
  98. except TypeError:
  99. print_header('', sep='=', inline=True)
  100. try:
  101. return self
  102. finally:
  103. self.post_setup_minions()
  104. def __exit__(self, type, value, traceback):
  105. '''
  106. Kill the minion and master processes
  107. '''
  108. try:
  109. if hasattr(self.sub_minion_process, 'terminate'):
  110. self.sub_minion_process.terminate()
  111. else:
  112. log.error('self.sub_minion_process can\'t be terminate.')
  113. except AttributeError:
  114. pass
  115. try:
  116. if hasattr(self.minion_process, 'terminate'):
  117. self.minion_process.terminate()
  118. else:
  119. log.error('self.minion_process can\'t be terminate.')
  120. except AttributeError:
  121. pass
  122. try:
  123. if hasattr(self.sub_master_process, 'terminate'):
  124. self.sub_master_process.terminate()
  125. else:
  126. log.error('self.sub_master_process can\'t be terminate.')
  127. except AttributeError:
  128. pass
  129. try:
  130. if hasattr(self.master_process, 'terminate'):
  131. self.master_process.terminate()
  132. else:
  133. log.error('self.master_process can\'t be terminate.')
  134. except AttributeError:
  135. pass
  136. self._exit_mockbin()
  137. self._exit_ssh()
  138. # Shutdown the multiprocessing logging queue listener
  139. salt_log_setup.shutdown_multiprocessing_logging()
  140. salt_log_setup.shutdown_multiprocessing_logging_listener(daemonizing=True)
  141. # Shutdown the log server
  142. self.log_server.shutdown()
  143. self.log_server.server_close()
  144. self.log_server_process.join()
  145. def start_zeromq_daemons(self):
  146. '''
  147. Fire up the daemons used for zeromq tests
  148. '''
  149. self.log_server = ThreadedSocketServer(('localhost', SALT_LOG_PORT), SocketServerRequestHandler)
  150. self.log_server_process = threading.Thread(target=self.log_server.serve_forever)
  151. self.log_server_process.start()
  152. try:
  153. sys.stdout.write(
  154. ' * {LIGHT_YELLOW}Starting salt-master ... {ENDC}'.format(**self.colors)
  155. )
  156. sys.stdout.flush()
  157. self.master_process = start_daemon(
  158. daemon_name='salt-master',
  159. daemon_id=self.mm_master_opts['id'],
  160. daemon_log_prefix='salt-master/{}'.format(self.mm_master_opts['id']),
  161. daemon_cli_script_name='master',
  162. daemon_config=self.mm_master_opts,
  163. daemon_config_dir=RUNTIME_VARS.TMP_MM_CONF_DIR,
  164. daemon_class=SaltMaster,
  165. bin_dir_path=SCRIPT_DIR,
  166. fail_hard=True,
  167. start_timeout=120)
  168. sys.stdout.write(
  169. '\r{0}\r'.format(
  170. ' ' * getattr(self.parser.options, 'output_columns', PNUM)
  171. )
  172. )
  173. sys.stdout.write(
  174. ' * {LIGHT_GREEN}Starting salt-master ... STARTED!\n{ENDC}'.format(**self.colors)
  175. )
  176. sys.stdout.flush()
  177. except (RuntimeWarning, RuntimeError):
  178. sys.stdout.write(
  179. '\r{0}\r'.format(
  180. ' ' * getattr(self.parser.options, 'output_columns', PNUM)
  181. )
  182. )
  183. sys.stdout.write(
  184. ' * {LIGHT_RED}Starting salt-master ... FAILED!\n{ENDC}'.format(**self.colors)
  185. )
  186. sys.stdout.flush()
  187. raise TestDaemonStartFailed()
  188. # Clone the master key to sub-master's pki dir
  189. for keyfile in ('master.pem', 'master.pub'):
  190. shutil.copyfile(
  191. os.path.join(self.mm_master_opts['pki_dir'], keyfile),
  192. os.path.join(self.mm_sub_master_opts['pki_dir'], keyfile)
  193. )
  194. try:
  195. sys.stdout.write(
  196. ' * {LIGHT_YELLOW}Starting second salt-master ... {ENDC}'.format(**self.colors)
  197. )
  198. sys.stdout.flush()
  199. self.sub_master_process = start_daemon(
  200. daemon_name='sub salt-master',
  201. daemon_id=self.mm_master_opts['id'],
  202. daemon_log_prefix='sub-salt-master/{}'.format(self.mm_sub_master_opts['id']),
  203. daemon_cli_script_name='master',
  204. daemon_config=self.mm_sub_master_opts,
  205. daemon_config_dir=RUNTIME_VARS.TMP_MM_SUB_CONF_DIR,
  206. daemon_class=SaltMaster,
  207. bin_dir_path=SCRIPT_DIR,
  208. fail_hard=True,
  209. start_timeout=120)
  210. sys.stdout.write(
  211. '\r{0}\r'.format(
  212. ' ' * getattr(self.parser.options, 'output_columns', PNUM)
  213. )
  214. )
  215. sys.stdout.write(
  216. ' * {LIGHT_GREEN}Starting second salt-master ... STARTED!\n{ENDC}'.format(**self.colors)
  217. )
  218. sys.stdout.flush()
  219. except (RuntimeWarning, RuntimeError):
  220. sys.stdout.write(
  221. '\r{0}\r'.format(
  222. ' ' * getattr(self.parser.options, 'output_columns', PNUM)
  223. )
  224. )
  225. sys.stdout.write(
  226. ' * {LIGHT_RED}Starting second salt-master ... FAILED!\n{ENDC}'.format(**self.colors)
  227. )
  228. sys.stdout.flush()
  229. raise TestDaemonStartFailed()
  230. try:
  231. sys.stdout.write(
  232. ' * {LIGHT_YELLOW}Starting salt-minion ... {ENDC}'.format(**self.colors)
  233. )
  234. sys.stdout.flush()
  235. self.minion_process = start_daemon(
  236. daemon_name='salt-minion',
  237. daemon_id=self.mm_master_opts['id'],
  238. daemon_log_prefix='salt-minion/{}'.format(self.mm_minion_opts['id']),
  239. daemon_cli_script_name='minion',
  240. daemon_config=self.mm_minion_opts,
  241. daemon_config_dir=RUNTIME_VARS.TMP_MM_CONF_DIR,
  242. daemon_class=SaltMinion,
  243. bin_dir_path=SCRIPT_DIR,
  244. fail_hard=True,
  245. start_timeout=120)
  246. sys.stdout.write(
  247. '\r{0}\r'.format(
  248. ' ' * getattr(self.parser.options, 'output_columns', PNUM)
  249. )
  250. )
  251. sys.stdout.write(
  252. ' * {LIGHT_GREEN}Starting salt-minion ... STARTED!\n{ENDC}'.format(**self.colors)
  253. )
  254. sys.stdout.flush()
  255. except (RuntimeWarning, RuntimeError):
  256. sys.stdout.write(
  257. '\r{0}\r'.format(
  258. ' ' * getattr(self.parser.options, 'output_columns', PNUM)
  259. )
  260. )
  261. sys.stdout.write(
  262. ' * {LIGHT_RED}Starting salt-minion ... FAILED!\n{ENDC}'.format(**self.colors)
  263. )
  264. sys.stdout.flush()
  265. raise TestDaemonStartFailed()
  266. try:
  267. sys.stdout.write(
  268. ' * {LIGHT_YELLOW}Starting sub salt-minion ... {ENDC}'.format(**self.colors)
  269. )
  270. sys.stdout.flush()
  271. self.sub_minion_process = start_daemon(
  272. daemon_name='sub salt-minion',
  273. daemon_id=self.mm_master_opts['id'],
  274. daemon_log_prefix='sub-salt-minion/{}'.format(self.mm_sub_minion_opts['id']),
  275. daemon_cli_script_name='minion',
  276. daemon_config=self.mm_sub_minion_opts,
  277. daemon_config_dir=RUNTIME_VARS.TMP_MM_SUB_CONF_DIR,
  278. daemon_class=SaltMinion,
  279. bin_dir_path=SCRIPT_DIR,
  280. fail_hard=True,
  281. start_timeout=120)
  282. sys.stdout.write(
  283. '\r{0}\r'.format(
  284. ' ' * getattr(self.parser.options, 'output_columns', PNUM)
  285. )
  286. )
  287. sys.stdout.write(
  288. ' * {LIGHT_GREEN}Starting sub salt-minion ... STARTED!\n{ENDC}'.format(**self.colors)
  289. )
  290. sys.stdout.flush()
  291. except (RuntimeWarning, RuntimeError):
  292. sys.stdout.write(
  293. '\r{0}\r'.format(
  294. ' ' * getattr(self.parser.options, 'output_columns', PNUM)
  295. )
  296. )
  297. sys.stdout.write(
  298. ' * {LIGHT_RED}Starting sub salt-minion ... FAILED!\n{ENDC}'.format(**self.colors)
  299. )
  300. sys.stdout.flush()
  301. raise TestDaemonStartFailed()
  302. start_tcp_daemons = start_zeromq_daemons
  303. def wait_for_minions(self, start, timeout, sleep=5):
  304. '''
  305. Ensure all minions and masters (including sub-masters) are connected.
  306. '''
  307. success = [False] * len(self.master_targets)
  308. while True:
  309. for num, client in enumerate(self.clients):
  310. if success[num]:
  311. continue
  312. try:
  313. ret = self.client.run_job('*', 'test.ping')
  314. except salt.exceptions.SaltClientError:
  315. ret = None
  316. if ret and 'minions' not in ret:
  317. continue
  318. if ret and sorted(ret['minions']) == sorted(self.minion_targets):
  319. success[num] = True
  320. continue
  321. if all(success):
  322. break
  323. if time.time() - start >= timeout:
  324. raise RuntimeError("Ping Minions Failed")
  325. time.sleep(sleep)
  326. @property
  327. def clients(self):
  328. '''
  329. Return a local client which will be used for example to ping and sync
  330. the test minions.
  331. This client is defined as a class attribute because its creation needs
  332. to be deferred to a latter stage. If created it on `__enter__` like it
  333. previously was, it would not receive the master events.
  334. '''
  335. if 'runtime_clients' not in RUNTIME_VARS.RUNTIME_CONFIGS:
  336. RUNTIME_VARS.RUNTIME_CONFIGS['runtime_clients'] = OrderedDict()
  337. runtime_clients = RUNTIME_VARS.RUNTIME_CONFIGS['runtime_clients']
  338. for mopts in self.master_targets:
  339. if mopts['id'] in runtime_clients:
  340. continue
  341. runtime_clients[mopts['id']] = salt.client.get_local_client(mopts=mopts)
  342. return runtime_clients
  343. @property
  344. def client(self):
  345. return self.clients['mm-master']
  346. @classmethod
  347. def transplant_configs(cls, transport='zeromq'):
  348. os.makedirs(RUNTIME_VARS.TMP_MM_CONF_DIR)
  349. os.makedirs(RUNTIME_VARS.TMP_MM_SUB_CONF_DIR)
  350. print(' * Transplanting multimaster configuration files to \'{0}\''.format(
  351. RUNTIME_VARS.TMP_CONF_DIR))
  352. tests_known_hosts_file = os.path.join(RUNTIME_VARS.TMP_CONF_DIR, 'salt_ssh_known_hosts')
  353. # Primary master in multimaster environment
  354. master_opts = salt.config._read_conf_file(os.path.join(RUNTIME_VARS.CONF_DIR, 'master'))
  355. master_opts.update(salt.config._read_conf_file(os.path.join(RUNTIME_VARS.CONF_DIR,
  356. 'mm_master')))
  357. master_opts['known_hosts_file'] = tests_known_hosts_file
  358. master_opts['cachedir'] = 'cache'
  359. master_opts['user'] = RUNTIME_VARS.RUNNING_TESTS_USER
  360. master_opts['config_dir'] = RUNTIME_VARS.TMP_MM_CONF_DIR
  361. master_opts['root_dir'] = os.path.join(TMP, 'rootdir-multimaster')
  362. master_opts['pki_dir'] = 'pki'
  363. file_tree = {
  364. 'root_dir': os.path.join(FILES, 'pillar', 'base', 'file_tree'),
  365. 'follow_dir_links': False,
  366. 'keep_newline': True,
  367. }
  368. master_opts['ext_pillar'].append({'file_tree': file_tree})
  369. # Secondary master in multimaster environment
  370. sub_master_opts = salt.config._read_conf_file(os.path.join(RUNTIME_VARS.CONF_DIR, 'master'))
  371. sub_master_opts.update(salt.config._read_conf_file(os.path.join(RUNTIME_VARS.CONF_DIR,
  372. 'mm_sub_master')))
  373. sub_master_opts['known_hosts_file'] = tests_known_hosts_file
  374. sub_master_opts['cachedir'] = 'cache'
  375. sub_master_opts['user'] = RUNTIME_VARS.RUNNING_TESTS_USER
  376. sub_master_opts['config_dir'] = RUNTIME_VARS.TMP_MM_SUB_CONF_DIR
  377. sub_master_opts['root_dir'] = os.path.join(TMP, 'rootdir-sub-multimaster')
  378. sub_master_opts['pki_dir'] = 'pki'
  379. sub_master_opts['ext_pillar'].append({'file_tree': copy.deepcopy(file_tree)})
  380. # Under windows we can't seem to properly create a virtualenv off of another
  381. # virtualenv, we can on linux but we will still point to the virtualenv binary
  382. # outside the virtualenv running the test suite, if that's the case.
  383. try:
  384. real_prefix = sys.real_prefix
  385. # The above attribute exists, this is a virtualenv
  386. if salt.utils.platform.is_windows():
  387. virtualenv_binary = os.path.join(real_prefix, 'Scripts', 'virtualenv.exe')
  388. else:
  389. # We need to remove the virtualenv from PATH or we'll get the virtualenv binary
  390. # from within the virtualenv, we don't want that
  391. path = os.environ.get('PATH')
  392. if path is not None:
  393. path_items = path.split(os.pathsep)
  394. for item in path_items[:]:
  395. if item.startswith(sys.base_prefix):
  396. path_items.remove(item)
  397. os.environ['PATH'] = os.pathsep.join(path_items)
  398. virtualenv_binary = salt.utils.path.which('virtualenv')
  399. if path is not None:
  400. # Restore previous environ PATH
  401. os.environ['PATH'] = path
  402. if not virtualenv_binary.startswith(real_prefix):
  403. virtualenv_binary = None
  404. if virtualenv_binary and not os.path.exists(virtualenv_binary):
  405. # It doesn't exist?!
  406. virtualenv_binary = None
  407. except AttributeError:
  408. # We're not running inside a virtualenv
  409. virtualenv_binary = None
  410. # This minion connects to both masters
  411. minion_opts = salt.config._read_conf_file(os.path.join(RUNTIME_VARS.CONF_DIR, 'minion'))
  412. minion_opts.update(salt.config._read_conf_file(os.path.join(RUNTIME_VARS.CONF_DIR,
  413. 'mm_minion')))
  414. minion_opts['cachedir'] = 'cache'
  415. minion_opts['user'] = RUNTIME_VARS.RUNNING_TESTS_USER
  416. minion_opts['config_dir'] = RUNTIME_VARS.TMP_MM_CONF_DIR
  417. minion_opts['root_dir'] = os.path.join(TMP, 'rootdir-multimaster')
  418. minion_opts['pki_dir'] = 'pki'
  419. minion_opts['hosts.file'] = os.path.join(TMP, 'rootdir', 'hosts')
  420. minion_opts['aliases.file'] = os.path.join(TMP, 'rootdir', 'aliases')
  421. if virtualenv_binary:
  422. minion_opts['venv_bin'] = virtualenv_binary
  423. # This sub_minion also connects to both masters
  424. sub_minion_opts = salt.config._read_conf_file(os.path.join(RUNTIME_VARS.CONF_DIR, 'sub_minion'))
  425. sub_minion_opts.update(salt.config._read_conf_file(os.path.join(RUNTIME_VARS.CONF_DIR,
  426. 'mm_sub_minion')))
  427. sub_minion_opts['cachedir'] = 'cache'
  428. sub_minion_opts['user'] = RUNTIME_VARS.RUNNING_TESTS_USER
  429. sub_minion_opts['config_dir'] = RUNTIME_VARS.TMP_MM_SUB_CONF_DIR
  430. sub_minion_opts['root_dir'] = os.path.join(TMP, 'rootdir-sub-multimaster')
  431. sub_minion_opts['pki_dir'] = 'pki'
  432. sub_minion_opts['hosts.file'] = os.path.join(TMP, 'rootdir', 'hosts')
  433. sub_minion_opts['aliases.file'] = os.path.join(TMP, 'rootdir', 'aliases')
  434. if virtualenv_binary:
  435. sub_minion_opts['venv_bin'] = virtualenv_binary
  436. if transport == 'raet':
  437. master_opts['transport'] = 'raet'
  438. master_opts['raet_port'] = 64506
  439. sub_master_opts['transport'] = 'raet'
  440. sub_master_opts['raet_port'] = 64556
  441. minion_opts['transport'] = 'raet'
  442. minion_opts['raet_port'] = 64510
  443. sub_minion_opts['transport'] = 'raet'
  444. sub_minion_opts['raet_port'] = 64520
  445. # syndic_master_opts['transport'] = 'raet'
  446. if transport == 'tcp':
  447. master_opts['transport'] = 'tcp'
  448. sub_master_opts['transport'] = 'tcp'
  449. minion_opts['transport'] = 'tcp'
  450. sub_minion_opts['transport'] = 'tcp'
  451. # Set up config options that require internal data
  452. master_opts['pillar_roots'] = sub_master_opts['pillar_roots'] = {
  453. 'base': [
  454. RUNTIME_VARS.TMP_PILLAR_TREE,
  455. os.path.join(FILES, 'pillar', 'base'),
  456. ]
  457. }
  458. minion_opts['pillar_roots'] = {
  459. 'base': [
  460. RUNTIME_VARS.TMP_PILLAR_TREE,
  461. os.path.join(FILES, 'pillar', 'base'),
  462. ]
  463. }
  464. master_opts['file_roots'] = sub_master_opts['file_roots'] = {
  465. 'base': [
  466. os.path.join(FILES, 'file', 'base'),
  467. # Let's support runtime created files that can be used like:
  468. # salt://my-temp-file.txt
  469. RUNTIME_VARS.TMP_STATE_TREE
  470. ],
  471. # Alternate root to test __env__ choices
  472. 'prod': [
  473. os.path.join(FILES, 'file', 'prod'),
  474. RUNTIME_VARS.TMP_PRODENV_STATE_TREE
  475. ]
  476. }
  477. minion_opts['file_roots'] = {
  478. 'base': [
  479. os.path.join(FILES, 'file', 'base'),
  480. # Let's support runtime created files that can be used like:
  481. # salt://my-temp-file.txt
  482. RUNTIME_VARS.TMP_STATE_TREE
  483. ],
  484. # Alternate root to test __env__ choices
  485. 'prod': [
  486. os.path.join(FILES, 'file', 'prod'),
  487. RUNTIME_VARS.TMP_PRODENV_STATE_TREE
  488. ]
  489. }
  490. master_opts.setdefault('reactor', []).append(
  491. {
  492. 'salt/minion/*/start': [
  493. os.path.join(FILES, 'reactor-sync-minion.sls')
  494. ],
  495. }
  496. )
  497. for opts_dict in (master_opts, sub_master_opts):
  498. if 'ext_pillar' not in opts_dict:
  499. opts_dict['ext_pillar'] = []
  500. if salt.utils.platform.is_windows():
  501. opts_dict['ext_pillar'].append(
  502. {'cmd_yaml': 'type {0}'.format(os.path.join(FILES, 'ext.yaml'))})
  503. else:
  504. opts_dict['ext_pillar'].append(
  505. {'cmd_yaml': 'cat {0}'.format(os.path.join(FILES, 'ext.yaml'))})
  506. # all read, only owner write
  507. autosign_file_permissions = stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH | stat.S_IWUSR
  508. for opts_dict in (master_opts, sub_master_opts):
  509. # We need to copy the extension modules into the new master root_dir or
  510. # it will be prefixed by it
  511. new_extension_modules_path = os.path.join(opts_dict['root_dir'], 'extension_modules')
  512. if not os.path.exists(new_extension_modules_path):
  513. shutil.copytree(
  514. os.path.join(
  515. INTEGRATION_TEST_DIR, 'files', 'extension_modules'
  516. ),
  517. new_extension_modules_path
  518. )
  519. opts_dict['extension_modules'] = os.path.join(opts_dict['root_dir'], 'extension_modules')
  520. # Copy the autosign_file to the new master root_dir
  521. new_autosign_file_path = os.path.join(opts_dict['root_dir'], 'autosign_file')
  522. shutil.copyfile(
  523. os.path.join(INTEGRATION_TEST_DIR, 'files', 'autosign_file'),
  524. new_autosign_file_path
  525. )
  526. os.chmod(new_autosign_file_path, autosign_file_permissions)
  527. # Point the config values to the correct temporary paths
  528. for name in ('hosts', 'aliases'):
  529. optname = '{0}.file'.format(name)
  530. optname_path = os.path.join(TMP, name)
  531. master_opts[optname] = optname_path
  532. sub_master_opts[optname] = optname_path
  533. minion_opts[optname] = optname_path
  534. sub_minion_opts[optname] = optname_path
  535. master_opts['runtests_conn_check_port'] = get_unused_localhost_port()
  536. sub_master_opts['runtests_conn_check_port'] = get_unused_localhost_port()
  537. minion_opts['runtests_conn_check_port'] = get_unused_localhost_port()
  538. sub_minion_opts['runtests_conn_check_port'] = get_unused_localhost_port()
  539. for conf in (master_opts, sub_master_opts, minion_opts, sub_minion_opts):
  540. if 'engines' not in conf:
  541. conf['engines'] = []
  542. conf['engines'].append({'salt_runtests': {}})
  543. if 'engines_dirs' not in conf:
  544. conf['engines_dirs'] = []
  545. conf['engines_dirs'].insert(0, ENGINES_DIR)
  546. if 'log_handlers_dirs' not in conf:
  547. conf['log_handlers_dirs'] = []
  548. conf['log_handlers_dirs'].insert(0, LOG_HANDLERS_DIR)
  549. conf['runtests_log_port'] = SALT_LOG_PORT
  550. conf['runtests_log_level'] = os.environ.get('TESTS_MIN_LOG_LEVEL_NAME') or 'debug'
  551. # ----- Transcribe Configuration ---------------------------------------------------------------------------->
  552. computed_config = copy.deepcopy(master_opts)
  553. with salt.utils.files.fopen(os.path.join(RUNTIME_VARS.TMP_MM_CONF_DIR, 'master'), 'w') as wfh:
  554. salt.utils.yaml.safe_dump(copy.deepcopy(master_opts), wfh, default_flow_style=False)
  555. with salt.utils.files.fopen(os.path.join(RUNTIME_VARS.TMP_MM_SUB_CONF_DIR, 'master'), 'w') as wfh:
  556. salt.utils.yaml.safe_dump(copy.deepcopy(sub_master_opts), wfh, default_flow_style=False)
  557. with salt.utils.files.fopen(os.path.join(RUNTIME_VARS.TMP_MM_CONF_DIR, 'minion'), 'w') as wfh:
  558. salt.utils.yaml.safe_dump(copy.deepcopy(minion_opts), wfh, default_flow_style=False)
  559. with salt.utils.files.fopen(os.path.join(RUNTIME_VARS.TMP_MM_SUB_CONF_DIR, 'minion'), 'w') as wfh:
  560. salt.utils.yaml.safe_dump(copy.deepcopy(sub_minion_opts), wfh, default_flow_style=False)
  561. # <---- Transcribe Configuration -----------------------------------------------------------------------------
  562. # ----- Verify Environment ---------------------------------------------------------------------------------->
  563. master_opts = salt.config.master_config(os.path.join(RUNTIME_VARS.TMP_MM_CONF_DIR, 'master'))
  564. sub_master_opts = salt.config.master_config(os.path.join(RUNTIME_VARS.TMP_MM_SUB_CONF_DIR, 'master'))
  565. minion_opts = salt.config.minion_config(os.path.join(RUNTIME_VARS.TMP_MM_CONF_DIR, 'minion'))
  566. sub_minion_opts = salt.config.minion_config(os.path.join(RUNTIME_VARS.TMP_MM_SUB_CONF_DIR, 'minion'))
  567. RUNTIME_VARS.RUNTIME_CONFIGS['mm_master'] = freeze(master_opts)
  568. RUNTIME_VARS.RUNTIME_CONFIGS['mm_sub_master'] = freeze(sub_master_opts)
  569. RUNTIME_VARS.RUNTIME_CONFIGS['mm_minion'] = freeze(minion_opts)
  570. RUNTIME_VARS.RUNTIME_CONFIGS['mm_sub_minion'] = freeze(sub_minion_opts)
  571. verify_env([os.path.join(master_opts['pki_dir'], 'minions'),
  572. os.path.join(master_opts['pki_dir'], 'minions_pre'),
  573. os.path.join(master_opts['pki_dir'], 'minions_rejected'),
  574. os.path.join(master_opts['pki_dir'], 'minions_denied'),
  575. os.path.join(master_opts['cachedir'], 'jobs'),
  576. os.path.join(master_opts['cachedir'], 'raet'),
  577. os.path.join(master_opts['root_dir'], 'cache', 'tokens'),
  578. os.path.join(master_opts['pki_dir'], 'accepted'),
  579. os.path.join(master_opts['pki_dir'], 'rejected'),
  580. os.path.join(master_opts['pki_dir'], 'pending'),
  581. os.path.join(master_opts['cachedir'], 'raet'),
  582. os.path.join(sub_master_opts['pki_dir'], 'minions'),
  583. os.path.join(sub_master_opts['pki_dir'], 'minions_pre'),
  584. os.path.join(sub_master_opts['pki_dir'], 'minions_rejected'),
  585. os.path.join(sub_master_opts['pki_dir'], 'minions_denied'),
  586. os.path.join(sub_master_opts['cachedir'], 'jobs'),
  587. os.path.join(sub_master_opts['cachedir'], 'raet'),
  588. os.path.join(sub_master_opts['root_dir'], 'cache', 'tokens'),
  589. os.path.join(sub_master_opts['pki_dir'], 'accepted'),
  590. os.path.join(sub_master_opts['pki_dir'], 'rejected'),
  591. os.path.join(sub_master_opts['pki_dir'], 'pending'),
  592. os.path.join(sub_master_opts['cachedir'], 'raet'),
  593. os.path.join(minion_opts['pki_dir'], 'accepted'),
  594. os.path.join(minion_opts['pki_dir'], 'rejected'),
  595. os.path.join(minion_opts['pki_dir'], 'pending'),
  596. os.path.join(minion_opts['cachedir'], 'raet'),
  597. os.path.join(sub_minion_opts['pki_dir'], 'accepted'),
  598. os.path.join(sub_minion_opts['pki_dir'], 'rejected'),
  599. os.path.join(sub_minion_opts['pki_dir'], 'pending'),
  600. os.path.join(sub_minion_opts['cachedir'], 'raet'),
  601. os.path.dirname(master_opts['log_file']),
  602. minion_opts['extension_modules'],
  603. sub_minion_opts['extension_modules'],
  604. sub_minion_opts['pki_dir'],
  605. master_opts['sock_dir'],
  606. sub_master_opts['sock_dir'],
  607. sub_minion_opts['sock_dir'],
  608. minion_opts['sock_dir'],
  609. ],
  610. RUNTIME_VARS.RUNNING_TESTS_USER,
  611. root_dir=master_opts['root_dir'],
  612. )
  613. cls.mm_master_opts = master_opts
  614. cls.mm_sub_master_opts = sub_master_opts
  615. cls.mm_minion_opts = minion_opts
  616. cls.mm_sub_minion_opts = sub_minion_opts
  617. # <---- Verify Environment -----------------------------------------------------------------------------------
  618. @classmethod
  619. def config_location(cls):
  620. return (RUNTIME_VARS.TMP_MM_CONF_DIR, RUNTIME_VARS.TMP_MM_SUB_CONF_DIR)