U
    Adm0                     @   s,  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mZ d dlm	Z	 dddddd	d
dddddZ
ddd e
 D ZdZdZdZedddfZdd Zdd Zdd Zdd Zdd Zd d! Zd"d# Zd$d% Zd&d' Zd(d) Zd*d+ ZG d,d- d-Zd.d/ Zd0d1 Zd2d3 Z d<d6d7Z!d8d9 Z"d:d; Z#dS )=    N)subputil)uses_systemddeltaZdescriptionelapsed
event_typeindentlevelnameoriginresult	timestamp
total_time)z%dz%Dz%Ez%ez%Iz%lz%nz%oz%rz%tz%T c                 C   s$   g | ]\}}d  |dd|qS )z{0}: {1}%z%%)formatreplace.0kv r   8/usr/lib/python3/dist-packages/cloudinit/analyze/show.py
<listcomp>2   s     r   Z
successfulfailureZ	containerc                 C   sP   t  D ]:\}}|| kr|dkr2| |d| } q| |d| } q| jf |S )N)r   r   r   z
{%s:08.5f}z{%s})
format_keyitemsr   r   )msgeventijr   r   r   format_record:   s    r"   c                 C   sn   t dd |  D }|d }g }|D ]B}|d }tj|}t|d d}t	|| |
| q&|S )Nc                 s   s"   | ]\}}|d kr||fV  qdS ))contentNr   r   r   r   r   	<genexpr>F   s      z#dump_event_files.<locals>.<genexpr>filespathr#   ascii)dictr   osr&   basenamebase64Z	b64decodedecoder   Z
write_fileappend)r   r#   r%   ZsavedffnameZfn_localZfcontentr   r   r   dump_event_filesE   s    r0   c                 C   s   | r|  dS d S )Nr
   getr   r   r   r   
event_nameS   s    
r4   c                 C   s   | r|  dS d S )Nr   r1   r3   r   r   r   r   Y   s    
c                 C   s   | rt | dd S d S )N/r   )r4   splitr3   r   r   r   event_parent_   s    r7   c                 C   s   t | dS Nr   )floatr2   r3   r   r   r   event_timestampe   s    r:   c                 C   s   t j t| S N)datetimeZutcfromtimestampr:   r3   r   r   r   event_datetimei   s    r=   c                 C   s   ||    S r;   )Ztotal_seconds)t1t2r   r   r   delta_secondsm   s    r@   c                 C   s   t t| t|S r;   )r@   r=   )startfinishr   r   r   event_durationq   s    rC   c              	   C   sH   |  }|t||t| t|ddt|dd   d d |S )N|r   r5      z`->)r   r   r   )copyupdaterC   r@   r=   r4   count)
start_timerA   rB   recordr   r   r   event_recordu   s    rK   c                 C   s   d|  S )NzTotal Time: %3.5f seconds
r   )r   r   r   r   total_time_record   s    rL   c                   @   s*   e Zd ZdZd	ddZdd Zdd ZdS )
SystemctlReaderzQ
    Class for dealing with all systemctl subp calls in a consistent manner.
    Nc                 C   sD   d | _ tddg| _|r&| j| | jd|g |  | _d S )NZ	systemctlZshowz-p)epochr   Zwhichargsr-   extendr   )selfpropertyZ	parameterr   r   r   __init__   s    zSystemctlReader.__init__c              
   C   sZ   z*t j | jdd\}}|r |W S || _W dS  tk
rT } z| W Y S d}~X Y nX dS )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ZcaptureN)r   rO   rN   	Exception)rQ   valueerrZsystemctl_failr   r   r   r      s    zSystemctlReader.subpc                 C   s2   | j rtd| j | jdd }t|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 ({})=rE   i@B )r   RuntimeErrorr   rN   r6   r9   )rQ   r   r   r   r   parse_epoch_as_float   s    	z$SystemctlReader.parse_epoch_as_float)N)__name__
__module____qualname____doc__rS   r   rZ   r   r   r   r   rM      s   
rM   c                   C   s2   t  rt S t s(dt d  k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.
    Zgentoosystem)r   gather_timestamps_using_systemdr   Z
is_FreeBSDZsystem_infolowergather_timestamps_using_dmesgTIMESTAMP_UNKNOWNr   r   r   r   dist_check_timestamp   s
    
rd   c            	      C   s   zt j dgdd\} }| d  }|D ]n}|dddkr&|d }|d d	}t|}tt tt	  }|| }t
|||f  W S q&W n tk
r   Y nX tS )
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
    ZdmesgTrT   r   zUTF-8userr   rE   ])r   
splitlinesr,   findr6   stripr9   timer   uptimeSUCCESS_CODErU   rc   )	data_Zsplit_entriesr    ZsplitupstrippedZuser_space_timestampkernel_start
kernel_endr   r   r   rb      s    rb   c            
   
   C   s   t t t t  } ztd }tdd }| }t}t rt t t t  }zt	
d}|j} W n2 tk
r } ztd||W 5 d}~X Y nX t}|| }|| }W n2 tk
r }	 zt|	 t W Y S d}	~	X Y nX || ||fS )z
    Gather timestamps that corresponds to kernel begin initialization,
    kernel finish initialization. and cloud-init systemd unit activation

    :return: the three timestamps
    ZUserspaceTimestampMonotonicZInactiveExitTimestampMonotoniczcloud-init-localz/proc/1/cmdlinezBCould not determine container boot time from /proc/1/cmdline. ({})N)r9   rj   r   rk   rM   rZ   rl   Zis_container	monotonicr)   statst_atimeOSErrorrY   r   CONTAINER_CODErU   printrc   )
rp   Zdelta_k_endZ
delta_ci_sZ	base_timeZstatusZ	file_statrW   rq   Zcloudinit_sysder   r   r   r`      s>     

r`   F(%n) %d seconds in %I%Dc              	   C   s  t | dd d}g }d}d}i }	g }
g }tdt|D ]F}| | }z| |d  }W n tk
rl   d}Y nX t|dkr*|r|d	d
kr|t| |
| g }d}d}|dkrt|}||	t	|< t
|t
|krt|dkr(|t|t||| n |d|d	  || q6q6| }t
|t
|krtt|||}|td|d  ||d7 }q6|| q6|t| |
| |
S )a2  
    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 blame_sort: whether to sort by timestamp or by time taken.
    :param print_format: formatting to represent event, time stamp,
    and time taken by the event in one line
    :param dump_files: whether to dump files into JSONs
    :param log_datafiles: whether or not to log events generated

    :return: boot records ordered chronologically
    c                 S   s   | d S r8   r   )xr   r   r   <lambda>3      z"generate_records.<locals>.<lambda>)keyNg        r   rE   rA   r
   z
init-localrB   zStarting stage: %szFinished stage: (%n) %d seconds
r   )sortedrangelen
IndexErrorr   r2   r-   rL   r=   r7   r4   r"   rK   pop)eventsZ
blame_sortprint_formatZ
dump_filesZlog_datafilesZsorted_eventsZrecordsrI   r   Zstage_start_timeZboot_recordsZunprocessedrx   r   Znext_evtZprev_evtrJ   r   r   r   generate_records  s^    




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_eventsn  s    
r   c                 C   s:   |   }zt||fW S  tk
r4   d|f Y S X dS )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
    N)readjsonloads
ValueError)Zinfilerm   r   r   r   load_events_infile{  s
    r   )Fry   FF)$r+   r<   r   r)   rj   Z	cloudinitr   r   Zcloudinit.distrosr   r   joinr   Zformatting_helprl   Z	FAIL_CODErv   rc   r"   r0   r4   r   r7   r:   r=   r@   rC   rK   rL   rM   rd   rb   r`   r   r   r   r   r   r   r   <module>   s^   50    
P