示例#1
0
 def addHendrix(self):
     "instantiates the HendrixService"
     self.hendrix = HendrixService(self.application,
                                   self.options['http_port'],
                                   resources=self.resources,
                                   services=self.services,
                                   loud=self.options['loud'])
示例#2
0
文件: base.py 项目: ichem/hendrix
 def addHendrix(self):
     '''
     Instantiates a HendrixService with this object's threadpool.
     It will be added as a service later.
     '''
     self.hendrix = HendrixService(self.application,
                                   port=self.options['http_port'],
                                   threadpool=self.getThreadPool(),
                                   resources=self.resources,
                                   services=self.services,
                                   loud=self.options['loud'])
示例#3
0
 def addHendrix(self):
     '''
     Instantiates a HendrixService with this object's threadpool.
     It will be added as a service later.
     '''
     self.hendrix = HendrixService(self.application,
                                   threadpool=self.getThreadPool(),
                                   resources=self.resources,
                                   services=self.services,
                                   loud=self.options['loud'])
     if self.options["https_only"] is not True:
         self.hendrix.spawn_new_server(self.options['http_port'],
                                       HendrixTCPService)
示例#4
0
文件: base.py 项目: pritstift/hendrix
 def addHendrix(self):
     '''
     Instantiates a HendrixService with this object's threadpool.
     It will be added as a service later.
     '''
     self.hendrix = HendrixService(
         self.application,
         port=self.options['http_port'],
         threadpool=self.getThreadPool(),
         resources=self.resources,
         services=self.services,
         loud=self.options['loud']
     )
示例#5
0
文件: base.py 项目: hendrix/hendrix
 def addHendrix(self):
     '''
     Instantiates a HendrixService with this object's threadpool.
     It will be added as a service later.
     '''
     self.hendrix = HendrixService(
         self.application,
         threadpool=self.getThreadPool(),
         resources=self.resources,
         services=self.services,
         loud=self.options['loud']
     )
     if self.options["https_only"] is not True:
         self.hendrix.spawn_new_server(self.options['http_port'], HendrixTCPService)
示例#6
0
文件: base.py 项目: hendrix/hendrix
class HendrixDeploy(object):
    """
    HendrixDeploy encapsulates the necessary information needed to deploy
    the HendrixService on a single or multiple processes.
    """

    def __init__(self, action='start', options={},
                 reactor=reactor, threadpool=None):
        self.action = action
        self.options = hx_options()
        self.options.update(options)
        self.services = []
        self.resources = []
        self.reactor = reactor

        self.threadpool = threadpool or ThreadPool(name="Hendrix Web Service")

        self.use_settings = True
        # because running the management command overrides self.options['wsgi']
        if self.options['wsgi']:
            if hasattr(self.options['wsgi'], '__call__'):
                # If it has a __call__, we assume that it is the application
                # object itself.
                self.application = self.options['wsgi']
                try:
                    self.options['wsgi'] = "%s.%s" % (
                        self.application.__module__, self.application.__name__
                    )
                except AttributeError:
                    self.options['wsgi'] = self.application.__class__.__name__
            else:
                # Otherwise, we'll try to discern an application in the belief
                # that this is a dot path.
                wsgi_dot_path = self.options['wsgi']
                # will raise AttributeError if we can't import it.
                self.application = HendrixDeploy.importWSGI(wsgi_dot_path)
            self.use_settings = False
        else:
            os.environ['DJANGO_SETTINGS_MODULE'] = self.options['settings']
            settings = import_string('django.conf.settings')
            self.services = get_additional_services(settings)
            self.resources = get_additional_resources(settings)
            self.options = HendrixDeploy.getConf(settings, self.options)

        if self.use_settings:
            django = importlib.import_module('django')
            if django.VERSION[:2] >= (1, 7):
                django.setup()
            wsgi_dot_path = getattr(settings, 'WSGI_APPLICATION', None)
            self.application = HendrixDeploy.importWSGI(wsgi_dot_path)

        self.is_secure = self.options['key'] and self.options['cert']

        self.servers = []
        self._lock = DeferredLock()

    @classmethod
    def importWSGI(cls, wsgi_dot_path):
        try:
            wsgi_module, application_name = wsgi_dot_path.rsplit('.', 1)
        except AttributeError:
            pid = os.getpid()
            chalk.red(
                "Unable to discern a WSGI application from '%s'" %
                wsgi_dot_path
            )
            os.kill(pid, 15)
        try:
            wsgi = importlib.import_module(wsgi_module)
        except ImportError:
            chalk.red("Unable to Import module '%s'\n" % wsgi_dot_path)
            raise
        return getattr(wsgi, application_name, None)

    @classmethod
    def getConf(cls, settings, options):
        "updates the options dict to use config options in the settings module"
        ports = ['http_port', 'https_port', 'cache_port']
        for port_name in ports:
            port = getattr(settings, port_name.upper(), None)
            # only use the settings ports if the defaults were left unchanged
            default = getattr(defaults, port_name.upper())
            if port and options.get(port_name) == default:
                options[port_name] = port

        _opts = [
            ('key', 'hx_private_key'),
            ('cert', 'hx_certficate'),
            ('wsgi', 'wsgi_application')
        ]
        for opt_name, settings_name in _opts:
            opt = getattr(settings, settings_name.upper(), None)
            if opt:
                options[opt_name] = opt

        if not options['settings']:
            options['settings'] = environ['DJANGO_SETTINGS_MODULE']
        return options

    def addServices(self):
        """
        a helper function used in HendrixDeploy.run
        it instanstiates the HendrixService and adds child services
        note that these services will also be run on all processes
        """
        self.addHendrix()

    def addGlobalServices(self):
        """
        This is where we put service that we don't want to be duplicated on
        worker subprocesses
        """
        pass

    def getThreadPool(self):
        '''
        Case to match twisted.internet.reactor
        '''
        return self.threadpool

    def addHendrix(self):
        '''
        Instantiates a HendrixService with this object's threadpool.
        It will be added as a service later.
        '''
        self.hendrix = HendrixService(
            self.application,
            threadpool=self.getThreadPool(),
            resources=self.resources,
            services=self.services,
            loud=self.options['loud']
        )
        if self.options["https_only"] is not True:
            self.hendrix.spawn_new_server(self.options['http_port'], HendrixTCPService)

    def catalogServers(self, hendrix):
        "collects a list of service names serving on TCP or SSL"
        for service in hendrix.services:
            if isinstance(service, (TCPServer, SSLServer)):
                self.servers.append(service.name)

    def _listening_message(self):
        message = "non-TLS listening on port {}".format(self.options['http_port'])
        return message

    def run(self):
        "sets up the desired services and runs the requested action"
        self.addServices()
        self.catalogServers(self.hendrix)
        action = self.action
        fd = self.options['fd']

        if action.startswith('start'):
            chalk.blue(self._listening_message())
            getattr(self, action)(fd)

            ###########################
            # annnnd run the reactor! #
            ###########################
            try:
                self.reactor.run()
            finally:
                shutil.rmtree(PID_DIR, ignore_errors=True)  # cleanup tmp PID dir

        elif action == 'restart':
            getattr(self, action)(fd=fd)
        else:
            getattr(self, action)()

    @property
    def pid(self):
        "The default location of the pid file for process management"
        return get_pid(self.options)

    def getSpawnArgs(self):
        _args = [
            'hx',
            'start',  # action

            # kwargs
            '--http_port', str(self.options['http_port']),
            '--https_port', str(self.options['https_port']),
            '--cache_port', str(self.options['cache_port']),
            '--workers', '0',
            '--fd', pickle.dumps(self.fds),
        ]

        # args/signals
        if self.options['dev']:
            _args.append('--dev')

        if not self.use_settings:
            _args += ['--wsgi', self.options['wsgi']]
        return _args

    def start(self, fd=None):
        if fd is None:
            # anything in this block is only run once
            self.addGlobalServices()
            self.hendrix.startService()
            pids = [str(os.getpid())]  # script pid
            if self.options['workers']:
                self.launchWorkers(pids)
            self.pid_file = self.openPidList(pids)
        else:
            fds = pickle.loads(fd)
            factories = {}
            for name in self.servers:
                factory = self.disownService(name)
                factories[name] = factory
            self.hendrix.startService()
            for name, factory in factories.iteritems():
                self.addSubprocess(fds, name, factory)
            chalk.eraser()
            chalk.blue('Starting Hendrix...')

    def setFDs(self):
        """
        Iterator for file descriptors.
        Seperated from launchworkers for clarity and readability.
        """
        # 0 corresponds to stdin, 1 to stdout, 2 to stderr
        self.childFDs = {0: 0, 1: 1, 2: 2}
        self.fds = {}
        for name in self.servers:
            self.port = self.hendrix.get_port(name)
            fd = self.port.fileno()
            self.childFDs[fd] = fd
            self.fds[name] = fd

    def launchWorkers(self, pids):
        # Create a new listening port and several other processes to
        # help out.
        self.setFDs()
        args = self.getSpawnArgs()
        transports = []
        for i in range(self.options['workers']):
            time.sleep(0.05)
            transport = self.reactor.spawnProcess(
                DeployServerProtocol(args), 'hx', args, childFDs=self.childFDs, env=environ
            )
            transports.append(transport)
            pids.append(str(transport.pid))

    def openPidList(self, pids):
        with open(self.pid, 'w') as pid_file:
            pid_file.write('\n'.join(pids))
        return pid_file

    def addSubprocess(self, fds, name, factory):
        """
        Public method for _addSubprocess.
        Wraps reactor.adoptStreamConnection in 
        a simple DeferredLock to guarantee
        workers play well together.
        """
        self._lock.run(self._addSubprocess, self, fds, name, factory)

    def _addSubprocess(self, fds, name, factory):
        self.reactor.adoptStreamConnection(
            fds[name], AF_INET, factory
        )

    def stop(self, sig=9):
        with open(self.pid) as pid_file:
            pids = pid_file.readlines()
            for pid in pids:
                try:
                    os.kill(int(pid), sig)
                except OSError:
                    # OSError raised when it trys to kill the child processes
                    pass
        os.remove(self.pid)
        chalk.green('Stopping Hendrix...')

    def start_reload(self, fd=None):
        self.start(fd=fd)

    def restart(self, fd=None):
        self.stop()
        time.sleep(1)  # wait a second to ensure the port is closed
        self.start(fd)

    def disownService(self, name):
        """
        disowns a service on hendirix by name
        returns a factory for use in the adoptStreamPort part of setting up
        multiple processes
        """
        _service = self.hendrix.getServiceNamed(name)
        _service.disownServiceParent()
        return _service.factory

    def add_non_tls_websocket_service(self, websocket_factory):
        autobahn.twisted.websocket.listenWS(websocket_factory)
示例#7
0
class HendrixDeploy(object):
    """
    HendrixDeploy encapsulates the necessary information needed to deploy
    the HendrixService on a single or multiple processes.
    """
    def __init__(self,
                 action='start',
                 options={},
                 reactor=reactor,
                 threadpool=None):
        self.action = action
        self.options = hx_options()
        self.options.update(options)
        self.services = []
        self.resources = []
        self.reactor = reactor

        self.threadpool = threadpool or ThreadPool(name="Hendrix Web Service")

        self.use_settings = True
        # because running the management command overrides self.options['wsgi']
        if self.options['wsgi']:
            if hasattr(self.options['wsgi'], '__call__'):
                # If it has a __call__, we assume that it is the application
                # object itself.
                self.application = self.options['wsgi']
                try:
                    self.options['wsgi'] = "%s.%s" % (
                        self.application.__module__, self.application.__name__)
                except AttributeError:
                    self.options['wsgi'] = self.application.__class__.__name__
            else:
                # Otherwise, we'll try to discern an application in the belief
                # that this is a dot path.
                wsgi_dot_path = self.options['wsgi']
                # will raise AttributeError if we can't import it.
                self.application = HendrixDeploy.importWSGI(wsgi_dot_path)
            self.use_settings = False
        else:
            os.environ['DJANGO_SETTINGS_MODULE'] = self.options['settings']
            settings = import_string('django.conf.settings')
            self.services = get_additional_services(settings)
            self.resources = get_additional_resources(settings)
            self.options = HendrixDeploy.getConf(settings, self.options)

        if self.use_settings:
            django = importlib.import_module('django')
            if django.VERSION[:2] >= (1, 7):
                django.setup()
            wsgi_dot_path = getattr(settings, 'WSGI_APPLICATION', None)
            self.application = HendrixDeploy.importWSGI(wsgi_dot_path)

        self.is_secure = self.options['key'] and self.options['cert']

        self.servers = []
        self._lock = DeferredLock()

    @classmethod
    def importWSGI(cls, wsgi_dot_path):
        try:
            wsgi_module, application_name = wsgi_dot_path.rsplit('.', 1)
        except AttributeError:
            pid = os.getpid()
            chalk.red("Unable to discern a WSGI application from '%s'" %
                      wsgi_dot_path)
            os.kill(pid, 15)
        try:
            wsgi = importlib.import_module(wsgi_module)
        except ImportError:
            chalk.red("Unable to Import module '%s'\n" % wsgi_dot_path)
            raise
        return getattr(wsgi, application_name, None)

    @classmethod
    def getConf(cls, settings, options):
        "updates the options dict to use config options in the settings module"
        ports = ['http_port', 'https_port', 'cache_port']
        for port_name in ports:
            port = getattr(settings, port_name.upper(), None)
            # only use the settings ports if the defaults were left unchanged
            default = getattr(defaults, port_name.upper())
            if port and options.get(port_name) == default:
                options[port_name] = port

        _opts = [('key', 'hx_private_key'), ('cert', 'hx_certficate'),
                 ('wsgi', 'wsgi_application')]
        for opt_name, settings_name in _opts:
            opt = getattr(settings, settings_name.upper(), None)
            if opt:
                options[opt_name] = opt

        if not options['settings']:
            options['settings'] = environ['DJANGO_SETTINGS_MODULE']
        return options

    def addServices(self):
        """
        a helper function used in HendrixDeploy.run
        it instanstiates the HendrixService and adds child services
        note that these services will also be run on all processes
        """
        self.addHendrix()

    def addGlobalServices(self):
        """
        This is where we put service that we don't want to be duplicated on
        worker subprocesses
        """
        pass

    def getThreadPool(self):
        '''
        Case to match twisted.internet.reactor
        '''
        return self.threadpool

    def addHendrix(self):
        '''
        Instantiates a HendrixService with this object's threadpool.
        It will be added as a service later.
        '''
        self.hendrix = HendrixService(self.application,
                                      threadpool=self.getThreadPool(),
                                      resources=self.resources,
                                      services=self.services,
                                      loud=self.options['loud'])
        if self.options["https_only"] is not True:
            self.hendrix.spawn_new_server(self.options['http_port'],
                                          HendrixTCPService)

    def catalogServers(self, hendrix):
        "collects a list of service names serving on TCP or SSL"
        for service in hendrix.services:
            if isinstance(service, (TCPServer, SSLServer)):
                self.servers.append(service.name)

    def _listening_message(self):
        message = "non-TLS listening on port {}".format(
            self.options['http_port'])
        return message

    def run(self):
        "sets up the desired services and runs the requested action"
        self.addServices()
        self.catalogServers(self.hendrix)
        action = self.action
        fd = self.options['fd']

        if action.startswith('start'):
            chalk.blue(self._listening_message())
            getattr(self, action)(fd)

            ###########################
            # annnnd run the reactor! #
            ###########################
            self.reactor.run()

        elif action == 'restart':
            getattr(self, action)(fd=fd)
        else:
            getattr(self, action)()

    @property
    def pid(self):
        "The default location of the pid file for process management"
        return get_pid(self.options)

    def getSpawnArgs(self):
        _args = [
            'hx',
            'start',  # action

            # kwargs
            '--http_port',
            str(self.options['http_port']),
            '--https_port',
            str(self.options['https_port']),
            '--cache_port',
            str(self.options['cache_port']),
            '--workers',
            '0',
            '--fd',
            pickle.dumps(self.fds),
        ]

        # args/signals
        if self.options['dev']:
            _args.append('--dev')

        if not self.use_settings:
            _args += ['--wsgi', self.options['wsgi']]
        return _args

    def start(self, fd=None):
        if fd is None:
            # anything in this block is only run once
            self.addGlobalServices()
            self.hendrix.startService()
            pids = [str(os.getpid())]  # script pid
            if self.options['workers']:
                self.launchWorkers(pids)
            self.pid_file = self.openPidList(pids)
        else:
            fds = pickle.loads(fd)
            factories = {}
            for name in self.servers:
                factory = self.disownService(name)
                factories[name] = factory
            self.hendrix.startService()
            for name, factory in factories.iteritems():
                self.addSubprocess(fds, name, factory)
            chalk.eraser()
            chalk.blue('Starting Hendrix...')

    def setFDs(self):
        """
        Iterator for file descriptors.
        Seperated from launchworkers for clarity and readability.
        """
        # 0 corresponds to stdin, 1 to stdout, 2 to stderr
        self.childFDs = {0: 0, 1: 1, 2: 2}
        self.fds = {}
        for name in self.servers:
            self.port = self.hendrix.get_port(name)
            fd = self.port.fileno()
            self.childFDs[fd] = fd
            self.fds[name] = fd

    def launchWorkers(self, pids):
        # Create a new listening port and several other processes to
        # help out.
        self.setFDs()
        args = self.getSpawnArgs()
        transports = []
        for i in range(self.options['workers']):
            time.sleep(0.05)
            transport = self.reactor.spawnProcess(DeployServerProtocol(args),
                                                  'hx',
                                                  args,
                                                  childFDs=self.childFDs,
                                                  env=environ)
            transports.append(transport)
            pids.append(str(transport.pid))

    def openPidList(self, pids):
        with open(self.pid, 'w') as pid_file:
            pid_file.write('\n'.join(pids))
        return pid_file

    def addSubprocess(self, fds, name, factory):
        """
        Public method for _addSubprocess.
        Wraps reactor.adoptStreamConnection in 
        a simple DeferredLock to guarantee
        workers play well together.
        """
        self._lock.run(self._addSubprocess, self, fds, name, factory)

    def _addSubprocess(self, fds, name, factory):
        self.reactor.adoptStreamConnection(fds[name], AF_INET, factory)

    def stop(self, sig=9):
        with open(self.pid) as pid_file:
            pids = pid_file.readlines()
            for pid in pids:
                try:
                    os.kill(int(pid), sig)
                except OSError:
                    # OSError raised when it trys to kill the child processes
                    pass
        os.remove(self.pid)
        chalk.green('Stopping Hendrix...')

    def start_reload(self, fd=None):
        self.start(fd=fd)

    def restart(self, fd=None):
        self.stop()
        time.sleep(1)  # wait a second to ensure the port is closed
        self.start(fd)

    def disownService(self, name):
        """
        disowns a service on hendirix by name
        returns a factory for use in the adoptStreamPort part of setting up
        multiple processes
        """
        _service = self.hendrix.getServiceNamed(name)
        _service.disownServiceParent()
        return _service.factory

    def add_non_tls_websocket_service(self, websocket_factory):
        autobahn.twisted.websocket.listenWS(websocket_factory)