processes.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. # -*- coding: utf-8 -*-
  2. """
  3. :copyright: Copyright 2017 by the SaltStack Team, see AUTHORS for more details.
  4. :license: Apache 2.0, see LICENSE for more details.
  5. tests.support.processes
  6. ~~~~~~~~~~~~~~~~~~~~~~~
  7. Process handling utilities
  8. """
  9. from __future__ import absolute_import
  10. import logging
  11. from saltfactories.utils.processes.helpers import ( # pylint: disable=unused-import
  12. collect_child_processes,
  13. terminate_process,
  14. terminate_process_list,
  15. )
  16. from saltfactories.utils.processes.salts import SaltCallCLI as PytestSaltCall
  17. from saltfactories.utils.processes.salts import SaltCLI as PytestSalt
  18. from saltfactories.utils.processes.salts import SaltKeyCLI as PytestSaltKey
  19. from saltfactories.utils.processes.salts import SaltMaster as PytestSaltMaster
  20. from saltfactories.utils.processes.salts import SaltMinion as PytestSaltMinion
  21. from saltfactories.utils.processes.salts import SaltProxyMinion as PytestSaltProxy
  22. from saltfactories.utils.processes.salts import SaltRunCLI as PytestSaltRun
  23. from saltfactories.utils.processes.salts import SaltSyndic as PytestSaltSyndic
  24. from tests.support.cli_scripts import ScriptPathMixin
  25. log = logging.getLogger(__name__)
  26. class GetSaltRunFixtureMixin(ScriptPathMixin):
  27. """
  28. Override this classes `get_salt_run_fixture` because we're still not running under pytest
  29. """
  30. def get_salt_run_fixture(self):
  31. pass
  32. class Salt(ScriptPathMixin, PytestSalt):
  33. """
  34. Class which runs salt-call commands
  35. """
  36. def __init__(self, *args, **kwargs):
  37. super(Salt, self).__init__(None, *args, **kwargs)
  38. class SaltCall(ScriptPathMixin, PytestSaltCall):
  39. """
  40. Class which runs salt-call commands
  41. """
  42. def __init__(self, *args, **kwargs):
  43. super(SaltCall, self).__init__(None, *args, **kwargs)
  44. class SaltKey(ScriptPathMixin, PytestSaltKey):
  45. """
  46. Class which runs salt-key commands
  47. """
  48. def __init__(self, *args, **kwargs):
  49. super(SaltKey, self).__init__(None, *args, **kwargs)
  50. class SaltRun(ScriptPathMixin, PytestSaltRun):
  51. """
  52. Class which runs salt-run commands
  53. """
  54. def __init__(self, *args, **kwargs):
  55. super(SaltRun, self).__init__(None, *args, **kwargs)
  56. class SaltProxy(GetSaltRunFixtureMixin, PytestSaltProxy):
  57. """
  58. Class which runs the salt-proxy daemon
  59. """
  60. class SaltMinion(GetSaltRunFixtureMixin, PytestSaltMinion):
  61. """
  62. Class which runs the salt-minion daemon
  63. """
  64. class SaltMaster(GetSaltRunFixtureMixin, PytestSaltMaster):
  65. """
  66. Class which runs the salt-master daemon
  67. """
  68. class SaltSyndic(GetSaltRunFixtureMixin, PytestSaltSyndic):
  69. """
  70. Class which runs the salt-syndic daemon
  71. """
  72. def start_daemon(
  73. daemon_name=None,
  74. daemon_id=None,
  75. daemon_log_prefix=None,
  76. daemon_cli_script_name=None,
  77. daemon_config=None,
  78. daemon_config_dir=None,
  79. daemon_class=None,
  80. bin_dir_path=None,
  81. fail_hard=False,
  82. start_timeout=10,
  83. slow_stop=False,
  84. environ=None,
  85. cwd=None,
  86. event_listener_config_dir=None,
  87. ):
  88. """
  89. Returns a running salt daemon
  90. """
  91. # Old config name
  92. daemon_config["pytest_port"] = daemon_config["runtests_conn_check_port"]
  93. # New config name
  94. daemon_config["pytest_engine_port"] = daemon_config["runtests_conn_check_port"]
  95. request = None
  96. if fail_hard:
  97. fail_method = RuntimeError
  98. else:
  99. fail_method = RuntimeWarning
  100. log.info("[%s] Starting pytest %s(%s)", daemon_name, daemon_log_prefix, daemon_id)
  101. attempts = 0
  102. process = None
  103. while attempts <= 3: # pylint: disable=too-many-nested-blocks
  104. attempts += 1
  105. try:
  106. process = daemon_class(
  107. request=request,
  108. config=daemon_config,
  109. config_dir=daemon_config_dir,
  110. bin_dir_path=bin_dir_path,
  111. log_prefix=daemon_log_prefix,
  112. cli_script_name=daemon_cli_script_name,
  113. slow_stop=slow_stop,
  114. environ=environ,
  115. cwd=cwd,
  116. event_listener_config_dir=event_listener_config_dir,
  117. )
  118. except TypeError:
  119. process = daemon_class(
  120. request=request,
  121. config=daemon_config,
  122. config_dir=daemon_config_dir,
  123. bin_dir_path=bin_dir_path,
  124. log_prefix=daemon_log_prefix,
  125. cli_script_name=daemon_cli_script_name,
  126. slow_stop=slow_stop,
  127. environ=environ,
  128. cwd=cwd,
  129. )
  130. process.start()
  131. if process.is_alive():
  132. try:
  133. connectable = process.wait_until_running(timeout=start_timeout)
  134. if connectable is False:
  135. connectable = process.wait_until_running(timeout=start_timeout / 2)
  136. if connectable is False:
  137. process.terminate()
  138. if attempts >= 3:
  139. fail_method(
  140. "The pytest {0}({1}) has failed to confirm running status "
  141. "after {2} attempts".format(
  142. daemon_name, daemon_id, attempts
  143. )
  144. )
  145. continue
  146. except Exception as exc: # pylint: disable=broad-except
  147. log.exception("[%s] %s", daemon_log_prefix, exc, exc_info=True)
  148. terminate_process(process.pid, kill_children=True, slow_stop=slow_stop)
  149. if attempts >= 3:
  150. raise fail_method(str(exc))
  151. continue
  152. log.info(
  153. "[%s] The pytest %s(%s) is running and accepting commands "
  154. "after %d attempts",
  155. daemon_log_prefix,
  156. daemon_name,
  157. daemon_id,
  158. attempts,
  159. )
  160. break
  161. else:
  162. terminate_process(process.pid, kill_children=True, slow_stop=slow_stop)
  163. continue
  164. else:
  165. if process is not None:
  166. terminate_process(process.pid, kill_children=True, slow_stop=slow_stop)
  167. raise fail_method(
  168. "The pytest {0}({1}) has failed to start after {2} attempts".format(
  169. daemon_name, daemon_id, attempts - 1
  170. )
  171. )
  172. return process