o
    쑛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 )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   Timedrecvfromr*   __exit__r6   r   r   )r4   r   chunkr   r   r   	__enter__a   s2   	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 }|| 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*   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   
