Brooke's World The life and ramblings of Brooke.

November 15, 2016

Salt Reactor : Having a minion ask another minion to execute a module with events and reactors

Filed under: Uncategorized — Brooke @ 3:38 pm

 

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
 <<<<<<<<<<<<<<<<<<<  <<<<<<<<<<<<<<<<<<<

Powered by WordPress