U
    Ӈg                     @   sr   d 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 ddl	m
Z
 eeZedddZG d	d
 d
ZdS )z#A module for common socket helpers.    N)suppress)performance)DEFAULT_RUN_DIR)messagec              	   C   s   t jdd}|sdS |d dkr2|ddd n|d dkrFtd	ttjtjtjB 0}t	
d
t|  || || d W 5 Q R X dS )z[Send a sd_notify message.

    :param message: sd-notify message (must be valid ascii)
    ZNOTIFY_SOCKET Nr   @    /zUnsupported socket typezSending sd_notify(%s)ascii)osenvirongetreplaceOSErrorsocketAF_UNIX
SOCK_DGRAMSOCK_CLOEXECLOGinfostrconnectsendallencode)r   socket_pathsock r   2/usr/lib/python3/dist-packages/cloudinit/socket.py	sd_notify   s     

r   c                   @   s<   e Zd ZdZedddZedddZdd	 Zd
d ZdS )
SocketSyncz<A two way synchronization protocol over Unix domain sockets.)namesc              
   G   s   d| _ d| _d| _d| _d| _dd |D | _tjt dddd	 | j	 D ]@\}}t d
| d}t
t t| W 5 Q R X || qNdS )an  Initialize a synchronization context.

        1) Ensure that the socket directory exists.
        2) Bind a socket for each stage.

        Binding the sockets on initialization allows receipt of stage
        "start" notifications prior to the cloud-init stage being ready to
        start.

        :param names: stage names, used as a unique identifiers
        r   r   Fc                 S   s$   i | ]}|t  t jt jt jB qS r   )r   r   r   r   ).0namer   r   r   
<dictcomp>>   s     
z'SocketSync.__init__.<locals>.<dictcomp>z/sharei  T)modeexist_ok/share/z.sockN)stageremotefirst_exceptionsystemd_exit_codeexperienced_any_errorsocketsr   makedirsr   itemsr   FileNotFoundErrorremoveZbind)selfr!   r#   r   r   r   r   r   __init__-   s    
zSocketSync.__init__)r(   c                 C   s"   || j krtd| || _| S )a  Set the stage before entering context.

        This enables the context manager to be initialized separately from
        each stage synchronization.

        :param stage: the name of a stage to synchronize

        Example:
            sync = SocketSync("stage 1", "stage 2"):
            with sync("stage 1"):
                pass
            with sync("stage 2"):
                pass
        zInvalid stage name: )r-   
ValueErrorr(   )r2   r(   r   r   r   __call__M   s    
zSocketSync.__call__c              	   C   s   t tj rtd dS d| _td| j	 d | j
| j	 }td| j	  |d\}| _W 5 Q R X d|kr| ddd td	t| d
n:t d| j	 dt| jkr| ddd td| j td| j	 d | S )zWait until a message has been received on this stage's socket.

        Once the message has been received, enter the context.
        z:Stdin is a tty, so skipping stage synchronization protocolNr   zDSTATUS=Waiting on external services to complete before starting the z stage.zWaiting to start stage    s   startzReceived invalid message: []r'   z-return.sockz Unexpected path to unix socket: zSTATUS=Running (z stage))r   isattysysstdinfilenor   r   r+   r   r(   r-   r   ZTimedZrecvfromr)   __exit__r4   r   r   )r2   r   chunkr   r   r   	__enter__a   s,    	zSocketSync.__enter__c                 C   s   d| j  }|rXd| _d| _t| d|j }d}| js@|| _t| td|  | jpft	| j| _| j
| j  }|| j |d| d| j d	  |  dS )
z.Notify the socket that this stage is complete.z,Completed socket interaction for boot stage r	   Tz in zkfatal error, run "systemctl status cloud-init-main.service" and "cloud-init status --long" for more detailszSTATUS=zecho 'z'; exit ;)r(   r+   r,   reprtb_framer*   r   Zfatalr   boolr-   r   r)   r   r   close)r2   exc_typeZexc_valexc_tbr   Zstatusr   r   r   r   r<      s*    
zSocketSync.__exit__N)	__name__
__module____qualname____doc__r   r3   r5   r>   r<   r   r   r   r   r    *   s
    'r    )rI   Zloggingr   r   r9   
contextlibr   Z	cloudinitr   Zcloudinit.settingsr   Z	getLoggerrF   r   r   r   r    r   r   r   r   <module>   s   
