o
    fB                     @   s  d Z 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 ddlm	Z	m
Z
mZ ddlmZmZ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 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&deddfddZ'G dd dej(Z)G dd de)Z*de
e+ fddZ,de-fdd Z.d!e+de/fd"d#Z0d!e+de
e	e+e+f  fd$d%Z1d
e)j2e)j3d&d'e-de
e$ fd(d)Z4e)ej5ffe*ej5ej6ffgZ7d*d+ Z8ed,krddl9Z9d-Z:e9j;e:d.Z<e<=  e>e?e4 e. d/ dS 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)DictOptionalTuple)atomic_helperdminetsourcesutil)NetworkConfig)cmdline	ephemeralget_interfaces_by_macis_netfail_master)wait_for_urlconfigure_secondary_nicsFzOracleCloud.comz&http://169.254.169.254/opc/v{version}/z{path}/i(#  AuthorizationzBearer OracleOpcMetadataz version instance_data vnics_datac                   @   s   e Zd ZdZdef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_applicable:      
z,KlibcOracleNetworkConfigSource.is_applicableN)__name__
__module____qualname____doc__r   r   r   r   r   r   r   3   s    r   network_configr   c                 C   s  d| vrdS | d dvrt d| d  dS t }| d dkrJdd | d D D ]}|d	 d
krGd|v rG|d }||}|s@q(t|rG|d= q(dS | d dkr| di  D ]/\}}d|v r|di d}|r||}|ssqXt|r|d d= |d= ||d d< qXdS d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 |v r|qS )typer   ).0cr   r   r   
<listcomp>[   s    z,_ensure_netfailover_safe.<locals>.<listcomp>configr&   physicalmac_addressr%   	ethernetsmatch
macaddresszset-namename)LOGdebugr   getr   items)r"   mac_to_namecfgmaccur_name_macaddrr   r   r   _ensure_netfailover_safe?   sH   



r;   c                       s   e Zd ZU 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< dZdZdZ fdd	Zd
eddf fddZdefddZedefddZdd ZdefddZdd ZdefddZdefddZedd Zd"defd d!Z   Z!S )#DataSourceOracleOracleN.network_config_sourcesT      c                    st   t t| j|g|R i | d | _tt|d| jgi tg| _	t
 | _g dd| _|  }|j| _|j| _d S )N
datasourcer$   r*   r#   )superr<   __init___vnics_datar
   mergemanydictget_cfg_by_pathdsnameBUILTIN_DS_CONFIGds_cfgr   _network_config_source_network_configget_url_paramsmax_wait_secondsurl_max_waittimeout_secondsurl_timeout)r   sys_cfgargskwargs
url_params	__class__r   r   rD      s   zDataSourceOracle.__init__ci_pkl_versionr   c                    sX   t  | t| dst| dd  t| dst| dt  t| ds*g dd| _d S d S )NrE   rK   rL   r$   rB   )rC   	_unpicklehasattrsetattrr   rL   )r   rX   rV   r   r   rY      s   


zDataSourceOracle._unpicklec                 C   s   t | jdg S )Nr*   )r   rL   r3   r   r   r   r   _has_network_config      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  | _| jrtj| jt tj	dddt
dd}nt }|   }| jdtd }| t|p4|| j| jd}W d    n1 sEw   Y  |sNdS |j }| _tj	|jd	| _|j| _|d
 |d d|d |d d| _d|v r|d d}|rt|| _|d d| jd< dS )Nr%   instancer#   path)urlheaders)ifaceconnectivity_url_datar   fetch_vnics_datamax_waittimeoutF)r#   	ociAdNameidr   hostnamedisplayName)zavailability-zonezinstance-idzlaunch-indexzlocal-hostnamer0   metadata	user_datassh_authorized_keyspublic_keysT)_read_system_uuidsystem_uuidperform_dhcp_setupr   EphemeralDHCPv4distror   find_fallback_nicMETADATA_PATTERNformat
V2_HEADERSr
   nullcontext_is_iscsi_rootrJ   r3   rI   read_opc_metadatarO   rQ   instance_data_crawled_metadataMETADATA_ROOTr#   metadata_address
vnics_datarE   ro   base64	b64decodeuserdata_raw)r   network_contextfetch_primary_nicfetch_secondary_nicsfetched_metadatadatarp   r   r   r   	_get_data   sV   	

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	   instance_id_matches_system_uuidrt   )r   rR   r   r   r   check_instance_id   s   z"DataSourceOracle.check_instance_idc                 C   s   t | jdS )Nrr   )r	   normalize_pubkey_dataro   r3   r   r   r   r   get_public_ssh_keys   r]   z$DataSourceOracle.get_public_ssh_keysc                 C   
   | j  S )z)Return whether we are on a iscsi machine.)rK   r   r   r   r   r   r}      r   zDataSourceOracle._is_iscsi_rootc                 C   r   N)rK   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 }|s*|rAz| 	| W n t
y@   ttd Y nw 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!)r\   rL   r}   r   r1   warningrJ   r3   rI   !_add_network_config_from_opc_imds	Exceptionr
   logexcr;   )r   set_primaryset_secondaryr   r   r   r"      s2   


	zDataSourceOracle.network_configFr   c                 C   sV  | j du rtd dS |sd| j d v rtd dS t }|r$| j n| j dd }t|D ]y\}}|o8|dk}|d  }||vrJtd| q/|| }t|d	 }	| jd
 dkr|rcddi}
nd|d  d|	j	 d}
|d|t
|
gd}| jd | q/| jd
 dkrt
d|id|d}|s|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 benicIndexr   z\VNIC metadata indicates this is a bare metal machine; skipping secondary VNIC configuration.r$   macAddrz)Interface with MAC %s not found; skippingsubnetCidrBlockr#   r&   dhcpstatic	privateIp/)r&   addressr+   )r0   r&   r,   mtusubnetsr*   r%   r/   F)r   r.   dhcp6dhcp4	addressesr-   )rE   r1   r   r   	enumeratelower	ipaddress
ip_networkrL   	prefixlenMTUappend)r   r   interfaces_by_macr   index	vnic_dict
is_primaryr,   r0   networksubnetinterface_configr   r   r   r     s\   


z2DataSourceOracle._add_network_config_from_opc_imds)F)"r   r   r    rH   rt   r	   NetworkConfigSourceCMD_LINE
SYSTEM_CFGDS	INITRAMFSr>   r   __annotations__ru   rO   rQ   rD   intrY   r   r\   staticmethodr_   r   r   r   r}   dictr   propertyr"   r   __classcell__r   r   rV   r   r<   s   s0   
 6
-r<   c                   @   s   e Zd ZdZdS )DataSourceOracleNetFN)r   r   r    ru   r   r   r   r   r   n  s    r   c                  C   s   t d} | d u rd S |  S )Nzsystem-uuid)r   read_dmi_datar   )sys_uuidr   r   r   rs   r  s   
rs   c                  C   s   t d} | tkS )Nzchassis-asset-tag)r   r   CHASSIS_ASSET_TAG)	asset_tagr   r   r   r^   w  s   
r^   rc   c                 C   s   |  drdS dS )Nzhttp://169.254.169.254/opc/v2r%   r$   )
startswithrc   r   r   r   _url_version|  r]   r   c                 C   s   t | dkrtS d S )Nr%   )r   r{   r   r   r   r   _headers_cb  s   r   rg   rh   c                 C   s   t jdddt jdddg}t }t|||tdd\}}|s&td dS t	|
d	}t|}d}	| r]tt j|d
dg|t |  |tdd\}
}|
rXt	|
d	}	ntd t|||	S )ao  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
        or None if fetching metadata failed

    r%   r`   ra   r$   r   )ri   rj   
headers_cb
sleep_timezFailed to fetch IMDS metadata!Nzutf-8vnicsz+Failed to fetch IMDS network configuration!)ry   rz   time	monotonicr   r   r1   r   jsonloadsdecoder   r   )rh   ri   rj   urls
start_timeinstance_urlinstance_responser   metadata_versionr   	vnics_urlvnics_responser   r   r   r~     s:   



r~   c                 C   s   t | tS r   )r	   list_from_dependsdatasources)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)r~   r^   )@r!   r   r   r   loggingr   collectionsr   typingr   r   r   	cloudinitr   r   r   r	   r
   cloudinit.distros.networkingr   cloudinit.netr   r   r   r   cloudinit.url_helperr   	getLoggerr   r1   rI   r   r   ry   r   r{   r   KlibcNetworkConfigSourcer   r;   
DataSourcer<   r   strrs   r   r^   r   r   r   rO   rQ   r~   DEP_FILESYSTEMDEP_NETWORKr   r   argparser   ArgumentParserparser
parse_argsprint
json_dumpsr   r   r   r   <module>   sv   

4 |

<