blob: a539ec0d0b9e3b93fd8f95853bde95fc5388d8f4 [file] [log] [blame]
# -*- 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'])