示例#1
0
 def __init__(self, daemon, address, serializer):
     BaseServer.__init__(self, daemon, address, serializer)
     host, port = socket.gethostbyname(address[0]), address[1]
     self.sock = nicos_zmq_ctx.socket(zmq.ROUTER)
     self.sock.bind('tcp://%s:%s' % (host, port))
     self.event_queue = queue.Queue()
     self.event_sock = nicos_zmq_ctx.socket(zmq.PUB)
     self.event_sock.bind('tcp://%s:%s' % (host, port + 1))
     self.handlers = {}
     self.handler_ident = 0
     self.handler_lock = threading.Lock()
     self._stoprequest = False
示例#2
0
 def __init__(self, client_id, server):
     self.client_id = client_id
     self.ident = server.handler_ident  # only for logging purposes
     self.unregister = server.clear_handler
     self.command_queue = queue.Queue()
     self.reply_sender = nicos_zmq_ctx.socket(zmq.PUSH)
     self.reply_sender.connect('inproc://daemon_reply')
     self.serializer = server.serializer
     self.clientnames = []
     ConnectionHandler.__init__(self, server.daemon)
示例#3
0
    def start(self, interval):
        createThread('daemon event sender', self.event_sender)
        # TODO:
        # * clean up unused handlers (when?)
        # * more zmq inproc sockets and proxies instead of queues?
        # * useful and comprehensive error handling
        reply_collect = nicos_zmq_ctx.socket(zmq.PULL)
        reply_collect.bind('inproc://daemon_reply')

        poller = zmq.Poller()
        poller.register(self.sock, zmq.POLLIN)
        poller.register(reply_collect, zmq.POLLIN)

        # ZeroMQ expects a poll timeout given in msec. interval is passed
        # through in seconds.
        interval_ms = interval * 1000

        while not self._stoprequest:
            for (sock, _) in poller.poll(interval_ms):
                # reply? pass it through
                if sock is reply_collect:
                    self.sock.send_multipart(reply_collect.recv_multipart())
                    continue
                # otherwise, must be message from a client
                msg = self.sock.recv_multipart()
                client_id = msg[0]
                if client_id in self.handlers:
                    self.handlers[client_id].command_queue.put(msg)
                elif msg[2] == b'getbanner':
                    # new connection, create a handler
                    self.handler_ident += 1
                    handler = ServerTransport(client_id, self)
                    with self.handler_lock:
                        self.handlers[client_id] = handler
                    createThread('handler %d' % self.handler_ident,
                                 handler.handle_loop)
                else:
                    # all other messages: client must initiate connection first
                    self.sock.send_multipart([client_id, b'', b'error', b'',
                                              b'"session expired"'])
示例#4
0
 def _target(self, sandbox, uuid, code, setups, user, emitter, args, quiet):
     socket = nicos_zmq_ctx.socket(zmq.DEALER)
     poller = zmq.Poller()
     poller.register(socket, zmq.POLLIN)
     if sandbox:
         # create a new temporary directory for the sandbox helper to
         # mount the filesystem
         tempdir = tempfile.mkdtemp()
         rootdir = path.join(tempdir, 'root')
         os.mkdir(rootdir)
         # since the sandbox does not have TCP connection, use a Unix socket
         sockname = 'ipc://' + path.join(tempdir, 'sock')
         socket.bind(sockname)
         prefixargs = [sandbox, rootdir, str(os.getuid()), str(os.getgid())]
     else:
         port = socket.bind_to_random_port('tcp://127.0.0.1')
         sockname = 'tcp://127.0.0.1:%s' % port
         prefixargs = []
     scriptname = path.join(config.nicos_root, 'bin', 'nicos-simulate')
     userstr = '%s,%d' % (user.name, user.level)
     if quiet:
         args.append('--quiet')
     if config.sandbox_simulation_debug:
         args.append('--debug')
     proc = createSubprocess(prefixargs + [
         sys.executable, scriptname, sockname, uuid, ','.join(setups),
         userstr, code
     ] + args)
     if sandbox:
         if not session.current_sysconfig.get('cache'):
             raise NicosError('no cache is configured')
         socket.send(pickle.dumps(session.cache.get_values()))
     else:
         # let the subprocess connect to the cache
         socket.send(b'')
     while True:
         res = poller.poll(500)
         if not res:
             if proc.poll() is not None:
                 if emitter:
                     request = emitter.current_script()
                     if request.reqid == uuid:
                         request.setSimstate('failed')
                         request.emitETA(emitter._controller)
                 if not quiet:
                     session.log.warning('Dry run has terminated '
                                         'prematurely')
                 return
             continue
         msgtype, msg = unserialize(socket.recv())
         if msgtype == SIM_MESSAGE:
             if emitter:
                 emitter.emit_event('simmessage', msg)
             else:
                 record = logging.LogRecord(msg[0], msg[2], '', 0, msg[3],
                                            (), None)
                 record.message = msg[3].rstrip()
                 session.log.handle(record)
         elif msgtype == SIM_BLOCK_RES:
             if emitter:
                 block, duration, uuid = msg
                 request = emitter.current_script()
                 if request.reqid == uuid:
                     request.updateRuntime(block, duration)
         elif msgtype == SIM_END_RES:
             if emitter:
                 if not quiet:
                     emitter.emit_event('simresult', msg)
                 request = emitter.current_script()
                 if request.reqid == uuid:
                     request.setSimstate('success')
                     request.emitETA(emitter._controller)
             # In the console session, the summary is printed by the
             # sim() command.
             socket.close()
             break
     # wait for the process, but only for 5 seconds after the result
     # has arrived
     wait_start = time.time()
     try:
         # Python 3.x has a timeout argument for poll()...
         while time.time() < wait_start + 5:
             if proc.poll() is not None:
                 break
         else:
             raise Exception('did not terminate within 5 seconds')
     except Exception:
         session.log.exception('Error waiting for dry run process')
     if sandbox:
         try:
             os.rmdir(rootdir)
             os.rmdir(tempdir)
         except Exception:
             pass
示例#5
0
    def run(cls, sock, uuid, setups, user, code, quiet=False, debug=False):
        session.__class__ = cls
        session._is_sandboxed = sock.startswith('ipc://')
        session._debug_log = debug

        socket = nicos_zmq_ctx.socket(zmq.DEALER)
        socket.connect(sock)

        # we either get an empty message (retrieve cache data ourselves)
        # or a pickled key-value database
        data = socket.recv()
        db = pickle.loads(data) if data else None

        # send log messages back to daemon if requested
        session.log_sender = SimLogSender(socket, session, uuid, quiet)

        username, level = user.rsplit(',', 1)
        session._user = User(username, int(level))

        try:
            session.__init__(SIMULATION)
        except Exception as err:
            try:
                session.log.exception('Fatal error while initializing')
            finally:
                print('Fatal error while initializing:', err, file=sys.stderr)
            return 1

        # Give a sign of life and then tell the log handler to only log
        # errors during setup.
        session.log.info('setting up dry run...')
        session.begin_setup()
        # Handle "print" statements in the script.
        sys.stdout = LoggingStdout(sys.stdout)

        try:
            # Initialize the session in simulation mode.
            session._mode = SIMULATION

            # Load the setups from the original system, this should give the
            # information about the cache address.
            session.log.info('loading simulation mode setups: %s',
                             ', '.join(setups))
            session.loadSetup(setups, allow_startupcode=False)

            # Synchronize setups and cache values.
            session.log.info('synchronizing to master session')
            session.simulationSync(db)

            # Set session to always abort on errors.
            session.experiment.errorbehavior = 'abort'
        except:  # really *all* exceptions -- pylint: disable=W0702
            session.log.exception('Exception in dry run setup')
            session.log_sender.finish()
            session.shutdown()
            return 1

        # Set up log handlers to output everything.
        session.log_sender.begin_exec()
        # Execute the script code.
        exception = False
        try:
            last_clock = session.clock.time
            code, _ = parseScript(code)
            for i, c in enumerate(code):
                exec_(c, session.namespace)
                time = session.clock.time - last_clock
                last_clock = session.clock.time
                session.log_sender.send_block_result(i, time)
        except Abort:
            session.log.info('Dry run finished by abort()')
        except:  # pylint: disable=W0702
            session.log.exception('Exception in dry run')
            exception = True
        else:
            session.log.info('Dry run finished')
        finally:
            session.log_sender.finish(exception)

        # Shut down.
        session.shutdown()