events.rst 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. .. _event-system:
  2. ============
  3. Event System
  4. ============
  5. The Salt Event System is used to fire off events enabling third party
  6. applications or external processes to react to behavior within Salt.
  7. The event system uses a publish-subscribe pattern, otherwise know as pub/sub.
  8. Event Bus
  9. =========
  10. The event system is comprised of a two primary components, which make up the
  11. concept of an Event Bus:
  12. - The event sockets, which publish events
  13. - The event library, which can listen to events and send events into the salt system
  14. Events are published onto the event bus and event bus subscribers listen for the
  15. published events.
  16. The event bus is used for both inter-process communication as well as network transport
  17. in Salt. Inter-process communication is provided through UNIX domain sockets (UDX).
  18. The Salt Master and each Salt Minion has their own event bus.
  19. Event types
  20. ===========
  21. .. toctree::
  22. :maxdepth: 2
  23. master_events
  24. Listening for Events
  25. ====================
  26. Salt's event system is used heavily within Salt and it is also written to
  27. integrate heavily with existing tooling and scripts. There is a variety of
  28. ways to consume it.
  29. From the CLI
  30. ------------
  31. The quickest way to watch the event bus is by calling the :py:func:`state.event
  32. runner <salt.runners.state.event>`:
  33. .. code-block:: bash
  34. salt-run state.event pretty=True
  35. That runner is designed to interact with the event bus from external tools and
  36. shell scripts. See the documentation for more examples.
  37. Remotely via the REST API
  38. -------------------------
  39. Salt's event bus can be consumed
  40. :py:class:`salt.netapi.rest_cherrypy.app.Events` as an HTTP stream from
  41. external tools or services.
  42. .. code-block:: bash
  43. curl -SsNk https://salt-api.example.com:8000/events?token=05A3
  44. From Python
  45. -----------
  46. Python scripts can access the event bus only as the same system user that Salt
  47. is running as.
  48. The event system is accessed via the event library and can only be accessed
  49. by the same system user that Salt is running as. To listen to events a
  50. SaltEvent object needs to be created and then the get_event function needs to
  51. be run. The SaltEvent object needs to know the location that the Salt Unix
  52. sockets are kept. In the configuration this is the ``sock_dir`` option. The
  53. ``sock_dir`` option defaults to "/var/run/salt/master" on most systems.
  54. The following code will check for a single event:
  55. .. code-block:: python
  56. import salt.config
  57. import salt.utils.event
  58. opts = salt.config.client_config('/etc/salt/master')
  59. event = salt.utils.event.get_event(
  60. 'master',
  61. sock_dir=opts['sock_dir'],
  62. transport=opts['transport'],
  63. opts=opts)
  64. data = event.get_event()
  65. Events will also use a "tag". Tags allow for events to be filtered by prefix.
  66. By default all events will be returned. If only authentication events are
  67. desired, then pass the tag "salt/auth".
  68. The ``get_event`` method has a default poll time assigned of 5 seconds. To
  69. change this time set the "wait" option.
  70. The following example will only listen for auth events and will wait for 10 seconds
  71. instead of the default 5.
  72. .. code-block:: python
  73. data = event.get_event(wait=10, tag='salt/auth')
  74. To retrieve the tag as well as the event data, pass ``full=True``:
  75. .. code-block:: python
  76. evdata = event.get_event(wait=10, tag='salt/job', full=True)
  77. tag, data = evdata['tag'], evdata['data']
  78. Instead of looking for a single event, the ``iter_events`` method can be used to
  79. make a generator which will continually yield salt events.
  80. The iter_events method also accepts a tag but not a wait time:
  81. .. code-block:: python
  82. for data in event.iter_events(tag='salt/auth'):
  83. print(data)
  84. And finally event tags can be globbed, such as they can be in the Reactor,
  85. using the fnmatch library.
  86. .. code-block:: python
  87. import fnmatch
  88. import salt.config
  89. import salt.utils.event
  90. opts = salt.config.client_config('/etc/salt/master')
  91. sevent = salt.utils.event.get_event(
  92. 'master',
  93. sock_dir=opts['sock_dir'],
  94. transport=opts['transport'],
  95. opts=opts)
  96. while True:
  97. ret = sevent.get_event(full=True)
  98. if ret is None:
  99. continue
  100. if fnmatch.fnmatch(ret['tag'], 'salt/job/*/ret/*'):
  101. do_something_with_job_return(ret['data'])
  102. Firing Events
  103. =============
  104. It is possible to fire events on either the minion's local bus or to fire
  105. events intended for the master.
  106. To fire a local event from the minion on the command line call the
  107. :py:func:`event.fire <salt.modules.event.fire>` execution function:
  108. .. code-block:: bash
  109. salt-call event.fire '{"data": "message to be sent in the event"}' 'tag'
  110. To fire an event to be sent up to the master from the minion call the
  111. :py:func:`event.send <salt.modules.event.send>` execution function. Remember
  112. YAML can be used at the CLI in function arguments:
  113. .. code-block:: bash
  114. salt-call event.send 'myco/mytag/success' '{success: True, message: "It works!"}'
  115. If a process is listening on the minion, it may be useful for a user on the
  116. master to fire an event to it. An example of listening local events on
  117. a minion on a non-Windows system:
  118. .. code-block:: python
  119. # Job on minion
  120. import salt.utils.event
  121. opts = salt.config.minion_config('/etc/salt/minion')
  122. event = salt.utils.event.MinionEvent(opts)
  123. for evdata in event.iter_events(match_type = 'regex',
  124. tag = 'custom/.*'):
  125. # do your processing here...
  126. And an example of listening local events on a Windows system:
  127. .. code-block:: python
  128. # Job on minion
  129. import salt.utils.event
  130. opts = salt.config.minion_config(salt.minion.DEFAULT_MINION_OPTS)
  131. event = salt.utils.event.MinionEvent(opts)
  132. for evdata in event.iter_events(match_type = 'regex',
  133. tag = 'custom/.*'):
  134. # do your processing here...
  135. .. code-block:: bash
  136. salt minionname event.fire '{"data": "message for the minion"}' 'customtag/african/unladen'
  137. Firing Events from Python
  138. =========================
  139. From Salt execution modules
  140. ---------------------------
  141. Events can be very useful when writing execution modules, in order to inform
  142. various processes on the master when a certain task has taken place. This is
  143. easily done using the normal cross-calling syntax:
  144. .. code-block:: python
  145. # /srv/salt/_modules/my_custom_module.py
  146. def do_something():
  147. '''
  148. Do something and fire an event to the master when finished
  149. CLI Example::
  150. salt '*' my_custom_module:do_something
  151. '''
  152. # do something!
  153. __salt__['event.send']('myco/my_custom_module/finished', {
  154. 'finished': True,
  155. 'message': "The something is finished!",
  156. })
  157. From Custom Python Scripts
  158. --------------------------
  159. Firing events from custom Python code is quite simple and mirrors how it is
  160. done at the CLI:
  161. .. code-block:: python
  162. import salt.client
  163. caller = salt.client.Caller()
  164. ret = caller.cmd('event.send',
  165. 'myco/event/success'
  166. { 'success': True,
  167. 'message': "It works!" })
  168. if not ret:
  169. # the event could not be sent, process the error here