%PDF- %PDF-
Direktori : /lib/python2.7/site-packages/salt/daemons/flo/ |
Current File : //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()