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 )z‡Wait 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_valZ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    )rH   Zloggingr   r   r9   Ú
contextlibr   Z	cloudinitr   Zcloudinit.settingsr   Z	getLoggerrE   r   r   r   r    r   r   r   r   Ú<module>   s   
