1
0

sminion.py 8.3 KB

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