% Options for packages loaded elsewhere
\PassOptionsToPackage{unicode}{hyperref}
\PassOptionsToPackage{hyphens}{url}
%
\documentclass[
]{article}
\usepackage{amsmath,amssymb}
\usepackage{iftex}
\ifPDFTeX
  \usepackage[T1]{fontenc}
  \usepackage[utf8]{inputenc}
  \usepackage{textcomp} % provide euro and other symbols
\else % if luatex or xetex
  \usepackage{unicode-math} % this also loads fontspec
  \defaultfontfeatures{Scale=MatchLowercase}
  \defaultfontfeatures[\rmfamily]{Ligatures=TeX,Scale=1}
\fi
\usepackage{lmodern}
\ifPDFTeX\else
  % xetex/luatex font selection
\fi
% Use upquote if available, for straight quotes in verbatim environments
\IfFileExists{upquote.sty}{\usepackage{upquote}}{}
\IfFileExists{microtype.sty}{% use microtype if available
  \usepackage[]{microtype}
  \UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
}{}
\makeatletter
\@ifundefined{KOMAClassName}{% if non-KOMA class
  \IfFileExists{parskip.sty}{%
    \usepackage{parskip}
  }{% else
    \setlength{\parindent}{0pt}
    \setlength{\parskip}{6pt plus 2pt minus 1pt}}
}{% if KOMA class
  \KOMAoptions{parskip=half}}
\makeatother
\usepackage{xcolor}
\setlength{\emergencystretch}{3em} % prevent overfull lines
\providecommand{\tightlist}{%
  \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
\setcounter{secnumdepth}{-\maxdimen} % remove section numbering
\ifLuaTeX
  \usepackage{selnolig}  % disable illegal ligatures
\fi
\IfFileExists{bookmark.sty}{\usepackage{bookmark}}{\usepackage{hyperref}}
\IfFileExists{xurl.sty}{\usepackage{xurl}}{} % add URL line breaks if available
\urlstyle{same}
\hypersetup{
  pdftitle={salt-stack-piggy-back-encrypted-zmq-event-bus},
  hidelinks,
  pdfcreator={LaTeX via pandoc}}

\title{salt-stack-piggy-back-encrypted-zmq-event-bus}
\author{}
\date{}

\begin{document}
\maketitle

\hypertarget{salt-stack-piggy-back-encrypted-zmq-event-bus}{%
\section{salt-stack-piggy-back-encrypted-zmq-event-bus}\label{salt-stack-piggy-back-encrypted-zmq-event-bus}}

Salt Stack Piggy Back Encrypted ZMQ Event Bus
\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#

Some code examples that piggy back on Salt Stack's encrypted ZMQ event
bus. These code examples show how 3rd party scripts on each side may
communicate over secure and fast transport!

Requires:

\begin{itemize}
\tightlist
\item
  the salt-minion daemon alive and running on the minion host
\item
  the salt-master daemon alive and running on the master host
\item
  the 3rd party scripts must execute as the same user who runs the
  salt-minion or salt-master daemon because the 3rd party script needs
  to bind to the ZMQ sockets managed by the daemons.
\end{itemize}

.. contents::

\hypertarget{fire-event-to-minion-bus-and-listen-to-minion-bus}{%
\section{Fire event to minion bus and listen to minion
bus}\label{fire-event-to-minion-bus-and-listen-to-minion-bus}}

In this example we write a listener/subscriber script that connects to
the minion bus. We then write a emitter/publisher script that connects
to the minion bus and posts events.

\hypertarget{listen_to_minion_bus.py}{%
\subsection{listen\_to\_minion\_bus.py}\label{listen_to_minion_bus.py}}

3rd Party Subscriber / Listener:

.. code-block:: python

\# needed for config to opts processing import os import salt.syspaths
as syspaths import salt.config

\# get opts from minion config file, this function also looks in drop
dir! opts =
salt.config.minion\_config(os.path.join(syspaths.CONFIG\_DIR, `minion'))

\# debug to STDOUT import salt.log
salt.log.setup\_console\_logger(`all')

\# event libary for events over ZMQ import salt.utils.event

\# opts must have the valid minion ID else it binds to invalid socket
event = salt.utils.event.MinionEvent(**opts)

tag = `mytag'

print(`Listening for events tagged
\textquotesingle\{\}\textquotesingle{} on Salt Minion bus.'.format(tag))

\# generator iterator yields events forever, we filter on tag for data
in event.iter\_events(tag=tag): print(data)

\hypertarget{emit_to_minion_bus.py}{%
\subsection{emit\_to\_minion\_bus.py}\label{emit_to_minion_bus.py}}

3rd Party Publisher / Emitter:

.. code-block:: python

\# needed for config to opts processing import os import salt.syspaths
as syspaths import salt.config

\# get opts from minion config file, this function also looks in drop
dir! opts =
salt.config.minion\_config(os.path.join(syspaths.CONFIG\_DIR, `minion'))

\# debug to STDOUT import salt.log
salt.log.setup\_console\_logger(`all')

\# event libary for events over ZMQ import salt.utils.event

tag = `mytag' data = \{`message':`a drop in the bucket'\}

payload = \{ `id': opts{[}`id'{]}, `tag': tag, `data': data, \}

print (payload)

\# opts must valid minion ID else it binds to invalid socket event =
salt.utils.event.SaltEvent(`minion', **opts)

\# Fire event payload with tag event.fire\_event(payload, tag)

\hypertarget{notes-on-the-implementation}{%
\subsection{Notes on the
implementation}\label{notes-on-the-implementation}}

Notice how I use \texttt{event.MinionEvent} in listener and
\texttt{event.SaltEvent} in emitter? The \texttt{event.MinionEvent} is
just a very light weight subclass of \texttt{event.SaltEvent} so you can
use either or\ldots{}

The configuration code could be reduced to static variables, for
instance replace -

.. code-block:: python

\# needed for config to opts processing import os import salt.syspaths
as syspaths import salt.config

\# get opts from minion config file, this function also looks in drop
dir! opts =
salt.config.minion\_config(os.path.join(syspaths.CONFIG\_DIR, `minion'))

with this

.. code-block:: python

opts = \{`sock\_dir':`/var/run/salt/minion', `id':`id-of-this-minion'\}

\hypertarget{fire-event-to-master-bus-and-listen-to-master-bus}{%
\section{Fire event to master bus and listen to master
bus}\label{fire-event-to-master-bus-and-listen-to-master-bus}}

In this example we write a listener/subscriber script that connects to
the master bus. We then write a emitter/publisher script that connects
to the master bus and posts events.

\hypertarget{listen_to_master_bus.py}{%
\subsection{listen\_to\_master\_bus.py}\label{listen_to_master_bus.py}}

.. code-block:: python

\# debug logging to STDOUT import salt.log
salt.log.setup\_console\_logger(`all')

\# event libary for events over ZMQ import salt.utils.event

\# create event object, attach to master socket \ldots{} event =
salt.utils.event.MasterEvent(`/var/run/salt/master')

tag = `mytag'

print(`Listening for events tagged
\textquotesingle\{\}\textquotesingle{} on Salt Master bus.'.format(tag))

\# generator iterator yields events forever, we filter on tag for data
in event.iter\_events(tag=tag): print(data)

\hypertarget{emit_to_master_bus.py}{%
\subsection{emit\_to\_master\_bus.py}\label{emit_to_master_bus.py}}

.. code-block:: python

\# debug logging to STDOUT import salt.log
salt.log.setup\_console\_logger(`all')

\# event libary for events over ZMQ import salt.utils.event

payload = \{`sample-msg': `this is a test', `example': `this is the same
test'\}

sock\_dir = `/var/run/salt/master'

\# create event object, attach to master socket \ldots{} event =
salt.utils.event.SaltEvent(`master', sock\_dir)

\# post the event event.fire\_event(payload, `mytag')

\hypertarget{fire-events-between-minion-and-master}{%
\section{Fire events between minion and
master}\label{fire-events-between-minion-and-master}}

There is where I get stuck \ldots{} I want to allow minions to fire
events which end up on the master bus \ldots{}

I'm able to do this with \texttt{salt-call}, for example:

.. code-block:: python

salt-call event.fire\_master `\{``data'': ``message for the master''\}'
`mytag'

From my understanding the minion to master communication could work like
this:

\begin{enumerate}
\tightlist
\item
  A 3rd party script publishes to minion bus
\item
  salt-minion daemon sees the properly formatted event tagged
  `fire\_master' and runs \_fire\_master() method
\item
  the event ends up on master bus
\item
  A 3rd party script listens to the master bus and subscribes (filters)
  on the nested tag and gains access to the message
\end{enumerate}

The code in
\texttt{emit-to-minion-bus.py\ \textless{}http://www.foxhop.net/salt-stack-piggy-back-encrypted-zmq-event-bus\#emit-to-minion-bus-py\textgreater{}}\_
does the first step, but it seems my event ``package'' format is
incorrect so it never gets forwarded to the master \ldots{}

This area in the salt-minion daemon loop has conditionals which
determine if the package/event should be forwarded. It seems to look for
the `fire\_master' tag:

\begin{itemize}
\tightlist
\item
  https://github.com/saltstack/salt/blob/develop/salt/minion.py\#L1337
  \textbar{} `fire\_master' tag
\item
  https://github.com/saltstack/salt/pull/10890 \textbar{} possible fix
  to single `fire\_master' event
\end{itemize}

\hypertarget{emit_to_minion_bus_forward_to_master_bus.py}{%
\subsection{emit\_to\_minion\_bus\_forward\_to\_master\_bus.py}\label{emit_to_minion_bus_forward_to_master_bus.py}}

.. code-block:: python

\# needed for config to opts processing import os import salt.syspaths
as syspaths import salt.config

\# get opts from minion config file, this function also looks in drop
dir! opts =
salt.config.minion\_config(os.path.join(syspaths.CONFIG\_DIR, `minion'))

\# debug to STDOUT import salt.log
salt.log.setup\_console\_logger(`all')

\# event libary for events over ZMQ import salt.utils.event

tag = `mytag'

\# a list of event ret objects events = {[} \{`message':`a drap in the
bucket', `tag': tag \}, \{`message':`a drep in the bucket', `tag': tag
\}, \{`message':`a drip in the bucket', `tag': tag \}, \{`message':`a
drop in the bucket', `tag': tag \}, \{`message':`a drup in the bucket',
`tag': tag \}, {]}

\# multi event example, supports a list of event ret objects payload =
\{ `id': opts{[}`id'{]}, `events': events, `tag': None, `pretag': None,
`data': None \}

print (payload)

\# opts must valid minion ID else it binds to invalid socket event =
salt.utils.event.SaltEvent(`minion', **opts)

\# Fire event payload with `fire\_master' tag which the \# salt-minion
daemon will forward to the master event bus! event.fire\_event(payload,
`fire\_master')

\hypertarget{ideas}{%
\section{ideas}\label{ideas}}

I think it could be neat to build a returner which accepted a ZMQ
``channel'' tag. Then after a remote execution the ret data could be
passed from minion to master on a special channel. Then we could have a
3rd party script on the salt master that subscribes to this special
channel and performs further processing or presents the data in a neat
way.

for example:

.. code-block:: text

salt '*' --return=master\_bus --tag=monitoring cmd.run\_all
`/usr/lib/nagios/plugins/check\_procs -w 150 -c 200'

The minion would see the remote execution command, run the job, get data
back, and return to master on a special channel tag.

On the master we could have a 3rd party script subscribed to the special
channel tag and perform further manipulation or persist the output
somewhere.

UPDATE: I wrote a
\texttt{zeromq\ returner\ to\ return\ tagged\ data\ back\ to\ the\ master\textquotesingle{}s\ zeromq\ bus\ here\ \textless{}http://russell.ballestrini.net/replace-the-nagios-scheduler-and-nrpe-with-salt-stack/\textgreater{}}\_.

\hypertarget{references}{%
\section{references}\label{references}}

http://docs.saltstack.com/topics/event/index.html

\hypertarget{related-work}{%
\section{related work}\label{related-work}}

https://github.com/felskrone/salt-eventsd

\end{document}
