o
    x[h´  ã                   @   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def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r| ddd¡ n
|d dkr#td	ƒ‚t tjtjtjB ¡�}t	 
d
t| ƒ¡ | |¡ | |  d¡¡ W d  ƒ dS 1 sOw   Y  dS )z[Send a sd_notify message.

    :param message: sd-notify message (must be valid ascii)
    Ú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defdd„Zdef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 d  ƒ n1 sGw   Y  | |¡ q'd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ÚremoveÚbind)Úselfr"   r$   r   r   r   r   r   Ú__init__-   s    ü
ÿüzSocketSync.__init__r)   c                 C   s"   || j v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)   )r4   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 d  ƒ n1 s=w   Y  d|krW|  ddd¡ td	t|ƒ› d
�ƒ‚t› d| j	› d�t| jƒkrt|  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   ÚTimedÚrecvfromr*   Ú__exit__r6   r   r   )r4   r   Úchunkr   r   r   Ú	__enter__a   s2   ÿÿÿ	ÿÿzSocketSync.__enter__c                 C   s¬   d| j › �}|r,d| _d| _t|ƒ› d|j› �}d}| js || _t |¡ td|› �ƒ | jp3t	| 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   Úfatalr    Úboolr.   r   r*   r   r   Úclose)r4   Úexc_typeÚexc_valÚexc_tbr   Ústatusr   r   r   r   r@   ˆ   s*   ÿ
ÿÿzSocketSync.__exit__N)	Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r5   r7   rB   r@   r   r   r   r   r!   *   s     'r!   )rP   Úloggingr   r   r;   Ú
contextlibr   Ú	cloudinitr   Úcloudinit.settingsr   Ú	getLoggerrM   r   r   r    r!   r   r   r   r   Ú<module>   s   
