o
    MizK                     @   s  U 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mZm	Z	m
Z
mZ ddlmZmZmZ ddlmZ ddlmZ ddlmZ ddlmZ d	d
geg dZeed< dZdZdZdZdZdZe e!Z"dd Z#dd Z$dd Z%dLddZ&dLddZ'de(de	e( dee(e(f d e)fd!d"Z*dMd#d$Z+d%e(d&e(d dfd'd(Z,dNd)d*Z-d+d, Z.d e
ee( ee(e(f ee( f fd-d.Z/d/ee	ee	e(    dee(e(f d0ee(e(f d1ee	e(  d2ed eee(  fd3d4Z0d/eee(  d eee(  fd5d6Z1d/eee(  d7e(dee(e(f d0ee(e(f d2ed eee(  fd8d9Z2d:eee(  d eee(  fd;d<Z3d:eee(  d dfd=d>Z4d?e)d@e)dAee( d dfdBdCZ5dLdDe	e( d dfdEdFZ6dGe(dHed2edIe7d df
dJdKZ8dS )Oz-Mounts: Configure mount points and swap files    N)DictListOptionalTuplecast)performancesubputil)Cloud)Config)
MetaSchema)PER_INSTANCE	cc_mountsall)iddistros	frequencyactivate_by_schema_keysmetaz&^([x]{0,1}[shv]d[a-z][0-9]*|sr[0-9]+)$z^.+:.*z
/etc/fstabzcomment=cloudconfig   i   @c                 C   s8   | dv rdS dD ]}|  |r| ddkr dS qdS )N)amirootswapT)	ephemeralebs:F)
startswithfind)nameenumname r!   </usr/lib/python3/dist-packages/cloudinit/config/cc_mounts.pyis_meta_device_name,   s   r#   c                 C   s   t t| rdS dS )NTF)rematchNETWORK_NAME_FILTER)r   r!   r!   r"   is_network_device8   s   r'   c                 C   sH   t |d|f d|f g}|D ]}d| |f }tj|r!|  S qd S )Nzp%sz-part%sz%s%s)strospathexists)device_pathpartition_numberpotential_suffixessuffixpotential_partition_devicer!   r!   r"   _get_nth_partition_for_device?   s   r1   c                 C   sX   t j| dd }t jd|}|d ur&t j|t j|dd }t j|S )N/r   z/sys/block/)r)   r*   realpathsplitjoinr+   )r,   partition_pathdevice_namesys_pathr!   r!   r"   _is_block_deviceL   s   r9   c                 C   s  t d|  | }|dkrd}t d t| r| S t|\}}|}|r5|||}||kr5t d|| t|rS||}|sAd S |dsKd|f }t d|| nt	t
| r^d|f }d }|d u rjt|d	}nt||}|d u rud S t||r|d ur|S |S d S )
Nz+Attempting to determine the real name of %sr   
ephemeral0z2Adjusted mount option from ephemeral to ephemeral0zMapped device alias %s to %sr2   z/dev/%szMapped metadata name %s to %s   )LOGdebugr'   r	   expand_dotted_devnamegetr#   r   r$   r%   DEVICE_NAME_FILTERr1   r9   )	startnametransformeraliasesdevnamer,   r-   origr6   r!   r!   r"   sanitize_devnameV   sF   




rF   original	sanitized
fstab_devsreturnc                 C   sP   || krt d| | |du rt d|  dS ||v r&t d|||  dS dS )z*Get if the sanitized device name is valid.zchanged %s => %sNz+Ignoring nonexistent default named mount %sFz&Device %s already defined in fstab: %sT)r<   r=   )rG   rH   rI   r!   r!   r"   sanitized_devname_is_valid   s   rK   c              	   C   s`  | d u r
t  d } | d }d|| d}|d u r|d u r|}n2|rKt|}|j|j }||d< |d u r>tt|d |}n||d krJt|d }n|d u rQ|}||d< | dt k r^| }n| d	t k ridt }nt	t
| t t }t||}||d
< i }	| D ]\}
}t|trd|t  |	|
< q||	|
< qtd|	d
 |	d |	d |	d |	d  |S )Ntotal   na)availmax_inmemrO      g?max   sizez%s MBzCsuggest %s swap for %s memory with '%s' disk given max=%s [max=%s]'rQ   rP   )r	   read_meminfor)   statvfsf_frsizef_bfreeminintGBroundmathsqrtitems
isinstanceMBr<   r=   )memsizemaxsizefsyssugg_maxinforW   rO   minsizerU   pinfokvr!   r!   r"   suggested_swapsize   sN   




rl   fnamerU   c                    s  d  fdd}t j| }t| t|d dkr0tddd| g td	d
| g dkrAt dk rA|| |d nz|| |d W n tjy^   t	
d || |d Y nw t j| rkt| d z
td| g W dS  tjy   t|   w )zSize is in MiB.z6Failed to create swapfile '%s' of size %sMB via %s: %sc              
      s   t d| | |dkrddd| | g}n|dkr%ddd|  dd	| g}ntd
z
tj|dd W d S  tjyP } zt  | ||| t|   d }~ww )Nz3Creating swapfile in '%s' on fstype '%s' using '%s'	fallocatez-lz%sMddzif=/dev/zerozof=%szbs=1Mzcount=%sz:Missing dependency: 'dd' and 'fallocate' are not availableT)capture)r<   r=   r   ProcessExecutionErrorrg   r	   del_file)rm   rU   methodcmdeerrmsgfstyper!   r"   create_swap   s4   
z$create_swapfile.<locals>.create_swapr;   btrfstruncatez-s0chattrz+Cxfs)rR      ro   rn   z4fallocate swap creation failed, will attempt with ddi  mkswapN)r)   r*   dirnamer	   
ensure_dirget_mount_infor   kernel_versionrq   r<   rg   r+   chmodrr   )rm   rU   ry   swap_dirr!   rv   r"   create_swapfile   s0   


r   c                 C   s   t j| }t| dkr2zt d }W n ty%   t	d Y dS w t
| t|||d}tt|d }|sCt	d dS td t| | W d   | S 1 sYw   Y  | S )	z
    fname: full path string of filename to setup
    size: the size to create. set to "auto" for recommended
    maxsize: the maximum size
    autorL   z)Not creating swap: failed to read meminfoN)re   rd   rc   r   z'Not creating swap: suggested size was 0zSetting up swap file)r)   r*   r   r(   lowerr	   rV   IOErrorr<   r=   r   rl   r[   r   Timedr   )rm   rU   rd   r   rc   mibsizer!   r!   r"   setup_swapfile  s,   



r   c              
   C   sZ  t | tstd dS | dd}| dd}| dd}|r"|s)td dS tj|rstjd	s=td
| |S z$t	
d	 D ]}||d rYtd| |  W S qEtd| W n tyr   td| | Y S w z t |tr|dkrt	|}t |trt	|}t|||dW S  ty } ztd| W Y d}~dS d}~ww )zahandle the swap config, calling setup_swap if necessary.
    return None or (filename, size)
    z%input for swap config was not a dict.Nfilenamez	/swap.imgrU   r   rd   zno need to setup swapz/proc/swapsz:swap file %s exists, but no /proc/swaps exists, being safe zswap file %s already in usez+swap file %s exists, but not in /proc/swapsz.swap file %s exists. Error reading /proc/swapsr   )rm   rU   rd   zfailed to setup swap: %s)ra   dictr<   warningr?   r=   r)   r*   r+   r	   load_text_file
splitlinesr   	Exceptionr(   human2bytesr   )swapcfgrm   rU   rd   lineru   r!   r!   r"   handle_swapcfg/  sP   






r   c                  C   sl   g } i }g }t jtr1tt D ]}t|v r|| q|	 }|r0|||d < | | q| ||fS )as  Parse /etc/fstab.

    Parse fstab, ignoring any lines containing "comment=cloudconfig".
    :return: A 3-tuple containing:
        - A list of lines exactly as they appear in fstab
        - A dictionary with key being the first token in the line
          and value being the entire line
        - A list of any lines that were ignored due to "comment=cloudconfig"
    r   )
r)   r*   r+   
FSTAB_PATHr	   r   r   MNT_COMMENTappendr4   )fstab_linesrI   fstab_removedr   toksr!   r!   r"   parse_fstab_  s   



r   mountsdevice_aliasesdefault_fieldscloudc                 C   s   g }| D ]Y}t |tstd| qt|d }t||j|d}t|||r0|g|dd  }	n|}	t|	D ]\}
}|du rE||
 |	|
< q6t|	|
 |	|
< q6|	|t	|	d 7 }	|
|	 q|S )a  Sanitize mounts to ensure we can work with devices in config.

    Specifically:
     - Ensure the mounts configuration is a list of lists
     - Transform and sanitize device names
     - Ensure all tokens are strings
     - Add default options to any lines without options
    z%Mount option not a list, ignoring: %sr   rC   r;   N)ra   listr<   r   r(   rF   device_name_to_devicerK   	enumeratelenr   )r   rI   r   r   r   updated_linesr   startsanitized_devnameupdated_lineindextokenr!   r!   r"   sanitize_mounts_configurationy  s&   
r   c                 C   sl   g }g }| ddd D ]#}|d du s|d |v r)t d|d  ||d  q|| q|ddd S )zRemove any entries that have a device name that doesn't exist.

    If the second field of a mount line is None (not the string, the value),
    we skip it along with any other entries that came before it that share
    the same device name.
    Nr   r;   r   z$Skipping nonexistent device named %s)r<   r=   r   )r   actlistdev_denylistr   r!   r!   r"   remove_nonexistent_devices  s   r   default_mount_optionsc           	         s   t | }ddd|ddgg dfD ]5  d }t||j|d}t|||s&qtt| d< t fd	d
| D }|rAt	d| q|
  q|S )zAdd default mounts to the user provided mount configuration.

    Add them only if no other entry has the same device name
    r:   z/mntr   r|   2)r   noner   swr|   r|   r   r   c                 3   s     | ]}|d   d  kV  qdS )r   Nr!   ).0cfgmdefault_mountr!   r"   	<genexpr>  s    
z,add_default_mounts_to_cfg.<locals>.<genexpr>z-Not including %s, already previously included)copydeepcopyrF   r   rK   r   r(   anyr<   r=   r   )	r   r   rI   r   r   
new_mountsr   rH   default_already_existsr!   r   r"   add_default_mounts_to_cfg  s&   
r   r   c                 C   s   dd | D S )z=Add "comment=cloudconfig" to the mount options of each entry.c                 S   s8   g | ]}|d d |d  dt  g |dd   qS )N   ,rR   )r   r   entryr!   r!   r"   
<listcomp>  s    *zadd_comment.<locals>.<listcomp>r!   r   r!   r!   r"   add_comment  s   r   c                 C   s(   t dd | D rtddg dS dS )z1Call 'swapon -a' if any entry has a swap fs type.c                 s   s    | ]	}|d  dkV  qdS )rM   r   Nr!   r   r!   r!   r"   r     s    z*activate_swap_if_needed.<locals>.<genexpr>swapon-aN)r   r   r   r!   r!   r"   activate_swap_if_needed  s   r   uses_systemdchanges_madedirsc                 C   sf   d}|rd}ndd t   D }tt||}|r/tddg | r1tddg d	S d	S d	S )
zCall 'mount -a' if needed.

    If changes were made, always call 'mount -a'. Otherwise, call 'mount -a'
    if any of the directories in the mount list are not already mounted.
    FTc                 S   s   h | ]
}d |v r|d  qS )
mountpointr!   )r   valr!   r!   r"   	<setcomp>  s
    z"mount_if_needed.<locals>.<setcomp>mountr   	systemctlzdaemon-reloadN)r	   r   valuesboolset
differencer   )r   r   r   do_mountmount_pointsr!   r!   r"   mount_if_needed  s   
r   ds_remove_entryc              
      s  t jtsd S tg}| r||  ttd}| }W d    n1 s&w   Y  g }d}|D ] t fdd|D rAd}q1|  q1z(|rmttd}|	| W d    n1 s_w   Y  t
dt W d S W d S  ty } zt
d| W Y d }~d S d }~ww )	NrFc                 3   s    | ]}| v V  qd S Nr!   r   r   r!   r"   r     s    z cleanup_fstab.<locals>.<genexpr>Twz%Removed resource disk entries from %sz4Failed to clean resource disk entries from fstab: %s)r)   r*   r+   r   r   r   open	readlinesr   
writelinesr<   rg   r   r   )r   remove_entriesflines	new_lineschangedru   r!   r   r"   cleanup_fstab  s4   

r   r   cfgargsc              	      s  |j  }|r	dnd}ddd|ddg}|d|}|dg }td	| t \}	}
}|d
i }t||
|||}t|||
||}t|}t	|}t
|di }|r^||dddddg |sgtd dS dd |D }dd |D }|D ]}zt| W qw ty   ttd| Y qww dd |D  dd |D  fddD fdd D  }|	| dd|	 }tt| |rtd| ntd t| t|t|| dS )z Handle the mounts configuration.z:defaults,nofail,x-systemd.after=cloud-init.service,_netdevzdefaults,nobootwaitNr   r|   r   mount_default_fieldsr   zmounts configuration is %sr   r   r   r   z No modifications to fstab neededc                 S   s   g | ]}d  |qS )	)r5   r   r!   r!   r"   r   K  s    zhandle.<locals>.<listcomp>c                 S   s"   g | ]}|d   dr|d  qS )r;   r2   )r   )r   dr!   r!   r"   r   M  s   " z Failed to make '%s' config-mountc                 S      g | ]}| d dqS r   r   replacer   nr!   r!   r"   r   U      c                 S   r   r   r   r   r!   r!   r"   r   V  r   c                       g | ]}| vrd | qS )z- r!   )r   drop)saddsr!   r"   r   X  s    c                    r   )z+ r!   )r   add)sdropsr!   r"   r   X  s    z%s

zChanges to fstab: %szNo changes to /etc/fstab made.)distror   r?   r<   r=   r   r   r   r   r   r   r   r	   r   r   logexcextendr5   
write_filer   r   r   r   )r   r   r   r   r   r   hardcoded_defaultsr   r   r   rI   r   r   updated_cfgswapfile	cfg_linesr   r   sopscontentsr!   )r   r   r"   handle!  s`   





r  r   )NNN)NN)9__doc__r   loggingr^   r)   r$   typingr   r   r   r   r   	cloudinitr   r   r	   cloudinit.cloudr
   cloudinit.configr   cloudinit.config.schemar   cloudinit.settingsr   r   __annotations__r@   r&   r   r   rb   r\   	getLogger__name__r<   r#   r'   r1   r9   rF   r(   r   rK   rl   r   r   r   r   r   r   r   r   r   r   r   r   r  r!   r!   r!   r"   <module>   s   



1


9
>(0




".




"$
"