__init__.py 30 KB

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