def ping(self, p_host):
        """
        Returns True if host (str) responds to a ping request.
        Remember that a host may not respond to a ping (ICMP) request even if the host name is valid.
        """

        fmt = "{ping_command} -w 1 {c_option} {host}"
        raw_command = fmt.format(ping_command=self._config.ping_command,
                                 # Ping command count option as function of OS
                                 c_option='-n 1' if tools.is_windows() else '-c 1',
                                 host=shlex.quote(p_host))

        command = shlex.split(raw_command)
        delay = None

        fmt = "Executing command {cmd} in Popen"
        self._logger.debug(fmt.format(cmd=command))

        proc = subprocess.Popen(command, stdout=subprocess.PIPE)

        for line in proc.stdout:
            result = self.ping_result_regex.match(line.decode("UTF-8"))

            if result:
                delay = float(result.group(1))
                break

        fmt = "Host {host} is {status}"
        self._logger.debug(
            fmt.format(host=p_host, status="responding (%.1f ms)" % delay if delay is not None else "down"))

        return delay
예제 #2
0
    def install_handlers(self):

        for signal_id in self._active_signals:
            signal.signal(signal_id, self.handle_signal)

        if not tools.is_windows():
            signal.pthread_sigmask(signal.SIG_UNBLOCK, self._active_signals)
예제 #3
0
    def __init__(self,
                 p_app_name,
                 p_pid_file,
                 p_arguments,
                 p_dir_name,
                 p_languages=None):

        super().__init__(pidfile=p_pid_file)

        self._app_name = p_app_name
        self._dir_name = p_dir_name
        self._languages = p_languages
        self._arguments = p_arguments
        self._logger = log_handling.get_logger(self.__class__.__name__)
        self._config = None
        self._recurring_tasks = []
        self._downtime = 0
        self._locale_helper = None
        self._latest_request = None
        self._partial_basic_init_executed = False
        self._full_basic_init_executed = False
        self._active_signals = [signal.SIGTERM, signal.SIGINT]
        self._done = False

        if not tools.is_windows():
            self._active_signals.append(signal.SIGHUP)

        if self._languages is None:
            self._languages = DEFAULT_LANGUAGES

        self._langs = {}

        # Only temporary until the app has been initialized completely!
        self._app_config = BaseAppConfigModel()
    def ping(self, p_host):
        """
        Returns True if host (str) responds to a ping request.
        Remember that a host may not respond to a ping (ICMP) request even if the host name is valid.
        """

        # Ping command count option as function of OS
        param = '-n 1' if tools.is_windows() else '-c 1'

        # Building the command. Ex: "ping -c 1 google.com"
        command = [self._config.ping_command, param, p_host]

        delay = None

        proc = subprocess.Popen(command, stdout=subprocess.PIPE)

        for line in proc.stdout:
            result = self.ping_result_regex.match(line.decode("UTF-8"))

            if result:
                delay = float(result.group(1))
                break

        fmt = "Host {host} is {status}"
        self._logger.debug(
            fmt.format(host=p_host,
                       status="responding (%.1f ms)" %
                       delay if delay is not None else "down"))

        return delay
예제 #5
0
    def local_ping(self, p_host):
        """
        Checks if a host reacts to a ICMP ping request.
        Remember that a host may not respond to a ping (ICMP) request even if the host name is valid.

        :param p_host: DNS or ip address of the host to be pinged
        :return: the delay in milliseconds (as float) if the host responds, None otherwise
        """

        fmt = "{ping_command} {w_option} 1 {c_option} {host}"
        raw_command = fmt.format(
            ping_command=self._config.ping_command,
            # Ping command count option as function of OS
            c_option='-n 1' if tools.is_windows() else '-c 1',
            w_option=self._config.ping_wait_option,
            host=shlex.quote(p_host))

        command = shlex.split(raw_command)
        delay = None

        fmt = "Executing command {cmd} in Popen"
        self._logger.debug(fmt.format(cmd=command))

        # make sure we get floating points and not commas!
        run_env = os.environ.copy()
        run_env["LANG"] = "en_US"

        proc = subprocess.run(command, stdout=subprocess.PIPE, env=run_env)

        if proc.returncode >= 2:
            fmt = "{cmd} returns exit code {exitcode}"
            raise ConfigurationException(
                fmt.format(cmd=command, exitcode=proc.returncode))

        stdout_string = proc.stdout.decode("UTF-8")

        for line in stdout_string.split("\n"):
            fmt = "ping output: {line}"
            self._logger.debug(fmt.format(line=line))

            result = self.ping_result_regex.match(line)

            if result:
                delay = float(result.group(3))
                break

        fmt = "Host {host} is {status}"
        self._logger.debug(
            fmt.format(host=p_host,
                       status="responding (%.1f ms)" %
                       delay if delay is not None else "down"))

        return delay
    def play_audio_file(self, p_audio_filename):  # pragma: no cover

        if tools.is_windows():
            binary = '"' + self._mpg123_binary + '"'
            filename = '"' + p_audio_filename + '"'

        else:
            binary = self._mpg123_binary
            filename = p_audio_filename

        play_command = self._play_command_pattern.format(binary=binary,
                                                         filename=filename)

        msg = f"Executing command '{play_command}'..."

        self._logger.debug(msg)

        cmd_array = shlex.split(play_command)
        subprocess.run(cmd_array)
예제 #7
0
    def stop(self):
        """
        Stop the daemon
        """

        if self.verbose >= 1:
            self.log("Stopping daemon...")

        # Get the pid from the pidfile
        pid = self.get_pid()

        if not pid:
            message = "pidfile %s does not exist. Not running?\n"
            sys.stderr.write(message % self.pidfile)

            # Just to be sure. A ValueError might occur if the PID file is
            # empty but does actually exist
            if os.path.exists(self.pidfile):
                os.remove(self.pidfile)

            return  # Not an error in a restart

        # Try killing the daemon process
        try:
            i = 0
            while 1:
                os.kill(pid, signal.SIGTERM)
                time.sleep(0.1)
                i = i + 1

                if not tools.is_windows():
                    if i % 10 == 0:
                        os.kill(pid, signal.SIGHUP)
        except OSError as err:
            if err.errno == errno.ESRCH:
                if os.path.exists(self.pidfile):
                    os.remove(self.pidfile)
            else:
                print(str(err))
                sys.exit(1)

        self.log("Daemon stopped")
예제 #8
0
def get_site_packages_dir():

    major_version = sys.version_info[0]
    minor_version = sys.version_info[1]

    if tools.is_windows():
        pattern = f".+Python\.{major_version}\.{minor_version}.+\\\\lib$"

    else:
        pattern = f".+python{major_version}\.{minor_version}/(site|dist)-packages$"

    regex = re.compile(pattern)

    site_packages_dirs = [p for p in sys.path if regex.match(p)]

    if len(site_packages_dirs) != 1:
        msg = f"Cannot determine unique site-package dir with pattern '{pattern}'! Candidates {site_packages_dirs} remaining from {sys.path}"
        raise Exception(msg)

    return site_packages_dirs[0]
예제 #9
0
    def event_queue(self):

        self._done = False
        self._logger.info("Entering event queue...")

        while not self._done:
            try:
                now = datetime.datetime.utcnow()

                if len(self._recurring_tasks) > 0:
                    task = self._recurring_tasks[0]
                    wait_in_seconds = (task - now).total_seconds()

                else:
                    task = None
                    wait_in_seconds = ETERNITY

                if wait_in_seconds > 0:
                    try:
                        fmt = "Sleeping for {seconds} seconds (or until next signal)"
                        self._logger.debug(fmt.format(seconds=wait_in_seconds))

                        if not tools.is_windows():
                            signal.pthread_sigmask(signal.SIG_UNBLOCK,
                                                   self._active_signals)

                        time.sleep(wait_in_seconds)

                    except exceptions.SignalHangUp as e:
                        raise e

                    except Exception as e:
                        if self._app_config.debug_mode:
                            fmt = "Propagating exception due to debug_mode=True"
                            self._logger.warn(fmt)
                            raise e

                        fmt = "Exception %s while waiting for signal" % str(e)
                        self._logger.error(fmt)

                    fmt = "Woken by signal"
                    self._logger.debug(fmt)

                    if task is not None:
                        now = datetime.datetime.utcnow()
                        overslept_in_seconds = (now - task).total_seconds()

                        if overslept_in_seconds > self._app_config.maximum_timer_slack:
                            self.track_downtime(
                                p_downtime=overslept_in_seconds)

                if len(self._recurring_tasks) > 0:
                    task_executed = True

                    while task_executed:
                        task: RecurringTask = self._recurring_tasks[0]
                        now = datetime.datetime.utcnow()

                        if now > task:
                            delay = (now - task).total_seconds()

                            task = heapq.heappop(self._recurring_tasks)
                            self.add_recurring_task(p_recurring_task=task)

                            fmt = "Executing task {task} {secs:.3f} [s] behind schedule... *** START ***"
                            self._logger.debug(
                                fmt.format(task=task.name, secs=delay))

                            try:
                                task.handler_method()

                            except Exception as e:
                                self._logger.error(
                                    f"Exception {str(e)}  while executing task {task.name}"
                                )

                                if not task.ignore_exceptions:
                                    raise e

                            fmt = "Executing task {task} {secs:.3f} [s] behind schedule... *** END ***"
                            self._logger.debug(
                                fmt.format(task=task.name, secs=delay))

                            if delay > self._app_config.minimum_downtime_duration:
                                self.track_downtime(p_downtime=delay)

                        else:
                            task_executed = False

                    if self._downtime > 0:
                        self.handle_downtime(p_downtime=int(self._downtime))
                        self.reset_down_time()

            except exceptions.SignalHangUp:
                fmt = "Event queue interrupted by signal"
                self._logger.info(fmt)

                self._done = True

            except Exception as e:
                if self._app_config.debug_mode:
                    fmt = "Propagating exception due to debug_mode=True"
                    self._logger.warn(fmt)
                    raise e

                fmt = "Exception %s in event queue" % str(e)
                self._logger.error(fmt)
                tools.log_stack_trace(p_logger=self._logger)

            if self._arguments.single_run:
                self._done = True

        self._logger.info("Leaving event queue...")