New version of salt-formula from Saltstack
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. # -*- coding: utf-8 -*-
  2. '''
  3. HTTP monitoring states
  4. Perform an HTTP query and statefully return the result
  5. TODO: This is a copy of upstream state file: https://github.com/saltstack/salt/blob/2017.7.3/salt/states/http.py.
  6. It have to be removed when MCP Salt will be upgreaded up to 2017 or higher.
  7. .. versionadded:: 2015.5.0
  8. '''
  9. # Import python libs
  10. from __future__ import absolute_import
  11. import re
  12. import logging
  13. import time
  14. __monitor__ = [
  15. 'query',
  16. ]
  17. log = logging.getLogger(__name__)
  18. def query(name, match=None, match_type='string', status=None, wait_for=None, **kwargs):
  19. '''
  20. Perform an HTTP query and statefully return the result
  21. .. versionadded:: 2015.5.0
  22. name
  23. The name of the query.
  24. match
  25. Specifies a pattern to look for in the return text. By default, this will
  26. perform a string comparison of looking for the value of match in the return
  27. text.
  28. match_type
  29. Specifies the type of pattern matching to use. Default is ``string``, but
  30. can also be set to ``pcre`` to use regular expression matching if a more
  31. complex pattern matching is required.
  32. .. note::
  33. Despite the name of ``match_type`` for this argument, this setting
  34. actually uses Python's ``re.search()`` function rather than Python's
  35. ``re.match()`` function.
  36. status
  37. The status code for a URL for which to be checked. Can be used instead of
  38. or in addition to the ``match`` setting.
  39. If both ``match`` and ``status`` options are set, both settings will be checked.
  40. However, note that if only one option is ``True`` and the other is ``False``,
  41. then ``False`` will be returned. If this case is reached, the comments in the
  42. return data will contain troubleshooting information.
  43. For more information about the ``http.query`` state, refer to the
  44. :ref:`HTTP Tutorial <tutorial-http>`.
  45. .. code-block:: yaml
  46. query_example:
  47. http.query:
  48. - name: 'http://example.com/'
  49. - status: 200
  50. '''
  51. # Monitoring state, but changes may be made over HTTP
  52. ret = {'name': name,
  53. 'result': None,
  54. 'comment': '',
  55. 'changes': {},
  56. 'data': {}} # Data field for monitoring state
  57. if match is None and status is None:
  58. ret['result'] = False
  59. ret['comment'] += (
  60. ' Either match text (match) or a status code (status) is required.'
  61. )
  62. return ret
  63. if 'decode' not in kwargs:
  64. kwargs['decode'] = False
  65. kwargs['text'] = True
  66. kwargs['status'] = True
  67. if __opts__['test']:
  68. kwargs['test'] = True
  69. if wait_for:
  70. data = __salt__['http.wait_for_successful_query'](name, wait_for=wait_for, **kwargs)
  71. else:
  72. data = __salt__['http.query'](name, **kwargs)
  73. if match is not None:
  74. if match_type == 'string':
  75. if match in data.get('text', ''):
  76. ret['result'] = True
  77. ret['comment'] += ' Match text "{0}" was found.'.format(match)
  78. else:
  79. ret['result'] = False
  80. ret['comment'] += ' Match text "{0}" was not found.'.format(match)
  81. elif match_type == 'pcre':
  82. if re.search(match, data.get('text', '')):
  83. ret['result'] = True
  84. ret['comment'] += ' Match pattern "{0}" was found.'.format(match)
  85. else:
  86. ret['result'] = False
  87. ret['comment'] += ' Match pattern "{0}" was not found.'.format(match)
  88. if status is not None:
  89. if data.get('status', '') == status:
  90. ret['comment'] += 'Status {0} was found, as specified.'.format(status)
  91. if ret['result'] is None:
  92. ret['result'] = True
  93. else:
  94. ret['comment'] += 'Status {0} was not found, as specified.'.format(status)
  95. ret['result'] = False
  96. if __opts__['test'] is True:
  97. ret['result'] = None
  98. ret['comment'] += ' (TEST MODE'
  99. if 'test_url' in kwargs:
  100. ret['comment'] += ', TEST URL WAS: {0}'.format(kwargs['test_url'])
  101. ret['comment'] += ')'
  102. ret['data'] = data
  103. return ret
  104. def wait_for_successful_query(name, wait_for=300, **kwargs):
  105. '''
  106. Like query but, repeat and wait until match/match_type or status is fulfilled. State returns result from last
  107. query state in case of success or if no successful query was made within wait_for timeout.
  108. name
  109. The name of the query.
  110. wait_for
  111. Total time to wait for requests that succeed.
  112. request_interval
  113. Optional interval to delay requests by N seconds to reduce the number of requests sent.
  114. .. note::
  115. All other arguements are passed to the http.query state.
  116. '''
  117. starttime = time.time()
  118. while True:
  119. caught_exception = None
  120. ret = None
  121. try:
  122. ret = query(name, **kwargs)
  123. if ret['result']:
  124. return ret
  125. except Exception as exc:
  126. caught_exception = exc
  127. if time.time() > starttime + wait_for:
  128. if not ret and caught_exception:
  129. # workaround pylint bug https://www.logilab.org/ticket/3207
  130. raise caught_exception # pylint: disable=E0702
  131. return ret
  132. else:
  133. # Space requests out by delaying for an interval
  134. if 'request_interval' in kwargs:
  135. log.debug("delaying query for {0} seconds.".format(kwargs['request_interval']))
  136. time.sleep(kwargs['request_interval'])