ó
ÍÿŠTc           @   su   d  Z  d d l Z d d l m Z d d l m Z d d l m Z d d l m	 Z	 d „  Z
 d e f d	 „  ƒ  YZ d S(
   s­  Bridge client side plugins to the C{MessageExchange}.

The C{BrokerServer} provides C{BrokerClient}s with a mechanism to send messages
to the server and, likewise, triggers those plugins to take action when a
exchange is impending or resynchronisaton is required.

Each C{BrokerClient} has to be registered using the
L{BrokerServer.register_client} method, after which two way communications is
possible between the C{BrokerServer} and the C{BrokerClient}.

Resynchronisation Sequence
==========================

See L{landscape.broker.exchange} sequence diagram for origin of the
"resynchronize-clients" event.

Diagram::


 1. [event 1]               --->  BrokerServer        : Event
                                                      : "resynchronize-clients"

 2. [event 2]               <---  BrokerServer        : Broadcast event
                                                      : "resynchronize"

 3. [optional: various L{BrowserClientPlugin}s respond
               to the "resynchronize" event to reset
               themselves and start report afresh.]
     (See: L{landscape.monitor.packagemonitor.PackageMonitor}
           L{landscape.monitor.plugin.MonitorPlugin}
           L{landscape.manager.keystonetoken.KeystoneToken}
           L{landscape.monitor.activeprocessinfo.ActiveProcessInfo} )


 4. [event 1]               ---> MessageExchange      : Event
    (NOTE, this is the same event as step 1           : "resynchronize-clients"
     it is handled by both BrokerServer and
     MessageExchange.
     See MessageExchange._resynchronize )

 5. MessageExchange         ---> MessageExchange      : Schedule urgent
                                                      : exchange

iÿÿÿÿN(   t   Deferred(   t   gather_results(   t   remote(   t   FAILEDc            s(   |  j  j d d ƒ ‰  ‡  f d †  } | S(   s&  Turns a L{BrokerServer} method into an event broadcaster.

    When the decorated method is called, an event is fired on all connected
    clients. The event will have the same name as the method being called,
    except that any underscore in the method name will be replaced with a dash.
    t   _t   -c            sC   g  } x0 |  j  ƒ  D]" } | j | j ˆ  | | Ž ƒ q Wt | ƒ S(   N(   t   get_clientst   appendt
   fire_eventR   (   t   selft   argst   kwargst   firedt   client(   t
   event_type(    s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyt   broadcast_event@   s     (   t   __name__t   replace(   t   methodR   (    (   R   s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyt   event7   s    t   BrokerServerc           B   s”  e  Z d  Z d Z d „  Z e d „  ƒ Z e d d „ ƒ Z e d „  ƒ Z	 d „  Z
 d „  Z d „  Z d	 „  Z e e d
 „ ƒ Z e d „  ƒ Z e d „  ƒ Z e d „  ƒ Z e d „  ƒ Z e d „  ƒ Z e d „  ƒ Z e d „  ƒ Z e d „  ƒ Z e d „  ƒ Z e d „  ƒ Z e d „  ƒ Z e d „  ƒ Z e d „  ƒ Z e d „  ƒ Z e d „  ƒ Z e d „  ƒ Z  d „  Z! d „  Z" e d „  ƒ Z# RS(   s©  
    A broker server capable of handling messages from plugins connected using
    the L{BrokerProtocol}.

    @param config: The L{BrokerConfiguration} used by the broker.
    @param reactor: The L{LandscapeReactor} driving the broker's events.
    @param exchange: The L{MessageExchange} to send messages with.
    @param registration: The {RegistrationHandler}.
    @param message_store: The broker's L{MessageStore}.
    t   brokerc         C   sÚ   d d l  m } | ƒ  |  _ | |  _ | |  _ | |  _ | |  _ | |  _ i  |  _ i  |  _	 | |  _
 | j d |  j ƒ | j d |  j ƒ | j d |  j ƒ | j d |  j ƒ | j d |  j ƒ | j d |  j ƒ d  S(	   Niÿÿÿÿ(   t   get_component_registryt   messages   impending-exchanges   message-type-acceptance-changeds   server-uuid-changeds   package-data-changeds   resynchronize-clients(   t   landscape.broker.ampR   t   connectors_registryt   _configt   _reactort
   _exchangert   _registrationt   _message_storet   _registered_clientst   _connectorst   _pingert   call_ont   broadcast_messaget   impending_exchanget   message_type_acceptance_changedt   server_uuid_changedt   package_data_changedt   resynchronize(   R	   t   configt   reactort   exchanget   registrationt   message_storet   pingerR   (    (    s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyt   __init__V   s"    									
c         C   s   t  S(   s   Return C{True}.(   t   True(   R	   (    (    s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyt   pingk   s    c         C   s   |  j  j d | ƒ S(   s¦  Get a unique session ID to be used when sending messages.

        Anything that wants to send a message to the server via the broker is
        required to first acquire a session ID with this method. Such session
        IDs must be passed to L{send_message} whenever sending a message.

        The broker keeps track of the session IDs that it hands out and will
        drop them when a re-synchronisation event occurs.  Further messages
        sent using expired IDs will be silently discarded.

        For example each L{BrokerClientPlugin} calls this method to get a
        session ID and use it when sending messages, until the plugin gets
        notified of a re-synchronisation event and then asks for a new one.

        This eliminates issues with out-of-date messages being delivered to the
        server after a re-synchronisation request. For example when the client
        re-registers and gets a new computer ID we don't want to deliver
        messages containing references to activity IDs of the old computer
        (e.g. a message with the result of a "change-packages" activity
        delivered before re-registering). See also #328005 and #1158822.

        t   scope(   R   t   get_session_id(   R	   R2   (    (    s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyR3   p   s    c            sU   ˆ j  j ˆ  ƒ } | ˆ j ˆ j ƒ ‰ ‡ ‡ ‡  f d †  } ˆ j ƒ  } | j | ƒ S(   sR  Register a broker client called C{name}.

        Various broker clients interact with the broker server, such as the
        monitor for example, using the L{BrokerServerConnector} for performing
        remote method calls on the L{BrokerServer}.

        They establish connectivity with the broker by connecting and
        registering themselves, the L{BrokerServer} will in turn connect
        to them in order to be able to perform remote method calls like
        broadcasting events and messages.

        @param name: The name of the client, such a C{monitor} or C{manager}.
        c            s   |  ˆ j  ˆ <ˆ  ˆ j |  <d  S(   N(   R   R    (   t   remote_client(   t	   connectorR	   t   name(    s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyt   registerœ   s    (   R   t   getR   R   t   connectt   addCallback(   R	   R6   t   connector_classR7   t	   connected(    (   R6   R	   R5   s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyt   register_clientŠ   s
    c         C   s   |  j  j ƒ  S(   s5   Get L{RemoteClient} instances for registered clients.(   R   t   values(   R	   (    (    s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyR   £   s    c         C   s   |  j  j | ƒ S(   s4   Return the client with the given C{name} or C{None}.(   R   R8   (   R	   R6   (    (    s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyt
   get_client§   s    c         C   s   |  j  j ƒ  S(   sa   Get connectors for registered clients.

        @see L{RemoteLandscapeComponentCreator}.
        (   R    R>   (   R	   (    (    s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyt   get_connectors«   s    c         C   s   |  j  j |  j | ƒ ƒ S(   s6   Return the connector for the given C{name} or C{None}.(   R    R8   R?   (   R	   R6   (    (    s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyt   get_connector²   s    c         C   s{   t  | t ƒ r4 | d d k r4 t } |  j ƒ  } n  | d k rO t d ƒ ‚ n  |  j j | ƒ rw |  j j	 | d | ƒSd S(   s=  Queue C{message} for delivery to the server at the next exchange.

        @param message: The message C{dict} to send to the server.  It must
            have a C{type} key and be compatible with C{landscape.lib.bpickle}.
        @param session_id: A session ID.  You should acquire this
            with C{get_session_id} before attempting to send a message.
        @param urgent: If C{True}, exchange urgently, otherwise exchange
            during the next regularly scheduled exchange.
        @return: The message identifier created when queuing C{message}.
        t   types   operation-results   change-packages-results:   Session ID must be set before attempting to send a messaget   urgentN(   s   operation-results   change-packages-result(
   t
   isinstancet   boolR0   R3   t   Nonet   RuntimeErrorR   t   is_valid_session_idR   t   send(   R	   R   t
   session_idRC   (    (    s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyt   send_message¶   s    	c         C   s   |  j  j | ƒ S(   s:   Indicate if a message with given C{message_id} is pending.(   R   t
   is_pending(   R	   t
   message_id(    (    s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyt   is_message_pendingØ   s    c         C   sR   g  } x' |  j  ƒ  D] } | j | j ƒ  ƒ q Wt | d t ƒ} | j d „  ƒ S(   s   Tell all the clients to exit.t   consume_errorsc         S   s   d  S(   N(   RF   (   t   ignored(    (    s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyt   <lambda>å   s    (   R   R   t   exitR   R0   R:   (   R	   t   resultsR   t   result(    (    s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyt   stop_clientsÝ   s
    c         C   s   |  j  j ƒ  |  j ƒ  S(   s4   Reload the configuration file, and stop all clients.(   R   t   reloadRU   (   R	   (    (    s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyt   reload_configurationç   s    c         C   s   |  j  j ƒ  S(   sf   Attempt to register with the Landscape server.

        @see: L{RegistrationHandler.register}
        (   R   R7   (   R	   (    (    s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyR7   ï   s    c         C   s   |  j  j ƒ  S(   s:   Return the message types accepted by the Landscape server.(   R   t   get_accepted_types(   R	   (    (    s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyt   get_accepted_message_types÷   s    c         C   s   |  j  j ƒ  S(   s:   Return the uuid of the Landscape server we're pointing at.(   R   t   get_server_uuid(   R	   (    (    s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyRZ   ü   s    c         C   s   |  j  j | ƒ d S(   s|   Register a new message type which can be accepted by this client.

        @param type: The message type to accept.
        N(   R   t%   register_client_accepted_message_type(   R	   RB   (    (    s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyR[     s    c         C   s   |  j  j | ƒ d S(   s$   Fire an event in the broker reactor.N(   R   t   fire(   R	   R   (    (    s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyR   	  s    c            s(   ˆ  j  ƒ  } ‡  f d †  } | j | ƒ S(   s“  Request a graceful exit from the broker server.

        Before this method returns, all broker clients will be notified
        of the server broker's intention of exiting, so that they have
        the chance to stop whatever they're doing in a graceful way, and
        then exit themselves.

        This method will only return a result when all plugins returned
        their own results.
        c            s    ˆ  j  j d ‡  f d †  ƒ d  S(   Ni   c              s   ˆ  j  j ƒ  S(   N(   R   t   stop(    (   R	   (    s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyRQ   $  s    (   R   t
   call_later(   RP   (   R	   (    s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyt   schedule_reactor_stop  s    (   RU   t   addBoth(   R	   t   clients_stoppedR_   (    (   R	   s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyRR     s    
c         C   s   d S(   s2   Broadcast a C{resynchronize} event to the clients.N(    (   R	   (    (    s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyR(   (  s    c         C   s   d S(   s8   Broadcast an C{impending-exchange} event to the clients.N(    (   R	   (    (    s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyR$   ,  s    c            sa   t  ƒ  ‰ g  ‰  ‡ ‡ ‡  f d †  } x6 | D]. } ˆ j j | | | ƒ ƒ } ˆ  j | ƒ q+ Wˆ S(   sk   
        Return a C{Deferred} that fires when the first event occurs among the
        given ones.
        c            s   ‡ ‡ ‡  ‡ f d †  } | S(   Nc             s2   x ˆ D] }  ˆ j  j |  ƒ q Wˆ  j ˆ ƒ d  S(   N(   R   t   cancel_callt   callback(   t   call(   t   deferredR	   R   t   calls(    s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyt   handler;  s    (    (   R   Rg   (   Re   R	   Rf   (   R   s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyt   get_handler9  s    (   R    R   R"   R   (   R	   t   event_typesRh   R   Rd   (    (   Rf   R	   Re   s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyt   listen_events0  s    		c         C   s   d S(   s5   Broadcast a C{broker-reconnect} event to the clients.N(    (   R	   (    (    s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyt   broker_reconnectG  s    c         C   s   d S(   s8   Broadcast a C{server-uuid-changed} event to the clients.N(    (   R	   t   old_uuidt   new_uuid(    (    s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyR&   K  s    c         C   s   d  S(   N(    (   R	   RB   t   accepted(    (    s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyR%   O  s    c         C   s   d S(   s@   Fire a package-data-changed event in the reactor of each client.N(    (   R	   (    (    s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyR'   S  s    c         C   sR   g  } x* |  j  ƒ  D] } | j | j | ƒ ƒ q Wt | ƒ } | j |  j | ƒ S(   se   Call the C{message} method of all the registered plugins.

        @see: L{register_plugin}.
        (   R   R   R   R   R:   t   _message_delivered(   R	   R   RS   R   RT   (    (    s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyR#   W  s
    c         C   s¡   | j  d ƒ } t | k r | d
 k	 r | d d k r | d } t j d | f ƒ d | f } i d d 6t d 6| d 6| d 6} |  j j | d	 t ƒn  d
 S(   s¾   
        If the message wasn't handled, and it's an operation request (i.e. it
        has an operation-id), then respond with a failing operation result
        indicating as such.
        s   operation-idRB   R(   s   Nobody handled the %s message.s4  Landscape client failed to handle this request (%s) because the
plugin which should handle it isn't available.  This could mean that the
plugin has been intentionally disabled, or that the client isn't running
properly, or you may be running an older version of the client that doesn't
support this feature.
s   operation-resultt   statuss   result-textRC   N(   R8   R0   RF   t   loggingt   errorR   R   RI   (   R	   RS   R   t   opidt   mtypet   result_textt   response(    (    s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyRo   b  s    

c         C   s   |  j  j ƒ  |  j j ƒ  d S(   s  
        Stop exchaging messages with the message server.

        Eventually, it is required by the plugin that no more message exchanges
        are performed.
        For example, when a reboot process in running, the client stops
        accepting new messages so that no client action is running while the
        machine is rebooting.
        Also, some activities should be explicitly require that no more
        messages are exchanged so some level of serialization in the client
        could be achieved.
        N(   R   R]   R!   (   R	   (    (    s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyt   stop_exchanger}  s    N($   R   t
   __module__t   __doc__R6   R/   R   R1   RF   R3   R=   R   R?   R@   RA   t   FalseRK   RN   RU   RW   R7   RY   RZ   R[   R   RR   R   R(   R$   Rj   Rk   R&   R%   R'   R#   Ro   Rw   (    (    (    s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyR   I   s@   
					!
		(   Ry   Rq   t   twisted.internet.deferR    t   landscape.lib.twisted_utilR   t   landscape.ampR   t   landscape.manager.managerR   R   t   objectR   (    (    (    s;   /usr/lib/python2.7/dist-packages/landscape/broker/server.pyt   <module>,   s   	