sminion.py 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. # -*- coding: utf-8 -*-
  2. '''
  3. tests.support.sminion
  4. ~~~~~~~~~~~~~~~~~~~~~
  5. SMinion's support functions
  6. '''
  7. # Import python libs
  8. from __future__ import absolute_import, print_function, unicode_literals
  9. import os
  10. import sys
  11. import shutil
  12. import hashlib
  13. import logging
  14. # Import salt libs
  15. import salt.minion
  16. import salt.utils.stringutils
  17. # Import testing libs
  18. from tests.support.runtests import RUNTIME_VARS
  19. log = logging.getLogger(__name__)
  20. def build_minion_opts(minion_id=None,
  21. root_dir=None,
  22. initial_conf_file=None,
  23. minion_opts_overrides=None,
  24. skip_cached_opts=False,
  25. cache_opts=True,
  26. minion_role=None):
  27. if minion_id is None:
  28. minion_id = 'pytest-internal-sminion'
  29. if skip_cached_opts is False:
  30. try:
  31. opts_cache = build_minion_opts.__cached_opts__
  32. except AttributeError:
  33. opts_cache = build_minion_opts.__cached_opts__ = {}
  34. cached_opts = opts_cache.get(minion_id)
  35. if cached_opts:
  36. return cached_opts
  37. log.info('Generating testing minion %r configuration...', minion_id)
  38. if root_dir is None:
  39. hashed_minion_id = hashlib.sha1()
  40. hashed_minion_id.update(salt.utils.stringutils.to_bytes(minion_id))
  41. root_dir = os.path.join(RUNTIME_VARS.TMP_ROOT_DIR, hashed_minion_id.hexdigest()[:6])
  42. if initial_conf_file is not None:
  43. minion_opts = salt.config._read_conf_file(initial_conf_file) # pylint: disable=protected-access
  44. else:
  45. minion_opts = {}
  46. conf_dir = os.path.join(root_dir, 'conf')
  47. conf_file = os.path.join(conf_dir, 'minion')
  48. minion_opts['id'] = minion_id
  49. minion_opts['conf_file'] = conf_file
  50. minion_opts['root_dir'] = root_dir
  51. minion_opts['cachedir'] = 'cache'
  52. minion_opts['user'] = RUNTIME_VARS.RUNNING_TESTS_USER
  53. minion_opts['pki_dir'] = 'pki'
  54. minion_opts['hosts.file'] = os.path.join(RUNTIME_VARS.TMP_ROOT_DIR, 'hosts')
  55. minion_opts['aliases.file'] = os.path.join(RUNTIME_VARS.TMP_ROOT_DIR, 'aliases')
  56. minion_opts['file_client'] = 'local'
  57. minion_opts['server_id_use_crc'] = 'adler32'
  58. minion_opts['pillar_roots'] = {
  59. 'base': [
  60. RUNTIME_VARS.TMP_PILLAR_TREE,
  61. ]
  62. }
  63. minion_opts['file_roots'] = {
  64. 'base': [
  65. # Let's support runtime created files that can be used like:
  66. # salt://my-temp-file.txt
  67. RUNTIME_VARS.TMP_STATE_TREE
  68. ],
  69. # Alternate root to test __env__ choices
  70. 'prod': [
  71. os.path.join(RUNTIME_VARS.FILES, 'file', 'prod'),
  72. RUNTIME_VARS.TMP_PRODENV_STATE_TREE
  73. ]
  74. }
  75. if initial_conf_file and initial_conf_file.startswith(RUNTIME_VARS.FILES):
  76. # We assume we were passed a minion configuration file defined fo testing and, as such
  77. # we define the file and pillar roots to include the testing states/pillar trees
  78. minion_opts['pillar_roots']['base'].append(
  79. os.path.join(RUNTIME_VARS.FILES, 'pillar', 'base'),
  80. )
  81. minion_opts['file_roots']['base'].append(
  82. os.path.join(RUNTIME_VARS.FILES, 'file', 'base'),
  83. )
  84. minion_opts['file_roots']['prod'].append(
  85. os.path.join(RUNTIME_VARS.FILES, 'file', 'prod'),
  86. )
  87. # We need to copy the extension modules into the new master root_dir or
  88. # it will be prefixed by it
  89. extension_modules_path = os.path.join(root_dir, 'extension_modules')
  90. if not os.path.exists(extension_modules_path):
  91. shutil.copytree(
  92. os.path.join(
  93. RUNTIME_VARS.FILES, 'extension_modules'
  94. ),
  95. extension_modules_path
  96. )
  97. minion_opts['extension_modules'] = extension_modules_path
  98. # Custom grains
  99. if 'grains' not in minion_opts:
  100. minion_opts['grains'] = {}
  101. if minion_role is not None:
  102. minion_opts['grains']['role'] = minion_role
  103. # Under windows we can't seem to properly create a virtualenv off of another
  104. # virtualenv, we can on linux but we will still point to the virtualenv binary
  105. # outside the virtualenv running the test suite, if that's the case.
  106. try:
  107. real_prefix = sys.real_prefix
  108. # The above attribute exists, this is a virtualenv
  109. if salt.utils.platform.is_windows():
  110. virtualenv_binary = os.path.join(real_prefix, 'Scripts', 'virtualenv.exe')
  111. else:
  112. # We need to remove the virtualenv from PATH or we'll get the virtualenv binary
  113. # from within the virtualenv, we don't want that
  114. path = os.environ.get('PATH')
  115. if path is not None:
  116. path_items = path.split(os.pathsep)
  117. for item in path_items[:]:
  118. if item.startswith(sys.base_prefix):
  119. path_items.remove(item)
  120. os.environ['PATH'] = os.pathsep.join(path_items)
  121. virtualenv_binary = salt.utils.which('virtualenv')
  122. if path is not None:
  123. # Restore previous environ PATH
  124. os.environ['PATH'] = path
  125. if not virtualenv_binary.startswith(real_prefix):
  126. virtualenv_binary = None
  127. if virtualenv_binary and not os.path.exists(virtualenv_binary):
  128. # It doesn't exist?!
  129. virtualenv_binary = None
  130. except AttributeError:
  131. # We're not running inside a virtualenv
  132. virtualenv_binary = None
  133. if virtualenv_binary:
  134. minion_opts['venv_bin'] = virtualenv_binary
  135. # Override minion_opts with minion_opts_overrides
  136. if minion_opts_overrides:
  137. minion_opts.update(minion_opts_overrides)
  138. if not os.path.exists(conf_dir):
  139. os.makedirs(conf_dir)
  140. with salt.utils.files.fopen(conf_file, 'w') as fp_:
  141. salt.utils.yaml.safe_dump(minion_opts, fp_, default_flow_style=False)
  142. log.info('Generating testing minion %r configuration completed.', minion_id)
  143. minion_opts = salt.config.minion_config(conf_file, minion_id=minion_id, cache_minion_id=True)
  144. salt.utils.verify.verify_env(
  145. [
  146. os.path.join(minion_opts['pki_dir'], 'accepted'),
  147. os.path.join(minion_opts['pki_dir'], 'rejected'),
  148. os.path.join(minion_opts['pki_dir'], 'pending'),
  149. os.path.dirname(minion_opts['log_file']),
  150. minion_opts['extension_modules'],
  151. minion_opts['cachedir'],
  152. minion_opts['sock_dir'],
  153. RUNTIME_VARS.TMP_STATE_TREE,
  154. RUNTIME_VARS.TMP_PILLAR_TREE,
  155. RUNTIME_VARS.TMP_PRODENV_STATE_TREE,
  156. RUNTIME_VARS.TMP,
  157. ],
  158. RUNTIME_VARS.RUNNING_TESTS_USER,
  159. root_dir=root_dir
  160. )
  161. if cache_opts:
  162. try:
  163. opts_cache = build_minion_opts.__cached_opts__
  164. except AttributeError:
  165. opts_cache = build_minion_opts.__cached_opts__ = {}
  166. opts_cache[minion_id] = minion_opts
  167. return minion_opts
  168. def create_sminion(minion_id=None,
  169. root_dir=None,
  170. initial_conf_file=None,
  171. sminion_cls=salt.minion.SMinion,
  172. minion_opts_overrides=None,
  173. skip_cached_minion=False,
  174. cache_sminion=True):
  175. if minion_id is None:
  176. minion_id = 'pytest-internal-sminion'
  177. if skip_cached_minion is False:
  178. try:
  179. minions_cache = create_sminion.__cached_minions__
  180. except AttributeError:
  181. create_sminion.__cached_minions__ = {}
  182. cached_minion = create_sminion.__cached_minions__.get(minion_id)
  183. if cached_minion:
  184. return cached_minion
  185. minion_opts = build_minion_opts(minion_id=minion_id,
  186. root_dir=root_dir,
  187. initial_conf_file=initial_conf_file,
  188. minion_opts_overrides=minion_opts_overrides,
  189. skip_cached_opts=skip_cached_minion,
  190. cache_opts=cache_sminion)
  191. log.info('Instantiating a testing %s(%s)', sminion_cls.__name__, minion_id)
  192. sminion = sminion_cls(minion_opts)
  193. if cache_sminion:
  194. try:
  195. minions_cache = create_sminion.__cached_minions__
  196. except AttributeError:
  197. minions_cache = create_sminion.__cached_minions__ = {}
  198. minions_cache[minion_id] = sminion
  199. return sminion