示例#1
0
    def clearProcessLogs(self, name):
        """ Clear the stdout and stderr logs for the named process and
        reopen them.

        @param string name   The name of the process (or 'group:name')
        @return boolean result      Always True unless error
        """
        self._update('clearProcessLogs')

        group, process = self._getGroupAndProcess(name)

        if process is None:
            raise RPCError(Faults.BAD_NAME, name)

        try:
            # implies a reopen
            process.removelogs()
        except (IOError, OSError):
            raise RPCError(Faults.FAILED, name)

        return True
示例#2
0
 def _makeConfigParser(self, section_name, options):
     """ Populate a new UnhosedConfigParser instance with a
     section built from an options dict.
     """
     config = UnhosedConfigParser()
     try:
         config.add_section(section_name)
         for k, v in dict(options).items():
             config.set(section_name, k, v)
     except (TypeError, ValueError):
         raise RPCError(SupervisorFaults.INCORRECT_PARAMETERS)
     return config
    def removeProcessFromGroup(self, group_name, process_name):
        self._update('removeProcessFromGroup')
        group = self._getProcessGroup(group_name)

        # check process exists and is running
        process = group.processes.get(process_name)
        if process is None:
            raise RPCError(SupervisorFaults.BAD_NAME, process_name)

        if process.pid or process.state not in STOPPED_STATES:
            raise RPCError(SupervisorFaults.STILL_RUNNING, process_name)

        group.transition()

        # del process config from group, then del process
        for index, config in enumerate(group.config.process_configs):
            if config.name == process_name:
                del group.config.process_configs[index]

        del group.processes[process_name]
        return True
示例#4
0
    def _tailProcessLog(self, name, offset, length, channel):
        group, process = self._getGroupAndProcess(name)

        if process is None:
            raise RPCError(Faults.BAD_NAME, name)

        logfile = getattr(process.config, '%s_logfile' % channel)

        if logfile is None or not os.path.exists(logfile):
            return ['', 0, False]

        return tailFile(logfile, int(offset), int(length))
    def log(self, message, level=supervisor.loggers.LevelsByName.INFO):
        self._update('log')

        if isinstance(level, str):
            level = getattr(supervisor.loggers.LevelsByName, level.upper(),
                            None)

        if supervisor.loggers.LOG_LEVELS_BY_NUM.get(level, None) is None:
            raise RPCError(SupervisorFaults.INCORRECT_PARAMETERS)

        self.supervisord.options.logger.log(level, message)
        return True
示例#6
0
        def killit():
            if not called:
                if process.get_state() not in RUNNING_STATES:
                    raise RPCError(Faults.NOT_RUNNING)
                # use a mutable for lexical scoping; see startProcess
                called.append(1)

            if not killed:
                kill(process.pid, sig)
                killed.append(1)

            return True
示例#7
0
    def sendProcessStdin(self, name, chars):
        """ Send a string of chars to the stdin of the process name.
        If non-7-bit data is sent (unicode), it is encoded to utf-8
        before being sent to the process' stdin.  If chars is not a
        string or is not unicode, raise INCORRECT_PARAMETERS.  If the
        process is not running, raise NOT_RUNNING.  If the process'
        stdin cannot accept input (e.g. it was closed by the child
        process), raise NO_FILE.

        @param string name        The process name to send to (or 'group:name')
        @param string chars       The character data to send to the process
        @return boolean result    Always return True unless error
        """
        self._update('sendProcessStdin')

        if isinstance(chars, unicode):
            chars = chars.encode('utf-8')

        if not isinstance(chars, basestring):
            raise RPCError(Faults.INCORRECT_PARAMETERS, chars)

        group, process = self._getGroupAndProcess(name)

        if process is None:
            raise RPCError(Faults.BAD_NAME, name)

        if not process.pid or process.killing:
            raise RPCError(Faults.NOT_RUNNING, name)

        try:
            process.write(chars)
        except OSError:
            why = sys.exc_info()[1]
            if why.args[0] == errno.EPIPE:
                raise RPCError(Faults.NO_FILE, name)
            else:
                raise

        return True
示例#8
0
    def clearLog(self):
        """ Clear the main log.

        @return boolean result always returns True unless error
        """
        self._update('clearLog')

        logfile = self.supervisord.options.logfile
        if logfile is None or not self.supervisord.options.exists(logfile):
            raise RPCError(Faults.NO_FILE)

        # there is a race condition here, but ignore it.
        try:
            self.supervisord.options.remove(logfile)
        except (OSError, IOError):
            raise RPCError(Faults.FAILED)

        for handler in self.supervisord.options.logger.handlers:
            if hasattr(handler, 'reopen'):
                self.supervisord.options.logger.info('reopening log file')
                handler.reopen()
        return True
示例#9
0
    def fetch(self, key):
        """ Retrieve data from cache stored under 'key'

        @param  string key  The cache key
        @return string      Cache data stored at key
        """
        self._update('fetch')
        self._validateKey(key)

        data = self.cache.get(key)
        if data is None:
            raise RPCError(Faults.BAD_NAME)
        return data
示例#10
0
    def get_address_info(self, address_name):
        """ Get information about the **Supvisors** instance running on the host named address_name.

        *@param* ``str address_name``: the address name where the Supervisor daemon is running.

        *@throws* ``RPCError``: with code ``Faults.BAD_ADDRESS`` if address name is unknown to **Supvisors**.

        *@return* ``dict``: a structure containing data about the **Supvisors** instance.
        """
        try:
            status = self.context.addresses[address_name]
        except KeyError:
            raise RPCError(Faults.BAD_ADDRESS, 'address {} unknown in Supvisors'.format(address_name))
        return status.serial()
示例#11
0
        def killit():
            if not called:
                if process.get_state() not in RUNNING_STATES:
                    raise RPCError(Faults.NOT_RUNNING)
                # use a mutable for lexical scoping; see startProcess
                called.append(1)

            if not stopped:
                msg = process.stop()
                if msg is not None:
                    raise RPCError(Faults.FAILED, msg)
                stopped.append(1)

                if wait:
                    return NOT_DONE_YET
                else:
                    return True

            if process.get_state() not in (ProcessStates.STOPPED,
                                           ProcessStates.EXITED):
                return NOT_DONE_YET
            else:
                return True
示例#12
0
    def _get_process_group(self, group_name, create_group_if_not_exists=True):
        """
        Retrieves the process group config for a specified process group.
        
        Args:
            group_name (str): The name of the process group to get.

        Returns:
            (ProcessGroupConfig): The process group configuration
        """
        if not self.hasGroup(group_name):
            if create_group_if_not_exists:
                self.addGroup(group_name)
            else:
                raise RPCError(Faults.BAD_NAME, 'group: %s' % group_name)
        return self.supervisord.process_groups.get(group_name)
示例#13
0
    def getProcessInfo(self, name):
        """ Get info about a process named name

        @param string name The name of the process (or 'group:name')
        @return struct result     A structure containing data about the process
        """
        self._update('getProcessInfo')

        group, process = self._getGroupAndProcess(name)

        if process is None:
            raise RPCError(Faults.BAD_NAME, name)

        # TODO timestamps are returned as xml-rpc integers for b/c but will
        # saturate the xml-rpc integer type in jan 2038 ("year 2038 problem").
        # future api versions should return timestamps as a different type.
        start = capped_int(process.laststart)
        stop = capped_int(process.laststop)
        now = capped_int(self._now())

        state = process.get_state()
        spawnerr = process.spawnerr or ''
        exitstatus = process.exitstatus or 0
        stdout_logfile = process.config.stdout_logfile or ''
        stderr_logfile = process.config.stderr_logfile or ''

        info = {
            'name':process.config.name,
            'group':group.config.name,
            'start':start,
            'stop':stop,
            'now':now,
            'state':state,
            'statename':getProcessStateDescription(state),
            'spawnerr':spawnerr,
            'exitstatus':exitstatus,
            'logfile':stdout_logfile, # b/c alias
            'stdout_logfile':stdout_logfile,
            'stderr_logfile':stderr_logfile,
            'pid':process.pid,
            }

        description = self._interpretProcessInfo(info)
        info['description'] = description
        return info
示例#14
0
    def reloadConfig(self):
        """
        Reload configuration

        @return boolean result  always return True unless error
        """
        self._update('reloadConfig')
        try:
            self.supervisord.options.process_config(do_usage=False)
        except ValueError as msg:
            raise RPCError(Faults.CANT_REREAD, msg)

        added, changed, removed = self.supervisord.diff_to_active()

        added = [group.name for group in added]
        changed = [group.name for group in changed]
        removed = [group.name for group in removed]
        return [[added, changed, removed]]  # cannot return len > 1, apparently
示例#15
0
    def getProcessInfo(self, name):
        """ Get info about a process named name

        @param string name The name of the process (or 'group:name')
        @return struct result     A structure containing data about the process
        """
        self._update('getProcessInfo')

        group, process = self._getGroupAndProcess(name)
        if process is None:
            return self._getGroupProcessInfo(group)

        if process is None:
            raise RPCError(Faults.BAD_NAME, name)

        start = int(process.laststart)
        stop = int(process.laststop)
        now = int(time.time())

        state = process.get_state()
        spawnerr = process.spawnerr or ''
        exitstatus = process.exitstatus or 0
        stdout_logfile = process.config.stdout_logfile or ''
        stderr_logfile = process.config.stderr_logfile or ''

        info = {
            'name': process.config.name,
            'group': group.config.name,
            'start': start,
            'stop': stop,
            'now': now,
            'state': state,
            'statename': getProcessStateDescription(state),
            'spawnerr': spawnerr,
            'exitstatus': exitstatus,
            'logfile': stdout_logfile,  # b/c alias
            'stdout_logfile': stdout_logfile,
            'stderr_logfile': stderr_logfile,
            'pid': process.pid,
        }

        description = self._interpretProcessInfo(info)
        info['description'] = description
        return info
示例#16
0
 def __init__(self, supervisord):
     """ Initialization of the attributes. """
     # store this instance in supervisord to ensure persistence
     supervisord.supvisors = self
     # get options from config file
     server_options = SupvisorsServerOptions()
     server_options.realize()
     self.options = server_options.supvisors_options
     # create logger
     stdout = supervisord.options.nodaemon
     self.logger = getLogger(self.options.logfile, self.options.loglevel,
                             Supvisors.LOGGER_FORMAT, True,
                             self.options.logfile_maxbytes,
                             self.options.logfile_backups, stdout)
     # configure supervisor info source
     self.info_source = SupervisordSource(supervisord)
     # set addresses and check local address
     self.address_mapper = AddressMapper(self.logger)
     self.address_mapper.addresses = self.options.address_list
     if not self.address_mapper.local_address:
         raise RPCError(
             Faults.SUPVISORS_CONF_ERROR,
             'local host unexpected in address list: {}'.format(
                 self.options.address_list))
     # create context data
     self.context = Context(self)
     # create application starter and stopper
     self.starter = Starter(self)
     self.stopper = Stopper(self)
     # create statistics handler
     self.statistician = StatisticsCompiler(self)
     # create the failure handler of crashing processes
     self.failure_handler = RunningFailureHandler(self)
     # create state machine
     self.fsm = FiniteStateMachine(self)
     # check parsing
     try:
         self.parser = Parser(self)
     except:
         self.logger.warn('cannot parse rules file: {}'.format(
             self.options.rules_file))
         self.parser = None
     # create event subscriber
     self.listener = SupervisorListener(self)
示例#17
0
    def stop_process(self, namespec, wait=True):
        """ Stop the process named namespec where it is running.

        *@param* ``str namespec``: the process namespec (``name``, ``group:name``, or ``group:*``).

        *@param* ``bool wait``: wait for process to be fully stopped.

        *@throws* ``RPCError``:

            * with code ``Faults.BAD_SUPVISORS_STATE`` if **Supvisors** is not in state ``OPERATION`` or ``CONCILIATION``,
            * with code ``Faults.BAD_NAME`` if namespec is unknown to **Supvisors**.
            * with code ``Faults.NOT_RUNNING`` if process is in a stopped state,

        *@return* ``bool``: always ``True`` unless error.
        """
        self._check_operating_conciliation()
        # check names
        application, process = self._get_application_process(namespec)
        processes = [process] if process else application.processes.values()
        # check processes are not already running
        for process in processes:
            if process.stopped():
                raise RPCError(Faults.NOT_RUNNING, process.namespec())
        # stop all processes
        done = True
        for process in processes:
            self.logger.info('stopping process {}'.format(process.namespec()))
            done &= self.stopper.stop_process(process)
        # wait until processes are in STOPPED_STATES
        if wait and not done:

            def onwait():
                # check stopper
                if self.stopper.in_progress():
                    return NOT_DONE_YET
                for process in processes:
                    if process.running():
                        raise RPCError(Faults.ABNORMAL_TERMINATION,
                                       process.namespec())
                return True

            onwait.delay = 0.1
            return onwait  # deferred
        return True
示例#18
0
    def log(self, message, level=supervisor.loggers.LevelsByName.INFO):
        """ Write an arbitrary message to the main supervisord log.  This is
            useful for recording information about your twiddling.

        @param  string      message      Message to write to the log
        @param  string|int  level        Log level name (INFO) or code (20)
        @return boolean                  Always True unless error
        """
        self._update('log')

        if isinstance(level, str):
            level = getattr(supervisor.loggers.LevelsByName, level.upper(),
                            None)

        if supervisor.loggers.LOG_LEVELS_BY_NUM.get(level, None) is None:
            raise RPCError(SupervisorFaults.INCORRECT_PARAMETERS)

        self.supervisord.options.logger.log(level, message)
        return True
示例#19
0
    def startProcess(self, name, wait=True):
        """ Start a process

        @param string name Process name (or ``group:name``, or ``group:*``)
        @param boolean wait Wait for process to be fully started
        @return boolean result     Always true unless error

        """
        self._update('startProcess')
        group, process = self._getGroupAndProcess(name)
        if process is None:
            group_name, process_name = split_namespec(name)
            return self.startProcessGroup(group_name, wait)

        # test filespec, don't bother trying to spawn if we know it will
        # eventually fail
        try:
            filename, argv = process.get_execv_args()
        except NotFound, why:
            raise RPCError(Faults.NO_FILE, why.args[0])
示例#20
0
    def reloadConfig(self):
        """
        Reload the configuration.

        The result contains three arrays containing names of process
        groups:

        * `added` gives the process groups that have been added
        * `changed` gives the process groups whose contents have
          changed
        * `removed` gives the process groups that are no longer
          in the configuration

        @return array result  [[added, changed, removed]]

        """
        self._update('reloadConfig')
        try:
            self.supervisord.options.process_config(do_usage=False)
        except ValueError, msg:
            raise RPCError(Faults.CANT_REREAD, msg)
示例#21
0
    def killProcess(self, name, signal):
        """ Send signal to a process

        @param string signal Signal identifier
        @param string name Process name (or 'group:name', or 'group:*')
        @return boolean result     Always true unless error

        """
        self._update('killProcess')
        group, process = self._getGroupAndProcess(name)
        if process is None:
            group_name, process_name = split_namespec(name)
            return self.killProcessGroup(signal, group_name)

        sig = self._getSignalFromString(signal)

        if sig is None:
            raise RPCError(Faults.BAD_ARGUMENTS, signal)

        killed = []
        called  = []
        kill = self.supervisord.options.kill

        def killit():
            if not called:
                if process.get_state() not in RUNNING_STATES:
                    raise RPCError(Faults.NOT_RUNNING)
                # use a mutable for lexical scoping; see startProcess
                called.append(1)

            if not killed:
                kill(process.pid, sig)
                killed.append(1)

            return True

        killit.delay = 0.2
        killit.rpcinterface = self
        return killit # deferred
示例#22
0
    def signalProcessGroup(self, name, signal):
        """ Send a signal to all processes in the group named 'name'

        @param string name    The group name
        @param string signal  Signal to send, as name ('HUP') or number ('1')
        @return array
        """
        self._update('signalProcessGroup')

        group = self.supervisord.process_groups.get(name)
        if group is None:
            raise RPCError(Faults.BAD_NAME, name)

        processes = group.processes.values()
        processes.sort()
        processes = [(group, process) for process in processes]

        sendall = make_allfunc(processes, isRunning, self.signalProcess,
                               signal=signal)
        result = sendall()
        self._update('signalProcessGroup')

        return result
示例#23
0
    def _make_config_parser(self, section_name, section_options):
        """
        Populates a new UnhosedConfigParser instance with a section
        built from a dict of section options.
        
        Args:
            section_name (str) -- The name of the section
            section_options (dict) -- The configuration options for the section

        Returns:
            config (supervisor.options.UnhosedConfgParser)

        Raises:
            RPCError: Raises error if section parameters are invalid
        """
        config = UnhosedConfigParser()
        try:
            config.add_section(section_name)
            for key, value in dict(section_options).items():
                config.set(section_name, key, value)
        except (TypeError, ValueError):
            raise RPCError(Faults.INCORRECT_PARAMETERS)
        return config
示例#24
0
    def conciliate(self, strategy):
        """ Apply the conciliation strategy only if **Supvisors** is in ``CONCILIATION`` state,
        with a USER strategy.

        *@param* ``ConciliationStrategies strategy``: the strategy used to conciliate.

        *@throws* ``RPCError``:

            * with code ``Faults.BAD_SUPVISORS_STATE`` if **Supvisors** is not in state ``CONCILIATION``,
            * with code ``Faults.BAD_STRATEGY`` if strategy is unknown to **Supvisors**.

        *@return* ``bool``: ``True`` if conciliation is triggered, ``False`` when strategy is USER.
        """
        self._check_conciliation()
        # check strategy
        if strategy not in ConciliationStrategies._values():
            raise RPCError(Faults.BAD_STRATEGY, '{}'.format(strategy))
        # trigger conciliation
        if strategy != ConciliationStrategies.USER:
            conciliate_conflicts(self.supvisors, strategy,
                                 self.context.conflicts())
            return True
        return False
示例#25
0
    def killProcessGroup(self, name, signal):
        """ Send signal to all processes in the group named 'name'

        @param string signal      Signal identifier
        @param string name        The group name
        @return struct result     A structure containing start statuses
        """
        self._update('killProcessGroup')

        group = self.supervisord.process_groups.get(name)

        if group is None:
            raise RPCError(Faults.BAD_NAME, name)

        processes = group.processes.values()
        processes.sort()
        processes = [ (group, process) for process in processes ]

        killall = make_allfunc(processes, isRunning, self.killProcess, signal=signal)

        killall.delay = 0.05
        killall.rpcinterface = self
        return killall # deferred
示例#26
0
    def startProcessGroup(self, name, wait=True):
        """ Start all processes in the group named 'name'

        @param string name        The group name
        @param boolean wait       Wait for each process to be fully started
        @return struct result     A structure containing start statuses
        """
        self._update('startProcessGroup')

        group = self.supervisord.process_groups.get(name)

        if group is None:
            raise RPCError(Faults.BAD_NAME, name)

        processes = group.processes.values()
        processes.sort()
        processes = [ (group, process) for process in processes ]

        startall = make_allfunc(processes, isNotRunning, self.startProcess,
                                wait=wait)
            
        startall.delay = 0.05
        startall.rpcinterface = self
        return startall # deferred
示例#27
0
    def stopProcessGroup(self, name, wait=True):
        """ Stop all processes in the process group named 'name'

        @param string name     The group name
        @param boolean wait    Wait for each process to be fully stopped
        @return array result   An array of process status info structs
        """
        self._update('stopProcessGroup')

        group = self.supervisord.process_groups.get(name)

        if group is None:
            raise RPCError(Faults.BAD_NAME, name)

        processes = list(group.processes.values())
        processes.sort()
        processes = [ (group, process) for process in processes ]

        killall = make_allfunc(processes, isRunning, self.stopProcess,
                               wait=wait)

        killall.delay = 0.05
        killall.rpcinterface = self
        return killall # deferred
示例#28
0
 def inner():
     raise RPCError(Faults.BAD_NAME, 'foo')
示例#29
0
 def bad_name(self):
     raise RPCError(Faults.BAD_NAME, 'foo')
示例#30
0
 def callback():
     raise RPCError(Faults.UNKNOWN_METHOD)