o
    f;                     @   sn   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	 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)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(   )r3   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 t
 }| j| j	 }|d\}| _d|krB| ddd tdt| d	t d
| j	 dt| jkr_| ddd td| j t
 | }|dkrpd|ddnd}td| j	 d td| j	| | 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.   s   startzReceived invalid message: []r'   z-return.sockz Unexpected path to unix socket: g{Gz?ztook z .3fzs to r   zSTATUS=Running (z stage)z$sync(%s): synchronization %scomplete)r   isattysysstdinfilenor   r   r+   r   r(   time	monotonicr-   recvfromr)   __exit__r5   r   r   debug)r3   
start_timer   chunktotaltime_msgr   r   r   	__enter__a   s6   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)r3   exc_typeexc_valexc_tbr   statusr   r   r   r   r@      s*   
zSocketSync.__exit__N)	__name__
__module____qualname____doc__r   r4   r6   rF   r@   r   r   r   r   r    *   s     *r    )rT   loggingr   r   r:   r=   
contextlibr   cloudinit.settingsr   	getLoggerrQ   r   r   r   r    r   r   r   r   <module>   s   
