File: //proc/self/root/usr/lib/python2.7/site-packages/salt/states/http.py
# -*- coding: utf-8 -*-
'''
HTTP monitoring states
Perform an HTTP query and statefully return the result
.. versionadded:: 2015.5.0
'''
# Import python libs
from __future__ import absolute_import, print_function, unicode_literals
import logging
import re
import time
__monitor__ = [
'query',
]
log = logging.getLogger(__name__)
def query(name, match=None, match_type='string', status=None, status_type='string', wait_for=None, **kwargs):
'''
Perform an HTTP query and statefully return the result
Passes through all the parameters described in the
:py:func:`utils.http.query function <salt.utils.http.query>`:
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 on match. 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. This can be passed as an individual status code
or a list of status codes.
status_type
Specifies the type of pattern matching to use for status. Default is ``string``, but
can also be set to ``pcre`` to use regular expression matching if a more
complex pattern matching is required. Additionally, if a list of strings representing
statuses is given, the type ``list`` can be used.
.. versionadded:: 3000
.. 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.
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
query_example2:
http.query:
- name: 'http://example.com/'
- status:
- 200
- 201
- status_type: list
'''
# 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 str(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(str(match), str(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:
# Deals with case of status_type as a list of strings representing statuses
if status_type == 'list':
for stat in status:
if str(data.get('status', '')) == str(stat):
ret['comment'] += ' Status {0} was found.'.format(stat)
if ret['result'] is None:
ret['result'] = True
if ret['result'] is not True:
ret['comment'] += ' Statuses {0} were not found.'.format(status)
ret['result'] = False
# Deals with the case of status_type representing a regex
elif status_type == 'pcre':
if re.search(str(status), str(data.get('status', ''))):
ret['comment'] += ' Status pattern "{0}" was found.'.format(status)
if ret['result'] is None:
ret['result'] = True
else:
ret['comment'] += ' Status pattern "{0}" was not found.'.format(status)
ret['result'] = False
# Deals with the case of status_type as a single string representing a status
elif status_type == 'string':
if str(data.get('status', '')) == str(status):
ret['comment'] += ' Status {0} was found.'.format(status)
if ret['result'] is None:
ret['result'] = True
else:
ret['comment'] += ' Status {0} was not found.'.format(status)
ret['result'] = False
# cleanup spaces in comment
ret['comment'] = ret['comment'].strip()
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 arguments 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: # pylint: disable=broad-except
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
elif 'request_interval' in kwargs:
# Space requests out by delaying for an interval
log.debug('delaying query for %s seconds.', kwargs['request_interval'])
time.sleep(kwargs['request_interval'])