ó
ÍÿŠTc           @   sê  d  Z  d d l Z d d l Z d d l Z d d l Z d d l Z d d l m Z d d l m	 Z	 m
 Z
 m Z m Z m Z d d l m Z d d l m Z d d l m Z d d l m Z d d	 l m Z m Z d d
 l m Z d d l m Z d d l m Z m Z m  Z  e! ƒ  Z" d Z# d Z$ d Z% d e& f d „  ƒ  YZ' d d „ Z) d e& f d „  ƒ  YZ* d e& f d „  ƒ  YZ+ d e& f d „  ƒ  YZ, d e! f d „  ƒ  YZ- d e e- f d „  ƒ  YZ. d e f d „  ƒ  YZ/ d e f d  „  ƒ  YZ0 d S(!   su   
Functionality for running arbitrary shell scripts.

@var ALL_USERS: A token indicating all users should be allowed.
iÿÿÿÿN(   t   ProcessProtocol(   t   Deferredt   failt   inlineCallbackst   returnValuet   succeed(   t   ProcessDone(   t   VERSION(   t   UBUNTU_PATH(   t   build_script(   t   fetch_asynct   HTTPCodeError(   t   Persist(   t   encode_if_needed(   t   ManagerPlugint	   SUCCEEDEDt   FAILEDif   ig   ih   t   UnknownUserErrorc           B   s   e  Z RS(    (   t   __name__t
   __module__(    (    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyR       s   c         C   s§   d  } d  } d  } |  d  k	 rš t |  ƒ } y t j | ƒ } Wn! t k
 r` t d |  ƒ ‚ n X| j } | j } | j } t	 j
 j | ƒ sš d } qš n  | | | f S(   Nu   Unknown user '%s't   /(   t   NoneR   t   pwdt   getpwnamt   KeyErrorR   t   pw_uidt   pw_gidt   pw_dirt   ost   patht   exists(   t   usernamet   uidt   gidR   t   username_strt   info(    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyt   get_user_info$   s    			t   ProcessTimeLimitReachedErrorc           B   s   e  Z d  Z d „  Z RS(   s™   
    Raised when a process has been running for too long.

    @ivar data: The data that the process printed before reaching the time
        limit.
    c         C   s   | |  _  d  S(   N(   t   data(   t   selfR&   (    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyt   __init__>   s    (   R   R   t   __doc__R(   (    (    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyR%   6   s   t   ProcessFailedErrorc           B   s   e  Z d  Z d „  Z RS(   s“   Raised when a process exits with a non-0 exit code.

    @ivar data: The data that the process printed before reaching the time
        limit.
    c         C   s   | |  _  | |  _ d  S(   N(   R&   t	   exit_code(   R'   R&   R+   (    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyR(   I   s    	(   R   R   R)   R(   (    (    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyR*   B   s   t   UnknownInterpreterErrorc           B   s    e  Z d  Z d „  Z d „  Z RS(   sˆ   Raised when the interpreter specified to run a script is invalid.

    @ivar interpreter: the interpreter specified for the script.
    c         C   s#   | |  _  t j |  |  j ƒ  ƒ d  S(   N(   t   interpretert	   ExceptionR(   t   _get_message(   R'   R-   (    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyR(   T   s    	c         C   s   d |  j  S(   Ns   Unknown interpreter: '%s'(   R-   (   R'   (    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyR/   X   s    (   R   R   R)   R(   R/   (    (    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyR,   N   s   	t   ScriptRunnerMixinc           B   s5   e  Z d  Z d d „ Z d „  Z d „  Z d „  Z RS(   sb   
    @param process_factory: The L{IReactorProcess} provider to run the
        process with.
    c         C   s,   | d  k r d d l m } n  | |  _ d  S(   Niÿÿÿÿ(   t   reactor(   R   t   twisted.internetR1   t   process_factory(   R'   R3   (    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyR(   b   s    c         C   s(   |  j  j j ƒ  } | t k p' | | k S(   N(   t   registryt   configt   get_allowed_script_userst	   ALL_USERS(   R'   t   usert   allowed_users(    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyt   is_user_allowedg   s    c         C   sV   t  j | d ƒ | d  k	 r2 t  j | | | ƒ n  | j t | | ƒ ƒ | j ƒ  d  S(   NiÀ  (   R   t   chmodR   t   chownt   writeR	   t   close(   R'   t   script_filet   filenamet   shellt   codeR    R!   (    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyt   write_script_filek   s
    c         C   sœ   | t  j ƒ  k r d  } n  | t  j ƒ  k r6 d  } n  t |  j j |  j ƒ } |  j j	 | | d | d | d | d | ƒ| d  k	 r• | j
 | ƒ n  | j S(   NR    R!   R   t   env(   R   t   getuidR   t   getgidt   ProcessAccumulationProtocolR4   R1   t
   size_limitR3   t   spawnProcesst   schedule_cancelt   result_deferred(   R'   R@   R    R!   R   RD   t
   time_limitt   pp(    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyt   _run_scriptw   s    			"N(   R   R   R)   R   R(   R:   RC   RN   (    (    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyR0   \   s
   		t   ScriptExecutionPluginc           B   sz   e  Z d  Z d Z d „  Z d d „ Z d „  Z d „  Z d „  Z	 d „  Z
 e d „  ƒ Z d d d d d	 „ Z d
 „  Z RS(   s   A plugin which allows execution of arbitrary shell scripts.

    @ivar size_limit: The number of bytes at which to truncate process output.
    i ¡ c         C   s-   t  t |  ƒ j | ƒ | j d |  j ƒ d  S(   Ns   execute-script(   t   superRO   t   registert   register_messaget   _handle_execute_script(   R'   R4   (    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyRQ      s    c         C   su   t  | t ƒ s$ | j d d ƒ } n  i d d 6| d 6| d 6| d 6} | rY | | d <n  |  j j j | |  j t ƒ S(	   Ns   utf-8t   replaces   operation-resultt   typet   statuss   result-texts   operation-ids   result-code(   t
   isinstancet   unicodet   decodeR4   t   brokert   send_messaget   _session_idt   True(   R'   RV   R&   t   opidt   result_codet   message(    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyt   _respond”   s    

c         C   sð   | d } y­ | d } |  j  | ƒ s@ |  j t d | f | ƒ S| j d d  ƒ } |  j | d | d d | d d	 | d
 | d
 d | ƒ} | j |  j | ƒ | j |  j	 | ƒ | SWn2 t
 k
 rë } |  j t |  j | ƒ | ƒ ‚  n Xd  S(   Ns   operation-idR   u!   Scripts cannot be run as user %s.RD   R-   RB   RL   s
   time-limitR8   t   attachmentst   server_supplied_env(   R:   Ra   R   t   getR   t
   run_scriptt   addCallbackt   _respond_successt
   addErrbackt   _respond_failureR.   t   _format_exception(   R'   R`   R^   R8   Rc   t   dt   e(    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyRS   ¢   s&    



	c         C   s   d | j  j | j d f S(   Nu   %s: %si    (   t	   __class__R   t   args(   R'   Rl   (    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyRj   ¸   s    c         C   s   |  j  t | | ƒ S(   N(   Ra   R   (   R'   R&   R^   (    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyRg   »   s    c         C   s¯   d  } | j t ƒ r t } nL | j t ƒ r6 t } n4 | j t ƒ rj t } |  j t	 t
 | j ƒ | t ƒ S| d  k	 r’ |  j t	 | j j | | ƒ S|  j t	 t
 | ƒ | ƒ Sd  S(   N(   R   t   checkR%   t   TIMEOUT_RESULTR*   t   PROCESS_FAILED_RESULTR   t   FETCH_ATTACHMENTS_FAILED_RESULTRa   R   t   strt   valueR&   (   R'   t   failureR^   RB   (    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyRi   ¾   s    		c         c   sg  |  j  j j j d d ƒ d d } t j ƒ  } i d t d 6d d 6| d	 6} xÖ | j ƒ  D]È \ } }	 t |	 t	 ƒ rŠ |	 }
 t
 d  ƒ Vn, t d
 | |	 f d |  j  j j d | ƒV}
 t j j | | ƒ } t | d ƒ } t j | d ƒ | d  k	 rt j | | | ƒ n  | j |
 ƒ | j ƒ  q[ Wt j | d ƒ | d  k	 rYt j | | | ƒ n  t | ƒ d  S(   NR   i   i    s   /attachment/s   landscape-client/%ss
   User-Agents   application/octet-streams   Content-Types   X-Computer-IDs   %s%dt   cainfot   headerst   wbi€  iÀ  (   R4   R5   t   urlt   rsplitt   tempfilet   mkdtempR   t   itemsRW   Rs   R   R   R
   t   ssl_public_keyR   R   t   joint   fileR;   R<   R=   R>   R   (   R'   Rb   R    R!   t   computer_idt	   root_patht   attachment_dirRw   R@   t   attachment_idR&   t   full_filenamet
   attachment(    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyt   _save_attachmentsÏ   s0    #

c      	      s†  t  j j | j ƒ  d ƒ s, t t | ƒ ƒ St | ƒ \ ‰ ‰ ‰ t j ƒ  \ } ‰ t  j	 | d ƒ } ˆ j
 | ˆ | | ˆ ˆ ƒ i t d 6| p” d d 6ˆ p¡ d d 6‰ | r¾ ˆ j | ƒ n  t  j d ƒ }	 | r3t d t  j j ˆ j j j d	 ƒ ƒ }
 |
 j d
 ƒ }
 |
 j d ƒ } ˆ j | ˆ ˆ | ƒ } n t d ƒ } ‡  ‡ ‡ ‡ ‡ ‡ ‡ f d †  } | j | ƒ | j ˆ j ˆ ˆ |	 ƒ S(   s8  
        Run a script based on a shell and the code.

        A file will be written with #!<shell> as the first line, as executable,
        and run as the given user.

        XXX: Handle the 'reboot' and 'killall landscape-client' commands
        gracefully.

        @param shell: The interpreter to use.
        @param code: The code to run.
        @param user: The username to run the process as.
        @param time_limit: The number of seconds to allow the process to run
            before killing it and failing the returned Deferred with a
            L{ProcessTimeLimitReachedError}.
        @param attachments: C{dict} of filename/data attached to the script.

        @return: A deferred that will fire with the data printed by the process
            or fail with a L{ProcessTimeLimitReachedError}.
        i    t   wt   PATHt    t   USERt   HOMEi   R@   s   broker.bpicklet   registrations	   secure-idc            s5   |  d  k	 r |  ˆ d <n  ˆ j ˆ ˆ ˆ ˆ ˆ ˆ  ƒ S(   Nt   LANDSCAPE_ATTACHMENTS(   R   RN   (   Rƒ   (   RL   R    R'   R@   R!   RD   R   (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyt   prepare_script  s    N(   R   R   R   t   splitR   R,   R$   R{   t   mkstempt   fdopenRC   R   t   updatet   umaskR   R   R4   R5   t	   data_patht   root_atRd   R‡   R   R   Rf   t   addBotht   _cleanup(   R'   RA   RB   R8   RL   Rb   Rc   t   fdR?   t	   old_umaskt   persistR   Rk   R   (    (   RL   R    R'   R@   R!   RD   R   sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyRe   ì   s.    '!c         C   sZ   y t  j | ƒ Wn n Xd | k rI y t j | d ƒ WqI qI Xn  t  j | ƒ | S(   NRŽ   (   R   t   unlinkt   shutilt   rmtreeR”   (   R'   t   resultR@   RD   Rš   (    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyR˜   '  s    N(   R   R   R)   RH   RQ   R   Ra   RS   Rj   Rg   Ri   R   R‡   Re   R˜   (    (    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyRO   ‡   s   					:RG   c           B   s;   e  Z d  Z d „  Z d „  Z d „  Z d „  Z d „  Z RS(   sx   A ProcessProtocol which accumulates output.

    @ivar size_limit: The number of bytes at which to truncate output.
    c         C   s=   g  |  _  t ƒ  |  _ t |  _ | |  _ | |  _ d  |  _ d  S(   N(	   R&   R   RK   t   Falset
   _cancelledRH   R1   R   t   _scheduled_cancel(   R'   R1   RH   (    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyR(   ;  s    				c         C   s   |  j  j | |  j ƒ |  _ d  S(   N(   R1   t
   call_latert   _cancelR¢   (   R'   RL   (    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyRJ   C  s    	c         C   s@   t  t j t t |  j ƒ d ƒ } |  j j | |  j |  ƒ d S(   s‰   Some data was received from the child.

        Add it to our buffer, as long as it doesn't go over L{size_limit}
        bytes.
        i    N(   t   reducet   operatort   addt   mapt   lenR&   t   appendRH   (   R'   R™   R&   t   current_size(    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyt   childDataReceivedG  s    !c         C   s³   | j  j } d j |  j ƒ } |  j r@ |  j j t | ƒ ƒ no |  j d k	 rt |  j } d |  _ |  j
 j | ƒ n  | j t ƒ r– |  j j | ƒ n |  j j t | | ƒ ƒ d S(   s  Fire back the deferred.

        The deferred will be fired with the string of data received from the
        subprocess, or if the subprocess was cancelled, a
        L{ProcessTimeLimitReachedError} will be fired with data accumulated so
        far.
        RŠ   N(   Rt   t   exitCodeR   R&   R¡   RK   t   errbackR%   R¢   R   R1   t   cancel_callRo   R   t   callbackR*   (   R'   t   reasonR+   R&   t	   scheduled(    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyt   processEndedP  s    			c         C   s>   x d D] } |  j  j | ƒ q W|  j  j d ƒ t |  _ d S(   s—   
        Close filedescriptors, kill the process, and indicate that a
        L{ProcessTimeLimitReachedError} should be fired on the deferred.
        i    i   i   t   KILLN(   i    i   i   (   t	   transportt   closeChildFDt   signalProcessR]   R¡   (   R'   t   i(    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyR¤   h  s    
(   R   R   R)   R(   RJ   R¬   R³   R¤   (    (    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyRG   5  s   					t   ScriptExecutionc           B   s,   e  Z d  Z d „  Z d „  Z e d „ Z RS(   sK   
    Meta-plugin wrapping ScriptExecutionPlugin and CustomGraphPlugin.
    c         C   s,   d d l  m } t ƒ  |  _ | ƒ  |  _ d  S(   Niÿÿÿÿ(   t   CustomGraphPlugin(   t   landscape.manager.customgraphRº   RO   t   _script_executiont   _custom_graph(   R'   Rº   (    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyR(   }  s    c         C   s:   t  t |  ƒ j | ƒ |  j j | ƒ |  j j | ƒ d  S(   N(   RP   R¹   RQ   R¼   R½   (   R'   R4   (    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyRQ   ‚  s    c         C   s   |  j  j | ƒ d  S(   N(   R½   t   exchange(   R'   t   urgent(    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyR¾   ‡  s    (   R   R   R)   R(   RQ   R    R¾   (    (    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyR¹   x  s   		(1   R)   R   R   R{   R¦   R   t   twisted.internet.protocolR    t   twisted.internet.deferR   R   R   R   R   t   twisted.internet.errorR   t	   landscapeR   t   landscape.constantsR   t   landscape.lib.scriptcontentR	   t   landscape.lib.fetchR
   R   t   landscape.lib.persistR   t   landscape.lib.encodingR   t   landscape.manager.pluginR   R   R   t   objectR7   Rp   Rq   Rr   R.   R   R   R$   R%   R*   R,   R0   RO   RG   R¹   (    (    (    sE   /usr/lib/python2.7/dist-packages/landscape/manager/scriptexecution.pyt   <module>   s8   (	+®C