o
    th*7                     @   sJ  d dl Z d dlZd dlZd dlZd dlmZmZmZmZm	Z	m
Z
mZmZ d dlmZmZ d dlmZ ddddd	d
ddddddZdZdZdZedddfZeZdededefddZde	e de	e fddZde	e de	e fddZde	e de	e fddZdedefdd Zdede j fd!d"Zd#e j d$e j defd%d&Z d'ed(edefd)d*Z!d+e j d'ed(edefd,d-Z"dedefd.d/Z#G d0d1 d1Z$de
eeeef fd2d3Z%de
eeeef fd4d5Z&de
eeeef fd6d7Z'	8dBd9ee d:edeee  fd;d<Z(d9ee d:edeee  fd=d>Z)d?ede
e	e ef fd@dAZ*dS )C    N)IOAnyDictListOptionalTupleUnioncast)subputil)uses_systemddeltadescriptionelapsed
event_typeindentlevelnameoriginresult	timestamp
total_time)z%dz%Dz%Ez%ez%Iz%lz%nz%oz%rz%tz%T
successfulfailure	containermsgeventreturnc                 C   sT   t  D ]\}}|| v r!|dv r| |d| } q| |d| } q| jdi |S )N)r   r   r   z
{%s:08.5f}z{%s} )
format_keyitemsreplaceformat)r   r   ijr   r   8/usr/lib/python3/dist-packages/cloudinit/analyze/show.pyformat_record9   s   r'   c                 C      | r|  dS d S )Nr   getr   r   r   r&   
event_nameD      
r,   c                 C   r(   )Nr   r)   r+   r   r   r&   r   J   r-   c                 C   s   t | }|r|dd S d S )N/r   )r,   split)r   r   r   r   r&   event_parentP   s   r0   c                 C   s"   |  d}|d u rtdt|S )Nr   zEvent is missing a 'timestamp')r*   
ValueErrorfloat)r   tsr   r   r&   event_timestampW   s   
r4   c                 C   s   t j t| t jjS N)datetimefromtimestampr4   timezoneutcr+   r   r   r&   event_datetime^   s   r:   t1t2c                 C   s   ||    S r5   )total_seconds)r;   r<   r   r   r&   delta_secondsd   s   r>   startfinishc                 C   s   t t| t|S r5   )r>   r:   )r?   r@   r   r   r&   event_durationh   s   rA   
start_timec                 C   sX   |  }t|}d}|r|d|dd  d 7 }|t||t| t||d |S )N| r.      z`->)r   r   r   )copyr,   countupdaterA   r>   r:   )rB   r?   r@   recordr   r   r   r   r&   event_recordl   s   rJ   c                 C   s   d|  S )NzTotal Time: %3.5f seconds
r   )r   r   r   r&   total_time_record   s   rK   c                   @   sP   e Zd ZdZddedee fddZdeeeef  fdd	Z	de
fd
dZdS )SystemctlReaderzQ
    Class for dealing with all systemctl subp calls in a consistent manner.
    Nproperty	parameterc                 C   sF   d | _ tddg| _|r| j| | jd|dg |  | _d S )N	systemctlshowz-pz--timestamp=us+utc)stdoutr
   whichargsappendextend_subpr   )selfrM   rN   r   r   r&   __init__   s   zSystemctlReader.__init__r   c              
   C   sT   zt j | jdd\}}|r|W S || _W dS  ty) } z|W  Y d}~S d}~ww )z
        Make a subp call based on set args and handle errors by setting
        failure code

        :return: whether the subp call failed or not
        TcaptureN)r
   rS   rQ   	Exception)rW   valueerrsystemctl_failr   r   r&   rV      s   zSystemctlReader._subpc                 C   sv   | j rtd| j | jdu rtd| jdd  }| r*t|d }|S tj	|dj
tjjd }|S )	z{
        If subp call succeeded, return the timestamp from subp as a float.

        :return: timestamp as a float
        zBSubprocess call to systemctl has failed, returning error code ({})Nz.stdout of subprocess call to systemctl is None=rE   i@B z%a %Y-%m-%d %H:%M:%S.%f %Z)tzinfo)r   RuntimeErrorr#   rQ   r/   strip	isnumericr2   r6   strptimer"   r8   r9   r   )rW   valr   r   r   r&   convert_val_to_float   s&   	
z$SystemctlReader.convert_val_to_floatr5   )__name__
__module____qualname____doc__strr   rX   r   r[   rV   r2   rf   r   r   r   r&   rL      s
    rL   c                   C   s2   t  rt S t sdt d  v rt S tS )a)  
    Determine which init system a particular linux distro is using.
    Each init system (systemd, etc) has a different way of
    providing timestamps.

    :return: timestamps of kernelboot, kernelendboot, and cloud-initstart
    or TIMESTAMP_UNKNOWN if the timestamps cannot be retrieved.
    gentoosystem)r   gather_timestamps_using_systemdr   
is_FreeBSDsystem_infolowergather_timestamps_using_dmesgTIMESTAMP_UNKNOWNr   r   r   r&   dist_check_timestamp   s
   
rt   c            	      C   s   zMt j dgdd\} }| d  }|D ]7}|dddkrJ|d }|d d	}t|}tt tt	  }|| }t
|||f  W S qW tS  tyW   Y tS w )
a  
    Gather timestamps that corresponds to kernel begin initialization,
    kernel finish initialization using dmesg as opposed to systemctl

    :return: the two timestamps plus a dummy timestamp to keep consistency
    with gather_timestamps_using_systemd
    dmesgTrY   r   zUTF-8userr   rE   ])r
   
splitlinesdecodefindr/   rb   r2   timer   uptimeSUCCESS_CODEr[   rs   )	data_split_entriesr$   splitupstrippeduser_space_timestampkernel_start
kernel_endr   r   r&   rr      s$   rr   c               
   C   s   z0t  rtd } td }ntd } td }td | }tdd | }W n tyH } zt| tW  Y d}~S d}~ww t  rOtnt}|| | | | | fS )z
    Gather timestamps that corresponds to kernel begin initialization,
    kernel finish initialization. and cloud-init systemd unit activation

    :return: the three timesread_propertystamps
    UserspaceTimestampUserspaceTimestampMonotonicKernelTimestampKernelTimestampMonotonicInactiveExitTimestampMonotoniczcloud-init-localN)	r   is_containerrL   rf   r[   printrs   CONTAINER_CODEr}   )r   monotonic_offsetr   cloudinit_sysdestatusr   r   r&   rn     s^   rn   (%n) %d seconds in %I%Deventsprint_formatc              	   C   s  t | dd d}g }d}d}i }g }g }tt|D ]}	| |	 }
z| |	d  }W n ty3   d}Y nw t|
dkr|rU|
dd	krU|t| || g }d}d}|du rct|
}||t	|
< t
|
t
|krt|d
krtt|}|t|t||
| q|d|
d  ||
 q| }t
|
t
|kr|rt|||
}|td|d  ||dpd7 }q|| q|t| || |S )as  
    Take in raw events and create parent-child dependencies between events
    in order to order events in chronological order.

    :param events: JSONs from dump that represents events taken from logs
    :param print_format: formatting to represent event, time stamp,
    and time taken by the event in one line

    :return: boot records ordered chronologically
    c                 S   s   | d S )Nr   r   )xr   r   r&   <lambda>W  s    z"generate_records.<locals>.<lambda>)keyNg        rE   r?   r   z
init-localr@   zStarting stage: %szFinished stage: (%n) %d seconds
r   )sortedrangelen
IndexErrorr   r*   rT   rK   r:   r0   r,   r	   r   r'   rJ   pop)r   r   sorted_eventsrecordsrB   r   stage_start_timeboot_recordsunprocessedr   r   next_evtprev_evtrI   r   r   r&   generate_recordsH  sl   




r   c                 C   s   t | |dS )a<  
    A passthrough method that makes it easier to call generate_records()

    :param events: JSONs from dump that represents events taken from logs
    :param print_format: formatting to represent event, time stamp,
    and time taken by the event in one line

    :return: boot records ordered chronologically
    )r   )r   )r   r   r   r   r&   show_events  s   
r   infilec                 C   sX   |   }| stjd| j  td zt||fW S  t	y+   d|f Y S w )z
    Takes in a log file, read it, and convert to json.

    :param infile: The Log file to be read

    :return: json version of logfile, raw file
    zEmpty file %s
rE   N)
readrb   sysstderrwriter   exitjsonloadsr1   )r   r~   r   r   r&   load_events_infile  s   
r   )r   )+r6   r   r   r{   typingr   r   r   r   r   r   r   r	   	cloudinitr
   r   cloudinit.distrosr   r    r}   	FAIL_CODEr   rs   Eventrk   r'   r,   r   r0   r2   r4   r:   r>   rA   rJ   rK   rL   rt   rr   rn   r   r   r   r   r   r   r&   <module>   sp   (
U;

"P"