http.rst 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. .. _tutorial-http:
  2. HTTP Modules
  3. ============
  4. This tutorial demonstrates using the various HTTP modules available in Salt.
  5. These modules wrap the Python ``tornado``, ``urllib2``, and ``requests``
  6. libraries, extending them in a manner that is more consistent with Salt
  7. workflows.
  8. The ``salt.utils.http`` Library
  9. -------------------------------
  10. This library forms the core of the HTTP modules. Since it is designed to be used
  11. from the minion as an execution module, in addition to the master as a runner,
  12. it was abstracted into this multi-use library. This library can also be imported
  13. by 3rd-party programs wishing to take advantage of its extended functionality.
  14. Core functionality of the execution, state, and runner modules is derived from
  15. this library, so common usages between them are described here. Documentation
  16. specific to each module is described below.
  17. This library can be imported with:
  18. .. code-block:: python
  19. import salt.utils.http
  20. Configuring Libraries
  21. ~~~~~~~~~~~~~~~~~~~~~
  22. This library can make use of either ``tornado``, which is required by Salt,
  23. ``urllib2``, which ships with Python, or ``requests``, which can be installed
  24. separately. By default, ``tornado`` will be used. In order to switch to
  25. ``urllib2``, set the following variable:
  26. .. code-block:: yaml
  27. backend: urllib2
  28. In order to switch to ``requests``, set the following variable:
  29. .. code-block:: yaml
  30. backend: requests
  31. This can be set in the master or minion configuration file, or passed as an
  32. option directly to any ``http.query()`` functions.
  33. ``salt.utils.http.query()``
  34. ~~~~~~~~~~~~~~~~~~~~~~~~~~~
  35. This function forms a basic query, but with some add-ons not present in the
  36. ``tornado``, ``urllib2``, and ``requests`` libraries. Not all functionality
  37. currently available in these libraries has been added, but can be in future
  38. iterations.
  39. HTTPS Request Methods
  40. `````````````````````
  41. A basic query can be performed by calling this function with no more than a
  42. single URL:
  43. .. code-block:: python
  44. salt.utils.http.query("http://example.com")
  45. By default the query will be performed with a ``GET`` method. The method can
  46. be overridden with the ``method`` argument:
  47. .. code-block:: python
  48. salt.utils.http.query("http://example.com/delete/url", "DELETE")
  49. When using the ``POST`` method (and others, such as ``PUT``), extra data is usually
  50. sent as well. This data can be sent directly (would be URL encoded when necessary),
  51. or in whatever format is required by the remote server (XML, JSON, plain text, etc).
  52. .. code-block:: python
  53. salt.utils.http.query(
  54. "http://example.com/post/url", method="POST", data=json.dumps(mydict)
  55. )
  56. Data Formatting and Templating
  57. ``````````````````````````````
  58. Bear in mind that the data must be sent pre-formatted; this function will not
  59. format it for you. However, a templated file stored on the local system may be
  60. passed through, along with variables to populate it with. To pass through only
  61. the file (untemplated):
  62. .. code-block:: python
  63. salt.utils.http.query(
  64. "http://example.com/post/url", method="POST", data_file="/srv/salt/somefile.xml"
  65. )
  66. To pass through a file that contains jinja + yaml templating (the default):
  67. .. code-block:: python
  68. salt.utils.http.query(
  69. "http://example.com/post/url",
  70. method="POST",
  71. data_file="/srv/salt/somefile.jinja",
  72. data_render=True,
  73. template_dict={"key1": "value1", "key2": "value2"},
  74. )
  75. To pass through a file that contains mako templating:
  76. .. code-block:: python
  77. salt.utils.http.query(
  78. "http://example.com/post/url",
  79. method="POST",
  80. data_file="/srv/salt/somefile.mako",
  81. data_render=True,
  82. data_renderer="mako",
  83. template_dict={"key1": "value1", "key2": "value2"},
  84. )
  85. Because this function uses Salt's own rendering system, any Salt renderer can
  86. be used. Because Salt's renderer requires ``__opts__`` to be set, an ``opts``
  87. dictionary should be passed in. If it is not, then the default ``__opts__``
  88. values for the node type (master or minion) will be used. Because this library
  89. is intended primarily for use by minions, the default node type is ``minion``.
  90. However, this can be changed to ``master`` if necessary.
  91. .. code-block:: python
  92. salt.utils.http.query(
  93. "http://example.com/post/url",
  94. method="POST",
  95. data_file="/srv/salt/somefile.jinja",
  96. data_render=True,
  97. template_dict={"key1": "value1", "key2": "value2"},
  98. opts=__opts__,
  99. )
  100. salt.utils.http.query(
  101. "http://example.com/post/url",
  102. method="POST",
  103. data_file="/srv/salt/somefile.jinja",
  104. data_render=True,
  105. template_dict={"key1": "value1", "key2": "value2"},
  106. node="master",
  107. )
  108. Headers
  109. ```````
  110. Headers may also be passed through, either as a ``header_list``, a
  111. ``header_dict``, or as a ``header_file``. As with the ``data_file``, the
  112. ``header_file`` may also be templated. Take note that because HTTP headers are
  113. normally syntactically-correct YAML, they will automatically be imported as an
  114. a Python dict.
  115. .. code-block:: python
  116. salt.utils.http.query(
  117. "http://example.com/delete/url",
  118. method="POST",
  119. header_file="/srv/salt/headers.jinja",
  120. header_render=True,
  121. header_renderer="jinja",
  122. template_dict={"key1": "value1", "key2": "value2"},
  123. )
  124. Because much of the data that would be templated between headers and data may be
  125. the same, the ``template_dict`` is the same for both. Correcting possible
  126. variable name collisions is up to the user.
  127. Authentication
  128. ``````````````
  129. The ``query()`` function supports basic HTTP authentication. A username and
  130. password may be passed in as ``username`` and ``password``, respectively.
  131. .. code-block:: python
  132. salt.utils.http.query(
  133. "http://example.com", username="larry", password="5700g3543v4r",
  134. )
  135. Cookies and Sessions
  136. ````````````````````
  137. Cookies are also supported, using Python's built-in ``cookielib``. However, they
  138. are turned off by default. To turn cookies on, set ``cookies`` to True.
  139. .. code-block:: python
  140. salt.utils.http.query("http://example.com", cookies=True)
  141. By default cookies are stored in Salt's cache directory, normally
  142. ``/var/cache/salt``, as a file called ``cookies.txt``. However, this location
  143. may be changed with the ``cookie_jar`` argument:
  144. .. code-block:: python
  145. salt.utils.http.query(
  146. "http://example.com", cookies=True, cookie_jar="/path/to/cookie_jar.txt"
  147. )
  148. By default, the format of the cookie jar is LWP (aka, lib-www-perl). This
  149. default was chosen because it is a human-readable text file. If desired, the
  150. format of the cookie jar can be set to Mozilla:
  151. .. code-block:: python
  152. salt.utils.http.query(
  153. "http://example.com",
  154. cookies=True,
  155. cookie_jar="/path/to/cookie_jar.txt",
  156. cookie_format="mozilla",
  157. )
  158. Because Salt commands are normally one-off commands that are piped together,
  159. this library cannot normally behave as a normal browser, with session cookies
  160. that persist across multiple HTTP requests. However, the session can be
  161. persisted in a separate cookie jar. The default filename for this file, inside
  162. Salt's cache directory, is ``cookies.session.p``. This can also be changed.
  163. .. code-block:: python
  164. salt.utils.http.query(
  165. "http://example.com", persist_session=True, session_cookie_jar="/path/to/jar.p"
  166. )
  167. The format of this file is msgpack, which is consistent with much of the rest
  168. of Salt's internal structure. Historically, the extension for this file is
  169. ``.p``. There are no current plans to make this configurable.
  170. Proxy
  171. `````
  172. If the ``tornado`` backend is used (``tornado`` is the default), proxy
  173. information configured in ``proxy_host``, ``proxy_port``, ``proxy_username``,
  174. ``proxy_password`` and ``no_proxy`` from the ``__opts__`` dictionary will be used. Normally
  175. these are set in the minion configuration file.
  176. .. code-block:: yaml
  177. proxy_host: proxy.my-domain
  178. proxy_port: 31337
  179. proxy_username: charon
  180. proxy_password: obolus
  181. no_proxy: ['127.0.0.1', 'localhost']
  182. .. code-block:: python
  183. salt.utils.http.query("http://example.com", opts=__opts__, backend="tornado")
  184. Return Data
  185. ~~~~~~~~~~~
  186. .. note:: Return data encoding
  187. If ``decode`` is set to ``True``, ``query()`` will attempt to decode the
  188. return data. ``decode_type`` defaults to ``auto``. Set it to a specific
  189. encoding, ``xml``, for example, to override autodetection.
  190. Because Salt's http library was designed to be used with REST interfaces,
  191. ``query()`` will attempt to decode the data received from the remote server
  192. when ``decode`` is set to ``True``. First it will check the ``Content-type``
  193. header to try and find references to XML. If it does not find any, it will look
  194. for references to JSON. If it does not find any, it will fall back to plain
  195. text, which will not be decoded.
  196. JSON data is translated into a dict using Python's built-in ``json`` library.
  197. XML is translated using ``salt.utils.xml_util``, which will use Python's
  198. built-in XML libraries to attempt to convert the XML into a dict. In order to
  199. force either JSON or XML decoding, the ``decode_type`` may be set:
  200. .. code-block:: python
  201. salt.utils.http.query("http://example.com", decode_type="xml")
  202. Once translated, the return dict from ``query()`` will include a dict called
  203. ``dict``.
  204. If the data is not to be translated using one of these methods, decoding may be
  205. turned off.
  206. .. code-block:: python
  207. salt.utils.http.query("http://example.com", decode=False)
  208. If decoding is turned on, and references to JSON or XML cannot be found, then
  209. this module will default to plain text, and return the undecoded data as
  210. ``text`` (even if text is set to ``False``; see below).
  211. The ``query()`` function can return the HTTP status code, headers, and/or text
  212. as required. However, each must individually be turned on.
  213. .. code-block:: python
  214. salt.utils.http.query("http://example.com", status=True, headers=True, text=True)
  215. The return from these will be found in the return dict as ``status``,
  216. ``headers`` and ``text``, respectively.
  217. Writing Return Data to Files
  218. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  219. It is possible to write either the return data or headers to files, as soon as
  220. the response is received from the server, but specifying file locations via the
  221. ``text_out`` or ``headers_out`` arguments. ``text`` and ``headers`` do not need
  222. to be returned to the user in order to do this.
  223. .. code-block:: python
  224. salt.utils.http.query(
  225. "http://example.com",
  226. text=False,
  227. headers=False,
  228. text_out="/path/to/url_download.txt",
  229. headers_out="/path/to/headers_download.txt",
  230. )
  231. SSL Verification
  232. ~~~~~~~~~~~~~~~~
  233. By default, this function will verify SSL certificates. However, for testing or
  234. debugging purposes, SSL verification can be turned off.
  235. .. code-block:: python
  236. salt.utils.http.query(
  237. "https://example.com", verify_ssl=False,
  238. )
  239. CA Bundles
  240. ~~~~~~~~~~
  241. The ``requests`` library has its own method of detecting which CA (certificate
  242. authority) bundle file to use. Usually this is implemented by the packager for
  243. the specific operating system distribution that you are using. However,
  244. ``urllib2`` requires a little more work under the hood. By default, Salt will
  245. try to auto-detect the location of this file. However, if it is not in an
  246. expected location, or a different path needs to be specified, it may be done so
  247. using the ``ca_bundle`` variable.
  248. .. code-block:: python
  249. salt.utils.http.query(
  250. "https://example.com", ca_bundle="/path/to/ca_bundle.pem",
  251. )
  252. Updating CA Bundles
  253. ```````````````````
  254. The ``update_ca_bundle()`` function can be used to update the bundle file at a
  255. specified location. If the target location is not specified, then it will
  256. attempt to auto-detect the location of the bundle file. If the URL to download
  257. the bundle from does not exist, a bundle will be downloaded from the cURL
  258. website.
  259. CAUTION: The ``target`` and the ``source`` should always be specified! Failure
  260. to specify the ``target`` may result in the file being written to the wrong
  261. location on the local system. Failure to specify the ``source`` may cause the
  262. upstream URL to receive excess unnecessary traffic, and may cause a file to be
  263. download which is hazardous or does not meet the needs of the user.
  264. .. code-block:: python
  265. salt.utils.http.update_ca_bundle(
  266. target="/path/to/ca-bundle.crt",
  267. source="https://example.com/path/to/ca-bundle.crt",
  268. opts=__opts__,
  269. )
  270. The ``opts`` parameter should also always be specified. If it is, then the
  271. ``target`` and the ``source`` may be specified in the relevant configuration
  272. file (master or minion) as ``ca_bundle`` and ``ca_bundle_url``, respectively.
  273. .. code-block:: yaml
  274. ca_bundle: /path/to/ca-bundle.crt
  275. ca_bundle_url: https://example.com/path/to/ca-bundle.crt
  276. If Salt is unable to auto-detect the location of the CA bundle, it will raise
  277. an error.
  278. The ``update_ca_bundle()`` function can also be passed a string or a list of
  279. strings which represent files on the local system, which should be appended (in
  280. the specified order) to the end of the CA bundle file. This is useful in
  281. environments where private certs need to be made available, and are not
  282. otherwise reasonable to add to the bundle file.
  283. .. code-block:: python
  284. salt.utils.http.update_ca_bundle(
  285. opts=__opts__,
  286. merge_files=[
  287. "/etc/ssl/private_cert_1.pem",
  288. "/etc/ssl/private_cert_2.pem",
  289. "/etc/ssl/private_cert_3.pem",
  290. ],
  291. )
  292. Test Mode
  293. ~~~~~~~~~
  294. This function may be run in test mode. This mode will perform all work up until
  295. the actual HTTP request. By default, instead of performing the request, an empty
  296. dict will be returned. Using this function with ``TRACE`` logging turned on will
  297. reveal the contents of the headers and POST data to be sent.
  298. Rather than returning an empty dict, an alternate ``test_url`` may be passed in.
  299. If this is detected, then test mode will replace the ``url`` with the
  300. ``test_url``, set ``test`` to ``True`` in the return data, and perform the rest
  301. of the requested operations as usual. This allows a custom, non-destructive URL
  302. to be used for testing when necessary.
  303. Execution Module
  304. ----------------
  305. The ``http`` execution module is a very thin wrapper around the
  306. ``salt.utils.http`` library. The ``opts`` can be passed through as well, but if
  307. they are not specified, the minion defaults will be used as necessary.
  308. Because passing complete data structures from the command line can be tricky at
  309. best and dangerous (in terms of execution injection attacks) at worse, the
  310. ``data_file``, and ``header_file`` are likely to see more use here.
  311. All methods for the library are available in the execution module, as kwargs.
  312. .. code-block:: bash
  313. salt myminion http.query http://example.com/restapi method=POST \
  314. username='larry' password='5700g3543v4r' headers=True text=True \
  315. status=True decode_type=xml data_render=True \
  316. header_file=/tmp/headers.txt data_file=/tmp/data.txt \
  317. header_render=True cookies=True persist_session=True
  318. Runner Module
  319. -------------
  320. Like the execution module, the ``http`` runner module is a very thin wrapper
  321. around the ``salt.utils.http`` library. The only significant difference is that
  322. because runners execute on the master instead of a minion, a target is not
  323. required, and default opts will be derived from the master config, rather than
  324. the minion config.
  325. All methods for the library are available in the runner module, as kwargs.
  326. .. code-block:: bash
  327. salt-run http.query http://example.com/restapi method=POST \
  328. username='larry' password='5700g3543v4r' headers=True text=True \
  329. status=True decode_type=xml data_render=True \
  330. header_file=/tmp/headers.txt data_file=/tmp/data.txt \
  331. header_render=True cookies=True persist_session=True
  332. State Module
  333. ------------
  334. The state module is a wrapper around the runner module, which applies stateful
  335. logic to a query. All kwargs as listed above are specified as usual in state
  336. files, but two more kwargs are available to apply stateful logic. A required
  337. parameter is ``match``, which specifies a pattern to look for in the return
  338. text. By default, this will perform a string comparison of looking for the
  339. value of match in the return text. In Python terms this looks like:
  340. .. code-block:: python
  341. def myfunc():
  342. if match in html_text:
  343. return True
  344. If more complex pattern matching is required, a regular expression can be used
  345. by specifying a ``match_type``. By default this is set to ``string``, but it
  346. can be manually set to ``pcre`` instead. Please note that despite the name, this
  347. will use Python's ``re.search()`` rather than ``re.match()``.
  348. Therefore, the following states are valid:
  349. .. code-block:: yaml
  350. http://example.com/restapi:
  351. http.query:
  352. - match: 'SUCCESS'
  353. - username: 'larry'
  354. - password: '5700g3543v4r'
  355. - data_render: True
  356. - header_file: /tmp/headers.txt
  357. - data_file: /tmp/data.txt
  358. - header_render: True
  359. - cookies: True
  360. - persist_session: True
  361. http://example.com/restapi:
  362. http.query:
  363. - match_type: pcre
  364. - match: '(?i)succe[ss|ed]'
  365. - username: 'larry'
  366. - password: '5700g3543v4r'
  367. - data_render: True
  368. - header_file: /tmp/headers.txt
  369. - data_file: /tmp/data.txt
  370. - header_render: True
  371. - cookies: True
  372. - persist_session: True
  373. In addition to, or instead of a match pattern, the status code for a URL can be
  374. checked. This is done using the ``status`` argument:
  375. .. code-block:: yaml
  376. http://example.com/:
  377. http.query:
  378. - status: 200
  379. If both are specified, both will be checked, but if only one is ``True`` and the
  380. other is ``False``, then ``False`` will be returned. In this case, the comments
  381. in the return data will contain information for troubleshooting.
  382. Because this is a monitoring state, it will return extra data to code that
  383. expects it. This data will always include ``text`` and ``status``. Optionally,
  384. ``headers`` and ``dict`` may also be requested by setting the ``headers`` and
  385. ``decode`` arguments to True, respectively.