processes.py 6.3 KB

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