Ejemplo n.º 1
0
def main():
    ### Options management
    parser = ArgumentParser()
    parser.add_argument("-V", action="store_true", dest="display_version", default=False, help="Display the xPL hub version.")
    parser.add_argument("-f", action="store_true", dest="run_in_foreground", default=False, help="Run the xPL hub in foreground, default to background.")
    options = parser.parse_args()
    if options.display_version:
        print(VERSION)
        return
    if not options.run_in_foreground:
        daemon = True

        ctx = DaemonContext()
        ctx.open()

        #from twisted.internet.protocol import DatagramProtocol
        from twisted.internet import reactor
        #from twisted.python import log

    else:
        daemon = False
        #from twisted.internet.protocol import DatagramProtocol
        from twisted.internet import reactor
        #from twisted.python import log


    ### Launch the hub
    from domogik.xpl.hub.lib import Hub
    Hub(daemon)
Ejemplo n.º 2
0
def main():
    cfg = Loader('mq')
    my_conf = cfg.load()
    config = dict(my_conf[1])

    ctx = DaemonContext()
    ctx.open()

    context = zmq.Context()
    print(("tcp://{0}:{1}".format(config['ip'], config['req_rep_port'])))
    broker = MDPBroker(context, "tcp://{0}:{1}".format(config['ip'], config['req_rep_port']))
    IOLoop.instance().start()
    broker.shutdown()
Ejemplo n.º 3
0
def main():
    cfg = Loader('mq')
    my_conf = cfg.load()
    config = dict(my_conf[1])

    ctx = DaemonContext()
    ctx.open()

    context = zmq.Context()
    print(("tcp://{0}:{1}".format(config['ip'], config['req_rep_port'])))
    broker = MDPBroker(
        context, "tcp://{0}:{1}".format(config['ip'], config['req_rep_port']))
    IOLoop.instance().start()
    broker.shutdown()
Ejemplo n.º 4
0
def main():
    """
       Main loop for the forwarder
    """
    ctx = DaemonContext()
    ctx.open()

    cfg = Loader('mq').load()
    config = dict(cfg[1])
    log = logger.Logger('mq_forwarder').get_logger()
    log.info("Starting the forwarder")
    
    try:
        context = zmq.Context(1)

        # Socket facing emitters
        frontend = context.socket(zmq.SUB)
        # Forwarder subscribes to the emitter *pub* port
        sub_addr = "tcp://{0}:{1}".format(\
                   config['ip'], config['pub_port'])
        frontend.bind(sub_addr)
        log.info("Waiting for messages on {0}".format(sub_addr))
        # We want to get all messages from emitters
        frontend.setsockopt(zmq.SUBSCRIBE, "")
        
        # Socket facing receivers
        backend = context.socket(zmq.PUB)
        # Forwarder publishes to the receiver *sub* port
        pub_addr = "tcp://{0}:{1}".format(\
                   config['ip'], config['sub_port'])
        backend.bind(pub_addr)
        log.info("Sending messages to {0}".format(pub_addr))
        
        log.info("Forwarding messages...")
        zmq.device(zmq.FORWARDER, frontend, backend)
    except Exception as exp:
        log.error(exp)
        log.error("Bringing down ZMQ device")
        raise Exception("Error with forwarder device")
    finally:
        frontend.close()
        backend.close()
        context.term()
        log.info("Forwarder stopped")
Ejemplo n.º 5
0
def main():
    """
       Main loop for the forwarder
    """
    ctx = DaemonContext()
    ctx.open()

    cfg = Loader('mq').load()
    config = dict(cfg[1])
    log = logger.Logger('mq_forwarder').get_logger()
    log.info("Starting the forwarder")

    try:
        context = zmq.Context(1)

        # Socket facing emitters
        frontend = context.socket(zmq.SUB)
        # Forwarder subscribes to the emitter *pub* port
        sub_addr = "tcp://{0}:{1}".format(\
                   config['ip'], config['pub_port'])
        frontend.bind(sub_addr)
        log.info("Waiting for messages on {0}".format(sub_addr))
        # We want to get all messages from emitters
        frontend.setsockopt(zmq.SUBSCRIBE, "")

        # Socket facing receivers
        backend = context.socket(zmq.PUB)
        # Forwarder publishes to the receiver *sub* port
        pub_addr = "tcp://{0}:{1}".format(\
                   config['ip'], config['sub_port'])
        backend.bind(pub_addr)
        log.info("Sending messages to {0}".format(pub_addr))

        log.info("Forwarding messages...")
        zmq.device(zmq.FORWARDER, frontend, backend)
    except Exception as exp:
        log.error(exp)
        log.error("Bringing down ZMQ device")
        raise Exception("Error with forwarder device")
    finally:
        frontend.close()
        backend.close()
        context.term()
        log.info("Forwarder stopped")
Ejemplo n.º 6
0
def main():
    ### Options management
    parser = ArgumentParser()
    parser.add_argument("-V",
                        action="store_true",
                        dest="display_version",
                        default=False,
                        help="Display the xPL hub version.")
    parser.add_argument(
        "-f",
        action="store_true",
        dest="run_in_foreground",
        default=False,
        help="Run the xPL hub in foreground, default to background.")
    options = parser.parse_args()
    if options.display_version:
        print(VERSION)
        return
    if not options.run_in_foreground:
        daemon = True

        ctx = DaemonContext()
        ctx.open()

        #from twisted.internet.protocol import DatagramProtocol
        from twisted.internet import reactor
        #from twisted.python import log

    else:
        daemon = False
        #from twisted.internet.protocol import DatagramProtocol
        from twisted.internet import reactor
        #from twisted.python import log

    ### Launch the hub
    from domogik.xpl.hub.lib import Hub
    Hub(daemon)
Ejemplo n.º 7
0
    def __init__(self, name, stop_cb = None, p = None, daemonize = True, log_prefix= ""):
        ''' 
        @param p : An instance of ArgumentParser. If you want to add extra options to the generic option parser,
        create your own ArgumentParser instance, use parser.add_argument and then pass your parser instance as parameter.
        Your options/params will then be available on self.options and self.args
        @param daemonize : If set to False, force the instance *not* to daemonize, even if '-f' is not passed
        on the command line. If set to True (default), will check if -f was added.
        @param log_prefix : If set, use this prefix when creating the log file in Logger()
        '''
        ### First, check if the user is allowed to launch the plugin. The user must be the same as the one defined
        # in the file /etc/default/domogik : DOMOGIK_USER
        Default = DefaultLoader()
        dmg_user = Default.get("DOMOGIK_USER")
        logname = pwd.getpwuid(os.getuid())[0]
        if dmg_user != logname:
            print(u"ERROR : this Domogik part must be run with the user defined in /etc/default/domogik as DOMOGIK_USER : %s" % dmg_user)
            sys.exit(1)

        if name is not None:
            self._plugin_name = name

        l = logger.Logger(name, use_filename = "{0}{1}".format(log_prefix, name))
        self.log = l.get_logger()

        ### Check if the plugin is not already launched
        # notice that when the plugin is launched from the manager, this call is not done as the manager already does this test before starting a plugin
        res, pid_list = is_already_launched(self.log, name)
        if res:
            sys.exit(2)

        ### Create a file to handle the return code
        # this is used by the function set_return_code and get_return_code
        # this is needed as a Domogik process is forked, there is no way to send from a class a return code from the child to the parent.
        try: 
            self.return_code_filename = "{0}/{1}_return_code_{2}".format(FIFO_DIR, self._plugin_name, os.getpid())
            # just touch the file to create it
            open(self.return_code_filename, 'a').close()
        except:
            self.log.error("Error while creating return_code file '{0}' : {1}".format(self.return_code_filename, traceback.format_exc()))
            sys.exit(3)

        ### Start the plugin...
        self._threads = []
        self._timers = []
        self._stop = threading.Event()
        self._lock_add_thread = threading.Semaphore()
        self._lock_add_timer = threading.Semaphore()
        self._lock_add_cb = threading.Semaphore()
        if stop_cb is not None:
            self._stop_cb = [stop_cb]
        else:
            self._stop_cb = []

        ### options management
        if p is not None and isinstance(p, ArgumentParser):
            parser = p
        else:
            parser = ArgumentParser()
        parser.add_argument("-V", 
                          "--version", 
                          action="store_true", 
                          dest="display_version", 
                          default=False, 
                          help="Display Domogik version.")
        parser.add_argument("-f", 
                          action="store_true", 
                          dest="run_in_foreground", 
                          default=False, 
                          help="Run the plugin in foreground, default to background.")
        parser.add_argument("-T", 
                          dest="test_option", 
                          default=None,
                          help="Test option.")
        self.options = parser.parse_args()
        if self.options.display_version:
            __import__("domogik")
            global_release = sys.modules["domogik"].__version__
            print(global_release)
            sys.exit(0)
        elif not self.options.run_in_foreground and daemonize:
            self.log.info(u"Starting the plugin in background...")
            ctx = DaemonContext()
            ctx.files_preserve = l.get_fds([name])
            ctx.open()
            self.log.info(u"Daemonize plugin %s" % name)
            self.is_daemon = True
        else:
            #l = logger.Logger(name)
            #self.log = l.get_logger()
            self.is_daemon = False
Ejemplo n.º 8
0
    def __init__(self,
                 name,
                 stop_cb=None,
                 p=None,
                 daemonize=True,
                 log_prefix="",
                 log_on_stdout=True):
        ''' 
        @param p : An instance of ArgumentParser. If you want to add extra options to the generic option parser,
        create your own ArgumentParser instance, use parser.add_argument and then pass your parser instance as parameter.
        Your options/params will then be available on self.options and self.args
        @param daemonize : If set to False, force the instance *not* to daemonize, even if '-f' is not passed
        on the command line. If set to True (default), will check if -f was added.
        @param log_prefix : If set, use this prefix when creating the log file in Logger()
        @param log_on_stdout : if set to True, allow to read logs on both stdout and log file
        '''
        ### First, check if the user is allowed to launch the plugin. The user must be the same as the one defined
        # in the file /etc/default/domogik : DOMOGIK_USER
        Default = DefaultLoader()
        dmg_user = Default.get("DOMOGIK_USER")
        logname = pwd.getpwuid(os.getuid())[0]
        if dmg_user != logname:
            print(
                u"ERROR : this Domogik part must be run with the user defined in /etc/default/domogik as DOMOGIK_USER : %s"
                % dmg_user)
            sys.exit(1)

        if name is not None:
            self._plugin_name = name

        l = logger.Logger(name,
                          use_filename="{0}{1}".format(log_prefix, name),
                          log_on_stdout=log_on_stdout)
        self.log = l.get_logger()

        ### Check if the plugin is not already launched
        # notice that when the plugin is launched from the manager, this call is not done as the manager already does this test before starting a plugin
        # TODO : improve ? currently, as it is not used, we set the type of the client to None
        # in case the 'is_already_launched function would use it a day, we should find a way to get the client type
        res, pid_list = is_already_launched(self.log, None, name)
        if res:
            sys.exit(2)

        ### Create a file to handle the return code
        # this is used by the function set_return_code and get_return_code
        # this is needed as a Domogik process is forked, there is no way to send from a class a return code from the child to the parent.
        try:
            self.return_code_filename = "{0}/{1}_return_code_{2}".format(
                FIFO_DIR, self._plugin_name, os.getpid())
            # just touch the file to create it
            open(self.return_code_filename, 'a').close()
        except:
            self.log.error(
                "Error while creating return_code file '{0}' : {1}".format(
                    self.return_code_filename, traceback.format_exc()))
            sys.exit(3)

        ### Start the plugin...
        self._threads = []
        self._timers = []
        self._stop = threading.Event()
        self._lock_add_thread = threading.Semaphore()
        self._lock_add_timer = threading.Semaphore()
        self._lock_add_cb = threading.Semaphore()
        if stop_cb is not None:
            self._stop_cb = [stop_cb]
        else:
            self._stop_cb = []

        ### options management
        if p is not None and isinstance(p, ArgumentParser):
            parser = p
        else:
            parser = ArgumentParser()
        parser.add_argument("-V",
                            "--version",
                            action="store_true",
                            dest="display_version",
                            default=False,
                            help="Display Domogik version.")
        parser.add_argument(
            "-f",
            action="store_true",
            dest="run_in_foreground",
            default=False,
            help="Run the plugin in foreground, default to background.")
        parser.add_argument("-T",
                            dest="test_option",
                            default=None,
                            help="Test option.")
        self.options = parser.parse_args()
        if self.options.display_version:
            __import__("domogik")
            global_release = sys.modules["domogik"].__version__
            print(global_release)
            sys.exit(0)
        elif not self.options.run_in_foreground and daemonize:
            self.log.info(u"Starting the plugin in background...")
            ctx = DaemonContext()
            ctx.files_preserve = l.get_fds([name])
            ctx.open()
            self.log.info(u"Daemonize plugin %s" % name)
            self.is_daemon = True
        else:
            #l = logger.Logger(name)
            #self.log = l.get_logger()
            self.is_daemon = False
Ejemplo n.º 9
0
class DaemonRunner(object):
    """ Controller for a callable running in a separate background process.

        The first command-line argument is the action to take:

        * 'start': Become a daemon and call `app.run()`.
        * 'stop': Exit the daemon process specified in the PID file.
        * 'restart': Stop, then start.

        """

    start_message = "started with pid %(pid)d"

    def __init__(self, app):
        """ Set up the parameters of a new runner.

            The `app` argument must have the following attributes:

            * `stdin_path`, `stdout_path`, `stderr_path`: Filesystem
              paths to open and replace the existing `sys.stdin`,
              `sys.stdout`, `sys.stderr`.

            * `pidfile_path`: Absolute filesystem path to a file that
              will be used as the PID file for the daemon. If
              ``None``, no PID file will be used.

            * `pidfile_timeout`: Used as the default acquisition
              timeout value supplied to the runner's PID lock file.

            * `run`: Callable that will be invoked when the daemon is
              started.
            
            """
        self.parse_args()
        self.app = app
        self.daemon_context = DaemonContext()
        self.daemon_context.stdin = open(app.stdin_path, 'r')
        self.daemon_context.stdout = open(app.stdout_path, 'w+')
        self.daemon_context.stderr = open(
            app.stderr_path, 'w+', buffering=0)

        self.pidfile = None
        if app.pidfile_path is not None:
            self.pidfile = make_pidlockfile(
                app.pidfile_path, app.pidfile_timeout)
        self.daemon_context.pidfile = self.pidfile

    def _usage_exit(self, argv):
        """ Emit a usage message, then exit.
            """
        progname = os.path.basename(argv[0])
        usage_exit_code = 2
        action_usage = "|".join(self.action_funcs.keys())
        message = "usage: %(progname)s %(action_usage)s" % vars()
        emit_message(message)
        sys.exit(usage_exit_code)

    def parse_args(self, argv=None):
        """ Parse command-line arguments.
            """
        if argv is None:
            argv = sys.argv

        min_args = 2
        if len(argv) < min_args:
            self._usage_exit(argv)

        self.action = argv[1]
        if self.action not in self.action_funcs:
            self._usage_exit(argv)

    def _start(self):
        """ Open the daemon context and run the application.
            """
        if is_pidfile_stale(self.pidfile):
            self.pidfile.break_lock()

        try:
            self.daemon_context.open()
        except pidlockfile.AlreadyLocked:
            pidfile_path = self.pidfile.path
            raise DaemonRunnerStartFailureError(
                "PID file %(pidfile_path)r already locked" % vars())

        pid = os.getpid()
        message = self.start_message % vars()
        emit_message(message)

        self.app.run()

    def _terminate_daemon_process(self):
        """ Terminate the daemon process specified in the current PID file.
            """
        pid = self.pidfile.read_pid()
        try:
            os.kill(pid, signal.SIGTERM)
        except OSError as exc:
            raise DaemonRunnerStopFailureError(
                "Failed to terminate %(pid)d: %(exc)s" % vars())

    def _stop(self):
        """ Exit the daemon process specified in the current PID file.
            """
        if not self.pidfile.is_locked():
            pidfile_path = self.pidfile.path
            raise DaemonRunnerStopFailureError(
                "PID file %(pidfile_path)r not locked" % vars())

        if is_pidfile_stale(self.pidfile):
            self.pidfile.break_lock()
        else:
            self._terminate_daemon_process()

    def _restart(self):
        """ Stop, then start.
            """
        self._stop()
        self._start()

    action_funcs = {
        'start': _start,
        'stop': _stop,
        'restart': _restart,
        }

    def _get_action_func(self):
        """ Return the function for the specified action.

            Raises ``DaemonRunnerInvalidActionError`` if the action is
            unknown.

            """
        try:
            func = self.action_funcs[self.action]
        except KeyError:
            raise DaemonRunnerInvalidActionError(
                "Unknown action: %(action)r" % vars(self))
        return func

    def do_action(self):
        """ Perform the requested action.
            """
        func = self._get_action_func()
        func(self)
Ejemplo n.º 10
0
class DaemonRunner(object):
    """ Controller for a callable running in a separate background process.

        The first command-line argument is the action to take:

        * 'start': Become a daemon and call `app.run()`.
        * 'stop': Exit the daemon process specified in the PID file.
        * 'restart': Stop, then start.

        """

    start_message = "started with pid %(pid)d"

    def __init__(self, app):
        """ Set up the parameters of a new runner.

            The `app` argument must have the following attributes:

            * `stdin_path`, `stdout_path`, `stderr_path`: Filesystem
              paths to open and replace the existing `sys.stdin`,
              `sys.stdout`, `sys.stderr`.

            * `pidfile_path`: Absolute filesystem path to a file that
              will be used as the PID file for the daemon. If
              ``None``, no PID file will be used.

            * `pidfile_timeout`: Used as the default acquisition
              timeout value supplied to the runner's PID lock file.

            * `run`: Callable that will be invoked when the daemon is
              started.
            
            """
        self.parse_args()
        self.app = app
        self.daemon_context = DaemonContext()
        self.daemon_context.stdin = open(app.stdin_path, 'r')
        self.daemon_context.stdout = open(app.stdout_path, 'w+')
        self.daemon_context.stderr = open(app.stderr_path, 'w+', buffering=0)

        self.pidfile = None
        if app.pidfile_path is not None:
            self.pidfile = make_pidlockfile(app.pidfile_path,
                                            app.pidfile_timeout)
        self.daemon_context.pidfile = self.pidfile

    def _usage_exit(self, argv):
        """ Emit a usage message, then exit.
            """
        progname = os.path.basename(argv[0])
        usage_exit_code = 2
        action_usage = "|".join(self.action_funcs.keys())
        message = "usage: %(progname)s %(action_usage)s" % vars()
        emit_message(message)
        sys.exit(usage_exit_code)

    def parse_args(self, argv=None):
        """ Parse command-line arguments.
            """
        if argv is None:
            argv = sys.argv

        min_args = 2
        if len(argv) < min_args:
            self._usage_exit(argv)

        self.action = argv[1]
        if self.action not in self.action_funcs:
            self._usage_exit(argv)

    def _start(self):
        """ Open the daemon context and run the application.
            """
        if is_pidfile_stale(self.pidfile):
            self.pidfile.break_lock()

        try:
            self.daemon_context.open()
        except pidlockfile.AlreadyLocked:
            pidfile_path = self.pidfile.path
            raise DaemonRunnerStartFailureError(
                "PID file %(pidfile_path)r already locked" % vars())

        pid = os.getpid()
        message = self.start_message % vars()
        emit_message(message)

        self.app.run()

    def _terminate_daemon_process(self):
        """ Terminate the daemon process specified in the current PID file.
            """
        pid = self.pidfile.read_pid()
        try:
            os.kill(pid, signal.SIGTERM)
        except OSError as exc:
            raise DaemonRunnerStopFailureError(
                "Failed to terminate %(pid)d: %(exc)s" % vars())

    def _stop(self):
        """ Exit the daemon process specified in the current PID file.
            """
        if not self.pidfile.is_locked():
            pidfile_path = self.pidfile.path
            raise DaemonRunnerStopFailureError(
                "PID file %(pidfile_path)r not locked" % vars())

        if is_pidfile_stale(self.pidfile):
            self.pidfile.break_lock()
        else:
            self._terminate_daemon_process()

    def _restart(self):
        """ Stop, then start.
            """
        self._stop()
        self._start()

    action_funcs = {
        'start': _start,
        'stop': _stop,
        'restart': _restart,
    }

    def _get_action_func(self):
        """ Return the function for the specified action.

            Raises ``DaemonRunnerInvalidActionError`` if the action is
            unknown.

            """
        try:
            func = self.action_funcs[self.action]
        except KeyError:
            raise DaemonRunnerInvalidActionError("Unknown action: %(action)r" %
                                                 vars(self))
        return func

    def do_action(self):
        """ Perform the requested action.
            """
        func = self._get_action_func()
        func(self)