U
    Ld2                     @   sJ  d dl 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mZm	Z	m
Z
mZmZ d dlmZ d dlmZmZ d dlmZmZ eeZdZdZdd	d
dgZdddddddddddgZedfddZdd ZdddZddd Z dd!d"Z!d#d$ Z"d%d& Z#d'd( Z$d)d* Z%d+d, Z&d-d. Z'd/d0 Z(d1d2 Z)ej*dd3e+d4d5d6Z,ej*dd3e-d4d7d8Z.e/e+d9d:d;Z0dd<d=Z1d>d? Z2d@dA Z3de+d4dBdCZ4ddDdEZ5ddFdGZ6dHdI Z7dJdK Z8dLdM Z9dNdO Z:dPdQ Z;G dRdS dSe<Z=dTdU Z>e
e/ d4dVdWZ?ee/ d4dXdYZ@e
e/ d4dZd[ZAee/ d4d\d]ZBe
e/ d4d^d_ZCee/ d4d`daZDe
e/ d4dbdcZEee/ d4dddeZFddfdgZGdhdi ZHddkdlZIddndoZJddpdqZKdrds ZLdtdu ZMeNd4dvdwZOe/ee/ dxdydzZPeNd4d{d|ZQeNd4d}d~ZReNd4ddZSeNd4ddZTde+e+e+e+e+e+e+e-dddZUed e
ee/e/e/e/f  ddddZVdd ZWe	e/ef e+dddZXee/dddZYe/e+dddZZe/e+dddZ[e/e+dddZ\e/e+dddZ]e/e+dddZ^e/e+dddZ_e+d4ddZ`e/d4ddZaebd4ddZcebd4ddZde/e/e/dddZeG dd defZgdS )    N)AnyCallableDictListOptionalTuple)urlparse)subputil)UrlErrorreadurlz/sys/class/net/Zeth0Zdhcp6Z
ipv6_slaaczipv6_dhcpv6-statelesszipv6_dhcpv6-stateful	ovs-vsctlz--formatZcsvz--no-headingsz	--timeoutZ10z	--columnsnamefind	interfaceztype=internalz([0-9]+)c                 C   s   dd t || D S )aD  Sorting for Humans: natural sort order. Can be use as the key to sort
    functions.
    This will sort ['eth0', 'ens3', 'ens10', 'ens12', 'ens8', 'ens0'] as
    ['ens0', 'ens3', 'ens8', 'ens10', 'ens12', 'eth0'] instead of the simple
    python way which will produce ['ens0', 'ens10', 'ens12', 'ens3', 'ens8',
    'eth0'].c                 S   s$   g | ]}|  rt|n| qS  )isdigitintlower).0textr   r   8/usr/lib/python3/dist-packages/cloudinit/net/__init__.py
<listcomp>3   s   z$natural_sort_key.<locals>.<listcomp>)resplit)sZ_nsrer   r   r   natural_sort_key,   s    
r   c                   C   s   t S )z3Simple function to return the global SYS_CLASS_NET.)SYS_CLASS_NETr   r   r   r   get_sys_class_path9   s    r    c                 C   s   t  |  d | S )N/)r   devnamepathr   r   r   sys_dev_path>   s    r$   c           
   
   C   s
  t | |}zt|}W n ttfk
r } z^t|dd }	|	tjtjfkrb|d k	rb|| W Y ,S |	tj	fkr|d k	r|| W Y S  W 5 d }~X Y nX |
 }|d kr|S z
|| W S  tk
r } z,|d k	r|| W Y S td||  W 5 d }~X Y nX d S )Nerrnoz5Found unexpected (not translatable) value '%s' in '%s)r$   r
   Z	load_fileOSErrorIOErrorgetattrr%   ENOENTZENOTDIRZEINVALstripKeyErrorLOGdebug)
r"   r#   	translate	on_enoenton_keyerror	on_einvalZdev_pathcontentseZe_errnor   r   r   read_sys_netB   s4    

r4   c                 C   s   dd }t | |||||dS )Nc                 S   s   dS NFr   )r3   r   r   r   on_excp_falseh   s    z(read_sys_net_safe.<locals>.on_excp_false)r0   r/   r1   r.   )r4   )ifacefieldr.   r6   r   r   r   read_sys_net_safeg   s    r9   c                 C   s<   t | |}|dkrd S z
t|W S  tk
r6   Y d S X d S r5   )r9   r   
ValueError)r7   r8   valr   r   r   read_sys_net_intu   s    

r<   c                 C   s   dddd}t | d|dS )NTF)upunknowndown	operstate)r.   r9   )r"   r.   r   r   r   is_up   s    rB   c                 C   s   t jt| dS )Nbridgeosr#   existsr$   r"   r   r   r   	is_bridge   s    rH   c                 C   s   t jt| dS )NbondingrD   rG   r   r   r   is_bond   s    rJ   c                 C   s    t | dd}tj|r|S dS )z8Return the master path for devname, or None if no mastermasterr#   N)r$   rE   r#   rF   r!   r   r   r   
get_master   s    rM   c                 C   sH   t | }|dkrdS tj|d}tj|d}tj|pFtj|S )z@Return a bool indicating if devname's master is a bridge or bondNFrI   rC   )rM   rE   r#   joinrF   )r"   master_pathZbonding_pathZbridge_pathr   r   r   master_is_bridge_or_bond   s    rP   c                 C   s,   t | }|dkrdS t| dd}tj|S )z;Return a bool indicating if devname's master is openvswitchNFzupper_ovs-systemrL   )rM   r$   rE   r#   rF   )r"   rO   Zovs_pathr   r   r   master_is_openvswitch   s
    rQ   c                 C   s   t | ddkS )Ntype32rA   rG   r   r   r   is_ib_interface   s    rT   )maxsize)returnc                  C   s    t td} | std | S )zDReturn a bool indicating if Open vSwitch is installed in the system.r   z<ovs-vsctl not in PATH; not detecting Open vSwitch interfaces)boolr	   Zwhichr,   r-   )retr   r   r   openvswitch_is_installed   s    rY   c               
   C   sf   zt  t\} }W nF t jk
rX } z&d|jkrFtd g  W Y S  W 5 d}~X Y n
X |  S dS )zReturn a list of the names of OVS internal interfaces on the system.

    These will all be strings, and are used to exclude OVS-specific interface
    from cloud-init's network configuration handling.
    zdatabase connection failedzJOpen vSwitch is not yet up; no interfaces will be detected as OVS-internalN)r	   !OVS_INTERNAL_INTERFACE_LOOKUP_CMDZProcessExecutionErrorstderrr,   info
splitlines)out_errexcr   r   r   get_ovs_internal_interfaces   s    
ra   )r"   rV   c                 C   s,   t  s
dS t }| |kr(td|  dS dS )zReturns True if this is an OVS internal interface.

    If OVS is not installed or not yet running, this will return False.
    FzDetected %s as an OVS interfaceT)rY   ra   r,   r-   )r"   Zovs_bridgesr   r   r   !is_openvswitch_internal_interface   s    rb   c                 C   s,   |dkrt | }t| |s$t| |r(dS dS )znetfailover driver uses 3 nics, master, primary and standby.
    this returns True if the device is either the primary or standby
    as these devices are to be ignored.
    NTF)device_driveris_netfail_primaryis_netfail_standbyr"   driverr   r   r   is_netfailover   s     rh   c                 C   s,   d}zt | d}W n tk
r&   Y nX |S )zDReturns a str from reading /sys/class/net/<devname>/device/features.r   zdevice/features)r4   	Exceptionr"   Zfeaturesr   r   r   get_dev_features   s    rk   c                 C   s(   t | }|rt|dk rdS |d dkS )z Return True if VIRTIO_NET_F_STANDBY bit (62) is set.

    https://github.com/torvalds/linux/blob/         089cf7f6ecb266b6a4164919a2e69bd2f938374a/         include/uapi/linux/virtio_net.h#L60
    @   F>   1)rk   lenrj   r   r   r   has_netfail_standby_feature   s    rp   c                 C   s<   t | dk	rdS |dkr t| }|dkr,dS t| s8dS dS )zA device is a "netfail master" device if:

    - The device does NOT have the 'master' sysfs attribute
    - The device driver is 'virtio_net'
    - The device has the standby feature bit set

    Return True if all of the above is True.
    NF
virtio_netTrM   rc   rp   rf   r   r   r   is_netfail_master  s    	rs   c                 C   st   t | dd}tj|sdS |dkr,t| }|dkr8dS tjtj|}t|}|dkr`dS t|}|spdS dS )a7  A device is a "netfail primary" device if:

    - the device has a 'master' sysfs file
    - the device driver is not 'virtio_net'
    - the 'master' sysfs file points to device with virtio_net driver
    - the 'master' device has the 'standby' feature bit set

    Return True if all of the above is True.
    rK   rL   FNrq   T)r$   rE   r#   rF   rc   basenamerealpathrp   )r"   rg   Zmaster_sysfs_pathZmaster_devnameZmaster_driverZmaster_has_standbyr   r   r   rd     s    rd   c                 C   s<   t | dkrdS |dkr t| }|dkr,dS t| s8dS dS )zA device is a "netfail standby" device if:

    - The device has a 'master' sysfs attribute
    - The device driver is 'virtio_net'
    - The device has the standby feature bit set

    Return True if all of the above is True.
    NFrq   Trr   rf   r   r   r   re   :  s    	re   c                 C   s   t | d}|r|dkrdS dS )a  
    /* interface name assignment types (sysfs name_assign_type attribute) */
    #define NET_NAME_UNKNOWN      0  /* unknown origin (not exposed to user) */
    #define NET_NAME_ENUM         1  /* enumerated by kernel */
    #define NET_NAME_PREDICTABLE  2  /* predictably named by the kernel */
    #define NET_NAME_USER         3  /* provided by user-space */
    #define NET_NAME_RENAMED      4  /* renamed by user-space */
    name_assign_type)34TFrA   )r"   rv   r   r   r   
is_renamedR  s    	
ry   c                 C   s   t t| d}d| kS )NueventzDEVTYPE=vlan)strr9   r]   )r"   rz   r   r   r   is_vlana  s    r|   c                 C   s0   d}t | d}tj|r,tjt|}|S )z8Return the device driver for net device named 'devname'.Nzdevice/driver)r$   rE   r#   islinkrt   readlink)r"   rg   Zdriver_pathr   r   r   rc   f  s
    
rc   c                 C   s   t | d}|dkrdS |S )z;Return the device id string for net device named 'devname'.zdevice/deviceFNrA   )r"   Zdev_idr   r   r   device_devidq  s    
r   c               
   C   sj   t  st  rtt  S ztt } W n6 t	k
rd } z|j
t
jkrRg } n W 5 d }~X Y nX | S N)r
   
is_FreeBSDis_DragonFlyBSDlistget_interfaces_by_macvaluesrE   listdirr   r&   r%   r)   )devsr3   r   r   r   get_devicelistz  s    r   c                   @   s   e Zd ZdZdS )ParserErrorz6Raised when a parser has issue parsing a file/content.N)__name__
__module____qualname____doc__r   r   r   r   r     s   r   c                 C   s    | rt | tsdS | ddkS )NFconfigZdisabled)
isinstancedictget)cfgr   r   r   is_disabled_cfg  s    r   c                   C   s6   t  st  rt S t  s&t  r,t S t S dS )zqGet the list of network interfaces viable for networking.

    @return List of interfaces, sorted naturally.
    N)r
   r   r   find_candidate_nics_on_freebsd	is_NetBSD
is_OpenBSD(find_candidate_nics_on_netbsd_or_openbsdfind_candidate_nics_on_linuxr   r   r   r   find_candidate_nics  s
    r   c                   C   s6   t  st  rt S t  s&t  r,t S t S dS )z.Get the name of the 'fallback' network device.N)r
   r   r   find_fallback_nic_on_freebsdr   r   &find_fallback_nic_on_netbsd_or_openbsdfind_fallback_nic_on_linuxr   r   r   r   find_fallback_nic  s
    r   c                   C   s   t t  tdS )zmGet the names of the candidate network devices on NetBSD/OpenBSD.

    @return list of sorted interfaces
    key)sortedr   r   r   r   r   r   r   r     s    r   c                  C   s   t  } | r| d S dS )zfGet the 'fallback' network device name on NetBSD/OpenBSD.

    @return default interface, or None
    r   N)r   namesr   r   r   r     s    r   c                  C   s8   t  ddddg\} }|  }|r&|S tt  tdS )zgGet the names of the candidate network devices on FreeBSD.

    @return List of sorted interfaces.
    ifconfigz-lz-uetherr   )r	   r   r   r   r   r   )stdoutZ_stderrr   r   r   r   r     s
    r   c                  C   s   t  } | r| d S dS )z_Get the 'fallback' network device name on FreeBSD.

    @return List of sorted interfaces.
    r   N)r   r   r   r   r   r     s    r   c                  C   sV  dt  krtd n<dd t D } t| rTtd|  d}t jtj|t jd g }g }tdddddd	d
D ]\}}}}|dkrqp|	drtd| qpt
|d}|r|| qptd| t
|d}|r|| qpt|d}|dkr|| qptd| qpg }	||fD ]:}
t|
td}
t|
krF|
t |
dt |	|
7 }	q|	S )zeGet the names of the candidate network devices on Linux.

    @return List of sorted interfaces.
    znet.ifnames=0z9Stable ifnames disabled by net.ifnames=0 in /proc/cmdlinec                 S   s    g | ]}|d krt |s|qS )lo)ry   )r   Zdevicer   r   r   r     s    z0find_candidate_nics_on_linux.<locals>.<listcomp>z4Found unstable nic names: %s; calling udevadm settlez!Waiting for udev events to settle)funcFT)filter_openvswitch_internal2filter_slave_if_master_not_bridge_bond_openvswitchfilter_vlanfilter_without_own_macfilter_zero_maclog_filtered_reasonsr   ZvethzIgnoring veth interface: %scarrierzInterface has no carrier: %sdormantr@   )r   r?   Zlowerlayerdownr>   zInterface ignored: %sr   r   )r
   Zget_cmdliner,   r-   r   ro   Zlog_timeZudevadm_settleget_interfaces
startswithr<   appendr9   r   r   DEFAULT_PRIMARY_INTERFACEremoveinsert)ZunstablemsgZ	connectedZpossibly_connectedr   _r   r   r@   Zsorted_interfaces
interfacesr   r   r   r     sb    








r   c                  C   s   t  } | r| d S dS )z]Get the 'fallback' network device name on Linux.

    @return List of sorted interfaces.
    r   N)r   r   r   r   r   r   !  s    r   c                 C   st   | sd} t  }|sdS t|r(d|i}ndt|d i}d||d}| rbt|}|rb||d d	< ||id
d}|S )zBGenerate network cfg v2 for dhcp on the NIC most likely connected.FNr   
macaddressaddressT)Zdhcp4set-namematchr   rg      )	ethernetsversion)r   rs   r9   r   rc   )Zconfig_driverZtarget_namer   r   rg   Znconfr   r   r   generate_fallback_config-  s"    
 r   c                 C   sJ   dd }dd }|  d}|dkr*|| S |dkr:|| S td| d S )	Nc                 S   s   g }|  di D ]|}| ddkr$q| d}|s4q| d}| di  d}| di  d}|snt|}|szt|}|||||g q|S )	Nr   rR   ZphysicalZmac_addressr   paramsrg   	device_id)r   rc   r   r   )netcfgphysdevsentmacr   rg   r   r   r   r   
_version_1H  s     

z$extract_physdevs.<locals>._version_1c                 S   s   g }|  di  D ]z}| d}|s(q| di  d}|s@q| di  d}| di  d}|spt|}|s|t|}|||||g q|S )Nr   r   r   r   rg   r   )r   r   rc   r   r   )r   r   r   r   r   rg   r   r   r   r   
_version_2Z  s     
z$extract_physdevs.<locals>._version_2r      r   z"Unknown network config version: %s)r   RuntimeError)r   r   r   r   r   r   r   extract_physdevsG  s    
r   Fc                 C   s*   t | d}|dkr"|rtddS |dkS )a  return True if the provided interface has its own address.

    Based on addr_assign_type in /sys.  Return true for any interface
    that does not have a 'stolen' address. Examples of such devices
    are bonds or vlans that inherit their mac from another device.
    Possible values are:
      0: permanent address    2: stolen from another device
      1: randomly generated   3: set using dev_set_mac_addressZaddr_assign_typeNz%s had no addr_assign_type.T)r   r      )r<   r:   )ifnamestrictZassign_typer   r   r   interface_has_own_macw  s    

r   Tc                 C   s   i }t  D ]*\}}}}d||| |t|d||< q
| rtd}tjdddddd	d
gdd\}}tjddddgdd\}	}t }
||	fD ]}|
|| q|	 D ] }|d dkp|d |
k|d< q|S )a  Collect information necessary for rename_interfaces.

    returns a dictionary by mac address like:
       {name:
         {
          'downable': None or boolean indicating that the
                      device has only automatically assigned ip addrs.
          'device_id': Device id value (if it has one)
          'driver': Device driver (if it has one)
          'mac': mac address (in lower case)
          'name': name
          'up': boolean: is_up(name)
         }}
    N)downabler   rg   r   r   r=   z[0-9]+:\s+(\w+)[@:]ipz-6ZaddrZshowZ	permanentZscopeglobalTZcapturez-4r=   Fr   r   )
r   r   rB   r   compiler	   setupdatefindallr   )Zcheck_downablecur_infor   r   rg   r   ZnmatchZipv6r_   Zipv4Znics_with_addressesZ	bytes_outdr   r   r   _get_current_rename_info  s.    	

r   c                    s  t | std d S |d kr$t }i  | D ]:\}}| }|drZ|d  |d< ||d< | |< q0td   fdd}dd }d	d
 }	dd }
g }g }g }| }d}d}dd  fdd}| D ]\}}}}|r| }g }||||}|s|r|d||f  q|d}||kr0q|sN|r|d||f  q|d rd}|d s|r|||||f  qd|d< |d|||ff |d|||ff ||krz|| }|d r
d}|d s|r|||||f  qn|d|||ff d }|d ks"||kr6|d7 }|| }q|d||||ff ||d< | }|d rz|d|||ff |d|||d |ff ||d< | }||7 }q||	|
d}t |t | dkrt |rtd|  ntd|  nztd | ||  || D ]^\}}}}z|||  W n< t	k
rj } z|d!|||||f  W 5 d }~X Y nX qt |rt
d"|d S )#Nzno interfaces to renamer   r   zDetected interfaces %sc                    s   t dd   D S )Nc                 s   s   | ]}|d  |fV  qdS )r   Nr   r   datar   r   r   	<genexpr>  s     z<_rename_interfaces.<locals>.update_byname.<locals>.<genexpr>)r   r   )Zbymac)r   r   r   update_byname  s    z)_rename_interfaces.<locals>.update_bynamec                 S   s   t j ddd| d|gdd d S )Nr   linkr   r   Tr   r	   )curnewr   r   r   rename  s    z"_rename_interfaces.<locals>.renamec                 S   s   t j ddd| dgdd d S )Nr   r   r   r?   Tr   r   r   r   r   r   r?     s    z _rename_interfaces.<locals>.downc                 S   s   t j ddd| dgdd d S )Nr   r   r   r=   Tr   r   r   r   r   r   r=     s    z_rename_interfaces.<locals>.upz
cirename%dc                 S   sd   |r0|r0|r0| d |ko.| d |ko.| d |kS |rP|rP| d |koN| d |kS |r`| d |kS dS )zmatch if set and in datar   rg   r   Fr   )r   r   rg   r   r   r   r   entry_match  s    

z'_rename_interfaces.<locals>.entry_matchc                    sT    fdd  D }t|rPt|dkrHd| f }t||d S d S )Nc                    s   g | ]}| r|qS r   r   r   )r   rg   r   r   r   r   r     s   z:_rename_interfaces.<locals>.find_entry.<locals>.<listcomp>r   zjFailed to match a single device. Matched devices "%s" with search values "(mac:%s driver:%s device_id:%s)"r   )r   ro   r:   )r   rg   r   r   r   r   r   )r   rg   r   r   
find_entry  s    
z&_rename_interfaces.<locals>.find_entryz<[nic not present] Cannot rename mac=%s to %s, not available.r=   z*[busy] Error renaming mac=%s from %s to %sr   Fr?   z2[busy-target] Error renaming mac=%s from %s to %s.r   r   )r   r?   r=   r   z(unable to do any work for renaming of %sz$no work necessary for renaming of %sz$achieving renaming of %s with ops %sz.[unknown] Error performing %s%s for %s, %s: %s
)ro   r,   r-   r   itemscopyr   r   r   ri   r   rN   )renamesZstrict_presentZstrict_busyZcurrent_infor   r   r   r   r   r?   r=   ZopserrorsZupsZ
cur_bynameZtmpname_fmtZtmpir   r   new_namerg   r   Zcur_opsZcur_namer   targetZtmp_nameZopmapopr   r3   r   r   r   _rename_interfaces  s    













r   c                 C   s$   d}t jt| drd}t| |S )z6Returns the string value of an interface's MAC Addressr   Zbonding_slavezbonding_slave/perm_hwaddr)rE   r#   isdirr$   r9   )r   r#   r   r   r   get_interface_macX  s    r   c                 C   s>   t | ddkr:t| }|r6|r6|dd |dd  }|S dS )zReturns the string value of an Infiniband interface's hardware
    address. If ethernet_format is True, an Ethernet MAC-style 6 byte
    representation of the address will be returned.
    rR   rS   $   i3   N)r9   r   )r   Zethernet_formatr   r   r   r   get_ib_interface_hwaddrb  s
    r   c                   C   s<   t  st  rt S t  r$t S t  r2t S t S d S r   )	r
   r   r    get_interfaces_by_mac_on_freebsdr   get_interfaces_by_mac_on_netbsdr    get_interfaces_by_mac_on_openbsdget_interfaces_by_mac_on_linuxr   r   r   r   r   p  s    r   )r   rV   c                 C   s0   t   D ] \}}|  | kr
|  S q
d S r   )r   r   r   )r   Zinterface_macZinterface_namer   r   r   find_interface_name_from_mac{  s    
r   c                  C   s>   t  dddg\} }dd }dd }dd	 ||| D }|S )
Nr   -ar   c                 s   s@   d}|  dD ]&}|dr&||7 }q|r0|V  |}q|V  d S )Nr   r   	)r   r   )r^   Z
curr_blockliner   r   r   flatten  s    

z1get_interfaces_by_mac_on_freebsd.<locals>.flattenc                 s   s4   | D ]*}t d|}|r|d|dfV  qd S )Nz2^(?P<ifname>\S*): .*ether\s(?P<mac>[\da-f:]{17}).*r   r   )r   searchgroup)Z	flat_listblockmr   r   r   find_mac  s     z2get_interfaces_by_mac_on_freebsd.<locals>.find_macc                 S   s   i | ]\}}||qS r   r   )r   r   r   r   r   r   
<dictcomp>  s      z4get_interfaces_by_mac_on_freebsd.<locals>.<dictcomp>r   )r^   r   r   r  Zresultsr   r   r   r     s
    r   c                  C   sb   i } d}t  ddg\}}tdd| }|D ],}t||}|r0| }|d | |d < q0| S )NzE(?P<ifname>\w+).*address:\s(?P<mac>([\da-f]{2}[:-]){5}([\da-f]{2})).*r   r   \n\s+ r   r   r	   r   subr]   r   	groupdictrX   Zre_field_matchr^   r   Zif_linesr   r  Zfieldsr   r   r   r     s    r   c                  C   sb   i } d}t  ddg\}}tdd| }|D ],}t||}|r0| }|d | |d < q0| S )NzC(?P<ifname>\w+).*lladdr\s(?P<mac>([\da-f]{2}[:-]){5}([\da-f]{2})).*r   r   r  r  r   r   r  r  r   r   r   r     s    r   c                  C   s   i } t  D ]\}}}}|| krV|dkr<td|| | | q
d|| | |f }t||| |< t|d}|r
|| kr~|| |< q
td|| | | q
| S )zmBuild a dictionary of tuples {mac: name}.

    Bridges and any devices that have a 'stolen' mac are excluded.)Z	fsl_enetcZ
mscc_felixZqmi_wwanz>Ignoring duplicate macs from '%s' and '%s' due to driver '%s'.z6duplicate mac found! both '%s' and '%s' have mac '%s'.Tz^Ethernet and InfiniBand interfaces have the same address both '%s' and '%s' have address '%s'.)r   r,   r-   r   r   warning)rX   r   r   rg   Z_devidr   ib_macr   r   r   r     s:    

r   )filter_hyperv_vf_with_syntheticr   r   r   r   r   r   rV   c                 C   s$  |r
t jndd }g }t }	dd}
|	D ]}|r<t|s<q*t|rP|d| q*|r^t|r^q*t|rr|d| q*|rt|dk	rt	|st
|sq*t|r|d| q*t|}|s|d	| q*|r|d
kr||
dt| krq*|rt|rq*t|}||||t|f q*| r t|| |S )zReturn list of interface tuples (name, mac, driver, device_id)

    Bridges and any devices that have a 'stolen' mac are excluded.c                  W   s   d S r   r   )argsr   r   r   <lambda>      z get_interfaces.<locals>.<lambda>:)00r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  zIgnoring bridge interface: %szIgnoring bond interface: %sNzIgnoring failover interface: %sz"Ignoring interface without mac: %sr   )r,   r-   r   rN   r   rH   r|   rJ   rM   rP   rQ   rh   r   ro   rb   rc   r   r   )filter_hyperv_vf_with_synthetic_interface)r  r   r   r   r   r   r   filtered_loggerrX   r   Zzero_macr   r   rg   r   r   r   r     sT    





 
r   ).N)r  r   rV   c                    sX   dd |D   fdd|D }|D ].}|\}}}}| d|| | | | | q$dS )a  Filter Hyper-V SR-IOV/VFs when used with synthetic hv_netvsc.

    Hyper-V's netvsc driver may register an SR-IOV/VF interface with a mac
    that matches the synthetic (hv_netvsc) interface.  This VF will be
    enslaved to the synthetic interface, but cloud-init may be racing this
    process.  The [perhaps-yet-to-be-enslaved] VF should never be directly
    configured, so we filter interfaces that duplicate any hv_netvsc mac
    address, as this the most reliable indicator that it is meant to be
    subordinate to the synthetic interface.

    VF drivers will be mlx4_core, mlx5_core, or mana.  However, given that
    this list of drivers has changed over time and mana's dependency on
    hv_netvsc is expected to be removed in the future, we no longer rely
    on these names. Note that this will not affect mlx4/5 instances outside
    of Hyper-V, as it only affects environments where hv_netvsc is present.
    c                 S   s&   i | ]}|d  dkr|d |d qS )r   	hv_netvscr   r   r   r   ir   r   r   r  U  s      z=filter_hyperv_vf_with_synthetic_interface.<locals>.<dictcomp>c                    s(   g | ] }|d   kr|d dkr|qS )r   r   r  r   r  Zhv_netvsc_mac_to_namer   r   r   X  s    z=filter_hyperv_vf_with_synthetic_interface.<locals>.<listcomp>zdIgnoring %r VF interface with driver %r due to synthetic hv_netvsc interface %r with mac address %r.N)r   )r  r   Zinterfaces_to_remover   r   r   rg   r   r   r  r   r  A  s     
r  c                  C   sP   i } t  D ]@\}}}}t|d}|r
|| krBtd|| | |f || |< q
| S )zTBuild a dictionary mapping Infiniband interface names to their hardware
    address.Fz5duplicate mac found! both '%s' and '%s' have mac '%s')r   r   r   )rX   r   r   r  r   r   r   get_ib_hwaddrs_by_interfacek  s    

r  )url_datarV   c              
   C   s   d| krt d|  dS | d }z8t|}t|jdk|jdkgsVt d|j W dS W n4 tk
r } zt d| W Y dS d}~X Y nX d	| krd
| d	< ztf |  W n tk
r   Y dS X dS )aD  Return true when the instance has access to the provided URL.

    Logs a warning if url is not the expected format.

    url_data is a dictionary of kwargs to send to readurl. E.g.:

    has_url_connectivity({
        "url": "http://example.invalid",
        "headers": {"some": "header"},
        "timeout": 10
    })
    urlz4Ignoring connectivity check. No 'url' to check in %sFZhttpZhttpsz2Ignoring connectivity check. Invalid URL scheme %sz+Ignoring connectivity check. Invalid URL %sNZtimeout   T)r,   r  r   anyZschemer:   r   r   )r  r  resulterrr   r   r   has_url_connectivity{  s2     
r!  )convert_to_addressr   c                 K   s*   z| |f|W S  t k
r$   Y dS X dS )a  Use a function to return an address. If conversion throws a ValueError
    exception return False.

    :param check_cb:
        Test function, must return a truthy value
    :param address:
        The string to test.

    :return:
        Address or False

    FN)r:   )r"  r   kwargsr   r   r   maybe_get_address  s    r$  )r   rV   c                 C   s   t ttj| S )zReturns a bool indicating if ``s`` is an IP address.

    :param address:
        The string to test.

    :return:
        A bool indicating if the string is an IP address or not.
    )rW   r$  	ipaddress
ip_addressr   r   r   r   is_ip_address  s    	r(  c                 C   s   t ttj| S )zReturns a bool indicating if ``s`` is an IPv4 address.

    :param address:
        The string to test.

    :return:
        A bool indicating if the string is an IPv4 address or not.
    )rW   r$  r%  ZIPv4Addressr'  r   r   r   is_ipv4_address  s    	r)  c                 C   s   t ttj| S )zReturns a bool indicating if ``s`` is an IPv6 address.

    :param address:
        The string to test.

    :return:
        A bool indicating if the string is an IPv4 address or not.
    )rW   r$  r%  ZIPv6Addressr'  r   r   r   is_ipv6_address  s    	r*  c                 C   s   t ttj| ddS )zReturns a bool indicating if ``s`` is an IPv4 or IPv6 network.

    :param address:
        The string to test.

    :return:
        A bool indicating if the string is an IPv4 address or not.
    Fr   )rW   r$  r%  
ip_networkr'  r   r   r   is_ip_network  s    	r-  c                 C   s   t ttj| ddS )zReturns a bool indicating if ``s`` is an IPv4 network.

    :param address:
        The string to test.

    :return:
        A bool indicating if the string is an IPv4 address or not.
    Fr+  )rW   r$  r%  IPv4Networkr'  r   r   r   is_ipv4_network  s    	r/  c                 C   s   t ttj| ddS )zReturns a bool indicating if ``s`` is an IPv6 network.

    :param address:
        The string to test.

    :return:
        A bool indicating if the string is an IPv4 address or not.
    Fr+  )rW   r$  r%  ZIPv6Networkr'  r   r   r   is_ipv6_network  s    	r0  c                 C   s@   | d  ds| d tkrdS | d dkr<t| dr<dS dS )z:Common helper for checking network_state subnets for ipv6.rR   6TZstaticr   F)endswithIPV6_DYNAMIC_TYPESr*  r   )Zsubnetr   r   r   subnet_is_ipv6  s
    r4  c                 C   s   t td|  jS )zConvert a network prefix to an ipv4 netmask.

    This is the inverse of ipv4_mask_to_net_prefix.
        24 -> "255.255.255.0"
    Also supports input as a string.0.0.0.0/)r{   r%  r.  netmask)prefixr   r   r   net_prefix_to_ipv4_mask  s    r8  c                 C   s   t d|  jS )a  Convert an ipv4 netmask into a network prefix length.

    If the input is already an integer or a string representation of
    an integer, then int(mask) will be returned.
       "255.255.255.0" => 24
       str(24)         => 24
       "24"            => 24
    r5  )r%  r,  	prefixlen)maskr   r   r   ipv4_mask_to_net_prefix  s    	r;  c                 C   s   zt d|  j}|W S  tk
r,   Y nX t | }t|}|dkrL|S tt j| |d @  }||? }t j| }d|> d }||krtd|  |S )zConvert an ipv6 netmask (very uncommon) or prefix (64) to prefix.

    If the input is already an integer or a string representation of
    an integer, then int(mask) will be returned.
       "ffff:ffff:ffff::"  => 48
       "48"                => 48
    z::/r   r   zInvalid network mask '%s')	r%  r,  r9  r:   r&  r   minZ
IPV6LENGTH
bit_length)r:  r9  r6  Zmask_intZtrailing_zeroesZleading_onesZall_onesr   r   r   ipv6_mask_to_net_prefix"  s&    
 
r>  )r:  r   rV   c                 C   s   t tj| d|  ddjS )zCGet string representation of broadcast address from an ip/mask pairr    Fr+  )r{   r%  r.  Zbroadcast_address)r:  r   r   r   r   mask_and_ipv4_to_bcast_addrE  s    r?  c                   @   s   e Zd ZdS )RendererNotFoundErrorN)r   r   r   r   r   r   r   r@  L  s   r@  )r   )NNNN)N)N)N)N)N)N)F)T)TTN)TTTTTTF)hr%   	functoolsr%  ZloggingrE   r   typingr   r   r   r   r   r   Zurllib.parser   Z	cloudinitr	   r
   Zcloudinit.url_helperr   r   Z	getLoggerr   r,   r   r   r3  rZ   r   r   r   r$   r4   r9   r<   rB   rH   rJ   rM   rP   rQ   rT   	lru_cacherW   rY   r   ra   r{   rb   rh   rk   rp   rs   rd   re   ry   r|   rc   r   r   ri   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r!  r$  r(  r)  r*  r-  r/  r0  r4  r8  r   r;  r>  r?  r   r@  r   r   r   r   <module>   s    

    
%


	





!
	
I
0

/     
  
H       =*'	#