o
    ÷¢ig  ã                   @   s~   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
 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)ÚDict)Ú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 ƒ| _i | _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   ÚSOCK_STREAMr   )Ú.0Únamer   r   r    Ú
<dictcomp>>   s    ýÿÿz'SocketSync.__init__.<locals>.<dictcomp>z/shareiÀ  T)ÚmodeÚexist_okz/share/z.sockN)ÚstageÚfirst_exceptionÚsystemd_exit_codeÚexperienced_any_errorÚsocketsÚconnectionsr   Úmakedirsr   Úitemsr   ÚFileNotFoundErrorÚremoveÚbindÚlisten)Ú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*   )r6   r*   r   r   r    Ú__call__O   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¡\}}|| j| j	< W d  ƒ n1 sHw   Y  d|krb|  ddd¡ td	t|ƒ› d
�ƒ‚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: [ú]zSTATUS=Running (z stage))r   ÚisattyÚsysÚstdinÚfilenor   r   r,   r!   r*   r.   r   ÚTimedÚacceptÚrecvfromr/   Ú__exit__r8   r   )r6   r   Ú
connectionÚ_Úchunkr   r   r    Ú	__enter__c   s,   ÿÿÿ	ýzSocketSync.__enter__c                 C   s´   t  tj ¡ ¡r
dS d| j› �}|r6d| _d| _t|ƒ› d|j	› �}d}| j
s*|| _
t |¡ td|› �ƒ | jp=t| jƒ| _| j| j }| d|› d	| j› d
� ¡ ¡ | ¡  dS )z.Notify the socket that this stage is complete.Nz,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=   r>   r?   r*   r,   r-   ÚreprÚtb_framer+   r   Úfatalr!   Úboolr/   r   r   Úclose)r6   Úexc_typeÚexc_valÚexc_tbr   Ústatusr   r   r   r    rC   …   s,   ÿ
ÿÿzSocketSync.__exit__N)	Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r7   r9   rG   rC   r   r   r   r    r"   +   s    !"r"   )rU   Úloggingr   r   r=   Ú
contextlibr   Útypingr   Ú	cloudinitr   Úcloudinit.settingsr   Ú	getLoggerrR   r   r   r!   r"   r   r   r   r    Ú<module>   s   
