|
|
@@ -0,0 +1,172 @@ |
|
|
|
# -*- coding: utf-8 -*- |
|
|
|
''' |
|
|
|
HTTP monitoring states |
|
|
|
|
|
|
|
Perform an HTTP query and statefully return the result |
|
|
|
|
|
|
|
TODO: This is a copy of upstream state file: https://github.com/saltstack/salt/blob/2017.7.3/salt/states/http.py. |
|
|
|
It have to be removed when MCP Salt will be upgreaded up to 2017 or higher. |
|
|
|
|
|
|
|
.. versionadded:: 2015.5.0 |
|
|
|
''' |
|
|
|
|
|
|
|
# Import python libs |
|
|
|
from __future__ import absolute_import |
|
|
|
import re |
|
|
|
import logging |
|
|
|
import time |
|
|
|
|
|
|
|
__monitor__ = [ |
|
|
|
'query', |
|
|
|
] |
|
|
|
|
|
|
|
log = logging.getLogger(__name__) |
|
|
|
|
|
|
|
|
|
|
|
def query(name, match=None, match_type='string', status=None, wait_for=None, **kwargs): |
|
|
|
''' |
|
|
|
Perform an HTTP query and statefully return the result |
|
|
|
|
|
|
|
.. versionadded:: 2015.5.0 |
|
|
|
|
|
|
|
name |
|
|
|
The name of the query. |
|
|
|
|
|
|
|
match |
|
|
|
Specifies a pattern to look for in the return text. By default, this will |
|
|
|
perform a string comparison of looking for the value of match in the return |
|
|
|
text. |
|
|
|
|
|
|
|
match_type |
|
|
|
Specifies the type of pattern matching to use. Default is ``string``, but |
|
|
|
can also be set to ``pcre`` to use regular expression matching if a more |
|
|
|
complex pattern matching is required. |
|
|
|
|
|
|
|
.. note:: |
|
|
|
|
|
|
|
Despite the name of ``match_type`` for this argument, this setting |
|
|
|
actually uses Python's ``re.search()`` function rather than Python's |
|
|
|
``re.match()`` function. |
|
|
|
|
|
|
|
status |
|
|
|
The status code for a URL for which to be checked. Can be used instead of |
|
|
|
or in addition to the ``match`` setting. |
|
|
|
|
|
|
|
If both ``match`` and ``status`` options are set, both settings will be checked. |
|
|
|
However, note that if only one option is ``True`` and the other is ``False``, |
|
|
|
then ``False`` will be returned. If this case is reached, the comments in the |
|
|
|
return data will contain troubleshooting information. |
|
|
|
|
|
|
|
For more information about the ``http.query`` state, refer to the |
|
|
|
:ref:`HTTP Tutorial <tutorial-http>`. |
|
|
|
|
|
|
|
.. code-block:: yaml |
|
|
|
|
|
|
|
query_example: |
|
|
|
http.query: |
|
|
|
- name: 'http://example.com/' |
|
|
|
- status: 200 |
|
|
|
|
|
|
|
''' |
|
|
|
# Monitoring state, but changes may be made over HTTP |
|
|
|
ret = {'name': name, |
|
|
|
'result': None, |
|
|
|
'comment': '', |
|
|
|
'changes': {}, |
|
|
|
'data': {}} # Data field for monitoring state |
|
|
|
|
|
|
|
if match is None and status is None: |
|
|
|
ret['result'] = False |
|
|
|
ret['comment'] += ( |
|
|
|
' Either match text (match) or a status code (status) is required.' |
|
|
|
) |
|
|
|
return ret |
|
|
|
|
|
|
|
if 'decode' not in kwargs: |
|
|
|
kwargs['decode'] = False |
|
|
|
kwargs['text'] = True |
|
|
|
kwargs['status'] = True |
|
|
|
if __opts__['test']: |
|
|
|
kwargs['test'] = True |
|
|
|
|
|
|
|
if wait_for: |
|
|
|
data = __salt__['http.wait_for_successful_query'](name, wait_for=wait_for, **kwargs) |
|
|
|
else: |
|
|
|
data = __salt__['http.query'](name, **kwargs) |
|
|
|
|
|
|
|
if match is not None: |
|
|
|
if match_type == 'string': |
|
|
|
if match in data.get('text', ''): |
|
|
|
ret['result'] = True |
|
|
|
ret['comment'] += ' Match text "{0}" was found.'.format(match) |
|
|
|
else: |
|
|
|
ret['result'] = False |
|
|
|
ret['comment'] += ' Match text "{0}" was not found.'.format(match) |
|
|
|
elif match_type == 'pcre': |
|
|
|
if re.search(match, data.get('text', '')): |
|
|
|
ret['result'] = True |
|
|
|
ret['comment'] += ' Match pattern "{0}" was found.'.format(match) |
|
|
|
else: |
|
|
|
ret['result'] = False |
|
|
|
ret['comment'] += ' Match pattern "{0}" was not found.'.format(match) |
|
|
|
|
|
|
|
if status is not None: |
|
|
|
if data.get('status', '') == status: |
|
|
|
ret['comment'] += 'Status {0} was found, as specified.'.format(status) |
|
|
|
if ret['result'] is None: |
|
|
|
ret['result'] = True |
|
|
|
else: |
|
|
|
ret['comment'] += 'Status {0} was not found, as specified.'.format(status) |
|
|
|
ret['result'] = False |
|
|
|
|
|
|
|
if __opts__['test'] is True: |
|
|
|
ret['result'] = None |
|
|
|
ret['comment'] += ' (TEST MODE' |
|
|
|
if 'test_url' in kwargs: |
|
|
|
ret['comment'] += ', TEST URL WAS: {0}'.format(kwargs['test_url']) |
|
|
|
ret['comment'] += ')' |
|
|
|
|
|
|
|
ret['data'] = data |
|
|
|
return ret |
|
|
|
|
|
|
|
|
|
|
|
def wait_for_successful_query(name, wait_for=300, **kwargs): |
|
|
|
''' |
|
|
|
Like query but, repeat and wait until match/match_type or status is fulfilled. State returns result from last |
|
|
|
query state in case of success or if no successful query was made within wait_for timeout. |
|
|
|
|
|
|
|
name |
|
|
|
The name of the query. |
|
|
|
|
|
|
|
wait_for |
|
|
|
Total time to wait for requests that succeed. |
|
|
|
|
|
|
|
request_interval |
|
|
|
Optional interval to delay requests by N seconds to reduce the number of requests sent. |
|
|
|
|
|
|
|
.. note:: |
|
|
|
|
|
|
|
All other arguements are passed to the http.query state. |
|
|
|
''' |
|
|
|
starttime = time.time() |
|
|
|
|
|
|
|
while True: |
|
|
|
caught_exception = None |
|
|
|
ret = None |
|
|
|
try: |
|
|
|
ret = query(name, **kwargs) |
|
|
|
if ret['result']: |
|
|
|
return ret |
|
|
|
except Exception as exc: |
|
|
|
caught_exception = exc |
|
|
|
|
|
|
|
if time.time() > starttime + wait_for: |
|
|
|
if not ret and caught_exception: |
|
|
|
# workaround pylint bug https://www.logilab.org/ticket/3207 |
|
|
|
raise caught_exception # pylint: disable=E0702 |
|
|
|
return ret |
|
|
|
else: |
|
|
|
# Space requests out by delaying for an interval |
|
|
|
if 'request_interval' in kwargs: |
|
|
|
log.debug("delaying query for {0} seconds.".format(kwargs['request_interval'])) |
|
|
|
time.sleep(kwargs['request_interval']) |