o
    thg                     @   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 )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: []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   
