1
0

http.rst 18 KB

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