%PDF- %PDF-
| Direktori : /proc/self/root/proc/thread-self/root/lib/python2.7/site-packages/salt/daemons/flo/ |
| Current File : //proc/self/root/proc/thread-self/root/lib/python2.7/site-packages/salt/daemons/flo/zero.py |
# -*- coding: utf-8 -*-
'''
IoFlo behaviors for running a ZeroMQ based master
'''
# pylint: disable=W0232
# pylint: disable=3rd-party-module-not-gated
# Import python libs
from __future__ import absolute_import, print_function, unicode_literals
import os
import logging
import hashlib
import multiprocessing
import errno
# Import ioflo libs
import ioflo.base.deeding
# Import third party libs
from salt.utils.zeromq import zmq
import salt.master
import salt.crypt
import salt.daemons.masterapi
import salt.payload
import salt.utils.stringutils
log = logging.getLogger(__name__)
class SaltZmqSetup(ioflo.base.deeding.Deed):
'''
do salt zmq setup at enter
Setup shares
.salt.var.zmq.master_key
.salt.var.zmq.aet share
This behavior must be run before any other zmq related
'''
Ioinits = {'opts': salt.utils.stringutils.to_str('.salt.opts'),
'mkey': salt.utils.stringutils.to_str('.salt.var.zmq.master_key'),
'aes': salt.utils.stringutils.to_str('.salt.var.zmq.aes')}
def action(self):
'''
Assign master key to .salt.var.zmq.master_key
Copy opts['aes'] to .salt.var.zmq.aes
'''
self.mkey.value = salt.crypt.MasterKeys(self.opts.value)
self.aes.value = self.opts.value['aes']
@ioflo.base.deeding.deedify(
salt.utils.stringutils.to_str('SaltZmqRetFork'),
ioinits={
'opts': salt.utils.stringutils.to_str('.salt.opts'),
'proc_mgr': salt.utils.stringutils.to_str('.salt.usr.proc_mgr'),
'mkey': salt.utils.stringutils.to_str('.salt.var.zmq.master_key'),
'aes': salt.utils.stringutils.to_str('.salt.var.zmq.aes')})
def zmq_ret_fork(self):
'''
Create the forked process for the ZeroMQ Ret Port
'''
self.proc_mgr.value.add_process(
ZmqRet,
args=(
self.opts.value,
self.mkey.value,
self.aes.value))
class ZmqRet(multiprocessing.Process):
'''
Create the forked process for the ZeroMQ Ret Port
'''
def __init__(self, opts, mkey, aes):
self.opts = opts
self.mkey = mkey
self.aes = aes
super(ZmqRet, self).__init__()
def run(self):
'''
Start the ret port binding
'''
self.context = zmq.Context(self.opts['worker_threads'])
self.uri = 'tcp://{interface}:{ret_port}'.format(**self.opts)
log.info('ZMQ Ret port binding to %s', self.uri)
self.clients = self.context.socket(zmq.ROUTER)
if self.opts['ipv6'] is True and hasattr(zmq, 'IPV4ONLY'):
# IPv6 sockets work for both IPv6 and IPv4 addresses
self.clients.setsockopt(zmq.IPV4ONLY, 0)
try:
self.clients.setsockopt(zmq.HWM, self.opts['rep_hwm'])
except AttributeError:
self.clients.setsockopt(zmq.SNDHWM, self.opts['rep_hwm'])
self.clients.setsockopt(zmq.RCVHWM, self.opts['rep_hwm'])
self.clients.setsockopt(zmq.BACKLOG, self.opts['zmq_backlog'])
self.workers = self.context.socket(zmq.DEALER)
self.w_uri = 'ipc://{0}'.format(
os.path.join(self.opts['sock_dir'], 'workers.ipc')
)
log.info('Setting up the master communication server')
self.clients.bind(self.uri)
self.workers.bind(self.w_uri)
while True:
try:
zmq.device(zmq.QUEUE, self.clients, self.workers)
except zmq.ZMQError as exc:
if exc.errno == errno.EINTR:
continue
raise exc
class SaltZmqCrypticleSetup(ioflo.base.deeding.Deed):
'''
Setup the crypticle for the salt zmq publisher behavior
do salt zmq crypticle setup at enter
'''
Ioinits = {'opts': salt.utils.stringutils.to_str('.salt.opts'),
'aes': salt.utils.stringutils.to_str('.salt.var.zmq.aes'),
'crypticle': salt.utils.stringutils.to_str('.salt.var.zmq.crypticle')}
def action(self):
'''
Initializes zmq
Put here so only runs initialization if we want multi-headed master
'''
self.crypticle.value = salt.crypt.Crypticle(
self.opts.value,
self.opts.value.get('aes'))
class SaltZmqPublisher(ioflo.base.deeding.Deed):
'''
The zeromq publisher
do salt zmq publisher
Must run the deed
do salt zmq publisher setup
before this deed
'''
Ioinits = {'opts': salt.utils.stringutils.to_str('.salt.opts'),
'publish': salt.utils.stringutils.to_str('.salt.var.publish'),
'zmq_behavior': salt.utils.stringutils.to_str('.salt.etc.zmq_behavior'),
'aes': salt.utils.stringutils.to_str('.salt.var.zmq.aes'),
'crypticle': salt.utils.stringutils.to_str('.salt.var.zmq.crypticle')}
def _prepare(self):
'''
Set up tracking value(s)
'''
if not zmq:
return
self.created = False
self.serial = salt.payload.Serial(self.opts.value)
def action(self):
'''
Create the publish port if it is not available and then publish the
messages on it
'''
if not self.zmq_behavior:
return
if not self.created:
self.context = zmq.Context(1)
self.pub_sock = self.context.socket(zmq.PUB)
# if 2.1 >= zmq < 3.0, we only have one HWM setting
try:
self.pub_sock.setsockopt(zmq.HWM, self.opts.value.get('pub_hwm', 1000))
# in zmq >= 3.0, there are separate send and receive HWM settings
except AttributeError:
self.pub_sock.setsockopt(zmq.SNDHWM, self.opts.value.get('pub_hwm', 1000))
self.pub_sock.setsockopt(zmq.RCVHWM, self.opts.value.get('pub_hwm', 1000))
if self.opts.value['ipv6'] is True and hasattr(zmq, 'IPV4ONLY'):
# IPv6 sockets work for both IPv6 and IPv4 addresses
self.pub_sock.setsockopt(zmq.IPV4ONLY, 0)
self.pub_sock.setsockopt(zmq.BACKLOG, self.opts.get('zmq_backlog', 1000))
self.pub_uri = 'tcp://{interface}:{publish_port}'.format(**self.opts.value)
log.info('Starting the Salt ZeroMQ Publisher on %s', self.pub_uri)
self.pub_sock.bind(self.pub_uri)
self.created = True
# Don't pop the publish messages! The raet behavior still needs them
try:
for package in self.publish.value:
payload = {'enc': 'aes'}
payload['load'] = self.crypticle.value.dumps(package['return']['pub'])
if self.opts.value['sign_pub_messages']:
master_pem_path = os.path.join(self.opts.value['pki_dir'], 'master.pem')
log.debug('Signing data packet for publish')
payload['sig'] = salt.crypt.sign_message(master_pem_path, payload['load'])
send_payload = self.serial.dumps(payload)
if self.opts.value['zmq_filtering']:
# if you have a specific topic list, use that
if package['return']['pub']['tgt_type'] == 'list':
for topic in package['return']['pub']['tgt']:
# zmq filters are substring match, hash the topic
# to avoid collisions
htopic = hashlib.sha1(topic).hexdigest()
self.pub_sock.send(htopic, flags=zmq.SNDMORE)
self.pub_sock.send(send_payload)
# otherwise its a broadcast
else:
self.pub_sock.send('broadcast', flags=zmq.SNDMORE)
self.pub_sock.send(send_payload)
else:
self.pub_sock.send(send_payload)
except zmq.ZMQError as exc:
if exc.errno == errno.EINTR:
return
raise exc
class SaltZmqWorker(ioflo.base.deeding.Deed):
'''
The zeromq behavior for the workers
'''
Ioinits = {'opts': salt.utils.stringutils.to_str('.salt.opts'),
'key': salt.utils.stringutils.to_str('.salt.access_keys'),
'aes': salt.utils.stringutils.to_str('.salt.var.zmq.aes')}
def _prepare(self):
'''
Create the initial seting value for the worker
'''
self.created = False
def action(self):
'''
Create the master MWorker if it is not present, then iterate over the
connection with the ioflo sequence
'''
if not self.created:
crypticle = salt.crypt.Crypticle(self.opts.value, self.aes.value)
self.worker = salt.master.FloMWorker(
self.opts.value,
self.key.value,
)
self.worker.setup()
self.created = True
log.info('Started ZMQ worker')
self.worker.handle_request()