Ejemplo n.º 1
0
def expire_zookeeper_client_session(client, timeout=10):
    """Expire zookeeper session for the given client.

    This method should only be used for testing purposed.
    It will induce an EXPIRED_SESSION_STATE event in
    given client.

    Args:
        client: ZookeeperClient object
        timeout: optional timeout in seconds
            to wait for the session to expire.
            If None, this call will block.
            This is not recommended.
    
    Returns:
        True if session exipration occured within
        timeout seconds, False otherwise.
    """
    #session expiration event to wait on
    session_expiration_event = Event()

    def observer(event):
        if event.state_name == "EXPIRED_SESSION_STATE":
            session_expiration_event.set()
    client.add_session_observer(observer)

    #construct new client with same session_id
    #so we can cause a session expiration event
    #in our other client.
    zookeeper_client = ZookeeperClient(
            client.servers,
            client.session_id,
            client.session_password)
    
    def zookeeper_observer(event):
        #Upon connection, immediately stop the client
        #which will cause a session expiration in
        #self.zookeeper_client.
        if event.state_name == "CONNECTED_STATE":
            zookeeper_client.stop()
    
    zookeeper_client.add_session_observer(zookeeper_observer)
    zookeeper_client.start()
    zookeeper_client.join()
    
    session_expiration_event.wait(timeout)

    client.remove_session_observer(observer)
    return session_expiration_event.is_set()
Ejemplo n.º 2
0
def expire_zookeeper_client_session(client, timeout=10):
    """Expire zookeeper session for the given client.

    This method should only be used for testing purposed.
    It will induce an EXPIRED_SESSION_STATE event in
    given client.

    Args:
        client: ZookeeperClient object
        timeout: optional timeout in seconds
            to wait for the session to expire.
            If None, this call will block.
            This is not recommended.
    
    Returns:
        True if session exipration occured within
        timeout seconds, False otherwise.
    """
    #session expiration event to wait on
    session_expiration_event = Event()

    def observer(event):
        if event.state_name == "EXPIRED_SESSION_STATE":
            session_expiration_event.set()

    client.add_session_observer(observer)

    #construct new client with same session_id
    #so we can cause a session expiration event
    #in our other client.
    zookeeper_client = ZookeeperClient(client.servers, client.session_id,
                                       client.session_password)

    def zookeeper_observer(event):
        #Upon connection, immediately stop the client
        #which will cause a session expiration in
        #self.zookeeper_client.
        if event.state_name == "CONNECTED_STATE":
            zookeeper_client.stop()

    zookeeper_client.add_session_observer(zookeeper_observer)
    zookeeper_client.start()
    zookeeper_client.join()

    session_expiration_event.wait(timeout)

    client.remove_session_observer(observer)
    return session_expiration_event.is_set()
Ejemplo n.º 3
0
class ServiceHandler(TRService.Iface, Handler):
    """Service handler base class.
    
    This class is intended to be subclassed by concrete
    service handlers.
    """

    def __init__(self, service, zookeeper_hosts,
            database_connection=None, database_connection_pool_size=5):
        """ServiceHandler constructor.

        Args:
            service: Service object. Note that this will not be fully initialized
                until start() is called. It may be neccessary delay some handler
                instantiation until then.
            zookeeper_hosts: list of zookeeper hosts, i.e. ["localhost:2181", "localdev:2181"]
            database_connection: optional database connection string
        """
        self.service = service
        self.options = {}
        self.counters = AtomicCounters()
        self.running = False

        #Zookeeper client
        self.zookeeper_client = ZookeeperClient(zookeeper_hosts)

        #Database session factory
        if database_connection:
            from sqlalchemy import create_engine
            from sqlalchemy.orm import sessionmaker
            engine = create_engine(
                    database_connection,
                    pool_size=database_connection_pool_size)
            self.DatabaseSession = sessionmaker(bind=engine)
        else:
            self.DatabaseSession = None

        #Registrar
        self.registrar = ZookeeperServiceRegistrar(self.zookeeper_client)
        
        #Add counter decorator to track service method calls
        def counter_decorator(func):
            requests_counter = self.counters.get_counter("requests")
            open_requests_counter = self.counters.get_counter("open_requests")
            def wrapper(*args, **kwargs):
                try:
                    requests_counter.increment()
                    open_requests_counter.increment()
                    return func(*args, **kwargs)
                finally:
                    open_requests_counter.decrement()
            return wrapper
        self._decorate_service_methods(counter_decorator)

    def _decorate_service_methods(self, decorator, cls=None, decorated=None):
        """Decorate service interface methods at runtime.

        This method will decorate the service instance methods on the
        current handler with the given decorator. Service interface
        methods are identified as any callable on a base class
        with the name "Iface".

        This method should be used judicially to limit the magic.
        The main advantage of this method is that decorators can
        be added to all service methods from a base class,
        without specific knowledge of each service's interface.

        Derived classes should NOT add decorators using this method.
        """
        cls = cls or self.__class__
        decorated = decorated if decorated is not None else {}

        if cls.__name__ == "Iface":
            for attribute_name in cls.__dict__:
                attribute = getattr(self, attribute_name)
                if callable(attribute) and attribute_name not in decorated:
                    setattr(self, attribute_name, decorator(attribute))
                    decorated[attribute_name] = True
        
        for base_class in cls.__bases__:
            self._decorate_service_methods(decorator, base_class, decorated)

    def start(self):
        """Start service handler."""
        if not self.running:
            self.running = True
            self.zookeeper_client.start()
            self.registrar.register_service(self.service)
    
    def join(self, timeout):
        """Join service handler.

        Join the handler, waiting for the completion of all threads 
        or greenlets.

        Args:
            timeout: Optional timeout in seconds to observe before returning.
                If timeout is specified, the status() method must be called
                to determine if the handler is still running.
        """
        self.zookeeper_client.join(timeout)
    
    def stop(self):
        """Stop service handler."""
        if self.running:
            self.running = False
            self.registrar.unregister_service(self.service)
            self.zookeeper_client.stop()

    def status(self):
        """Get the handler status.

        Returns Status enum.
        """
        if self.running:
            return Status.ALIVE
        else:
            return Status.STOPPED

    def get_database_session(self, **kwargs):
        """Return new database SQLAlchemy database session.

        Returns:
            new SQLAlchemy session
        Raises:
            RuntimeError: If database_connection not provided to handler.
        """
        if self.DatabaseSession:
            return self.DatabaseSession(**kwargs)
        else:
            raise RuntimeError("database_connection not provided")

    def getName(self, requestContext):
        """Get service name.

        Args:
            requestContext: RequestContext object containing user information.
        
        Returns:
            service name (string)
        """
        return self.service.name()

    def getVersion(self, requestContext):
        """Get service version.

        Args:
            requestContext: RequestContext object containing user information.
        
        Returns:
            service version (string)
        """
        return self.service.version()

    def getBuildNumber(self, requestContext):
        """Get service build number.

        Args:
            requestContext: RequestContext object containing user information.
        
        Returns:
            service build number (string)
        """
        return self.service.build() or ""

    def getStatus(self, requestContext):
        """Get service status.

        Args:
            requestContext: RequestContext object containing user information.
        
        Returns:
            Status enum
        """
        return self.service.status()

    def getStatusDetails(self, requestContext):
        """Get service status details.

        Args:
            requestContext: RequestContext object containing user information.
        
        Returns:
            String description of the current Status enum.
        """
        if self.running:
            return "Alive and well"
        else:
            return "Dead"

    def getCounter(self, requestContext, key):
        """Get service counter.

        Args:
            requestContext: RequestContext object containing user information.
            key: counter name
        
        Returns:
            counter value
        """
        if key in self.counters:
            return self.counters[key]
        else:
            return -1

    def getCounters(self, requestContext):
        """Get service counters.

        Args:
            requestContext: RequestContext object containing user information.
        
        Returns:
            Dict of service specific counters.
        """
        return self.counters.as_dict()

    def getOption(self, requestContext, key):
        """Get service option.

        Args:
            requestContext: RequestContext object containing user information.
            key: Option name
        
        Returns:
            String value for the option.
        """
        if key in self.options:
            return self.options[key]
        else:
            return "invalid option"

    def getOptions(self, requestContext):
        """Get all service options.

        Args:
            requestContext: RequestContext object containing user information.
        
        Returns:
            Dict of service specific options  key / values.
        """
        return self.options

    def setOption(self, requestContext, key, value):
        """Set service options.

        Args:
            requestContext: RequestContext object containing user information.
            key: Option name (string)
            value: Option value
        """
        self.options[key] = value

    def shutdown(self, requestContext):
        """Shutdown service.

        Args:
            requestContext: RequestContext object containing user information.
        """
        self.service.stop()

    def reinitialize(self, requestContext):
        """Reinitialize service.

        Args:
            requestContext: RequestContext object containing user information.
        """
        pass
Ejemplo n.º 4
0
class ServiceHandler(TRService.Iface, Handler):
    """Service handler base class.
    
    This class is intended to be subclassed by concrete
    service handlers.
    """
    def __init__(self,
                 service,
                 zookeeper_hosts,
                 database_connection=None,
                 database_connection_pool_size=5):
        """ServiceHandler constructor.

        Args:
            service: Service object. Note that this will not be fully initialized
                until start() is called. It may be neccessary delay some handler
                instantiation until then.
            zookeeper_hosts: list of zookeeper hosts, i.e. ["localhost:2181", "localdev:2181"]
            database_connection: optional database connection string
        """
        self.service = service
        self.options = {}
        self.counters = AtomicCounters()
        self.running = False

        #Zookeeper client
        self.zookeeper_client = ZookeeperClient(zookeeper_hosts)

        #Database session factory
        if database_connection:
            from sqlalchemy import create_engine
            from sqlalchemy.orm import sessionmaker
            engine = create_engine(database_connection,
                                   pool_size=database_connection_pool_size)
            self.DatabaseSession = sessionmaker(bind=engine)
        else:
            self.DatabaseSession = None

        #Registrar
        self.registrar = ZookeeperServiceRegistrar(self.zookeeper_client)

        #Add counter decorator to track service method calls
        def counter_decorator(func):
            requests_counter = self.counters.get_counter("requests")
            open_requests_counter = self.counters.get_counter("open_requests")

            def wrapper(*args, **kwargs):
                try:
                    requests_counter.increment()
                    open_requests_counter.increment()
                    return func(*args, **kwargs)
                finally:
                    open_requests_counter.decrement()

            return wrapper

        self._decorate_service_methods(counter_decorator)

    def _decorate_service_methods(self, decorator, cls=None, decorated=None):
        """Decorate service interface methods at runtime.

        This method will decorate the service instance methods on the
        current handler with the given decorator. Service interface
        methods are identified as any callable on a base class
        with the name "Iface".

        This method should be used judicially to limit the magic.
        The main advantage of this method is that decorators can
        be added to all service methods from a base class,
        without specific knowledge of each service's interface.

        Derived classes should NOT add decorators using this method.
        """
        cls = cls or self.__class__
        decorated = decorated if decorated is not None else {}

        if cls.__name__ == "Iface":
            for attribute_name in cls.__dict__:
                attribute = getattr(self, attribute_name)
                if callable(attribute) and attribute_name not in decorated:
                    setattr(self, attribute_name, decorator(attribute))
                    decorated[attribute_name] = True

        for base_class in cls.__bases__:
            self._decorate_service_methods(decorator, base_class, decorated)

    def start(self):
        """Start service handler."""
        if not self.running:
            self.running = True
            self.zookeeper_client.start()
            self.registrar.register_service(self.service)

    def join(self, timeout):
        """Join service handler.

        Join the handler, waiting for the completion of all threads 
        or greenlets.

        Args:
            timeout: Optional timeout in seconds to observe before returning.
                If timeout is specified, the status() method must be called
                to determine if the handler is still running.
        """
        self.zookeeper_client.join(timeout)

    def stop(self):
        """Stop service handler."""
        if self.running:
            self.running = False
            self.registrar.unregister_service(self.service)
            self.zookeeper_client.stop()

    def status(self):
        """Get the handler status.

        Returns Status enum.
        """
        if self.running:
            return Status.ALIVE
        else:
            return Status.STOPPED

    def get_database_session(self, **kwargs):
        """Return new database SQLAlchemy database session.

        Returns:
            new SQLAlchemy session
        Raises:
            RuntimeError: If database_connection not provided to handler.
        """
        if self.DatabaseSession:
            return self.DatabaseSession(**kwargs)
        else:
            raise RuntimeError("database_connection not provided")

    def getName(self, requestContext):
        """Get service name.

        Args:
            requestContext: RequestContext object containing user information.
        
        Returns:
            service name (string)
        """
        return self.service.name()

    def getVersion(self, requestContext):
        """Get service version.

        Args:
            requestContext: RequestContext object containing user information.
        
        Returns:
            service version (string)
        """
        return self.service.version()

    def getBuildNumber(self, requestContext):
        """Get service build number.

        Args:
            requestContext: RequestContext object containing user information.
        
        Returns:
            service build number (string)
        """
        return self.service.build() or ""

    def getStatus(self, requestContext):
        """Get service status.

        Args:
            requestContext: RequestContext object containing user information.
        
        Returns:
            Status enum
        """
        return self.service.status()

    def getStatusDetails(self, requestContext):
        """Get service status details.

        Args:
            requestContext: RequestContext object containing user information.
        
        Returns:
            String description of the current Status enum.
        """
        if self.running:
            return "Alive and well"
        else:
            return "Dead"

    def getCounter(self, requestContext, key):
        """Get service counter.

        Args:
            requestContext: RequestContext object containing user information.
            key: counter name
        
        Returns:
            counter value
        """
        if key in self.counters:
            return self.counters[key]
        else:
            return -1

    def getCounters(self, requestContext):
        """Get service counters.

        Args:
            requestContext: RequestContext object containing user information.
        
        Returns:
            Dict of service specific counters.
        """
        return self.counters.as_dict()

    def getOption(self, requestContext, key):
        """Get service option.

        Args:
            requestContext: RequestContext object containing user information.
            key: Option name
        
        Returns:
            String value for the option.
        """
        if key in self.options:
            return self.options[key]
        else:
            return "invalid option"

    def getOptions(self, requestContext):
        """Get all service options.

        Args:
            requestContext: RequestContext object containing user information.
        
        Returns:
            Dict of service specific options  key / values.
        """
        return self.options

    def setOption(self, requestContext, key, value):
        """Set service options.

        Args:
            requestContext: RequestContext object containing user information.
            key: Option name (string)
            value: Option value
        """
        self.options[key] = value

    def shutdown(self, requestContext):
        """Shutdown service.

        Args:
            requestContext: RequestContext object containing user information.
        """
        self.service.stop()

    def reinitialize(self, requestContext):
        """Reinitialize service.

        Args:
            requestContext: RequestContext object containing user information.
        """
        pass