U
    M[‚^(3  ã                   @   sø   d dl Z d dlm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	m
Z
 d dlmZmZ d dlmZ zd dlmZmZmZmZ W n ek
r¤   dd	„ ZY nX d
de	jjjdg e	jjjdœZe e¡ZdZeddƒZG dd„ dƒZddd„ZdS )é    N)Údatetime)Ú
namedtuple)ÚstatusÚutil)ÚCONFIG_DEFAULTSÚDEFAULT_CONFIG_FILE)Ú
exceptions)ÚAnyÚcastÚDictÚOptionalc                 C   s   |S )N© )Ú_Úxr   r   ú1/usr/lib/python3/dist-packages/uaclient/config.pyr
      s    r
   zUContent provided in json response is currently considered Experimental and may changeF)Z_docÚattachedÚexpiresÚoriginÚservicesÚtechSupportLevelÚprivateÚDataPath)Úfilenamer   c                   @   sD  e Zd ZeddƒeddƒeddƒeddƒdœZdZdZd:d	dd
œdd„Zedd„ ƒZ	edd„ ƒZ
edd„ ƒZedd„ ƒZedd„ ƒZedd„ ƒZedd„ ƒZedd„ ƒZd;dedœdd „Zedd!œd"d#„Zeddœd$d%„Zd&d'„ Zd<eed(d)œd*d+„Zed,dd-œd.d/„Zd	d0œd1d2„Zd3d0œd4d5„Zd	d0œd6d7„Zd	d0œd8d9„ZdS )=ÚUAConfigúinstance-idTú
machine-idzmachine-token.jsonzstatus.jsonF)r   r   úmachine-tokenústatus-cacheNúDict[str, Any])ÚcfgÚreturnc                 C   s   |r|| _ ntƒ | _ dS )Ú N)r   Úparse_config)Úselfr   r   r   r   Ú__init__5   s    zUAConfig.__init__c                 C   s   | j r| jd d }|gS g S )z?Return the list of accounts that apply to this authorized user.ÚmachineTokenInfoÚaccountInfo)Úis_attachedÚmachine_token)r#   r&   r   r   r   Úaccounts<   s    zUAConfig.accountsc                 C   s   | j  dd¡S )NÚcontract_urlzhttps://contracts.canonical.com)r   Úget©r#   r   r   r   r*   D   s    zUAConfig.contract_urlc                 C   s
   | j d S )NÚdata_dir)r   r,   r   r   r   r-   H   s    zUAConfig.data_dirc                 C   sD   | j  d¡}ztt| ¡ ƒW S  tk
r>   tttd ƒ Y S X d S )NÚ	log_level)r   r+   ÚgetattrÚloggingÚupperÚAttributeErrorr   )r#   r.   r   r   r   r.   L   s
    zUAConfig.log_levelc                 C   s   | j  dtd ¡S )NÚlog_file)r   r+   r   r,   r   r   r   r3   T   s    zUAConfig.log_filec                 C   s¤   | j r| j S | j}|si S i | _ |d d }tdd„ | dg ¡D ƒƒ}tdd„ |d D ƒƒ}| ¡ D ]8\}}d|i}||krˆ|| |d	< t |¡ || j |< qd| j S )
z…Return a dictionary of entitlements keyed by entitlement name.

        Return an empty dict if no entitlements are present.
        r%   ÚcontractInfoc                 s   s   | ]}|d  |d fV  qdS )ÚtypeÚtokenNr   ©Ú.0Úer   r   r   Ú	<genexpr>f   s   ÿz(UAConfig.entitlements.<locals>.<genexpr>ZresourceTokensc                 s   s   | ]}|d  |fV  qdS )r5   Nr   r7   r   r   r   r:   j   s    ZresourceEntitlementsÚentitlementZresourceToken)Ú_entitlementsr(   Údictr+   Úitemsr   Zapply_series_overrides)r#   r(   r4   Ztokens_by_nameZent_by_nameZentitlement_nameZ	ent_valueZentitlement_cfgr   r   r   ÚentitlementsX   s,    
þÿÿ
zUAConfig.entitlementsc                 C   s
   t | jƒS )z<Report whether this machine configuration is attached to UA.)Úboolr(   r,   r   r   r   r'   w   s    zUAConfig.is_attachedc                 C   s   | j s|  d¡| _ | j S )zAReturn the machine-token if cached in the machine token response.r   )Ú_machine_tokenÚ
read_cacher,   r   r   r   r(   |   s    zUAConfig.machine_tokenzOptional[str])Úkeyr    c                 C   sh   | j d }|stj |t¡S || jkrX| j| }|jrHtj |t|j¡S tj ||j¡S tj |t|¡S )zAReturn the file path in the data directory represented by the keyr-   )r   ÚosÚpathÚjoinÚPRIVATE_SUBDIRÚ
data_pathsr   r   )r#   rC   r-   Ú	data_pathr   r   r   rI   ƒ   s    


  ÿzUAConfig.data_path)Ú
cache_pathr    c                 C   s   t j |¡rt  |¡ dS )z“Delete the given cache_path if it exists.

        (This is a separate method to allow easier disabling of deletion during
        tests.)
        N)rD   rE   ÚexistsÚunlink)r#   rJ   r   r   r   Ú_perform_delete‘   s    zUAConfig._perform_deletec                 C   s8   |st dƒ‚|dkr d| _d| _|  |¡}|  |¡ dS )zRemove specific cache file.z1Invalid or empty key provided to delete_cache_keyr   N)ÚRuntimeErrorr<   rA   rI   rM   )r#   rC   rJ   r   r   r   Údelete_cache_keyš   s    ÿ
zUAConfig.delete_cache_keyc                 C   s   | j  ¡ D ]}|  |¡ q
dS )z<Remove configuration cached response files class attributes.N)rH   ÚkeysrO   )r#   Zpath_keyr   r   r   Údelete_cache¦   s    zUAConfig.delete_cachezOptional[Any])rC   Úsilentr    c                 C   s|   |   |¡}zt |¡}W n2 tk
rJ   tj |¡sD|sDt d|¡ Y d S X zt	j
|tjdW S  tk
rv   | Y S X d S )NzFile does not exist: %s©Úcls)rI   r   Ú	load_fileÚ	ExceptionrD   rE   rK   r0   ÚdebugÚjsonÚloadsZDatetimeAwareJSONDecoderÚ
ValueError)r#   rC   rR   rJ   Úcontentr   r   r   rB   «   s    
zUAConfig.read_cacher	   )rC   r[   r    c                 C   s¨   |   |¡}tj |¡}tj |¡sHt |¡ tj |¡tkrHt |d¡ |dkr\d | _	d | _
t|tƒsvtj|tjd}d}|| jkr”| j| js”d}tj|||d d S )NiÀ  r   rS   i€  i¤  )Úmode)rI   rD   rE   ÚdirnamerK   ÚmakedirsÚbasenamerG   ÚchmodrA   r<   Ú
isinstanceÚstrrX   Údumpsr   ZDatetimeAwareJSONEncoderrH   r   Z
write_file)r#   rC   r[   Úfilepathr-   r\   r   r   r   Úwrite_cache¸   s     



zUAConfig.write_cache)r    c                 C   s¢   ddl m} ddlm} t t¡}|| ƒ}t|dd„ dD ]b}|d rRtj	j
j}n
tj	jj}| |d ¡}|s€t d	|d ¡ q:|d
  |d |j|dœ¡ q:|S )z#Return unattached status as a dict.r   ©Úget_available_resources)ÚENTITLEMENT_CLASS_BY_NAMEc                 S   s   | d S ©NÚnamer   ©r   r   r   r   Ú<lambda>Ñ   ó    z-UAConfig._unattached_status.<locals>.<lambda>©rC   Ú	availablerj   z@Ignoring availability of unknown service %s from contract serverr   )rj   Údescriptionro   )Úuaclient.contractrg   Úuaclient.entitlementsrh   ÚcopyÚdeepcopyÚDEFAULT_STATUSÚsortedr   ZUserFacingAvailabilityZ	AVAILABLEÚvalueÚUNAVAILABLEr+   ÚLOGrW   Úappendrp   )r#   rg   rh   ÚresponseÚ	resourcesÚresourcero   Úent_clsr   r   r   Ú_unattached_statusÊ   s,    

ýýÿzUAConfig._unattached_statuszDict[str, Optional[str]]c                 C   sj   d}d }|  ¡ }|tjjkr&tjj}n*|j|krDtjj}||j }n| ¡ \}}|j|j	|j
|j
||dœS )Nr!   )rj   rp   Zentitledr   ZstatusDetailsÚdescription_override)Úcontract_statusr   ZContractStatusZ
UNENTITLEDÚUserFacingStatusrx   rj   ÚINAPPLICABLEZuser_facing_statusrp   rw   )r#   ÚentÚinapplicable_resourcesZdetailsr€   r   Z
ent_statusr   r   r   Ú_attached_service_statusç   s     

úz!UAConfig._attached_service_statusc              	   C   s(  ddl m} ddlm} t t¡}| jd d }| d| j	d d | j	d d | 
d	¡|d |d d
œ¡ | 
d¡rˆt |d d¡|d< | j 
d¡}|s || ƒ}dd„ t|dd„ dD ƒ}|D ]"}|| ƒ}|d  |  ||¡¡ q¾| j 
di ¡ 
d¡}	|	r$|	 
di ¡ 
d¡}
|
std }
|
|d< |S )z8Return configuration of attached status as a dictionary.r   rf   )ÚENTITLEMENT_CLASSESr%   r4   Trj   Úidr   )r   Zaccountz
account-idr   Zsubscriptionzsubscription-idZeffectiveToz%Y-%m-%dT%H:%M:%SZr   ZavailableResourcesc                 S   s$   i | ]}|d  s|d |  d¡“qS )ro   rj   rp   )r+   )r8   r}   r   r   r   Ú
<dictcomp>  s   þ z-UAConfig._attached_status.<locals>.<dictcomp>c                 S   s   | d S ri   r   rk   r   r   r   rl     rm   z+UAConfig._attached_status.<locals>.<lambda>rn   r   Úsupportr;   ZaffordancesÚsupportLevelr   )rq   rg   rr   r‡   rs   rt   ru   r(   Úupdater)   r+   r   Ústrptimerv   rz   r†   r?   )r#   rg   r‡   r{   r4   r|   r…   r~   r„   rŠ   r‹   r   r   r   Ú_attached_statusþ   sH    
úÿ

 ÿþ
ÿzUAConfig._attached_statusc                 C   s^   t  ¡ dkr*td|  d¡ƒ}|sB|  ¡ }n| js:|  ¡ }n|  ¡ }t  ¡ dkrZ|  d|¡ |S )a  Return status as a dict, using a cache for non-root users

        When unattached, get available resources from the contract service
        to report detailed availability of different resources for this
        machine.

        Write the status-cache when called by root.
        r   r   r   )rD   Úgetuidr
   rB   r   r'   rŽ   re   )r#   r{   r   r   r   r   *  s    	

zUAConfig.status)N)N)F)Ú__name__Ú
__module__Ú__qualname__r   rH   r<   rA   r$   Úpropertyr)   r*   r-   r.   r3   r?   r'   r(   rb   rI   rM   rO   rQ   r@   rB   re   r   r†   rŽ   r   r   r   r   r   r   )   sF   ü







	þ,r   c                 C   s  | st } t t¡}tj t ¡ tj | ¡¡}tj |¡r<|} tj	 
d¡rTtj	 
d¡} t d| ¡ tj | ¡r‚| t t | ¡¡¡ i }tj	 ¡ D ]*\}}| ¡ }| d¡r|||dd… < q| |¡ |d  ¡ |d< tj |d ¡|d< t |d ¡st d	 |d ¡¡‚|S )
aŒ  Parse known UA config file

    Attempt to find configuration in cwd and fallback to DEFAULT_CONFIG_FILE.
    Any missing configuration keys will be set to CONFIG_DEFAULTS.

    Values are overridden by any environment variable with prefix 'UA_'.

    @param config_path: Fullpath to ua configfile. If unspecified, use
        DEFAULT_CONFIG_FILE.

    @return: Dict of configuration values.
    ZUA_CONFIG_FILEz(Using UA client configuration file at %sZua_é   Nr.   r-   r*   z'Invalid url in config. contract_url: {})r   rs   r   rD   rE   rF   Úgetcwdr_   rK   Úenvironr+   ry   rW   rŒ   ÚyamlZ	safe_loadr   rU   r>   ÚlowerÚ
startswithr1   Ú
expanduserZis_service_urlr   ZUserFacingErrorÚformat)Zconfig_pathr   Z	local_cfgZenv_keysrC   rw   r   r   r   r"   @  s4    


ÿÿr"   )N) rs   r   rX   r0   rD   r—   Úcollectionsr   Zuaclientr   r   Zuaclient.defaultsr   r   r   Útypingr	   r
   r   r   ÚImportErrorr‚   rƒ   rw   ru   Z	getLoggerr   ry   rG   r   r   r"   r   r   r   r   Ú<module>   s6   ù


  