__init__.py 30 KB

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