I needed to solve the task of having a minion execute a job on another minion and this is how I accomplished the task. This stemmed from having a minion that runs a web applications which just needed to execute an execution module that already existed, but needed to run on a different minion.
My solution depends on Salt events and reactors to orchestrate the request from the web server minion to the worker minion and have the worker minion give a response of the work it completed back to the web server minion.
Salt version: salt 2016.3.4
Machines:
| Host | Salt Role | Use Case |
| saltmast16 | Salt Master | Orchestrator |
| saltmina16 | Salt Minion | Where execution module will run |
| saltminb16 | Salt Minion | Web server that initiates work |
/srv/salt/_modules/rhtest.py
The event.fire_master call sends the com/millamilla/test/event/finish event to the master
| saltminb16
Web Server |
Web Server Files/ Code | salmast16
Master |
Master Files/ Code | saltmina16
Worker |
Worker Files/ Code | |
| Send an event from the web server to the master. | Send event com/millamilla/test/event/start |
Python: send_event.py
import salt.client
import uuid
caller = salt.client.Caller()
event_uuid = str(uuid.uuid1())
caller.sminion.functions['event.send'](
'com/millamilla/test/event/start',
{
'target': "saltmina16",
'site': "moodle",
'user': "hedrickbt",
'uuid': event_uuid,
}
)
|
Receive event com/millamilla/test/event/start |
/etc/salt/master.d/reactor.conf
reactor:
# ...
- 'com/millamilla/test/event/start':
- salt://reactor/rhtesteventstart.sls
# ...
#... |
||
| >>>>>>>>>>>>>>>>>>>> | >>>>>>>>>>>>>>>>>>>>>>>>>>>> | |||||
| Master handles event and causes execuction module to run on worker minion | Handle com/millamilla/test/event/start Event. Call execution module on worker. | /srv/salt/reactor/rhtesteventstart.sls
run_it:
local.rhtest.rhfunc:
- tgt: {{ data['data']['target'] }}
- arg:
- {{ data['data']['site'] }}
- {{ data['data']['user'] }}
- {{ data['id'] }}
- {{ data['data']['uuid'] }}
|
Execute module | Created on master: /srv/salt/_modules/rhtest.py and sync’d to minions from master via: salt ‘*’ saltutil.sync_all import salt
__outputter__ = {
'rhfunc': 'yaml'
}
def rhfunc(site, user, requesting_host, event_uuid):
result = {
"site":site,
"user":user,
"requesting_host":requesting_host,
"uuid":event_uuid
}
__salt__['event.fire_master'](
{
"site":site,
"user":user,
"requesting_host":requesting_host,
"uuid":event_uuid,
},
'com/millamilla/test/event/finish',
)
return result
|
||
| >>>>>>>>>>>>>>>>>>> | >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> | |||||
| After worker minion executes modules send event back to master | Receive event com/millamilla/test/event/finish |
/etc/salt/master.d/reactor.conf
reactor:
# ...
- 'com/millamilla/test/event/finish':
- salt://reactor/rhtesteventfinish.sls
# ...
|
||||
| <<<<<<<<<<<<<<<<<<< | <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< | |||||
| Forward event Master received to the web minion. | Receive/Handle Event
com/millamilla/test/event/finish |
Python: receive_event.py
This needs to run just after sending the message so it can be listening. You will want to add code that has a timeout in the for…print loop. Otherwise, it could run forever. You will also want to add code to look at the data[‘uuid’] to make sure it is the one you sent out. Typically, you wouldn’t have a separate send/receive program, but you can. I plant to create a single script that generates the uuid, sends the request, and waits for a message to return within a timeout period. If the timeout is exceeded an error would be thrown. import salt.config
import salt.utils.event
import socket
import os
# Import 3rd-party libs
import salt.ext.six as six
my_hostname = socket.gethostname()
#opts = salt.config.client_config('/etc/salt/minion')
opts = {}
opts['node'] = 'minion'
opts['sock_dir'] = '/var/run/salt'
opts['sock_dir'] = os.path.join(opts['sock_dir'], opts['node'])
opts['id'] = my_hostname
opts['transport'] = 'zeromq'
event = salt.utils.event.get_event(
opts['node'],
sock_dir=opts['sock_dir'],
transport=opts['transport'],
opts=opts)
for data in event.iter_events(tag='com/millamilla/test/event/finish'):
print(data)
|
Handle Event
com/millamilla/test/event/finish |
/srv/salt/reactor/rhtesteventfinish.sls
notify_it:
local.event.fire:
- tgt: {{ data['data']['requesting_host'] }}
- arg:
- {{ data['data'] }}
- com/millamilla/test/event/finish
|
||
| <<<<<<<<<<<<<<<<<<< | <<<<<<<<<<<<<<<<<<< | |||||