index.rst 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. .. _returners:
  2. =========
  3. Returners
  4. =========
  5. By default the return values of the commands sent to the Salt minions are
  6. returned to the Salt master, however anything at all can be done with the results
  7. data.
  8. By using a Salt returner, results data can be redirected to external data-stores
  9. for analysis and archival.
  10. Returners pull their configuration values from the Salt minions. Returners are only
  11. configured once, which is generally at load time.
  12. The returner interface allows the return data to be sent to any system that
  13. can receive data. This means that return data can be sent to a Redis server,
  14. a MongoDB server, a MySQL server, or any system.
  15. .. seealso:: :ref:`Full list of builtin returners <all-salt.returners>`
  16. Using Returners
  17. ===============
  18. All Salt commands will return the command data back to the master. Specifying
  19. returners will ensure that the data is _also_ sent to the specified returner
  20. interfaces.
  21. Specifying what returners to use is done when the command is invoked:
  22. .. code-block:: bash
  23. salt '*' test.version --return redis_return
  24. This command will ensure that the redis_return returner is used.
  25. It is also possible to specify multiple returners:
  26. .. code-block:: bash
  27. salt '*' test.version --return mongo_return,redis_return,cassandra_return
  28. In this scenario all three returners will be called and the data from the
  29. test.version command will be sent out to the three named returners.
  30. Writing a Returner
  31. ==================
  32. Returners are Salt modules that allow the redirection of results data to targets other than the Salt Master.
  33. Returners Are Easy To Write!
  34. ----------------------------
  35. Writing a Salt returner is straightforward.
  36. A returner is a Python module containing at minimum a ``returner`` function.
  37. Other optional functions can be included to add support for
  38. :conf_master:`master_job_cache`, :ref:`external-job-cache`, and `Event Returners`_.
  39. ``returner``
  40. The ``returner`` function must accept a single argument. The argument
  41. contains return data from the called minion function. If the minion
  42. function ``test.version`` is called, the value of the argument will be a
  43. dictionary. Run the following command from a Salt master to get a sample
  44. of the dictionary:
  45. .. code-block:: bash
  46. salt-call --local --metadata test.version --out=pprint
  47. .. code-block:: python
  48. import redis
  49. import salt.utils.json
  50. def returner(ret):
  51. '''
  52. Return information to a redis server
  53. '''
  54. # Get a redis connection
  55. serv = redis.Redis(
  56. host='redis-serv.example.com',
  57. port=6379,
  58. db='0')
  59. serv.sadd("%(id)s:jobs" % ret, ret['jid'])
  60. serv.set("%(jid)s:%(id)s" % ret, salt.utils.json.dumps(ret['return']))
  61. serv.sadd('jobs', ret['jid'])
  62. serv.sadd(ret['jid'], ret['id'])
  63. The above example of a returner set to send the data to a Redis server
  64. serializes the data as JSON and sets it in redis.
  65. Using Custom Returner Modules
  66. -----------------------------
  67. Place custom returners in a ``_returners/`` directory within the
  68. :conf_master:`file_roots` specified by the master config file.
  69. Custom returners are distributed when any of the following are called:
  70. - :mod:`state.apply <salt.modules.state.apply_>`
  71. - :mod:`saltutil.sync_returners <salt.modules.saltutil.sync_returners>`
  72. - :mod:`saltutil.sync_all <salt.modules.saltutil.sync_all>`
  73. Any custom returners which have been synced to a minion that are named the
  74. same as one of Salt's default set of returners will take the place of the
  75. default returner with the same name.
  76. Naming the Returner
  77. -------------------
  78. Note that a returner's default name is its filename (i.e. ``foo.py`` becomes
  79. returner ``foo``), but that its name can be overridden by using a
  80. :ref:`__virtual__ function <virtual-modules>`. A good example of this can be
  81. found in the `redis`_ returner, which is named ``redis_return.py`` but is
  82. loaded as simply ``redis``:
  83. .. code-block:: python
  84. try:
  85. import redis
  86. HAS_REDIS = True
  87. except ImportError:
  88. HAS_REDIS = False
  89. __virtualname__ = 'redis'
  90. def __virtual__():
  91. if not HAS_REDIS:
  92. return False
  93. return __virtualname__
  94. Master Job Cache Support
  95. ------------------------
  96. :conf_master:`master_job_cache`, :ref:`external-job-cache`, and `Event Returners`_.
  97. Salt's :conf_master:`master_job_cache` allows returners to be used as a pluggable
  98. replacement for the :ref:`default_job_cache`. In order to do so, a returner
  99. must implement the following functions:
  100. .. note::
  101. The code samples contained in this section were taken from the cassandra_cql
  102. returner.
  103. ``prep_jid``
  104. Ensures that job ids (jid) don't collide, unless passed_jid is provided.
  105. ``nocache`` is an optional boolean that indicates if return data
  106. should be cached. ``passed_jid`` is a caller provided jid which should be
  107. returned unconditionally.
  108. .. code-block:: python
  109. def prep_jid(nocache, passed_jid=None): # pylint: disable=unused-argument
  110. '''
  111. Do any work necessary to prepare a JID, including sending a custom id
  112. '''
  113. return passed_jid if passed_jid is not None else salt.utils.jid.gen_jid()
  114. ``save_load``
  115. Save job information. The ``jid`` is generated by ``prep_jid`` and should
  116. be considered a unique identifier for the job. The jid, for example, could
  117. be used as the primary/unique key in a database. The ``load`` is what is
  118. returned to a Salt master by a minion. ``minions`` is a list of minions
  119. that the job was run against. The following code example stores the load as
  120. a JSON string in the salt.jids table.
  121. .. code-block:: python
  122. import salt.utils.json
  123. def save_load(jid, load, minions=None):
  124. '''
  125. Save the load to the specified jid id
  126. '''
  127. query = '''INSERT INTO salt.jids (
  128. jid, load
  129. ) VALUES (
  130. '{0}', '{1}'
  131. );'''.format(jid, salt.utils.json.dumps(load))
  132. # cassandra_cql.cql_query may raise a CommandExecutionError
  133. try:
  134. __salt__['cassandra_cql.cql_query'](query)
  135. except CommandExecutionError:
  136. log.critical('Could not save load in jids table.')
  137. raise
  138. except Exception as e:
  139. log.critical(
  140. 'Unexpected error while inserting into jids: {0}'.format(e)
  141. )
  142. raise
  143. ``get_load``
  144. must accept a job id (jid) and return the job load stored by ``save_load``,
  145. or an empty dictionary when not found.
  146. .. code-block:: python
  147. def get_load(jid):
  148. '''
  149. Return the load data that marks a specified jid
  150. '''
  151. query = '''SELECT load FROM salt.jids WHERE jid = '{0}';'''.format(jid)
  152. ret = {}
  153. # cassandra_cql.cql_query may raise a CommandExecutionError
  154. try:
  155. data = __salt__['cassandra_cql.cql_query'](query)
  156. if data:
  157. load = data[0].get('load')
  158. if load:
  159. ret = json.loads(load)
  160. except CommandExecutionError:
  161. log.critical('Could not get load from jids table.')
  162. raise
  163. except Exception as e:
  164. log.critical('''Unexpected error while getting load from
  165. jids: {0}'''.format(str(e)))
  166. raise
  167. return ret
  168. External Job Cache Support
  169. --------------------------
  170. Salt's :ref:`external-job-cache` extends the :conf_master:`master_job_cache`. External
  171. Job Cache support requires the following functions in addition to what is
  172. required for Master Job Cache support:
  173. ``get_jid``
  174. Return a dictionary containing the information (load) returned by each
  175. minion when the specified job id was executed.
  176. Sample:
  177. .. code-block:: JSON
  178. {
  179. "local": {
  180. "master_minion": {
  181. "fun_args": [],
  182. "jid": "20150330121011408195",
  183. "return": "2018.3.4",
  184. "retcode": 0,
  185. "success": true,
  186. "cmd": "_return",
  187. "_stamp": "2015-03-30T12:10:12.708663",
  188. "fun": "test.version",
  189. "id": "master_minion"
  190. }
  191. }
  192. }
  193. ``get_fun``
  194. Return a dictionary of minions that called a given Salt function as their
  195. last function call.
  196. Sample:
  197. .. code-block:: JSON
  198. {
  199. "local": {
  200. "minion1": "test.version",
  201. "minion3": "test.version",
  202. "minion2": "test.version"
  203. }
  204. }
  205. ``get_jids``
  206. Return a list of all job ids.
  207. Sample:
  208. .. code-block:: JSON
  209. {
  210. "local": [
  211. "20150330121011408195",
  212. "20150330195922139916"
  213. ]
  214. }
  215. ``get_minions``
  216. Returns a list of minions
  217. Sample:
  218. .. code-block:: JSON
  219. {
  220. "local": [
  221. "minion3",
  222. "minion2",
  223. "minion1",
  224. "master_minion"
  225. ]
  226. }
  227. Please refer to one or more of the existing returners (i.e. mysql,
  228. cassandra_cql) if you need further clarification.
  229. Event Support
  230. -------------
  231. An ``event_return`` function must be added to the returner module to allow
  232. events to be logged from a master via the returner. A list of events are passed
  233. to the function by the master.
  234. The following example was taken from the MySQL returner. In this example, each
  235. event is inserted into the salt_events table keyed on the event tag. The tag
  236. contains the jid and therefore is guaranteed to be unique.
  237. .. code-block:: python
  238. import salt.utils.json
  239. def event_return(events):
  240. '''
  241. Return event to mysql server
  242. Requires that configuration be enabled via 'event_return'
  243. option in master config.
  244. '''
  245. with _get_serv(events, commit=True) as cur:
  246. for event in events:
  247. tag = event.get('tag', '')
  248. data = event.get('data', '')
  249. sql = '''INSERT INTO `salt_events` (`tag`, `data`, `master_id` )
  250. VALUES (%s, %s, %s)'''
  251. cur.execute(sql, (tag, salt.utils.json.dumps(data), __opts__['id']))
  252. Testing the Returner
  253. --------------------
  254. The ``returner``, ``prep_jid``, ``save_load``, ``get_load``, and
  255. ``event_return`` functions can be tested by configuring the
  256. :conf_master:`master_job_cache` and `Event Returners`_ in the master config
  257. file and submitting a job to ``test.version`` each minion from the master.
  258. Once you have successfully exercised the Master Job Cache functions, test the
  259. External Job Cache functions using the ``ret`` execution module.
  260. .. code-block:: bash
  261. salt-call ret.get_jids cassandra_cql --output=json
  262. salt-call ret.get_fun cassandra_cql test.version --output=json
  263. salt-call ret.get_minions cassandra_cql --output=json
  264. salt-call ret.get_jid cassandra_cql 20150330121011408195 --output=json
  265. Event Returners
  266. ===============
  267. For maximum visibility into the history of events across a Salt
  268. infrastructure, all events seen by a salt master may be logged to one or
  269. more returners.
  270. To enable event logging, set the ``event_return`` configuration option in the
  271. master config to the returner(s) which should be designated as the handler
  272. for event returns.
  273. .. note::
  274. Not all returners support event returns. Verify a returner has an
  275. ``event_return()`` function before using.
  276. .. note::
  277. On larger installations, many hundreds of events may be generated on a
  278. busy master every second. Be certain to closely monitor the storage of
  279. a given returner as Salt can easily overwhelm an underpowered server
  280. with thousands of returns.
  281. Full List of Returners
  282. ======================
  283. .. toctree::
  284. all/index
  285. .. _`redis`: https://github.com/saltstack/salt/tree/|repo_primary_branch|/salt/returners/redis_return.py