conftest.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. """
  2. tests.pytests.conftest
  3. ~~~~~~~~~~~~~~~~~~~~~~
  4. """
  5. import logging
  6. import os
  7. import shutil
  8. import stat
  9. import pytest
  10. import salt.utils.files
  11. import salt.utils.platform
  12. from salt.serializers import yaml
  13. from saltfactories.utils import random_string
  14. from saltfactories.utils.ports import get_unused_localhost_port
  15. from tests.support.helpers import get_virtualenv_binary_path
  16. from tests.support.runtests import RUNTIME_VARS
  17. log = logging.getLogger(__name__)
  18. @pytest.fixture(scope="session")
  19. def salt_minion_id():
  20. return random_string("minion-")
  21. @pytest.fixture(scope="session")
  22. def salt_sub_minion_id():
  23. return random_string("sub-minion-")
  24. @pytest.fixture(scope="session")
  25. def sdb_etcd_port():
  26. return get_unused_localhost_port()
  27. @pytest.fixture(scope="session")
  28. def vault_port():
  29. return get_unused_localhost_port()
  30. @pytest.fixture(scope="session")
  31. def salt_master_factory(
  32. request,
  33. salt_factories,
  34. salt_minion_id,
  35. salt_sub_minion_id,
  36. base_env_state_tree_root_dir,
  37. base_env_pillar_tree_root_dir,
  38. prod_env_state_tree_root_dir,
  39. prod_env_pillar_tree_root_dir,
  40. ext_pillar_file_tree_root_dir,
  41. sdb_etcd_port,
  42. vault_port,
  43. ):
  44. master_id = random_string("master-")
  45. root_dir = salt_factories.get_root_dir_for_daemon(master_id)
  46. conf_dir = root_dir / "conf"
  47. conf_dir.mkdir(exist_ok=True)
  48. with salt.utils.files.fopen(os.path.join(RUNTIME_VARS.CONF_DIR, "master")) as rfh:
  49. config_defaults = yaml.deserialize(rfh.read())
  50. tests_known_hosts_file = str(root_dir / "salt_ssh_known_hosts")
  51. with salt.utils.files.fopen(tests_known_hosts_file, "w") as known_hosts:
  52. known_hosts.write("")
  53. config_defaults["root_dir"] = str(root_dir)
  54. config_defaults["known_hosts_file"] = tests_known_hosts_file
  55. config_defaults["syndic_master"] = "localhost"
  56. config_defaults["transport"] = request.config.getoption("--transport")
  57. config_defaults["reactor"] = [
  58. {"salt/test/reactor": [os.path.join(RUNTIME_VARS.FILES, "reactor-test.sls")]}
  59. ]
  60. nodegroups = {
  61. "min": salt_minion_id,
  62. "sub_min": salt_sub_minion_id,
  63. "mins": "N@min or N@sub_min",
  64. "list_nodegroup": [salt_minion_id, salt_sub_minion_id],
  65. "multiline_nodegroup": [salt_minion_id, "or", salt_sub_minion_id],
  66. "one_minion_list": [salt_minion_id],
  67. "redundant_minions": "N@min or N@mins",
  68. "nodegroup_loop_a": "N@nodegroup_loop_b",
  69. "nodegroup_loop_b": "N@nodegroup_loop_a",
  70. "missing_minion": "L@{},ghostminion".format(salt_minion_id),
  71. "list_group": "N@multiline_nodegroup",
  72. "one_list_group": "N@one_minion_list",
  73. "list_group2": "N@list_nodegroup",
  74. }
  75. config_defaults["nodegroups"] = nodegroups
  76. config_defaults["sdbetcd"] = {
  77. "driver": "etcd",
  78. "etcd.host": "127.0.0.1",
  79. "etcd.port": sdb_etcd_port,
  80. }
  81. config_defaults["vault"] = {
  82. "url": "http://127.0.0.1:{}".format(vault_port),
  83. "auth": {"method": "token", "token": "testsecret", "uses": 0},
  84. "policies": ["testpolicy"],
  85. }
  86. config_overrides = {}
  87. ext_pillar = []
  88. if salt.utils.platform.is_windows():
  89. ext_pillar.append(
  90. {"cmd_yaml": "type {}".format(os.path.join(RUNTIME_VARS.FILES, "ext.yaml"))}
  91. )
  92. else:
  93. ext_pillar.append(
  94. {"cmd_yaml": "cat {}".format(os.path.join(RUNTIME_VARS.FILES, "ext.yaml"))}
  95. )
  96. ext_pillar.append(
  97. {
  98. "file_tree": {
  99. "root_dir": str(ext_pillar_file_tree_root_dir),
  100. "follow_dir_links": False,
  101. "keep_newline": True,
  102. }
  103. }
  104. )
  105. config_overrides["pillar_opts"] = True
  106. # We need to copy the extension modules into the new master root_dir or
  107. # it will be prefixed by it
  108. extension_modules_path = str(root_dir / "extension_modules")
  109. if not os.path.exists(extension_modules_path):
  110. shutil.copytree(
  111. os.path.join(RUNTIME_VARS.FILES, "extension_modules"),
  112. extension_modules_path,
  113. )
  114. # Copy the autosign_file to the new master root_dir
  115. autosign_file_path = str(root_dir / "autosign_file")
  116. shutil.copyfile(
  117. os.path.join(RUNTIME_VARS.FILES, "autosign_file"), autosign_file_path
  118. )
  119. # all read, only owner write
  120. autosign_file_permissions = (
  121. stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH | stat.S_IWUSR
  122. )
  123. os.chmod(autosign_file_path, autosign_file_permissions)
  124. config_overrides.update(
  125. {
  126. "ext_pillar": ext_pillar,
  127. "extension_modules": extension_modules_path,
  128. "file_roots": {
  129. "base": [
  130. str(base_env_state_tree_root_dir),
  131. os.path.join(RUNTIME_VARS.FILES, "file", "base"),
  132. ],
  133. # Alternate root to test __env__ choices
  134. "prod": [
  135. str(prod_env_state_tree_root_dir),
  136. os.path.join(RUNTIME_VARS.FILES, "file", "prod"),
  137. ],
  138. },
  139. "pillar_roots": {
  140. "base": [
  141. str(base_env_pillar_tree_root_dir),
  142. os.path.join(RUNTIME_VARS.FILES, "pillar", "base"),
  143. ],
  144. "prod": [str(prod_env_pillar_tree_root_dir)],
  145. },
  146. }
  147. )
  148. # Let's copy over the test cloud config files and directories into the running master config directory
  149. for entry in os.listdir(RUNTIME_VARS.CONF_DIR):
  150. if not entry.startswith("cloud"):
  151. continue
  152. source = os.path.join(RUNTIME_VARS.CONF_DIR, entry)
  153. dest = str(conf_dir / entry)
  154. if os.path.isdir(source):
  155. shutil.copytree(source, dest)
  156. else:
  157. shutil.copyfile(source, dest)
  158. factory = salt_factories.get_salt_master_daemon(
  159. master_id,
  160. config_defaults=config_defaults,
  161. config_overrides=config_overrides,
  162. extra_cli_arguments_after_first_start_failure=["--log-level=debug"],
  163. )
  164. return factory
  165. @pytest.fixture(scope="session")
  166. def salt_minion_factory(salt_master_factory, salt_minion_id, sdb_etcd_port, vault_port):
  167. with salt.utils.files.fopen(os.path.join(RUNTIME_VARS.CONF_DIR, "minion")) as rfh:
  168. config_defaults = yaml.deserialize(rfh.read())
  169. config_defaults["hosts.file"] = os.path.join(RUNTIME_VARS.TMP, "hosts")
  170. config_defaults["aliases.file"] = os.path.join(RUNTIME_VARS.TMP, "aliases")
  171. config_defaults["transport"] = salt_master_factory.config["transport"]
  172. config_defaults["sdbetcd"] = {
  173. "driver": "etcd",
  174. "etcd.host": "127.0.0.1",
  175. "etcd.port": sdb_etcd_port,
  176. }
  177. config_defaults["vault"] = {
  178. "url": "http://127.0.0.1:{}".format(vault_port),
  179. "auth": {"method": "token", "token": "testsecret", "uses": 0},
  180. "policies": ["testpolicy"],
  181. }
  182. config_overrides = {
  183. "file_roots": salt_master_factory.config["file_roots"].copy(),
  184. "pillar_roots": salt_master_factory.config["pillar_roots"].copy(),
  185. }
  186. virtualenv_binary = get_virtualenv_binary_path()
  187. if virtualenv_binary:
  188. config_overrides["venv_bin"] = virtualenv_binary
  189. factory = salt_master_factory.get_salt_minion_daemon(
  190. salt_minion_id,
  191. config_defaults=config_defaults,
  192. config_overrides=config_overrides,
  193. extra_cli_arguments_after_first_start_failure=["--log-level=debug"],
  194. )
  195. factory.register_after_terminate_callback(
  196. pytest.helpers.remove_stale_minion_key, salt_master_factory, factory.id
  197. )
  198. return factory
  199. @pytest.fixture(scope="session")
  200. def salt_sub_minion_factory(salt_master_factory, salt_sub_minion_id):
  201. with salt.utils.files.fopen(
  202. os.path.join(RUNTIME_VARS.CONF_DIR, "sub_minion")
  203. ) as rfh:
  204. config_defaults = yaml.deserialize(rfh.read())
  205. config_defaults["hosts.file"] = os.path.join(RUNTIME_VARS.TMP, "hosts")
  206. config_defaults["aliases.file"] = os.path.join(RUNTIME_VARS.TMP, "aliases")
  207. config_defaults["transport"] = salt_master_factory.config["transport"]
  208. config_overrides = {
  209. "file_roots": salt_master_factory.config["file_roots"].copy(),
  210. "pillar_roots": salt_master_factory.config["pillar_roots"].copy(),
  211. }
  212. virtualenv_binary = get_virtualenv_binary_path()
  213. if virtualenv_binary:
  214. config_overrides["venv_bin"] = virtualenv_binary
  215. factory = salt_master_factory.get_salt_minion_daemon(
  216. salt_sub_minion_id,
  217. config_defaults=config_defaults,
  218. config_overrides=config_overrides,
  219. extra_cli_arguments_after_first_start_failure=["--log-level=debug"],
  220. )
  221. factory.register_after_terminate_callback(
  222. pytest.helpers.remove_stale_minion_key, salt_master_factory, factory.id
  223. )
  224. return factory
  225. @pytest.fixture(scope="session")
  226. def salt_proxy_factory(salt_factories, salt_master_factory):
  227. proxy_minion_id = random_string("proxytest-")
  228. root_dir = salt_factories.get_root_dir_for_daemon(proxy_minion_id)
  229. conf_dir = root_dir / "conf"
  230. conf_dir.mkdir(parents=True, exist_ok=True)
  231. RUNTIME_VARS.TMP_PROXY_CONF_DIR = str(conf_dir)
  232. with salt.utils.files.fopen(os.path.join(RUNTIME_VARS.CONF_DIR, "proxy")) as rfh:
  233. config_defaults = yaml.deserialize(rfh.read())
  234. config_defaults["root_dir"] = str(root_dir)
  235. config_defaults["hosts.file"] = os.path.join(RUNTIME_VARS.TMP, "hosts")
  236. config_defaults["aliases.file"] = os.path.join(RUNTIME_VARS.TMP, "aliases")
  237. config_defaults["transport"] = salt_master_factory.config["transport"]
  238. config_defaults["user"] = salt_master_factory.config["user"]
  239. factory = salt_master_factory.get_salt_proxy_minion_daemon(
  240. proxy_minion_id,
  241. config_defaults=config_defaults,
  242. extra_cli_arguments_after_first_start_failure=["--log-level=debug"],
  243. start_timeout=240,
  244. )
  245. factory.register_after_terminate_callback(
  246. pytest.helpers.remove_stale_minion_key, salt_master_factory, factory.id
  247. )
  248. return factory
  249. @pytest.fixture(scope="session")
  250. def bridge_pytest_and_runtests():
  251. """
  252. We're basically overriding the same fixture defined in tests/conftest.py
  253. """