Beispiel #1
0
    def post_fork(self, payload_handler, io_loop):
        '''
        After forking we need to create all of the local sockets to listen to the
        router

        :param func payload_handler: A function to called to handle incoming payloads as
                                     they are picked up off the wire
        :param IOLoop io_loop: An instance of a Tornado IOLoop, to handle event scheduling
        '''
        self.payload_handler = payload_handler
        self.io_loop = io_loop

        self.context = zmq.Context(1)
        self._socket = self.context.socket(zmq.REP)
        self._start_zmq_monitor()

        if self.opts.get('ipc_mode', '') == 'tcp':
            self.w_uri = 'tcp://127.0.0.1:{0}'.format(
                self.opts.get('tcp_master_workers', 4515)
                )
        else:
            self.w_uri = 'ipc://{0}'.format(
                os.path.join(self.opts['sock_dir'], 'workers.ipc')
                )
        log.info('Worker binding to socket %s', self.w_uri)
        self._socket.connect(self.w_uri)

        salt.transport.mixins.auth.AESReqServerMixin.post_fork(self, payload_handler, io_loop)

        self.stream = zmq.eventloop.zmqstream.ZMQStream(self._socket, io_loop=self.io_loop)
        self.stream.on_recv_stream(self.handle_message)
Beispiel #2
0
    def post_fork(self, message_handler, io_loop):
        """
        After forking we need to create all of the local sockets to listen to the
        router

        :param func message_handler: A function to called to handle incoming payloads as
                                     they are picked up off the wire
        :param IOLoop io_loop: An instance of a Tornado IOLoop, to handle event scheduling
        """
        context = zmq.Context(1)
        self._socket = context.socket(zmq.REP)
        # Linger -1 means we'll never discard messages.
        self._socket.setsockopt(zmq.LINGER, -1)
        self._start_zmq_monitor()

        if self.opts.get("ipc_mode", "") == "tcp":
            self.w_uri = "tcp://127.0.0.1:{}".format(
                self.opts.get("tcp_master_workers", 4515))
        else:
            self.w_uri = "ipc://{}".format(
                os.path.join(self.opts["sock_dir"], "workers.ipc"))
        log.info("Worker binding to socket %s", self.w_uri)
        self._socket.connect(self.w_uri)
        self.stream = zmq.eventloop.zmqstream.ZMQStream(self._socket,
                                                        io_loop=io_loop)
        self.message_handler = message_handler
        self.stream.on_recv_stream(self.handle_message)
Beispiel #3
0
    def __init__(self, opts, addr, linger=0, io_loop=None):
        """
        Create an asynchronous message client

        :param dict opts: The salt opts dictionary
        :param str addr: The interface IP address to bind to
        :param int linger: The number of seconds to linger on a ZMQ socket. See
                           http://api.zeromq.org/2-1:zmq-setsockopt [ZMQ_LINGER]
        :param IOLoop io_loop: A Tornado IOLoop event scheduler [tornado.ioloop.IOLoop]
        """
        self.opts = opts
        self.addr = addr
        self.linger = linger
        if io_loop is None:
            self.io_loop = salt.ext.tornado.ioloop.IOLoop.current()
        else:
            self.io_loop = io_loop

        self.context = zmq.Context()

        self.send_queue = []
        # mapping of message -> future
        self.send_future_map = {}

        self._closing = False
Beispiel #4
0
    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
                six.reraise(*sys.exc_info())
Beispiel #5
0
    def __init__(self, opts, addr, linger=0, io_loop=None):
        '''
        Create an asynchronous message client

        :param dict opts: The salt opts dictionary
        :param str addr: The interface IP address to bind to
        :param int linger: The number of seconds to linger on a ZMQ socket. See
                           http://api.zeromq.org/2-1:zmq-setsockopt [ZMQ_LINGER]
        :param IOLoop io_loop: A Tornado IOLoop event scheduler [tornado.ioloop.IOLoop]
        '''
        self.opts = opts
        self.addr = addr
        self.linger = linger
        if io_loop is None:
            install_zmq()
            ZMQDefaultLoop.current()
        else:
            self.io_loop = io_loop

        self.serial = salt.payload.Serial(self.opts)
        self.context = zmq.Context()

        # wire up sockets
        self._init_socket()

        self.send_queue = []
        # mapping of message -> future
        self.send_future_map = {}

        self.send_timeout_map = {}  # message -> timeout
Beispiel #6
0
def _zmq(address, port, **kwargs):
    context = zmq.Context()
    socket = context.socket(zmq.SUB)
    if salt.utils.network.is_ipv6(address):
        socket.ipv6 = True
    socket.connect("tcp://{addr}:{port}".format(addr=address, port=port))
    socket.setsockopt(zmq.SUBSCRIBE, b"")
    return socket.recv
Beispiel #7
0
    def publish_daemon(
        self,
        publish_payload,
        presence_callback=None,
        remove_presence_callback=None,
    ):
        """
        This method represents the Publish Daemon process. It is intended to be
        run in a thread or process as it creates and runs an it's own ioloop.
        """
        ioloop = salt.ext.tornado.ioloop.IOLoop()
        ioloop.make_current()
        self.io_loop = ioloop
        context = zmq.Context(1)
        pub_sock = context.socket(zmq.PUB)
        monitor = ZeroMQSocketMonitor(pub_sock)
        monitor.start_io_loop(ioloop)
        _set_tcp_keepalive(pub_sock, self.opts)
        self.dpub_sock = pub_sock = zmq.eventloop.zmqstream.ZMQStream(pub_sock)
        # if 2.1 >= zmq < 3.0, we only have one HWM setting
        try:
            pub_sock.setsockopt(zmq.HWM, self.opts.get("pub_hwm", 1000))
        # in zmq >= 3.0, there are separate send and receive HWM settings
        except (AttributeError, zmq.error.ZMQError):
            # Set the High Water Marks. For more information on HWM, see:
            # http://api.zeromq.org/4-1:zmq-setsockopt
            pub_sock.setsockopt(zmq.SNDHWM, self.opts.get("pub_hwm", 1000))
            pub_sock.setsockopt(zmq.RCVHWM, self.opts.get("pub_hwm", 1000))
        if self.opts["ipv6"] is True and hasattr(zmq, "IPV4ONLY"):
            # IPv6 sockets work for both IPv6 and IPv4 addresses
            pub_sock.setsockopt(zmq.IPV4ONLY, 0)
        pub_sock.setsockopt(zmq.BACKLOG, self.opts.get("zmq_backlog", 1000))
        pub_sock.setsockopt(zmq.LINGER, -1)
        # Prepare minion pull socket
        pull_sock = context.socket(zmq.PULL)
        pull_sock = zmq.eventloop.zmqstream.ZMQStream(pull_sock)
        pull_sock.setsockopt(zmq.LINGER, -1)
        salt.utils.zeromq.check_ipc_path_max_len(self.pull_uri)
        # Start the minion command publisher
        log.info("Starting the Salt Publisher on %s", self.pub_uri)
        pub_sock.bind(self.pub_uri)
        # Securely create socket
        log.info("Starting the Salt Puller on %s", self.pull_uri)
        with salt.utils.files.set_umask(0o177):
            pull_sock.bind(self.pull_uri)

        @salt.ext.tornado.gen.coroutine
        def on_recv(packages):
            for package in packages:
                payload = salt.payload.loads(package)
                yield publish_payload(payload)

        pull_sock.on_recv(on_recv)
        try:
            ioloop.start()
        finally:
            pub_sock.close()
            pull_sock.close()
Beispiel #8
0
    def publish(self, load):
        '''
        Publish "load" to minions

        :param dict load: A load to be sent across the wire to minions
        '''
        payload = {'enc': 'aes'}

        crypticle = salt.crypt.Crypticle(
            self.opts, salt.master.SMaster.secrets['aes']['secret'].value)
        payload['load'] = crypticle.dumps(load)
        if self.opts['sign_pub_messages']:
            master_pem_path = os.path.join(self.opts['pki_dir'], 'master.pem')
            log.debug("Signing data packet")
            payload['sig'] = salt.crypt.sign_message(master_pem_path,
                                                     payload['load'])
        # Send 0MQ to the publisher
        context = zmq.Context(1)
        pub_sock = context.socket(zmq.PUSH)
        if self.opts.get('ipc_mode', '') == 'tcp':
            pull_uri = 'tcp://127.0.0.1:{0}'.format(
                self.opts.get('tcp_master_publish_pull', 4514))
        else:
            pull_uri = 'ipc://{0}'.format(
                os.path.join(self.opts['sock_dir'], 'publish_pull.ipc'))
        pub_sock.connect(pull_uri)
        int_payload = {'payload': self.serial.dumps(payload)}

        # add some targeting stuff for lists only (for now)
        if load['tgt_type'] == 'list':
            int_payload['topic_lst'] = load['tgt']

        # If zmq_filtering is enabled, target matching has to happen master side
        match_targets = ["pcre", "glob", "list"]
        if self.opts['zmq_filtering'] and load['tgt_type'] in match_targets:
            # Fetch a list of minions that match
            _res = self.ckminions.check_minions(load['tgt'],
                                                tgt_type=load['tgt_type'])
            match_ids = _res['minions']

            log.debug("Publish Side Match: %s", match_ids)
            # Send list of miions thru so zmq can target them
            int_payload['topic_lst'] = match_ids
        payload = self.serial.dumps(int_payload)
        log.debug(
            'Sending payload to publish daemon. jid=%s size=%d',
            load.get('jid', None),
            len(payload),
        )
        pub_sock.send(payload)
        log.debug('Sent payload to publish daemon.')

        pub_sock.close()
        context.term()
    def _proxy_logs_target(self, socket_bind_event):
        context = zmq.Context()
        out_proxy = pusher = None
        try:
            out_proxy = context.socket(zmq.PAIR)
            out_proxy.set_hwm(100000)
            proxy_port = out_proxy.bind_to_random_port("tcp://127.0.0.1")
            self.proxy_address = "tcp://127.0.0.1:{}".format(proxy_port)
        except zmq.ZMQError as exc:
            if out_proxy is not None:
                out_proxy.close(1000)
            context.term()
            sys.stderr.write(
                "Failed to bind the ZMQ PAIR socket: {}\n{}\n".format(
                    exc, traceback.format_exc(exc)))
            sys.stderr.flush()
            return

        try:
            pusher = context.socket(zmq.PUSH)
            pusher.set_hwm(100000)
            pusher.connect(self.push_address)
        except zmq.ZMQError as exc:
            if pusher is not None:
                pusher.close(1000)
            context.term()
            sys.stderr.write(
                "Failed to connect the ZMQ PUSH socket: {}\n{}\n".format(
                    exc, traceback.format_exc(exc)))
            sys.stderr.flush()

        socket_bind_event.set()

        sentinel = salt.utils.msgpack.dumps(None)
        while True:
            try:
                msg = out_proxy.recv()
                if msg == sentinel:
                    # Received sentinel to stop
                    break
                pusher.send(msg)
            except zmq.ZMQError as exc:
                sys.stderr.write(
                    "Failed to proxy log message: {}\n{}\n".format(
                        exc, traceback.format_exc(exc)))
                sys.stderr.flush()
                break

        # Close the receiving end of the PAIR proxy socket
        out_proxy.close(0)
        # Allow, the pusher queue to send any messsges in it's queue for
        # the next 1.5 seconds
        pusher.close(1500)
        context.term()
Beispiel #10
0
    def zmq_device(self):
        """
        Multiprocessing target for the zmq queue device
        """
        self.__setup_signals()
        context = zmq.Context(self.opts["worker_threads"])
        # Prepare the zeromq sockets
        self.uri = "tcp://{interface}:{ret_port}".format(**self.opts)
        self.clients = context.socket(zmq.ROUTER)
        self.clients.setsockopt(zmq.LINGER, -1)
        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)
        self.clients.setsockopt(zmq.BACKLOG,
                                self.opts.get("zmq_backlog", 1000))
        self._start_zmq_monitor()
        self.workers = context.socket(zmq.DEALER)
        self.workers.setsockopt(zmq.LINGER, -1)

        if self.opts[
                "mworker_queue_niceness"] and not salt.utils.platform.is_windows(
                ):
            log.info(
                "setting mworker_queue niceness to %d",
                self.opts["mworker_queue_niceness"],
            )
            os.nice(self.opts["mworker_queue_niceness"])

        if self.opts.get("ipc_mode", "") == "tcp":
            self.w_uri = "tcp://127.0.0.1:{}".format(
                self.opts.get("tcp_master_workers", 4515))
        else:
            self.w_uri = "ipc://{}".format(
                os.path.join(self.opts["sock_dir"], "workers.ipc"))

        log.info("Setting up the master communication server")
        log.error("ReqServer clients %s", self.uri)
        self.clients.bind(self.uri)
        log.error("ReqServer workers %s", self.w_uri)
        self.workers.bind(self.w_uri)

        while True:
            if self.clients.closed or self.workers.closed:
                break
            try:
                zmq.device(zmq.QUEUE, self.clients, self.workers)
            except zmq.ZMQError as exc:
                if exc.errno == errno.EINTR:
                    continue
                raise
            except (KeyboardInterrupt, SystemExit):
                break
        context.term()
    def start(self):
        if self.pid != os.getpid():
            self.stop()
            self._exiting = False

        if self._exiting is True:
            return

        if self.in_proxy is not None:
            return

        atexit.register(self.stop)
        context = in_proxy = None
        try:
            context = zmq.Context()
            self.context = context
        except zmq.ZMQError as exc:
            sys.stderr.write(
                "Failed to create the ZMQ Context: {}\n{}\n".format(
                    exc, traceback.format_exc(exc)))
            sys.stderr.flush()

        # Let's start the proxy thread
        socket_bind_event = threading.Event()
        self.proxy_thread = threading.Thread(target=self._proxy_logs_target,
                                             args=(socket_bind_event, ))
        self.proxy_thread.daemon = True
        self.proxy_thread.start()
        # Now that we discovered which random port to use, lest's continue with the setup
        if socket_bind_event.wait(5) is not True:
            sys.stderr.write("Failed to bind the ZMQ socket PAIR\n")
            sys.stderr.flush()
            context.term()
            return

        # And we can now also connect the messages input side of the proxy
        try:
            in_proxy = self.context.socket(zmq.PAIR)
            in_proxy.set_hwm(100000)
            in_proxy.connect(self.proxy_address)
            self.in_proxy = in_proxy
        except zmq.ZMQError as exc:
            if in_proxy is not None:
                in_proxy.close(1000)
            sys.stderr.write(
                "Failed to bind the ZMQ PAIR socket: {}\n{}\n".format(
                    exc, traceback.format_exc(exc)))
            sys.stderr.flush()
Beispiel #12
0
    def run(self):
        """
        main loop that fires the event every second
        """
        context = zmq.Context()
        # the socket for outgoing timer events
        socket = context.socket(zmq.PUB)
        socket.setsockopt(zmq.LINGER, 100)
        socket.bind("ipc://" + self.timer_sock)

        count = 0
        log.debug("ConCache-Timer started")
        while not self.stopped.wait(1):
            socket.send(salt.payload.dumps(count))

            count += 1
            if count >= 60:
                count = 0
Beispiel #13
0
    def run(self):
        '''
        main loop that fires the event every second
        '''
        context = zmq.Context()
        # the socket for outgoing timer events
        socket = context.socket(zmq.PUB)
        socket.setsockopt(zmq.LINGER, 100)
        socket.bind('ipc://' + self.timer_sock)

        count = 0
        log.debug('ConCache-Timer started')
        while not self.stopped.wait(1):
            socket.send(self.serial.dumps(count))

            count += 1
            if count >= 60:
                count = 0
Beispiel #14
0
 def pub_connect(self):
     """
     Create and connect this thread's zmq socket. If a publisher socket
     already exists "pub_close" is called before creating and connecting a
     new socket.
     """
     if self.pub_sock:
         self.pub_close()
     ctx = zmq.Context()
     self._sock_data.sock = ctx.socket(zmq.PUSH)
     self.pub_sock.setsockopt(zmq.LINGER, -1)
     if self.opts.get("ipc_mode", "") == "tcp":
         pull_uri = "tcp://127.0.0.1:{}".format(
             self.opts.get("tcp_master_publish_pull", 4514))
     else:
         pull_uri = "ipc://{}".format(
             os.path.join(self.opts["sock_dir"], "publish_pull.ipc"))
     log.debug("Connecting to pub server: %s", pull_uri)
     self.pub_sock.connect(pull_uri)
     return self._sock_data.sock
Beispiel #15
0
    def __init__(self, opts):
        """
        Sets up the zmq-connection to the ConCache
        """
        self.opts = opts
        self.serial = salt.payload.Serial(self.opts.get("serial", ""))
        self.cache_sock = os.path.join(self.opts["sock_dir"], "con_cache.ipc")
        self.cache_upd_sock = os.path.join(self.opts["sock_dir"], "con_upd.ipc")

        context = zmq.Context()

        # the socket for talking to the cache
        self.creq_out = context.socket(zmq.REQ)
        self.creq_out.setsockopt(zmq.LINGER, 100)
        self.creq_out.connect("ipc://" + self.cache_sock)

        # the socket for sending updates to the cache
        self.cupd_out = context.socket(zmq.PUB)
        self.cupd_out.setsockopt(zmq.LINGER, 1)
        self.cupd_out.connect("ipc://" + self.cache_upd_sock)
Beispiel #16
0
    def zmq_device(self):
        '''
        Multiprocessing target for the zmq queue device
        '''
        self.__setup_signals()
        salt.utils.process.appendproctitle('MWorkerQueue')
        self.context = zmq.Context(self.opts['worker_threads'])
        # Prepare the zeromq sockets
        self.uri = 'tcp://{interface}:{ret_port}'.format(**self.opts)
        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)
        self.clients.setsockopt(zmq.BACKLOG, self.opts.get('zmq_backlog', 1000))
        self._start_zmq_monitor()
        self.workers = self.context.socket(zmq.DEALER)

        if self.opts.get('ipc_mode', '') == 'tcp':
            self.w_uri = 'tcp://127.0.0.1:{0}'.format(
                self.opts.get('tcp_master_workers', 4515)
                )
        else:
            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:
            if self.clients.closed or self.workers.closed:
                break
            try:
                zmq.device(zmq.QUEUE, self.clients, self.workers)
            except zmq.ZMQError as exc:
                if exc.errno == errno.EINTR:
                    continue
                raise exc
            except (KeyboardInterrupt, SystemExit):
                break
Beispiel #17
0
    def __init__(self, opts):
        '''
        Sets up the zmq-connection to the ConCache
        '''
        self.opts = opts
        self.serial = salt.payload.Serial(self.opts.get('serial', ''))
        self.cache_sock = os.path.join(self.opts['sock_dir'], 'con_cache.ipc')
        self.cache_upd_sock = os.path.join(
            self.opts['sock_dir'], 'con_upd.ipc')

        context = zmq.Context()

        # the socket for talking to the cache
        self.creq_out = context.socket(zmq.REQ)
        self.creq_out.setsockopt(zmq.LINGER, 100)
        self.creq_out.connect('ipc://' + self.cache_sock)

        # the socket for sending updates to the cache
        self.cupd_out = context.socket(zmq.PUB)
        self.cupd_out.setsockopt(zmq.LINGER, 1)
        self.cupd_out.connect('ipc://' + self.cache_upd_sock)
Beispiel #18
0
    def run(self):
        '''
        Main loop of the ConCache, starts updates in intervals and
        answers requests from the MWorkers
        '''
        context = zmq.Context()
        # the socket for incoming cache requests
        creq_in = context.socket(zmq.REP)
        creq_in.setsockopt(zmq.LINGER, 100)
        creq_in.bind('ipc://' + self.cache_sock)

        # the socket for incoming cache-updates from workers
        cupd_in = context.socket(zmq.SUB)
        cupd_in.setsockopt(zmq.SUBSCRIBE, b'')
        cupd_in.setsockopt(zmq.LINGER, 100)
        cupd_in.bind('ipc://' + self.update_sock)

        # the socket for the timer-event
        timer_in = context.socket(zmq.SUB)
        timer_in.setsockopt(zmq.SUBSCRIBE, b'')
        timer_in.setsockopt(zmq.LINGER, 100)
        timer_in.connect('ipc://' + self.upd_t_sock)

        poller = zmq.Poller()
        poller.register(creq_in, zmq.POLLIN)
        poller.register(cupd_in, zmq.POLLIN)
        poller.register(timer_in, zmq.POLLIN)

        # our serializer
        serial = salt.payload.Serial(self.opts.get('serial', ''))

        # register a signal handler
        signal.signal(signal.SIGINT, self.signal_handler)

        # secure the sockets from the world
        self.secure()

        log.info('ConCache started')

        while self.running:

            # we check for new events with the poller
            try:
                socks = dict(poller.poll(1))
            except KeyboardInterrupt:
                self.stop()
            except zmq.ZMQError as zmq_err:
                log.error('ConCache ZeroMQ-Error occurred')
                log.exception(zmq_err)
                self.stop()

            # check for next cache-request
            if socks.get(creq_in) == zmq.POLLIN:
                msg = serial.loads(creq_in.recv())
                log.debug('ConCache Received request: %s', msg)

                # requests to the minion list are send as str's
                if isinstance(msg, six.string_types):
                    if msg == 'minions':
                        # Send reply back to client
                        reply = serial.dumps(self.minions)
                        creq_in.send(reply)

            # check for next cache-update from workers
            if socks.get(cupd_in) == zmq.POLLIN:
                new_c_data = serial.loads(cupd_in.recv())
                # tell the worker to exit
                #cupd_in.send(serial.dumps('ACK'))

                # check if the returned data is usable
                if not isinstance(new_c_data, list):
                    log.error('ConCache Worker returned unusable result')
                    del new_c_data
                    continue

                # the cache will receive lists of minions
                # 1. if the list only has 1 item, its from an MWorker, we append it
                # 2. if the list contains another list, its from a CacheWorker and
                #    the currently cached minions are replaced with that list
                # 3. anything else is considered malformed

                try:

                    if not new_c_data:
                        log.debug('ConCache Got empty update from worker')
                        continue

                    data = new_c_data[0]

                    if isinstance(data, six.string_types):
                        if data not in self.minions:
                            log.debug('ConCache Adding minion %s to cache',
                                      new_c_data[0])
                            self.minions.append(data)

                    elif isinstance(data, list):
                        log.debug('ConCache Replacing minion list from worker')
                        self.minions = data

                except IndexError:
                    log.debug('ConCache Got malformed result dict from worker')
                    del new_c_data

                log.info('ConCache %s entries in cache', len(self.minions))

            # check for next timer-event to start new jobs
            if socks.get(timer_in) == zmq.POLLIN:
                sec_event = serial.loads(timer_in.recv())

                # update the list every 30 seconds
                if int(sec_event % 30) == 0:
                    cw = CacheWorker(self.opts)
                    cw.start()

        self.stop()
        creq_in.close()
        cupd_in.close()
        timer_in.close()
        context.term()
        log.debug('ConCache Shutting down')
Beispiel #19
0
    def _publish_daemon(self, log_queue=None):
        """
        Bind to the interface specified in the configuration file
        """
        salt.utils.process.appendproctitle(self.__class__.__name__)

        if self.opts["pub_server_niceness"] and not salt.utils.platform.is_windows():
            log.info(
                "setting Publish daemon niceness to %i",
                self.opts["pub_server_niceness"],
            )
            os.nice(self.opts["pub_server_niceness"])

        if log_queue:
            salt.log.setup.set_multiprocessing_logging_queue(log_queue)
            salt.log.setup.setup_multiprocessing_logging(log_queue)

        # Set up the context
        context = zmq.Context(1)
        # Prepare minion publish socket
        pub_sock = context.socket(zmq.PUB)
        _set_tcp_keepalive(pub_sock, self.opts)
        # if 2.1 >= zmq < 3.0, we only have one HWM setting
        try:
            pub_sock.setsockopt(zmq.HWM, self.opts.get("pub_hwm", 1000))
        # in zmq >= 3.0, there are separate send and receive HWM settings
        except AttributeError:
            # Set the High Water Marks. For more information on HWM, see:
            # http://api.zeromq.org/4-1:zmq-setsockopt
            pub_sock.setsockopt(zmq.SNDHWM, self.opts.get("pub_hwm", 1000))
            pub_sock.setsockopt(zmq.RCVHWM, self.opts.get("pub_hwm", 1000))
        if self.opts["ipv6"] is True and hasattr(zmq, "IPV4ONLY"):
            # IPv6 sockets work for both IPv6 and IPv4 addresses
            pub_sock.setsockopt(zmq.IPV4ONLY, 0)
        pub_sock.setsockopt(zmq.BACKLOG, self.opts.get("zmq_backlog", 1000))
        pub_sock.setsockopt(zmq.LINGER, -1)
        pub_uri = "tcp://{interface}:{publish_port}".format(**self.opts)
        # Prepare minion pull socket
        pull_sock = context.socket(zmq.PULL)
        pull_sock.setsockopt(zmq.LINGER, -1)

        if self.opts.get("ipc_mode", "") == "tcp":
            pull_uri = "tcp://127.0.0.1:{}".format(
                self.opts.get("tcp_master_publish_pull", 4514)
            )
        else:
            pull_uri = "ipc://{}".format(
                os.path.join(self.opts["sock_dir"], "publish_pull.ipc")
            )
        salt.utils.zeromq.check_ipc_path_max_len(pull_uri)

        # Start the minion command publisher
        log.info("Starting the Salt Publisher on %s", pub_uri)
        pub_sock.bind(pub_uri)

        # Securely create socket
        log.info("Starting the Salt Puller on %s", pull_uri)
        with salt.utils.files.set_umask(0o177):
            pull_sock.bind(pull_uri)

        try:
            while True:
                # Catch and handle EINTR from when this process is sent
                # SIGUSR1 gracefully so we don't choke and die horribly
                try:
                    log.debug("Publish daemon getting data from puller %s", pull_uri)
                    package = pull_sock.recv()
                    log.debug("Publish daemon received payload. size=%d", len(package))

                    unpacked_package = salt.payload.unpackage(package)
                    unpacked_package = salt.transport.frame.decode_embedded_strs(
                        unpacked_package
                    )
                    payload = unpacked_package["payload"]
                    log.trace("Accepted unpacked package from puller")
                    if self.opts["zmq_filtering"]:
                        # if you have a specific topic list, use that
                        if "topic_lst" in unpacked_package:
                            for topic in unpacked_package["topic_lst"]:
                                log.trace(
                                    "Sending filtered data over publisher %s", pub_uri
                                )
                                # zmq filters are substring match, hash the topic
                                # to avoid collisions
                                htopic = salt.utils.stringutils.to_bytes(
                                    hashlib.sha1(
                                        salt.utils.stringutils.to_bytes(topic)
                                    ).hexdigest()
                                )
                                pub_sock.send(htopic, flags=zmq.SNDMORE)
                                pub_sock.send(payload)
                                log.trace("Filtered data has been sent")

                            # Syndic broadcast
                            if self.opts.get("order_masters"):
                                log.trace("Sending filtered data to syndic")
                                pub_sock.send(b"syndic", flags=zmq.SNDMORE)
                                pub_sock.send(payload)
                                log.trace("Filtered data has been sent to syndic")
                        # otherwise its a broadcast
                        else:
                            # TODO: constants file for "broadcast"
                            log.trace(
                                "Sending broadcasted data over publisher %s", pub_uri
                            )
                            pub_sock.send(b"broadcast", flags=zmq.SNDMORE)
                            pub_sock.send(payload)
                            log.trace("Broadcasted data has been sent")
                    else:
                        log.trace(
                            "Sending ZMQ-unfiltered data over publisher %s", pub_uri
                        )
                        pub_sock.send(payload)
                        log.trace("Unfiltered data has been sent")
                except zmq.ZMQError as exc:
                    if exc.errno == errno.EINTR:
                        continue
                    raise

        except KeyboardInterrupt:
            log.trace("Publish daemon caught Keyboard interupt, tearing down")
        # Cleanly close the sockets if we're shutting down
        if pub_sock.closed is False:
            pub_sock.close()
        if pull_sock.closed is False:
            pull_sock.close()
        if context.closed is False:
            context.term()
Beispiel #20
0
    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
            six.reraise(*sys.exc_info())
Beispiel #21
0
    def __init__(self,
                 opts,
                 **kwargs):
        self.opts = opts
        self.ttype = 'zeromq'
        self.io_loop = kwargs.get('io_loop')

        if self.io_loop is None:
            install_zmq()
            self.io_loop = ZMQDefaultLoop.current()

        self.hexid = hashlib.sha1(salt.utils.stringutils.to_bytes(self.opts['id'])).hexdigest()
        self.auth = salt.crypt.AsyncAuth(self.opts, io_loop=self.io_loop)
        self.serial = salt.payload.Serial(self.opts)
        self.context = zmq.Context()
        self._socket = self.context.socket(zmq.SUB)

        if self.opts['zmq_filtering']:
            # TODO: constants file for "broadcast"
            self._socket.setsockopt(zmq.SUBSCRIBE, b'broadcast')
            if self.opts.get('__role') == 'syndic':
                self._socket.setsockopt(zmq.SUBSCRIBE, b'syndic')
            else:
                self._socket.setsockopt(
                    zmq.SUBSCRIBE,
                    salt.utils.stringutils.to_bytes(self.hexid)
                )
        else:
            self._socket.setsockopt(zmq.SUBSCRIBE, b'')

        self._socket.setsockopt(zmq.IDENTITY, salt.utils.stringutils.to_bytes(self.opts['id']))

        # TODO: cleanup all the socket opts stuff
        if hasattr(zmq, 'TCP_KEEPALIVE'):
            self._socket.setsockopt(
                zmq.TCP_KEEPALIVE, self.opts['tcp_keepalive']
            )
            self._socket.setsockopt(
                zmq.TCP_KEEPALIVE_IDLE, self.opts['tcp_keepalive_idle']
            )
            self._socket.setsockopt(
                zmq.TCP_KEEPALIVE_CNT, self.opts['tcp_keepalive_cnt']
            )
            self._socket.setsockopt(
                zmq.TCP_KEEPALIVE_INTVL, self.opts['tcp_keepalive_intvl']
            )

        recon_delay = self.opts['recon_default']

        if self.opts['recon_randomize']:
            recon_delay = randint(self.opts['recon_default'],
                                  self.opts['recon_default'] + self.opts['recon_max'])

            log.debug(
                "Generated random reconnect delay between '%sms' and '%sms' (%s)",
                self.opts['recon_default'],
                self.opts['recon_default'] + self.opts['recon_max'],
                recon_delay
            )

        log.debug("Setting zmq_reconnect_ivl to '%sms'", recon_delay)
        self._socket.setsockopt(zmq.RECONNECT_IVL, recon_delay)

        if hasattr(zmq, 'RECONNECT_IVL_MAX'):
            log.debug(
                "Setting zmq_reconnect_ivl_max to '%sms'",
                self.opts['recon_default'] + self.opts['recon_max']
            )

            self._socket.setsockopt(
                zmq.RECONNECT_IVL_MAX, self.opts['recon_max']
            )

        if (self.opts['ipv6'] is True or ':' in self.opts['master_ip']) and hasattr(zmq, 'IPV4ONLY'):
            # IPv6 sockets work for both IPv6 and IPv4 addresses
            self._socket.setsockopt(zmq.IPV4ONLY, 0)

        if HAS_ZMQ_MONITOR and self.opts['zmq_monitor']:
            self._monitor = ZeroMQSocketMonitor(self._socket)
            self._monitor.start_io_loop(self.io_loop)
Beispiel #22
0
    def __init__(self, opts, io_loop, **kwargs):
        super().__init__(opts, io_loop, **kwargs)
        self.opts = opts
        self.io_loop = io_loop
        self.hexid = hashlib.sha1(
            salt.utils.stringutils.to_bytes(self.opts["id"])).hexdigest()
        self._closing = False
        self.context = zmq.Context()
        self._socket = self.context.socket(zmq.SUB)
        if self.opts["zmq_filtering"]:
            # TODO: constants file for "broadcast"
            self._socket.setsockopt(zmq.SUBSCRIBE, b"broadcast")
            if self.opts.get("__role") == "syndic":
                self._socket.setsockopt(zmq.SUBSCRIBE, b"syndic")
            else:
                self._socket.setsockopt(
                    zmq.SUBSCRIBE, salt.utils.stringutils.to_bytes(self.hexid))
        else:
            self._socket.setsockopt(zmq.SUBSCRIBE, b"")

        self._socket.setsockopt(
            zmq.IDENTITY, salt.utils.stringutils.to_bytes(self.opts["id"]))

        # TODO: cleanup all the socket opts stuff
        if hasattr(zmq, "TCP_KEEPALIVE"):
            self._socket.setsockopt(zmq.TCP_KEEPALIVE,
                                    self.opts["tcp_keepalive"])
            self._socket.setsockopt(zmq.TCP_KEEPALIVE_IDLE,
                                    self.opts["tcp_keepalive_idle"])
            self._socket.setsockopt(zmq.TCP_KEEPALIVE_CNT,
                                    self.opts["tcp_keepalive_cnt"])
            self._socket.setsockopt(zmq.TCP_KEEPALIVE_INTVL,
                                    self.opts["tcp_keepalive_intvl"])

        recon_delay = self.opts["recon_default"]

        if self.opts["recon_randomize"]:
            recon_delay = randint(
                self.opts["recon_default"],
                self.opts["recon_default"] + self.opts["recon_max"],
            )

            log.debug(
                "Generated random reconnect delay between '%sms' and '%sms' (%s)",
                self.opts["recon_default"],
                self.opts["recon_default"] + self.opts["recon_max"],
                recon_delay,
            )

        log.debug("Setting zmq_reconnect_ivl to '%sms'", recon_delay)
        self._socket.setsockopt(zmq.RECONNECT_IVL, recon_delay)

        if hasattr(zmq, "RECONNECT_IVL_MAX"):
            log.debug(
                "Setting zmq_reconnect_ivl_max to '%sms'",
                self.opts["recon_default"] + self.opts["recon_max"],
            )

            self._socket.setsockopt(zmq.RECONNECT_IVL_MAX,
                                    self.opts["recon_max"])

        if (self.opts["ipv6"] is True
                or ":" in self.opts["master_ip"]) and hasattr(zmq, "IPV4ONLY"):
            # IPv6 sockets work for both IPv6 and IPv4 addresses
            self._socket.setsockopt(zmq.IPV4ONLY, 0)

        if HAS_ZMQ_MONITOR and self.opts["zmq_monitor"]:
            self._monitor = ZeroMQSocketMonitor(self._socket)
            self._monitor.start_io_loop(self.io_loop)
Beispiel #23
0
    def _publish_daemon(self):
        '''
        Bind to the interface specified in the configuration file
        '''
        salt.utils.process.appendproctitle(self.__class__.__name__)
        # Set up the context
        context = zmq.Context(1)
        # Prepare minion publish socket
        pub_sock = context.socket(zmq.PUB)
        _set_tcp_keepalive(pub_sock, self.opts)
        # if 2.1 >= zmq < 3.0, we only have one HWM setting
        try:
            pub_sock.setsockopt(zmq.HWM, self.opts.get('pub_hwm', 1000))
        # in zmq >= 3.0, there are separate send and receive HWM settings
        except AttributeError:
            # Set the High Water Marks. For more information on HWM, see:
            # http://api.zeromq.org/4-1:zmq-setsockopt
            pub_sock.setsockopt(zmq.SNDHWM, self.opts.get('pub_hwm', 1000))
            pub_sock.setsockopt(zmq.RCVHWM, self.opts.get('pub_hwm', 1000))
        if self.opts['ipv6'] is True and hasattr(zmq, 'IPV4ONLY'):
            # IPv6 sockets work for both IPv6 and IPv4 addresses
            pub_sock.setsockopt(zmq.IPV4ONLY, 0)
        pub_sock.setsockopt(zmq.BACKLOG, self.opts.get('zmq_backlog', 1000))
        pub_uri = 'tcp://{interface}:{publish_port}'.format(**self.opts)
        # Prepare minion pull socket
        pull_sock = context.socket(zmq.PULL)

        if self.opts.get('ipc_mode', '') == 'tcp':
            pull_uri = 'tcp://127.0.0.1:{0}'.format(
                self.opts.get('tcp_master_publish_pull', 4514)
                )
        else:
            pull_uri = 'ipc://{0}'.format(
                os.path.join(self.opts['sock_dir'], 'publish_pull.ipc')
                )
        salt.utils.zeromq.check_ipc_path_max_len(pull_uri)

        # Start the minion command publisher
        log.info('Starting the Salt Publisher on %s', pub_uri)
        pub_sock.bind(pub_uri)

        # Securely create socket
        log.info('Starting the Salt Puller on %s', pull_uri)
        with salt.utils.files.set_umask(0o177):
            pull_sock.bind(pull_uri)

        try:
            while True:
                # Catch and handle EINTR from when this process is sent
                # SIGUSR1 gracefully so we don't choke and die horribly
                try:
                    log.trace('Getting data from puller %s', pull_uri)
                    package = pull_sock.recv()
                    unpacked_package = salt.payload.unpackage(package)
                    if six.PY3:
                        unpacked_package = salt.transport.frame.decode_embedded_strs(unpacked_package)
                    payload = unpacked_package['payload']
                    log.trace('Accepted unpacked package from puller')
                    if self.opts['zmq_filtering']:
                        # if you have a specific topic list, use that
                        if 'topic_lst' in unpacked_package:
                            for topic in unpacked_package['topic_lst']:
                                log.trace('Sending filtered data over publisher %s', pub_uri)
                                # zmq filters are substring match, hash the topic
                                # to avoid collisions
                                htopic = salt.utils.stringutils.to_bytes(hashlib.sha1(topic).hexdigest())
                                pub_sock.send(htopic, flags=zmq.SNDMORE)
                                pub_sock.send(payload)
                                log.trace('Filtered data has been sent')

                            # Syndic broadcast
                            if self.opts.get('order_masters'):
                                log.trace('Sending filtered data to syndic')
                                pub_sock.send(b'syndic', flags=zmq.SNDMORE)
                                pub_sock.send(payload)
                                log.trace('Filtered data has been sent to syndic')
                        # otherwise its a broadcast
                        else:
                            # TODO: constants file for "broadcast"
                            log.trace('Sending broadcasted data over publisher %s', pub_uri)
                            pub_sock.send(b'broadcast', flags=zmq.SNDMORE)
                            pub_sock.send(payload)
                            log.trace('Broadcasted data has been sent')
                    else:
                        log.trace('Sending ZMQ-unfiltered data over publisher %s', pub_uri)
                        pub_sock.send(payload)
                        log.trace('Unfiltered data has been sent')
                except zmq.ZMQError as exc:
                    if exc.errno == errno.EINTR:
                        continue
                    raise exc

        except KeyboardInterrupt:
            # Cleanly close the sockets if we're shutting down
            if pub_sock.closed is False:
                pub_sock.setsockopt(zmq.LINGER, 1)
                pub_sock.close()
            if pull_sock.closed is False:
                pull_sock.setsockopt(zmq.LINGER, 1)
                pull_sock.close()
            if context.closed is False:
                context.term()