U
    Ld:                     @   s  d 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 ddlmZmZmZ ddlmZ dd	lmZmZmZmZ dd
lmZmZ eeZddiZdZdZed Z dZ!ddiZ"eddZ#G dd dej$Z%eddddZ&G dd dej'Z(ee) dddZ*e+ddd Z,d/e-e)e-e.d"d#d$Z/dd%e+e#d&d'd(Z0e(ej1ffgZ2d)d* Z3ed+krddl4Z4d,Z5e4j6e5d-Z7e78  e9e	:e0 e, d. dS )0a3  Datasource for Oracle (OCI/Oracle Cloud Infrastructure)

Notes:
 * This datasource does not support OCI Classic. OCI Classic provides an EC2
   lookalike metadata service.
 * The UUID provided in DMI data is not the same as the meta-data provided
   instance-id, but has an equivalent lifespan.
 * We do need to support upgrade from an instance that cloud-init
   identified as OpenStack.
 * Bare metal instances use iSCSI root, virtual machine instances do not.
 * Both bare metal and virtual machine instances provide a chassis-asset-tag of
   OracleCloud.com.
    N)
namedtuple)OptionalTuple)atomic_helperdmi)log)netsourcesutil)NetworkConfig)cmdline	ephemeralget_interfaces_by_macis_netfail_master)UrlErrorreadurlconfigure_secondary_nicsFzOracleCloud.comz&http://169.254.169.254/opc/v{version}/z{path}/i(#  ZAuthorizationzBearer OracleOpcMetadataz version instance_data vnics_datac                   @   s   e Zd ZdZedddZdS )KlibcOracleNetworkConfigSourcezOverride super class to lower the applicability conditions.

    If any `/run/net-*.cfg` files exist, then it is applicable. Even if
    `/run/initramfs/open-iscsi.interface` does not exist.
    returnc                 C   s
   t | jS )zOverride is_applicable)bool_filesself r   D/usr/lib/python3/dist-packages/cloudinit/sources/DataSourceOracle.pyis_applicable9   s    z,KlibcOracleNetworkConfigSource.is_applicableN)__name__
__module____qualname____doc__r   r   r   r   r   r   r   2   s   r   )network_configr   c                 C   s  d| krdS | d dkr,t d| d  dS t }| d dkrdd | d D D ]@}|d	 d
krPd|krP|d }||}|sqPqPt|rP|d= qPn|| d dkr| di  D ]\\}}d|kr|di d}|r||}|sqqt|r|d d= |d= ||d d< qdS )aP  
    Search network config physical interfaces to see if any of them are
    a netfailover master.  If found, we prevent matching by MAC as the other
    failover devices have the same MAC but need to be ignored.

    Note: we rely on cloudinit.net changes which prevent netfailover devices
    from being present in the provided network config.  For more details about
    netfailover devices, refer to cloudinit.net module.

    :param network_config
       A v1 or v2 network config dict with the primary NIC, and possibly
       secondary nic configured.  This dict will be mutated.

    versionN)      z+Ignoring unknown network config version: %sr$   c                 S   s   g | ]}d |kr|qS )typer   ).0cr   r   r   
<listcomp>Z   s      z,_ensure_netfailover_safe.<locals>.<listcomp>configr&   physicalmac_addressr%   	ethernetsmatch
macaddresszset-namename)LOGdebugr   getr   items)r"   Zmac_to_nameZcfgZmacZcur_name_Zmacaddrr   r   r   _ensure_netfailover_safe>   s>    



r6   c                       s   e Zd ZU dZdZdZejjejj	ejj
ejjfZeejdf ed< g ddZeed<  fdd	Zed
ddZeed
ddZdd Zed
ddZdd Zed
ddZed
ddZedd ZdedddZ  ZS ) DataSourceOracleZOracleN.network_config_sourcesr$   )r*   r#   _network_configc                    sJ   t t| j|f|| d | _tt|d| jgi tg| _	t
 | _d S )NZ
datasource)superr7   __init___vnics_datar
   ZmergemanydictZget_cfg_by_pathdsnameBUILTIN_DS_CONFIGds_cfgr   _network_config_source)r   sys_cfgargskwargs	__class__r   r   r;      s    zDataSourceOracle.__init__r   c                 C   s   t | jdg S )Nr*   )r   r9   r3   r   r   r   r   _has_network_config   s    z$DataSourceOracle._has_network_configc                   C   s   t  S )z@Check platform environment to report if this datasource may run.)_is_platform_viabler   r   r   r   	ds_detect   s    zDataSourceOracle.ds_detectc              	   C   s   t  | _tj| jt tjdddt	dd}| 
  }| jdtd }| t|pX|d}W 5 Q R X |j }| _tj|jd| _|j| _|d	 |d
 d|d |d d| _d|kr|d d}|rt|| _|d d| jd< dS )Nr%   instancer#   path)urlheaders)ZifaceZconnectivity_url_datar   fetch_vnics_data)r#   Z	ociAdNameidr   ZhostnameZdisplayName)zavailability-zonezinstance-idzlaunch-indexzlocal-hostnamer0   metadata	user_dataZssh_authorized_keyspublic_keysT)_read_system_uuidsystem_uuidr   ZEphemeralDHCPv4Zdistror   Zfind_fallback_nicMETADATA_PATTERNformat
V2_HEADERS_is_iscsi_rootr?   r3   r>   read_opc_metadatainstance_dataZ_crawled_metadataMETADATA_ROOTr#   Zmetadata_address
vnics_datar<   rQ   base64Z	b64decodeZuserdata_raw)r   Znetwork_contextZfetch_primary_nicZfetch_secondary_nicsZfetched_metadatadatarR   r   r   r   	_get_data   sH    

zDataSourceOracle._get_datac                 C   s   t | jS )zquickly check (local only) if self.instance_id is still valid

        On Oracle, the dmi-provided system uuid differs from the instance-id
        but has the same life-span.)r	   Zinstance_id_matches_system_uuidrU   )r   rA   r   r   r   check_instance_id   s    z"DataSourceOracle.check_instance_idc                 C   s   t | jdS )NrS   )r	   Znormalize_pubkey_datarQ   r3   r   r   r   r   get_public_ssh_keys   s    z$DataSourceOracle.get_public_ssh_keysc                 C   s
   | j  S )z)Return whether we are on a iscsi machine.)r@   r   r   r   r   r   rY      s    zDataSourceOracle._is_iscsi_rootc                 C   s
   | j  S N)r@   Zrender_configr   r   r   r   _get_iscsi_config   s    z"DataSourceOracle._get_iscsi_configc                 C   s   |   r| jS d}|  r$|  | _|   s:td d}| jdtd }|sT|rz| 	| W n  t
k
r   ttd Y nX t| j | jS )zNetwork config is read from initramfs provided files

        Priority for primary network_config selection:
        - iscsi
        - imds

        If none is present, then we fall back to fallback configuration.
        FzLCould not obtain network configuration from initramfs. Falling back to IMDS.Tr   z+Failed to parse IMDS network configuration!)rF   r9   rY   rd   r1   warningr?   r3   r>   !_add_network_config_from_opc_imds	Exceptionr
   logexcr6   )r   set_primaryZset_secondaryr   r   r   r"      s0    



zDataSourceOracle.network_configF)ri   c                 C   sZ  | j dkrtd dS |s8d| j d kr8td dS t }|rH| j n| j dd }t|D ]\}}|op|dk}|d  }||krtd| q^|| }t|d	 }	| jd
 dkr|rddi}
nd|d  d|	j	 d}
|d|t
|
gd}| jd | q^| jd
 dkr^t
d|id|d}|sF|d  d|	j	 g|d< || jd |< q^dS )a  Generate primary and/or secondary NIC config from IMDS and merge it.

        It will mutate the network config to include the secondary VNICs.

        :param set_primary: If True set primary interface.
        :raises:
            Exceptions are not handled within this function.  Likely
            exceptions are KeyError/IndexError
            (if the IMDS returns valid JSON with unexpected contents).
        Nz#NIC data is UNSET but should not beZnicIndexr   z\VNIC metadata indicates this is a bare metal machine; skipping secondary VNIC configuration.r$   ZmacAddrz)Interface with MAC %s not found; skippingZsubnetCidrBlockr#   r&   ZdhcpZstaticZ	privateIp/)r&   Zaddressr+   )r0   r&   r,   mtuZsubnetsr*   r%   r/   F)rk   r.   Zdhcp6Zdhcp4Z	addressesr-   )r<   r1   re   r   	enumeratelower	ipaddressZ
ip_networkr9   Z	prefixlenMTUappend)r   ri   Zinterfaces_by_macr]   indexZ	vnic_dictZ
is_primaryr,   r0   ZnetworkZsubnetZinterface_configr   r   r   rf     sX    


z2DataSourceOracle._add_network_config_from_opc_imds)F)r   r   r    r=   rU   Zvendordata_purer	   ZNetworkConfigSourceZCMD_LINEZ
SYSTEM_CFGZDSZ	INITRAMFSr8   r   __annotations__r9   dictr;   r   rF   staticmethodrH   r`   ra   rb   rY   rd   propertyr"   rf   __classcell__r   r   rD   r   r7   r   s*   
.
-r7   r   c                  C   s   t d} | d krd S |  S )Nzsystem-uuid)r   read_dmi_datarm   )Zsys_uuidr   r   r   rT   P  s    
rT   c                  C   s   t d} | tkS )Nzchassis-asset-tag)r   rw   CHASSIS_ASSET_TAG)Z	asset_tagr   r   r   rG   U  s    
rG   r%   )metadata_versionrK   retriesr   c                 C   s*   t tj| |d| dkrtnd |dj S )NrJ   r$   )rL   rM   rz   )r   rV   rW   rX   Z	_responseZjson)ry   rK   rz   r   r   r   _fetchZ  s
    r{   rN   )rO   r   c                 C   s   d}zt |dd}W n$ tk
r8   d}t |dd}Y nX d}| rtzt |dd}W n  tk
rr   ttd Y nX t|||S )aC  Fetch metadata from the /opc/ routes.

    :return:
        A namedtuple containing:
          The metadata version as an integer
          The JSON-decoded value of the instance data endpoint on the IMDS
          The JSON-decoded value of the vnics data endpoint if
            `fetch_vnics_data` is True, else None

    r%   rI   )rK   r$   NZvnicsz+Failed to fetch IMDS network configuration!)r{   r   r
   rh   r1   r   )rO   ry   r[   r]   r   r   r   rZ   b  s    rZ   c                 C   s   t | tS rc   )r	   Zlist_from_dependsdatasources)Zdependsr   r   r   get_datasource_list  s    r}   __main__z
        Query Oracle Cloud metadata and emit a JSON object with two keys:
        `read_opc_metadata` and `_is_platform_viable`.  The values of each are
        the return values of the corresponding functions defined in
        DataSourceOracle.py.)description)rZ   rG   )r%   );r!   r^   rn   collectionsr   typingr   r   Z	cloudinitr   r   r   Zloggingr   r	   r
   Zcloudinit.distros.networkingr   Zcloudinit.netr   r   r   r   Zcloudinit.url_helperr   r   Z	getLoggerr   r1   r>   rx   r\   rV   ro   rX   r   ZKlibcNetworkConfigSourcer   r6   Z
DataSourcer7   strrT   r   rG   intrs   r{   rZ   ZDEP_FILESYSTEMr|   r}   argparser   ArgumentParserparser
parse_argsprintZ
json_dumpsr   r   r   r   <module>   sV   
 
4 _ 

