Ejemplo n.º 1
0
    def connect(self, socket = None):
        """
        Connects to the notify socket.  However, if we can't, it's not considered an error.
        We just return False.
        """

        self.close()

        if socket is None:
            if "NOTIFY_SOCKET" not in os.environ:
                return False
            socket = os.environ["NOTIFY_SOCKET"]
        
        self._client = NotifyClient(socket, 
                                    onClose = lambda which,exc: self.close(),
                                    onError = lambda which,exc: debug("{0} error, notifications disabled".format(socket)))

        try:
            yield from self._client.run()
        except OSError as ex:
            debug("could not connect to notify socket '{0} ({1})".format(socket, ex))
            self.close()
            return False

        return True
Ejemplo n.º 2
0
    def configFromCommandSpec(cls, spec, user = None, default = None, extra_settings = None, disable_console_log = False):
        """
        A command specification (typically specified with the --config=<file_or_dir> command
        line option) is used to create a configuration object.   The target may be either a file
        or a directory.  If it is a file, then the file itself will be the only configuration
        read.  If it is a directory, then a search is made for any top-level files which end in
        .conf or .yaml, and those will be combined according to lexicographic order.

        If the configuration path is a relative path, then it is relative to either the root
        directory, or the home directory of the given user.  This allows a user-specific
        configuration to automatically take effect if desired.
        """

        frombase = '/'

        if user:
            frombase = lookup_user(user).pw_dir

        trypath = os.path.join(frombase, spec)

        debug("TRY CONFIG PATH: {0}".format(trypath))

        if not os.path.exists(trypath):
            return cls(default = default)
        else:
            os.environ[ENV_CONFIG_DIR] = os.path.dirname(trypath)

        if os.path.isdir(trypath):
            return cls(*[os.path.join(trypath, f) for f in sorted(os.listdir(trypath))
                         if f.endswith('.yaml') or f.endswith('.conf')],
                       default = default, uid = user, extra_settings = extra_settings, disable_console_log = disable_console_log)


        return cls(trypath, default = default, uid = user, extra_settings = extra_settings, disable_console_log = disable_console_log)
Ejemplo n.º 3
0
    def _no_processes(self, ignore_service_state = False):
        if not (ignore_service_state or self._services_started):
            return    # do not react during system initialization

        self._all_killed = True

        if not self._killing_system:
            if not self.detect_exit:
                return
            if self._family:
                ss = self._family.get_scheduled_services()
                if ss:
                    warn("system will remain active since there are scheduled services: " + ", ".join(s.name for s in ss))
                    return

        # Passed all checks, now kill system

        self.notify.stopping()

        debug("Final termination phase.")

        self._services_started = False
        if self._kill_future and not self._kill_future.cancelled():
            self._kill_future.cancel()
        self.activate(self._final_system_stop())
Ejemplo n.º 4
0
 def send(self, name, val):
     if name not in self._lev:
         return
     self._sent.add(name)
     if self._client:
         debug("queueing '{0}={1}' to notify socket '{2}'".format(name, val, self._client.socket_name))
         asyncio.async(self._do_send("{0}={1}".format(name, val)))
Ejemplo n.º 5
0
    def _do_waitpid_all(self):
        # Because of signal coalescing, we must keep calling waitpid() as
        # long as we're able to reap a child.
        while True:
            try:
                pid, status = os.waitpid(-1, os.WNOHANG)
                debug("REAP pid={0},status={1}".format(pid,status))
            except ChildProcessError:
                # No more child processes exist.
                if self._had_children:
                    debug("no child processes present")
                    self.events.onNoProcesses()
                return
            else:
                self._had_children = True
                if pid == 0:
                    # A child process is still alive.
                    return

                returncode = ProcStatus(status)

            with self._lock:
                try:
                    callback, args = self._callbacks.pop(pid)
                except KeyError:
                    # unknown child
                    if self._forks:
                        # It may not be registered yet.
                        self._zombies[pid] = returncode
                        continue
                    callback = None

            if callback is None:
                info(
                    "Caught subprocess termination from unknown pid: "
                    "%d -> %d", pid, returncode)
            else:
                callback(pid, returncode, *args)
Ejemplo n.º 6
0
    def __init__(self, *args, default = None, uid = None, extra_settings = None, disable_console_log = False):
        """
        Given one or more files, load our configuration.  If no configuration is provided,
        then use the configuration specified by the default.
        """
        debug("CONFIG INPUT (uid={1}): '{0}'".format(args, uid))

        self.uid = uid
        self._conf = lazydict()

        for fn in args:
            if os.path.exists(fn):
                self._merge(yaml.load(open(fn, 'r').read().expandtabs()))
        
        if not self._conf and default:
            self._conf = lazydict(yaml.load(default))

        validator(self._conf)

        if extra_settings:
            self.update_settings(extra_settings)

        s = self.get_settings()
        self.uid = s.get('uid', self.uid)
        self.gid = s.get('gid', self.gid)

        # Special case used by --no-console-log.  It really was just easiest to do it this way
        # rather than try to build some special notion of "console logging" into the log services
        # backends.

        if disable_console_log:
            for k,v in self._conf.items():
                if k.endswith('.logging'):
                    if 'stdout' in v:
                        del v['stdout']
                    if 'stderr' in v:
                        del v['stderr']
Ejemplo n.º 7
0
    def _kill_system_co(self):

        self.notify.stopping()

        self._cancel_pending()

        # Tell the family it's been nice.  It's unlikely we won't have a process family, but
        # it's optional, so we should handle the situation.

        wait_done = False  # indicates if shutdown_timeout has expired

        if self._family:
            for f in self._family.values():
                yield from f.final_stop()
            # let normal shutdown happen
            if self._watcher.number_of_waiters > 0 and self._shutdown_timeout:
                debug(
                    "still have {0} waiting, sleeping for shutdown_timeout={1}"
                    .format(self._watcher.number_of_waiters,
                            self._shutdown_timeout))
                yield from asyncio.sleep(self._shutdown_timeout)
                wait_done = True

        try:
            os.kill(-1, signal.SIGTERM)  # first try a sig term
            if self.send_sighup:
                os.kill(-1, signal.SIGHUP)
        except ProcessLookupError:
            debug(
                "No processes remain when attempting to kill system, just stop."
            )
            self._no_processes(True)
            return

        if wait_done:  # give a short wait just so the signals fire
            yield from asyncio.sleep(1)  # these processes are unknowns
        else:
            yield from asyncio.sleep(self._shutdown_timeout)

        if self._all_killed:
            return

        info("Some processes remain after {0}secs.  Forcing kill".format(
            self._shutdown_timeout))

        try:
            os.kill(-1, signal.SIGKILL)
        except ProcessLookupError:
            debug("No processes when attempting to force quit")
            self._no_processes(True)
            return
Ejemplo n.º 8
0
    def _kill_system_co(self):

        self.notify.stopping()

        self._cancel_pending()

        # Tell the family it's been nice.  It's unlikely we won't have a process family, but
        # it's optional, so we should handle the situation.

        wait_done = False       # indicates if shutdown_timeout has expired

        if self._family:
            for f in self._family.values():
                yield from f.final_stop()
            # let normal shutdown happen
            if self._watcher.number_of_waiters > 0 and self._shutdown_timeout:
                debug("still have {0} waiting, sleeping for shutdown_timeout={1}".format(self._watcher.number_of_waiters, self._shutdown_timeout))
                yield from asyncio.sleep(self._shutdown_timeout)
                wait_done = True

        try:
            os.kill(-1, signal.SIGTERM) # first try a sig term
            if self.send_sighup:
                os.kill(-1, signal.SIGHUP)
        except ProcessLookupError:
            debug("No processes remain when attempting to kill system, just stop.")
            self._no_processes(True)
            return

        if wait_done:                   # give a short wait just so the signals fire
            yield from asyncio.sleep(1) # these processes are unknowns
        else:
            yield from asyncio.sleep(self._shutdown_timeout)
            
        if self._all_killed:
            return

        info("Some processes remain after {0}secs.  Forcing kill".format(self._shutdown_timeout))

        try:
            os.kill(-1, signal.SIGKILL)
        except ProcessLookupError:
            debug("No processes when attempting to force quit")
            self._no_processes(True)
            return
Ejemplo n.º 9
0
 def dump(self):
     debug('FULL CONFIGURATION: {0}'.format(self._conf))
Ejemplo n.º 10
0
 def dump(self):
     debug('FULL CONFIGURATION: {0}'.format(self._conf))
Ejemplo n.º 11
0
 def logdebug(self, *args, **kwargs):
     debug(*args, facility=self.syslog_facility, **kwargs)
Ejemplo n.º 12
0
 def logdebug(self, *args, **kwargs):
     debug(*args, facility=self.syslog_facility, **kwargs)